Skip to content

Commit e244454

Browse files
committed
chore(e2e): restructure e2e test helpers to better separate shared state and setup / teardown functions
1 parent 27da7ec commit e244454

File tree

13 files changed

+416
-755
lines changed

13 files changed

+416
-755
lines changed

packages/compass-e2e-tests/.gitignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,3 @@
22
.log
33
fixtures/*.csv
44
fixtures/*.json
5-
write-electron-versions.js
6-
electron-versions.json

packages/compass-e2e-tests/.prettierignore

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,3 @@
33
fixtures
44
.nyc_output
55
coverage
6-
7-
# Generated files
8-
electron-versions.json
9-
write-electron-versions.js

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import path from 'path';
22
import type { CompassBrowser } from '../compass-browser';
3-
import { SCREENSHOTS_PATH } from '../compass';
3+
import { LOG_SCREENSHOTS_PATH } from '../test-runner-context';
44

55
const withTimeout = (millis: number, promise: Promise<any>) => {
66
let timeoutPid: NodeJS.Timeout;
@@ -26,7 +26,7 @@ export async function screenshot(
2626
// are still in progress or not.
2727
await browser.pause(1000);
2828

29-
const fullPath = path.join(SCREENSHOTS_PATH, filename);
29+
const fullPath = path.join(LOG_SCREENSHOTS_PATH, filename);
3030
try {
3131
await withTimeout(10000, browser.saveScreenshot(fullPath));
3232
} catch (err: any) {

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

Lines changed: 38 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,20 @@ import Debug from 'debug';
2424
import semver from 'semver';
2525
import crossSpawn from 'cross-spawn';
2626
import { CHROME_STARTUP_FLAGS } from './chrome-startup-flags';
27+
import {
28+
DEFAULT_CONNECTION_STRINGS,
29+
DEFAULT_CONNECTIONS_NAMES,
30+
DEFAULT_CONNECTIONS_SERVER_INFO,
31+
ELECTRON_CHROMIUM_VERSION,
32+
TEST_COMPASS_WEB as _TEST_COMPASS_WEB,
33+
LOG_PATH,
34+
LOG_COVERAGE_PATH,
35+
COMPASS_DESKTOP_PATH,
36+
LOG_OUTPUT_PATH,
37+
LOG_SCREENSHOTS_PATH,
38+
WEBDRIVER_DEFAULT_WAITFOR_TIMEOUT,
39+
WEBDRIVER_DEFAULT_WAITFOR_INTERVAL,
40+
} from './test-runner-context';
2741

2842
const debug = Debug('compass-e2e-tests');
2943

@@ -32,20 +46,8 @@ const { Z_SYNC_FLUSH } = zlib.constants;
3246

3347
const packageCompassAsync = promisify(packageCompass);
3448

35-
export const COMPASS_PATH = path.dirname(
36-
require.resolve('mongodb-compass/package.json')
37-
);
38-
export const LOG_PATH = path.resolve(__dirname, '..', '.log');
39-
const OUTPUT_PATH = path.join(LOG_PATH, 'output');
40-
export const SCREENSHOTS_PATH = path.join(LOG_PATH, 'screenshots');
41-
const COVERAGE_PATH = path.join(LOG_PATH, 'coverage');
42-
43-
let MONGODB_VERSION = '';
44-
let MONGODB_USE_ENTERPRISE =
45-
(process.env.MONGODB_VERSION?.endsWith('-enterprise') && 'yes') ?? 'no';
46-
4749
// should we test compass-web (true) or compass electron (false)?
48-
export const TEST_COMPASS_WEB = process.argv.includes('--test-compass-web');
50+
export const TEST_COMPASS_WEB = _TEST_COMPASS_WEB;
4951
// multiple connections is now the default
5052
export const TEST_MULTIPLE_CONNECTIONS = true;
5153

@@ -75,70 +77,27 @@ export const MONGODB_TEST_SERVER_PORT = Number(
7577
process.env.MONGODB_TEST_SERVER_PORT ?? 27091
7678
);
7779

78-
export const DEFAULT_CONNECTION_STRING_1 = `mongodb://127.0.0.1:${MONGODB_TEST_SERVER_PORT}/test`;
80+
export const DEFAULT_CONNECTION_STRING_1 = DEFAULT_CONNECTION_STRINGS[0];
7981
// NOTE: in browser.setupDefaultConnections() we don't give the first connection an
8082
// explicit name, so it gets a calculated one based off the connection string
81-
export const DEFAULT_CONNECTION_NAME_1 = connectionNameFromString(
82-
DEFAULT_CONNECTION_STRING_1
83-
);
83+
export const DEFAULT_CONNECTION_NAME_1 = DEFAULT_CONNECTIONS_NAMES[0];
8484

8585
// for testing multiple connections
86-
export const DEFAULT_CONNECTION_STRING_2 = `mongodb://127.0.0.1:${
87-
MONGODB_TEST_SERVER_PORT + 1
88-
}/test`;
86+
export const DEFAULT_CONNECTION_STRING_2 = DEFAULT_CONNECTION_STRINGS[1];
8987
// NOTE: in browser.setupDefaultConnections() the second connection gets given an explicit name
90-
export const DEFAULT_CONNECTION_NAME_2 = 'connection-2';
91-
92-
export function updateMongoDBServerInfo() {
93-
try {
94-
const { stdout, stderr } = crossSpawn.sync(
95-
'npm',
96-
[
97-
'run',
98-
'--silent',
99-
/**
100-
* The server info update is done through a separate script and not by
101-
* using a MongoClient directly because doing so causes an unexplainable
102-
* segfault crash in e2e-coverage task in evergreen CI. Moving this
103-
* logic to a separate script seems to solve this problem, but if at any
104-
* point the issue returns, feel free to revert this whole change
105-
**/
106-
'server-info',
107-
'--',
108-
'--connectionString',
109-
`mongodb://127.0.0.1:${String(MONGODB_TEST_SERVER_PORT)}`,
110-
],
111-
{ encoding: 'utf-8' }
112-
);
113-
if (stderr?.length) {
114-
throw new Error(stderr);
115-
}
116-
const { version, enterprise } = JSON.parse(stdout);
117-
MONGODB_VERSION = version;
118-
MONGODB_USE_ENTERPRISE = enterprise ? 'yes' : 'no';
119-
debug(
120-
`Got server info: v${String(version)} (${
121-
enterprise ? 'enterprise' : 'community'
122-
})`
123-
);
124-
} catch (err) {
125-
(err as Error).message =
126-
'Failed trying to get MongoDB server info:\n\n' + (err as Error).message;
127-
throw err;
128-
}
129-
}
88+
export const DEFAULT_CONNECTION_NAME_2 = DEFAULT_CONNECTIONS_NAMES[2];
13089

13190
export const serverSatisfies = (
13291
semverCondition: string,
13392
enterpriseExact?: boolean
13493
) => {
94+
const { version, enterprise } = DEFAULT_CONNECTIONS_SERVER_INFO[0];
13595
return (
136-
semver.satisfies(MONGODB_VERSION, semverCondition, {
96+
semver.satisfies(version, semverCondition, {
13797
includePrerelease: true,
13898
}) &&
13999
(typeof enterpriseExact === 'boolean'
140-
? (enterpriseExact && MONGODB_USE_ENTERPRISE === 'yes') ||
141-
(!enterpriseExact && MONGODB_USE_ENTERPRISE !== 'yes')
100+
? (enterpriseExact && enterprise) || (!enterpriseExact && !enterprise)
142101
: true)
143102
);
144103
};
@@ -391,13 +350,13 @@ export class Compass {
391350
});
392351
if (coverage.main) {
393352
await fs.writeFile(
394-
path.join(COVERAGE_PATH, `main.${this.name}.log`),
353+
path.join(LOG_COVERAGE_PATH, `main.${this.name}.log`),
395354
coverage.main
396355
);
397356
}
398357
if (coverage.renderer) {
399358
await fs.writeFile(
400-
path.join(COVERAGE_PATH, `renderer.${this.name}.log`),
359+
path.join(LOG_COVERAGE_PATH, `renderer.${this.name}.log`),
401360
coverage.renderer
402361
);
403362
}
@@ -509,7 +468,7 @@ export async function runCompassOnce(args: string[], timeout = 30_000) {
509468
const { binary } = await getCompassExecutionParameters();
510469
debug('spawning compass...', {
511470
binary,
512-
COMPASS_PATH,
471+
COMPASS_DESKTOP_PATH,
513472
defaultUserDataDir,
514473
args,
515474
timeout,
@@ -522,7 +481,7 @@ export async function runCompassOnce(args: string[], timeout = 30_000) {
522481
const { error, stdout, stderr } = await execFileIgnoreError(
523482
binary,
524483
[
525-
COMPASS_PATH,
484+
COMPASS_DESKTOP_PATH,
526485
// When running binary without webdriver, we need to pass the same flags
527486
// as we pass when running with webdriverio to have similar behaviour.
528487
...CHROME_STARTUP_FLAGS,
@@ -585,9 +544,9 @@ async function processCommonOpts({
585544
// for consistency let's mkdir for both of them just in case
586545
await fs.mkdir(path.dirname(chromedriverLogPath), { recursive: true });
587546
await fs.mkdir(webdriverLogPath, { recursive: true });
588-
await fs.mkdir(OUTPUT_PATH, { recursive: true });
589-
await fs.mkdir(SCREENSHOTS_PATH, { recursive: true });
590-
await fs.mkdir(COVERAGE_PATH, { recursive: true });
547+
await fs.mkdir(LOG_OUTPUT_PATH, { recursive: true });
548+
await fs.mkdir(LOG_SCREENSHOTS_PATH, { recursive: true });
549+
await fs.mkdir(LOG_COVERAGE_PATH, { recursive: true });
591550

592551
// https://webdriver.io/docs/options/#webdriver-options
593552
const webdriverOptions = {
@@ -597,14 +556,8 @@ async function processCommonOpts({
597556

598557
// https://webdriver.io/docs/options/#webdriverio
599558
const wdioOptions = {
600-
// default is 3000ms
601-
waitforTimeout: process.env.COMPASS_TEST_DEFAULT_WAITFOR_TIMEOUT
602-
? Number(process.env.COMPASS_TEST_DEFAULT_WAITFOR_TIMEOUT)
603-
: 120_000, // shorter than the test timeout so the exact line will fail, not the test
604-
// default is 500ms
605-
waitforInterval: process.env.COMPASS_TEST_DEFAULT_WAITFOR_INTERVAL
606-
? Number(process.env.COMPASS_TEST_DEFAULT_WAITFOR_INTERVAL)
607-
: 100,
559+
waitforTimeout: WEBDRIVER_DEFAULT_WAITFOR_TIMEOUT,
560+
waitforInterval: WEBDRIVER_DEFAULT_WAITFOR_INTERVAL,
608561
};
609562

610563
process.env.DEBUG = `${process.env.DEBUG ?? ''},mongodb-compass:main:logging`;
@@ -638,7 +591,7 @@ async function startCompassElectron(
638591

639592
if (!testPackagedApp) {
640593
// https://www.electronjs.org/docs/latest/tutorial/automated-testing#with-webdriverio
641-
chromeArgs.push(`--app=${COMPASS_PATH}`);
594+
chromeArgs.push(`--app=${COMPASS_DESKTOP_PATH}`);
642595
}
643596

644597
if (opts.firstRun === false) {
@@ -685,7 +638,7 @@ async function startCompassElectron(
685638
automationProtocol: 'webdriver' as const,
686639
capabilities: {
687640
browserName: 'chromium',
688-
browserVersion: process.env.CHROME_VERSION,
641+
browserVersion: ELECTRON_CHROMIUM_VERSION,
689642
// https://chromedriver.chromium.org/capabilities#h.p_ID_106
690643
'goog:chromeOptions': {
691644
binary: maybeWrappedBinary,
@@ -866,7 +819,7 @@ function formattedDate(): string {
866819
}
867820

868821
export async function rebuildNativeModules(
869-
compassPath = COMPASS_PATH
822+
compassPath = COMPASS_DESKTOP_PATH
870823
): Promise<void> {
871824
const fullCompassPath = require.resolve(
872825
path.join(compassPath, 'package.json')
@@ -893,7 +846,7 @@ export async function rebuildNativeModules(
893846
}
894847

895848
export async function compileCompassAssets(
896-
compassPath = COMPASS_PATH
849+
compassPath = COMPASS_DESKTOP_PATH
897850
): Promise<void> {
898851
await promisify(execFile)('npm', ['run', 'compile'], { cwd: compassPath });
899852
}
@@ -925,7 +878,7 @@ async function getCompassBuildMetadata(): Promise<BinPathOptions> {
925878

926879
export async function buildCompass(
927880
force = false,
928-
compassPath = COMPASS_PATH
881+
compassPath = COMPASS_DESKTOP_PATH
929882
): Promise<void> {
930883
if (!force) {
931884
try {
@@ -1040,7 +993,7 @@ export async function init(
1040993
await browser.execute(() => {
1041994
// eslint-disable-next-line @typescript-eslint/no-var-requires
1042995
const { ipcRenderer } = require('electron');
1043-
ipcRenderer.invoke('compass:maximize');
996+
void ipcRenderer.invoke('compass:maximize');
1044997
});
1045998
}
1046999

@@ -1116,7 +1069,7 @@ export function screenshotPathName(text: string) {
11161069
* @param {string} filename
11171070
*/
11181071
export function outputFilename(filename: string): string {
1119-
return path.join(OUTPUT_PATH, filename);
1072+
return path.join(LOG_OUTPUT_PATH, filename);
11201073
}
11211074

11221075
export async function screenshotIfFailed(
Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
#!/usr/bin/env ts-node
2-
1+
import Debug from 'debug';
32
import fastGlob from 'fast-glob';
43
import { createReadStream, createWriteStream } from 'fs';
54
import { pipeline } from 'stream';
65
import { promisify } from 'util';
76
import { createGunzip } from 'zlib';
87

8+
const debug = Debug('compass-e2e-tests:gunzip');
9+
910
const pipe = promisify(pipeline);
1011

1112
async function gunzip(input: string, output: string) {
@@ -16,22 +17,13 @@ async function gunzip(input: string, output: string) {
1617
await pipe(readStream, gunzip, writeStream);
1718
}
1819

19-
async function run() {
20-
// windows does not expand * automatically
21-
const filenames = await fastGlob(process.argv.slice(2));
22-
20+
async function run(glob: string) {
21+
const filenames = await fastGlob(glob);
2322
for (const input of filenames) {
2423
const output = input.replace(/\.gz$/, '');
25-
console.log(input, '=>', output);
24+
debug(input, '=>', output);
2625
await gunzip(input, output);
2726
}
2827
}
2928

30-
if (require.main === module) {
31-
run().catch((err: Error) => {
32-
console.error('An error occurred:', err);
33-
process.exitCode = 1;
34-
});
35-
}
36-
37-
module.exports = gunzip;
29+
export default run;

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

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ for (let i = 0; i < 26; ++i) {
4646
let clients: MongoClient[];
4747
let test_dbs: Db[];
4848

49-
before(async () => {
49+
export const beforeAll = async () => {
5050
// Insert data on both connections so that the same databases and collections
5151
// will exist on both servers and then anything that's not properly scoped to
5252
// the correct connection has a chance to operate on the wrong one and
@@ -70,13 +70,13 @@ before(async () => {
7070
);
7171

7272
test_dbs = clients.map((client) => client.db('test'));
73-
});
73+
};
7474

75-
after(async () => {
75+
export const afterAll = async () => {
7676
await Promise.all(clients.map((client) => client.close()));
77-
});
77+
};
7878

79-
beforeEach(async () => {
79+
export const beforeEach = async () => {
8080
// Drop the databases that get created by tests or the functions below
8181
const promises = [];
8282

@@ -87,7 +87,13 @@ beforeEach(async () => {
8787
}
8888

8989
await Promise.all(promises);
90-
});
90+
};
91+
92+
export const mochaRootHooks: Mocha.RootHookObject = {
93+
beforeAll,
94+
beforeEach,
95+
afterAll,
96+
};
9197

9298
export async function createDummyCollections(): Promise<void> {
9399
const promises = [];

0 commit comments

Comments
 (0)