Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 22 additions & 20 deletions e2e/__tests__/detectOpenHandles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import {wrap} from 'jest-snapshot-serializer-raw';
import {onNodeVersions} from '@jest/test-utils';
import runJest, {until} from '../runJest';
import runJest, {runContinuous} from '../runJest';

try {
require('async_hooks');
Expand All @@ -27,33 +27,34 @@ function getTextAfterTest(stderr: string) {
}

it('prints message about flag on slow tests', async () => {
const {stderr} = await until(
'detect-open-handles',
['outside'],
'Jest did not exit one second after the test run has completed.',
const run = runContinuous('detect-open-handles', ['outside']);
await run.waitUntil(({stderr}) =>
stderr.includes(
'Jest did not exit one second after the test run has completed.',
),
);
const {stderr} = await run.end();
const textAfterTest = getTextAfterTest(stderr);

expect(wrap(textAfterTest)).toMatchSnapshot();
});

it('prints message about flag on forceExit', async () => {
const {stderr} = await until(
'detect-open-handles',
['outside', '--forceExit'],
'Force exiting Jest',
);
const run = runContinuous('detect-open-handles', ['outside', '--forceExit']);
await run.waitUntil(({stderr}) => stderr.includes('Force exiting Jest'));
const {stderr} = await run.end();
const textAfterTest = getTextAfterTest(stderr);

expect(wrap(textAfterTest)).toMatchSnapshot();
});

it('prints out info about open handlers', async () => {
const {stderr} = await until(
'detect-open-handles',
['outside', '--detectOpenHandles'],
'Jest has detected',
);
const run = runContinuous('detect-open-handles', [
'outside',
'--detectOpenHandles',
]);
await run.waitUntil(({stderr}) => stderr.includes('Jest has detected'));
const {stderr} = await run.end();
const textAfterTest = getTextAfterTest(stderr);

expect(wrap(textAfterTest)).toMatchSnapshot();
Expand Down Expand Up @@ -84,11 +85,12 @@ onNodeVersions('>=11', () => {
});

it('prints out info about open handlers from inside tests', async () => {
const {stderr} = await until(
'detect-open-handles',
['inside', '--detectOpenHandles'],
'Jest has detected',
);
const run = runContinuous('detect-open-handles', [
'inside',
'--detectOpenHandles',
]);
await run.waitUntil(({stderr}) => stderr.includes('Jest has detected'));
const {stderr} = await run.end();
const textAfterTest = getTextAfterTest(stderr);

expect(wrap(textAfterTest)).toMatchSnapshot();
Expand Down
73 changes: 62 additions & 11 deletions e2e/runJest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,28 +136,79 @@ export const json = function(
}
};

// Runs `jest` until a given output is achieved, then kills it with `SIGTERM`
export const until = async function(
type StdErrAndOutString = {stderr: string; stdout: string};
type ConditionFunction = (arg: StdErrAndOutString) => boolean;

// Runs `jest` continously (watch mode) and allows the caller to wait for
// conditions on stdout and stderr and to end the process.
export const runContinuous = function(
dir: string,
args: Array<string> | undefined,
text: string,
args?: Array<string>,
options: RunJestOptions = {},
) {
const jestPromise = spawnJest(dir, args, {timeout: 30000, ...options}, true);

jestPromise.stderr!.pipe(
let stderr = '';
let stdout = '';
const pending = new Set<(arg: StdErrAndOutString) => void>();

const dispatch = () => {
for (const fn of pending) {
fn({stderr, stdout});
}
};

jestPromise.stdout!.pipe(
new Writable({
write(chunk, _encoding, callback) {
const output = chunk.toString('utf8');

if (output.includes(text)) {
jestPromise.kill();
}
stdout += chunk.toString('utf8');
dispatch();
callback();
},
}),
);

jestPromise.stderr!.pipe(
new Writable({
write(chunk, _encoding, callback) {
stderr += chunk.toString('utf8');
dispatch();
callback();
},
}),
);

return normalizeStdoutAndStderr(await jestPromise, options);
return {
async end() {
jestPromise.kill();

const result = await jestPromise;

// Not sure why we have to assign here... The ones on `result` are empty strings
result.stdout = stdout;
result.stderr = stderr;

return normalizeStdoutAndStderr(result, options);
},

getCurrentOutput(): StdErrAndOutString {
return {stderr, stdout};
},

getInput() {
return jestPromise.stdin;
},

async waitUntil(fn: ConditionFunction) {
await new Promise(resolve => {
const check = (state: StdErrAndOutString) => {
if (fn(state)) {
pending.delete(check);
resolve();
}
};
pending.add(check);
});
},
};
};