Skip to content

Commit 0601808

Browse files
committed
Split test-shell.ts to separate concerns
1 parent 8f3b45e commit 0601808

File tree

5 files changed

+104
-101
lines changed

5 files changed

+104
-101
lines changed

packages/e2e-tests/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"url": "git://github.com/mongodb-js/mongosh.git"
1212
},
1313
"scripts": {
14-
"test": "mocha -r ts-node/register -r \"../../scripts/import-expansions.js\" -r \"./test/test-shell.ts\" --timeout 15000 --colors \"./test/*.spec.ts\"",
14+
"test": "mocha -r ts-node/register -r \"../../scripts/import-expansions.js\" -r \"./test/test-shell-context.ts\" --timeout 15000 --colors \"./test/*.spec.ts\"",
1515
"test-ci": "node ../../scripts/run-if-package-requested.js npm test",
1616
"test-coverage": "nyc --no-clean --cwd ../.. --reporter=none npm run test",
1717
"test-ci-coverage": "nyc --no-clean --cwd ../.. --reporter=none npm run test-ci",

packages/e2e-tests/test/e2e.spec.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import type { Db } from 'mongodb';
44
import { MongoClient } from 'mongodb';
55

66
import { eventually } from '../../../testing/eventually';
7-
import { ensureTestShellAfterHook, TestShell } from './test-shell';
7+
import { TestShell } from './test-shell';
8+
import { ensureTestShellAfterHook } from './test-shell-context';
89
import {
910
skipIfServerVersion,
1011
startSharedTestServer,

packages/e2e-tests/test/test-shell.spec.ts renamed to packages/e2e-tests/test/test-shell-context.spec.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { ensureTestShellAfterHook, TestShell } from './test-shell';
1+
import { TestShell } from './test-shell';
2+
import { ensureTestShellAfterHook } from './test-shell-context';
23

3-
describe('TestShell', function () {
4+
describe('TestShell context', function () {
45
context('hooks and tests', function () {
56
before(async function () {
67
const shell = this.startTestShell({ args: ['--nodb'] });
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import assert from 'assert';
2+
import Mocha from 'mocha';
3+
import { TestShell, type TestShellOptions } from './test-shell';
4+
5+
declare module 'mocha' {
6+
interface Context {
7+
/**
8+
* Starts a test shell and registers a hook to kill it after the test
9+
*/
10+
startTestShell(options?: TestShellOptions): TestShell;
11+
}
12+
}
13+
14+
const TEST_SHELLS_AFTER_ALL = Symbol('test-shells-after-all');
15+
const TEST_SHELLS_AFTER_EACH = Symbol('test-shells-after-each');
16+
17+
type AfterAllInjectedSuite = {
18+
[TEST_SHELLS_AFTER_ALL]: Set<TestShell>;
19+
};
20+
21+
type AfterEachInjectedSuite = {
22+
[TEST_SHELLS_AFTER_EACH]: Set<TestShell>;
23+
};
24+
25+
/**
26+
* Registers an after (all or each) hook to kill test shells started during the hooks or tests.
27+
* You don't have to call this from tests, but you can if you want to register an after (each) hook
28+
* which runs after the shells have been killed.
29+
*/
30+
export function ensureTestShellAfterHook(
31+
hookName: 'afterEach',
32+
suite: Mocha.Suite
33+
): asserts suite is AfterEachInjectedSuite & Mocha.Suite;
34+
export function ensureTestShellAfterHook(
35+
hookName: 'afterAll',
36+
suite: Mocha.Suite
37+
): asserts suite is AfterAllInjectedSuite & Mocha.Suite;
38+
export function ensureTestShellAfterHook(
39+
hookName: 'afterEach' | 'afterAll',
40+
suite: Partial<AfterAllInjectedSuite & AfterEachInjectedSuite> & Mocha.Suite
41+
): void {
42+
const symbol =
43+
hookName === 'afterAll' ? TEST_SHELLS_AFTER_ALL : TEST_SHELLS_AFTER_EACH;
44+
if (!suite[symbol]) {
45+
// Store the set of shells to kill afterwards
46+
const shells = new Set<TestShell>();
47+
suite[symbol] = shells;
48+
suite[hookName](async () => {
49+
const shellsToKill = [...shells];
50+
shells.clear();
51+
await Promise.all(
52+
shellsToKill.map((shell) => {
53+
// TODO: Consider if it's okay to kill those that are already killed?
54+
shell.kill();
55+
return shell.waitForExit();
56+
})
57+
);
58+
});
59+
}
60+
}
61+
62+
Mocha.Context.prototype.startTestShell = function (
63+
this: Mocha.Context,
64+
options: TestShellOptions
65+
) {
66+
const { test: runnable } = this;
67+
assert(runnable, 'Expected a runnable / test');
68+
const { parent } = runnable;
69+
assert(parent, 'Expected runnable to have a parent');
70+
// Start the shell
71+
const shell = TestShell.start(options);
72+
// Register a hook to kill the shell
73+
if (runnable instanceof Mocha.Hook) {
74+
if (
75+
runnable.originalTitle === '"before each" hook' ||
76+
runnable.originalTitle === '"after each" hook'
77+
) {
78+
ensureTestShellAfterHook('afterEach', parent);
79+
parent[TEST_SHELLS_AFTER_EACH].add(shell);
80+
} else if (
81+
runnable.originalTitle === '"before all" hook' ||
82+
runnable.originalTitle === '"after all" hook'
83+
) {
84+
ensureTestShellAfterHook('afterAll', parent);
85+
parent[TEST_SHELLS_AFTER_ALL].add(shell);
86+
} else {
87+
throw new Error(`Unexpected ${runnable.originalTitle || runnable.title}`);
88+
}
89+
} else if (runnable instanceof Mocha.Test) {
90+
ensureTestShellAfterHook('afterEach', parent);
91+
parent[TEST_SHELLS_AFTER_EACH].add(shell);
92+
} else {
93+
throw new Error('Unexpected Runnable: Expected a Hook or a Test');
94+
}
95+
return shell;
96+
};

packages/e2e-tests/test/test-shell.ts

+2-97
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import Mocha from 'mocha';
21
import assert from 'assert';
32
import type {
43
ChildProcess,
@@ -49,7 +48,8 @@ export class TestShell {
4948
private static _openShells: Set<TestShell> = new Set();
5049

5150
/**
52-
* @deprecated Use the {@link Mocha.Context.startTestShell} hook instead
51+
* Starts a test shell.
52+
* @private Use the {@link Mocha.Context.startTestShell} hook instead
5353
*/
5454
static start(options: TestShellOptions = { args: [] }): TestShell {
5555
let shellProcess: ChildProcessWithoutNullStreams;
@@ -335,98 +335,3 @@ export class TestShell {
335335
return match.groups!.logId;
336336
}
337337
}
338-
339-
// Context extension to manage TestShell lifetime
340-
341-
declare module 'mocha' {
342-
interface Context {
343-
/**
344-
* Starts a test shell and registers a hook to kill it after the test
345-
*/
346-
startTestShell(options?: TestShellOptions): TestShell;
347-
}
348-
}
349-
350-
const TEST_SHELLS_AFTER_ALL = Symbol('test-shells-after-all');
351-
const TEST_SHELLS_AFTER_EACH = Symbol('test-shells-after-each');
352-
353-
type AfterAllInjectedSuite = {
354-
[TEST_SHELLS_AFTER_ALL]: Set<TestShell>;
355-
};
356-
357-
type AfterEachInjectedSuite = {
358-
[TEST_SHELLS_AFTER_EACH]: Set<TestShell>;
359-
};
360-
361-
/**
362-
* Registers an after (all or each) hook to kill test shells started during the hooks or tests.
363-
* You don't have to call this from tests, but you can if you want to register an after (each) hook
364-
* which runs after the shells have been killed.
365-
*/
366-
export function ensureTestShellAfterHook(
367-
hookName: 'afterEach',
368-
suite: Mocha.Suite
369-
): asserts suite is AfterEachInjectedSuite & Mocha.Suite;
370-
export function ensureTestShellAfterHook(
371-
hookName: 'afterAll',
372-
suite: Mocha.Suite
373-
): asserts suite is AfterAllInjectedSuite & Mocha.Suite;
374-
export function ensureTestShellAfterHook(
375-
hookName: 'afterEach' | 'afterAll',
376-
suite: Partial<AfterAllInjectedSuite & AfterEachInjectedSuite> & Mocha.Suite
377-
): void {
378-
const symbol =
379-
hookName === 'afterAll' ? TEST_SHELLS_AFTER_ALL : TEST_SHELLS_AFTER_EACH;
380-
if (!suite[symbol]) {
381-
// Store the set of shells to kill afterwards
382-
const shells = new Set<TestShell>();
383-
suite[symbol] = shells;
384-
suite[hookName](async () => {
385-
const shellsToKill = [...shells];
386-
shells.clear();
387-
await Promise.all(
388-
shellsToKill.map((shell) => {
389-
// TODO: Consider if it's okay to kill those that are already killed?
390-
shell.kill();
391-
return shell.waitForExit();
392-
})
393-
);
394-
});
395-
}
396-
}
397-
398-
Mocha.Context.prototype.startTestShell = function (
399-
this: Mocha.Context,
400-
options: TestShellOptions
401-
) {
402-
const { test: runnable } = this;
403-
assert(runnable, 'Expected a runnable / test');
404-
const { parent } = runnable;
405-
assert(parent, 'Expected runnable to have a parent');
406-
// Start the shell
407-
const shell = TestShell.start(options);
408-
// Register a hook to kill the shell
409-
if (runnable instanceof Mocha.Hook) {
410-
if (
411-
runnable.originalTitle === '"before each" hook' ||
412-
runnable.originalTitle === '"after each" hook'
413-
) {
414-
ensureTestShellAfterHook('afterEach', parent);
415-
parent[TEST_SHELLS_AFTER_EACH].add(shell);
416-
} else if (
417-
runnable.originalTitle === '"before all" hook' ||
418-
runnable.originalTitle === '"after all" hook'
419-
) {
420-
ensureTestShellAfterHook('afterAll', parent);
421-
parent[TEST_SHELLS_AFTER_ALL].add(shell);
422-
} else {
423-
throw new Error(`Unexpected ${runnable.originalTitle || runnable.title}`);
424-
}
425-
} else if (runnable instanceof Mocha.Test) {
426-
ensureTestShellAfterHook('afterEach', parent);
427-
parent[TEST_SHELLS_AFTER_EACH].add(shell);
428-
} else {
429-
throw new Error('Unexpected Runnable: Expected a Hook or a Test');
430-
}
431-
return shell;
432-
};

0 commit comments

Comments
 (0)