fix: multiple Jest versions in a single workspace should work (#6138)

close #5176
close #6213
This commit is contained in:
Zoltan Kochan
2023-03-15 05:57:12 +02:00
committed by GitHub
parent b38d711f38
commit f9c30c6d78
5 changed files with 152 additions and 1 deletions

View File

@@ -0,0 +1,6 @@
---
"@pnpm/link-bins": patch
"pnpm": patch
---
Command shim should not set higher priority to the `node_modules/.pnpm/node_modules` directory through the `NODE_PATH` env variable, then the command's own `node_modules` directory [#5176](https://github.com/pnpm/pnpm/issues/5176).

View File

@@ -0,0 +1,17 @@
{
"presets": [
[
"env",
{
"targets": {
"browsers": [
"last 2 versions",
"IE >= 9"
]
}
}
],
"stage-0",
"react"
]
}

View File

View File

@@ -0,0 +1,103 @@
import fs from 'fs'
import path from 'path'
import { preparePackages, tempDir } from '@pnpm/prepare'
import { fixtures } from '@pnpm/test-fixtures'
import {
MutatedProject,
mutateModules,
install,
} from '@pnpm/core'
import { sync as loadJsonFile } from 'load-json-file'
import { testDefaults } from '../utils'
const f = fixtures(__dirname)
test('jest CLI should print the right version when multiple instances of jest are used in a workspace', async () => {
preparePackages([
{
location: 'project-1',
package: { name: 'project-1' },
},
{
location: 'project-2',
package: { name: 'project-2' },
},
])
const importers: MutatedProject[] = [
{
mutation: 'install',
rootDir: path.resolve('project-1'),
},
{
mutation: 'install',
rootDir: path.resolve('project-2'),
},
]
const allProjects = [
{
buildIndex: 0,
manifest: {
name: 'project-1',
version: '1.0.0',
scripts: {
postinstall: 'jest --version | json-append output.json',
},
dependencies: {
jest: '27.5.1',
'json-append': '1.1.1',
},
},
rootDir: path.resolve('project-1'),
},
{
buildIndex: 0,
manifest: {
name: 'project-2',
version: '1.0.0',
scripts: {
postinstall: 'jest --version | json-append output.json',
},
dependencies: {
jest: '24.9.0',
'json-append': '1.1.1',
},
},
rootDir: path.resolve('project-2'),
},
]
await mutateModules(importers, await testDefaults({
allProjects,
extendNodePath: true,
fastUnpack: false,
hoistPattern: '*',
}))
{
const [jestVersion] = loadJsonFile<string[]>('project-1/output.json')
expect(jestVersion.trim()).toStrictEqual('27.5.1')
}
{
const [jestVersion] = loadJsonFile<string[]>('project-2/output.json')
expect(jestVersion.trim()).toStrictEqual('24.9.0')
}
})
test('drupal-js-build should find plugins inside the hidden node_modules directory', async () => {
const tmp = tempDir()
f.copy('tooling-that-needs-node-path', tmp)
await install({
dependencies: {
'drupal-js-build': 'github:pnpm-e2e/drupal-js-build#f766801580f10543c24ba8bfa59046a776848097',
},
scripts: {
prepare: 'drupal-js-build',
},
}, await testDefaults({
extendNodePath: true,
fastUnpack: false,
hoistPattern: '*',
}))
expect(fs.existsSync(path.join(tmp, 'index.js'))).toBeTruthy()
})

View File

@@ -1,4 +1,5 @@
import { promises as fs, existsSync } from 'fs'
import Module from 'module'
import path from 'path'
import { PnpmError } from '@pnpm/error'
import { logger, globalWarn } from '@pnpm/logger'
@@ -222,9 +223,18 @@ async function linkBin (cmd: CommandInfo, binsDir: string, opts?: LinkBinOptions
}
try {
let nodePath: string[] | undefined
if (opts?.extraNodePaths?.length) {
nodePath = []
for (const modulesPath of await getBinNodePaths(cmd.path)) {
if (opts.extraNodePaths.includes(modulesPath)) break
nodePath.push(modulesPath)
}
nodePath.push(...opts.extraNodePaths)
}
await cmdShim(cmd.path, externalBinPath, {
createPwshFile: cmd.makePowerShellShim,
nodePath: opts?.extraNodePaths,
nodePath,
nodeExecPath: cmd.nodeExecPath,
})
} catch (err: any) { // eslint-disable-line
@@ -253,6 +263,21 @@ function getExeExtension (): string {
return cmdExtension ?? '.exe'
}
async function getBinNodePaths (target: string): Promise<string[]> {
const targetDir = path.dirname(target)
try {
const targetRealPath = await fs.realpath(targetDir)
// @ts-expect-error
return Module['_nodeModulePaths'](targetRealPath)
} catch (err: any) { // eslint-disable-line
if (err.code !== 'ENOENT') {
throw err
}
// @ts-expect-error
return Module['_nodeModulePaths'](targetDir)
}
}
async function safeReadPkgJson (pkgDir: string): Promise<DependencyManifest | null> {
try {
return await readPackageJsonFromDir(pkgDir) as DependencyManifest