Skip to content

Commit 2f4577b

Browse files
authored
feat(compass-collection): Collection Header Experimentation Integration for Mock Data Generator – CLOUDP-333847 (#7181)
* WIP * WIP * Re order buttons * WIP * Rename datatest-id * Move state to redux * Update tests per comments * Fix import * Test file * Tests cleanup * Add tests * Rename actions; Remove action wrapper * Address comments * WIP * WIP
1 parent 749435b commit 2f4577b

File tree

14 files changed

+545
-210
lines changed

14 files changed

+545
-210
lines changed

packages/compass-collection/src/components/collection-header-actions/collection-header-actions.spec.tsx

Lines changed: 228 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import { expect } from 'chai';
22
import React, { type ComponentProps } from 'react';
3-
import { render, screen, cleanup } from '@mongodb-js/testing-library-compass';
3+
import {
4+
renderWithActiveConnection,
5+
screen,
6+
cleanup,
7+
} from '@mongodb-js/testing-library-compass';
48
import sinon from 'sinon';
59
import {
610
WorkspacesServiceProvider,
@@ -9,38 +13,62 @@ import {
913
import type { PreferencesAccess } from 'compass-preferences-model';
1014
import { createSandboxFromDefaultPreferences } from 'compass-preferences-model';
1115
import { PreferencesProvider } from 'compass-preferences-model/provider';
16+
import { ExperimentTestName } from '@mongodb-js/compass-telemetry/provider';
17+
import { CompassExperimentationProvider } from '@mongodb-js/compass-telemetry';
18+
import type { ConnectionInfo } from '@mongodb-js/compass-connections/provider';
1219

1320
import CollectionHeaderActions from '../collection-header-actions';
1421

1522
describe('CollectionHeaderActions [Component]', function () {
1623
let preferences: PreferencesAccess;
24+
let mockUseAssignment: sinon.SinonStub;
25+
1726
beforeEach(async function () {
1827
preferences = await createSandboxFromDefaultPreferences();
28+
mockUseAssignment = sinon.stub();
29+
mockUseAssignment.returns({
30+
assignment: {
31+
assignmentData: {
32+
variant: 'mockDataGeneratorControl',
33+
},
34+
},
35+
});
1936
});
37+
2038
afterEach(function () {
2139
sinon.restore();
2240
});
2341

2442
const renderCollectionHeaderActions = (
2543
props: Partial<ComponentProps<typeof CollectionHeaderActions>> = {},
26-
workspaceService: Partial<WorkspacesService> = {}
44+
workspaceService: Partial<WorkspacesService> = {},
45+
connectionInfo?: ConnectionInfo
2746
) => {
28-
return render(
29-
<WorkspacesServiceProvider value={workspaceService as WorkspacesService}>
30-
<PreferencesProvider value={preferences}>
31-
<CollectionHeaderActions
32-
namespace="test.test"
33-
isReadonly={false}
34-
{...props}
35-
/>
36-
</PreferencesProvider>
37-
</WorkspacesServiceProvider>
47+
return renderWithActiveConnection(
48+
<CompassExperimentationProvider
49+
useAssignment={mockUseAssignment}
50+
assignExperiment={sinon.stub()}
51+
>
52+
<WorkspacesServiceProvider
53+
value={workspaceService as WorkspacesService}
54+
>
55+
<PreferencesProvider value={preferences}>
56+
<CollectionHeaderActions
57+
namespace="test.test"
58+
isReadonly={false}
59+
onOpenMockDataModal={sinon.stub()}
60+
{...props}
61+
/>
62+
</PreferencesProvider>
63+
</WorkspacesServiceProvider>
64+
</CompassExperimentationProvider>,
65+
connectionInfo
3866
);
3967
};
4068

4169
context('when the collection is not readonly', function () {
42-
beforeEach(function () {
43-
renderCollectionHeaderActions({
70+
beforeEach(async function () {
71+
await renderCollectionHeaderActions({
4472
isReadonly: false,
4573
namespace: 'db.coll2',
4674
sourceName: 'db.coll',
@@ -63,7 +91,7 @@ describe('CollectionHeaderActions [Component]', function () {
6391
it('does not render edit view buttons when in readonly mode', async function () {
6492
await preferences.savePreferences({ readOnly: true });
6593

66-
renderCollectionHeaderActions({
94+
await renderCollectionHeaderActions({
6795
isReadonly: true,
6896
namespace: 'db.coll2',
6997
sourceName: 'db.someSource',
@@ -78,8 +106,8 @@ describe('CollectionHeaderActions [Component]', function () {
78106
).to.not.exist;
79107
});
80108

81-
it('renders edit view buttons when not in readonly mode', function () {
82-
renderCollectionHeaderActions({
109+
it('renders edit view buttons when not in readonly mode', async function () {
110+
await renderCollectionHeaderActions({
83111
isReadonly: true,
84112
namespace: 'db.coll2',
85113
sourceName: 'db.someSource',
@@ -94,9 +122,9 @@ describe('CollectionHeaderActions [Component]', function () {
94122

95123
context('when the collection is a view', function () {
96124
let openEditViewWorkspaceStub: sinon.SinonStub;
97-
beforeEach(function () {
125+
beforeEach(async function () {
98126
openEditViewWorkspaceStub = sinon.stub();
99-
renderCollectionHeaderActions(
127+
await renderCollectionHeaderActions(
100128
{
101129
isReadonly: true,
102130
namespace: 'db.coll2',
@@ -135,9 +163,9 @@ describe('CollectionHeaderActions [Component]', function () {
135163

136164
context('when the collection is editing a view', function () {
137165
let openCollectionWorkspaceStub: sinon.SinonStub;
138-
beforeEach(function () {
166+
beforeEach(async function () {
139167
openCollectionWorkspaceStub = sinon.stub();
140-
renderCollectionHeaderActions(
168+
await renderCollectionHeaderActions(
141169
{
142170
isReadonly: false,
143171
namespace: 'db.coll2',
@@ -168,4 +196,183 @@ describe('CollectionHeaderActions [Component]', function () {
168196
);
169197
});
170198
});
199+
200+
context('Mock Data Generator Button', function () {
201+
const atlasConnectionInfo: ConnectionInfo = {
202+
id: 'test-atlas-connection',
203+
connectionOptions: {
204+
connectionString: 'mongodb://localhost:27017',
205+
},
206+
atlasMetadata: {
207+
orgId: 'test-org',
208+
projectId: 'test-project',
209+
clusterName: 'test-cluster',
210+
clusterUniqueId: 'test-cluster-unique-id',
211+
clusterType: 'REPLICASET',
212+
clusterState: 'IDLE',
213+
metricsId: 'test-metrics-id',
214+
metricsType: 'replicaSet',
215+
regionalBaseUrl: null,
216+
instanceSize: 'M10',
217+
supports: {
218+
globalWrites: false,
219+
rollingIndexes: true,
220+
},
221+
},
222+
};
223+
224+
it('should not show Mock Data Generator button when user is in control group', async function () {
225+
mockUseAssignment.returns({
226+
assignment: {
227+
assignmentData: {
228+
variant: 'mockDataGeneratorControl',
229+
},
230+
},
231+
});
232+
233+
await renderCollectionHeaderActions(
234+
{
235+
namespace: 'test.collection',
236+
isReadonly: false,
237+
},
238+
{},
239+
atlasConnectionInfo
240+
);
241+
242+
expect(
243+
screen.queryByTestId('collection-header-generate-mock-data-button')
244+
).to.not.exist;
245+
});
246+
247+
it('should not show Mock Data Generator button when not in Atlas', async function () {
248+
mockUseAssignment.returns({
249+
assignment: {
250+
assignmentData: {
251+
variant: 'treatment',
252+
},
253+
},
254+
});
255+
256+
await renderCollectionHeaderActions({
257+
namespace: 'test.collection',
258+
isReadonly: false,
259+
// Don't pass atlasConnectionInfo, to simulate not being in Atlas
260+
});
261+
262+
expect(
263+
screen.queryByTestId('collection-header-generate-mock-data-button')
264+
).to.not.exist;
265+
});
266+
267+
it('should not show Mock Data Generator button for readonly collections', async function () {
268+
mockUseAssignment.returns({
269+
assignment: {
270+
assignmentData: {
271+
variant: 'treatment',
272+
},
273+
},
274+
});
275+
276+
await renderCollectionHeaderActions(
277+
{
278+
namespace: 'test.collection',
279+
isReadonly: true,
280+
},
281+
{},
282+
atlasConnectionInfo
283+
);
284+
285+
expect(
286+
screen.queryByTestId('collection-header-generate-mock-data-button')
287+
).to.not.exist;
288+
});
289+
290+
it('should not show Mock Data Generator button for views (sourceName present)', async function () {
291+
mockUseAssignment.returns({
292+
assignment: {
293+
assignmentData: {
294+
variant: 'treatment',
295+
},
296+
},
297+
});
298+
299+
await renderCollectionHeaderActions(
300+
{
301+
namespace: 'test.collection',
302+
isReadonly: false,
303+
sourceName: 'source-collection',
304+
},
305+
{},
306+
atlasConnectionInfo
307+
);
308+
309+
expect(
310+
screen.queryByTestId('collection-header-generate-mock-data-button')
311+
).to.not.exist;
312+
});
313+
314+
it('should show Mock Data Generator button when user is in treatment group and in Atlas', async function () {
315+
mockUseAssignment.returns({
316+
assignment: {
317+
assignmentData: {
318+
variant: 'mockDataGeneratorVariant',
319+
},
320+
},
321+
});
322+
323+
await renderCollectionHeaderActions(
324+
{
325+
namespace: 'test.collection',
326+
isReadonly: false,
327+
},
328+
{},
329+
atlasConnectionInfo
330+
);
331+
332+
expect(
333+
screen.getByTestId('collection-header-generate-mock-data-button')
334+
).to.exist;
335+
});
336+
337+
it('should call useAssignment with correct parameters', async function () {
338+
await renderCollectionHeaderActions({
339+
namespace: 'test.collection',
340+
isReadonly: false,
341+
});
342+
343+
expect(mockUseAssignment).to.have.been.calledWith(
344+
ExperimentTestName.mockDataGenerator,
345+
true // trackIsInSample - Experiment viewed analytics event
346+
);
347+
});
348+
349+
it('should call onOpenMockDataModal when CTA button is clicked', async function () {
350+
const onOpenMockDataModal = sinon.stub();
351+
352+
mockUseAssignment.returns({
353+
assignment: {
354+
assignmentData: {
355+
variant: 'mockDataGeneratorVariant',
356+
},
357+
},
358+
});
359+
360+
await renderCollectionHeaderActions(
361+
{
362+
namespace: 'test.collection',
363+
isReadonly: false,
364+
onOpenMockDataModal,
365+
},
366+
{},
367+
atlasConnectionInfo
368+
);
369+
370+
const button = screen.getByTestId(
371+
'collection-header-generate-mock-data-button'
372+
);
373+
button.click();
374+
375+
expect(onOpenMockDataModal).to.have.been.calledOnce;
376+
});
377+
});
171378
});

0 commit comments

Comments
 (0)