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
3 changes: 2 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ jobs:
fail-fast: false
matrix:
node-version:
- 26
- 24
- 18
os:
Expand All @@ -31,7 +32,7 @@ jobs:
with:
args: --cache --verbose --no-progress --include-fragments --exclude packagephobia --exclude /pull/ --exclude linkedin --exclude stackoverflow --exclude stackexchange --exclude github.com/nodejs/node --exclude file:///test --exclude invalid.com '*.md' 'docs/*.md' '.github/**/*.md' '*.json' '*.js' 'lib/**/*.js' 'test/**/*.js' '*.ts' 'test-d/**/*.ts'
fail: true
if: ${{ matrix.os == 'ubuntu' && matrix.node-version == 24 }}
if: ${{ matrix.os == 'ubuntu' && matrix.node-version == 26 }}
- run: npm run lint
- run: npm run type
- run: npm run unit
Expand Down
29 changes: 15 additions & 14 deletions test/arguments/local.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {existsSync} from 'node:fs';
import path from 'node:path';
import process from 'node:process';
import {pathToFileURL} from 'node:url';
Expand All @@ -10,52 +11,52 @@ process.env.FOO = 'foo';

const isWindows = process.platform === 'win32';
const ENOENT_REGEXP = isWindows ? /failed with exit code 1/ : /spawn.* ENOENT/;
const AVA_BINARY_NAMES = isWindows ? ['ava.cmd', 'ava.exe', 'ava.bat', 'ava.ps1', 'ava'] : ['ava'];

const getPathWithoutLocalDirectory = () => {
const getPathWithoutCommand = commandNames => {
const newPath = process.env[PATH_KEY]
.split(path.delimiter)
.filter(pathDirectory => !BIN_DIR_REGEXP.test(pathDirectory)).join(path.delimiter);
.filter(pathDirectory => commandNames.every(commandName => !existsSync(path.join(pathDirectory, commandName))))
.join(path.delimiter);
return {[PATH_KEY]: newPath};
};

const BIN_DIR_REGEXP = /node_modules[\\/]\.bin/;

const pathWitoutLocalDirectory = getPathWithoutLocalDirectory();
const pathWithoutAva = getPathWithoutCommand(AVA_BINARY_NAMES);

test('preferLocal: true', async t => {
await t.notThrowsAsync(execa('ava', ['--version'], {preferLocal: true, env: pathWitoutLocalDirectory}));
await t.notThrowsAsync(execa('ava', ['--version'], {preferLocal: true, env: pathWithoutAva}));
});

test('preferLocal: false', async t => {
await t.throwsAsync(execa('ava', ['--version'], {preferLocal: false, env: pathWitoutLocalDirectory}), {message: ENOENT_REGEXP});
await t.throwsAsync(execa('ava', ['--version'], {preferLocal: false, env: pathWithoutAva}), {message: ENOENT_REGEXP});
});

test('preferLocal: undefined', async t => {
await t.throwsAsync(execa('ava', ['--version'], {env: pathWitoutLocalDirectory}), {message: ENOENT_REGEXP});
await t.throwsAsync(execa('ava', ['--version'], {env: pathWithoutAva}), {message: ENOENT_REGEXP});
});

test('preferLocal: undefined with $', async t => {
await t.notThrowsAsync($('ava', ['--version'], {env: pathWitoutLocalDirectory}));
await t.notThrowsAsync($('ava', ['--version'], {env: pathWithoutAva}));
});

test('preferLocal: undefined with $.sync', t => {
t.notThrows(() => $.sync('ava', ['--version'], {env: pathWitoutLocalDirectory}));
t.notThrows(() => $.sync('ava', ['--version'], {env: pathWithoutAva}));
});

test('preferLocal: undefined with execa.pipe`...`', async t => {
await t.throwsAsync(() => execa('node', ['--version']).pipe({env: pathWitoutLocalDirectory})`ava --version`);
await t.throwsAsync(() => execa('node', ['--version']).pipe({env: pathWithoutAva})`ava --version`);
});

test('preferLocal: undefined with $.pipe`...`', async t => {
await t.notThrows(() => $('node', ['--version']).pipe({env: pathWitoutLocalDirectory})`ava --version`);
await t.notThrows(() => $('node', ['--version']).pipe({env: pathWithoutAva})`ava --version`);
});

test('preferLocal: undefined with execa.pipe()', async t => {
await t.throwsAsync(() => execa('node', ['--version']).pipe('ava', ['--version'], {env: pathWitoutLocalDirectory}));
await t.throwsAsync(() => execa('node', ['--version']).pipe('ava', ['--version'], {env: pathWithoutAva}));
});

test('preferLocal: undefined with $.pipe()', async t => {
await t.notThrows(() => $('node', ['--version']).pipe('ava', ['--version'], {env: pathWitoutLocalDirectory}));
await t.notThrows(() => $('node', ['--version']).pipe('ava', ['--version'], {env: pathWithoutAva}));
});

test('localDir option', async t => {
Expand Down
4 changes: 2 additions & 2 deletions test/helpers/early-error.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import {execa, execaSync} from '../../index.js';

export const earlyErrorOptions = {detached: 'true'};
export const getEarlyErrorSubprocess = options => execa('empty.js', {...earlyErrorOptions, ...options});
export const earlyErrorOptionsSync = {maxBuffer: false};
export const earlyErrorOptionsSync = {windowsHide: 'true'};
export const getEarlyErrorSubprocessSync = options => execaSync('empty.js', {...earlyErrorOptionsSync, ...options});

export const expectedEarlyError = {code: 'ERR_INVALID_ARG_TYPE'};
export const expectedEarlyErrorSync = {code: 'ERR_OUT_OF_RANGE'};
export const expectedEarlyErrorSync = {code: 'ERR_INVALID_ARG_TYPE'};
1 change: 1 addition & 0 deletions test/helpers/input.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {inspect} from 'node:util';
const textEncoder = new TextEncoder();

export const foobarString = 'foobar';
export const foobarRed = `\u001B[31m${foobarString}\u001B[39m`;
export const foobarArray = ['foo', 'bar'];
export const foobarUint8Array = textEncoder.encode(foobarString);
export const foobarArrayBuffer = foobarUint8Array.buffer;
Expand Down
4 changes: 2 additions & 2 deletions test/return/message.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ test('error.message newlines are consistent - no newline', testErrorMessageConsi
test('error.message newlines are consistent - newline', testErrorMessageConsistent, 'stdout\n');

test('Original error.message is kept', async t => {
const {originalMessage} = await t.throwsAsync(execa('noop.js', {uid: true}));
t.is(originalMessage, 'The "options.uid" property must be int32. Received type boolean (true)');
const {originalMessage} = await t.throwsAsync(execa('noop.js', {windowsHide: 'true'}));
t.is(originalMessage, 'The "options.windowsHide" property must be of type boolean. Received type string (\'true\')');
});

const testIpcOutput = async (t, doubles, ipcInput, returnedMessage) => {
Expand Down
5 changes: 2 additions & 3 deletions test/verbose/error.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import test from 'ava';
import {red} from 'yoctocolors';
import {setFixtureDirectory} from '../helpers/fixtures-directory.js';
import {foobarString} from '../helpers/input.js';
import {foobarString, foobarRed} from '../helpers/input.js';
import {nestedSubprocess} from '../helpers/nested.js';
import {
QUOTE,
Expand Down Expand Up @@ -150,7 +149,7 @@ test('Does not escape internal characters from error', async t => {
});

test('Escapes and strips color sequences from error', async t => {
const {stderr} = await t.throwsAsync(nestedSubprocess('noop-forever.js', [red(foobarString)], {parentFixture: 'nested-fail.js', verbose: 'short'}, {env: {FORCE_COLOR: '1'}}));
const {stderr} = await t.throwsAsync(nestedSubprocess('noop-forever.js', [foobarRed], {parentFixture: 'nested-fail.js', verbose: 'short'}));
t.deepEqual(getErrorLines(stderr), [
`${testTimestamp} [0] × Command was killed with SIGTERM (Termination): noop-forever.js ${QUOTE}\\u001b[31m${foobarString}\\u001b[39m${QUOTE}`,
`${testTimestamp} [0] × ${foobarString}`,
Expand Down
4 changes: 2 additions & 2 deletions test/verbose/info.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ test('Prints early spawn errors, sync', async t => {
const {stderr} = await nestedSubprocess('empty.js', {...earlyErrorOptionsSync, verbose: 'full', isSync: true});
t.deepEqual(getNormalizedLines(stderr), [
`${testTimestamp} [0] $ empty.js`,
`${testTimestamp} [0] × Command failed with ERR_OUT_OF_RANGE: empty.js`,
`${testTimestamp} [0] × The value of "options.maxBuffer" is out of range. It must be a positive number. Received false`,
`${testTimestamp} [0] × Command failed with ERR_INVALID_ARG_TYPE: empty.js`,
`${testTimestamp} [0] × The "options.windowsHide" property must be of type boolean. Received type string ('true')`,
`${testTimestamp} [0] × (done in 0ms)`,
]);
});
5 changes: 2 additions & 3 deletions test/verbose/ipc.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import {on} from 'node:events';
import {inspect} from 'node:util';
import test from 'ava';
import {red} from 'yoctocolors';
import {setFixtureDirectory} from '../helpers/fixtures-directory.js';
import {foobarString, foobarObject} from '../helpers/input.js';
import {foobarString, foobarRed, foobarObject} from '../helpers/input.js';
import {nestedSubprocess, nestedInstance} from '../helpers/nested.js';
import {
getIpcLine,
Expand Down Expand Up @@ -84,7 +83,7 @@ test('Does not escape internal characters from IPC', async t => {
});

test('Strips color sequences from IPC', async t => {
const {stderr} = await nestedSubprocess('ipc-send.js', [red(foobarString)], {ipc: true, verbose: 'full'}, {env: {FORCE_COLOR: '1'}});
const {stderr} = await nestedSubprocess('ipc-send.js', [foobarRed], {ipc: true, verbose: 'full'});
t.is(getIpcLine(stderr), `${testTimestamp} [0] * ${foobarString}`);
});

Expand Down
2 changes: 1 addition & 1 deletion test/verbose/log.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ test('Logs on stderr not stdout, verbose "short", sync', testNoStdout, 'short',
test('Logs on stderr not stdout, verbose "full", sync', testNoStdout, 'full', true);

const testColor = async (t, expectedResult, forceColor) => {
const {stderr} = await nestedSubprocess('noop.js', [foobarString], {verbose: 'short'}, {env: {FORCE_COLOR: forceColor}});
const {stderr} = await nestedSubprocess('noop.js', [foobarString], {verbose: 'short'}, {env: {FORCE_COLOR: forceColor, NO_COLOR: undefined}});
t.is(stderr !== stripVTControlCharacters(stderr), expectedResult);
};

Expand Down
5 changes: 2 additions & 3 deletions test/verbose/output-enable.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import test from 'ava';
import {red} from 'yoctocolors';
import {setFixtureDirectory} from '../helpers/fixtures-directory.js';
import {foobarString, foobarUtf16Uint8Array} from '../helpers/input.js';
import {foobarString, foobarRed, foobarUtf16Uint8Array} from '../helpers/input.js';
import {fullStdio} from '../helpers/stdio.js';
import {nestedSubprocess} from '../helpers/nested.js';
import {
Expand Down Expand Up @@ -106,7 +105,7 @@ test('Does not escape internal characters from stdout', async t => {
});

test('Strips color sequences from stdout', async t => {
const {stderr} = await nestedSubprocess('noop.js', [red(foobarString)], {verbose: 'full'}, {env: {FORCE_COLOR: '1'}});
const {stderr} = await nestedSubprocess('noop.js', [foobarRed], {verbose: 'full'});
t.is(getOutputLine(stderr), `${testTimestamp} [0] ${foobarString}`);
});

Expand Down
5 changes: 2 additions & 3 deletions test/verbose/start.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import test from 'ava';
import {red} from 'yoctocolors';
import {setFixtureDirectory} from '../helpers/fixtures-directory.js';
import {foobarString} from '../helpers/input.js';
import {foobarString, foobarRed} from '../helpers/input.js';
import {nestedSubprocess} from '../helpers/nested.js';
import {
QUOTE,
Expand Down Expand Up @@ -152,7 +151,7 @@ test('Does not escape internal characters from command', async t => {
});

test('Escapes color sequences from command', async t => {
const {stderr} = await nestedSubprocess('noop.js', [red(foobarString)], {verbose: 'short'}, {env: {FORCE_COLOR: '1'}});
const {stderr} = await nestedSubprocess('noop.js', [foobarRed], {verbose: 'short'});
t.true(getCommandLine(stderr).includes(`${QUOTE}\\u001b[31m${foobarString}\\u001b[39m${QUOTE}`));
});

Expand Down
Loading