Skip to content

Commit

Permalink
feat(schema-validation): add confirmation modal when applying rules, …
Browse files Browse the repository at this point in the history
…add explicit editing state COMPASS-8861 (#6766)
  • Loading branch information
Anemy authored Mar 5, 2025
1 parent e8e0f6e commit dad404d
Show file tree
Hide file tree
Showing 13 changed files with 232 additions and 122 deletions.
3 changes: 3 additions & 0 deletions packages/compass-e2e-tests/helpers/commands/set-validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ export async function setValidation(

await browser.clickVisible(Selectors.UpdateValidationButton);

// Confirm in the confirmation modal.
await browser.clickVisible(Selectors.confirmationModalConfirmButton());

// both buttons should become hidden if it succeeds
await validationActionMessageElement.waitForDisplayed({
reverse: true,
Expand Down
2 changes: 2 additions & 0 deletions packages/compass-e2e-tests/helpers/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1144,6 +1144,8 @@ export const UnhideIndexButton = '[data-testid="index-actions-unhide-action"]';

// Validation tab
export const AddRuleButton = '[data-testid="add-rule-button"]';
export const EnableEditValidationButton =
'[data-testid="enable-edit-validation-button"]';
export const ValidationEditor = '[data-testid="validation-editor"]';
export const ValidationActionMessage =
'[data-testid="validation-action-message"]';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,14 @@ describe('Collection validation tab', function () {
);
});

// Reset the validation again to make everything valid for future tests
const enableUpdateValidationButtonElement = browser.$(
Selectors.EnableEditValidationButton
);
// Enable the editing mode and wait for it to be enabled.
await browser.clickVisible(enableUpdateValidationButtonElement);
await enableUpdateValidationButtonElement.waitForDisplayed({
reverse: true,
});

// the automatic indentation and brackets makes multi-line values very fiddly here
await browser.setValidation(PASSING_VALIDATOR);
Expand Down
9 changes: 9 additions & 0 deletions packages/compass-editor/src/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,14 @@ const disabledContainerDarkModeStyles = css({
boxShadow: `0 0 0 1px ${palette.gray.dark2}`,
});

const readOnlyStyle = css({
// We hide the blinking cursor in read only mode
// as it can appear to users like the editor is editable.
'& .cm-cursor': {
display: 'none !important',
},
});

const hiddenScrollStyle = css({
'& .cm-scroller': {
overflow: '-moz-scrollbars-none',
Expand Down Expand Up @@ -1204,6 +1212,7 @@ const BaseEditor = React.forwardRef<EditorRef, EditorProps>(function BaseEditor(
className={cx(
disabled && disabledContainerStyles,
disabled && darkMode && disabledContainerDarkModeStyles,
readOnly && readOnlyStyle,
className
)}
style={{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,88 +1,94 @@
import React from 'react';
import { render, screen } from '@mongodb-js/testing-library-compass';
import { render, screen, userEvent } from '@mongodb-js/testing-library-compass';
import { expect } from 'chai';
import sinon from 'sinon';
import { ValidationEditor } from './validation-editor';

function renderValidationEditor(
props: Partial<React.ComponentProps<typeof ValidationEditor>>
) {
const validation = {
validator: '',
validationAction: 'warn',
validationLevel: 'moderate',
isChanged: false,
syntaxError: null,
error: null,
} as const;

return render(
<ValidationEditor
namespace="test.test"
validatorChanged={() => {}}
validationActionChanged={() => {}}
validationLevelChanged={() => {}}
cancelValidation={() => {}}
saveValidation={() => {}}
clearSampleDocuments={() => {}}
serverVersion="8.0.5"
onClickEnableEditRules={() => {}}
validation={validation}
isEditable
isEditingEnabled
{...props}
/>
);
}

describe('ValidationEditor [Component]', function () {
context('when it is an editable mode', function () {
const setValidatorChangedSpy = sinon.spy();
const setValidationActionChangedSpy = sinon.spy();
const setValidationLevelChangedSpy = sinon.spy();
const setCancelValidationSpy = sinon.spy();
const saveValidationSpy = sinon.spy();
const clearSampleDocumentsSpy = sinon.spy();
const serverVersion = '3.6.0';
const validation = {
validator: '',
validationAction: 'warn',
validationLevel: 'moderate',
isChanged: false,
syntaxError: null,
error: null,
} as const;
const isEditable = true;
context(
'when it is an editable mode but editing is not yet enabled',
function () {
let onClickEnableEditRulesSpy: sinon.SinonSpy;
beforeEach(function () {
onClickEnableEditRulesSpy = sinon.spy();
renderValidationEditor({
onClickEnableEditRules: onClickEnableEditRulesSpy,
isEditingEnabled: false,
isEditable: true,
});
});

it('does not allow to edit the editor', function () {
expect(screen.getByTestId('validation-editor')).to.exist;
expect(screen.getByRole('textbox').ariaReadOnly).to.eq('true');
expect(screen.getByTestId('enable-edit-validation-button')).to.be
.visible;
expect(onClickEnableEditRulesSpy).to.not.have.been.called;
userEvent.click(screen.getByTestId('enable-edit-validation-button'));
expect(onClickEnableEditRulesSpy).to.have.been.calledOnce;
});
}
);

context('when it is an editable mode and editing is enabled', function () {
beforeEach(function () {
render(
<ValidationEditor
namespace="test.test"
validatorChanged={setValidatorChangedSpy}
validationActionChanged={setValidationActionChangedSpy}
validationLevelChanged={setValidationLevelChangedSpy}
cancelValidation={setCancelValidationSpy}
saveValidation={saveValidationSpy}
clearSampleDocuments={clearSampleDocumentsSpy}
serverVersion={serverVersion}
validation={validation}
isEditable={isEditable}
/>
);
renderValidationEditor({
isEditable: true,
isEditingEnabled: true,
});
});

it('allows to edit the editor', function () {
expect(screen.getByTestId('validation-editor')).to.exist;
expect(screen.getByRole('textbox').ariaReadOnly).to.eq(null);
expect(
screen.queryByTestId('enable-edit-validation-button')
).to.not.exist;
});
});

context('when it is a not editable mode', function () {
const setValidatorChangedSpy = sinon.spy();
const setValidationActionChangedSpy = sinon.spy();
const setValidationLevelChangedSpy = sinon.spy();
const setCancelValidationSpy = sinon.spy();
const saveValidationSpy = sinon.spy();
const clearSampleDocumentsSpy = sinon.spy();
const serverVersion = '3.6.0';
const validation = {
validator: '',
validationAction: 'warn',
validationLevel: 'moderate',
isChanged: false,
syntaxError: null,
error: null,
} as const;
const isEditable = false;

beforeEach(function () {
render(
<ValidationEditor
namespace="test.test"
validatorChanged={setValidatorChangedSpy}
validationActionChanged={setValidationActionChangedSpy}
validationLevelChanged={setValidationLevelChangedSpy}
cancelValidation={setCancelValidationSpy}
saveValidation={saveValidationSpy}
clearSampleDocuments={clearSampleDocumentsSpy}
serverVersion={serverVersion}
validation={validation}
isEditable={isEditable}
/>
);
renderValidationEditor({
isEditable: false,
});
});

it('sets editor into readonly mode', function () {
expect(screen.getByRole('textbox').ariaReadOnly).to.eq('true');
expect(
screen.queryByTestId('enable-edit-validation-button')
).to.not.exist;
});
});
});
Loading

0 comments on commit dad404d

Please sign in to comment.