diff --git a/src/test/cli-options.test.ts b/src/test/cli-options.test.ts index d271b501a..aef72d145 100644 --- a/src/test/cli-options.test.ts +++ b/src/test/cli-options.test.ts @@ -4,13 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as pathlib from 'path'; import * as assert from 'uvu/assert'; -import {suite} from 'uvu'; -import {rigTest} from './util/rig-test.js'; -import {WireitTestRig} from './util/test-rig.js'; -import {Options} from '../cli-options.js'; +import * as pathlib from 'path'; +import {Agent, Options} from '../cli-options.js'; +import {IS_WINDOWS} from './util/windows.js'; import {Result} from '../error.js'; +import {WireitTestRig} from './util/test-rig.js'; +import {rigTest} from './util/rig-test.js'; +import {suite} from 'uvu'; const test = suite(); @@ -29,6 +30,58 @@ async function getOptionsResult( extraScripts?: Record, ): Promise> { rig.env.WIREIT_DEBUG_LOG_FILE = ''; + + if (command.startsWith('yarnBerry')) { + // `yarn` chooses whether to use "classic" or "berry" based on the presence + // of `yarnPath` in `.yarnrc.yml`. + // + // To closest simulate a user's environment, set `yarnPath` and let the + // global `yarn` command pick it when testing `yarnBerry`. + command = command.replace(/yarnBerry/g, 'yarn'); + + extraScripts = Object.fromEntries( + Object.entries(extraScripts || {}).map(([scriptName, scriptCommand]) => [ + scriptName, + scriptCommand.replace(/yarnBerry/g, 'yarn'), + ]), + ); + + await rig.write({ + '.yarnrc.yml': ` + nodeLinker: node-modules + yarnPath: ${pathlib.join( + process.cwd(), + 'third_party', + '.yarn', + 'releases', + 'yarn-4.0.1.cjs', + )} + `, + }); + + // `yarn.lock` tells `yarn` that this test is meant to be its own workspace + // root, even though there are higher `package.json` files in the file tree. + // + // This is the `yarn.lock` you get if you initialize `yarn` in an empty + // folder. + await rig.write({ + 'yarn.lock': ` + # This file is generated by running "yarn install" inside your project. + # Manual changes might be lost - proceed with caution! + + __metadata: + version: 8 + cacheKey: 10c0 + + "root-workspace-0b6124@workspace:.": + version: 0.0.0-use.local + resolution: "root-workspace-0b6124@workspace:." + languageName: unknown + linkType: soft + `, + }); + } + await rig.write({ 'package.json': { scripts: { @@ -39,7 +92,12 @@ async function getOptionsResult( }, }, }); - env = {...env, WIREIT_DEBUG_LOG_FILE: ''}; + + env = { + ...env, + WIREIT_DEBUG_LOG_FILE: '', + }; + assert.equal((await rig.exec(command, {env}).exit).code, 0); return JSON.parse(await rig.read('options.json')) as Result; } @@ -67,8 +125,12 @@ async function assertOptions( }); } -for (const command of ['npm', 'yarn', 'pnpm'] as const) { - const agent = command === 'yarn' ? 'yarnClassic' : command; +const commands = (['npm', 'yarn', 'pnpm', 'yarnBerry'] as const).filter( + (command) => !IS_WINDOWS || command !== 'yarnBerry', +); + +for (const command of commands) { + const agent: Agent = command === 'yarn' ? 'yarnClassic' : command; // eslint-disable-next-line @typescript-eslint/unbound-method const skipIfYarn = command === 'yarn' ? test.skip : test; // eslint-disable-next-line @typescript-eslint/unbound-method diff --git a/src/test/util/test-rig.ts b/src/test/util/test-rig.ts index 488cf2946..aa1ffd49f 100644 --- a/src/test/util/test-rig.ts +++ b/src/test/util/test-rig.ts @@ -64,22 +64,30 @@ export class WireitTestRig */ override async setup() { await super.setup(); - const absWireitBinaryPath = pathlib.resolve(repoRoot, 'bin', 'wireit.js'); - const absWireitTempInstallPath = pathlib.resolve( - this.temp, - 'node_modules', - '.bin', - 'wireit', + + await Promise.all( + [['wireit', ['bin', 'wireit.js']] as const].map( + async ([name, pathParts]) => { + const binaryPath = pathlib.resolve(repoRoot, ...pathParts); + const tempInstallPath = pathlib.resolve( + this.temp, + 'node_modules', + '.bin', + name, + ); + + if (IS_WINDOWS) { + // Npm install works differently on Windows, since it won't recognize a + // shebang like "#!/usr/bin/env node". Npm instead uses the cmd-shim + // package to generate Windows shell wrappers for each binary, so we do + // that here too. + await cmdShim(binaryPath, tempInstallPath); + } else { + await this.symlink(binaryPath, tempInstallPath, 'file'); + } + }, + ), ); - if (IS_WINDOWS) { - // Npm install works differently on Windows, since it won't recognize a - // shebang like "#!/usr/bin/env node". Npm instead uses the cmd-shim - // package to generate Windows shell wrappers for each binary, so we do - // that here too. - await cmdShim(absWireitBinaryPath, absWireitTempInstallPath); - } else { - await this.symlink(absWireitBinaryPath, absWireitTempInstallPath, 'file'); - } } /**