diff --git a/packages/compass-e2e-tests/helpers/selectors.ts b/packages/compass-e2e-tests/helpers/selectors.ts index 4b3d5d4431b..f4d909151e2 100644 --- a/packages/compass-e2e-tests/helpers/selectors.ts +++ b/packages/compass-e2e-tests/helpers/selectors.ts @@ -1151,7 +1151,7 @@ export const UpdateValidationButton = '[data-testid="update-validation-button"]'; export const ValidationMatchingDocumentsPreview = '[data-testid="validation-content"] [data-testid="matching-documents"] [data-testid="document-preview"]'; -export const ValidationLoadMatchingDocumentsBtn = `${ValidationMatchingDocumentsPreview} [data-testid="load-sample-document"]`; +export const ValidationLoadSampleDocumentsBtn = `[data-testid="load-sample-documents"]`; export const ValidationNotMatchingDocumentsPreview = '[data-testid="validation-content"] [data-testid="notmatching-documents"] [data-testid="document-preview"]'; export const ValidationLoadNotMatchingDocumentsBtn = `${ValidationNotMatchingDocumentsPreview} [data-testid="load-sample-document"]`; diff --git a/packages/compass-e2e-tests/tests/collection-validation-tab.test.ts b/packages/compass-e2e-tests/tests/collection-validation-tab.test.ts index b5e35f8d67e..d34c7badeb4 100644 --- a/packages/compass-e2e-tests/tests/collection-validation-tab.test.ts +++ b/packages/compass-e2e-tests/tests/collection-validation-tab.test.ts @@ -10,7 +10,6 @@ import * as Selectors from '../helpers/selectors'; import { createNumbersCollection } from '../helpers/insert-data'; const NO_PREVIEW_DOCUMENTS = 'No Preview Documents'; -const LOAD_SAMPLE_DOCUMENT = 'Load document'; const PASSING_VALIDATOR = '{ $jsonSchema: {} }'; const FAILING_VALIDATOR = '{ $jsonSchema: { bsonType: "object", required: [ "phone" ] } }'; @@ -54,9 +53,11 @@ describe('Collection validation tab', function () { } context('when the schema validation is set or modified', function () { - it('provides users with a button to load sample documents', async function () { + it('provides users with a single button to load sample documents', async function () { await addValidation(PASSING_VALIDATOR); + await browser.clickVisible(Selectors.ValidationLoadSampleDocumentsBtn); + await browser.waitUntil(async () => { const matchTextElement = browser.$( Selectors.ValidationMatchingDocumentsPreview @@ -67,18 +68,15 @@ describe('Collection validation tab', function () { ); const notMatchingText = await notMatchingTextElement.getText(); return ( - matchText === LOAD_SAMPLE_DOCUMENT && - notMatchingText === LOAD_SAMPLE_DOCUMENT + matchText.includes('ObjectId(') && + notMatchingText === NO_PREVIEW_DOCUMENTS ); }); }); it('supports rules in JSON schema', async function () { await addValidation(FAILING_VALIDATOR); - await browser.clickVisible(Selectors.ValidationLoadMatchingDocumentsBtn); - await browser.clickVisible( - Selectors.ValidationLoadNotMatchingDocumentsBtn - ); + await browser.clickVisible(Selectors.ValidationLoadSampleDocumentsBtn); // nothing passed, everything failed await browser.waitUntil(async () => { @@ -100,10 +98,7 @@ describe('Collection validation tab', function () { // the automatic indentation and brackets makes multi-line values very fiddly here await browser.setValidation(PASSING_VALIDATOR); - await browser.clickVisible(Selectors.ValidationLoadMatchingDocumentsBtn); - await browser.clickVisible( - Selectors.ValidationLoadNotMatchingDocumentsBtn - ); + await browser.clickVisible(Selectors.ValidationLoadSampleDocumentsBtn); // nothing failed, everything passed await browser.waitUntil(async () => { diff --git a/packages/compass-schema-validation/src/components/document-preview.spec.tsx b/packages/compass-schema-validation/src/components/document-preview.spec.tsx index 7824f90fc04..23b90b8cb66 100644 --- a/packages/compass-schema-validation/src/components/document-preview.spec.tsx +++ b/packages/compass-schema-validation/src/components/document-preview.spec.tsx @@ -5,37 +5,14 @@ import { expect } from 'chai'; import { DocumentPreview } from './document-preview'; describe('DocumentPreview [Component]', function () { - context('when document loading state is initial', function () { - it('renders a button to load a sample document', function () { - const component = mount(); - expect(component.find('[data-testid="load-sample-document"]')).to.exist; - }); - }); - - context('when document loading state is loading', function () { - it('renders a spinner', function () { - const component = mount(); - expect(component.find('[data-testid="load-sample-spinner"]')).to.exist; - }); - }); - context('when document loading state is success', function () { it('renders a document if there is one present', function () { - const component = mount( - - ); + const component = mount(); expect(component.find('HadronDocument')).to.exist; }); it('renders a no preview text when there is no document', function () { - const component = mount(); - expect(component).to.have.text('No Preview Documents'); - }); - }); - - context('when document loading state is error', function () { - it('renders a no preview text', function () { - const component = mount(); + const component = mount(); expect(component).to.have.text('No Preview Documents'); }); }); diff --git a/packages/compass-schema-validation/src/components/document-preview.tsx b/packages/compass-schema-validation/src/components/document-preview.tsx index cf4f512236b..fbd02b84a84 100644 --- a/packages/compass-schema-validation/src/components/document-preview.tsx +++ b/packages/compass-schema-validation/src/components/document-preview.tsx @@ -1,23 +1,13 @@ import React from 'react'; -import { connect } from 'react-redux'; import { Body, KeylineCard, css, cx, spacing, - Button, } from '@mongodb-js/compass-components'; import { Document } from '@mongodb-js/compass-crud'; -import { LoadingOverlay } from './loading-overlay'; -import type { DOCUMENT_LOADING_STATES } from '../modules/sample-documents'; -import { - fetchValidDocument, - fetchInvalidDocument, -} from '../modules/sample-documents'; -import type { RootState } from '../modules'; - const previewStyles = css({ display: 'flex', height: spacing[6] * 3, @@ -30,11 +20,6 @@ const noPreviewStyles = css({ alignItems: 'center', }); -const loadSampleStyles = css({ - width: '100%', - textAlign: 'center', -}); - const noPreviewTextStyles = css({ padding: spacing[3], textAlign: 'center', @@ -42,33 +27,13 @@ const noPreviewTextStyles = css({ width: '100%', }); -function DocumentPreview({ - document, - loadingState, - onLoadSampleClick, -}: { - document?: Record; - loadingState: DOCUMENT_LOADING_STATES; - onLoadSampleClick?: () => void; -}) { +function DocumentPreview({ document }: { document?: Record }) { return ( - {loadingState === 'initial' ? ( - - - - ) : loadingState === 'loading' ? ( - - ) : document ? ( + {document ? ( ) : ( ({ - document: state.sampleDocuments.validDocument, - loadingState: state.sampleDocuments.validDocumentState, - }), - { - onLoadSampleClick: fetchValidDocument, - } -)(DocumentPreview); - -const InvalidDocumentPreview = connect( - (state: RootState) => ({ - document: state.sampleDocuments.invalidDocument, - loadingState: state.sampleDocuments.invalidDocumentState, - }), - { - onLoadSampleClick: fetchInvalidDocument, - } -)(DocumentPreview); - -export { DocumentPreview, ValidDocumentPreview, InvalidDocumentPreview }; +export { DocumentPreview }; diff --git a/packages/compass-schema-validation/src/components/sample-documents.spec.tsx b/packages/compass-schema-validation/src/components/sample-documents.spec.tsx index 7228dab67e1..d476594479a 100644 --- a/packages/compass-schema-validation/src/components/sample-documents.spec.tsx +++ b/packages/compass-schema-validation/src/components/sample-documents.spec.tsx @@ -1,20 +1,46 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { render, screen } from '@mongodb-js/testing-library-compass'; import { expect } from 'chai'; import { SampleDocuments } from './sample-documents'; import { Provider } from 'react-redux'; import { configureStore } from '../stores/store'; +import { INITIAL_STATE } from '../modules'; describe('SampleDocuments [Component]', function () { - it('renders a valid and invalid document preview', function () { + it('initial state : renders the CTA', function () { const store = configureStore({}, {} as any); - const component = mount( + render( ); - expect(component.find('[data-testid="matching-documents"]')).to.exist; - expect(component.find('[data-testid="notmatching-documents"]')).to.exist; + expect(screen.getByRole('button', { name: 'Preview documents' })).to.be + .visible; + }); + + it('non initial state : renders a valid and invalid document preview', function () { + const store = configureStore( + { + ...INITIAL_STATE, + sampleDocuments: { + validDocumentState: 'loading', + invalidDocumentState: 'loading', + validDocument: undefined, + invalidDocument: undefined, + }, + }, + {} as any + ); + render( + + + + ); + + expect(screen.queryByRole('button', { name: 'Preview documents' })).not.to + .exist; + expect(screen.getByTestId('matching-documents')).to.be.visible; + expect(screen.getByTestId('notmatching-documents')).to.be.visible; }); }); diff --git a/packages/compass-schema-validation/src/components/sample-documents.tsx b/packages/compass-schema-validation/src/components/sample-documents.tsx index 972e720ae28..3d0e496a9f1 100644 --- a/packages/compass-schema-validation/src/components/sample-documents.tsx +++ b/packages/compass-schema-validation/src/components/sample-documents.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useMemo } from 'react'; import { Icon, Body, @@ -7,14 +7,14 @@ import { spacing, palette, InlineDefinition, - Subtitle, useDarkMode, + Button, + ButtonVariant, } from '@mongodb-js/compass-components'; -import { SAMPLE_SIZE } from '../modules/sample-documents'; -import { - InvalidDocumentPreview, - ValidDocumentPreview, -} from './document-preview'; +import { fetchSampleDocuments, SAMPLE_SIZE } from '../modules/sample-documents'; +import { DocumentPreview } from './document-preview'; +import { connect } from 'react-redux'; +import type { RootState } from '../modules'; const SAMPLE_DEFINITION = `A sample is fetched from a sample-space of ${SAMPLE_SIZE} randomly selected documents`; @@ -26,6 +26,13 @@ const sampleDocumentsSectionStyles = css({ display: 'flex', flexDirection: 'column', gap: spacing[200], + border: `1px solid ${palette.gray.light2}`, + borderRadius: spacing[200], + padding: spacing[400], +}); + +const sampleDocumentsSectionDarkModeStyles = css({ + border: `1px solid ${palette.gray.dark2}`, }); const sampleDocumentsStyles = css({ @@ -66,47 +73,180 @@ const documentHeadingTextStyles = css({ color: 'inherit', }); -export function SampleDocuments() { +const initialStateContainerStyles = css({ + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + height: '228px', // using the same space as the previews + gap: spacing[300], +}); + +const previewHeaderStyles = css({ + fontSize: spacing[400], + fontWeight: 'bold', + color: palette.green.dark2, + marginTop: spacing[200], +}); + +const previewHeaderDarkModeStyles = css({ + color: palette.green.light2, +}); + +const DocumentGraphic: React.FunctionComponent = () => { const darkMode = useDarkMode(); + const fillColor = useMemo( + () => (darkMode ? palette.green.light1 : palette.green.base), + [darkMode] + ); + const strokeColor = useMemo( + () => (darkMode ? palette.white : palette.black), + [darkMode] + ); + return ( -
- + + + + + + + + ); +}; + +const InitialState: React.FC<{ + onPreviewClick: () => void; +}> = ({ onPreviewClick }) => { + const darkMode = useDarkMode(); + return ( +
+ +
- Sample documents + Preview sample documents - -
- {/* Documents that match the validation */} -
+
+
+ This section displays one document that passed validation and one that + failed validation. +
+ +
+ ); +}; + +function SampleDocuments({ + validDocument, + invalidDocument, + isInitialState, + fetchSampleDocuments, +}: { + validDocument?: Record; + invalidDocument?: Record; + isInitialState: boolean; + fetchSampleDocuments: () => void; +}) { + const darkMode = useDarkMode(); + + return ( +
+ {isInitialState ? ( + + ) : ( +
+ {/* Documents that match the validation */}
- - Passed validation +
+ + + Passed validation + +
+
- -
- {/* Documents that do not match the validation */} -
+ {/* Documents that do not match the validation */}
- - Failed validation +
+ + + Failed validation + +
+
-
-
+ )}
); } + +const ConnectedSampleDocuments = connect( + (state: RootState) => ({ + validDocument: state.sampleDocuments.validDocument, + invalidDocument: state.sampleDocuments.invalidDocument, + isInitialState: state.sampleDocuments.validDocumentState === 'initial', + }), + { + fetchSampleDocuments, + } +)(SampleDocuments); + +export { ConnectedSampleDocuments as SampleDocuments }; diff --git a/packages/compass-schema-validation/src/modules/sample-documents.spec.ts b/packages/compass-schema-validation/src/modules/sample-documents.spec.ts index ddfdd1e2d29..01b3eae8e45 100644 --- a/packages/compass-schema-validation/src/modules/sample-documents.spec.ts +++ b/packages/compass-schema-validation/src/modules/sample-documents.spec.ts @@ -4,18 +4,17 @@ import reducer, { INITIAL_STATE, CLEAR_SAMPLE_DOCUMENTS, clearSampleDocuments, - fetchingValidDocument, - FETCHING_VALID_DOCUMENT, fetchedValidDocument, FETCHED_VALID_DOCUMENT, - fetchingInvalidDocument, - FETCHING_INVALID_DOCUMENT, fetchedInvalidDocument, FETCHED_INVALID_DOCUMENT, fetchingValidDocumentFailed, FETCHING_INVALID_DOCUMENT_FAILED, fetchingInvalidDocumentFailed, FETCHING_VALID_DOCUMENT_FAILED, + fetchingSampleDocuments, + FETCHING_SAMPLE_DOCUMENTS, + type SampleDocumentState, } from './sample-documents'; const SAMPLE_DOCUMENT = { @@ -31,14 +30,8 @@ describe('sample-documents module', function () { }); it('returns the FETCHING_VALID_DOCUMENT action', function () { - expect(fetchingValidDocument()).to.deep.equal({ - type: FETCHING_VALID_DOCUMENT, - }); - }); - - it('returns the FETCHING_INVALID_DOCUMENT action', function () { - expect(fetchingInvalidDocument()).to.deep.equal({ - type: FETCHING_INVALID_DOCUMENT, + expect(fetchingSampleDocuments()).to.deep.equal({ + type: FETCHING_SAMPLE_DOCUMENTS, }); }); @@ -93,66 +86,74 @@ describe('sample-documents module', function () { }); }); - context('when the action is FETCHING_VALID_DOCUMENT', function () { + context('when the action is FETCHING_SAMPLE_DOCUMENTS', function () { it('returns a loading state', function () { - const sampleDocuments = reducer(undefined, fetchingValidDocument()); + const sampleDocuments = reducer(undefined, fetchingSampleDocuments()); expect(sampleDocuments.validDocumentState).to.equal('loading'); - }); - }); - - context('when the action is FETCHING_INVALID_DOCUMENT', function () { - it('returns a loading state', function () { - const sampleDocuments = reducer(undefined, fetchingInvalidDocument()); expect(sampleDocuments.invalidDocumentState).to.equal('loading'); }); }); - context('when the action is FETCHED_VALID_DOCUMENT', function () { - it('updates the state with the document', function () { - for (const document of [null, undefined, SAMPLE_DOCUMENT] as any[]) { - const sampleDocuments = reducer( - undefined, - fetchedValidDocument(document) - ); - expect(sampleDocuments.validDocumentState).to.equal('success'); - expect(sampleDocuments.validDocument).to.deep.equal(document); - } + context('fetch results', function () { + let loadingState: SampleDocumentState; + beforeEach(function () { + loadingState = reducer(undefined, fetchingSampleDocuments()); }); - }); - context('when the action is FETCHED_INVALID_DOCUMENT', function () { - it('updates the state with the document', function () { - for (const document of [null, undefined, SAMPLE_DOCUMENT] as any[]) { - const sampleDocuments = reducer( - undefined, - fetchedInvalidDocument(document) - ); - expect(sampleDocuments.invalidDocumentState).to.equal('success'); - expect(sampleDocuments.invalidDocument).to.deep.equal(document); - } + context('when the action is FETCHED_VALID_DOCUMENT', function () { + it('updates the state with the document', function () { + for (const document of [null, undefined, SAMPLE_DOCUMENT] as any[]) { + const sampleDocuments = reducer( + loadingState, + fetchedValidDocument(document) + ); + expect(sampleDocuments.validDocumentState).to.equal('success'); + expect(sampleDocuments.validDocument).to.deep.equal(document); + expect(sampleDocuments.invalidDocumentState).to.equal('loading'); + } + }); }); - }); - context('when the action is FETCHING_VALID_DOCUMENT_FAILED', function () { - it('updates an error state', function () { - const sampleDocuments = reducer( - undefined, - fetchingValidDocumentFailed() - ); - expect(sampleDocuments.validDocumentState).to.equal('error'); - expect(sampleDocuments.validDocument).to.equal(undefined); + context('when the action is FETCHED_INVALID_DOCUMENT', function () { + it('updates the invalid document state', function () { + for (const document of [null, undefined, SAMPLE_DOCUMENT] as any[]) { + const sampleDocuments = reducer( + loadingState, + fetchedInvalidDocument(document) + ); + expect(sampleDocuments.invalidDocumentState).to.equal('success'); + expect(sampleDocuments.invalidDocument).to.deep.equal(document); + expect(sampleDocuments.validDocumentState).to.equal('loading'); + } + }); }); - }); - context('when the action is FETCHING_INVALID_DOCUMENT_FAILED', function () { - it('updates an error state', function () { - const sampleDocuments = reducer( - undefined, - fetchingInvalidDocumentFailed() - ); - expect(sampleDocuments.invalidDocumentState).to.equal('error'); - expect(sampleDocuments.invalidDocument).to.deep.equal(undefined); + context('when the action is FETCHING_VALID_DOCUMENT_FAILED', function () { + it('updates an error state', function () { + const sampleDocuments = reducer( + loadingState, + fetchingValidDocumentFailed() + ); + expect(sampleDocuments.validDocumentState).to.equal('error'); + expect(sampleDocuments.validDocument).to.equal(undefined); + expect(sampleDocuments.invalidDocumentState).to.equal('loading'); + }); }); + + context( + 'when the action is FETCHING_INVALID_DOCUMENT_FAILED', + function () { + it('updates an error state', function () { + const sampleDocuments = reducer( + loadingState, + fetchingInvalidDocumentFailed() + ); + expect(sampleDocuments.invalidDocumentState).to.equal('error'); + expect(sampleDocuments.invalidDocument).to.deep.equal(undefined); + expect(sampleDocuments.validDocumentState).to.equal('loading'); + }); + } + ); }); }); }); diff --git a/packages/compass-schema-validation/src/modules/sample-documents.ts b/packages/compass-schema-validation/src/modules/sample-documents.ts index 5dbaab7ea8d..b018d7ba651 100644 --- a/packages/compass-schema-validation/src/modules/sample-documents.ts +++ b/packages/compass-schema-validation/src/modules/sample-documents.ts @@ -8,19 +8,22 @@ export const SAMPLE_SIZE = 10000; /** * Initial state */ -export type DOCUMENT_LOADING_STATES = - | 'initial' - | 'loading' - | 'success' - | 'error'; +export type DOCUMENT_LOADING_STATES = 'loading' | 'success' | 'error'; -export interface SampleDocumentState { - validDocumentState: DOCUMENT_LOADING_STATES; - validDocument: undefined | Record; +type InitialState = { + validDocumentState: 'initial'; + invalidDocumentState: 'initial'; +}; +type LoadingState = { + validDocumentState: DOCUMENT_LOADING_STATES; invalidDocumentState: DOCUMENT_LOADING_STATES; +}; + +export type SampleDocumentState = { + validDocument: undefined | Record; invalidDocument: undefined | Record; -} +} & (InitialState | LoadingState); export const INITIAL_STATE: SampleDocumentState = { validDocumentState: 'initial', @@ -39,10 +42,10 @@ interface ClearSampleDocumentsAction { type: typeof CLEAR_SAMPLE_DOCUMENTS; } -export const FETCHING_VALID_DOCUMENT = - 'validation/namespace/FETCHING_VALID_DOCUMENT' as const; -interface FetchingValidDocumentAction { - type: typeof FETCHING_VALID_DOCUMENT; +export const FETCHING_SAMPLE_DOCUMENTS = + 'validation/namespace/FETCHING_SAMPLE_DOCUMENTS' as const; +interface FetchingSampleDocumentsAction { + type: typeof FETCHING_SAMPLE_DOCUMENTS; } export const FETCHED_VALID_DOCUMENT = @@ -58,12 +61,6 @@ interface FetchingValidDocumentFailedAction { type: typeof FETCHING_VALID_DOCUMENT_FAILED; } -export const FETCHING_INVALID_DOCUMENT = - 'validation/namespace/FETCHING_INVALID_DOCUMENT' as const; -interface FetchingInvalidDocumentAction { - type: typeof FETCHING_INVALID_DOCUMENT; -} - export const FETCHED_INVALID_DOCUMENT = 'validation/namespace/FETCHED_INVALID_DOCUMENT' as const; interface FetchedInvalidDocumentAction { @@ -77,16 +74,17 @@ interface FetchingInvalidDocumentFailedAction { type: typeof FETCHING_INVALID_DOCUMENT_FAILED; } -export type SampleDocumentAction = +type SampleDocumentNonInitialAction = | ClearSampleDocumentsAction - | FetchingValidDocumentAction | FetchedValidDocumentAction - | FetchingValidDocumentAction - | FetchingInvalidDocumentAction | FetchedInvalidDocumentAction | FetchingInvalidDocumentFailedAction | FetchingValidDocumentFailedAction; +export type SampleDocumentAction = + | SampleDocumentNonInitialAction + | FetchingSampleDocumentsAction; + /** * Action creators */ @@ -95,12 +93,8 @@ export const clearSampleDocuments = (): ClearSampleDocumentsAction => ({ type: CLEAR_SAMPLE_DOCUMENTS, }); -export const fetchingValidDocument = (): FetchingValidDocumentAction => ({ - type: FETCHING_VALID_DOCUMENT, -}); - -export const fetchingInvalidDocument = (): FetchingInvalidDocumentAction => ({ - type: FETCHING_INVALID_DOCUMENT, +export const fetchingSampleDocuments = (): FetchingSampleDocumentsAction => ({ + type: FETCHING_SAMPLE_DOCUMENTS, }); export const fetchedValidDocument = ( @@ -133,22 +127,16 @@ export const fetchingInvalidDocumentFailed = export const clearingSampleDocuments = (): SampleDocumentState => INITIAL_STATE; -export const startFetchingValidDocument = ( +export const startFetchingSampleDocuments = ( state: SampleDocumentState ): SampleDocumentState => ({ ...state, validDocumentState: 'loading', -}); - -export const startFetchingInvalidDocument = ( - state: SampleDocumentState -): SampleDocumentState => ({ - ...state, invalidDocumentState: 'loading', }); export const updateStateWithFetchedValidDocument = ( - state: SampleDocumentState, + state: SampleDocumentState & LoadingState, action: FetchedValidDocumentAction ): SampleDocumentState => ({ ...state, @@ -157,7 +145,7 @@ export const updateStateWithFetchedValidDocument = ( }); export const updateStateWithFetchedInvalidDocument = ( - state: SampleDocumentState, + state: SampleDocumentState & LoadingState, action: FetchedInvalidDocumentAction ): SampleDocumentState => ({ ...state, @@ -166,7 +154,7 @@ export const updateStateWithFetchedInvalidDocument = ( }); export const validDocumentFetchErrored = ( - state: SampleDocumentState + state: SampleDocumentState & LoadingState ): SampleDocumentState => ({ ...state, validDocumentState: 'error', @@ -174,24 +162,22 @@ export const validDocumentFetchErrored = ( }); export const invalidDocumentFetchErrored = ( - state: SampleDocumentState + state: SampleDocumentState & LoadingState ): SampleDocumentState => ({ ...state, invalidDocumentState: 'error', invalidDocument: undefined, }); -const ACTION_TO_REDUCER_MAPPINGS: { - [Type in SampleDocumentAction['type']]: ( - state: SampleDocumentState, - action: SampleDocumentAction & { type: Type } +const LOADING_ACTION_TO_REDUCER_MAPPINGS: { + [Type in SampleDocumentNonInitialAction['type']]: ( + state: SampleDocumentState & LoadingState, + action: SampleDocumentNonInitialAction & { type: Type } ) => SampleDocumentState; } = { [CLEAR_SAMPLE_DOCUMENTS]: clearingSampleDocuments, - [FETCHING_VALID_DOCUMENT]: startFetchingValidDocument, [FETCHED_VALID_DOCUMENT]: updateStateWithFetchedValidDocument, [FETCHING_VALID_DOCUMENT_FAILED]: validDocumentFetchErrored, - [FETCHING_INVALID_DOCUMENT]: startFetchingInvalidDocument, [FETCHED_INVALID_DOCUMENT]: updateStateWithFetchedInvalidDocument, [FETCHING_INVALID_DOCUMENT_FAILED]: invalidDocumentFetchErrored, }; @@ -200,8 +186,14 @@ export default function ( state: SampleDocumentState = INITIAL_STATE, action: RootAction ): SampleDocumentState { - const fn = - ACTION_TO_REDUCER_MAPPINGS[action.type as SampleDocumentAction['type']]; + let fn; + if (state.validDocumentState !== 'initial') { + fn = + LOADING_ACTION_TO_REDUCER_MAPPINGS[ + action.type as SampleDocumentNonInitialAction['type'] + ]; + } else if (action.type === FETCHING_SAMPLE_DOCUMENTS) + fn = startFetchingSampleDocuments; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore-error TS does not understand that action can be passed to fn @@ -232,11 +224,12 @@ const getSampleDocuments = async ({ return await dataService.aggregate(namespace, pipeline, aggOptions); }; -export const fetchValidDocument = (): SchemaValidationThunkAction< - Promise +export const fetchSampleDocuments = (): SchemaValidationThunkAction< + void, + FetchingSampleDocumentsAction > => { - return async (dispatch, getState, { preferences, dataService }) => { - dispatch(fetchingValidDocument()); + return (dispatch, getState) => { + dispatch(fetchingSampleDocuments()); const state = getState(); const namespace = state.namespace.ns; @@ -247,6 +240,22 @@ export const fetchValidDocument = (): SchemaValidationThunkAction< checkedValidator.validator as string ).validator; + void dispatch(fetchValidDocument({ namespace, query })); + void dispatch(fetchInvalidDocument({ namespace, query })); + }; +}; + +const fetchValidDocument = ({ + namespace, + query, +}: { + namespace: string; + query: string | Record; +}): SchemaValidationThunkAction< + Promise, + FetchedValidDocumentAction | FetchingValidDocumentFailedAction +> => { + return async (dispatch, getState, { preferences, dataService }) => { try { const valid = ( await getSampleDocuments({ @@ -264,22 +273,17 @@ export const fetchValidDocument = (): SchemaValidationThunkAction< }; }; -export const fetchInvalidDocument = (): SchemaValidationThunkAction< - Promise +const fetchInvalidDocument = ({ + namespace, + query, +}: { + namespace: string; + query: string | Record; +}): SchemaValidationThunkAction< + Promise, + FetchedInvalidDocumentAction | FetchingInvalidDocumentFailedAction > => { return async (dispatch, getState, { preferences, dataService }) => { - dispatch(fetchingInvalidDocument()); - - const state = getState(); - const namespace = state.namespace.ns; - const validator = state.validation.validator; - - // Calling checkValidator twice here seems wrong - const checkedValidator = checkValidator(validator); - const query = checkValidator( - checkedValidator.validator as string - ).validator; - try { const invalid = ( await getSampleDocuments({ diff --git a/packages/compass-schema-validation/src/stores/store.spec.ts b/packages/compass-schema-validation/src/stores/store.spec.ts index 598b1f1ba48..3c9154385cb 100644 --- a/packages/compass-schema-validation/src/stores/store.spec.ts +++ b/packages/compass-schema-validation/src/stores/store.spec.ts @@ -9,10 +9,7 @@ import { validationActionChanged, validationLevelChanged, } from '../modules/validation'; -import { - fetchValidDocument, - fetchInvalidDocument, -} from '../modules/sample-documents'; +import { fetchSampleDocuments } from '../modules/sample-documents'; import { stringify as javascriptStringify } from 'javascript-stringify'; import type { Store } from 'redux'; import type { RootAction, RootState } from '../modules'; @@ -157,7 +154,7 @@ describe('Schema Validation Store', function () { }); }); - context('when the action is fetch valid sample documents', function () { + context('when the action is fetch sample documents', function () { it('updates the sample document loading in state', function (done) { expect(store.getState().sampleDocuments.validDocumentState).to.equal( 'initial' @@ -167,25 +164,12 @@ describe('Schema Validation Store', function () { expect(store.getState().sampleDocuments.validDocumentState).to.equal( 'loading' ); - done(); - }); - store.dispatch(fetchValidDocument() as any); - }); - }); - - context('when the action is fetch invalid sample documents', function () { - it('updates the sample document loading in state', function (done) { - expect(store.getState().sampleDocuments.invalidDocumentState).to.equal( - 'initial' - ); - const unsubscribe = store.subscribe(() => { - unsubscribe(); expect( store.getState().sampleDocuments.invalidDocumentState ).to.equal('loading'); done(); }); - store.dispatch(fetchInvalidDocument() as any); + store.dispatch(fetchSampleDocuments() as any); }); });