From 3c9fe3ebd47bfdde63f6f2160736c54c8a99f6c0 Mon Sep 17 00:00:00 2001 From: Seung Park Date: Tue, 23 Jan 2024 12:44:18 -0500 Subject: [PATCH] DOP-4264: allow sibling associated products' ToC to be visible (#985) --- .../gatsby-node.js | 4 + .../gatsby-source-snooty-prod/gatsby-node.js | 78 ++++++---- plugins/utils/docsets.js | 1 + src/components/Image.js | 5 +- src/components/RootProvider.js | 19 +-- src/context/toc-context.js | 9 +- src/context/version-context.js | 37 +++-- src/hooks/useAllDocsets.js | 6 + src/hooks/useAssociatedProducts.js | 17 ++ src/init/DocumentDatabase.js | 13 +- src/layouts/index.js | 7 +- src/utils/realm.js | 2 +- tests/context/toc-context.test.js | 10 +- tests/context/version-context.test.js | 147 ++++++++++-------- tests/unit/VersionDropdown.test.js | 28 +++- 15 files changed, 238 insertions(+), 145 deletions(-) create mode 100644 src/hooks/useAssociatedProducts.js diff --git a/plugins/gatsby-source-snooty-preview/gatsby-node.js b/plugins/gatsby-source-snooty-preview/gatsby-node.js index a38a46c5c..62e45a46e 100644 --- a/plugins/gatsby-source-snooty-preview/gatsby-node.js +++ b/plugins/gatsby-source-snooty-preview/gatsby-node.js @@ -55,6 +55,10 @@ exports.createSchemaCustomization = async ({ actions }) => { slug: String images: [File] @link(by: "relativePath", from: "pageAssets") } + + type AssociatedProduct implements Node @dontInfer { + productName: String + } `; createTypes(typeDefs); }; diff --git a/plugins/gatsby-source-snooty-prod/gatsby-node.js b/plugins/gatsby-source-snooty-prod/gatsby-node.js index a8e0e89d0..974b2ec6e 100644 --- a/plugins/gatsby-source-snooty-prod/gatsby-node.js +++ b/plugins/gatsby-source-snooty-prod/gatsby-node.js @@ -24,43 +24,23 @@ const assets = new Map(); let db; -let isAssociatedProduct = false; -const associatedReposInfo = {}; - // Creates node for RemoteMetadata, mostly used for Embedded Versions. If no associated products // or data are found, the node will be null -const createRemoteMetadataNode = async ({ createNode, createNodeId, createContentDigest }) => { - // fetch associated child products - const productList = manifestMetadata?.associated_products || []; - await Promise.all( - productList.map(async (product) => { - associatedReposInfo[product.name] = await db.realmInterface.fetchDocset({ project: product.name }); - }) - ); - // check if product is associated child product - try { - const umbrellaProduct = await db.realmInterface.getMetadata({ - 'associated_products.name': siteMetadata.project, - }); - isAssociatedProduct = !!umbrellaProduct; - } catch (e) { - console.log('No umbrella product found. Not an associated product.'); - isAssociatedProduct = false; - } - +const createRemoteMetadataNode = async ({ createNode, createNodeId, createContentDigest }, umbrellaProduct) => { // get remote metadata for updated ToC in Atlas try { const filter = { project: manifestMetadata.project, branch: manifestMetadata.branch, }; + const isAssociatedProduct = !!umbrellaProduct; if (isAssociatedProduct || manifestMetadata?.associated_products?.length) { filter['is_merged_toc'] = true; } const findOptions = { sort: { build_id: -1 }, }; - const remoteMetadata = await db.realmInterface.getMetadata(filter, findOptions); + const remoteMetadata = await db.realmInterface.getMetadata(filter, undefined, findOptions); createNode({ children: [], @@ -78,6 +58,37 @@ const createRemoteMetadataNode = async ({ createNode, createNodeId, createConten } }; +/** + * Creates graphql nodes on metadata for associated products + * Association can be an umbrella product, associated product (in snooty.toml), + * or sibling products + */ +const createAssociatedProductNodes = async ({ createNode, createNodeId, createContentDigest }, umbrellaProduct) => { + try { + const associatedProducts = manifestMetadata?.associated_products || []; + if (umbrellaProduct) { + associatedProducts.push(...(umbrellaProduct.associated_products || [])); + } + + return await Promise.all( + associatedProducts.map(async (product) => + createNode({ + children: [], + id: createNodeId(`associated-metadata-${product.name}`), + internal: { + contentDigest: createContentDigest(product), + type: 'AssociatedProduct', + }, + parent: null, + productName: product.name, + }) + ) + ); + } catch (e) { + console.error(`Error while creating associated metadata nodes: ${JSON.stringify(e)}`); + } +}; + exports.sourceNodes = async ({ actions, createContentDigest, createNodeId }) => { let hasOpenAPIChangelog = false; const { createNode } = actions; @@ -167,11 +178,24 @@ exports.sourceNodes = async ({ actions, createContentDigest, createNodeId }) => await createProductNodes({ db, createNode, createNodeId, createContentDigest }); - await createRemoteMetadataNode({ createNode, createNodeId, createContentDigest }); + const umbrellaProduct = await db.realmInterface.getMetadata( + { + 'associated_products.name': siteMetadata.project, + }, + { associated_products: 1 } + ); + + await createAssociatedProductNodes({ createNode, createNodeId, createContentDigest }, umbrellaProduct); + + await createRemoteMetadataNode({ createNode, createNodeId, createContentDigest }, umbrellaProduct); + if (siteMetadata.project === 'cloud-docs' && hasOpenAPIChangelog) await createOpenAPIChangelogNode({ createNode, createNodeId, createContentDigest, siteMetadata, db }); await saveAssetFiles(assets, db); + if (!siteMetadata.manifestPath) { + console.error('Getting metadata from realm without filters'); + } const { static_files: staticFiles, ...metadataMinusStatic } = await db.getMetadata(); const { parentPaths, slugToTitle } = metadataMinusStatic; @@ -257,8 +281,6 @@ exports.createPages = async ({ actions }) => { context: { slug, repoBranches, - associatedReposInfo, - isAssociatedProduct, template: pageNodes?.options?.template, page: pageNodes, }, @@ -327,5 +349,9 @@ exports.createSchemaCustomization = ({ actions }) => { slug: String images: [File] @link(by: "relativePath", from: "pageAssets") } + + type AssociatedProduct implements Node @dontInfer { + productName: String + } `); }; diff --git a/plugins/utils/docsets.js b/plugins/utils/docsets.js index 09345bb30..8eb916064 100644 --- a/plugins/utils/docsets.js +++ b/plugins/utils/docsets.js @@ -13,6 +13,7 @@ const createDocsetNodes = async ({ db, createNode, createNodeId, createContentDi prefix: docset.prefix, project: docset.project, url: docset.url, + branches: docset.branches, }); }); }; diff --git a/src/components/Image.js b/src/components/Image.js index 63cea858a..b54e11a0b 100644 --- a/src/components/Image.js +++ b/src/components/Image.js @@ -29,6 +29,9 @@ const Image = ({ nodeData, className }) => { border: 0.5px solid ${palette.gray.light1}; border-radius: 4px; `; + const gatsbyContainerStyle = css` + height: max-content; + `; const { imageByPath } = useContext(ImageContext); const image = imageByPath[removeLeadingSlash(imgSrc)]; @@ -61,7 +64,7 @@ const Image = ({ nodeData, className }) => { alt={altText} style={userOptionStyle} imgClassName={cx(defaultStyling, hasBorder ? borderStyling : '')} - className={cx(directiveClass, customAlign, className)} + className={cx(gatsbyContainerStyle, directiveClass, customAlign, className)} /> ); } diff --git a/src/components/RootProvider.js b/src/components/RootProvider.js index 3d077b110..a2a13773a 100644 --- a/src/components/RootProvider.js +++ b/src/components/RootProvider.js @@ -12,27 +12,12 @@ import { SearchContextProvider } from './SearchResults/SearchContext'; // Check for feature flag here to make it easier to pass down for testing purposes const SHOW_FACETS = process.env.GATSBY_FEATURE_FACETED_SEARCH === 'true'; -const RootProvider = ({ - children, - headingNodes, - selectors, - slug, - repoBranches, - associatedReposInfo, - isAssociatedProduct, - remoteMetadata, - project, -}) => { +const RootProvider = ({ children, headingNodes, selectors, slug, repoBranches, remoteMetadata, project }) => { let providers = ( - + {children} diff --git a/src/context/toc-context.js b/src/context/toc-context.js index 6cb900256..2e8e1d879 100644 --- a/src/context/toc-context.js +++ b/src/context/toc-context.js @@ -2,7 +2,7 @@ import React, { createContext, useContext, useEffect, useState } from 'react'; import { useCallback } from 'react'; import { METADATA_COLLECTION } from '../build-constants'; import { useSiteMetadata } from '../hooks/use-site-metadata'; -import { fetchDocuments } from '../utils/realm'; +import { fetchDocument } from '../utils/realm'; import useSnootyMetadata from '../utils/use-snooty-metadata'; import { isGatsbyPreview } from '../utils/is-gatsby-preview'; import { VersionContext } from './version-context'; @@ -39,16 +39,15 @@ const TocContextProvider = ({ children, remoteMetadata }) => { if (associatedProducts?.length || showVersionDropdown) { filter['is_merged_toc'] = true; } - const db = database; - const metadata = await fetchDocuments(db, METADATA_COLLECTION, filter, undefined, findOptions); - return metadata[0]?.toctree ?? toctree; + const metadata = await fetchDocument(database, METADATA_COLLECTION, filter, { toctree: 1 }, findOptions); + return metadata?.toctree ?? toctree; } catch (e) { // fallback to toctree from build time console.error(e); return remoteMetadata?.toctree || toctree; } // below dependents are server constants - }, [project, branch, associatedProducts, showVersionDropdown, database, toctree, remoteMetadata]); + }, [toctree, project, branch, associatedProducts?.length, showVersionDropdown, database, remoteMetadata?.toctree]); const setInitVersion = useCallback( (tocNode) => { diff --git a/src/context/version-context.js b/src/context/version-context.js index 2e79acc70..f616423ba 100644 --- a/src/context/version-context.js +++ b/src/context/version-context.js @@ -1,10 +1,12 @@ import React, { createContext, useReducer, useEffect, useState, useCallback, useRef, useMemo } from 'react'; import { navigate } from '@gatsbyjs/reach-router'; import { METADATA_COLLECTION } from '../build-constants'; +import { useAllDocsets } from '../hooks/useAllDocsets'; +import { useAllAssociatedProducts } from '../hooks/useAssociatedProducts'; import { useSiteMetadata } from '../hooks/use-site-metadata'; import { useCurrentUrlSlug } from '../hooks/use-current-url-slug'; import { getLocalValue, setLocalValue } from '../utils/browser-storage'; -import { fetchDocset, fetchDocuments } from '../utils/realm'; +import { fetchDocset, fetchDocument } from '../utils/realm'; import { getUrl } from '../utils/url-utils'; import useSnootyMetadata from '../utils/use-snooty-metadata'; @@ -60,7 +62,7 @@ const getBranches = async (metadata, repoBranches, associatedReposInfo, associat for (let associatedProduct of associatedProducts) { promises.push( fetchDocset(metadata.reposDatabase, { - project: associatedProduct.name, + project: associatedProduct, }) ); } @@ -122,8 +124,8 @@ const getUmbrellaProject = async (project, dbName) => { const query = { 'associated_products.name': project, }; - const umbrellaProjects = fetchDocuments(dbName, METADATA_COLLECTION, query); - return umbrellaProjects; + const umbrellaProject = await fetchDocument(dbName, METADATA_COLLECTION, query); + return umbrellaProject; } catch (e) { console.error(e); } @@ -139,12 +141,28 @@ const VersionContext = createContext({ setAvailableVersions: () => {}, showVersionDropdown: false, showEol: false, + isAssociatedProduct: false, onVersionSelect: () => {}, }); -const VersionContextProvider = ({ repoBranches, associatedReposInfo, isAssociatedProduct, slug, children }) => { +const VersionContextProvider = ({ repoBranches, slug, children }) => { const siteMetadata = useSiteMetadata(); - const { associated_products: associatedProducts, project } = useSnootyMetadata(); + const associatedProductNames = useAllAssociatedProducts(); + const docsets = useAllDocsets(); + const { project } = useSnootyMetadata(); + const associatedReposInfo = useMemo( + () => + associatedProductNames.reduce((res, productName) => { + res[productName] = docsets.find((docset) => docset.project === productName); + return res; + }, {}), + [associatedProductNames, docsets] + ); + + const isAssociatedProduct = useMemo( + () => associatedProductNames.includes(project), + [associatedProductNames, project] + ); const metadata = useMemo(() => { return { ...siteMetadata, @@ -176,7 +194,7 @@ const VersionContextProvider = ({ repoBranches, associatedReposInfo, isAssociate // on init, fetch versions from realm app services useEffect(() => { - getBranches(metadata, repoBranches, associatedReposInfo, associatedProducts || []).then( + getBranches(metadata, repoBranches, associatedReposInfo, associatedProductNames).then( ({ versions, groups, hasEolBranches }) => { if (!mountRef.current) { return; @@ -194,11 +212,11 @@ const VersionContextProvider = ({ repoBranches, associatedReposInfo, isAssociate const [showVersionDropdown, setShowVersionDropdown] = useState(isAssociatedProduct); useEffect(() => { - getUmbrellaProject(metadata.project, metadata.database).then((metadataList) => { + getUmbrellaProject(metadata.project, metadata.database).then((umbrellaMetadata) => { if (!mountRef.current) { return; } - setShowVersionDropdown(metadataList.length > 0); + setShowVersionDropdown(!!umbrellaMetadata); }); }, [metadata.project, metadata.database]); @@ -273,6 +291,7 @@ const VersionContextProvider = ({ repoBranches, associatedReposInfo, isAssociate availableGroups, showVersionDropdown, onVersionSelect, + isAssociatedProduct, showEol, }} > diff --git a/src/hooks/useAllDocsets.js b/src/hooks/useAllDocsets.js index 104a5daa9..4705f44d6 100644 --- a/src/hooks/useAllDocsets.js +++ b/src/hooks/useAllDocsets.js @@ -23,6 +23,12 @@ export const useAllDocsets = () => { stg regression } + branches { + gitBranchName + active + urlSlug + urlAliases + } } } } diff --git a/src/hooks/useAssociatedProducts.js b/src/hooks/useAssociatedProducts.js new file mode 100644 index 000000000..adee98b61 --- /dev/null +++ b/src/hooks/useAssociatedProducts.js @@ -0,0 +1,17 @@ +import { useStaticQuery, graphql } from 'gatsby'; + +// Return an array of MongoDB products +export const useAllAssociatedProducts = () => { + const { allAssociatedProduct } = useStaticQuery( + graphql` + query AllAssociatedProducts { + allAssociatedProduct { + nodes { + productName + } + } + } + ` + ); + return allAssociatedProduct.nodes.map((ap) => ap.productName); +}; diff --git a/src/init/DocumentDatabase.js b/src/init/DocumentDatabase.js index 2a2691711..d776f06a7 100644 --- a/src/init/DocumentDatabase.js +++ b/src/init/DocumentDatabase.js @@ -25,12 +25,19 @@ class RealmInterface { return this.realmClient.callFunction('fetchDocuments', DB, collection, buildFilter); } - async getMetadata(buildFilter, findOptions) { - return this.realmClient.callFunction('fetchDocument', DB, METADATA_COLLECTION, buildFilter, undefined, findOptions); + async getMetadata(buildFilter, projectionOptions, findOptions) { + return this.realmClient.callFunction( + 'fetchDocumentSorted', + DB, + METADATA_COLLECTION, + buildFilter, + projectionOptions, + findOptions + ); } async fetchDocument(database, collectionName, query) { - return this.realmClient.callFunction('fetchDocument', database, collectionName, query); + return this.realmClient.callFunction('fetchDocumentSorted', database, collectionName, query); } async fetchDocset(matchConditions = { project: siteMetadata.project }) { diff --git a/src/layouts/index.js b/src/layouts/index.js index b5027d895..28595fe47 100644 --- a/src/layouts/index.js +++ b/src/layouts/index.js @@ -83,10 +83,7 @@ const GlobalGrid = styled('div')` overflow: clip; `; -const DefaultLayout = ({ - children, - pageContext: { page, slug, repoBranches, template, associatedReposInfo, isAssociatedProduct }, -}) => { +const DefaultLayout = ({ children, pageContext: { page, slug, repoBranches, template } }) => { const { sidenav } = getTemplate(template); const { chapters, guides, publishedBranches, slugToTitle, title, toctree, eol, project } = useSnootyMetadata(); const remoteMetadata = useRemoteMetadata(); @@ -102,10 +99,8 @@ const DefaultLayout = ({ diff --git a/src/utils/realm.js b/src/utils/realm.js index 6e17b7aa2..d55293982 100644 --- a/src/utils/realm.js +++ b/src/utils/realm.js @@ -59,7 +59,7 @@ export const fetchOASFile = async (apiName, database) => { }; export const fetchDocument = async (database, collectionName, query, projections) => { - return callAuthenticatedFunction('fetchDocument', database, collectionName, query, projections); + return callAuthenticatedFunction('fetchDocumentSorted', database, collectionName, query, projections); }; export const fetchDocset = async (database, matchConditions) => { diff --git a/tests/context/toc-context.test.js b/tests/context/toc-context.test.js index c020bf7ac..23b249359 100644 --- a/tests/context/toc-context.test.js +++ b/tests/context/toc-context.test.js @@ -11,7 +11,7 @@ import { TocContext, TocContextProvider } from '../../src/context/toc-context'; // <------------------ START test data mocks ------------------> const siteMetadataMock = jest.spyOn(siteMetadata, 'useSiteMetadata'); const snootyMetadataMock = jest.spyOn(snootyMetadata, 'default'); -const realmMock = jest.spyOn(realm, 'fetchDocuments'); +const realmMock = jest.spyOn(realm, 'fetchDocument'); const project = 'cloud-docs'; let sampleTocTree, responseTree, mockedResponse; @@ -80,11 +80,9 @@ const setResponse = () => { }, }); - mockedResponse = [ - { - toctree: responseTree, - }, - ]; + mockedResponse = { + toctree: responseTree, + }; }; const setMocks = () => { diff --git a/tests/context/version-context.test.js b/tests/context/version-context.test.js index f1796f009..a4f50c7df 100644 --- a/tests/context/version-context.test.js +++ b/tests/context/version-context.test.js @@ -1,71 +1,20 @@ import React, { useContext } from 'react'; -import * as Gatsby from 'gatsby'; import { render } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { act } from 'react-dom/test-utils'; import { VersionContextProvider, VersionContext, STORAGE_KEY } from '../../src/context/version-context'; +import * as siteMetadata from '../../src/hooks/use-site-metadata'; +import * as snootyMetadata from '../../src/utils/use-snooty-metadata'; +import * as useAssociatedProducts from '../../src/hooks/useAssociatedProducts'; +import * as useAllDocsets from '../../src/hooks/useAllDocsets'; import * as browserStorage from '../../src/utils/browser-storage'; import * as realm from '../../src/utils/realm'; -import * as snootyMetadata from '../../src/utils/use-snooty-metadata'; const snootyMetadataMock = jest.spyOn(snootyMetadata, 'default'); -const useStaticQuery = jest.spyOn(Gatsby, 'useStaticQuery'); +const uesSiteMetadataMock = jest.spyOn(siteMetadata, 'useSiteMetadata'); +const useAssociatedProductsMock = jest.spyOn(useAssociatedProducts, 'useAllAssociatedProducts'); +const useAllDocsetsMock = jest.spyOn(useAllDocsets, 'useAllDocsets'); const project = 'cloud-docs'; -const setProjectAndAssociatedProducts = () => { - useStaticQuery.mockImplementation(() => ({ - site: { - siteMetadata: { - parserBranch: 'master', - }, - }, - })); - snootyMetadataMock.mockImplementation(() => ({ - project, - associated_products: [ - { - name: 'atlas-cli', - versions: ['v1.1', 'v1.2', 'master'], - }, - ], - })); -}; - -const getKey = (project, branchName) => `${project}-${branchName}`; - -const TestConsumer = () => { - const { activeVersions, setActiveVersions, availableVersions } = useContext(VersionContext); - - const handleClick = (project, version) => { - const value = {}; - value[project] = version; - setActiveVersions(value); - }; - - const versionElms = []; - for (let project in availableVersions) { - for (let branch of availableVersions[project]) { - versionElms.push( -
{ - handleClick(project, branch.gitBranchName); - }} - key={getKey(project, branch.gitBranchName)} - id={getKey(project, branch.gitBranchName)} - > - {getKey(project, branch.gitBranchName)} -
- ); - } - } - return ( - <> -

active versions:

-
{JSON.stringify(activeVersions)}
-

availableVersions:

-
{versionElms}
- - ); -}; const cloudDocsRepoBranches = { branches: [ @@ -134,10 +83,73 @@ const mockedAssociatedRepoInfo = { }, }; +const setProjectAndAssociatedProducts = () => { + uesSiteMetadataMock.mockImplementation(() => ({ + parserBranch: 'master', + })); + snootyMetadataMock.mockImplementation(() => ({ + project, + associated_products: [ + { + name: 'atlas-cli', + versions: ['v1.1', 'v1.2', 'master'], + }, + ], + })); + useAssociatedProductsMock.mockImplementation(() => ['atlas-cli']); + useAllDocsetsMock.mockImplementation(() => [ + { + project: 'cloud-docs', + branches: cloudDocsRepoBranches.branches, + }, + { + project: 'atlas-cli', + branches: mockedAssociatedRepoInfo['atlas-cli']['branches'], + }, + ]); +}; + +const getKey = (project, branchName) => `${project}-${branchName}`; + +const TestConsumer = () => { + const { activeVersions, setActiveVersions, availableVersions } = useContext(VersionContext); + + const handleClick = (project, version) => { + const value = {}; + value[project] = version; + setActiveVersions(value); + }; + + const versionElms = []; + for (let project in availableVersions) { + for (let branch of availableVersions[project]) { + versionElms.push( +
{ + handleClick(project, branch.gitBranchName); + }} + key={getKey(project, branch.gitBranchName)} + id={getKey(project, branch.gitBranchName)} + > + {getKey(project, branch.gitBranchName)} +
+ ); + } + } + return ( + <> +

active versions:

+
{JSON.stringify(activeVersions)}
+

availableVersions:

+
{versionElms}
+ + ); +}; + const mountConsumer = () => { setProjectAndAssociatedProducts(); return render( - + test consumer below @@ -146,13 +158,9 @@ const mountConsumer = () => { const mountAtlasCliConsumer = (eol) => { const project = 'atlas-cli'; - useStaticQuery.mockImplementationOnce(() => ({ - site: { - siteMetadata: { - project: project, - parserBranch: eol ? 'v1.0' : 'master', - }, - }, + uesSiteMetadataMock.mockImplementationOnce(() => ({ + project: project, + parserBranch: eol ? 'v1.0' : 'master', })); snootyMetadataMock.mockImplementationOnce(() => { @@ -163,7 +171,7 @@ const mountAtlasCliConsumer = (eol) => { }); return render( - + test consumer below @@ -226,9 +234,9 @@ describe('Version Context', () => { }; }); }); - mockFetchDocuments = jest.spyOn(realm, 'fetchDocuments').mockImplementation(async (dbName, collectionName, query) => { + mockFetchDocuments = jest.spyOn(realm, 'fetchDocument').mockImplementation(async (dbName, collectionName, query) => { if (query && query['associated_products'] === 'docs-atlas-cli') { - return [{}]; // spoofing data for "at least one parent association" + return {}; // spoofing data for "at least one parent association" } return []; }); @@ -302,6 +310,7 @@ describe('Version Context', () => { await act(async () => { wrapper = mountAtlasCliConsumer(true); }); + wrapper.debug(); for (let branch of mockedAssociatedRepoInfo['atlas-cli'].branches) { expect(await wrapper.findByText(getKey(project, branch.gitBranchName))).toBeTruthy(); } diff --git a/tests/unit/VersionDropdown.test.js b/tests/unit/VersionDropdown.test.js index 59a744131..04408bdb3 100644 --- a/tests/unit/VersionDropdown.test.js +++ b/tests/unit/VersionDropdown.test.js @@ -4,6 +4,8 @@ import userEvent from '@testing-library/user-event'; import * as realm from '../../src/utils/realm'; import { generatePrefix } from '../../src/components/VersionDropdown/utils'; import VersionDropdown from '../../src/components/VersionDropdown'; +import * as useAssociatedProducts from '../../src/hooks/useAssociatedProducts'; +import * as useAllDocsets from '../../src/hooks/useAllDocsets'; import mockData from '../unit/data/VersionDropdown.test.json'; import { VersionContextProvider } from '../../src/context/version-context'; import { tick } from '../utils'; @@ -20,6 +22,20 @@ jest.mock('@gatsbyjs/reach-router', () => ({ navigate: jest.fn(), })); +const useAssociatedProductsMock = jest.spyOn(useAssociatedProducts, 'useAllAssociatedProducts'); +const useAllDocsetsMock = jest.spyOn(useAllDocsets, 'useAllDocsets'); +useAssociatedProductsMock.mockImplementation(() => ['atlas-cli']); +useAllDocsetsMock.mockImplementation(() => [ + { + project: 'cloud-docs', + branches: [], + }, + { + project: 'atlas-cli', + branches: [], + }, +]); + const fetchDocuments = () => { return jest.spyOn(realm, 'fetchDocuments').mockImplementation(async (dbName, collectionName, query) => { if (query && query['associated_products'] === 'docs-atlas-cli') { @@ -29,6 +45,12 @@ const fetchDocuments = () => { }); }; +const fetchDocument = () => { + return jest.spyOn(realm, 'fetchDocument').mockImplementation(async () => { + return {}; + }); +}; + const fetchDocset = () => { return jest.spyOn(realm, 'fetchDocset').mockImplementation(async (database, matchConditions) => { switch (matchConditions.project) { @@ -121,7 +143,7 @@ const queryElementWithin = (versionDropdown, role) => within(versionDropdown).qu const mountConsumer = () => { return render( - + ); @@ -195,14 +217,16 @@ describe('VersionDropdown', () => { describe('Component', () => { jest.useFakeTimers(); - let mockFetchDocuments, mockedFetchDocset; + let mockFetchDocuments, mockedFetchDocset, mockFetchDocument; beforeEach(async () => { + mockFetchDocument = fetchDocument(); mockFetchDocuments = fetchDocuments(); mockedFetchDocset = fetchDocset(); }); afterAll(async () => { + mockFetchDocument.mockClear(); mockFetchDocuments.mockClear(); mockedFetchDocset.mockClear(); });