Skip to content

Commit 02b5520

Browse files
committed
add e2e test
1 parent e7fa6d9 commit 02b5520

File tree

7 files changed

+176
-22
lines changed

7 files changed

+176
-22
lines changed

packages/compass-e2e-tests/helpers/compass.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { inspect } from 'util';
22
import { ObjectId, EJSON } from 'bson';
33
import { promises as fs, rmdirSync } from 'fs';
44
import type Mocha from 'mocha';
5-
import path from 'path';
65
import os from 'os';
76
import { execFile } from 'child_process';
87
import type { ExecFileOptions, ExecFileException } from 'child_process';
@@ -42,6 +41,8 @@ import {
4241
ELECTRON_PATH,
4342
} from './test-runner-paths';
4443
import treeKill from 'tree-kill';
44+
import { downloadPath } from './downloads';
45+
import path from 'path';
4546

4647
const killAsync = async (pid: number, signal?: string) => {
4748
return new Promise<void>((resolve, reject) => {
@@ -677,6 +678,13 @@ async function startCompassElectron(
677678

678679
try {
679680
browser = (await remote(options)) as CompassBrowser;
681+
// https://webdriver.io/docs/best-practices/file-download/#configuring-chromium-browser-downloads
682+
const page = await browser.getPuppeteer();
683+
const cdpSession = await page.target().createCDPSession();
684+
await cdpSession.send('Browser.setDownloadBehavior', {
685+
behavior: 'allow',
686+
downloadPath: downloadPath,
687+
});
680688
} catch (err) {
681689
debug('Failed to start remote webdriver session', {
682690
error: (err as Error).stack,
@@ -755,6 +763,26 @@ export async function startBrowser(
755763
runCounter++;
756764
const { webdriverOptions, wdioOptions } = await processCommonOpts();
757765

766+
const browserCapabilities: Record<string, Record<string, unknown>> = {
767+
chrome: {
768+
'goog:chromeOptions': {
769+
prefs: {
770+
'download.default_directory': downloadPath,
771+
},
772+
},
773+
},
774+
firefox: {
775+
'moz:firefoxOptions': {
776+
prefs: {
777+
'browser.download.dir': downloadPath,
778+
'browser.download.folderList': 2,
779+
'browser.download.manager.showWhenStarting': false,
780+
'browser.helperApps.neverAsk.saveToDisk': '*/*',
781+
},
782+
},
783+
},
784+
};
785+
758786
// webdriverio removed RemoteOptions. It is now
759787
// Capabilities.WebdriverIOConfig, but Capabilities is not exported
760788
const options = {
@@ -763,6 +791,7 @@ export async function startBrowser(
763791
...(context.browserVersion && {
764792
browserVersion: context.browserVersion,
765793
}),
794+
...browserCapabilities[context.browserName],
766795

767796
// from https://github.com/webdriverio-community/wdio-electron-service/blob/32457f60382cb4970c37c7f0a19f2907aaa32443/packages/wdio-electron-service/src/launcher.ts#L102
768797
'wdio:enforceWebDriverClassic': true,
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import path from 'path';
2+
import fs from 'fs';
3+
4+
export const downloadPath = path.join(__dirname, 'downloads');
5+
6+
export const waitForFileDownload = async (
7+
filename: string,
8+
browser: WebdriverIO.Browser
9+
): Promise<{
10+
fileExists: boolean;
11+
filePath: string;
12+
}> => {
13+
const filePath = `${downloadPath}/${filename}`;
14+
await browser.waitUntil(
15+
function () {
16+
return fs.existsSync(filePath);
17+
},
18+
{ timeout: 3000, timeoutMsg: 'file not downloaded yet.' }
19+
);
20+
21+
return { fileExists: fs.existsSync(filePath), filePath };
22+
};
23+
24+
export const cleanUpDownloadedFile = (filename: string) => {
25+
const filePath = `${downloadPath}/${filename}`;
26+
try {
27+
if (fs.existsSync(filePath)) {
28+
fs.unlinkSync(filePath);
29+
}
30+
} catch (err) {
31+
console.error(`Error deleting file: ${(err as Error).message}`);
32+
}
33+
};

packages/compass-e2e-tests/helpers/selectors.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,7 +1025,12 @@ export const AnalyzeSchemaButton = '[data-testid="analyze-schema-button"]';
10251025
export const ExportSchemaButton = '[data-testid="open-schema-export-button"]';
10261026
export const ExportSchemaFormatOptions =
10271027
'[data-testid="export-schema-format-type-box-group"]';
1028+
export const exportSchemaFormatOption = (
1029+
option: 'standardJSON' | 'mongoDBJSON' | 'extendedJSON'
1030+
) => `[data-testid="export-schema-format-${option}-button"]`;
10281031
export const ExportSchemaOutput = '[data-testid="export-schema-content"]';
1032+
export const ExportSchemaDownloadButton =
1033+
'[data-testid="schema-export-download-button"]';
10291034
export const SchemaFieldList = '[data-testid="schema-field-list"]';
10301035
export const AnalysisMessage =
10311036
'[data-testid="schema-content"] [data-testid="schema-analysis-message"]';

packages/compass-e2e-tests/tests/collection-schema-tab.test.ts

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ import {
1313
createGeospatialCollection,
1414
createNumbersCollection,
1515
} from '../helpers/insert-data';
16+
import {
17+
cleanUpDownloadedFile,
18+
waitForFileDownload,
19+
} from '../helpers/downloads';
20+
import { readFileSync } from 'fs';
1621

1722
const { expect } = chai;
1823

@@ -116,7 +121,17 @@ describe('Collection schema tab', function () {
116121
await browser.setFeature('enableExportSchema', true);
117122
});
118123

119-
it('shows an exported schema to copy', async function () {
124+
const filename = 'schema-test-numbers-standardJSON.json';
125+
126+
before(() => {
127+
cleanUpDownloadedFile(filename);
128+
});
129+
130+
after(() => {
131+
cleanUpDownloadedFile(filename);
132+
});
133+
134+
it('shows an exported schema to copy (standard JSON Schema)', async function () {
120135
await browser.navigateToCollectionTab(
121136
DEFAULT_CONNECTION_NAME_1,
122137
'test',
@@ -157,6 +172,57 @@ describe('Collection schema tab', function () {
157172
},
158173
});
159174
});
175+
176+
it('can download schema (MongoDB $jsonSchema)', async function () {
177+
await browser.navigateToCollectionTab(
178+
DEFAULT_CONNECTION_NAME_1,
179+
'test',
180+
'numbers',
181+
'Schema'
182+
);
183+
await browser.clickVisible(Selectors.AnalyzeSchemaButton);
184+
185+
const element = browser.$(Selectors.SchemaFieldList);
186+
await element.waitForDisplayed();
187+
188+
await browser.clickVisible(Selectors.ExportSchemaButton);
189+
190+
const exportModal = browser.$(Selectors.ExportSchemaFormatOptions);
191+
await exportModal.waitForDisplayed();
192+
193+
await browser.clickVisible(
194+
Selectors.exportSchemaFormatOption('mongoDBJSON')
195+
);
196+
197+
const exportSchemaButton = browser.$(
198+
Selectors.ExportSchemaDownloadButton
199+
);
200+
await exportSchemaButton.waitForEnabled();
201+
await exportSchemaButton.click();
202+
203+
const { fileExists, filePath } = await waitForFileDownload(
204+
filename,
205+
browser
206+
);
207+
expect(fileExists).to.be.true;
208+
209+
const content = readFileSync(filePath, 'utf-8');
210+
expect(JSON.parse(content)).to.deep.equal({
211+
bsonType: 'object',
212+
required: ['_id', 'i', 'j'],
213+
properties: {
214+
_id: {
215+
bsonType: 'objectId',
216+
},
217+
i: {
218+
bsonType: 'int',
219+
},
220+
j: {
221+
bsonType: 'int',
222+
},
223+
},
224+
});
225+
});
160226
});
161227

162228
it('analyzes the schema with a query');

packages/compass-schema/src/components/export-schema-modal.tsx

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import {
1414
ErrorSummary,
1515
Label,
1616
CancelLoader,
17-
Link,
1817
SpinLoader,
1918
} from '@mongodb-js/compass-components';
2019
import { CodemirrorMultilineEditor } from '@mongodb-js/compass-editor';
@@ -190,17 +189,18 @@ const ExportSchemaModal: React.FunctionComponent<{
190189
<Button onClick={onClose} variant="default">
191190
Cancel
192191
</Button>
193-
<Button
194-
variant="primary"
195-
isLoading={!downloadUrl}
196-
loadingIndicator={<SpinLoader />}
197-
disabled={!exportedSchema}
198-
download={filename}
199-
href={downloadUrl}
200-
onClick={onExportedSchema}
201-
>
202-
Export
203-
</Button>
192+
<Button
193+
variant="primary"
194+
isLoading={!downloadUrl}
195+
loadingIndicator={<SpinLoader />}
196+
disabled={!exportedSchema}
197+
download={filename}
198+
href={downloadUrl}
199+
onClick={onExportedSchema}
200+
data-testid="schema-export-download-button"
201+
>
202+
Export
203+
</Button>
204204
</ModalFooter>
205205
</Modal>
206206
);

packages/compass-schema/src/stores/schema-export-reducer.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ async function getSchemaByFormat({
156156
break;
157157
}
158158

159-
JSON.stringify(schema, null, 2);
159+
return JSON.stringify(schema, null, 2);
160160
}
161161

162162
const _trackSchemaExportFailed = (stage: string): SchemaThunkAction<void> => {
@@ -235,14 +235,17 @@ const prepareDownload = (): SchemaThunkAction<void> => {
235235
const blob = new Blob([exportedSchema], {
236236
type: 'application/json',
237237
});
238-
const filename = `schema-${exportFormat}-${namespace}.json`;
238+
const filename = `schema-${namespace.replace(
239+
'.',
240+
'-'
241+
)}-${exportFormat}.json`;
239242
dispatch({
240243
type: SchemaExportActions.schemaDownloadReady,
241244
blob,
242245
filename,
243246
});
244247
} catch (error) {
245-
_trackSchemaExportFailed('prepareDownload');
248+
dispatch(_trackSchemaExportFailed('prepareDownload'));
246249
}
247250
};
248251
};
@@ -309,7 +312,7 @@ export const changeExportSchemaFormat = (
309312
type: SchemaExportActions.changeExportSchemaFormatError,
310313
errorMessage: (err as Error).message,
311314
});
312-
_trackSchemaExportFailed('changeExportFormat');
315+
dispatch(_trackSchemaExportFailed('changeExportFormat'));
313316
return;
314317
}
315318

packages/compass-schema/src/stores/store.spec.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,13 @@ describe('Schema Store', function () {
158158
'complete'
159159
);
160160
});
161-
const { exportStatus, errorMessage, exportedSchema } =
162-
store.getState().schemaExport;
161+
const {
162+
exportStatus,
163+
errorMessage,
164+
exportedSchema,
165+
filename,
166+
blobToDownload,
167+
} = store.getState().schemaExport;
163168
expect(exportStatus).to.equal('complete');
164169
expect(!!errorMessage).to.be.false;
165170
expect(exportedSchema).not.to.be.undefined;
@@ -171,14 +176,23 @@ describe('Schema Store', function () {
171176
expect(JSON.parse(exportedSchema!).properties).to.deep.equal({
172177
name: { type: 'string' },
173178
});
179+
expect(filename).to.equal('schema-db-coll-standardJSON.json');
180+
expect(blobToDownload).to.be.a('Blob');
181+
expect(blobToDownload?.type).to.equal('application/json');
182+
expect(blobToDownload?.size).to.be.greaterThan(0);
174183
});
175184

176185
it('runs schema export formatting with a new format', async function () {
177186
sampleStub.resolves([{ name: 'Hans' }, { name: 'Greta' }]);
178187
await store.dispatch(changeExportSchemaFormat('mongoDBJSON'));
179188
expect(sampleStub).to.have.been.called;
180-
const { exportStatus, errorMessage, exportedSchema } =
181-
store.getState().schemaExport;
189+
const {
190+
exportStatus,
191+
errorMessage,
192+
exportedSchema,
193+
filename,
194+
blobToDownload,
195+
} = store.getState().schemaExport;
182196
expect(exportStatus).to.equal('complete');
183197
expect(!!errorMessage).to.be.false;
184198
expect(exportedSchema).not.to.be.undefined;
@@ -189,6 +203,10 @@ describe('Schema Store', function () {
189203
expect(JSON.parse(exportedSchema!).properties).to.deep.equal({
190204
name: { bsonType: 'string' },
191205
});
206+
expect(filename).to.equal('schema-db-coll-mongoDBJSON.json');
207+
expect(blobToDownload).to.be.a('Blob');
208+
expect(blobToDownload?.type).to.equal('application/json');
209+
expect(blobToDownload?.size).to.be.greaterThan(0);
192210
});
193211
});
194212
});

0 commit comments

Comments
 (0)