Skip to content

Commit 1e7d058

Browse files
authored
feat(compass-collection): Add mock data generator modal container CLOUD-333848 (#7156)
1 parent 93dfcf1 commit 1e7d058

File tree

6 files changed

+323
-0
lines changed

6 files changed

+323
-0
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { MockDataGeneratorStep } from './types';
2+
3+
export const StepButtonLabelMap = {
4+
[MockDataGeneratorStep.AI_DISCLAIMER]: 'Use Natural Language',
5+
[MockDataGeneratorStep.SCHEMA_CONFIRMATION]: 'Confirm',
6+
[MockDataGeneratorStep.SCHEMA_EDITOR]: 'Next',
7+
[MockDataGeneratorStep.DOCUMENT_COUNT]: 'Next',
8+
[MockDataGeneratorStep.PREVIEW_DATA]: 'Generate Script',
9+
[MockDataGeneratorStep.GENERATE_DATA]: 'Done',
10+
} as const;
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { expect } from 'chai';
2+
import React from 'react';
3+
import { render, screen } from '@mongodb-js/testing-library-compass';
4+
import Sinon from 'sinon';
5+
import MockDataGeneratorModal from './mock-data-generator-modal';
6+
import { MockDataGeneratorStep } from './types';
7+
import { StepButtonLabelMap } from './constants';
8+
9+
describe('MockDataGeneratorModal', () => {
10+
const sandbox = Sinon.createSandbox();
11+
let onOpenChange: Sinon.SinonSpy;
12+
13+
beforeEach(() => {
14+
onOpenChange = sandbox.spy();
15+
});
16+
17+
afterEach(() => {
18+
sandbox.restore();
19+
});
20+
21+
function renderModal({
22+
isOpen = true,
23+
currentStep = MockDataGeneratorStep.AI_DISCLAIMER,
24+
} = {}) {
25+
function MockDataGeneratorModalWrapper() {
26+
const [currentStepStateMock, onCurrentStepChangeStateMock] =
27+
React.useState<MockDataGeneratorStep>(currentStep);
28+
return (
29+
<MockDataGeneratorModal
30+
isOpen={isOpen}
31+
onOpenChange={onOpenChange}
32+
currentStep={currentStepStateMock}
33+
onCurrentStepChange={(step) => {
34+
onCurrentStepChangeStateMock(step);
35+
}}
36+
/>
37+
);
38+
}
39+
return render(<MockDataGeneratorModalWrapper />);
40+
}
41+
42+
it('renders the modal when isOpen is true', () => {
43+
renderModal();
44+
45+
expect(screen.getByTestId('generate-mock-data-modal')).to.exist;
46+
});
47+
48+
it('does not render the modal when isOpen is false', () => {
49+
renderModal({ isOpen: false });
50+
51+
expect(screen.queryByTestId('generate-mock-data-modal')).to.not.exist;
52+
});
53+
54+
it('calls onOpenChange(false) when the modal is closed', () => {
55+
renderModal();
56+
57+
screen.getByLabelText('Close modal').click();
58+
59+
expect(onOpenChange.calledOnceWith(false)).to.be.true;
60+
});
61+
62+
it('calls onOpenChange(false) when the cancel button is clicked', () => {
63+
renderModal();
64+
65+
screen.getByText('Cancel').click();
66+
67+
expect(onOpenChange.calledOnceWith(false)).to.be.true;
68+
});
69+
70+
it('disables the Back button on the first step', () => {
71+
renderModal();
72+
73+
expect(
74+
screen.getByRole('button', { name: 'Back' }).getAttribute('aria-disabled')
75+
).to.equal('true');
76+
});
77+
78+
describe('when rendering the modal in a specific step', () => {
79+
const steps = Object.keys(
80+
StepButtonLabelMap
81+
) as unknown as MockDataGeneratorStep[];
82+
83+
steps.forEach((currentStep) => {
84+
it(`renders the button with the correct label when the user is in step "${currentStep}"`, () => {
85+
renderModal({ currentStep });
86+
expect(screen.getByTestId('next-step-button')).to.have.text(
87+
StepButtonLabelMap[currentStep]
88+
);
89+
});
90+
});
91+
});
92+
});
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import React from 'react';
2+
3+
import {
4+
css,
5+
ModalBody,
6+
ModalHeader,
7+
spacing,
8+
} from '@mongodb-js/compass-components';
9+
10+
import {
11+
Button,
12+
Modal,
13+
ModalFooter,
14+
ButtonVariant,
15+
} from '@mongodb-js/compass-components';
16+
import { MockDataGeneratorStep } from './types';
17+
import { StepButtonLabelMap } from './constants';
18+
import { getNextStep, getPreviousStep } from './utils';
19+
20+
const footerStyles = css`
21+
flex-direction: row;
22+
justify-content: space-between;
23+
`;
24+
25+
const rightButtonsStyles = css`
26+
display: flex;
27+
gap: ${spacing[200]}px;
28+
flex-direction: row;
29+
`;
30+
31+
interface Props {
32+
isOpen: boolean;
33+
onOpenChange: (isOpen: boolean) => void;
34+
currentStep: MockDataGeneratorStep;
35+
onCurrentStepChange: (step: MockDataGeneratorStep) => void;
36+
}
37+
38+
const MockDataGeneratorModal = ({
39+
isOpen,
40+
onOpenChange,
41+
currentStep,
42+
onCurrentStepChange,
43+
}: Props) => {
44+
const onNext = () => {
45+
const nextStep = getNextStep(currentStep);
46+
onCurrentStepChange(nextStep);
47+
};
48+
49+
const onBack = () => {
50+
const previousStep = getPreviousStep(currentStep);
51+
onCurrentStepChange(previousStep);
52+
};
53+
54+
const onCancel = () => {
55+
onOpenChange(false);
56+
};
57+
58+
return (
59+
<Modal
60+
open={isOpen}
61+
setOpen={(open) => onOpenChange(open)}
62+
data-testid="generate-mock-data-modal"
63+
>
64+
<ModalHeader title="Generate Mock Data" />
65+
<ModalBody>
66+
{/* TODO: Render actual step content here based on currentStep. (CLOUDP-333851) */}
67+
<div data-testid={`generate-mock-data-step-${currentStep}`} />
68+
</ModalBody>
69+
<ModalFooter className={footerStyles}>
70+
<Button
71+
onClick={onBack}
72+
disabled={currentStep === MockDataGeneratorStep.AI_DISCLAIMER}
73+
>
74+
Back
75+
</Button>
76+
<div className={rightButtonsStyles}>
77+
<Button onClick={onCancel}>Cancel</Button>
78+
<Button
79+
variant={ButtonVariant.Primary}
80+
onClick={onNext}
81+
data-testid="next-step-button"
82+
>
83+
{StepButtonLabelMap[currentStep]}
84+
</Button>
85+
</div>
86+
</ModalFooter>
87+
</Modal>
88+
);
89+
};
90+
91+
export default MockDataGeneratorModal;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export enum MockDataGeneratorStep {
2+
AI_DISCLAIMER = 'AI_DISCLAIMER',
3+
SCHEMA_CONFIRMATION = 'SCHEMA_CONFIRMATION',
4+
SCHEMA_EDITOR = 'SCHEMA_EDITOR',
5+
DOCUMENT_COUNT = 'DOCUMENT_COUNT',
6+
PREVIEW_DATA = 'PREVIEW_DATA',
7+
GENERATE_DATA = 'GENERATE_DATA',
8+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { expect } from 'chai';
2+
import { getNextStep, getPreviousStep } from './utils';
3+
import { MockDataGeneratorStep } from './types';
4+
5+
describe('Mock Data Generator Modal Utils', () => {
6+
describe('getNextStep', () => {
7+
it('should go from AI_DISCLAIMER to SCHEMA_CONFIRMATION', () => {
8+
expect(getNextStep(MockDataGeneratorStep.AI_DISCLAIMER)).to.equal(
9+
MockDataGeneratorStep.SCHEMA_CONFIRMATION
10+
);
11+
});
12+
13+
it('should go from SCHEMA_CONFIRMATION to SCHEMA_EDITOR', () => {
14+
expect(getNextStep(MockDataGeneratorStep.SCHEMA_CONFIRMATION)).to.equal(
15+
MockDataGeneratorStep.SCHEMA_EDITOR
16+
);
17+
});
18+
19+
it('should go from SCHEMA_EDITOR to DOCUMENT_COUNT', () => {
20+
expect(getNextStep(MockDataGeneratorStep.SCHEMA_EDITOR)).to.equal(
21+
MockDataGeneratorStep.DOCUMENT_COUNT
22+
);
23+
});
24+
25+
it('should go from DOCUMENT_COUNT to PREVIEW_DATA', () => {
26+
expect(getNextStep(MockDataGeneratorStep.DOCUMENT_COUNT)).to.equal(
27+
MockDataGeneratorStep.PREVIEW_DATA
28+
);
29+
});
30+
31+
it('should go from PREVIEW_DATA to GENERATE_DATA', () => {
32+
expect(getNextStep(MockDataGeneratorStep.PREVIEW_DATA)).to.equal(
33+
MockDataGeneratorStep.GENERATE_DATA
34+
);
35+
});
36+
37+
it('should stay on GENERATE_DATA if already at GENERATE_DATA', () => {
38+
expect(getNextStep(MockDataGeneratorStep.GENERATE_DATA)).to.equal(
39+
MockDataGeneratorStep.GENERATE_DATA
40+
);
41+
});
42+
});
43+
44+
describe('getPreviousStep', () => {
45+
it('should stay on AI_DISCLAIMER if already at AI_DISCLAIMER', () => {
46+
expect(getPreviousStep(MockDataGeneratorStep.AI_DISCLAIMER)).to.equal(
47+
MockDataGeneratorStep.AI_DISCLAIMER
48+
);
49+
});
50+
51+
it('should go from SCHEMA_CONFIRMATION to AI_DISCLAIMER', () => {
52+
expect(
53+
getPreviousStep(MockDataGeneratorStep.SCHEMA_CONFIRMATION)
54+
).to.equal(MockDataGeneratorStep.AI_DISCLAIMER);
55+
});
56+
57+
it('should go from SCHEMA_EDITOR to SCHEMA_CONFIRMATION', () => {
58+
expect(getPreviousStep(MockDataGeneratorStep.SCHEMA_EDITOR)).to.equal(
59+
MockDataGeneratorStep.SCHEMA_CONFIRMATION
60+
);
61+
});
62+
63+
it('should go from DOCUMENT_COUNT to SCHEMA_EDITOR', () => {
64+
expect(getPreviousStep(MockDataGeneratorStep.DOCUMENT_COUNT)).to.equal(
65+
MockDataGeneratorStep.SCHEMA_EDITOR
66+
);
67+
});
68+
69+
it('should go from PREVIEW_DATA to DOCUMENT_COUNT', () => {
70+
expect(getPreviousStep(MockDataGeneratorStep.PREVIEW_DATA)).to.equal(
71+
MockDataGeneratorStep.DOCUMENT_COUNT
72+
);
73+
});
74+
75+
it('should go from GENERATE_DATA to PREVIEW_DATA', () => {
76+
expect(getPreviousStep(MockDataGeneratorStep.GENERATE_DATA)).to.equal(
77+
MockDataGeneratorStep.PREVIEW_DATA
78+
);
79+
});
80+
});
81+
});
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { MockDataGeneratorStep } from './types';
2+
3+
export const getNextStep = (
4+
currentStep: MockDataGeneratorStep
5+
): MockDataGeneratorStep => {
6+
switch (currentStep) {
7+
case MockDataGeneratorStep.AI_DISCLAIMER:
8+
return MockDataGeneratorStep.SCHEMA_CONFIRMATION;
9+
case MockDataGeneratorStep.SCHEMA_CONFIRMATION:
10+
return MockDataGeneratorStep.SCHEMA_EDITOR;
11+
case MockDataGeneratorStep.SCHEMA_EDITOR:
12+
return MockDataGeneratorStep.DOCUMENT_COUNT;
13+
case MockDataGeneratorStep.DOCUMENT_COUNT:
14+
return MockDataGeneratorStep.PREVIEW_DATA;
15+
case MockDataGeneratorStep.PREVIEW_DATA:
16+
return MockDataGeneratorStep.GENERATE_DATA;
17+
case MockDataGeneratorStep.GENERATE_DATA:
18+
// No next step after data generation
19+
return currentStep;
20+
}
21+
};
22+
23+
export const getPreviousStep = (
24+
currentStep: MockDataGeneratorStep
25+
): MockDataGeneratorStep => {
26+
switch (currentStep) {
27+
case MockDataGeneratorStep.AI_DISCLAIMER:
28+
// No previous step from AI disclaimer
29+
return currentStep;
30+
case MockDataGeneratorStep.SCHEMA_CONFIRMATION:
31+
return MockDataGeneratorStep.AI_DISCLAIMER;
32+
case MockDataGeneratorStep.SCHEMA_EDITOR:
33+
return MockDataGeneratorStep.SCHEMA_CONFIRMATION;
34+
case MockDataGeneratorStep.DOCUMENT_COUNT:
35+
return MockDataGeneratorStep.SCHEMA_EDITOR;
36+
case MockDataGeneratorStep.PREVIEW_DATA:
37+
return MockDataGeneratorStep.DOCUMENT_COUNT;
38+
case MockDataGeneratorStep.GENERATE_DATA:
39+
return MockDataGeneratorStep.PREVIEW_DATA;
40+
}
41+
};

0 commit comments

Comments
 (0)