Skip to content

Commit

Permalink
Self-host the built-in Node.js assert tests
Browse files Browse the repository at this point in the history
Also make `test-ava` work from inside the `test` directory.

Co-authored-by: Mark Wubben <mark@novemberborn.net>
  • Loading branch information
jonathansamines and novemberborn committed Aug 3, 2020
1 parent 5ddc9fd commit 1150991
Show file tree
Hide file tree
Showing 12 changed files with 60 additions and 55 deletions.
5 changes: 1 addition & 4 deletions test-tap/helper/cli.js
Expand Up @@ -4,7 +4,6 @@ const childProcess = require('child_process');
const getStream = require('get-stream');

const cliPath = path.join(__dirname, '../../cli.js');
const ttySimulator = path.join(__dirname, 'simulate-tty.js');

function execCli(args, options, cb) {
let dirname;
Expand All @@ -24,9 +23,7 @@ function execCli(args, options, cb) {
let stderr;

const processPromise = new Promise(resolve => {
// Spawning a child with piped IO means that the CLI will never see a TTY.
// Inserting a shim here allows us to fake a TTY.
child = childProcess.spawn(process.execPath, ['--require', ttySimulator, cliPath].concat(args), {
child = childProcess.spawn(process.execPath, [cliPath].concat(args), {
cwd: dirname,
env: {AVA_FORCE_CI: 'ci', ...env}, // Force CI to ensure the correct reporter is selected
// env,
Expand Down
29 changes: 0 additions & 29 deletions test-tap/integration/node-assertions.js

This file was deleted.

2 changes: 1 addition & 1 deletion test/assertions/test.js
Expand Up @@ -2,6 +2,6 @@ const test = require('@ava/test');
const exec = require('../helpers/exec');

test('happy path', async t => {
const result = await exec.fixture('happy-path.js');
const result = await exec.fixture(['happy-path.js']);
t.snapshot(result.stats.passed.map(({title}) => title));
});
@@ -1,5 +1,5 @@
const test = require('ava');
const assert = require('assert');
const test = require('../../..');

test('test', () => {
assert(false);
Expand Down
7 changes: 7 additions & 0 deletions test/builtin-nodejs-assert/fixtures/package.json
@@ -0,0 +1,7 @@
{
"ava": {
"files": [
"*.js"
]
}
}
25 changes: 25 additions & 0 deletions test/builtin-nodejs-assert/test.js
@@ -0,0 +1,25 @@
const test = require('@ava/test');
const exec = require('../helpers/exec');

test('node assertion failures are reported to the console when running in a terminal', async t => {
const options = {
env: {
// The AssertionError constructor in Node.js 10 depends on the TTY interface, so opt-in
// to it being simulated.
AVA_SIMULATE_TTY: true,
AVA_TTY_COLOR_DEPTH: 8
}
};

const result = await t.throwsAsync(exec.fixture(['assert-failure.js'], options));
const error = result.stats.getError(result.stats.failed[0]);

t.true(error.values.every(value => value.formatted.includes('AssertionError')));
});

test('node assertion failures are reported to the console when not running in a terminal', async t => {
const result = await t.throwsAsync(exec.fixture(['assert-failure.js']));
const error = result.stats.getError(result.stats.failed[0]);

t.true(error.values.every(value => value.formatted.includes('AssertionError')));
});
12 changes: 8 additions & 4 deletions test/helpers/exec.js
Expand Up @@ -3,8 +3,11 @@ const v8 = require('v8');

const test = require('@ava/test');
const execa = require('execa');
const defaultsDeep = require('lodash/defaultsDeep');

const cliPath = path.resolve(__dirname, '../../cli.js');
const ttySimulator = path.join(__dirname, './simulate-tty.js');

const serialization = process.versions.node >= '12.16.0' ? 'advanced' : 'json';

const normalizePath = (root, file) => path.posix.normalize(path.relative(root, file));
Expand All @@ -25,15 +28,16 @@ const compareStatObjects = (a, b) => {
return 1;
};

exports.fixture = async (...args) => {
exports.fixture = async (args, options = {}) => {
const cwd = path.join(path.dirname(test.meta.file), 'fixtures');
const running = execa.node(cliPath, args, {
const running = execa.node(cliPath, args, defaultsDeep({
env: {
AVA_EMIT_RUN_STATUS_OVER_IPC: 'I\'ll find a payphone baby / Take some time to talk to you'
},
cwd,
serialization
});
serialization,
nodeOptions: ['--require', ttySimulator]
}, options));

// Besides buffering stderr, if this environment variable is set, also pipe
// to stderr. This can be useful when debugging the tests.
Expand Down
16 changes: 8 additions & 8 deletions test-tap/helper/simulate-tty.js → test/helpers/simulate-tty.js
Expand Up @@ -5,7 +5,7 @@ const assertHasColorsArguments = count => {
tty.WriteStream.prototype.hasColors(count);
};

const makeHasColors = colorDepth => (count = 16, env = undefined) => {
const makeHasColors = colorDepth => (count = 16, env) => { // eslint-disable-line default-param-last
// `count` is optional too, so make sure it's not an env object.
if (env === undefined && typeof count === 'object' && count !== null) {
count = 16;
Expand All @@ -15,7 +15,7 @@ const makeHasColors = colorDepth => (count = 16, env = undefined) => {
return count <= 2 ** colorDepth;
};

const simulateTTY = (stream, colorDepth, hasColors) => {
const simulateTTY = (stream, colorDepth) => {
stream.isTTY = true;
stream.columns = 80;
stream.rows = 24;
Expand All @@ -24,9 +24,10 @@ const simulateTTY = (stream, colorDepth, hasColors) => {
stream.getColorDepth = () => colorDepth;
}

if (hasColors) {
stream.hasColors = makeHasColors(colorDepth);
}
stream.hasColors = makeHasColors(colorDepth);
stream.clearLine = tty.WriteStream.prototype.clearLine;
stream.cursorTo = tty.WriteStream.prototype.cursorTo;
stream.moveCursor = tty.WriteStream.prototype.moveCursor;
};

// The execCli helper spawns tests in a child process. This means that stdout is
Expand All @@ -36,8 +37,7 @@ if (process.env.AVA_SIMULATE_TTY) {
const colorDepth = process.env.AVA_TTY_COLOR_DEPTH ?
Number.parseInt(process.env.AVA_TTY_COLOR_DEPTH, 10) :
undefined;
const hasColors = process.env.AVA_TTY_HAS_COLORS !== undefined;

simulateTTY(process.stderr, colorDepth, hasColors);
simulateTTY(process.stdout, colorDepth, hasColors);
simulateTTY(process.stderr, colorDepth);
simulateTTY(process.stdout, colorDepth);
}
4 changes: 2 additions & 2 deletions test/hook-restrictions/test.js
Expand Up @@ -2,13 +2,13 @@ const test = require('@ava/test');
const exec = require('../helpers/exec');

test('snapshots cannot be used in hooks', async t => {
const result = await t.throwsAsync(exec.fixture('invalid-snapshots-in-hooks.js'));
const result = await t.throwsAsync(exec.fixture(['invalid-snapshots-in-hooks.js']));
const error = result.stats.getError(result.stats.failedHooks[0]);
t.snapshot(error.message, 'error message');
});

test('`t.try()` cannot be used in hooks', async t => {
const result = await t.throwsAsync(exec.fixture('invalid-t-try-in-hooks.js'));
const result = await t.throwsAsync(exec.fixture(['invalid-t-try-in-hooks.js']));
const error = result.stats.getError(result.stats.failedHooks[0]);
t.snapshot(error.message, 'error message');
});
1 change: 1 addition & 0 deletions test/node_modules/.bin/test-ava

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions test/snapshot-updates/test.js
Expand Up @@ -2,14 +2,14 @@ const test = require('@ava/test');
const exec = require('../helpers/exec');

test('cannot update snapshots when file contains skipped tests', async t => {
const result = await t.throwsAsync(exec.fixture('contains-skip.js', '-u'));
const result = await t.throwsAsync(exec.fixture(['contains-skip.js', '-u']));
t.snapshot(result.stats.failed, 'failed tests');
t.snapshot(result.stats.skipped, 'skipped tests');
t.snapshot(result.stats.unsavedSnapshots, 'files where snapshots could not be updated');
});

test('cannot update snapshots when file contains exclusive tests', async t => {
const result = await exec.fixture('contains-only.js', '-u');
const result = await exec.fixture(['contains-only.js', '-u']);
t.snapshot(result.stats.failed, 'failed tests');
t.snapshot(result.stats.passed, 'passed tests');
t.snapshot(result.stats.unsavedSnapshots, 'files where snapshots could not be updated');
Expand All @@ -18,11 +18,11 @@ test('cannot update snapshots when file contains exclusive tests', async t => {
const stripLeadingFigures = string => string.replace(/^\W+/, '');

test('cannot update snapshots when matching test titles', async t => {
const result = await t.throwsAsync(exec.fixture('contains-skip.js', '-u', '-m=snapshot'));
const result = await t.throwsAsync(exec.fixture(['contains-skip.js', '-u', '-m=snapshot']));
t.snapshot(stripLeadingFigures(result.stderr.trim()));
});

test('cannot update snapshots when selecting tests by line number', async t => {
const result = await t.throwsAsync(exec.fixture('contains-skip.js:4', '-u'));
const result = await t.throwsAsync(exec.fixture(['contains-skip.js:4', '-u']));
t.snapshot(stripLeadingFigures(result.stderr.trim()));
});
4 changes: 2 additions & 2 deletions test/test-timeouts/test.js
Expand Up @@ -2,13 +2,13 @@ const test = require('@ava/test');
const exec = require('../helpers/exec');

test('timeout message can be specified', async t => {
const result = await t.throwsAsync(exec.fixture('custom-message.js'));
const result = await t.throwsAsync(exec.fixture(['custom-message.js']));
const error = result.stats.getError(result.stats.failed[0]);
t.is(error.message, 'time budget exceeded');
});

test('timeout messages must be strings', async t => {
const result = await t.throwsAsync(exec.fixture('invalid-message.js'));
const result = await t.throwsAsync(exec.fixture(['invalid-message.js']));
const error = result.stats.getError(result.stats.failed[0]);
t.snapshot(error.message, 'error message');
t.snapshot(error.values, 'formatted values');
Expand Down

0 comments on commit 1150991

Please sign in to comment.