diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 30e4a55612..452b039aa6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,6 +10,7 @@ jobs: fail-fast: false matrix: node-version: + - 26 - 24 - 18 os: @@ -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 diff --git a/test/arguments/local.js b/test/arguments/local.js index 47136f33af..b2035b57d0 100644 --- a/test/arguments/local.js +++ b/test/arguments/local.js @@ -1,3 +1,4 @@ +import {existsSync} from 'node:fs'; import path from 'node:path'; import process from 'node:process'; import {pathToFileURL} from 'node:url'; @@ -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 => { diff --git a/test/helpers/early-error.js b/test/helpers/early-error.js index ced3752cc0..0b9395a001 100644 --- a/test/helpers/early-error.js +++ b/test/helpers/early-error.js @@ -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'}; diff --git a/test/helpers/input.js b/test/helpers/input.js index d4c027584f..509fcc019a 100644 --- a/test/helpers/input.js +++ b/test/helpers/input.js @@ -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; diff --git a/test/return/message.js b/test/return/message.js index 0642c2497e..ddbcde0976 100644 --- a/test/return/message.js +++ b/test/return/message.js @@ -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) => { diff --git a/test/verbose/error.js b/test/verbose/error.js index 4b018d984d..82d1a8021b 100644 --- a/test/verbose/error.js +++ b/test/verbose/error.js @@ -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, @@ -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}`, diff --git a/test/verbose/info.js b/test/verbose/info.js index 5c9188f28c..6d5ff0ae3d 100644 --- a/test/verbose/info.js +++ b/test/verbose/info.js @@ -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)`, ]); }); diff --git a/test/verbose/ipc.js b/test/verbose/ipc.js index b842746df4..a2ac942726 100644 --- a/test/verbose/ipc.js +++ b/test/verbose/ipc.js @@ -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, @@ -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}`); }); diff --git a/test/verbose/log.js b/test/verbose/log.js index c2b447eea9..778a01603e 100644 --- a/test/verbose/log.js +++ b/test/verbose/log.js @@ -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); }; diff --git a/test/verbose/output-enable.js b/test/verbose/output-enable.js index 5820a1b08b..eef37ef032 100644 --- a/test/verbose/output-enable.js +++ b/test/verbose/output-enable.js @@ -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 { @@ -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}`); }); diff --git a/test/verbose/start.js b/test/verbose/start.js index 78f38d08a4..44ba0f87bf 100644 --- a/test/verbose/start.js +++ b/test/verbose/start.js @@ -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, @@ -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}`)); });