From 8f9d83f9d01eba77edfa93fe26b301c7bdd784c7 Mon Sep 17 00:00:00 2001 From: Jacob Samuel Lu Date: Fri, 8 Aug 2025 11:46:35 -0400 Subject: [PATCH 01/16] WIP --- .../collection-header-actions.spec.tsx | 270 ++++++++++++++++-- .../collection-header-actions.tsx | 58 +++- .../collection-header/collection-header.tsx | 23 +- .../src/growth-experiments.ts | 5 + packages/compass-telemetry/src/index.ts | 2 +- packages/compass-telemetry/src/provider.tsx | 3 +- 6 files changed, 329 insertions(+), 32 deletions(-) diff --git a/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.spec.tsx b/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.spec.tsx index 27edfa32e3d..22668161d53 100644 --- a/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.spec.tsx +++ b/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.spec.tsx @@ -1,6 +1,9 @@ import { expect } from 'chai'; import React, { type ComponentProps } from 'react'; -import { render, screen, cleanup } from '@mongodb-js/testing-library-compass'; +import { + renderWithActiveConnection, + screen, +} from '@mongodb-js/testing-library-compass'; import sinon from 'sinon'; import { WorkspacesServiceProvider, @@ -9,46 +12,83 @@ import { import type { PreferencesAccess } from 'compass-preferences-model'; import { createSandboxFromDefaultPreferences } from 'compass-preferences-model'; import { PreferencesProvider } from 'compass-preferences-model/provider'; +import { + TelemetryProvider, + ExperimentTestName, +} from '@mongodb-js/compass-telemetry/provider'; +import { CompassExperimentationProvider } from '@mongodb-js/compass-telemetry'; +import type { ConnectionInfo } from '@mongodb-js/compass-connections/provider'; import CollectionHeaderActions from '../collection-header-actions'; describe('CollectionHeaderActions [Component]', function () { let preferences: PreferencesAccess; + let mockUseAssignment: sinon.SinonStub; + beforeEach(async function () { preferences = await createSandboxFromDefaultPreferences(); + mockUseAssignment = sinon.stub(); + mockUseAssignment.returns({ + assignment: { + assignmentData: { + variant: 'mockDataGeneratorControl', + }, + }, + }); }); + afterEach(function () { sinon.restore(); }); - const renderCollectionHeaderActions = ( + const renderCollectionHeaderActions = async ( props: Partial> = {}, - workspaceService: Partial = {} + workspaceService: Partial = {}, + connectionInfo?: ConnectionInfo ) => { - return render( - - - - - + const defaultProps = { + namespace: 'test.test', + isReadonly: false, + onOpenMockDataModal: sinon.stub(), + ...props, + }; + + const ui = ( + + + + + + + + + ); + + if (connectionInfo) { + // For tests that need Atlas metadata (Mock Data Generator button visibility, etc.) + return await renderWithActiveConnection(ui, connectionInfo); + } else { + // For tests that only need basic component rendering (readonly checks, view buttons, etc.) + const { render } = await import('@mongodb-js/testing-library-compass'); + return render(ui); + } }; context('when the collection is not readonly', function () { - beforeEach(function () { - renderCollectionHeaderActions({ + beforeEach(async function () { + await renderCollectionHeaderActions({ isReadonly: false, namespace: 'db.coll2', sourceName: 'db.coll', }); }); - afterEach(cleanup); - it('does not render any buttons', function () { expect( screen.queryByTestId('collection-header-actions-edit-button') @@ -63,7 +103,7 @@ describe('CollectionHeaderActions [Component]', function () { it('does not render edit view buttons when in readonly mode', async function () { await preferences.savePreferences({ readOnly: true }); - renderCollectionHeaderActions({ + await renderCollectionHeaderActions({ isReadonly: true, namespace: 'db.coll2', sourceName: 'db.someSource', @@ -78,8 +118,8 @@ describe('CollectionHeaderActions [Component]', function () { ).to.not.exist; }); - it('renders edit view buttons when not in readonly mode', function () { - renderCollectionHeaderActions({ + it('renders edit view buttons when not in readonly mode', async function () { + await renderCollectionHeaderActions({ isReadonly: true, namespace: 'db.coll2', sourceName: 'db.someSource', @@ -94,9 +134,9 @@ describe('CollectionHeaderActions [Component]', function () { context('when the collection is a view', function () { let openEditViewWorkspaceStub: sinon.SinonStub; - beforeEach(function () { + beforeEach(async function () { openEditViewWorkspaceStub = sinon.stub(); - renderCollectionHeaderActions( + await renderCollectionHeaderActions( { isReadonly: true, namespace: 'db.coll2', @@ -109,8 +149,6 @@ describe('CollectionHeaderActions [Component]', function () { ); }); - afterEach(cleanup); - it('shows a button to edit the view pipeline', function () { expect( screen.getByTestId('collection-header-actions-edit-button') @@ -135,9 +173,9 @@ describe('CollectionHeaderActions [Component]', function () { context('when the collection is editing a view', function () { let openCollectionWorkspaceStub: sinon.SinonStub; - beforeEach(function () { + beforeEach(async function () { openCollectionWorkspaceStub = sinon.stub(); - renderCollectionHeaderActions( + await renderCollectionHeaderActions( { isReadonly: false, namespace: 'db.coll2', @@ -149,8 +187,6 @@ describe('CollectionHeaderActions [Component]', function () { ); }); - afterEach(cleanup); - it('shows a button to return to the view', function () { expect( screen.getByTestId('collection-header-actions-return-to-view-button') @@ -168,4 +204,182 @@ describe('CollectionHeaderActions [Component]', function () { ); }); }); + + context('Mock Data Generator Button', function () { + const atlasConnectionInfo: ConnectionInfo = { + id: 'test-atlas-connection', + connectionOptions: { + connectionString: 'mongodb://localhost:27017', + }, + atlasMetadata: { + orgId: 'test-org', + projectId: 'test-project', + clusterName: 'test-cluster', + clusterUniqueId: 'test-cluster-unique-id', + clusterType: 'REPLICASET', + clusterState: 'IDLE', + metricsId: 'test-metrics-id', + metricsType: 'replicaSet', + regionalBaseUrl: null, + instanceSize: 'M10', + supports: { + globalWrites: false, + rollingIndexes: true, + }, + }, + }; + + it('should not show Mock Data Generator button when user is in control group', async function () { + mockUseAssignment.returns({ + assignment: { + assignmentData: { + variant: 'mockDataGeneratorControl', + }, + }, + }); + + await renderCollectionHeaderActions( + { + namespace: 'test.collection', + isReadonly: false, + }, + {}, + atlasConnectionInfo + ); + + expect( + screen.queryByTestId('collection-header-generate-mock-data') + ).to.not.exist; + }); + + it('should not show Mock Data Generator button when not in Atlas', async function () { + mockUseAssignment.returns({ + assignment: { + assignmentData: { + variant: 'treatment', + }, + }, + }); + + await renderCollectionHeaderActions({ + namespace: 'test.collection', + isReadonly: false, + // Don't pass atlasConnectionInfo, to simulate not being in Atlas + }); + + expect( + screen.queryByTestId('collection-header-generate-mock-data') + ).to.not.exist; + }); + + it('should not show Mock Data Generator button for readonly collections', async function () { + mockUseAssignment.returns({ + assignment: { + assignmentData: { + variant: 'treatment', + }, + }, + }); + + await renderCollectionHeaderActions( + { + namespace: 'test.collection', + isReadonly: true, + }, + {}, + atlasConnectionInfo + ); + + expect( + screen.queryByTestId('collection-header-generate-mock-data') + ).to.not.exist; + }); + + it('should not show Mock Data Generator button for views (sourceName present)', async function () { + mockUseAssignment.returns({ + assignment: { + assignmentData: { + variant: 'treatment', + }, + }, + }); + + await renderCollectionHeaderActions( + { + namespace: 'test.collection', + isReadonly: false, + sourceName: 'source-collection', + }, + {}, + atlasConnectionInfo + ); + + expect( + screen.queryByTestId('collection-header-generate-mock-data') + ).to.not.exist; + }); + + it('should show Mock Data Generator button when user is in treatment group and in Atlas', async function () { + mockUseAssignment.returns({ + assignment: { + assignmentData: { + variant: 'mockDataGeneratorVariant', + }, + }, + }); + + await renderCollectionHeaderActions( + { + namespace: 'test.collection', + isReadonly: false, + }, + {}, + atlasConnectionInfo + ); + + expect( + screen.getByTestId('collection-header-generate-mock-data') + ).to.exist; + expect(screen.getByText('Generate Mock Data')).to.exist; + }); + + it('should call useAssignment with correct parameters', async function () { + await renderCollectionHeaderActions({ + namespace: 'test.collection', + isReadonly: false, + }); + + expect(mockUseAssignment).to.have.been.calledWith( + ExperimentTestName.mockDataGenerator, + true // trackIsInSample - Experiment viewed analytics event + ); + }); + + it('should call onOpenMockDataModal when CTA button is clicked', async function () { + const onOpenMockDataModal = sinon.stub(); + + mockUseAssignment.returns({ + assignment: { + assignmentData: { + variant: 'mockDataGeneratorVariant', + }, + }, + }); + + await renderCollectionHeaderActions( + { + namespace: 'test.collection', + isReadonly: false, + onOpenMockDataModal, + }, + {}, + atlasConnectionInfo + ); + + const button = screen.getByTestId('collection-header-generate-mock-data'); + button.click(); + + expect(onOpenMockDataModal).to.have.been.calledOnce; + }); + }); }); diff --git a/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.tsx b/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.tsx index 64e36dabede..e2f6bdaeb96 100644 --- a/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.tsx +++ b/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.tsx @@ -4,6 +4,7 @@ import { Icon, css, spacing, + Tooltip, } from '@mongodb-js/compass-components'; import { useConnectionInfo } from '@mongodb-js/compass-connections/provider'; import { useOpenWorkspace } from '@mongodb-js/compass-workspaces/provider'; @@ -11,7 +12,12 @@ import React from 'react'; import { usePreferences } from 'compass-preferences-model/provider'; import toNS from 'mongodb-ns'; import { wrapField } from '@mongodb-js/mongodb-constants'; -import { useTelemetry } from '@mongodb-js/compass-telemetry/provider'; +import { + useTelemetry, + useAssignment, + ExperimentTestName, + ExperimentTestGroup, +} from '@mongodb-js/compass-telemetry/provider'; const collectionHeaderActionsStyles = css({ display: 'flex', @@ -40,6 +46,7 @@ type CollectionHeaderActionsProps = { editViewName?: string; sourceName?: string; sourcePipeline?: unknown[]; + onOpenMockDataModal: () => void; }; const CollectionHeaderActions: React.FunctionComponent< @@ -50,6 +57,7 @@ const CollectionHeaderActions: React.FunctionComponent< editViewName, sourceName, sourcePipeline, + onOpenMockDataModal, }: CollectionHeaderActionsProps) => { const connectionInfo = useConnectionInfo(); const { id: connectionId, atlasMetadata } = connectionInfo; @@ -59,8 +67,36 @@ const CollectionHeaderActions: React.FunctionComponent< usePreferences(['readOnly', 'enableShell']); const track = useTelemetry(); + // Get experiment assignment for Mock Data Generator + const mockDataGeneratorAssignment = useAssignment( + ExperimentTestName.mockDataGenerator, + true // trackIsInSample - this will fire the "Experiment Viewed" event + ); + const { database, collection } = toNS(namespace); + // Check if user is in treatment group for Mock Data Generator experiment + const isInMockDataTreatmentVariant = + mockDataGeneratorAssignment?.assignment?.assignmentData?.variant === + ExperimentTestGroup.mockDataGeneratorVariant; + + // Determine if we should show the Mock Data Generator button + const shouldShowMockDataButton = + isInMockDataTreatmentVariant && + atlasMetadata && // Only show in Atlas + !isReadonly && // Don't show for readonly collections (views) // TODO is this redundant? + !sourceName; // Don't show for views (sourceName indicates it's a view) + + // For now, we'll assume collection has data (no schema analysis dependency) + // In the future, this will be replaced with actual schema analysis + const hasCollectionData = true; + + // Determine if button should be enabled or disabled with tooltip + const canGenerateMockData = hasCollectionData; // TODO: Redundant + const disabledTooltipText = !hasCollectionData + ? 'Collection is empty' + : undefined; + return (
)} + {shouldShowMockDataButton && ( + + +
+ } + > + {disabledTooltipText} + + )} ); }; diff --git a/packages/compass-collection/src/components/collection-header/collection-header.tsx b/packages/compass-collection/src/components/collection-header/collection-header.tsx index 02eb416e623..e075ab90953 100644 --- a/packages/compass-collection/src/components/collection-header/collection-header.tsx +++ b/packages/compass-collection/src/components/collection-header/collection-header.tsx @@ -10,7 +10,7 @@ import { } from '@mongodb-js/compass-components'; import type { BreadcrumbItem } from '@mongodb-js/compass-components'; import type { Signal } from '@mongodb-js/compass-components'; -import React, { useMemo } from 'react'; +import React, { useMemo, useState, useCallback } from 'react'; import toNS from 'mongodb-ns'; import { usePreference } from 'compass-preferences-model/provider'; import CollectionHeaderActions from '../collection-header-actions'; @@ -18,6 +18,8 @@ import { CollectionBadge } from './badges'; import { useOpenWorkspace } from '@mongodb-js/compass-workspaces/provider'; import { useConnectionInfo } from '@mongodb-js/compass-connections/provider'; import { getConnectionTitle } from '@mongodb-js/connection-info'; +import MockDataGeneratorModal from '../mock-data-generator-modal/mock-data-generator-modal'; +import { MockDataGeneratorStep } from '../mock-data-generator-modal/types'; const collectionHeaderStyles = css({ padding: spacing[400], @@ -106,6 +108,16 @@ export const CollectionHeader: React.FunctionComponent< const connectionId = connectionInfo.id; const connectionName = getConnectionTitle(connectionInfo); + // Mock Data Generator modal state + const [isMockDataModalOpen, setIsMockDataModalOpen] = useState(false); + const [currentStep, setCurrentStep] = useState( + MockDataGeneratorStep.AI_DISCLAIMER + ); + + const handleOpenMockDataModal = useCallback(() => { + setIsMockDataModalOpen(true); + }, []); + const breadcrumbItems = useMemo(() => { return [ { @@ -170,8 +182,17 @@ export const CollectionHeader: React.FunctionComponent< namespace={namespace} sourceName={sourceName} sourcePipeline={sourcePipeline} + onOpenMockDataModal={handleOpenMockDataModal} /> + { + setCurrentStep(step); + }} + /> ); }; diff --git a/packages/compass-telemetry/src/growth-experiments.ts b/packages/compass-telemetry/src/growth-experiments.ts index 87437d07e5b..6b242a921fd 100644 --- a/packages/compass-telemetry/src/growth-experiments.ts +++ b/packages/compass-telemetry/src/growth-experiments.ts @@ -2,3 +2,8 @@ export enum ExperimentTestName { earlyJourneyIndexesGuidance = 'EARLY_JOURNEY_INDEXES_GUIDANCE_20250328', mockDataGenerator = 'MOCK_DATA_GENERATOR_20251001', } + +export enum ExperimentTestGroup { + mockDataGeneratorVariant = 'mockDataGeneratorVariant', + mockDataGeneratorControl = 'mockDataGeneratorControl', +} diff --git a/packages/compass-telemetry/src/index.ts b/packages/compass-telemetry/src/index.ts index 248c878dc21..a781a95e2fb 100644 --- a/packages/compass-telemetry/src/index.ts +++ b/packages/compass-telemetry/src/index.ts @@ -8,4 +8,4 @@ export type { export { CompassExperimentationProvider } from './experimentation-provider'; export { experimentationServiceLocator } from './provider'; -export { ExperimentTestName } from './growth-experiments'; +export { ExperimentTestName, ExperimentTestGroup } from './growth-experiments'; diff --git a/packages/compass-telemetry/src/provider.tsx b/packages/compass-telemetry/src/provider.tsx index 9eea405ad2e..da211b54ed6 100644 --- a/packages/compass-telemetry/src/provider.tsx +++ b/packages/compass-telemetry/src/provider.tsx @@ -154,4 +154,5 @@ export const useFireExperimentViewed = ({ }; export type { TrackFunction }; -export { ExperimentTestName }; +export { ExperimentTestName, ExperimentTestGroup } from './growth-experiments'; +export { useAssignment } from './experimentation-provider'; From a0b79e04aaf9d90cae87c16b4dd7a808d0043737 Mon Sep 17 00:00:00 2001 From: Jacob Samuel Lu Date: Fri, 8 Aug 2025 13:28:37 -0400 Subject: [PATCH 02/16] WIP --- .../collection-header-actions.tsx | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.tsx b/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.tsx index e2f6bdaeb96..c2f2f95e292 100644 --- a/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.tsx +++ b/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.tsx @@ -80,21 +80,18 @@ const CollectionHeaderActions: React.FunctionComponent< mockDataGeneratorAssignment?.assignment?.assignmentData?.variant === ExperimentTestGroup.mockDataGeneratorVariant; - // Determine if we should show the Mock Data Generator button const shouldShowMockDataButton = isInMockDataTreatmentVariant && atlasMetadata && // Only show in Atlas - !isReadonly && // Don't show for readonly collections (views) // TODO is this redundant? - !sourceName; // Don't show for views (sourceName indicates it's a view) + !isReadonly && // Don't show for readonly collections (views) + !sourceName; // sourceName indicates it's a view - // For now, we'll assume collection has data (no schema analysis dependency) - // In the future, this will be replaced with actual schema analysis - const hasCollectionData = true; + const hasData = true; // TODO: CLOUDP-337090 // Determine if button should be enabled or disabled with tooltip - const canGenerateMockData = hasCollectionData; // TODO: Redundant - const disabledTooltipText = !hasCollectionData - ? 'Collection is empty' + const isMockDataButtonEnabled = hasData; // TODO: CLOUDP-337090: also filter out overly nested collections + const disabledTooltipText = !hasData + ? 'Please add data to your collection to generate similar mock documents' : undefined; return ( @@ -166,13 +163,13 @@ const CollectionHeaderActions: React.FunctionComponent< )} {shouldShowMockDataButton && ( )} + {shouldShowMockDataButton && ( + + + + } + > + {disabledTooltipText} + + )} {atlasMetadata && ( - - } - > - {disabledTooltipText} - - )} ); }; From 6f3f32062fd632193ad1a5d0ce003a4216c4c455 Mon Sep 17 00:00:00 2001 From: Jacob Samuel Lu Date: Fri, 8 Aug 2025 15:57:29 -0400 Subject: [PATCH 04/16] WIP --- .../collection-header-actions.tsx | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.tsx b/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.tsx index f7da045f47b..95a43432d46 100644 --- a/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.tsx +++ b/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.tsx @@ -85,15 +85,10 @@ const CollectionHeaderActions: React.FunctionComponent< atlasMetadata && // Only show in Atlas !isReadonly && // Don't show for readonly collections (views) !sourceName; // sourceName indicates it's a view + // TODO: CLOUDP-337090: also filter out overly nested collections const hasData = true; // TODO: CLOUDP-337090 - // Determine if button should be enabled or disabled with tooltip - const isMockDataButtonEnabled = hasData; // TODO: CLOUDP-337090: also filter out overly nested collections - const disabledTooltipText = !hasData - ? 'Please add data to your collection to generate similar mock documents' - : undefined; - return (
} > - {disabledTooltipText} + Please add data to your collection to generate similar mock documents )} {atlasMetadata && ( From 8935d2285b6d5b1f76812fddcc38076997375924 Mon Sep 17 00:00:00 2001 From: Jacob Samuel Lu Date: Fri, 8 Aug 2025 17:33:16 -0400 Subject: [PATCH 05/16] Rename datatest-id --- .../collection-header-actions.spec.tsx | 14 ++++++++------ .../collection-header-actions.tsx | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.spec.tsx b/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.spec.tsx index 22668161d53..ed9d4b684ff 100644 --- a/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.spec.tsx +++ b/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.spec.tsx @@ -248,7 +248,7 @@ describe('CollectionHeaderActions [Component]', function () { ); expect( - screen.queryByTestId('collection-header-generate-mock-data') + screen.queryByTestId('collection-header-generate-mock-data-button') ).to.not.exist; }); @@ -268,7 +268,7 @@ describe('CollectionHeaderActions [Component]', function () { }); expect( - screen.queryByTestId('collection-header-generate-mock-data') + screen.queryByTestId('collection-header-generate-mock-data-button') ).to.not.exist; }); @@ -291,7 +291,7 @@ describe('CollectionHeaderActions [Component]', function () { ); expect( - screen.queryByTestId('collection-header-generate-mock-data') + screen.queryByTestId('collection-header-generate-mock-data-button') ).to.not.exist; }); @@ -315,7 +315,7 @@ describe('CollectionHeaderActions [Component]', function () { ); expect( - screen.queryByTestId('collection-header-generate-mock-data') + screen.queryByTestId('collection-header-generate-mock-data-button') ).to.not.exist; }); @@ -338,7 +338,7 @@ describe('CollectionHeaderActions [Component]', function () { ); expect( - screen.getByTestId('collection-header-generate-mock-data') + screen.getByTestId('collection-header-generate-mock-data-button') ).to.exist; expect(screen.getByText('Generate Mock Data')).to.exist; }); @@ -376,7 +376,9 @@ describe('CollectionHeaderActions [Component]', function () { atlasConnectionInfo ); - const button = screen.getByTestId('collection-header-generate-mock-data'); + const button = screen.getByTestId( + 'collection-header-generate-mock-data-button' + ); button.click(); expect(onOpenMockDataModal).to.have.been.calledOnce; diff --git a/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.tsx b/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.tsx index 95a43432d46..e6f06f6525e 100644 --- a/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.tsx +++ b/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.tsx @@ -115,7 +115,7 @@ const CollectionHeaderActions: React.FunctionComponent< trigger={
{ - setCurrentStep(step); - }} + onCurrentStepChange={onSetMockDataGeneratorStep} /> ); }; + +const mapStateToProps = (state: CollectionState) => ({ + isMockDataModalOpen: state.mockDataGenerator.isModalOpen, + currentStep: state.mockDataGenerator.currentStep, +}); + +type ConnectedCollectionHeaderProps = Omit< + CollectionHeaderProps, + | 'isMockDataModalOpen' + | 'currentStep' + | 'onOpenMockDataModal' + | 'onCloseMockDataModal' + | 'onSetMockDataGeneratorStep' +>; + +const ConnectedCollectionHeader = connect(mapStateToProps, { + onOpenMockDataModal: openMockDataGeneratorModal, + onCloseMockDataModal: closeMockDataGeneratorModal, + onSetMockDataGeneratorStep: setMockDataGeneratorStep, +})(CollectionHeader) as React.ComponentType; + +export { + ConnectedCollectionHeader as CollectionHeader, + CollectionHeader as UnconnectedCollectionHeader, // For tests +}; diff --git a/packages/compass-collection/src/components/mock-data-generator-modal/mock-data-generator-modal.spec.tsx b/packages/compass-collection/src/components/mock-data-generator-modal/mock-data-generator-modal.spec.tsx index 88d94c6e778..75fc890e1dc 100644 --- a/packages/compass-collection/src/components/mock-data-generator-modal/mock-data-generator-modal.spec.tsx +++ b/packages/compass-collection/src/components/mock-data-generator-modal/mock-data-generator-modal.spec.tsx @@ -8,10 +8,10 @@ import { StepButtonLabelMap } from './constants'; describe('MockDataGeneratorModal', () => { const sandbox = Sinon.createSandbox(); - let onOpenChange: Sinon.SinonSpy; + let onClose: Sinon.SinonSpy; beforeEach(() => { - onOpenChange = sandbox.spy(); + onClose = sandbox.spy(); }); afterEach(() => { @@ -28,7 +28,7 @@ describe('MockDataGeneratorModal', () => { return ( { onCurrentStepChangeStateMock(step); @@ -51,20 +51,20 @@ describe('MockDataGeneratorModal', () => { expect(screen.queryByTestId('generate-mock-data-modal')).to.not.exist; }); - it('calls onOpenChange(false) when the modal is closed', () => { + it('calls onClose when the modal is closed', () => { renderModal(); screen.getByLabelText('Close modal').click(); - expect(onOpenChange.calledOnceWith(false)).to.be.true; + expect(onClose.calledOnce).to.be.true; }); - it('calls onOpenChange(false) when the cancel button is clicked', () => { + it('calls onClose when the cancel button is clicked', () => { renderModal(); screen.getByText('Cancel').click(); - expect(onOpenChange.calledOnceWith(false)).to.be.true; + expect(onClose.calledOnce).to.be.true; }); it('disables the Back button on the first step', () => { diff --git a/packages/compass-collection/src/components/mock-data-generator-modal/mock-data-generator-modal.tsx b/packages/compass-collection/src/components/mock-data-generator-modal/mock-data-generator-modal.tsx index b7723530d61..053194ff051 100644 --- a/packages/compass-collection/src/components/mock-data-generator-modal/mock-data-generator-modal.tsx +++ b/packages/compass-collection/src/components/mock-data-generator-modal/mock-data-generator-modal.tsx @@ -30,14 +30,14 @@ const rightButtonsStyles = css` interface Props { isOpen: boolean; - onOpenChange: (isOpen: boolean) => void; + onClose: () => void; currentStep: MockDataGeneratorStep; onCurrentStepChange: (step: MockDataGeneratorStep) => void; } const MockDataGeneratorModal = ({ isOpen, - onOpenChange, + onClose, currentStep, onCurrentStepChange, }: Props) => { @@ -51,14 +51,14 @@ const MockDataGeneratorModal = ({ onCurrentStepChange(previousStep); }; - const onCancel = () => { - onOpenChange(false); - }; - return ( onOpenChange(open)} + setOpen={(open) => { + if (!open) { + onClose(); + } + }} data-testid="generate-mock-data-modal" > @@ -74,7 +74,7 @@ const MockDataGeneratorModal = ({ Back
- +
- + ); }; -const mapStateToProps = (state: CollectionState) => ({ - isMockDataModalOpen: state.mockDataGenerator.isModalOpen, - currentStep: state.mockDataGenerator.currentStep, -}); - -type ConnectedCollectionHeaderProps = Omit< - CollectionHeaderProps, - | 'isMockDataModalOpen' - | 'currentStep' - | 'onOpenMockDataModal' - | 'onCloseMockDataModal' - | 'onSetMockDataGeneratorStep' ->; - -const ConnectedCollectionHeader = connect(mapStateToProps, { +const ConnectedCollectionHeader = connect(undefined, { onOpenMockDataModal: mockDataGeneratorModalOpened, - onCloseMockDataModal: mockDataGeneratorModalClosed, - onSetMockDataGeneratorStep: mockDataGeneratorStepChanged, -})(CollectionHeader) as React.ComponentType; +})(CollectionHeader); -export { - ConnectedCollectionHeader as CollectionHeader, - CollectionHeader as UnconnectedCollectionHeader, // For tests -}; +export default ConnectedCollectionHeader; diff --git a/packages/compass-collection/src/components/mock-data-generator-modal/mock-data-generator-modal.spec.tsx b/packages/compass-collection/src/components/mock-data-generator-modal/mock-data-generator-modal.spec.tsx index 75fc890e1dc..25550d79a8e 100644 --- a/packages/compass-collection/src/components/mock-data-generator-modal/mock-data-generator-modal.spec.tsx +++ b/packages/compass-collection/src/components/mock-data-generator-modal/mock-data-generator-modal.spec.tsx @@ -2,7 +2,7 @@ import { expect } from 'chai'; import React from 'react'; import { render, screen } from '@mongodb-js/testing-library-compass'; import Sinon from 'sinon'; -import MockDataGeneratorModal from './mock-data-generator-modal'; +import { UnconnectedMockDataGeneratorModal as MockDataGeneratorModal } from './mock-data-generator-modal'; import { MockDataGeneratorStep } from './types'; import { StepButtonLabelMap } from './constants'; @@ -18,25 +18,22 @@ describe('MockDataGeneratorModal', () => { sandbox.restore(); }); + const onNextStep = Sinon.stub(); + const onPreviousStep = Sinon.stub(); + function renderModal({ isOpen = true, currentStep = MockDataGeneratorStep.AI_DISCLAIMER, } = {}) { - function MockDataGeneratorModalWrapper() { - const [currentStepStateMock, onCurrentStepChangeStateMock] = - React.useState(currentStep); - return ( - { - onCurrentStepChangeStateMock(step); - }} - /> - ); - } - return render(); + return render( + + ); } it('renders the modal when isOpen is true', () => { diff --git a/packages/compass-collection/src/components/mock-data-generator-modal/mock-data-generator-modal.tsx b/packages/compass-collection/src/components/mock-data-generator-modal/mock-data-generator-modal.tsx index 053194ff051..0e9791b901d 100644 --- a/packages/compass-collection/src/components/mock-data-generator-modal/mock-data-generator-modal.tsx +++ b/packages/compass-collection/src/components/mock-data-generator-modal/mock-data-generator-modal.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { connect } from 'react-redux'; import { css, @@ -15,7 +16,12 @@ import { } from '@mongodb-js/compass-components'; import { MockDataGeneratorStep } from './types'; import { StepButtonLabelMap } from './constants'; -import { getNextStep, getPreviousStep } from './utils'; +import type { CollectionState } from '../../modules/collection-tab'; +import { + mockDataGeneratorModalClosed, + mockDataGeneratorNextButtonClicked, + mockDataGeneratorPreviousButtonClicked, +} from '../../modules/collection-tab'; const footerStyles = css` flex-direction: row; @@ -32,25 +38,17 @@ interface Props { isOpen: boolean; onClose: () => void; currentStep: MockDataGeneratorStep; - onCurrentStepChange: (step: MockDataGeneratorStep) => void; + onNextStep: () => void; + onPreviousStep: () => void; } const MockDataGeneratorModal = ({ isOpen, onClose, currentStep, - onCurrentStepChange, + onNextStep, + onPreviousStep, }: Props) => { - const onNext = () => { - const nextStep = getNextStep(currentStep); - onCurrentStepChange(nextStep); - }; - - const onBack = () => { - const previousStep = getPreviousStep(currentStep); - onCurrentStepChange(previousStep); - }; - return (