diff --git a/packages/compass-components/src/components/collapsible-field-set.tsx b/packages/compass-components/src/components/collapsible-field-set.tsx index dc4a15d67b8..d69542bf2c7 100644 --- a/packages/compass-components/src/components/collapsible-field-set.tsx +++ b/packages/compass-components/src/components/collapsible-field-set.tsx @@ -16,6 +16,10 @@ const collapsibleFieldsetStyles = css({ }, }); +const checkboxStyles = css({ + padding: `${spacing[2]}px 0`, +}); + export type CollapsibleFieldSetProps = { darkMode?: boolean; dataTestId?: string; @@ -73,6 +77,7 @@ const UnthemedCollapsibleFieldSet = ({ checked={toggled} id={labelId} darkMode={darkMode} + className={checkboxStyles} /> {toggled &&
{children}
} diff --git a/packages/compass-indexes/src/components/create-index-actions/create-index-actions.spec.jsx b/packages/compass-indexes/src/components/create-index-actions/create-index-actions.spec.jsx new file mode 100644 index 00000000000..547e10d3f32 --- /dev/null +++ b/packages/compass-indexes/src/components/create-index-actions/create-index-actions.spec.jsx @@ -0,0 +1,224 @@ +import React from 'react'; +import { expect } from 'chai'; +import sinon from 'sinon'; + +import { + render, + screen, + cleanup, + fireEvent, + within, +} from '@testing-library/react'; + +import CreateIndexActions from '../create-index-actions'; + +describe('CreateIndexActions Component', function () { + let toggleIsVisibleSpy; + let clearErrorSpy; + let createIndexSpy; + let resetFormSpy; + + beforeEach(function () { + toggleIsVisibleSpy = sinon.spy(); + clearErrorSpy = sinon.spy(); + createIndexSpy = sinon.spy(); + resetFormSpy = sinon.spy(); + }); + + afterEach(function () { + toggleIsVisibleSpy = null; + clearErrorSpy = null; + createIndexSpy = null; + resetFormSpy = null; + + cleanup(); + }); + + it('renders a cancel button', function () { + render( + + ); + + const button = screen.getByTestId('create-index-actions-cancel-button'); + expect(button.textContent).to.be.equal('Cancel'); + }); + + context('onCancel', function () { + it('calls the toggleIsVisible function', function () { + render( + + ); + + const button = screen.getByTestId('create-index-actions-cancel-button'); + fireEvent.click(button); + expect(toggleIsVisibleSpy).to.have.been.calledWith(false); + }); + + it('calls the resetForm function', function () { + render( + + ); + + const button = screen.getByTestId('create-index-actions-cancel-button'); + fireEvent.click(button); + expect(resetFormSpy).to.have.been.calledOnce; + }); + }); + + context('onConfirm', function () { + it('calls the createIndex function', function () { + render( + + ); + + const button = screen.getByTestId( + 'create-index-actions-create-index-button' + ); + fireEvent.click(button); + expect(createIndexSpy).to.have.been.calledOnce; + }); + }); + + it('renders a create index button', function () { + render( + + ); + + const button = screen.getByTestId( + 'create-index-actions-create-index-button' + ); + expect(button.textContent).to.be.equal('Create Index'); + }); + + context('with error', function () { + it('renders error banner', function () { + render( + + ); + + const errorBanner = screen.getByTestId( + 'create-index-actions-error-banner-wrapper' + ); + expect(errorBanner).to.contain.text('Some error happened!'); + }); + + it('closes error banner', function () { + render( + + ); + + const errorBanner = screen.getByTestId( + 'create-index-actions-error-banner-wrapper' + ); + const closeIcon = within(errorBanner).getByLabelText('X Icon'); + + fireEvent.click(closeIcon); + expect(clearErrorSpy).to.have.been.calledOnce; + }); + + it('does not render in progress banner', function () { + render( + + ); + + const inProgressBanner = screen.queryByTestId( + 'create-index-actions-in-progress-banner-wrapper' + ); + expect(inProgressBanner).to.not.exist; + }); + }); + + context('without error', function () { + it('does not render error banner', function () { + render( + + ); + + const errorBanner = screen.queryByTestId( + 'create-index-actions-error-banner-wrapper' + ); + expect(errorBanner).to.not.exist; + }); + + it('renders in progress banner', function () { + render( + + ); + + const inProgressBanner = screen.getByTestId( + 'create-index-actions-in-progress-banner-wrapper' + ); + expect(inProgressBanner).to.contain.text('Create in Progress'); + }); + }); +}); diff --git a/packages/compass-indexes/src/components/create-index-actions/create-index-actions.tsx b/packages/compass-indexes/src/components/create-index-actions/create-index-actions.tsx new file mode 100644 index 00000000000..e257a20e889 --- /dev/null +++ b/packages/compass-indexes/src/components/create-index-actions/create-index-actions.tsx @@ -0,0 +1,114 @@ +import React from 'react'; +import { + css, + withTheme, + Banner, + spacing, + Button, +} from '@mongodb-js/compass-components'; + +const bannerStyles = css({ + margin: `${spacing[3]}px 0`, +}); + +const createIndexButtonStyles = css({ + marginLeft: spacing[2], +}); + +const modalFooterActionsStyles = css({ + display: 'flex', + justifyContent: 'flex-end', + gap: spacing[2], +}); + +/** + * Create index actions. + */ +function CreateIndexActions({ + darkMode, + toggleIsVisible, + resetForm, + error, + clearError, + inProgress, + createIndex, +}: { + darkMode?: boolean; + toggleIsVisible: (isVisible: boolean) => void; + resetForm: () => void; + error: string | null; + clearError: () => void; + inProgress: boolean; + createIndex: () => void; +}) { + const renderError = () => { + if (!error) { + return; + } + + return ( +
+ + {error} + +
+ ); + }; + + const renderInProgress = () => { + if (error || !inProgress) { + return; + } + + return ( +
+ + Create in Progress + +
+ ); + }; + + const onCancel = () => { + toggleIsVisible(false); + resetForm(); + }; + + const onConfirm = () => { + createIndex(); + }; + + return ( + <> +
+ {renderError()} + {renderInProgress()} +
+
+ + +
+ + ); +} + +export default withTheme(CreateIndexActions); diff --git a/packages/compass-indexes/src/components/create-index-actions/index.ts b/packages/compass-indexes/src/components/create-index-actions/index.ts new file mode 100644 index 00000000000..518f0383b65 --- /dev/null +++ b/packages/compass-indexes/src/components/create-index-actions/index.ts @@ -0,0 +1,3 @@ +import CreateIndexActions from './create-index-actions'; + +export default CreateIndexActions; diff --git a/packages/compass-indexes/src/components/create-index-fields/create-index-fields.spec.tsx b/packages/compass-indexes/src/components/create-index-fields/create-index-fields.spec.tsx index c274732048b..54130772462 100644 --- a/packages/compass-indexes/src/components/create-index-fields/create-index-fields.spec.tsx +++ b/packages/compass-indexes/src/components/create-index-fields/create-index-fields.spec.tsx @@ -48,6 +48,84 @@ describe('CreateIndexFields Component', function () { const fieldTypes = screen.getByTestId('create-index-fields-type-0'); expect(fieldTypes).to.not.contain.html('columnstore'); }); + + it('does not render a minus button for a single field', function () { + render( + + ); + const minusButton = screen.queryByTestId('remove-index-field-button'); + expect(minusButton).to.not.exist; + }); + + it('renders a minus button for more than one field', function () { + render( + + ); + const minusButton = screen.getAllByTestId('remove-index-field-button'); + expect(minusButton.length).to.be.equal(2); + }); + + it('renders a plus button for a single field', function () { + render( + + ); + const minusButton = screen.getAllByTestId('add-index-field-button'); + expect(minusButton.length).to.be.equal(1); + }); + + it('renders a plus button for more than one field', function () { + render( + + ); + const minusButton = screen.getAllByTestId('add-index-field-button'); + expect(minusButton.length).to.be.equal(2); + }); }); describe('server version 6.1.0', function () { diff --git a/packages/compass-indexes/src/components/create-index-form/columnstore-projection.tsx b/packages/compass-indexes/src/components/create-index-form/columnstore-projection.tsx index 33652d1fba8..be412673077 100644 --- a/packages/compass-indexes/src/components/create-index-form/columnstore-projection.tsx +++ b/packages/compass-indexes/src/components/create-index-form/columnstore-projection.tsx @@ -28,6 +28,7 @@ const ColumnstoreProjectionCollapsibleFieldSet = ({ > + ); + }); + + after(function () { + resetSpyComponentProps(); + cleanup(); + }); + + it('calls the collationStringChanged function', function () { + const createIndexOptions = screen.getByTestId( + 'create-index-modal-toggle-options' + ); + fireEvent.click(createIndexOptions); + const editorWrapper = screen.getByTestId( + 'create-index-modal-use-custom-collation-editor' + ); + + const editor = within(editorWrapper).getByRole('textbox'); + + screen.debug(editor); + + userEvent.paste(editor, '{}'); + + expect(collationStringChangedSpy).to.have.been.calledWith('{}'); + }); + }); + context('with partial filter expression', function () { before(function () { spyComponentProps(); @@ -409,15 +486,89 @@ describe('CreateIndexForm Component', function () { 'create-index-modal-toggle-options' ); fireEvent.click(createIndexOptions); - const input = screen.getByTestId('create-index-modal-is-pfe-input'); - fireEvent.change(input, { target: { value: '{}' } }); + const editorWrapper = screen.getByTestId( + 'create-index-modal-is-pfe-editor' + ); + + const editor = within(editorWrapper).getByRole('textbox'); + + screen.debug(editor); + + userEvent.paste(editor, '{}'); + expect(partialFilterExpressionChangedSpy).to.have.been.calledWith('{}'); }); }); - // TODO: test editors on change event. - context.skip('with custom collation', function () {}); - context.skip('with wildcard projection', function () {}); + context('with wildcard projection', function () { + before(function () { + spyComponentProps(); + render( + + ); + }); + + after(function () { + resetSpyComponentProps(); + cleanup(); + }); + + it('calls the wildcardProjectionChanged function', function () { + const createIndexOptions = screen.getByTestId( + 'create-index-modal-toggle-options' + ); + fireEvent.click(createIndexOptions); + const editorWrapper = screen.getByTestId( + 'create-index-modal-use-wildcard-editor' + ); + + const editor = within(editorWrapper).getByRole('textbox'); + + screen.debug(editor); + + userEvent.paste(editor, '{}'); + + expect(wildcardProjectionChangedSpy).to.have.been.calledWith('{}'); + }); + }); }); describe('server version 6.1.0', function () { @@ -494,6 +645,74 @@ describe('CreateIndexForm Component', function () { }); }); - context.skip('with columnstore projection', function () {}); + context('with columnstore projection', function () { + before(function () { + spyComponentProps(); + render( + + ); + }); + + after(function () { + resetSpyComponentProps(); + cleanup(); + }); + + it('calls the columnstoreProjectionChanged function', function () { + const createIndexOptions = screen.getByTestId( + 'create-index-modal-toggle-options' + ); + fireEvent.click(createIndexOptions); + const editorWrapper = screen.getByTestId( + 'create-index-modal-use-columnstore-editor' + ); + + const editor = within(editorWrapper).getByRole('textbox'); + + screen.debug(editor); + + userEvent.paste(editor, '{}'); + + expect(columnstoreProjectionChangedSpy).to.have.been.calledWith('{}'); + }); + }); }); }); diff --git a/packages/compass-indexes/src/components/create-index-form/create-index-form.tsx b/packages/compass-indexes/src/components/create-index-form/create-index-form.tsx index 23bc22078fe..7e60f4e00ef 100644 --- a/packages/compass-indexes/src/components/create-index-form/create-index-form.tsx +++ b/packages/compass-indexes/src/components/create-index-form/create-index-form.tsx @@ -148,18 +148,18 @@ class CreateIndexForm extends Component { this.props.partialFilterExpressionChanged } /> - + {hasColumnstoreIndexesSupport(this.props.serverVersion) && ( - partialFilterExpressionChanged(e.target.value)} - spellCheck={false} + ); diff --git a/packages/compass-indexes/src/components/create-index-form/wildcard-projection.tsx b/packages/compass-indexes/src/components/create-index-form/wildcard-projection.tsx index 93335b3e5ed..e520f7f6efb 100644 --- a/packages/compass-indexes/src/components/create-index-form/wildcard-projection.tsx +++ b/packages/compass-indexes/src/components/create-index-form/wildcard-projection.tsx @@ -28,6 +28,7 @@ const WildcardProjectionCollapsibleFieldSet = ({ > { - if (!error) { - return; - } - - return ( - - {error} - - ); - }; - - const renderInProgress = () => { - if (error || !inProgress) { - return; - } - - return ( - - Create in Progress - - ); - }; - - const onCancel = () => { - toggleIsVisible(false); - resetForm(); - }; - - const onConfirm = () => { - createIndex(); - }; - return ( -
- {renderError()} - {renderInProgress()} -
-
- - -
+
); diff --git a/packages/compass-indexes/src/modules/create-index/partial-filter-expression.spec.js b/packages/compass-indexes/src/modules/create-index/partial-filter-expression.spec.js index 469c56937ad..aa478ff11d8 100644 --- a/packages/compass-indexes/src/modules/create-index/partial-filter-expression.spec.js +++ b/packages/compass-indexes/src/modules/create-index/partial-filter-expression.spec.js @@ -13,15 +13,15 @@ describe('create index partial filter expression module', function () { expect( reducer( undefined, - partialFilterExpressionChanged({ testkey: 'testvalue' }) + partialFilterExpressionChanged("{ testkey: 'testvalue' }") ) - ).to.deep.equal({ testkey: 'testvalue' }); + ).to.deep.equal("{ testkey: 'testvalue' }"); }); }); context('when an action is not provided', function () { it('returns the default state', function () { - expect(reducer(undefined, {})).to.equal(INITIAL_STATE); + expect(reducer(undefined, { type: 'test' })).to.equal(INITIAL_STATE); }); }); }); @@ -29,10 +29,10 @@ describe('create index partial filter expression module', function () { describe('#partialFilterExpressionChanged', function () { it('returns the action', function () { expect( - partialFilterExpressionChanged({ testkey: 'testvalue' }) + partialFilterExpressionChanged("{ testkey: 'testvalue' }") ).to.deep.equal({ type: PARTIAL_FILTER_EXPRESSION_CHANGED, - partialFilterExpression: { testkey: 'testvalue' }, + partialFilterExpression: "{ testkey: 'testvalue' }", }); }); });