diff --git a/.config/vitest.config.mts b/.config/vitest.config.mts index 104645a1b..ef3420347 100644 --- a/.config/vitest.config.mts +++ b/.config/vitest.config.mts @@ -1,9 +1,37 @@ import { defineConfig } from 'vitest/config'; import path from 'node:path'; +import { existsSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; + +import { getEarliestDependencies } from './vitest.earliest.mts'; const isAutoInstallPackage = path.basename(process.cwd()) === 'auto-install'; +const escapeRegExp = (value: string) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + +const getEarliestAliases = (mode: string) => + mode === 'earliest' + ? getEarliestDependencies().map(({ name, path: dependencyPath }) => ({ + find: new RegExp(`^${escapeRegExp(name)}$`), + replacement: dependencyPath + })) + : []; + +const getSnapshotPath = (testPath: string, snapExt: string, mode: string) => { + const defaultPath = path.join( + path.dirname(testPath), + 'snapshots', + path.basename(testPath) + snapExt + ); + // Packages opt in to version-specific snapshots by adding the file to this directory. + const earliestPath = path.join( + path.dirname(testPath), + 'snapshots-earliest', + path.basename(testPath) + snapExt + ); + return mode === 'earliest' && existsSync(earliestPath) ? earliestPath : defaultPath; +}; -export default defineConfig({ +export default defineConfig(({ mode }) => ({ test: { // Enable global APIs for CommonJS test files. globals: true, @@ -20,16 +48,26 @@ export default defineConfig({ '**/test/recipes/**', '**/test/output/**', '**/test/snapshots/**', + '**/test/snapshots-earliest/**', '**/test/types.ts' ], // These tests switch process cwd and invoke package managers; run files serially there. fileParallelism: !isAutoInstallPackage, + // Some tests, e.g. TypeScript-based ones, can take several seconds on slow CI runners. + testTimeout: 20000, // Keep snapshots in the same location used by Ava. - resolveSnapshotPath: (testPath, snapExt) => - path.join(path.dirname(testPath), 'snapshots', path.basename(testPath) + snapExt) + resolveSnapshotPath: (testPath, snapExt) => getSnapshotPath(testPath, snapExt, mode), + setupFiles: + mode === 'earliest' + ? [fileURLToPath(new URL('./vitest.setup.earliest.mts', import.meta.url))] + : [] }, resolve: { // Allow importing the current package under test via `~package` - alias: [{ find: /^~package$/, replacement: path.resolve(process.cwd()) }] + alias: [ + { find: /^~package$/, replacement: path.resolve(process.cwd()) }, + // In earliest mode, resolve imports of aliased dependencies to the earliest supported versions. + ...getEarliestAliases(mode) + ] } -}); +})); diff --git a/.config/vitest.earliest.mts b/.config/vitest.earliest.mts new file mode 100644 index 000000000..7f998fbdf --- /dev/null +++ b/.config/vitest.earliest.mts @@ -0,0 +1,26 @@ +import { existsSync, readFileSync } from 'node:fs'; +import { join } from 'node:path'; + +const EARLIEST_SUFFIX = '-earliest'; + +export function getEarliestDependencies() { + const packageJsonPath = join(process.cwd(), 'package.json'); + const { devDependencies = {} } = JSON.parse(readFileSync(packageJsonPath, 'utf8')); + const dependencies = Object.keys(devDependencies) + .filter((name) => name.endsWith(EARLIEST_SUFFIX)) + .map((name) => ({ + name: name.slice(0, -EARLIEST_SUFFIX.length), + path: join(process.cwd(), 'node_modules', name) + })); + if (!dependencies.some(({ name }) => name === 'rollup')) { + throw new Error(`Missing "rollup-earliest" devDependency in ${packageJsonPath}.`); + } + for (const { path } of dependencies) { + if (!existsSync(path)) { + throw new Error( + `Missing "${path}". Run "pnpm install" to test against the earliest supported versions.` + ); + } + } + return dependencies; +} diff --git a/.config/vitest.setup.earliest.mts b/.config/vitest.setup.earliest.mts new file mode 100644 index 000000000..5ca63ef39 --- /dev/null +++ b/.config/vitest.setup.earliest.mts @@ -0,0 +1,35 @@ +// The vite aliases in vitest.config.mts redirect ESM imports of the aliased dependencies to +// their earliest supported versions, but they do not affect require(...). Patch the Node +// module resolution so CommonJS tests resolve the same versions. +import Module from 'node:module'; + +import { getEarliestDependencies } from './vitest.earliest.mts'; + +type ResolveFilename = ( + request: string, + parent?: unknown, + isMain?: boolean, + options?: unknown +) => string; + +const earliestPaths = new Map( + getEarliestDependencies().map(({ name, path }) => [name, path] as const) +); + +const originalResolveFilename = (Module as { _resolveFilename?: ResolveFilename })._resolveFilename; + +if ( + originalResolveFilename && + !originalResolveFilename.name.includes('redirectEarliestDependencies') +) { + (Module as { _resolveFilename: ResolveFilename })._resolveFilename = + function redirectEarliestDependencies(this: unknown, request, parent, isMain, options) { + return originalResolveFilename.call( + this, + earliestPaths.get(request) ?? request, + parent, + isMain, + options + ); + }; +} diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index b2e799ae7..5442f0459 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -31,7 +31,7 @@ Any code change should be submitted as a pull request. Our guidelines for Pull R Some packages use Vitest for tests. When converting or running tests locally inside a package directory (e.g. `packages/alias`): - Tests import the package under test via `~package`. A shared config at `.config/vitest.config.mts` provides a runtime alias that resolves `~package` to the current working directory. -- Snapshots are written alongside each test under a local `.snapshots` directory. +- Snapshots are written to a `snapshots` directory alongside the tests. Example (from a package directory): @@ -40,6 +40,8 @@ pnpm build pnpm test ``` +To also run the tests against the earliest version of rollup the package supports, use `pnpm test:earliest`. In this mode, snapshots for a test file are taken from `test/snapshots-earliest` when a file with the same name exists there, falling back to the regular snapshots otherwise. When regenerating snapshots with `-u` in this mode, test files without a counterpart in `test/snapshots-earliest` get their regular snapshots overwritten with the output generated for the earliest rollup version, so when version-specific snapshots are intended, first copy the snapshot file into `test/snapshots-earliest` and then regenerate. + ## Code review process The bigger the pull request, the longer it will take to review and merge. Try to break down large pull requests in smaller chunks that are easier to review and merge. diff --git a/.github/workflows/node-windows.yml b/.github/workflows/node-windows.yml index 1fb0e95dd..7126b1239 100644 --- a/.github/workflows/node-windows.yml +++ b/.github/workflows/node-windows.yml @@ -50,3 +50,6 @@ jobs: - name: run tests run: pnpm --workspace-concurrency 1 --filter "...[origin/master]" ci:test + + - name: run tests against earliest supported rollup + run: pnpm --workspace-concurrency 1 --filter "...[origin/master]" test:earliest diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 0901be955..da7ab19fd 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -76,3 +76,6 @@ jobs: - name: Run Tests run: pnpm --filter "...[origin/master]" ci:coverage + + - name: Run Tests Against Earliest Supported Rollup + run: pnpm --filter "...[origin/master]" test:earliest diff --git a/.prettierignore b/.prettierignore index 1cf411722..e8d263f77 100644 --- a/.prettierignore +++ b/.prettierignore @@ -6,4 +6,5 @@ packages/yaml/test/fixtures/**/* **/dist/ **/fixtures/ **/snapshots/ +**/snapshots-earliest/ pnpm-lock.yaml diff --git a/README.md b/README.md index 29b6623e9..9f8d82fb7 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,14 @@ To run tests on a specific package: $ pnpm --filter ./packages/ test ``` +To also run the tests of a package against the earliest version of rollup it supports: + +```console +$ pnpm --filter ./packages/ test:earliest +``` + +In this mode, snapshots are read from the `test/snapshots-earliest` directory of a package when a file with the same name exists there, falling back to the regular snapshots otherwise. Be careful when regenerating snapshots with `-u` in this mode: for test files without a counterpart in `test/snapshots-earliest`, this overwrites the regular snapshots with the output generated for the earliest rollup version. To add version-specific snapshots for a test file, first copy its snapshot file from `test/snapshots` to `test/snapshots-earliest`, then regenerate in this mode. + Linting: To lint all packages which have changes: diff --git a/packages/alias/package.json b/packages/alias/package.json index 922347049..558430196 100755 --- a/packages/alias/package.json +++ b/packages/alias/package.json @@ -32,7 +32,8 @@ "prerelease": "pnpm build", "pretest": "pnpm build", "release": "pnpm --workspace-root package:release $(pwd)", - "test": "vitest --config ../../.config/vitest.config.mts run" + "test": "vitest --config ../../.config/vitest.config.mts run", + "test:earliest": "pnpm test -- --mode earliest" }, "files": [ "dist", @@ -58,7 +59,8 @@ "devDependencies": { "@rollup/plugin-node-resolve": "^15.0.0", "del-cli": "^5.0.0", - "rollup": "^4.0.0", + "rollup": "catalog:", + "rollup-earliest": "npm:rollup@4.0.0", "typescript": "catalog:" }, "types": "./dist/index.d.ts", diff --git a/packages/alias/test/alias.test.ts b/packages/alias/test/alias.test.ts index bc2e540e9..f1aad5255 100644 --- a/packages/alias/test/alias.test.ts +++ b/packages/alias/test/alias.test.ts @@ -3,7 +3,7 @@ import { fileURLToPath } from 'node:url'; import os from 'node:os'; import { describe, it, expect } from 'vitest'; -import { rollup } from 'rollup'; +import { rollup, VERSION } from 'rollup'; import nodeResolvePlugin from '@rollup/plugin-node-resolve'; import alias from '~package'; @@ -11,6 +11,11 @@ import alias from '~package'; const DIRNAME = fileURLToPath(new URL('.', import.meta.url)); const isWindows = os.platform() === 'win32'; +// rollup 4.13.0 added a prefix to plugin warning messages +const [rollupMajor, rollupMinor] = VERSION.split('.').map(Number); +const warningPrefix = + rollupMajor > 4 || (rollupMajor === 4 && rollupMinor >= 13) ? '[plugin alias] ' : ''; + /** * Helper function to test configuration with Rollup * @param plugins is an array of plugins for Rollup, they should include "alias" @@ -506,9 +511,9 @@ describe('plugin-alias', () => { expect(warnList).toMatchObject([ { message: - '[plugin alias] rewrote @/warn-importee.js to test/fixtures/folder/warn-importee.js but was not an absolute path and was not handled by other plugins. ' + - 'This will lead to duplicated modules for the same path. ' + - 'To avoid duplicating modules, you should resolve to an absolute path.', + `${warningPrefix}rewrote @/warn-importee.js to test/fixtures/folder/warn-importee.js but was not an absolute path and was not handled by other plugins. ` + + `This will lead to duplicated modules for the same path. ` + + `To avoid duplicating modules, you should resolve to an absolute path.`, code: 'PLUGIN_WARNING', plugin: 'alias' } diff --git a/packages/auto-install/package.json b/packages/auto-install/package.json index 26672ca30..e6848e09f 100755 --- a/packages/auto-install/package.json +++ b/packages/auto-install/package.json @@ -35,6 +35,7 @@ "pretest": "pnpm build", "release": "pnpm --workspace-root package:release $(pwd)", "test": "vitest --config ../../.config/vitest.config.mts run", + "test:earliest": "pnpm test -- --mode earliest", "test:ts": "tsc --noEmit" }, "files": [ @@ -63,10 +64,12 @@ }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.0.0", + "@rollup/plugin-node-resolve-earliest": "npm:@rollup/plugin-node-resolve@11.2.1", "@rollup/plugin-typescript": "^9.0.1", "del": "^6.1.1", "node-noop": "^1.0.0", - "rollup": "^4.0.0-24", + "rollup": "catalog:", + "rollup-earliest": "npm:rollup@1.20.0", "typescript": "^4.8.3" }, "types": "./types/index.d.ts" diff --git a/packages/auto-install/test/fixtures/pnpm-bare/.npmrc b/packages/auto-install/test/fixtures/pnpm-bare/.npmrc new file mode 100644 index 000000000..e941bcc63 --- /dev/null +++ b/packages/auto-install/test/fixtures/pnpm-bare/.npmrc @@ -0,0 +1,3 @@ +# pnpm refuses to add dependencies at a workspace root without an explicit opt-in; +# this also means the root .npmrc no longer applies here, which is fine for this fixture +ignore-workspace-root-check=true diff --git a/packages/auto-install/test/fixtures/pnpm-bare/pnpm-workspace.yaml b/packages/auto-install/test/fixtures/pnpm-bare/pnpm-workspace.yaml new file mode 100644 index 000000000..538d9c6dc --- /dev/null +++ b/packages/auto-install/test/fixtures/pnpm-bare/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +# Anchor pnpm workspace detection to this fixture so that package installs spawned here do not +# operate on the monorepo workspace root and regenerate its lockfile. diff --git a/packages/auto-install/test/fixtures/pnpm/.npmrc b/packages/auto-install/test/fixtures/pnpm/.npmrc new file mode 100644 index 000000000..e941bcc63 --- /dev/null +++ b/packages/auto-install/test/fixtures/pnpm/.npmrc @@ -0,0 +1,3 @@ +# pnpm refuses to add dependencies at a workspace root without an explicit opt-in; +# this also means the root .npmrc no longer applies here, which is fine for this fixture +ignore-workspace-root-check=true diff --git a/packages/auto-install/test/fixtures/pnpm/pnpm-workspace.yaml b/packages/auto-install/test/fixtures/pnpm/pnpm-workspace.yaml new file mode 100644 index 000000000..538d9c6dc --- /dev/null +++ b/packages/auto-install/test/fixtures/pnpm/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +# Anchor pnpm workspace detection to this fixture so that package installs spawned here do not +# operate on the monorepo workspace root and regenerate its lockfile. diff --git a/packages/auto-install/test/pnpm-bare.js b/packages/auto-install/test/pnpm-bare.js index 690592b02..0c173cec1 100644 --- a/packages/auto-install/test/pnpm-bare.js +++ b/packages/auto-install/test/pnpm-bare.js @@ -13,6 +13,12 @@ const input = join(cwd, '../input.js'); process.chdir(cwd); +// pnpm would otherwise discover the monorepo workspace root above the fixture and regenerate +// its lockfile. The fixture pnpm-workspace.yaml anchors workspace detection to the fixture +// directory; ensure the fixture installs leave the workspace root lockfile untouched. +const rootLockfile = join(__dirname, '../../../pnpm-lock.yaml'); +const originalLockfileContent = readFileSync(rootLockfile); + test('pnpm, bare', async () => { await rollup({ input, @@ -28,5 +34,12 @@ test('pnpm, bare', async () => { }, 50000); afterAll(async () => { - await del(['node_modules', 'package.json', 'pnpm-lock.yaml']); + try { + expect( + readFileSync(rootLockfile).equals(originalLockfileContent), + 'the workspace root lockfile was modified by a fixture install' + ).toBe(true); + } finally { + await del(['node_modules', 'package.json', 'pnpm-lock.yaml']); + } }); diff --git a/packages/auto-install/test/pnpm.js b/packages/auto-install/test/pnpm.js index 3be105293..bb1d13190 100644 --- a/packages/auto-install/test/pnpm.js +++ b/packages/auto-install/test/pnpm.js @@ -13,6 +13,12 @@ const input = join(cwd, '../input.js'); process.chdir(cwd); +// pnpm would otherwise discover the monorepo workspace root above the fixture and regenerate +// its lockfile. The fixture pnpm-workspace.yaml anchors workspace detection to the fixture +// directory; ensure the fixture installs leave the workspace root lockfile untouched. +const rootLockfile = join(__dirname, '../../../pnpm-lock.yaml'); +const originalLockfileContent = readFileSync(rootLockfile); + test('pnpm', async () => { await rollup({ input, @@ -29,6 +35,13 @@ test('pnpm', async () => { }, 50000); afterAll(async () => { - await del(['node_modules', 'package.json']); - writeFileSync('pnpm-lock.yaml', ''); + try { + expect( + readFileSync(rootLockfile).equals(originalLockfileContent), + 'the workspace root lockfile was modified by a fixture install' + ).toBe(true); + } finally { + await del(['node_modules', 'package.json']); + writeFileSync('pnpm-lock.yaml', ''); + } }); diff --git a/packages/babel/package.json b/packages/babel/package.json index 30fc774d9..58aac0514 100644 --- a/packages/babel/package.json +++ b/packages/babel/package.json @@ -35,6 +35,7 @@ "pretest": "pnpm build", "release": "pnpm --workspace-root package:release $(pwd)", "test": "vitest --config ../../.config/vitest.config.mts run", + "test:earliest": "pnpm test -- --mode earliest", "test:ts": "tsc types/index.d.ts test/types.ts --noEmit" }, "files": [ @@ -80,7 +81,8 @@ "@rollup/plugin-json": "^5.0.0", "@rollup/plugin-node-resolve": "^15.0.0", "@types/babel__core": "^7.1.9", - "rollup": "^4.0.0-24", + "rollup": "catalog:", + "rollup-earliest": "npm:rollup@2.78.0", "source-map": "^0.7.4" }, "types": "./types/index.d.ts", diff --git a/packages/babel/test/as-input-plugin.mjs b/packages/babel/test/as-input-plugin.mjs index c388a5b2e..6771b927b 100644 --- a/packages/babel/test/as-input-plugin.mjs +++ b/packages/babel/test/as-input-plugin.mjs @@ -4,7 +4,7 @@ import * as fs from 'node:fs'; import { fileURLToPath } from 'url'; import { test, expect } from 'vitest'; -import { rollup } from 'rollup'; +import { rollup, VERSION } from 'rollup'; import jsonPlugin from '@rollup/plugin-json'; import nodeResolvePlugin from '@rollup/plugin-node-resolve'; import { createFilter } from '@rollup/pluginutils'; @@ -13,8 +13,13 @@ import babelPlugin, { getBabelOutputPlugin, createBabelInputPluginFactory } from import { getCode } from '../../../util/test.js'; +const [rollupMajor] = VERSION.split('.').map(Number); const DIRNAME = fileURLToPath(new URL('.', import.meta.url)); const FIXTURES = `${DIRNAME}/fixtures/`; +const getUnresolvedImportWarning = (source, importer) => + rollupMajor < 3 + ? `'${source}' is imported by ${importer}, but could not be resolved – treating it as an external dependency` + : `"${source}" is imported by "${importer}", but could not be resolved – treating it as an external dependency.`; function getLocation(source, charIndex) { const lines = source.split('\n'); const len = lines.length; @@ -250,7 +255,9 @@ test('allows transform-runtime to be used instead of bundled helpers', async () { babelHelpers: 'runtime' }, - {}, + { + interop: 'default' + }, { onwarn(warning) { warnings.push(warning.message); @@ -258,8 +265,14 @@ test('allows transform-runtime to be used instead of bundled helpers', async () } ); expect(warnings).toEqual([ - `"@babel/runtime/helpers/createClass" is imported by "test/fixtures/runtime-helpers/main.js", but could not be resolved – treating it as an external dependency.`, - `"@babel/runtime/helpers/classCallCheck" is imported by "test/fixtures/runtime-helpers/main.js", but could not be resolved – treating it as an external dependency.` + getUnresolvedImportWarning( + '@babel/runtime/helpers/createClass', + 'test/fixtures/runtime-helpers/main.js' + ), + getUnresolvedImportWarning( + '@babel/runtime/helpers/classCallCheck', + 'test/fixtures/runtime-helpers/main.js' + ) ]); expect(code).toBe(`'use strict'; @@ -290,8 +303,14 @@ test('allows transform-runtime to inject esm version of helpers', async () => { } ); expect(warnings).toEqual([ - `"@babel/runtime/helpers/esm/createClass" is imported by "test/fixtures/runtime-helpers-esm/main.js", but could not be resolved – treating it as an external dependency.`, - `"@babel/runtime/helpers/esm/classCallCheck" is imported by "test/fixtures/runtime-helpers-esm/main.js", but could not be resolved – treating it as an external dependency.` + getUnresolvedImportWarning( + '@babel/runtime/helpers/esm/createClass', + 'test/fixtures/runtime-helpers-esm/main.js' + ), + getUnresolvedImportWarning( + '@babel/runtime/helpers/esm/classCallCheck', + 'test/fixtures/runtime-helpers-esm/main.js' + ) ]); expect(code).toBe(`import _createClass from '@babel/runtime/helpers/esm/createClass'; import _classCallCheck from '@babel/runtime/helpers/esm/classCallCheck'; diff --git a/packages/babel/test/as-output-plugin.mjs b/packages/babel/test/as-output-plugin.mjs index e33e33bd1..00590ad88 100644 --- a/packages/babel/test/as-output-plugin.mjs +++ b/packages/babel/test/as-output-plugin.mjs @@ -2,12 +2,15 @@ import * as nodePath from 'path'; import { fileURLToPath } from 'url'; import { test, expect } from 'vitest'; -import { rollup } from 'rollup'; +import { rollup, VERSION } from 'rollup'; import { getBabelOutputPlugin, createBabelOutputPluginFactory } from 'current-package'; import { getCode } from '../../../util/test.js'; +const [rollupMajor, rollupMinor] = VERSION.split('.').map(Number); +// rollup 4.13.0 augments plugin warnings and errors with a "[plugin ]" message prefix +const hasAugmentedPluginLogs = rollupMajor > 4 || (rollupMajor === 4 && rollupMinor >= 13); const DIRNAME = fileURLToPath(new URL('.', import.meta.url)); const FIXTURES = `${DIRNAME}/fixtures/`; function getLocation(source, charIndex) { @@ -192,7 +195,9 @@ test('warns when using the "include" option', async () => { } ); expect(warnings).toEqual([ - 'The "include", "exclude" and "extensions" options are ignored when transforming the output.' + `${ + hasAugmentedPluginLogs ? '[plugin babel] ' : '' + }The "include", "exclude" and "extensions" options are ignored when transforming the output.` ]); }); test('transforms all chunks in a code-splitting setup', async () => { @@ -212,8 +217,15 @@ test('transforms all chunks in a code-splitting setup', async () => { }, true ); + // the content hash algorithm changed in rollup 4.10.0 + const depFileName = + rollupMajor < 3 + ? 'dep-805038a5.js' + : rollupMajor > 4 || (rollupMajor === 4 && rollupMinor >= 10) + ? 'dep-D_rFPbwT.js' + : 'dep--s88I99N.js'; expect(output.map(({ code }) => code)).toEqual([ - `import('./dep--s88I99N.js').then(function (result) { + `import('./${depFileName}').then(function (result) { return console.log(result); }); `, diff --git a/packages/beep/package.json b/packages/beep/package.json index ac48a2964..382ddb3ca 100644 --- a/packages/beep/package.json +++ b/packages/beep/package.json @@ -23,7 +23,8 @@ "ci:lint:commits": "commitlint --from=${CIRCLE_BRANCH} --to=${CIRCLE_SHA1}", "ci:test": "pnpm test -- --reporter=verbose", "release": "pnpm --workspace-root package:release $(pwd)", - "test": "vitest --config ../../.config/vitest.config.mts run" + "test": "vitest --config ../../.config/vitest.config.mts run", + "test:earliest": "pnpm test -- --mode earliest" }, "files": [ "lib/", @@ -46,7 +47,8 @@ } }, "devDependencies": { - "rollup": "^4.0.0-24", + "rollup": "catalog:", + "rollup-earliest": "npm:rollup@1.20.0", "strip-ansi": "^7.0.1" }, "types": "types/index.d.ts" diff --git a/packages/beep/test/test.js b/packages/beep/test/test.js index bbe9cd5e8..52322901c 100644 --- a/packages/beep/test/test.js +++ b/packages/beep/test/test.js @@ -1,10 +1,16 @@ +const { dirname, resolve } = require('path'); + const execa = require('execa'); +// Resolve the CLI from the rollup module that is active in the current test mode +// ("rollup-earliest" in earliest mode) so that the subprocess matches the module under test. +const rollupCli = resolve(dirname(require.resolve('rollup')), 'bin/rollup'); + const options = { cwd: __dirname }; test('pass', async () => { const args = '--config fixtures/pass.config.js'.split(' '); - const { stderr } = await execa('rollup', args, options); + const { stderr } = await execa(rollupCli, args, options); const { default: strip } = await import('strip-ansi'); expect(strip(stderr.replace(/\d+ms|[\d.]+s/, '