test(pnpm): run e2e suite against pacquet via PNPM_E2E_BIN

The pnpm CLI e2e tests already exercise the bundled `pnpm.mjs` end-to-end,
so they can serve as a parity probe for the Rust port too. A new
`PNPM_E2E_BIN` env var swaps the spawned binary in `execPnpm`/`execPnpmSync`/
`spawnPnpm`, and a `skipIfPacquet` helper gates the per-test cases that
the port doesn't yet pass. Every failing test in the existing suite was
marked from a local sweep against `target/release/pacquet`; pacquet-CI
gets a new job that builds the binary, builds the pnpm bundle, and runs
jest with the env var set so future regressions surface in CI.

Written by an agent (Claude Code, claude-opus-4-7).
This commit is contained in:
Zoltan Kochan
2026-05-21 19:46:53 +02:00
parent a5a2c2482e
commit 19d5d714c7
59 changed files with 761 additions and 506 deletions

View File

@@ -9,6 +9,7 @@ on:
types: [opened, synchronize]
paths:
- 'pacquet/**'
- 'pnpm/test/**'
- 'Cargo.toml'
- 'Cargo.lock'
- 'rust-toolchain.toml'
@@ -27,6 +28,7 @@ on:
- main
paths:
- 'pacquet/**'
- 'pnpm/test/**'
- 'Cargo.toml'
- 'Cargo.lock'
- 'rust-toolchain.toml'
@@ -112,6 +114,61 @@ jobs:
just registry-mock end
pnpm-e2e:
name: pnpm e2e (against pacquet)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Install Rust Toolchain
uses: ./.github/actions/rustup
with:
save-cache: ${{ github.ref_name == 'main' }}
shared-key: 'pnpm-e2e'
- name: Build pacquet release binary
run: cargo build --locked --release --bin pacquet
- name: Install pnpm and Node
uses: pnpm/setup@b1cac37306e39c21283b9dd6cb0ac288fb35ba6b
with:
install: false
# Node 22.13.0 matches the minimum supported version in pnpm/package.json
# (engines.node = ">=22.13") and is known to work with jest's ESM VM
# modules path; newer 24.x patches have a regression that breaks it.
runtime: node@22.13.0
- name: Cache pnpm
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
key: pnpm-e2e-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
pnpm-e2e-${{ runner.os }}-
path: |
${{ env.PNPM_HOME }}/store/v11
${{ env.HOME }}/.local/share/pnpm/store/v11
timeout-minutes: 1
continue-on-error: true
- name: pnpm install
run: pnpm install --frozen-lockfile
- name: Build pnpm bundle
run: pnpm --filter pnpm run compile
- name: Run pnpm e2e against pacquet
working-directory: pnpm
env:
PNPM_E2E_BIN: ${{ github.workspace }}/target/release/pacquet
# `pnpm test` would rebuild the bundle we just built; invoke jest
# directly via the same env the hidden `.test` script uses.
run: |
pnpm exec cross-env \
NODE_OPTIONS="--experimental-vm-modules --disable-warning=ExperimentalWarning --disable-warning=DEP0169" \
jest
doc:
name: Doc
runs-on: ubuntu-latest

View File

@@ -1,13 +1,16 @@
import fs from 'node:fs'
import path from 'node:path'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { tempDir } from '@pnpm/prepare'
import PATH_NAME from 'path-name'
import { execPnpmSync } from './utils/index.js'
import {
execPnpmSync,
skipIfPacquet,
} from './utils/index.js'
test('pnpm bin', async () => {
skipIfPacquet('pnpm bin', async () => {
tempDir()
fs.mkdirSync('node_modules')
@@ -17,7 +20,7 @@ test('pnpm bin', async () => {
expect(result.stdout.toString().trim()).toBe(path.resolve('node_modules/.bin'))
})
test('pnpm bin -g', async () => {
skipIfPacquet('pnpm bin -g', async () => {
tempDir()
const binDir = path.join(process.cwd(), 'bin')

View File

@@ -5,7 +5,10 @@ import { expect, test } from '@jest/globals'
import { prepare, preparePackages, tempDir } from '@pnpm/prepare'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpmSync } from './utils/index.js'
import {
execPnpmSync,
skipIfPacquet,
} from './utils/index.js'
test('pnpm ci fails when lockfile is missing', () => {
tempDir()
@@ -21,7 +24,7 @@ test('pnpm ci fails when lockfile is missing', () => {
expect(result.status).not.toBe(0)
})
test('pnpm ci removes node_modules and installs from lockfile', () => {
skipIfPacquet('pnpm ci removes node_modules and installs from lockfile', () => {
prepare({
name: 'test-ci-clean-install',
version: '1.0.0',
@@ -48,7 +51,7 @@ test('pnpm ci removes node_modules and installs from lockfile', () => {
expect(fs.existsSync(path.join(process.cwd(), 'node_modules', 'is-positive'))).toBe(true)
})
test('pnpm ci reinstalls workspace package node_modules', () => {
skipIfPacquet('pnpm ci reinstalls workspace package node_modules', () => {
preparePackages([
{
name: 'foo',

View File

@@ -1,18 +1,21 @@
import fs from 'node:fs'
import path from 'node:path'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { preparePackages, tempDir } from '@pnpm/prepare'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpmSync } from './utils/index.js'
import {
execPnpmSync,
skipIfPacquet,
} from './utils/index.js'
function writeJsonFile (filePath: string, obj: object): void {
fs.mkdirSync(path.dirname(filePath), { recursive: true })
fs.writeFileSync(filePath, JSON.stringify(obj))
}
test('pnpm clean removes pnpm entries and packages but preserves non-pnpm hidden files', () => {
skipIfPacquet('pnpm clean removes pnpm entries and packages but preserves non-pnpm hidden files', () => {
tempDir()
fs.writeFileSync('package.json', '{}', 'utf8')
@@ -46,7 +49,7 @@ test('pnpm clean removes pnpm entries and packages but preserves non-pnpm hidden
expect(fs.existsSync('node_modules/.cache/some-file')).toBe(true)
})
test('pnpm clean handles missing node_modules gracefully', () => {
skipIfPacquet('pnpm clean handles missing node_modules gracefully', () => {
tempDir()
fs.writeFileSync('package.json', '{}', 'utf8')
@@ -57,7 +60,7 @@ test('pnpm clean handles missing node_modules gracefully', () => {
expect(result.status).toBe(0)
})
test('pnpm clean preserves lockfile by default', () => {
skipIfPacquet('pnpm clean preserves lockfile by default', () => {
tempDir()
fs.writeFileSync('package.json', '{}', 'utf8')
fs.writeFileSync('pnpm-lock.yaml', 'lockfileVersion: 9')
@@ -70,7 +73,7 @@ test('pnpm clean preserves lockfile by default', () => {
expect(fs.existsSync('pnpm-lock.yaml')).toBe(true)
})
test('pnpm clean preserves lockfile when pnpm-workspace.yaml sets lockfile', () => {
skipIfPacquet('pnpm clean preserves lockfile when pnpm-workspace.yaml sets lockfile', () => {
tempDir()
fs.writeFileSync('package.json', '{}', 'utf8')
writeYamlFileSync('pnpm-workspace.yaml', { lockfile: true })
@@ -84,7 +87,7 @@ test('pnpm clean preserves lockfile when pnpm-workspace.yaml sets lockfile', ()
expect(fs.existsSync('pnpm-lock.yaml')).toBe(true)
})
test('pnpm clean --lockfile removes lockfile', () => {
skipIfPacquet('pnpm clean --lockfile removes lockfile', () => {
tempDir()
fs.writeFileSync('package.json', '{}', 'utf8')
fs.writeFileSync('pnpm-lock.yaml', 'lockfileVersion: 9')
@@ -97,7 +100,7 @@ test('pnpm clean --lockfile removes lockfile', () => {
expect(fs.existsSync('pnpm-lock.yaml')).toBe(false)
})
test('pnpm clean works in a workspace', () => {
skipIfPacquet('pnpm clean works in a workspace', () => {
preparePackages([
{ name: 'project-a', version: '1.0.0' },
{ name: 'project-b', version: '1.0.0' },
@@ -131,7 +134,7 @@ test('pnpm clean works in a workspace', () => {
}
})
test('pnpm clean removes custom virtual-store-dir inside the project', () => {
skipIfPacquet('pnpm clean removes custom virtual-store-dir inside the project', () => {
tempDir()
fs.writeFileSync('package.json', '{}', 'utf8')
@@ -149,7 +152,7 @@ test('pnpm clean removes custom virtual-store-dir inside the project', () => {
expect(fs.existsSync('node_modules/lodash')).toBe(false)
})
test('pnpm clean does not remove virtual-store-dir outside the project root', () => {
skipIfPacquet('pnpm clean does not remove virtual-store-dir outside the project root', () => {
tempDir()
fs.writeFileSync('package.json', '{}', 'utf8')
@@ -167,7 +170,7 @@ test('pnpm clean does not remove virtual-store-dir outside the project root', ()
expect(fs.existsSync(path.join(outsideDir, 'data'))).toBe(true)
})
test('pnpm clean --lockfile removes lockfiles in workspace', () => {
skipIfPacquet('pnpm clean --lockfile removes lockfiles in workspace', () => {
preparePackages([
{ name: 'project-a', version: '1.0.0' },
{ name: 'project-b', version: '1.0.0' },
@@ -191,7 +194,7 @@ test('pnpm clean --lockfile removes lockfiles in workspace', () => {
}
})
test('pnpm clean runs the clean script from package.json when present', () => {
skipIfPacquet('pnpm clean runs the clean script from package.json when present', () => {
tempDir()
writeJsonFile('package.json', {
name: 'has-clean-script',
@@ -203,7 +206,7 @@ test('pnpm clean runs the clean script from package.json when present', () => {
expect(result.stdout.toString()).toContain('script-clean-ran')
})
test('pnpm purge runs the built-in clean even when a clean script exists', () => {
skipIfPacquet('pnpm purge runs the built-in clean even when a clean script exists', () => {
tempDir()
writeJsonFile('package.json', {
name: 'has-clean-script',
@@ -217,7 +220,7 @@ test('pnpm purge runs the built-in clean even when a clean script exists', () =>
expect(fs.existsSync('node_modules/.pnpm')).toBe(false)
})
test('pnpm purge runs the purge script from package.json when present', () => {
skipIfPacquet('pnpm purge runs the purge script from package.json when present', () => {
tempDir()
writeJsonFile('package.json', {
name: 'has-purge-script',
@@ -229,7 +232,7 @@ test('pnpm purge runs the purge script from package.json when present', () => {
expect(result.stdout.toString()).toContain('script-purge-ran')
})
test('pnpm clean runs the built-in when no clean script exists', () => {
skipIfPacquet('pnpm clean runs the built-in when no clean script exists', () => {
tempDir()
writeJsonFile('package.json', { name: 'no-clean-script' })
fs.mkdirSync('node_modules/.pnpm', { recursive: true })
@@ -239,7 +242,7 @@ test('pnpm clean runs the built-in when no clean script exists', () => {
expect(fs.existsSync('node_modules/.pnpm')).toBe(false)
})
test('pnpm clean errors in workspace subdir when root has clean script', () => {
skipIfPacquet('pnpm clean errors in workspace subdir when root has clean script', () => {
preparePackages([
{ name: 'project-a', version: '1.0.0' },
])
@@ -257,7 +260,7 @@ test('pnpm clean errors in workspace subdir when root has clean script', () => {
expect(output).toContain('ERR_PNPM_SCRIPT_OVERRIDE_IN_WORKSPACE_ROOT')
})
test('pnpm pm clean runs the built-in command even when a clean script exists', () => {
skipIfPacquet('pnpm pm clean runs the built-in command even when a clean script exists', () => {
tempDir()
writeJsonFile('package.json', {
name: 'has-clean-script',
@@ -271,7 +274,7 @@ test('pnpm pm clean runs the built-in command even when a clean script exists',
expect(fs.existsSync('node_modules/.pnpm')).toBe(false)
})
test('pnpm pm clean does not error in workspace subdir when root has clean script', () => {
skipIfPacquet('pnpm pm clean does not error in workspace subdir when root has clean script', () => {
preparePackages([
{ name: 'project-a', version: '1.0.0' },
])
@@ -289,7 +292,7 @@ test('pnpm pm clean does not error in workspace subdir when root has clean scrip
expect(fs.existsSync(path.join('project-a', 'node_modules', '.pnpm'))).toBe(false)
})
test('pnpm clean runs built-in in workspace subdir when root has no clean script', () => {
skipIfPacquet('pnpm clean runs built-in in workspace subdir when root has no clean script', () => {
preparePackages([
{ name: 'project-a', version: '1.0.0' },
])

View File

@@ -12,12 +12,13 @@ import {
execPnpm,
execPnpmSync,
execPnpxSync,
skipIfPacquet,
} from './utils/index.js'
const f = fixtures(import.meta.dirname)
const hasOutdatedDepsFixture = f.find('has-outdated-deps')
test('commands that were previously passed through to npm now fail', () => {
skipIfPacquet('commands that were previously passed through to npm now fail', () => {
const result = execPnpmSync(['access', 'public'])
expect(result.status).not.toBe(0)
@@ -25,7 +26,7 @@ test('commands that were previously passed through to npm now fail', () => {
expect(output).toContain('ERR_PNPM_NOT_IMPLEMENTED')
})
test('installs in the folder where the package.json file is', async () => {
skipIfPacquet('installs in the folder where the package.json file is', async () => {
const project = prepare()
fs.mkdirSync('subdir')
@@ -38,7 +39,7 @@ test('installs in the folder where the package.json file is', async () => {
project.isExecutable('.bin/rimraf')
})
test('pnpm import does not move modules created by npm', async () => {
skipIfPacquet('pnpm import does not move modules created by npm', async () => {
prepare()
await execa('npm', ['install', 'is-positive@1.0.0', '--save'])
@@ -62,7 +63,7 @@ test('previously passed through commands fail without package.json', async () =>
expect(result.status).not.toBe(0)
})
test('pnpm fails when an unsupported command is used', async () => {
skipIfPacquet('pnpm fails when an unsupported command is used', async () => {
prepare()
const { status } = execPnpmSync(['unsupported-command'])
@@ -70,7 +71,7 @@ test('pnpm fails when an unsupported command is used', async () => {
expect(status).toBe(1)
})
test('pnpm fails when no command is specified', async () => {
skipIfPacquet('pnpm fails when no command is specified', async () => {
prepare()
const { status, stdout } = execPnpmSync([])
@@ -79,7 +80,7 @@ test('pnpm fails when no command is specified', async () => {
expect(stdout.toString()).toMatch(/Usage:/)
})
test('command fails when an unsupported flag is used', async () => {
skipIfPacquet('command fails when an unsupported flag is used', async () => {
prepare()
const { status, stderr } = execPnpmSync(['update', '--save-dev'])
@@ -88,7 +89,7 @@ test('command fails when an unsupported flag is used', async () => {
expect(stderr.toString()).toMatch(/Unknown option: 'save-dev'/)
})
test('implicit run command fails when an unsupported top-level flag is used', () => {
skipIfPacquet('implicit run command fails when an unsupported top-level flag is used', () => {
prepare({
scripts: {
web: 'node -e "console.log(\'script should not run\')"',
@@ -103,7 +104,7 @@ test('implicit run command fails when an unsupported top-level flag is used', ()
expect(stderr.toString()).toMatch(/Did you mean 'filter'/)
})
test('command fails when a deprecated option is used', async () => {
skipIfPacquet('command fails when a deprecated option is used', async () => {
prepare()
const { status, stderr } = execPnpmSync(['install', '--no-lock'])
@@ -112,7 +113,7 @@ test('command fails when a deprecated option is used', async () => {
expect(stderr.toString()).toMatch(/Unknown option: 'lock'/)
})
test('command fails when deprecated options are used', async () => {
skipIfPacquet('command fails when deprecated options are used', async () => {
prepare()
const { status, stderr } = execPnpmSync(['install', '--no-lock', '--independent-leaves'])
@@ -121,7 +122,7 @@ test('command fails when deprecated options are used', async () => {
expect(stderr.toString()).toMatch(/Unknown options: 'lock', 'independent-leaves'/)
})
test('adding new dep does not fail if node_modules was created with --public-hoist-pattern=eslint-*', async () => {
skipIfPacquet('adding new dep does not fail if node_modules was created with --public-hoist-pattern=eslint-*', async () => {
const project = prepare()
await execPnpm(['add', 'is-positive', '--public-hoist-pattern=eslint-*'])
@@ -151,7 +152,7 @@ test('pnpx works', () => {
expect(result.status).toBe(0)
})
test('exit code from plugin is used to end the process', () => {
skipIfPacquet('exit code from plugin is used to end the process', () => {
process.chdir(hasOutdatedDepsFixture)
const result = execPnpmSync(['outdated'])
@@ -159,13 +160,13 @@ test('exit code from plugin is used to end the process', () => {
expect(result.stdout.toString()).toMatch(/is-positive/)
})
test('if an unknown command is executed, run it', async () => {
skipIfPacquet('if an unknown command is executed, run it', async () => {
prepare({})
await execPnpm(['node', '-e', "require('fs').writeFileSync('foo','','utf8')"])
expect(fs.readFileSync('foo', 'utf8')).toBe('')
})
test.each([
skipIfPacquet.each([
{ message: 'npm_command env available on special lifecycle hooks', script: 'prepare', command: 'install' },
{ message: 'npm_command env available on special lifecycle hooks (alias)', script: 'prepare', command: 'i', expected: 'install' },
{ message: 'npm_command env available on pre lifecycle hooks', script: 'prepack', command: 'pack' },

View File

@@ -1,14 +1,17 @@
import fs from 'node:fs'
import path from 'node:path'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { prepare } from '@pnpm/prepare'
import type { WorkspaceManifest } from '@pnpm/workspace.workspace-manifest-reader'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpmSync } from '../utils/index.js'
import {
execPnpmSync,
skipIfPacquet,
} from '../utils/index.js'
test('pnpm config get reads npm options but ignores other settings from .npmrc', () => {
skipIfPacquet('pnpm config get reads npm options but ignores other settings from .npmrc', () => {
prepare()
fs.writeFileSync('.npmrc', [
// npm options
@@ -65,7 +68,7 @@ test('pnpm config get reads npm options but ignores other settings from .npmrc',
}
})
test('pnpm config get reads workspace-specific settings from pnpm-workspace.yaml', () => {
skipIfPacquet('pnpm config get reads workspace-specific settings from pnpm-workspace.yaml', () => {
prepare()
writeYamlFileSync('pnpm-workspace.yaml', {
dlxCacheMaxAge: 1234,
@@ -99,7 +102,7 @@ test('pnpm config get reads workspace-specific settings from pnpm-workspace.yaml
}
})
test('pnpm config get ignores non camelCase settings from pnpm-workspace.yaml', () => {
skipIfPacquet('pnpm config get ignores non camelCase settings from pnpm-workspace.yaml', () => {
prepare()
writeYamlFileSync('pnpm-workspace.yaml', {
'dlx-cache-max-age': 1234,
@@ -127,7 +130,7 @@ test('pnpm config get ignores non camelCase settings from pnpm-workspace.yaml',
}
})
test('pnpm config get accepts a property path', () => {
skipIfPacquet('pnpm config get accepts a property path', () => {
const workspaceManifest = {
packageExtensions: {
'@babel/parser': {
@@ -202,7 +205,7 @@ test('pnpm config get accepts a property path', () => {
}
})
test('pnpm config get "" gives exactly the same result as pnpm config list', () => {
skipIfPacquet('pnpm config get "" gives exactly the same result as pnpm config list', () => {
prepare()
writeYamlFileSync('pnpm-workspace.yaml', {
dlxCacheMaxAge: 1234,
@@ -235,7 +238,7 @@ test('pnpm config get "" gives exactly the same result as pnpm config list', ()
}
})
test('pnpm config get shows settings from global config.yaml', () => {
skipIfPacquet('pnpm config get shows settings from global config.yaml', () => {
prepare()
const XDG_CONFIG_HOME = path.resolve('.config')

View File

@@ -1,14 +1,17 @@
import fs from 'node:fs'
import path from 'node:path'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import type { Config } from '@pnpm/config.reader'
import { prepare } from '@pnpm/prepare'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpmSync } from '../utils/index.js'
import {
execPnpmSync,
skipIfPacquet,
} from '../utils/index.js'
test('pnpm config list reads npm options but ignores other settings from .npmrc', () => {
skipIfPacquet('pnpm config list reads npm options but ignores other settings from .npmrc', () => {
prepare()
fs.writeFileSync('.npmrc', [
// npm options
@@ -42,7 +45,7 @@ test('pnpm config list reads npm options but ignores other settings from .npmrc'
expect(list).not.toHaveProperty(['packages'])
})
test('pnpm config list reads workspace-specific settings from pnpm-workspace.yaml', () => {
skipIfPacquet('pnpm config list reads workspace-specific settings from pnpm-workspace.yaml', () => {
const workspaceManifest = {
dlxCacheMaxAge: 1234,
trustPolicyExclude: ['foo', 'bar'],
@@ -71,7 +74,7 @@ test('pnpm config list reads workspace-specific settings from pnpm-workspace.yam
expect(JSON.parse(stdout.toString())).not.toHaveProperty(['package-extensions'])
})
test('pnpm config list ignores non camelCase settings from pnpm-workspace.yaml', () => {
skipIfPacquet('pnpm config list ignores non camelCase settings from pnpm-workspace.yaml', () => {
const workspaceManifest = {
'dlx-cache-max-age': 1234,
'trust-policy-exclude': ['foo', 'bar'],
@@ -103,7 +106,7 @@ test('pnpm config list ignores non camelCase settings from pnpm-workspace.yaml',
// This behavior is not really desired, it is but a side-effect of the config loader not validating pnpm-workspace.yaml.
// Still, removing it can be considered a breaking change, so this test is here to track for that.
test('pnpm config list still reads unknown camelCase keys from pnpm-workspace.yaml', () => {
skipIfPacquet('pnpm config list still reads unknown camelCase keys from pnpm-workspace.yaml', () => {
const workspaceManifest = {
thisOptionIsNotDefinedByPnpm: 'some-value',
}
@@ -118,7 +121,7 @@ test('pnpm config list still reads unknown camelCase keys from pnpm-workspace.ya
}
})
test('pnpm config list --json shows all keys in camelCase', () => {
skipIfPacquet('pnpm config list --json shows all keys in camelCase', () => {
const workspaceManifest = {
dlxCacheMaxAge: 1234,
allowBuilds: { foo: true, bar: true },
@@ -147,7 +150,7 @@ test('pnpm config list --json shows all keys in camelCase', () => {
expect(JSON.parse(stdout.toString())).not.toHaveProperty(['package-extensions'])
})
test('pnpm config list shows settings from global config.yaml', () => {
skipIfPacquet('pnpm config list shows settings from global config.yaml', () => {
prepare()
const XDG_CONFIG_HOME = path.resolve('.config')

View File

@@ -1,7 +1,7 @@
import fs from 'node:fs'
import path from 'node:path'
import { describe, expect, test } from '@jest/globals'
import { describe, expect } from '@jest/globals'
import { readEnvLockfile } from '@pnpm/lockfile.fs'
import { prepare } from '@pnpm/prepare'
import { getIntegrity } from '@pnpm/registry-mock'
@@ -10,9 +10,14 @@ import { readYamlFileSync } from 'read-yaml-file'
import { writeJsonFileSync } from 'write-json-file'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm, execPnpmSync, pnpmBinLocation } from './utils/index.js'
import {
execPnpm,
execPnpmSync,
pnpmBinLocation,
skipIfPacquet,
} from './utils/index.js'
test('patch from configuration dependency is applied', async () => {
skipIfPacquet('patch from configuration dependency is applied', async () => {
prepare()
writeYamlFileSync('pnpm-workspace.yaml', {
configDependencies: {
@@ -28,7 +33,7 @@ test('patch from configuration dependency is applied', async () => {
expect(fs.existsSync('node_modules/@pnpm.e2e/foo/index.js')).toBeTruthy()
})
test('patch from configuration dependency is applied via updateConfig hook', async () => {
skipIfPacquet('patch from configuration dependency is applied via updateConfig hook', async () => {
const project = prepare()
writeYamlFileSync('pnpm-workspace.yaml', {
configDependencies: {
@@ -45,7 +50,7 @@ test('patch from configuration dependency is applied via updateConfig hook', asy
expect(lockfile.patchedDependencies['@pnpm.e2e/foo']).toEqual(expect.any(String))
})
test('catalog applied by configurational dependency hook', async () => {
skipIfPacquet('catalog applied by configurational dependency hook', async () => {
const project = prepare({
dependencies: {
'@pnpm.e2e/foo': 'catalog:',
@@ -78,7 +83,7 @@ test('catalog applied by configurational dependency hook', async () => {
})
})
test('config deps are not installed before switching to a different pnpm version', async () => {
skipIfPacquet('config deps are not installed before switching to a different pnpm version', async () => {
prepare()
const pnpmHome = path.resolve('pnpm')
const env = { PNPM_HOME: pnpmHome }
@@ -102,7 +107,7 @@ test('config deps are not installed before switching to a different pnpm version
expect(fs.existsSync('node_modules/.pnpm-config/@pnpm.e2e/has-patch-for-foo')).toBeFalsy()
})
test('config deps are installed after switching to a pnpm version that supports them', async () => {
skipIfPacquet('config deps are installed after switching to a pnpm version that supports them', async () => {
prepare({
packageManager: 'pnpm@10.32.0',
})
@@ -123,7 +128,7 @@ test('config deps are installed after switching to a pnpm version that supports
expect(fs.existsSync('node_modules/.pnpm-config/@pnpm.e2e/has-patch-for-foo')).toBeTruthy()
})
test('package manager from the packageManager field is not saved into the lockfile', async () => {
skipIfPacquet('package manager from the packageManager field is not saved into the lockfile', async () => {
const pnpmVersion = JSON.parse(fs.readFileSync(path.join(path.dirname(pnpmBinLocation), '..', 'package.json'), 'utf8')).version as string
prepare({
packageManager: `pnpm@${pnpmVersion}`,
@@ -154,7 +159,7 @@ test('package manager from the packageManager field is not saved into the lockfi
// matching npm publish ("No matching version found for pnpm@<version>"), and
// pass again once the version lands on npmjs.
describe('release-brittle: may fail until current version is published to npm', () => {
test('packageManagerDependencies is refreshed when pnpm is invoked via corepack (#11397)', async () => {
skipIfPacquet('packageManagerDependencies is refreshed when pnpm is invoked via corepack (#11397)', async () => {
const pnpmVersion = JSON.parse(fs.readFileSync(path.join(path.dirname(pnpmBinLocation), '..', 'package.json'), 'utf8')).version as string
prepare({
devEngines: {
@@ -196,7 +201,7 @@ snapshots: {}
})
})
test('installing a new configurational dependency', async () => {
skipIfPacquet('installing a new configurational dependency', async () => {
prepare()
await execPnpm(['add', '@pnpm.e2e/foo@100.0.0', '--config'])
@@ -241,7 +246,7 @@ function writeFailingConfigDep () {
})
}
test('pnpm config set succeeds even when configDependencies fail to install', async () => {
skipIfPacquet('pnpm config set succeeds even when configDependencies fail to install', async () => {
prepare()
writeFailingConfigDep()
@@ -253,7 +258,7 @@ test('pnpm config set succeeds even when configDependencies fail to install', as
expect(npmrc).toContain(`${authKey}=my-secret-token`)
})
test('pnpm config get succeeds even when configDependencies fail to install', async () => {
skipIfPacquet('pnpm config get succeeds even when configDependencies fail to install', async () => {
prepare()
writeFailingConfigDep()
const authKey = '//example.com/:_authToken'
@@ -263,7 +268,7 @@ test('pnpm config get succeeds even when configDependencies fail to install', as
expect(result.stdout.toString()).toContain('my-secret-token')
})
test('pnpm set succeeds even when configDependencies fail to install', async () => {
skipIfPacquet('pnpm set succeeds even when configDependencies fail to install', async () => {
prepare()
writeFailingConfigDep()
@@ -274,7 +279,7 @@ test('pnpm set succeeds even when configDependencies fail to install', async ()
expect(npmrc).toContain(`${authKey}=my-secret-token`)
})
test('pnpm get succeeds even when configDependencies fail to install', async () => {
skipIfPacquet('pnpm get succeeds even when configDependencies fail to install', async () => {
prepare()
writeFailingConfigDep()
const authKey = '//example.com/:_authToken'

View File

@@ -1,7 +1,7 @@
import fs from 'node:fs'
import path from 'node:path'
import { beforeAll, describe, expect, test } from '@jest/globals'
import { beforeAll, describe, expect } from '@jest/globals'
import { getConfig } from '@pnpm/config.reader'
import { dlx } from '@pnpm/exec.commands'
import { readModulesManifest } from '@pnpm/installing.modules-yaml'
@@ -11,7 +11,11 @@ import type { BaseManifest } from '@pnpm/types'
import PATH_NAME from 'path-name'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm, execPnpmSync } from './utils/index.js'
import {
execPnpm,
execPnpmSync,
skipIfPacquet,
} from './utils/index.js'
let registries: Record<string, string>
@@ -24,9 +28,8 @@ beforeAll(async () => {
const createCacheKey = (...packages: string[]): string => dlx.createCacheKey({ packages, registries })
const describeOnLinuxOnly = process.platform === 'linux' ? describe : describe.skip
const skipOnWindows = process.platform === 'win32' ? test.skip : test
test('dlx parses options between "dlx" and the command name', async () => {
skipIfPacquet('dlx parses options between "dlx" and the command name', async () => {
prepareEmpty()
const global = path.resolve('..', 'global')
const pnpmHome = path.join(global, 'pnpm')
@@ -43,7 +46,7 @@ test('dlx parses options between "dlx" and the command name', async () => {
expect(result.stdout.toString().trim()).toBe('hi')
})
test('silent dlx prints the output of the child process only', async () => {
skipIfPacquet('silent dlx prints the output of the child process only', async () => {
prepareEmpty()
const global = path.resolve('..', 'global')
const pnpmHome = path.join(global, 'pnpm')
@@ -60,7 +63,7 @@ test('silent dlx prints the output of the child process only', async () => {
expect(result.stdout.toString().trim()).toBe('hi')
})
test('dlx ignores patchedDependencies in pnpm-workspace.yaml', async () => {
skipIfPacquet('dlx ignores patchedDependencies in pnpm-workspace.yaml', async () => {
prepare()
// Write a pnpm-workspace.yaml with a patchedDependencies that doesn't exist
// dlx should ignore this and succeed
@@ -95,7 +98,7 @@ describe('minimumReleaseAge from pnpm-workspace.yaml', () => {
const SHX_0_3_3_PUBLISHED = new Date('2020-10-26T05:35:14.984Z').getTime()
const MINUTES_MS = 60 * 1000
skipOnWindows('dlx fails when the requested version is younger than minimumReleaseAge', () => {
skipIfPacquet('dlx fails when the requested version is younger than minimumReleaseAge', () => {
prepare()
writeYamlFileSync('pnpm-workspace.yaml', {
minimumReleaseAge: 60 * 24 * 10000, // ~27.4 years: rejects everything published recently
@@ -111,7 +114,7 @@ describe('minimumReleaseAge from pnpm-workspace.yaml', () => {
expect(result.stderr.toString()).toMatch(/was published.+minimumReleaseAge cutoff/)
})
test('dlx succeeds when the requested version is older than minimumReleaseAge', () => {
skipIfPacquet('dlx succeeds when the requested version is older than minimumReleaseAge', () => {
prepare()
// Cutoff 30 days after 0.3.2 was published: 0.3.2 is "mature". Anything
// newer (like 0.3.3 or 0.3.4) would not be, but the spec pins 0.3.2.
@@ -128,7 +131,7 @@ describe('minimumReleaseAge from pnpm-workspace.yaml', () => {
], { expectSuccess: true, omitEnvDefaults: ['pnpm_config_minimum_release_age'] })
})
test('dlx picks the newest version within a range that satisfies minimumReleaseAge', () => {
skipIfPacquet('dlx picks the newest version within a range that satisfies minimumReleaseAge', () => {
prepare()
// Cutoff positioned between 0.3.2 (2018-07-11) and 0.3.3 (2020-10-26):
// 0.3.2 is mature, 0.3.3 and 0.3.4 are not. Range `0.3.x` should resolve to 0.3.2.
@@ -159,7 +162,7 @@ describe('minimumReleaseAge from pnpm-workspace.yaml', () => {
})
// pnpm create delegates to dlx, so the same inheritance applies.
skipOnWindows('pnpm create respects minimumReleaseAge from pnpm-workspace.yaml', () => {
skipIfPacquet('pnpm create respects minimumReleaseAge from pnpm-workspace.yaml', () => {
prepare()
writeYamlFileSync('pnpm-workspace.yaml', {
minimumReleaseAge: 60 * 24 * 10000, // ~27.4 years: rejects everything published recently
@@ -176,7 +179,7 @@ skipOnWindows('pnpm create respects minimumReleaseAge from pnpm-workspace.yaml',
})
describe('catalogs inherited from pnpm-workspace.yaml', () => {
test('dlx succeeds when in default catalog', () => {
skipIfPacquet('dlx succeeds when in default catalog', () => {
prepare()
writeYamlFileSync('pnpm-workspace.yaml', {
catalog: {
@@ -189,7 +192,7 @@ describe('catalogs inherited from pnpm-workspace.yaml', () => {
], { expectSuccess: true, omitEnvDefaults: ['pnpm_config_minimum_release_age'] })
})
test('dlx fails when not in default catalog', () => {
skipIfPacquet('dlx fails when not in default catalog', () => {
prepare()
writeYamlFileSync('pnpm-workspace.yaml', {
catalog: {},
@@ -203,7 +206,7 @@ describe('catalogs inherited from pnpm-workspace.yaml', () => {
expect(result.stderr.toString()).toMatch(/No catalog entry 'shx' was found for catalog 'default'/)
})
test('dlx succeeds when in named catalog', () => {
skipIfPacquet('dlx succeeds when in named catalog', () => {
prepare()
writeYamlFileSync('pnpm-workspace.yaml', {
catalogs: {
@@ -218,7 +221,7 @@ describe('catalogs inherited from pnpm-workspace.yaml', () => {
], { expectSuccess: true, omitEnvDefaults: ['pnpm_config_minimum_release_age'] })
})
test('dlx fails when not in named catalog', () => {
skipIfPacquet('dlx fails when not in named catalog', () => {
prepare()
writeYamlFileSync('pnpm-workspace.yaml', {
catalogs: {
@@ -235,7 +238,7 @@ describe('catalogs inherited from pnpm-workspace.yaml', () => {
})
})
test('dlx should work with pnpm_config_save_dev env variable', async () => {
skipIfPacquet('dlx should work with pnpm_config_save_dev env variable', async () => {
prepareEmpty()
execPnpmSync(['dlx', '@foo/touch-file-one-bin@latest'], {
env: {
@@ -246,9 +249,7 @@ test('dlx should work with pnpm_config_save_dev env variable', async () => {
})
})
const testParallel = process.version.startsWith('v25.') ? test.skip : test
testParallel('parallel dlx calls of the same package', async () => {
skipIfPacquet('parallel dlx calls of the same package', async () => {
prepareEmpty()
// parallel dlx calls without cache
@@ -315,7 +316,7 @@ testParallel('parallel dlx calls of the same package', async () => {
).toBe(path.resolve('cache', 'dlx', createCacheKey('shx@0.3.4')))
})
test('dlx creates cache and store prune cleans cache', async () => {
skipIfPacquet('dlx creates cache and store prune cleans cache', async () => {
prepareEmpty()
const commands = {
@@ -376,7 +377,7 @@ test('dlx creates cache and store prune cleans cache', async () => {
expect(fs.readdirSync(path.resolve('cache', 'dlx'))).toStrictEqual([])
})
test('dlx should ignore non-auth info from .npmrc in the current directory', async () => {
skipIfPacquet('dlx should ignore non-auth info from .npmrc in the current directory', async () => {
prepareEmpty()
fs.writeFileSync('.npmrc', 'hoist-pattern=', 'utf8')
@@ -390,7 +391,7 @@ test('dlx should ignore non-auth info from .npmrc in the current directory', asy
expect(modulesManifest?.hoistPattern).toStrictEqual(['*'])
})
test('dlx read registry from .npmrc in the current directory', async () => {
skipIfPacquet('dlx read registry from .npmrc in the current directory', async () => {
prepareEmpty()
const data = await addUser({
@@ -419,7 +420,7 @@ test('dlx read registry from .npmrc in the current directory', async () => {
expect(execResult.stdout.toString().trim()).toBe('hello from @pnpm.e2e/needs-auth')
})
test('dlx uses the node version specified by --package=node@runtime:<version>', async () => {
skipIfPacquet('dlx uses the node version specified by --package=node@runtime:<version>', async () => {
prepareEmpty()
const pnpmHome = path.resolve('home')
@@ -457,7 +458,7 @@ test('dlx uses the node version specified by --package=node@runtime:<version>',
}
})
test('dlx without arguments prints help text and exits with 1', () => {
skipIfPacquet('dlx without arguments prints help text and exits with 1', () => {
prepareEmpty()
const result = execPnpmSync(['dlx'])
@@ -477,7 +478,7 @@ describeOnLinuxOnly('dlx with supportedArchitectures CLI options', () => {
type NotInstalled = string[]
type Case = [CLIOption[], Installed, NotInstalled]
test.each([
skipIfPacquet.each([
[['--cpu=arm64', '--os=win32'], ['@pnpm.e2e/only-win32-arm64'], [
'@pnpm.e2e/only-darwin-arm64',
'@pnpm.e2e/only-darwin-x64',

View File

@@ -5,14 +5,17 @@ import getPort from 'get-port'
import isWindows from 'is-windows'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpmSync } from './utils/index.js'
import {
execPnpmSync,
skipIfPacquet,
} from './utils/index.js'
import { isPortInUse } from './utils/isPortInUse.js'
const f = fixtures(import.meta.dirname)
const multipleScriptsErrorExit = f.find('multiple-scripts-error-exit')
const testOnPosix = isWindows() ? test.skip : test
test('should print json format error when publish --json failed', async () => {
skipIfPacquet('should print json format error when publish --json failed', async () => {
prepare({
name: 'test-publish-package-no-version',
version: undefined,
@@ -26,7 +29,7 @@ test('should print json format error when publish --json failed', async () => {
expect(error?.message).toBe('Package version is not defined in the package.json.')
})
test('should print json format error when add dependency on workspace root', async () => {
skipIfPacquet('should print json format error when add dependency on workspace root', async () => {
preparePackages([
{
name: 'project-a',
@@ -62,7 +65,7 @@ testOnPosix('should clean up child processes when process exited', async () => {
expect(await isPortInUse(barPort)).toBe(false)
})
test('should print error summary when some packages fail with --no-bail', async () => {
skipIfPacquet('should print error summary when some packages fail with --no-bail', async () => {
preparePackages([
{
location: 'project-1',

View File

@@ -1,13 +1,17 @@
import fs from 'node:fs'
import path from 'node:path'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { prepare } from '@pnpm/prepare'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm, execPnpmSync } from './utils/index.js'
import {
execPnpm,
execPnpmSync,
skipIfPacquet,
} from './utils/index.js'
test("exec should respect the caller's current working directory", async () => {
skipIfPacquet("exec should respect the caller's current working directory", async () => {
prepare({
name: 'root',
version: '1.0.0',
@@ -32,7 +36,7 @@ test("exec should respect the caller's current working directory", async () => {
expect(fs.readFileSync(cmdFilePath, 'utf8')).toBe(subdirPath)
})
test('silent exec does not print verifyDepsBeforeRun install output', async () => {
skipIfPacquet('silent exec does not print verifyDepsBeforeRun install output', async () => {
prepare({})
writeYamlFileSync('pnpm-workspace.yaml', {
verifyDepsBeforeRun: 'install',

View File

@@ -1,4 +1,4 @@
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import {
preparePackages,
} from '@pnpm/prepare'
@@ -6,9 +6,9 @@ import { createTestIpcServer } from '@pnpm/test-ipc-server'
import type { ProjectManifest } from '@pnpm/types'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm } from './utils/index.js'
import { execPnpm, skipIfPacquet } from './utils/index.js'
test.each([
skipIfPacquet.each([
{ message: '--filter should include devDependencies', filter: '--filter', expected: ['project-1', 'project-3', 'project-4'] },
{ message: '--filter-prod should not include devDependencies', filter: '--filter-prod', expected: ['project-1', 'project-3'] },
])('$message', async ({ filter, expected }) => {

View File

@@ -1,7 +1,7 @@
import fs from 'node:fs'
import path from 'node:path'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { createHash } from '@pnpm/crypto.hash'
import { prepare, preparePackages } from '@pnpm/prepare'
import { getIntegrity } from '@pnpm/registry-mock'
@@ -9,9 +9,13 @@ import type { PackageManifest } from '@pnpm/types'
import { loadJsonFileSync } from 'load-json-file'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm, execPnpmSync } from './utils/index.js'
import {
execPnpm,
execPnpmSync,
skipIfPacquet,
} from './utils/index.js'
test('readPackage hook in single project doesn\'t modify manifest', async () => {
skipIfPacquet('readPackage hook in single project doesn\'t modify manifest', async () => {
const project = prepare()
const pnpmfile = `
module.exports = { hooks: { readPackage } }
@@ -55,7 +59,7 @@ test('readPackage hook in single project doesn\'t modify manifest', async () =>
expect(pkg.dependencies).toBeFalsy() // install --lockfile-only & readPackage hook work, with pnpm-lock.yaml
})
test('readPackage hook in monorepo doesn\'t modify manifest', async () => {
skipIfPacquet('readPackage hook in monorepo doesn\'t modify manifest', async () => {
preparePackages([
{
name: 'project-a',
@@ -109,7 +113,7 @@ test('readPackage hook in monorepo doesn\'t modify manifest', async () => {
expect(pkg.dependencies).toBeFalsy() // install --lockfile-only & readPackage hook work, with pnpm-lock.yaml
})
test('filterLog hook filters peer dependency warning', async () => {
skipIfPacquet('filterLog hook filters peer dependency warning', async () => {
prepare()
const pnpmfile = `
module.exports = { hooks: { filterLog } }
@@ -129,7 +133,7 @@ test('filterLog hook filters peer dependency warning', async () => {
)
})
test('importPackage hooks', async () => {
skipIfPacquet('importPackage hooks', async () => {
prepare()
const pnpmfile = `
const fs = require('fs')
@@ -161,7 +165,7 @@ test('importPackage hooks', async () => {
])
})
test('adding or changing pnpmfile should change pnpmfileChecksum and module structure', async () => {
skipIfPacquet('adding or changing pnpmfile should change pnpmfileChecksum and module structure', async () => {
const project = prepare({
dependencies: {
'@pnpm.e2e/pkg-with-good-optional': '1.0.0',
@@ -237,7 +241,7 @@ test('adding or changing pnpmfile should change pnpmfileChecksum and module stru
expect(lockfile3).toStrictEqual(lockfile0)
})
test('loading a pnpmfile from a config dependency', async () => {
skipIfPacquet('loading a pnpmfile from a config dependency', async () => {
prepare({
dependencies: {
'@pnpm/x': '1.0.0',
@@ -255,7 +259,7 @@ test('loading a pnpmfile from a config dependency', async () => {
expect(fs.readdirSync('node_modules/.pnpm')).toContain('@pnpm+y@1.0.0')
})
test('updateConfig hook', async () => {
skipIfPacquet('updateConfig hook', async () => {
prepare()
const pnpmfile = `
module.exports = {
@@ -276,7 +280,7 @@ module.exports = {
expect(nodeModulesFiles).toContain('is-number')
})
test('loading an ESM pnpmfile', async () => {
skipIfPacquet('loading an ESM pnpmfile', async () => {
prepare()
fs.writeFileSync('.pnpmfile.mjs', `
@@ -295,7 +299,7 @@ export const hooks = {
expect(nodeModulesFiles).toContain('is-number')
})
test('loading multiple pnpmfiles', async () => {
skipIfPacquet('loading multiple pnpmfiles', async () => {
prepare()
fs.writeFileSync('pnpmfile1.cjs', `
@@ -328,7 +332,7 @@ module.exports = {
expect(nodeModulesFiles).toContain('is-even')
})
test('automatically loading pnpmfile from a config dependency that has a name that starts with "@pnpm/plugin-"', async () => {
skipIfPacquet('automatically loading pnpmfile from a config dependency that has a name that starts with "@pnpm/plugin-"', async () => {
prepare()
await execPnpm(['add', '--config', '@pnpm/plugin-pnpmfile'])

View File

@@ -4,9 +4,13 @@ import { prepare } from '@pnpm/prepare'
import { getIntegrity } from '@pnpm/registry-mock'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm, execPnpmSync } from '../utils/index.js'
import {
execPnpm,
execPnpmSync,
skipIfPacquet,
} from '../utils/index.js'
test('installing configDependencies migrating to env lockfile', async () => {
skipIfPacquet('installing configDependencies migrating to env lockfile', async () => {
prepare()
writeYamlFileSync('pnpm-workspace.yaml', {
configDependencies: {
@@ -20,7 +24,7 @@ test('installing configDependencies migrating to env lockfile', async () => {
expect(envLockfile?.importers['.'].configDependencies['@pnpm.e2e/foo'].version).toBe('100.0.0')
})
test('installing configDependencies fails with --frozen-lockfile if env lockfile is missing', async () => {
skipIfPacquet('installing configDependencies fails with --frozen-lockfile if env lockfile is missing', async () => {
prepare()
writeYamlFileSync('pnpm-workspace.yaml', {
configDependencies: {

View File

@@ -14,6 +14,7 @@ import {
addDistTag,
execPnpm,
execPnpmSync,
skipIfPacquet,
} from '../utils/index.js'
const PUBLIC_REGISTRY = '--config.registry=https://registry.npmjs.org/'
@@ -60,7 +61,7 @@ function findGlobalPkgInstall (globalDir: string, pkgName: string): { installDir
return null
}
test('global installation', async () => {
skipIfPacquet('global installation', async () => {
prepare()
const global = path.resolve('..', 'global')
const pnpmHome = path.join(global, 'pnpm')
@@ -85,7 +86,7 @@ test('global installation', async () => {
expect(typeof isNegative).toBe('function')
})
test('global install warns when project has packageManager configured', async () => {
skipIfPacquet('global install warns when project has packageManager configured', async () => {
prepare({
name: 'project',
version: '1.0.0',
@@ -107,7 +108,7 @@ test('global install warns when project has packageManager configured', async ()
expect(status).toBe(0)
})
test('global installation to custom directory with --global-dir', async () => {
skipIfPacquet('global installation to custom directory with --global-dir', async () => {
prepare()
const global = path.resolve('..', 'global')
const pnpmHome = path.join(global, 'pnpm')
@@ -121,7 +122,7 @@ test('global installation to custom directory with --global-dir', async () => {
expect(typeof isPositive).toBe('function')
})
test('always install latest when doing global installation without spec', async () => {
skipIfPacquet('always install latest when doing global installation without spec', async () => {
prepare()
await addDistTag('@pnpm.e2e/peer-c', '2.0.0', 'latest')
@@ -139,7 +140,7 @@ test('always install latest when doing global installation without spec', async
expect((await import(path.join(peerCPath!, 'package.json'))).default.version).toBe('2.0.0')
})
test('run lifecycle events of global packages in correct working directory', async () => {
skipIfPacquet('run lifecycle events of global packages in correct working directory', async () => {
if (isWindows()) {
// Skipping this test on Windows because "$npm_execpath run create-file" will fail on Windows
return
@@ -177,7 +178,7 @@ test('run lifecycle events of global packages in correct working directory', asy
// passes `all: true` so `approve-builds` approves every pending build
// without prompting. The post-approval install must complete and the
// build artifact must end up in the global install dir.
test('approve-builds during global add does not produce a doubled modules path', async () => {
skipIfPacquet('approve-builds during global add does not produce a doubled modules path', async () => {
prepare()
const global = path.resolve('..', 'global')
const pnpmHome = path.join(global, 'pnpm')
@@ -322,7 +323,7 @@ test.skip('dangerously-allow-all-builds=false in global config', async () => {
expect(fs.readdirSync(path.resolve('node_modules/@pnpm.e2e/postinstall-calls-pnpm'))).not.toContain('created-by-postinstall')
})
test('global update to latest', async () => {
skipIfPacquet('global update to latest', async () => {
prepare()
const global = path.resolve('..', 'global')
const pnpmHome = path.join(global, 'pnpm')
@@ -339,7 +340,7 @@ test('global update to latest', async () => {
expect(pkgJson.version).toBe('3.1.0')
})
test('global update should not crash if there are no global packages', async () => {
skipIfPacquet('global update should not crash if there are no global packages', async () => {
prepare()
const global = path.resolve('..', 'global')
const pnpmHome = path.join(global, 'pnpm')
@@ -350,7 +351,7 @@ test('global update should not crash if there are no global packages', async ()
expect(execPnpmSync(['update', '--global'], { env }).status).toBe(0)
})
test('global add in loose minimumReleaseAge mode persists immature picks', () => {
skipIfPacquet('global add in loose minimumReleaseAge mode persists immature picks', () => {
prepare()
const global = path.resolve('..', 'global')
const pnpmHome = path.join(global, 'pnpm')
@@ -382,7 +383,7 @@ test('global add in loose minimumReleaseAge mode persists immature picks', () =>
expect(workspaceManifest.minimumReleaseAgeExclude).toContain('is-positive@1.0.0')
})
test('global add in strict minimumReleaseAge mode reports the user-facing error', () => {
skipIfPacquet('global add in strict minimumReleaseAge mode reports the user-facing error', () => {
prepare()
const global = path.resolve('..', 'global')
const pnpmHome = path.join(global, 'pnpm')
@@ -413,7 +414,7 @@ test('global add in strict minimumReleaseAge mode reports the user-facing error'
expect(output).not.toContain('ERR_PNPM_RESOLUTION_POLICY_VIOLATIONS_UNHANDLED')
})
test('global update in loose minimumReleaseAge mode persists immature picks', () => {
skipIfPacquet('global update in loose minimumReleaseAge mode persists immature picks', () => {
prepare()
const global = path.resolve('..', 'global')
const pnpmHome = path.join(global, 'pnpm')
@@ -455,7 +456,7 @@ test('global update in loose minimumReleaseAge mode persists immature picks', ()
]))
})
test('global add cleans up stale bins when re-adding a package with different bins', async () => {
skipIfPacquet('global add cleans up stale bins when re-adding a package with different bins', async () => {
prepare()
const global = path.resolve('..', 'global')
const pnpmHome = path.join(global, 'pnpm')
@@ -495,7 +496,7 @@ test('global add cleans up stale bins when re-adding a package with different bi
expect(fs.existsSync(path.join(pnpmHome, 'bin', 'new-bin'))).toBeTruthy()
})
test('global add refuses to install when bin name conflicts with another global package', async () => {
skipIfPacquet('global add refuses to install when bin name conflicts with another global package', async () => {
prepare()
const global = path.resolve('..', 'global')
const pnpmHome = path.join(global, 'pnpm')
@@ -535,7 +536,7 @@ test('global add refuses to install when bin name conflicts with another global
expect(findGlobalPkg(globalPkgDir(pnpmHome), 'pkg-a')).toBeTruthy()
})
test('global add from a local directory using "."', () => {
skipIfPacquet('global add from a local directory using "."', () => {
prepare()
const global = path.resolve('..', 'global')
const pnpmHome = path.join(global, 'pnpm')
@@ -581,7 +582,7 @@ test('global add from a local directory using "."', () => {
expect(fs.existsSync(path.join(pnpmHome, 'bin', 'my-local-tool'))).toBeTruthy()
})
test('global ls --json outputs valid JSON (#11440)', async () => {
skipIfPacquet('global ls --json outputs valid JSON (#11440)', async () => {
prepare()
const global = path.resolve('..', 'global')
const pnpmHome = path.join(global, 'pnpm')
@@ -600,7 +601,7 @@ test('global ls --json outputs valid JSON (#11440)', async () => {
expect(parsed[0].dependencies['is-negative'].version).toBe('1.0.0')
})
test('global ls --parseable outputs paths', async () => {
skipIfPacquet('global ls --parseable outputs paths', async () => {
prepare()
const global = path.resolve('..', 'global')
const pnpmHome = path.join(global, 'pnpm')
@@ -616,7 +617,7 @@ test('global ls --parseable outputs paths', async () => {
expect(lines.some((line) => line.endsWith(path.join('node_modules', 'is-positive')))).toBe(true)
})
test('global ls --depth>0 errors across multiple isolated installs', async () => {
skipIfPacquet('global ls --depth>0 errors across multiple isolated installs', async () => {
prepare()
const global = path.resolve('..', 'global')
const pnpmHome = path.join(global, 'pnpm')
@@ -632,7 +633,7 @@ test('global ls --depth>0 errors across multiple isolated installs', async () =>
expect(result.stdout.toString() + result.stderr.toString()).toContain('GLOBAL_LS_DEPTH_NOT_SUPPORTED')
})
test('global ls --depth>0 shows the full dependency tree of a single global install', async () => {
skipIfPacquet('global ls --depth>0 shows the full dependency tree of a single global install', async () => {
prepare()
const global = path.resolve('..', 'global')
const pnpmHome = path.join(global, 'pnpm')
@@ -651,7 +652,7 @@ test('global ls --depth>0 shows the full dependency tree of a single global inst
expect(pkg.dependencies['@pnpm.e2e/dep-of-pkg-with-1-dep']).toBeDefined()
})
test('global ls <transitive> --depth>0 against a single global install reports the match', async () => {
skipIfPacquet('global ls <transitive> --depth>0 against a single global install reports the match', async () => {
prepare()
const global = path.resolve('..', 'global')
const pnpmHome = path.join(global, 'pnpm')
@@ -669,7 +670,7 @@ test('global ls <transitive> --depth>0 against a single global install reports t
expect(pkg.dependencies['@pnpm.e2e/dep-of-pkg-with-1-dep']).toBeDefined()
})
test('global ls <pkg> --depth>0 narrows to the install dir containing <pkg> and shows its tree', async () => {
skipIfPacquet('global ls <pkg> --depth>0 narrows to the install dir containing <pkg> and shows its tree', async () => {
prepare()
const global = path.resolve('..', 'global')
const pnpmHome = path.join(global, 'pnpm')
@@ -691,7 +692,7 @@ test('global ls <pkg> --depth>0 narrows to the install dir containing <pkg> and
expect(pkg.dependencies['@pnpm.e2e/dep-of-pkg-with-1-dep']).toBeDefined()
})
test('global remove deletes install group and bin shims', async () => {
skipIfPacquet('global remove deletes install group and bin shims', async () => {
prepare()
const global = path.resolve('..', 'global')
const pnpmHome = path.join(global, 'pnpm')
@@ -731,7 +732,7 @@ test('global remove deletes install group and bin shims', async () => {
expect(findGlobalPkg(globalPkgDir(pnpmHome), 'tool-b')).toBeNull()
})
test('global add installs each space-separated package into its own isolated group', async () => {
skipIfPacquet('global add installs each space-separated package into its own isolated group', async () => {
prepare()
const global = path.resolve('..', 'global')
const pnpmHome = path.join(global, 'pnpm')
@@ -755,7 +756,7 @@ test('global add installs each space-separated package into its own isolated gro
expect(findGlobalPkg(globalPkgDir(pnpmHome), 'is-negative')).toBeTruthy()
})
test('global add bundles comma-separated packages into a single group', async () => {
skipIfPacquet('global add bundles comma-separated packages into a single group', async () => {
prepare()
const global = path.resolve('..', 'global')
const pnpmHome = path.join(global, 'pnpm')
@@ -779,7 +780,7 @@ test('global add bundles comma-separated packages into a single group', async ()
expect(peerC!.installDir).not.toBe(positive!.installDir)
})
test('global add does not treat commas inside a local path selector as a group separator', () => {
skipIfPacquet('global add does not treat commas inside a local path selector as a group separator', () => {
prepare()
const global = path.resolve('..', 'global')
const pnpmHome = path.join(global, 'pnpm')

View File

@@ -6,9 +6,12 @@ import { prepare } from '@pnpm/prepare'
import { readYamlFileSync } from 'read-yaml-file'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm } from '../utils/index.js'
import {
execPnpm,
skipIfPacquet,
} from '../utils/index.js'
test('using a global virtual store', async () => {
skipIfPacquet('using a global virtual store', async () => {
prepare({
dependencies: {
'@pnpm.e2e/pkg-with-1-dep': '100.0.0',
@@ -31,7 +34,7 @@ test('using a global virtual store', async () => {
expect(fs.existsSync(path.join(globalVirtualStoreDir, '@pnpm.e2e/pkg-with-1-dep/100.0.0', files[0], 'node_modules/@pnpm.e2e/dep-of-pkg-with-1-dep/package.json'))).toBeTruthy()
})
test('approve-builds updates GVS symlinks and runs builds at correct hash directory', async () => {
skipIfPacquet('approve-builds updates GVS symlinks and runs builds at correct hash directory', async () => {
prepare({
dependencies: {
'@pnpm.e2e/pre-and-postinstall-scripts-example': '1.0.0',

View File

@@ -1,10 +1,12 @@
import { test } from '@jest/globals'
import { prepare, preparePackages } from '@pnpm/prepare'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm } from '../utils/index.js'
import {
execPnpm,
skipIfPacquet,
} from '../utils/index.js'
test('hoist the dependency graph', async () => {
skipIfPacquet('hoist the dependency graph', async () => {
const project = prepare()
await execPnpm(['install', 'express@4.16.2'])
@@ -20,7 +22,7 @@ test('hoist the dependency graph', async () => {
project.hasNot('.pnpm/node_modules/cookie')
})
test('shamefully hoist the dependency graph', async () => {
skipIfPacquet('shamefully hoist the dependency graph', async () => {
const project = prepare()
writeYamlFileSync('pnpm-workspace.yaml', { shamefullyHoist: true })
@@ -38,7 +40,7 @@ test('shamefully hoist the dependency graph', async () => {
project.hasNot('cookie')
})
test('shamefully-hoist: applied to all the workspace projects when set to true in the root pnpm-workspace.yaml file', async () => {
skipIfPacquet('shamefully-hoist: applied to all the workspace projects when set to true in the root pnpm-workspace.yaml file', async () => {
const projects = preparePackages([
{
location: '.',
@@ -74,7 +76,7 @@ test('shamefully-hoist: applied to all the workspace projects when set to true i
projects.project.has('@pnpm.e2e/foobar')
})
test('shamefully-hoist: applied to all the workspace projects when set to true in the root pnpm-workspace.yaml file (with dedupe-direct-deps=true)', async () => {
skipIfPacquet('shamefully-hoist: applied to all the workspace projects when set to true in the root pnpm-workspace.yaml file (with dedupe-direct-deps=true)', async () => {
const projects = preparePackages([
{
location: '.',

View File

@@ -1,7 +1,7 @@
import fs from 'node:fs'
import path from 'node:path'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import type { LockfileFile } from '@pnpm/lockfile.types'
import { prepare, preparePackages } from '@pnpm/prepare'
import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
@@ -13,9 +13,10 @@ import {
addDistTag,
execPnpm,
execPnpmSync,
skipIfPacquet,
} from '../utils/index.js'
test('readPackage hook', async () => {
skipIfPacquet('readPackage hook', async () => {
const project = prepare()
fs.writeFileSync('.pnpmfile.cjs', `
@@ -40,7 +41,7 @@ test('readPackage hook', async () => {
project.storeHas('@pnpm.e2e/dep-of-pkg-with-1-dep', '100.0.0')
})
test('readPackage async hook', async () => {
skipIfPacquet('readPackage async hook', async () => {
const project = prepare()
fs.writeFileSync('.pnpmfile.cjs', `
@@ -65,7 +66,7 @@ test('readPackage async hook', async () => {
project.storeHas('@pnpm.e2e/dep-of-pkg-with-1-dep', '100.0.0')
})
test('readPackage hook makes installation fail if it does not return the modified package manifests', async () => {
skipIfPacquet('readPackage hook makes installation fail if it does not return the modified package manifests', async () => {
prepare()
fs.writeFileSync('.pnpmfile.cjs', `
@@ -82,7 +83,7 @@ test('readPackage hook makes installation fail if it does not return the modifie
expect(result.status).toBe(1)
})
test('readPackage hook from custom location', async () => {
skipIfPacquet('readPackage hook from custom location', async () => {
const project = prepare()
fs.writeFileSync('pnpm.js', `
@@ -107,7 +108,7 @@ test('readPackage hook from custom location', async () => {
project.storeHas('@pnpm.e2e/dep-of-pkg-with-1-dep', '100.0.0')
})
test('readPackage hook from global pnpmfile', async () => {
skipIfPacquet('readPackage hook from global pnpmfile', async () => {
const project = prepare()
fs.writeFileSync('../.pnpmfile.cjs', `
@@ -132,7 +133,7 @@ test('readPackage hook from global pnpmfile', async () => {
project.storeHas('@pnpm.e2e/dep-of-pkg-with-1-dep', '100.0.0')
})
test('readPackage hook from global pnpmfile and local pnpmfile', async () => {
skipIfPacquet('readPackage hook from global pnpmfile and local pnpmfile', async () => {
const project = prepare()
fs.writeFileSync('../.pnpmfile.cjs', `
@@ -173,7 +174,7 @@ test('readPackage hook from global pnpmfile and local pnpmfile', async () => {
project.storeHas('is-positive', '1.0.0')
})
test('readPackage async hook from global pnpmfile and local pnpmfile', async () => {
skipIfPacquet('readPackage async hook from global pnpmfile and local pnpmfile', async () => {
const project = prepare()
fs.writeFileSync('../.pnpmfile.cjs', `
@@ -214,7 +215,7 @@ test('readPackage async hook from global pnpmfile and local pnpmfile', async ()
project.storeHas('is-positive', '1.0.0')
})
test('readPackage hook from pnpmfile at root of workspace', async () => {
skipIfPacquet('readPackage hook from pnpmfile at root of workspace', async () => {
const projects = preparePackages([
{
name: 'project-1',
@@ -260,7 +261,7 @@ test('readPackage hook from pnpmfile at root of workspace', async () => {
})
})
test('readPackage hook during update', async () => {
skipIfPacquet('readPackage hook during update', async () => {
const project = prepare({
dependencies: {
'@pnpm.e2e/pkg-with-1-dep': '*',
@@ -289,7 +290,7 @@ test('readPackage hook during update', async () => {
project.storeHas('@pnpm.e2e/dep-of-pkg-with-1-dep', '100.0.0')
})
test('prints meaningful error when there is syntax error in .pnpmfile.cjs', async () => {
skipIfPacquet('prints meaningful error when there is syntax error in .pnpmfile.cjs', async () => {
prepare()
fs.writeFileSync('.pnpmfile.cjs', '/boom', 'utf8')
@@ -300,7 +301,7 @@ test('prints meaningful error when there is syntax error in .pnpmfile.cjs', asyn
expect(proc.status).toBe(1)
})
test('fails when .pnpmfile.cjs requires a non-existed module', async () => {
skipIfPacquet('fails when .pnpmfile.cjs requires a non-existed module', async () => {
prepare()
fs.writeFileSync('.pnpmfile.cjs', 'module.exports = require("./this-does-node-exist")', 'utf8')
@@ -311,7 +312,7 @@ test('fails when .pnpmfile.cjs requires a non-existed module', async () => {
expect(proc.status).toBe(1)
})
test('ignore .pnpmfile.cjs when --ignore-pnpmfile is used', async () => {
skipIfPacquet('ignore .pnpmfile.cjs when --ignore-pnpmfile is used', async () => {
const project = prepare()
fs.writeFileSync('.pnpmfile.cjs', `
@@ -335,7 +336,7 @@ test('ignore .pnpmfile.cjs when --ignore-pnpmfile is used', async () => {
project.storeHas('@pnpm.e2e/dep-of-pkg-with-1-dep', '100.1.0')
})
test('ignore .pnpmfile.cjs during update when --ignore-pnpmfile is used', async () => {
skipIfPacquet('ignore .pnpmfile.cjs during update when --ignore-pnpmfile is used', async () => {
const project = prepare({
dependencies: {
'@pnpm.e2e/pkg-with-1-dep': '*',
@@ -363,7 +364,7 @@ test('ignore .pnpmfile.cjs during update when --ignore-pnpmfile is used', async
project.storeHas('@pnpm.e2e/dep-of-pkg-with-1-dep', '100.1.0')
})
test('pnpmfile: pass log function to readPackage hook', async () => {
skipIfPacquet('pnpmfile: pass log function to readPackage hook', async () => {
const project = prepare()
fs.writeFileSync('.pnpmfile.cjs', `
@@ -401,7 +402,7 @@ test('pnpmfile: pass log function to readPackage hook', async () => {
expect(hookLog.message).toBe('@pnpm.e2e/dep-of-pkg-with-1-dep pinned to 100.0.0')
})
test('pnpmfile: pass log function to readPackage hook of global and local pnpmfile', async () => {
skipIfPacquet('pnpmfile: pass log function to readPackage hook of global and local pnpmfile', async () => {
const project = prepare()
fs.writeFileSync('../.pnpmfile.cjs', `
@@ -465,7 +466,7 @@ test('pnpmfile: pass log function to readPackage hook of global and local pnpmfi
expect(hookLogs[0].from).not.toBe(hookLogs[1].from)
})
test('pnpmfile: run afterAllResolved hook', async () => {
skipIfPacquet('pnpmfile: run afterAllResolved hook', async () => {
prepare()
fs.writeFileSync('.pnpmfile.cjs', `
@@ -495,7 +496,7 @@ test('pnpmfile: run afterAllResolved hook', async () => {
expect(hookLog.message).toBe('All resolved')
})
test('pnpmfile: run async afterAllResolved hook', async () => {
skipIfPacquet('pnpmfile: run async afterAllResolved hook', async () => {
prepare()
fs.writeFileSync('.pnpmfile.cjs', `
@@ -525,7 +526,7 @@ test('pnpmfile: run async afterAllResolved hook', async () => {
expect(hookLog.message).toBe('All resolved')
})
test('readPackage hook normalizes the package manifest', async () => {
skipIfPacquet('readPackage hook normalizes the package manifest', async () => {
prepare()
fs.writeFileSync('.pnpmfile.cjs', `
@@ -548,7 +549,7 @@ test('readPackage hook normalizes the package manifest', async () => {
await execPnpm(['install', '@pnpm.e2e/dep-of-pkg-with-1-dep'])
})
test('readPackage hook overrides project package', async () => {
skipIfPacquet('readPackage hook overrides project package', async () => {
const project = prepare({
name: 'test-read-package-hook',
})
@@ -577,7 +578,7 @@ test('readPackage hook overrides project package', async () => {
expect(pkg.dependencies).toBeFalsy()
})
test('readPackage hook is used during removal inside a workspace', async () => {
skipIfPacquet('readPackage hook is used during removal inside a workspace', async () => {
preparePackages([
{
name: 'project',
@@ -621,7 +622,7 @@ test('readPackage hook is used during removal inside a workspace', async () => {
expect(lockfile.packages!['@pnpm.e2e/abc@1.0.0'].peerDependencies!['is-negative']).toBe('1.0.0')
})
test('preResolution hook', async () => {
skipIfPacquet('preResolution hook', async () => {
prepare()
const pnpmfile = `
const fs = require('fs')
@@ -658,7 +659,7 @@ test('preResolution hook', async () => {
})
})
test('pass readPackage with shared lockfile', async () => {
skipIfPacquet('pass readPackage with shared lockfile', async () => {
const projects = preparePackages([
{
name: 'project-1',

View File

@@ -1,13 +1,16 @@
import fs from 'node:fs'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { preparePackages } from '@pnpm/prepare'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm } from '../utils/index.js'
import {
execPnpm,
skipIfPacquet,
} from '../utils/index.js'
// Covers https://github.com/pnpm/pnpm/issues/8959
test('restores deleted modules dir of a workspace package', async () => {
skipIfPacquet('restores deleted modules dir of a workspace package', async () => {
preparePackages([
{
location: '.',

View File

@@ -9,12 +9,16 @@ import { loadJsonFileSync } from 'load-json-file'
import PATH from 'path-name'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpmSync, pnpmBinLocation } from '../utils/index.js'
import {
execPnpmSync,
pnpmBinLocation,
skipIfPacquet,
} from '../utils/index.js'
const pkgRoot = path.join(import.meta.dirname, '..', '..')
const pnpmPkg = loadJsonFileSync<PackageManifest>(path.join(pkgRoot, 'package.json'))
test('installation fails if lifecycle script fails', () => {
skipIfPacquet('installation fails if lifecycle script fails', () => {
prepare({
scripts: {
preinstall: 'exit 1',
@@ -26,7 +30,7 @@ test('installation fails if lifecycle script fails', () => {
expect(result.status).toBe(1)
})
test('lifecycle script runs with the correct user agent', () => {
skipIfPacquet('lifecycle script runs with the correct user agent', () => {
prepare({
scripts: {
preinstall: 'node --eval "console.log(process.env.npm_config_user_agent)"',
@@ -40,7 +44,7 @@ test('lifecycle script runs with the correct user agent', () => {
expect(result.stdout.toString()).toContain(expectedUserAgentPrefix)
})
test('preinstall is executed before general installation', () => {
skipIfPacquet('preinstall is executed before general installation', () => {
prepare({
scripts: {
preinstall: 'echo "Hello world!"',
@@ -53,7 +57,7 @@ test('preinstall is executed before general installation', () => {
expect(result.stdout.toString()).toContain('Hello world!')
})
test('postinstall is executed after general installation', () => {
skipIfPacquet('postinstall is executed after general installation', () => {
prepare({
scripts: {
postinstall: 'echo "Hello world!"',
@@ -66,7 +70,7 @@ test('postinstall is executed after general installation', () => {
expect(result.stdout.toString()).toContain('Hello world!')
})
test('postinstall is not executed after named installation', () => {
skipIfPacquet('postinstall is not executed after named installation', () => {
prepare({
scripts: {
postinstall: 'echo "Hello world!"',
@@ -79,7 +83,7 @@ test('postinstall is not executed after named installation', () => {
expect(result.stdout.toString()).not.toContain('Hello world!')
})
test('prepare is not executed after installation with arguments', () => {
skipIfPacquet('prepare is not executed after installation with arguments', () => {
prepare({
scripts: {
prepare: 'echo "Hello world!"',
@@ -92,7 +96,7 @@ test('prepare is not executed after installation with arguments', () => {
expect(result.stdout.toString()).not.toContain('Hello world!')
})
test('prepare is executed after argumentless installation', () => {
skipIfPacquet('prepare is executed after argumentless installation', () => {
prepare({
scripts: {
prepare: 'echo "Hello world!"',
@@ -146,7 +150,7 @@ test('node-gyp is in the PATH', async () => {
expect(result.status).toBe(0)
})
test('selectively allow scripts in some dependencies by --allow-build flag', async () => {
skipIfPacquet('selectively allow scripts in some dependencies by --allow-build flag', async () => {
const project = prepare({})
execPnpmSync(['add', '--allow-build=@pnpm.e2e/install-script-example', '@pnpm.e2e/pre-and-postinstall-scripts-example@1.0.0', '@pnpm.e2e/install-script-example'])
@@ -161,7 +165,7 @@ test('selectively allow scripts in some dependencies by --allow-build flag', asy
})
})
test('--allow-build flag should specify the package', async () => {
skipIfPacquet('--allow-build flag should specify the package', async () => {
const project = prepare({})
const result = execPnpmSync(['add', '@pnpm.e2e/pre-and-postinstall-scripts-example@1.0.0', '--allow-build'])
@@ -176,7 +180,7 @@ test('--allow-build flag should specify the package', async () => {
expect(modulesManifest?.allowBuilds).toBeUndefined()
})
test('preinstall script does not trigger verify-deps-before-run (#8954)', async () => {
skipIfPacquet('preinstall script does not trigger verify-deps-before-run (#8954)', async () => {
const pnpm = `${process.execPath} ${pnpmBinLocation}` // this would fail if either paths happen to contain spaces
prepare({
@@ -197,7 +201,7 @@ test('preinstall script does not trigger verify-deps-before-run (#8954)', async
expect(output.stdout.toString()).toContain('hello world')
})
test('preinstall and postinstall scripts do not trigger verify-deps-before-run when using settings from a config file (#10060)', async () => {
skipIfPacquet('preinstall and postinstall scripts do not trigger verify-deps-before-run when using settings from a config file (#10060)', async () => {
const pnpm = `${process.execPath} ${pnpmBinLocation}` // this would fail if either paths happen to contain spaces
prepare({
@@ -223,7 +227,7 @@ test('preinstall and postinstall scripts do not trigger verify-deps-before-run w
expect(output.stdout.toString()).toContain('hello world')
})
test('throw an error when strict-dep-builds is true and there are ignored scripts', async () => {
skipIfPacquet('throw an error when strict-dep-builds is true and there are ignored scripts', async () => {
const project = prepare({})
const result = execPnpmSync(['add', '@pnpm.e2e/pre-and-postinstall-scripts-example@1.0.0', '--config.strict-dep-builds=true'])
@@ -242,7 +246,7 @@ test('throw an error when strict-dep-builds is true and there are ignored script
})
})
test('allowBuilds false resolves a strict ignored-build failure on repeat install', async () => {
skipIfPacquet('allowBuilds false resolves a strict ignored-build failure on repeat install', async () => {
const project = prepare({})
writeYamlFileSync('pnpm-workspace.yaml', {
optimisticRepeatInstall: true,
@@ -274,7 +278,7 @@ test('allowBuilds false resolves a strict ignored-build failure on repeat instal
expect(Array.from(modulesManifest?.ignoredBuilds ?? [])).toStrictEqual([])
})
test('the list of ignored builds is preserved after a repeat install', async () => {
skipIfPacquet('the list of ignored builds is preserved after a repeat install', async () => {
const project = prepare({})
execPnpmSync(['add', '@pnpm.e2e/pre-and-postinstall-scripts-example@1.0.0', 'esbuild@0.25.0', '--config.optimistic-repeat-install=false'])
@@ -289,7 +293,7 @@ test('the list of ignored builds is preserved after a repeat install', async ()
])
})
test('ignored builds are auto-populated as placeholders in allowBuilds', async () => {
skipIfPacquet('ignored builds are auto-populated as placeholders in allowBuilds', async () => {
prepare({})
execPnpmSync(['add', '@pnpm.e2e/pre-and-postinstall-scripts-example@1.0.0'])
@@ -297,7 +301,7 @@ test('ignored builds are auto-populated as placeholders in allowBuilds', async (
expect(manifest?.allowBuilds?.['@pnpm.e2e/pre-and-postinstall-scripts-example']).toBe('set this to true or false')
})
test('auto-populated placeholders are merged with existing allowBuilds', async () => {
skipIfPacquet('auto-populated placeholders are merged with existing allowBuilds', async () => {
prepare({})
writeYamlFileSync('pnpm-workspace.yaml', {
allowBuilds: {
@@ -311,7 +315,7 @@ test('auto-populated placeholders are merged with existing allowBuilds', async (
expect(manifest?.allowBuilds?.['@pnpm.e2e/pre-and-postinstall-scripts-example']).toBe('set this to true or false')
})
test('selective rebuild preserves ignoredBuilds for packages not being rebuilt', async () => {
skipIfPacquet('selective rebuild preserves ignoredBuilds for packages not being rebuilt', async () => {
const project = prepare({})
writeYamlFileSync('pnpm-workspace.yaml', {
allowBuilds: {
@@ -332,7 +336,7 @@ test('selective rebuild preserves ignoredBuilds for packages not being rebuilt',
expect(afterRebuild!.ignoredBuilds).toBeDefined()
})
test('strictDepBuilds fails for packages with cached side-effects (#11035)', async () => {
skipIfPacquet('strictDepBuilds fails for packages with cached side-effects (#11035)', async () => {
prepare({
dependencies: {
'@pnpm.e2e/pre-and-postinstall-scripts-example': '1.0.0',
@@ -365,7 +369,7 @@ test('strictDepBuilds fails for packages with cached side-effects (#11035)', asy
expect(secondResult.stdout.toString()).toContain('Ignored build scripts:')
})
test('git dependencies with preparation scripts should be installed when dangerouslyAllowAllBuilds is true', async () => {
skipIfPacquet('git dependencies with preparation scripts should be installed when dangerouslyAllowAllBuilds is true', async () => {
prepare({})
writeYamlFileSync('pnpm-workspace.yaml', { dangerouslyAllowAllBuilds: true })
@@ -376,7 +380,7 @@ test('git dependencies with preparation scripts should be installed when dangero
expect(fs.existsSync('node_modules/test-git-fetch/dist/index.js')).toBeTruthy()
})
test('--allow-build flag should error when conflicting with allowBuilds: false', async () => {
skipIfPacquet('--allow-build flag should error when conflicting with allowBuilds: false', async () => {
prepare({})
writeYamlFileSync('pnpm-workspace.yaml', {
allowBuilds: { '@pnpm.e2e/install-script-example': false },

View File

@@ -6,7 +6,11 @@ import { prepare, preparePackages } from '@pnpm/prepare'
import { readYamlFileSync } from 'read-yaml-file'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm, execPnpmSync } from '../utils/index.js'
import {
execPnpm,
execPnpmSync,
skipIfPacquet,
} from '../utils/index.js'
// The public npm registry is used here instead of verdaccio because the
// registry mock doesn't include the per-version `time` field in full-metadata
@@ -26,7 +30,7 @@ const IMMATURE_FOR_EVERYTHING = 60 * 24 * 365 * 27
const omitMinReleaseAgeEnv = { omitEnvDefaults: ['pnpm_config_minimum_release_age' as const] }
describe('lockfile minimumReleaseAge verification', () => {
test('install rejects a lockfile entry that does not satisfy the policy in strict mode', async () => {
skipIfPacquet('install rejects a lockfile entry that does not satisfy the policy in strict mode', async () => {
// Step 1: populate a lockfile under no policy. The resolver picks
// is-odd@0.1.2 (latest 0.1.x) without applying any maturity filter.
prepare({
@@ -120,7 +124,7 @@ describe('lockfile minimumReleaseAge verification', () => {
)
})
test('a fresh install records the just-written lockfile in the verification cache', async () => {
skipIfPacquet('a fresh install records the just-written lockfile in the verification cache', async () => {
// Reproduces the "install foo, rm -rf node_modules, install" flow:
// the lockfile written by the first install must be recorded under
// its post-resolution content, otherwise the second install re-runs
@@ -188,7 +192,7 @@ describe('lockfile minimumReleaseAge verification', () => {
expect(output).toMatch(/is-odd@0\.1\.2/)
})
test('loose mode auto-adds fresh immature picks to minimumReleaseAgeExclude', () => {
skipIfPacquet('loose mode auto-adds fresh immature picks to minimumReleaseAgeExclude', () => {
// Fresh resolution under loose mode: the resolver's lowest-version
// fallback picks an immature version, and the install layer surfaces it
// to `minimumReleaseAgeExclude`. The verifier sees an empty lockfile at
@@ -243,7 +247,7 @@ describe('lockfile minimumReleaseAge verification', () => {
expect(workspaceManifest.minimumReleaseAgeExclude).toBeUndefined()
})
test('subsequent installs run cleanly once the exclude list is populated', () => {
skipIfPacquet('subsequent installs run cleanly once the exclude list is populated', () => {
// Round-trip the auto-collect: first install populates the exclude list
// from fresh resolution, the next install runs the verifier against the
// now-populated list and succeeds without re-announcing anything. The
@@ -268,7 +272,7 @@ describe('lockfile minimumReleaseAge verification', () => {
)
})
test('recursive --no-save leaves the workspace manifest untouched even when picks are collected (shared lockfile)', () => {
skipIfPacquet('recursive --no-save leaves the workspace manifest untouched even when picks are collected (shared lockfile)', () => {
// The shared-lockfile recursive branch in recursive.ts: a single
// `mutateModules` call across all importers. Same drain-only-when-
// saving gate has to hold here.
@@ -294,7 +298,7 @@ describe('lockfile minimumReleaseAge verification', () => {
expect(workspaceManifest.minimumReleaseAgeExclude).toBeUndefined()
})
test('recursive --no-save leaves the workspace manifest untouched even when picks are collected (per-project lockfiles)', () => {
skipIfPacquet('recursive --no-save leaves the workspace manifest untouched even when picks are collected (per-project lockfiles)', () => {
// The other recursive branch: with sharedWorkspaceLockfile: false
// the per-project loop is taken instead of the single
// mutateModules call. The post-loop updateWorkspaceManifest at the
@@ -322,7 +326,7 @@ describe('lockfile minimumReleaseAge verification', () => {
expect(workspaceManifest.minimumReleaseAgeExclude).toBeUndefined()
})
test('--no-save leaves the workspace manifest untouched even when picks are collected', () => {
skipIfPacquet('--no-save leaves the workspace manifest untouched even when picks are collected', () => {
// `--no-save` means "don't persist anything from this install" — the
// auto-add should obey that. Without the gate, the info log would
// claim entries were added that never reached pnpm-workspace.yaml,

View File

@@ -16,16 +16,15 @@ import { writeProjectManifest } from '@pnpm/workspace.project-manifest-writer'
import { rimrafSync } from '@zkochan/rimraf'
import crossSpawn from 'cross-spawn'
import { dirIsCaseSensitive } from 'dir-is-case-sensitive'
import isWindows from 'is-windows'
import { readYamlFileSync } from 'read-yaml-file'
import { writeYamlFileSync } from 'write-yaml-file'
import {
execPnpm,
execPnpmSync,
skipIfPacquet,
} from '../utils/index.js'
const skipOnWindows = isWindows() ? test.skip : test
const f = fixtures(import.meta.dirname)
const storeIndexes: StoreIndex[] = []
@@ -33,7 +32,7 @@ afterAll(() => {
for (const si of storeIndexes) si.close()
})
test('bin files are found by lifecycle scripts', () => {
skipIfPacquet('bin files are found by lifecycle scripts', () => {
prepare({
dependencies: {
'@pnpm.e2e/hello-world-js-bin': '*',
@@ -49,7 +48,7 @@ test('bin files are found by lifecycle scripts', () => {
expect(result.stdout.toString()).toContain('Hello world!')
})
skipOnWindows('install --lockfile-only', async () => {
skipIfPacquet('install --lockfile-only', async () => {
const project = prepare()
await execPnpm(['install', 'rimraf@2.5.1', '--lockfile-only'])
@@ -60,7 +59,7 @@ skipOnWindows('install --lockfile-only', async () => {
expect(lockfile.packages).toHaveProperty(['rimraf@2.5.1'])
})
test('install --no-lockfile', async () => {
skipIfPacquet('install --no-lockfile', async () => {
const project = prepare()
await execPnpm(['install', 'is-positive', '--no-lockfile'])
@@ -70,7 +69,7 @@ test('install --no-lockfile', async () => {
expect(project.readLockfile()).toBeFalsy()
})
test('write to stderr when --use-stderr is used', async () => {
skipIfPacquet('write to stderr when --use-stderr is used', async () => {
const project = prepare()
const result = execPnpmSync(['add', 'is-positive', '--use-stderr'])
@@ -94,7 +93,7 @@ test('install with lockfile being false in pnpm-workspace.yaml', async () => {
expect(project.readLockfile()).toBeFalsy()
})
test('install from any location via the --prefix flag', async () => {
skipIfPacquet('install from any location via the --prefix flag', async () => {
const project = prepare({
dependencies: {
rimraf: '2.6.2',
@@ -109,7 +108,7 @@ test('install from any location via the --prefix flag', async () => {
project.isExecutable('.bin/rimraf')
})
test('install with external lockfile directory', async () => {
skipIfPacquet('install with external lockfile directory', async () => {
const project = prepare()
await execPnpm(['install', 'is-positive', '--lockfile-dir', path.resolve('..')])
@@ -121,7 +120,7 @@ test('install with external lockfile directory', async () => {
expect(Object.keys(lockfile.importers)).toStrictEqual(['project'])
})
test('install --save-exact', async () => {
skipIfPacquet('install --save-exact', async () => {
const project = prepare()
await execPnpm(['install', 'is-positive@3.1.0', '--save-exact', '--save-dev'])
@@ -133,7 +132,7 @@ test('install --save-exact', async () => {
expect(pkg.devDependencies).toStrictEqual({ 'is-positive': '3.1.0' })
})
test('install to a project that uses package.yaml', async () => {
skipIfPacquet('install to a project that uses package.yaml', async () => {
const project = prepareEmpty()
await writeProjectManifest(path.resolve('package.yaml'), { name: 'foo', version: '1.0.0' })
@@ -147,7 +146,7 @@ test('install to a project that uses package.yaml', async () => {
expect(manifest?.devDependencies).toStrictEqual({ 'is-positive': '3.1.0' })
})
test('install save new dep with the specified spec', async () => {
skipIfPacquet('install save new dep with the specified spec', async () => {
const project = prepare()
await execPnpm(['install', 'is-positive@~3.1.0'])
@@ -160,7 +159,7 @@ test('install save new dep with the specified spec', async () => {
})
// Covers https://github.com/pnpm/pnpm/issues/1685
test("don't fail on case insensitive filesystems when package has 2 files with same name", async () => {
skipIfPacquet("don't fail on case insensitive filesystems when package has 2 files with same name", async () => {
const project = prepare()
await execPnpm(['install', '@pnpm.e2e/with-same-file-in-different-cases'])
@@ -187,7 +186,7 @@ test("don't fail on case insensitive filesystems when package has 2 files with s
}
})
test('top-level packages should find the plugins they use', async () => {
skipIfPacquet('top-level packages should find the plugins they use', async () => {
prepare({
scripts: {
test: 'pkg-that-uses-plugins',
@@ -201,7 +200,7 @@ test('top-level packages should find the plugins they use', async () => {
expect(result.status).toBe(0)
})
test('not top-level packages should find the plugins they use', async () => {
skipIfPacquet('not top-level packages should find the plugins they use', async () => {
// standard depends on eslint and eslint plugins
prepare({
scripts: {
@@ -216,7 +215,7 @@ test('not top-level packages should find the plugins they use', async () => {
expect(result.status).toBe(0)
})
test('run js bin file', async () => {
skipIfPacquet('run js bin file', async () => {
prepare({
scripts: {
test: 'hello-world-js-bin',
@@ -230,7 +229,7 @@ test('run js bin file', async () => {
expect(result.status).toBe(0)
})
test('create a package.json if there is none', async () => {
skipIfPacquet('create a package.json if there is none', async () => {
prepareEmpty()
await execPnpm(['install', '@pnpm.e2e/dep-of-pkg-with-1-dep@100.1.0'])
@@ -242,7 +241,7 @@ test('create a package.json if there is none', async () => {
})
})
test('`pnpm add` should fail if no package name was provided', () => {
skipIfPacquet('`pnpm add` should fail if no package name was provided', () => {
prepare()
const { status, stdout } = execPnpmSync(['add'])
@@ -251,7 +250,7 @@ test('`pnpm add` should fail if no package name was provided', () => {
expect(stdout.toString()).toContain('`pnpm add` requires the package name')
})
test('`pnpm -r add` should fail if no package name was provided', () => {
skipIfPacquet('`pnpm -r add` should fail if no package name was provided', () => {
preparePackages([
{
name: 'project',
@@ -268,7 +267,7 @@ test('`pnpm -r add` should fail if no package name was provided', () => {
expect(stdout.toString()).toContain('`pnpm add` requires the package name')
})
test('engine-strict=false: install should not fail if the used Node version does not satisfy the Node version specified in engines', async () => {
skipIfPacquet('engine-strict=false: install should not fail if the used Node version does not satisfy the Node version specified in engines', async () => {
prepare({
name: 'project',
version: '1.0.0',
@@ -284,7 +283,7 @@ test('engine-strict=false: install should not fail if the used Node version does
expect(stdout.toString()).toContain('Unsupported engine')
})
test('engine-strict=true: install should fail if the used Node version does not satisfy the Node version specified in engines', async () => {
skipIfPacquet('engine-strict=true: install should fail if the used Node version does not satisfy the Node version specified in engines', async () => {
prepare({
name: 'project',
version: '1.0.0',
@@ -300,7 +299,7 @@ test('engine-strict=true: install should fail if the used Node version does not
expect(stdout.toString()).toContain('Your Node version is incompatible with')
})
test('recursive install should fail if the used pnpm version does not satisfy the pnpm version specified in engines of any of the workspace projects', async () => {
skipIfPacquet('recursive install should fail if the used pnpm version does not satisfy the pnpm version specified in engines of any of the workspace projects', async () => {
preparePackages([
{
name: 'project-1',
@@ -334,7 +333,7 @@ test('recursive install should fail if the used pnpm version does not satisfy th
expect(stdout.toString()).toContain('Your pnpm version is incompatible with')
})
test('engine-strict=true: recursive install should fail if the used Node version does not satisfy the Node version specified in engines of any of the workspace projects', async () => {
skipIfPacquet('engine-strict=true: recursive install should fail if the used Node version does not satisfy the Node version specified in engines of any of the workspace projects', async () => {
preparePackages([
{
name: 'project-1',
@@ -368,7 +367,7 @@ test('engine-strict=true: recursive install should fail if the used Node version
expect(stdout.toString()).toContain('Your Node version is incompatible with')
})
test('engine-strict=false: recursive install should not fail if the used Node version does not satisfy the Node version specified in engines of any of the workspace projects', async () => {
skipIfPacquet('engine-strict=false: recursive install should not fail if the used Node version does not satisfy the Node version specified in engines of any of the workspace projects', async () => {
preparePackages([
{
name: 'project-1',
@@ -402,7 +401,7 @@ test('engine-strict=false: recursive install should not fail if the used Node ve
expect(stdout.toString()).toContain('Unsupported engine')
})
test('using a custom virtual-store-dir location', async () => {
skipIfPacquet('using a custom virtual-store-dir location', async () => {
prepare({
dependencies: { rimraf: '2.5.1' },
})
@@ -424,7 +423,7 @@ test('using a custom virtual-store-dir location', async () => {
})
// This is an integration test only because it is hard to mock is-ci
test('installing in a CI environment', async () => {
skipIfPacquet('installing in a CI environment', async () => {
const project = prepare({
dependencies: { rimraf: '2.5.1' },
})
@@ -513,7 +512,7 @@ test('installation fails with a timeout error', async () => {
).rejects.toThrow()
})
test('installation fails when the stored package name and version do not match the meta of the installed package', async () => {
skipIfPacquet('installation fails when the stored package name and version do not match the meta of the installed package', async () => {
prepare()
const storeDir = path.resolve('store')
const settings = [`--config.store-dir=${storeDir}`]
@@ -538,7 +537,7 @@ test('installation fails when the stored package name and version do not match t
})
// Covers https://github.com/pnpm/pnpm/issues/8538
test('do not fail to render peer dependencies warning, when cache was hit during peer resolution', () => {
skipIfPacquet('do not fail to render peer dependencies warning, when cache was hit during peer resolution', () => {
prepare({
dependencies: {
'@udecode/plate-ui-table': '18.15.0',
@@ -553,7 +552,7 @@ test('do not fail to render peer dependencies warning, when cache was hit during
})
// Covers https://github.com/pnpm/pnpm/issues/8720
test('do not hang on circular peer dependencies', () => {
skipIfPacquet('do not hang on circular peer dependencies', () => {
const tempDir = f.prepare('workspace-with-circular-peers')
process.chdir(tempDir)
@@ -564,7 +563,7 @@ test('do not hang on circular peer dependencies', () => {
})
// Covers https://github.com/pnpm/pnpm/issues/7697
test('install success even though the url\'s hash contains slash', async () => {
skipIfPacquet('install success even though the url\'s hash contains slash', async () => {
prepare()
const settings = ['--fetch-retries=0']
const result = execPnpmSync([
@@ -575,7 +574,7 @@ test('install success even though the url\'s hash contains slash', async () => {
expect(result.status).toBe(0)
})
test('install fails when the trust evidence of a package is downgraded', async () => {
skipIfPacquet('install fails when the trust evidence of a package is downgraded', async () => {
const project = prepare()
const result = execPnpmSync([
'add',
@@ -586,7 +585,7 @@ test('install fails when the trust evidence of a package is downgraded', async (
project.hasNot('@pnpm/e2e.test-provenance')
})
test('install does not fail when the trust evidence of a package is downgraded but trust-policy is turned off', async () => {
skipIfPacquet('install does not fail when the trust evidence of a package is downgraded but trust-policy is turned off', async () => {
const project = prepare()
const result = execPnpmSync([
'add',
@@ -597,7 +596,7 @@ test('install does not fail when the trust evidence of a package is downgraded b
project.has('@pnpm/e2e.test-provenance')
})
test('install does not fail when the trust evidence of a package is downgraded but it is in trust-policy-exclude', async () => {
skipIfPacquet('install does not fail when the trust evidence of a package is downgraded but it is in trust-policy-exclude', async () => {
const project = prepare()
const result = execPnpmSync([
'add',
@@ -609,7 +608,7 @@ test('install does not fail when the trust evidence of a package is downgraded b
project.has('@pnpm/e2e.test-provenance')
})
test('install does not fail when the trust evidence of a package is downgraded but the package name is in trust-policy-exclude', async () => {
skipIfPacquet('install does not fail when the trust evidence of a package is downgraded but the package name is in trust-policy-exclude', async () => {
const project = prepare()
const result = execPnpmSync([
'add',
@@ -621,7 +620,7 @@ test('install does not fail when the trust evidence of a package is downgraded b
project.has('@pnpm/e2e.test-provenance')
})
test('install fails when trust evidence of an optional dependency is downgraded', async () => {
skipIfPacquet('install fails when trust evidence of an optional dependency is downgraded', async () => {
prepare()
const result = execPnpmSync([
'add',
@@ -632,7 +631,7 @@ test('install fails when trust evidence of an optional dependency is downgraded'
expect(result.status).toBe(1)
})
test('install does not fail when the trust evidence of a package is downgraded but the trust-policy-ignore-after is set', async () => {
skipIfPacquet('install does not fail when the trust evidence of a package is downgraded but the trust-policy-ignore-after is set', async () => {
const project = prepare()
const result = execPnpmSync([
'add',
@@ -644,7 +643,7 @@ test('install does not fail when the trust evidence of a package is downgraded b
project.has('@pnpm/e2e.test-provenance')
})
test('lockfile verifier rejects a trust-downgraded entry that bypassed resolution', () => {
skipIfPacquet('lockfile verifier rejects a trust-downgraded entry that bypassed resolution', () => {
// Step 1: install with trust policy off. The resolver picks up the
// downgraded version without complaint and writes it to the lockfile.
prepare()
@@ -669,7 +668,7 @@ test('lockfile verifier rejects a trust-downgraded entry that bypassed resolutio
expect(output).toMatch(/@pnpm\/e2e\.test-provenance/)
})
test('lockfile verifier respects trust-policy-exclude on a downgraded lockfile entry', () => {
skipIfPacquet('lockfile verifier respects trust-policy-exclude on a downgraded lockfile entry', () => {
prepare()
execPnpmSync(
['add', '@pnpm/e2e.test-provenance@0.0.5', '--trust-policy=off'],

View File

@@ -1,11 +1,14 @@
import fs from 'node:fs'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { prepare } from '@pnpm/prepare'
import { execPnpm } from '../utils/index.js'
import {
execPnpm,
skipIfPacquet,
} from '../utils/index.js'
test('installing a CLI tool that requires a specific version of Node.js to be installed alongside it', async () => {
skipIfPacquet('installing a CLI tool that requires a specific version of Node.js to be installed alongside it', async () => {
prepare()
fs.writeFileSync('pnpm-workspace.yaml', 'allowBuilds: { "@pnpm.e2e/cli-with-node-engine@1.0.0": true }', 'utf8')

View File

@@ -1,15 +1,18 @@
import path from 'node:path'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { prepare } from '@pnpm/prepare'
import type { PackageManifest } from '@pnpm/types'
import { loadJsonFileSync } from 'load-json-file'
import { execPnpm } from '../utils/index.js'
import {
execPnpm,
skipIfPacquet,
} from '../utils/index.js'
const basicPackageManifest = loadJsonFileSync<PackageManifest>(path.join(import.meta.dirname, '../utils/simple-package.json'))
test('production install (with --production flag)', async () => {
skipIfPacquet('production install (with --production flag)', async () => {
const project = prepare(basicPackageManifest)
await execPnpm(['install', '--production'])
@@ -19,7 +22,7 @@ test('production install (with --production flag)', async () => {
project.has('is-positive')
})
test('install dev dependencies only', async () => {
skipIfPacquet('install dev dependencies only', async () => {
const project = prepare({
dependencies: {
'is-positive': '^1.0.0',

View File

@@ -4,7 +4,11 @@ import { expect, test } from '@jest/globals'
import { prepare } from '@pnpm/prepare'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm, execPnpmSync } from '../utils/index.js'
import {
execPnpm,
execPnpmSync,
skipIfPacquet,
} from '../utils/index.js'
// `pacquet` is fetched from the real npm registry — registry-mock doesn't
// carry it (or its platform-specific binary sub-packages). Pinned to a
@@ -38,7 +42,7 @@ async function prepareWithPacquet (opts: PrepareOpts = {}): Promise<void> {
await execPnpm([PUBLIC_REGISTRY, 'install'])
}
test('pnpm install --frozen-lockfile delegates to pacquet when declared in configDependencies', async () => {
skipIfPacquet('pnpm install --frozen-lockfile delegates to pacquet when declared in configDependencies', async () => {
await prepareWithPacquet({ manifest: { dependencies: { 'is-positive': '3.1.0' } } })
expect(fs.existsSync('node_modules/.pnpm-config/pacquet/bin/pacquet')).toBe(true)
expect(fs.existsSync('node_modules/is-positive/package.json')).toBe(true)
@@ -56,7 +60,7 @@ test('pnpm install --frozen-lockfile delegates to pacquet when declared in confi
expect(fs.existsSync('node_modules/is-positive/package.json')).toBe(true)
}, TIMEOUT)
test('bare `pnpm install` (no --frozen-lockfile) delegates the materialization to pacquet', async () => {
skipIfPacquet('bare `pnpm install` (no --frozen-lockfile) delegates the materialization to pacquet', async () => {
await prepareWithPacquet({ manifest: { dependencies: { 'is-positive': '3.1.0' } } })
await fs.promises.rm('node_modules', { recursive: true, force: true })

View File

@@ -3,7 +3,7 @@ import http from 'node:http'
import os from 'node:os'
import path from 'node:path'
import { afterAll, beforeAll, expect, test } from '@jest/globals'
import { afterAll, beforeAll, expect } from '@jest/globals'
import { WANTED_LOCKFILE } from '@pnpm/constants'
import { prepare, preparePackages } from '@pnpm/prepare'
import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
@@ -11,7 +11,10 @@ import { loadJsonFileSync } from 'load-json-file'
import { createRegistryServer } from 'pnpm-agent'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm } from '../utils/index.js'
import {
execPnpm,
skipIfPacquet,
} from '../utils/index.js'
const REGISTRY = `http://localhost:${REGISTRY_MOCK_PORT}/`
@@ -73,7 +76,7 @@ afterAll(async () => {
await fs.promises.rm(tmpBaseDir, { recursive: true, force: true })
})
test('pnpm install uses pnpm agent when configured', async () => {
skipIfPacquet('pnpm install uses pnpm agent when configured', async () => {
prepare({
dependencies: {
'is-positive': '1.0.0',
@@ -96,7 +99,7 @@ test('pnpm install uses pnpm agent when configured', async () => {
expect(fs.existsSync('node_modules/is-positive')).toBe(true)
})
test('pnpm add uses pnpm agent when configured', async () => {
skipIfPacquet('pnpm add uses pnpm agent when configured', async () => {
prepare({
dependencies: {
'is-negative': '1.0.0',
@@ -122,7 +125,7 @@ test('pnpm add uses pnpm agent when configured', async () => {
expect(manifest.dependencies?.['is-negative']).toBe('1.0.0')
})
test('pnpm remove uses pnpm agent when configured', async () => {
skipIfPacquet('pnpm remove uses pnpm agent when configured', async () => {
prepare({
dependencies: {
'is-positive': '1.0.0',
@@ -147,7 +150,7 @@ test('pnpm remove uses pnpm agent when configured', async () => {
expect(manifest.dependencies?.['is-negative']).toBeUndefined()
})
test('pnpm add without a version uses the pnpm agent and writes the save-prefix spec from the lockfile', async () => {
skipIfPacquet('pnpm add without a version uses the pnpm agent and writes the save-prefix spec from the lockfile', async () => {
prepare({})
requestCount = 0
@@ -166,7 +169,7 @@ test('pnpm add without a version uses the pnpm agent and writes the save-prefix
expect(manifest.dependencies?.['is-positive']).toMatch(/^\^\d+\.\d+\.\d+$/)
})
test('pnpm add -D uses pnpm agent and targets devDependencies', async () => {
skipIfPacquet('pnpm add -D uses pnpm agent and targets devDependencies', async () => {
prepare({})
requestCount = 0
@@ -186,7 +189,7 @@ test('pnpm add -D uses pnpm agent and targets devDependencies', async () => {
expect(manifest.dependencies?.['is-positive']).toBeUndefined()
})
test('pnpm add with multiple selectors uses pnpm agent', async () => {
skipIfPacquet('pnpm add with multiple selectors uses pnpm agent', async () => {
prepare({})
requestCount = 0
@@ -204,7 +207,7 @@ test('pnpm add with multiple selectors uses pnpm agent', async () => {
expect(manifest.dependencies?.['is-negative']).toBe('1.0.0')
})
test('pnpm --filter remove inside a workspace uses pnpm agent', async () => {
skipIfPacquet('pnpm --filter remove inside a workspace uses pnpm agent', async () => {
preparePackages([
{
name: 'project-a',
@@ -244,7 +247,7 @@ test('pnpm --filter remove inside a workspace uses pnpm agent', async () => {
expect(projectBManifest.dependencies?.['is-positive']).toBe('1.0.0')
})
test('pnpm add inside a workspace project uses pnpm agent', async () => {
skipIfPacquet('pnpm add inside a workspace project uses pnpm agent', async () => {
preparePackages([
{
name: 'project-a',
@@ -279,7 +282,7 @@ test('pnpm add inside a workspace project uses pnpm agent', async () => {
expect(projectBManifest.dependencies?.['is-negative']).toBe('1.0.0')
})
test('pnpm install with agent works in a workspace with multiple projects', async () => {
skipIfPacquet('pnpm install with agent works in a workspace with multiple projects', async () => {
preparePackages([
{
name: 'project-a',

View File

@@ -1,4 +1,4 @@
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { WANTED_LOCKFILE } from '@pnpm/constants'
import { prepare } from '@pnpm/prepare'
import { rimrafSync } from '@zkochan/rimraf'
@@ -6,9 +6,10 @@ import { rimrafSync } from '@zkochan/rimraf'
import {
addDistTag,
execPnpm,
skipIfPacquet,
} from '../utils/index.js'
test('when prefer offline is used, meta from store is used, where latest might be out-of-date', async () => {
skipIfPacquet('when prefer offline is used, meta from store is used, where latest might be out-of-date', async () => {
const project = prepare()
await addDistTag('@pnpm.e2e/foo', '100.0.0', 'latest')

View File

@@ -1,13 +1,16 @@
import fs from 'node:fs'
import path from 'node:path'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { prepare } from '@pnpm/prepare'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm } from '../utils/index.js'
import {
execPnpm,
skipIfPacquet,
} from '../utils/index.js'
test('runtimeOnFail=download causes Node.js to be downloaded even when the manifest does not set onFail', async () => {
skipIfPacquet('runtimeOnFail=download causes Node.js to be downloaded even when the manifest does not set onFail', async () => {
const project = prepare({
devEngines: {
runtime: {
@@ -30,7 +33,7 @@ test('runtimeOnFail=download causes Node.js to be downloaded even when the manif
})
})
test('runtimeOnFail=ignore prevents Node.js download even when manifest sets onFail=download', async () => {
skipIfPacquet('runtimeOnFail=ignore prevents Node.js download even when manifest sets onFail=download', async () => {
const project = prepare({
devEngines: {
runtime: {
@@ -48,7 +51,7 @@ test('runtimeOnFail=ignore prevents Node.js download even when manifest sets onF
expect(lockfile.importers['.'].devDependencies).toBeUndefined()
})
test('--no-runtime keeps the runtime entry in the lockfile but skips installing the binary', async () => {
skipIfPacquet('--no-runtime keeps the runtime entry in the lockfile but skips installing the binary', async () => {
const project = prepare({
devEngines: {
runtime: {
@@ -76,7 +79,7 @@ test('--no-runtime keeps the runtime entry in the lockfile but skips installing
expectNoNodeBin()
})
test('--no-runtime works on a fresh checkout with no lockfile (non-frozen path)', async () => {
skipIfPacquet('--no-runtime works on a fresh checkout with no lockfile (non-frozen path)', async () => {
const project = prepare({
devEngines: {
runtime: {
@@ -96,7 +99,7 @@ test('--no-runtime works on a fresh checkout with no lockfile (non-frozen path)'
expectNoNodeBin()
})
test('--no-runtime works with enableGlobalVirtualStore=true', async () => {
skipIfPacquet('--no-runtime works with enableGlobalVirtualStore=true', async () => {
const project = prepare({
devEngines: {
runtime: {

View File

@@ -1,15 +1,19 @@
import fs from 'node:fs'
import path from 'node:path'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { prepare } from '@pnpm/prepare'
import type { ProjectManifest } from '@pnpm/types'
import { loadJsonFileSync } from 'load-json-file'
import PATH_NAME from 'path-name'
import { execPnpm, execPnpmSync } from '../utils/index.js'
import {
execPnpm,
execPnpmSync,
skipIfPacquet,
} from '../utils/index.js'
test('self-update updates the packageManager field in package.json', async () => {
skipIfPacquet('self-update updates the packageManager field in package.json', async () => {
prepare({
packageManager: 'pnpm@9.0.0',
})
@@ -27,7 +31,7 @@ test('self-update updates the packageManager field in package.json', async () =>
expect(loadJsonFileSync<ProjectManifest>('package.json').packageManager).toBe('pnpm@10.0.0')
})
test('version switch reuses pnpm previously installed by self-update', async () => {
skipIfPacquet('version switch reuses pnpm previously installed by self-update', async () => {
prepare({})
const pnpmHome = process.cwd()

View File

@@ -1,13 +1,16 @@
import fs from 'node:fs'
import path from 'node:path'
import { beforeEach, describe, expect, test } from '@jest/globals'
import { beforeEach, describe, expect } from '@jest/globals'
import { prepare } from '@pnpm/prepare'
import type { PackageManifest } from '@pnpm/types'
import { loadJsonFileSync } from 'load-json-file'
import type { ExecPnpmSyncOpts } from '../utils/execPnpm.js'
import { execPnpmSync } from '../utils/index.js'
import {
execPnpmSync,
skipIfPacquet,
} from '../utils/index.js'
const basicPackageManifest = loadJsonFileSync<PackageManifest>(path.join(import.meta.dirname, '../utils/simple-package.json'))
@@ -25,11 +28,11 @@ describe('pnpm install --yes', () => {
env: { CI: 'false' },
}
test('prompts without --yes flag', () => {
skipIfPacquet('prompts without --yes flag', () => {
expect(() => execPnpmSync(['install', '--config.optimistic-repeat-install=false'], execPnpmOpts)).toThrow('Aborted removal of modules directory due to no TTY')
})
test('skips prompt when --yes is passed', () => {
skipIfPacquet('skips prompt when --yes is passed', () => {
expect(() => execPnpmSync(['install', '--yes', '--config.optimistic-repeat-install=false'], execPnpmOpts)).not.toThrow()
})
})

View File

@@ -1,13 +1,17 @@
import fs from 'node:fs'
import path from 'node:path'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { prepare, preparePackages } from '@pnpm/prepare'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm, execPnpmSync } from './utils/index.js'
import {
execPnpm,
execPnpmSync,
skipIfPacquet,
} from './utils/index.js'
test('ls --filter=not-exist --json should prints an empty array (#9672)', async () => {
skipIfPacquet('ls --filter=not-exist --json should prints an empty array (#9672)', async () => {
preparePackages([
{
location: 'packages/foo',
@@ -27,7 +31,7 @@ test('ls --filter=not-exist --json should prints an empty array (#9672)', async
expect(JSON.parse(stdout.toString())).toStrictEqual([])
})
test('ls should load a finder from .pnpmfile.cjs', async () => {
skipIfPacquet('ls should load a finder from .pnpmfile.cjs', async () => {
prepare()
const pnpmfile = `
module.exports = { finders: { hasPeerA } }
@@ -46,7 +50,7 @@ function hasPeerA (context) {
expect(result.stdout.toString()).toMatch('@pnpm.e2e/peer-a@^1.0.0')
})
test('pnpm list returns correct paths with global virtual store', async () => {
skipIfPacquet('pnpm list returns correct paths with global virtual store', async () => {
prepare({
dependencies: {
'@pnpm.e2e/pkg-with-1-dep': '100.0.0',

View File

@@ -1,6 +1,6 @@
import path from 'node:path'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { WANTED_LOCKFILE } from '@pnpm/constants'
import { createPeerDepGraphHash } from '@pnpm/deps.path'
import type { LockfileFile } from '@pnpm/lockfile.types'
@@ -10,9 +10,12 @@ import { loadJsonFileSync } from 'load-json-file'
import { readYamlFileSync } from 'read-yaml-file'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm } from '../utils/index.js'
import {
execPnpm,
skipIfPacquet,
} from '../utils/index.js'
test('deduplicate packages that have peers, when adding new dependency in a workspace', async () => {
skipIfPacquet('deduplicate packages that have peers, when adding new dependency in a workspace', async () => {
await addDistTag({ package: '@pnpm.e2e/abc-parent-with-ab', version: '1.0.0', distTag: 'latest' })
await addDistTag({ package: '@pnpm.e2e/peer-a', version: '1.0.0', distTag: 'latest' })
await addDistTag({ package: '@pnpm.e2e/peer-b', version: '1.0.0', distTag: 'latest' })
@@ -52,7 +55,7 @@ test('deduplicate packages that have peers, when adding new dependency in a work
expect(depPaths).toContain(`@pnpm.e2e/abc-parent-with-ab@1.0.0${createPeerDepGraphHash([{ name: '@pnpm.e2e/peer-c', version: '1.0.0' }])}`)
})
test('partial update in a workspace should work with dedupe-peer-dependents is true', async () => {
skipIfPacquet('partial update in a workspace should work with dedupe-peer-dependents is true', async () => {
await addDistTag({ package: '@pnpm.e2e/abc-parent-with-ab', version: '1.0.0', distTag: 'latest' })
await addDistTag({ package: '@pnpm.e2e/abc', version: '1.0.0', distTag: 'latest' })
await addDistTag({ package: '@pnpm.e2e/peer-a', version: '1.0.0', distTag: 'latest' })
@@ -98,7 +101,7 @@ test('partial update in a workspace should work with dedupe-peer-dependents is t
})
// Covers https://github.com/pnpm/pnpm/issues/8877
test('partial update --latest in a workspace should not affect other packages when dedupe-peer-dependents is true', async () => {
skipIfPacquet('partial update --latest in a workspace should not affect other packages when dedupe-peer-dependents is true', async () => {
await addDistTag({ package: '@pnpm.e2e/foo', version: '1.0.0', distTag: 'latest' })
await addDistTag({ package: '@pnpm.e2e/bar', version: '100.0.0', distTag: 'latest' })
@@ -156,7 +159,7 @@ test('partial update --latest in a workspace should not affect other packages wh
})
// Covers https://github.com/pnpm/pnpm/issues/6154
test('peer dependents deduplication should not remove peer dependencies', async () => {
skipIfPacquet('peer dependents deduplication should not remove peer dependencies', async () => {
await addDistTag({ package: '@pnpm.e2e/peer-a', version: '1.0.0', distTag: 'latest' })
await addDistTag({ package: '@pnpm.e2e/peer-b', version: '1.0.0', distTag: 'latest' })
await addDistTag({ package: '@pnpm.e2e/peer-c', version: '1.0.0', distTag: 'latest' })

View File

@@ -26,9 +26,13 @@ import { symlinkDir } from 'symlink-dir'
import { temporaryDirectory } from 'tempy'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm, execPnpmSync } from '../utils/index.js'
import {
execPnpm,
execPnpmSync,
skipIfPacquet,
} from '../utils/index.js'
test('no projects matched the filters', async () => {
skipIfPacquet('no projects matched the filters', async () => {
preparePackages([
{
name: 'project',
@@ -53,7 +57,7 @@ test('no projects matched the filters', async () => {
}
})
test('no projects found', async () => {
skipIfPacquet('no projects found', async () => {
prepareEmpty()
{
@@ -66,7 +70,7 @@ test('no projects found', async () => {
}
})
test('empty pnpm-workspace.yaml should not break pnpm run -r', async () => {
skipIfPacquet('empty pnpm-workspace.yaml should not break pnpm run -r', async () => {
prepare({
name: 'project',
version: '1.0.0',
@@ -109,7 +113,7 @@ invalidWorkspaceManifests.forEach((filename) => {
})
})
test('linking a package inside a monorepo with --link-workspace-packages when installing new dependencies', async () => {
skipIfPacquet('linking a package inside a monorepo with --link-workspace-packages when installing new dependencies', async () => {
const projects = preparePackages([
{
name: 'project-1',
@@ -153,7 +157,7 @@ test('linking a package inside a monorepo with --link-workspace-packages when in
projects['project-1'].has('project-4')
})
test('linking a package inside a monorepo with --link-workspace-packages when installing new dependencies and save-workspace-protocol is "rolling"', async () => {
skipIfPacquet('linking a package inside a monorepo with --link-workspace-packages when installing new dependencies and save-workspace-protocol is "rolling"', async () => {
const projects = preparePackages([
{
name: 'project-1',
@@ -198,7 +202,7 @@ test('linking a package inside a monorepo with --link-workspace-packages when in
projects['project-1'].has('project-4')
})
test('linking a package inside a monorepo with --link-workspace-packages', async () => {
skipIfPacquet('linking a package inside a monorepo with --link-workspace-packages', async () => {
await using server = await createTestIpcServer()
const projects = preparePackages([
@@ -281,7 +285,7 @@ test('linking a package inside a monorepo with --link-workspace-packages', async
}
})
test('topological order of packages with self-dependencies in monorepo is correct', async () => {
skipIfPacquet('topological order of packages with self-dependencies in monorepo is correct', async () => {
await using server1 = await createTestIpcServer()
await using server2 = await createTestIpcServer()
@@ -333,7 +337,7 @@ test('topological order of packages with self-dependencies in monorepo is correc
expect(server2.getLines()).toStrictEqual(['project-2', 'project-3', 'project-1'])
})
test('testPattern is respected by the test script', async () => {
skipIfPacquet('testPattern is respected by the test script', async () => {
await using server = await createTestIpcServer()
const remote = temporaryDirectory()
@@ -401,7 +405,7 @@ test('testPattern is respected by the test script', async () => {
expect(server.getLines().sort()).toEqual(['project-2', 'project-4'])
})
test('changedFilesIgnorePattern is respected', async () => {
skipIfPacquet('changedFilesIgnorePattern is respected', async () => {
const remote = temporaryDirectory()
preparePackages([
@@ -509,7 +513,7 @@ test('changedFilesIgnorePattern is respected', async () => {
])
})
test('do not get confused by filtered dependencies when searching for dependents in monorepo', async () => {
skipIfPacquet('do not get confused by filtered dependencies when searching for dependents in monorepo', async () => {
/*
In this test case, we are filtering for 'project-2' and its dependents with
two projects in the dependency hierarchy, that can be ignored for this query,
@@ -569,7 +573,7 @@ test('do not get confused by filtered dependencies when searching for dependents
expect(project2Output < project4Output).toBeTruthy()
})
test('installation with --link-workspace-packages links packages even if they were previously installed from registry', async () => {
skipIfPacquet('installation with --link-workspace-packages links packages even if they were previously installed from registry', async () => {
const projects = preparePackages([
{
name: 'project',
@@ -607,7 +611,7 @@ test('installation with --link-workspace-packages links packages even if they we
}
})
test('shared-workspace-lockfile: installation with --link-workspace-packages links packages even if they were previously installed from registry', async () => {
skipIfPacquet('shared-workspace-lockfile: installation with --link-workspace-packages links packages even if they were previously installed from registry', async () => {
const projects = preparePackages([
{
name: 'project',
@@ -661,7 +665,7 @@ test('shared-workspace-lockfile: installation with --link-workspace-packages lin
}
})
test('recursive install with link-workspace-packages and shared-workspace-lockfile', async () => {
skipIfPacquet('recursive install with link-workspace-packages and shared-workspace-lockfile', async () => {
await using server = await createTestIpcServer()
await addDistTag({ package: '@pnpm.e2e/pkg-with-1-dep', version: '100.0.0', distTag: 'latest' })
const projects = preparePackages([
@@ -731,7 +735,7 @@ test('recursive install with link-workspace-packages and shared-workspace-lockfi
}
})
test('recursive install with shared-workspace-lockfile builds workspace projects in correct order', async () => {
skipIfPacquet('recursive install with shared-workspace-lockfile builds workspace projects in correct order', async () => {
await using server1 = await createTestIpcServer()
await using server2 = await createTestIpcServer()
@@ -825,7 +829,7 @@ test('recursive install with shared-workspace-lockfile builds workspace projects
])
})
test('recursive installation with shared-workspace-lockfile and a readPackage hook', async () => {
skipIfPacquet('recursive installation with shared-workspace-lockfile and a readPackage hook', async () => {
const projects = preparePackages([
{
name: 'project-1',
@@ -866,7 +870,7 @@ test('recursive installation with shared-workspace-lockfile and a readPackage ho
projects['project-1'].hasNot('project-1')
})
test('local packages should be preferred when running "pnpm install" inside a workspace', async () => {
skipIfPacquet('local packages should be preferred when running "pnpm install" inside a workspace', async () => {
const projects = preparePackages([
{
name: 'project-1',
@@ -898,7 +902,7 @@ test('local packages should be preferred when running "pnpm install" inside a wo
})
// covers https://github.com/pnpm/pnpm/issues/1437
test('shared-workspace-lockfile: create shared lockfile format when installation is inside workspace', async () => {
skipIfPacquet('shared-workspace-lockfile: create shared lockfile format when installation is inside workspace', async () => {
prepare({
dependencies: {
'is-positive': '1.0.0',
@@ -919,7 +923,7 @@ test('shared-workspace-lockfile: create shared lockfile format when installation
})
// covers https://github.com/pnpm/pnpm/issues/1451
test("shared-workspace-lockfile: don't install dependencies in projects that are outside of the current workspace", async () => {
skipIfPacquet("shared-workspace-lockfile: don't install dependencies in projects that are outside of the current workspace", async () => {
preparePackages([
{
location: 'workspace-1/package-1',
@@ -993,7 +997,7 @@ test("shared-workspace-lockfile: don't install dependencies in projects that are
})
})
test('shared-workspace-lockfile: install dependencies in projects that are relative to the workspace directory', async () => {
skipIfPacquet('shared-workspace-lockfile: install dependencies in projects that are relative to the workspace directory', async () => {
preparePackages([
{
location: 'monorepo/workspace',
@@ -1105,7 +1109,7 @@ test('shared-workspace-lockfile: install dependencies in projects that are relat
})
})
test('shared-workspace-lockfile: entries of removed projects should be removed from shared lockfile', async () => {
skipIfPacquet('shared-workspace-lockfile: entries of removed projects should be removed from shared lockfile', async () => {
preparePackages([
{
name: 'package-1',
@@ -1159,7 +1163,7 @@ test('shared-workspace-lockfile config is ignored if no pnpm-workspace.yaml is f
project.has('is-positive')
})
test('shared-workspace-lockfile: removing a package recursively', async () => {
skipIfPacquet('shared-workspace-lockfile: removing a package recursively', async () => {
preparePackages([
{
name: 'project1',
@@ -1212,7 +1216,7 @@ test('shared-workspace-lockfile: removing a package recursively', async () => {
})
// Covers https://github.com/pnpm/pnpm/issues/1506
test('peer dependency is grouped with dependent when the peer is a top dependency and external node_modules is used', async () => {
skipIfPacquet('peer dependency is grouped with dependent when the peer is a top dependency and external node_modules is used', async () => {
preparePackages([
{
name: 'foo',
@@ -1278,7 +1282,7 @@ test('peer dependency is grouped with dependent when the peer is a top dependenc
}
})
test('dependencies of workspace projects are built during headless installation', async () => {
skipIfPacquet('dependencies of workspace projects are built during headless installation', async () => {
const projects = preparePackages([
{
location: '.',
@@ -1314,7 +1318,7 @@ test('dependencies of workspace projects are built during headless installation'
}
})
test("linking the package's bin to another workspace package in a monorepo", async () => {
skipIfPacquet("linking the package's bin to another workspace package in a monorepo", async () => {
const projects = preparePackages([
{
name: 'hello',
@@ -1349,7 +1353,7 @@ test("linking the package's bin to another workspace package in a monorepo", asy
projects.main.isExecutable('.bin/hello')
})
test('pnpm sees the bins from the root of the workspace', async () => {
skipIfPacquet('pnpm sees the bins from the root of the workspace', async () => {
preparePackages([
{
location: '.',
@@ -1464,7 +1468,7 @@ test("root package can't be ignored using '!.' (or any other such glob)", async
})).toBeTruthy() // root project is present even when explicitly ignored
})
test('custom virtual store directory in a workspace with not shared lockfile', async () => {
skipIfPacquet('custom virtual store directory in a workspace with not shared lockfile', async () => {
const projects = preparePackages([
{
name: 'project-1',
@@ -1511,7 +1515,7 @@ test('custom virtual store directory in a workspace with not shared lockfile', a
}
})
test('custom virtual store directory in a workspace with shared lockfile', async () => {
skipIfPacquet('custom virtual store directory in a workspace with shared lockfile', async () => {
preparePackages([
{
name: 'project-1',
@@ -1547,7 +1551,7 @@ test('custom virtual store directory in a workspace with shared lockfile', async
}
})
test('pnpm run should ignore the root project', async () => {
skipIfPacquet('pnpm run should ignore the root project', async () => {
preparePackages([
{
location: '.',
@@ -1573,7 +1577,7 @@ test('pnpm run should ignore the root project', async () => {
expect(fs.existsSync('project/test')).toBeTruthy()
})
test('pnpm run should include the workspace root when --workspace-root option is used', async () => {
skipIfPacquet('pnpm run should include the workspace root when --workspace-root option is used', async () => {
preparePackages([
{
location: '.',
@@ -1600,7 +1604,7 @@ test('pnpm run should include the workspace root when --workspace-root option is
expect(fs.existsSync('project/test')).toBeTruthy()
})
test('pnpm run should include the workspace root when include-workspace-root is set to true', async () => {
skipIfPacquet('pnpm run should include the workspace root when include-workspace-root is set to true', async () => {
preparePackages([
{
location: '.',
@@ -1630,7 +1634,7 @@ test('pnpm run should include the workspace root when include-workspace-root is
expect(fs.existsSync('project/test')).toBeTruthy()
})
test('legacy directory filtering', async () => {
skipIfPacquet('legacy directory filtering', async () => {
preparePackages([
{
location: 'packages/project-1',
@@ -1659,7 +1663,7 @@ test('legacy directory filtering', async () => {
expect(output).toContain('project-2')
})
test('directory filtering', async () => {
skipIfPacquet('directory filtering', async () => {
preparePackages([
{
location: 'packages/project-1',
@@ -1691,7 +1695,7 @@ test('directory filtering', async () => {
}
})
test('run --stream should prefix with dir name', async () => {
skipIfPacquet('run --stream should prefix with dir name', async () => {
preparePackages([
{
location: '.',
@@ -1773,7 +1777,7 @@ packages/alfa test: OK`
)
})
test('run --reporter-hide-prefix should hide prefix', async () => {
skipIfPacquet('run --reporter-hide-prefix should hide prefix', async () => {
preparePackages([
{
location: '.',
@@ -1858,7 +1862,7 @@ packages/alfa test: Done`
)
})
test('peer dependencies are resolved from the root of the workspace when a new dependency is added to a workspace project', async () => {
skipIfPacquet('peer dependencies are resolved from the root of the workspace when a new dependency is added to a workspace project', async () => {
const projects = preparePackages([
{
location: '.',
@@ -1887,7 +1891,7 @@ test('peer dependencies are resolved from the root of the workspace when a new d
expect(lockfile.snapshots).toHaveProperty(['ajv-keywords@1.5.0(ajv@4.10.4)'])
})
test('overrides in workspace project should be taken into account when shared-workspace-lockfiles is false', async () => {
skipIfPacquet('overrides in workspace project should be taken into account when shared-workspace-lockfiles is false', async () => {
const projects = preparePackages([
{
name: 'project-1',
@@ -1919,7 +1923,7 @@ test('overrides in workspace project should be taken into account when shared-wo
})
})
test('deploy should keep files created by lifecycle scripts', async () => {
skipIfPacquet('deploy should keep files created by lifecycle scripts', async () => {
const preparedManifests = {
root: {
name: 'root',
@@ -1970,7 +1974,7 @@ test('deploy should keep files created by lifecycle scripts', async () => {
}
})
test('rebuild in a directory created with "pnpm deploy" should run lifecycle scripts', async () => {
skipIfPacquet('rebuild in a directory created with "pnpm deploy" should run lifecycle scripts', async () => {
const preparedManifests = {
root: {
name: 'root',

View File

@@ -1,14 +1,17 @@
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { WANTED_LOCKFILE } from '@pnpm/constants'
import type { LockfileFile } from '@pnpm/lockfile.types'
import { preparePackages } from '@pnpm/prepare'
import { readYamlFileSync } from 'read-yaml-file'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm } from '../utils/index.js'
import {
execPnpm,
skipIfPacquet,
} from '../utils/index.js'
// Covers https://github.com/pnpm/pnpm/issues/6272
test('peer dependency is not unlinked when adding a new dependency', async () => {
skipIfPacquet('peer dependency is not unlinked when adding a new dependency', async () => {
preparePackages([
{
name: 'project-1',

View File

@@ -2,9 +2,12 @@ import { describe, expect, test } from '@jest/globals'
import { prepare, prepareEmpty } from '@pnpm/prepare'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpmSync } from './utils/index.js'
import {
execPnpmSync,
skipIfPacquet,
} from './utils/index.js'
test('install should fail if the used pnpm version does not satisfy the pnpm version specified in engines', async () => {
skipIfPacquet('install should fail if the used pnpm version does not satisfy the pnpm version specified in engines', async () => {
prepare({
name: 'project',
version: '1.0.0',
@@ -20,7 +23,7 @@ test('install should fail if the used pnpm version does not satisfy the pnpm ver
expect(stdout.toString()).toContain('Your pnpm version is incompatible with')
})
test('install should not fail if the used pnpm version does not satisfy the pnpm version specified in packageManager', async () => {
skipIfPacquet('install should not fail if the used pnpm version does not satisfy the pnpm version specified in packageManager', async () => {
prepare({
name: 'project',
version: '1.0.0',
@@ -36,7 +39,7 @@ test('install should not fail if the used pnpm version does not satisfy the pnpm
expect(stderr.toString()).toContain('This project is configured to use 0.0.0 of pnpm. Your current pnpm is')
})
test('install should fail if the project requires a different package manager', async () => {
skipIfPacquet('install should fail if the project requires a different package manager', async () => {
prepare({
name: 'project',
version: '1.0.0',
@@ -91,7 +94,7 @@ test('some commands should not fail if the required package manager is not pnpm'
expect(status).toBe(0)
})
test('devEngines.packageManager with onFail=error should fail on version mismatch', async () => {
skipIfPacquet('devEngines.packageManager with onFail=error should fail on version mismatch', async () => {
prepare({
devEngines: {
packageManager: {
@@ -108,7 +111,7 @@ test('devEngines.packageManager with onFail=error should fail on version mismatc
expect(stderr.toString()).toContain('This project is configured to use 0.0.1 of pnpm')
})
test('devEngines.packageManager with onFail=warn should warn on version mismatch', async () => {
skipIfPacquet('devEngines.packageManager with onFail=warn should warn on version mismatch', async () => {
prepare({
devEngines: {
packageManager: {
@@ -143,7 +146,7 @@ test('devEngines.packageManager with onFail=ignore should not check version', as
expect(stderr.toString()).not.toContain('0.0.1')
})
test('devEngines.packageManager defaults to onFail=download (#11676)', async () => {
skipIfPacquet('devEngines.packageManager defaults to onFail=download (#11676)', async () => {
prepare({
devEngines: {
packageManager: {
@@ -168,7 +171,7 @@ test('devEngines.packageManager defaults to onFail=download (#11676)', async ()
expect(stderr.toString()).toContain('does not switch versions when running under corepack')
})
test('devEngines.packageManager with a different PM name should fail with onFail=error', async () => {
skipIfPacquet('devEngines.packageManager with a different PM name should fail with onFail=error', async () => {
prepare({
devEngines: {
packageManager: {
@@ -185,7 +188,7 @@ test('devEngines.packageManager with a different PM name should fail with onFail
expect(stderr.toString()).toContain('This project is configured to use yarn')
})
test('devEngines.packageManager array selects the pnpm entry', async () => {
skipIfPacquet('devEngines.packageManager array selects the pnpm entry', async () => {
prepare({
devEngines: {
packageManager: [
@@ -219,7 +222,7 @@ test('devEngines.packageManager array defaults onFail to ignore for non-last ele
expect(status).toBe(0)
})
test('devEngines.packageManager takes precedence over packageManager field', async () => {
skipIfPacquet('devEngines.packageManager takes precedence over packageManager field', async () => {
const versionProcess = execPnpmSync(['--version'])
const pnpmVersion = versionProcess.stdout.toString().trim()
prepare({
@@ -258,7 +261,7 @@ test('no warning when packageManager and devEngines.packageManager specify the s
expect(stderr.toString()).not.toContain('Cannot use both')
})
test('warns when packageManager specifies a different package manager from devEngines.packageManager', async () => {
skipIfPacquet('warns when packageManager specifies a different package manager from devEngines.packageManager', async () => {
prepare({
packageManager: 'yarn@1.2.3',
devEngines: {
@@ -275,7 +278,7 @@ test('warns when packageManager specifies a different package manager from devEn
expect(stderr.toString()).toContain('Cannot use both "packageManager" and "devEngines.packageManager"')
})
test('warns when packageManager version does not match the devEngines.packageManager version string exactly', async () => {
skipIfPacquet('warns when packageManager version does not match the devEngines.packageManager version string exactly', async () => {
prepare({
packageManager: 'pnpm@1.2.3',
devEngines: {
@@ -311,7 +314,7 @@ test('pmOnFail=ignore via env var bypasses the devEngines.packageManager check',
expect(stderr.toString()).not.toContain('0.0.1')
})
test('pmOnFail via --pm-on-fail CLI flag bypasses the devEngines.packageManager check', async () => {
skipIfPacquet('pmOnFail via --pm-on-fail CLI flag bypasses the devEngines.packageManager check', async () => {
prepare({
devEngines: {
packageManager: {
@@ -326,7 +329,7 @@ test('pmOnFail via --pm-on-fail CLI flag bypasses the devEngines.packageManager
expect(execPnpmSync(['install', '--config.pm-on-fail=ignore']).status).toBe(0)
})
test('devEngines.packageManager check runs even when pnpm is invoked via corepack', async () => {
skipIfPacquet('devEngines.packageManager check runs even when pnpm is invoked via corepack', async () => {
prepare({
devEngines: {
packageManager: {
@@ -353,7 +356,7 @@ test('devEngines.packageManager check runs even when pnpm is invoked via corepac
expect(stdout.toString()).toContain('Corepack invoked pnpm')
})
test('devEngines.packageManager onFail=download surfaces a regular error under corepack instead of switching versions', async () => {
skipIfPacquet('devEngines.packageManager onFail=download surfaces a regular error under corepack instead of switching versions', async () => {
prepare({
devEngines: {
packageManager: {
@@ -406,7 +409,7 @@ test('pmOnFail=ignore set in pnpm-workspace.yaml bypasses the devEngines.package
// silently disappeared whenever it was combined with `--version` or
// `--help` — leaving users with no way to opt out of the strict
// packageManager check just to read help or check the running version.
test.each([
skipIfPacquet.each([
[['--pm-on-fail=ignore', '--version']],
[['--version', '--pm-on-fail=ignore']],
[['audit', '--pm-on-fail=ignore', '--help']],

View File

@@ -1,13 +1,16 @@
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { preparePackages } from '@pnpm/prepare'
import { fixtures } from '@pnpm/test-fixtures'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpmSync } from '../utils/index.js'
import {
execPnpmSync,
skipIfPacquet,
} from '../utils/index.js'
const f = fixtures(import.meta.dirname)
test('allowUnusedPatches=false errors on unused patches', async () => {
skipIfPacquet('allowUnusedPatches=false errors on unused patches', async () => {
preparePackages([
{
name: 'foo',
@@ -38,7 +41,7 @@ test('allowUnusedPatches=false errors on unused patches', async () => {
expect(stdout.toString()).toContain('The following patches were not used: is-positive')
})
test('allowUnusedPatches=true warns about unused patches', async () => {
skipIfPacquet('allowUnusedPatches=true warns about unused patches', async () => {
preparePackages([
{
name: 'foo',

View File

@@ -1,11 +1,14 @@
import fs from 'node:fs'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { prepare, preparePackages } from '@pnpm/prepare'
import { execPnpmSync } from '../utils/index.js'
import {
execPnpmSync,
skipIfPacquet,
} from '../utils/index.js'
test('pnpm --filter <root> add <pkg> should work', async () => {
skipIfPacquet('pnpm --filter <root> add <pkg> should work', async () => {
prepare({
name: 'root',
version: '1.0.0',
@@ -24,7 +27,7 @@ test('pnpm --filter <root> add <pkg> should work', async () => {
expect(pkg.dependencies['is-positive']).toBeTruthy()
})
test('pnpm --filter . add <pkg> should work', async () => {
skipIfPacquet('pnpm --filter . add <pkg> should work', async () => {
prepare({
name: 'root',
version: '1.0.0',
@@ -44,7 +47,7 @@ test('pnpm --filter . add <pkg> should work', async () => {
})
// Regression test for https://github.com/pnpm/pnpm/issues/11341
test('pnpm --recursive --filter "!<pkg>" run should still exclude the workspace root', async () => {
skipIfPacquet('pnpm --recursive --filter "!<pkg>" run should still exclude the workspace root', async () => {
preparePackages([
{
location: '.',
@@ -100,7 +103,7 @@ test('pnpm --recursive --filter "!<pkg>" run should still exclude the workspace
expect(stdout).not.toContain('a which$')
})
test('pnpm --recursive --filter "!<pkg>" --include-workspace-root run should include the workspace root', async () => {
skipIfPacquet('pnpm --recursive --filter "!<pkg>" --include-workspace-root run should include the workspace root', async () => {
preparePackages([
{
location: '.',

View File

@@ -14,9 +14,10 @@ import { writeYamlFileSync } from 'write-yaml-file'
import {
execPnpm,
execPnpmSync,
skipIfPacquet,
} from '../utils/index.js'
test('recursive installation with packageConfigs', async () => {
skipIfPacquet('recursive installation with packageConfigs', async () => {
const projects = preparePackages([
{
name: 'project-1',
@@ -56,7 +57,7 @@ test('recursive installation with packageConfigs', async () => {
expect(modulesYaml2?.hoistPattern).toBeFalsy()
})
test('workspace packageConfigs is always read', async () => {
skipIfPacquet('workspace packageConfigs is always read', async () => {
const projects = preparePackages([
{
location: 'workspace/project-1',
@@ -111,7 +112,7 @@ test('workspace packageConfigs is always read', async () => {
expect(modulesYaml2?.hoistPattern).toBeFalsy()
})
test('recursive installation of packages with hooks', async () => {
skipIfPacquet('recursive installation of packages with hooks', async () => {
// This test hangs on Appveyor for some reason
if (isCI && isWindows()) return
const projects = preparePackages([
@@ -158,7 +159,7 @@ test('recursive installation of packages with hooks', async () => {
expect(lockfile2.packages).toHaveProperty(['@pnpm.e2e/dep-of-pkg-with-1-dep@100.1.0'])
})
test('recursive installation of packages in workspace ignores hooks in packages', async () => {
skipIfPacquet('recursive installation of packages in workspace ignores hooks in packages', async () => {
// This test hangs on Appveyor for some reason
if (isCI && isWindows()) return
preparePackages([
@@ -209,7 +210,7 @@ test('recursive installation of packages in workspace ignores hooks in packages'
expect(depPaths).toContain('is-number@1.0.0')
})
test('ignores .pnpmfile.cjs during recursive installation when --ignore-pnpmfile is used', async () => {
skipIfPacquet('ignores .pnpmfile.cjs during recursive installation when --ignore-pnpmfile is used', async () => {
// This test hangs on Appveyor for some reason
if (isCI && isWindows()) return
const projects = preparePackages([
@@ -256,7 +257,7 @@ test('ignores .pnpmfile.cjs during recursive installation when --ignore-pnpmfile
expect(lockfile2.packages).not.toHaveProperty(['@pnpm.e2e/dep-of-pkg-with-1-dep@100.1.0'])
})
test('recursive command with filter from config', async () => {
skipIfPacquet('recursive command with filter from config', async () => {
const projects = preparePackages([
{
name: 'project-1',
@@ -336,7 +337,7 @@ test('non-recursive install ignores filter from config', async () => {
projects['project-3'].hasNot('minimatch')
})
test('adding new dependency in the root should fail if neither --workspace-root nor --ignore-workspace-root-check are used', async () => {
skipIfPacquet('adding new dependency in the root should fail if neither --workspace-root nor --ignore-workspace-root-check are used', async () => {
const project = preparePackages([
{
location: '.',
@@ -384,7 +385,7 @@ test('adding new dependency in the root should fail if neither --workspace-root
}
})
test('--workspace-packages', async () => {
skipIfPacquet('--workspace-packages', async () => {
const projects = preparePackages([
{
location: 'project-1',
@@ -419,7 +420,7 @@ test('--workspace-packages', async () => {
projects['project-2'].hasNot('is-positive')
})
test('set recursive-install to false in .npmrc would disable recursive install in workspace', async () => {
skipIfPacquet('set recursive-install to false in .npmrc would disable recursive install in workspace', async () => {
const projects = preparePackages([
{
location: 'workspace/project-1',
@@ -459,7 +460,7 @@ test('set recursive-install to false in .npmrc would disable recursive install i
projects['project-2'].hasNot('is-negative')
})
test('set recursive-install to false would install as --filter {.}...', async () => {
skipIfPacquet('set recursive-install to false would install as --filter {.}...', async () => {
const projects = preparePackages([
{
location: 'workspace/project-1',

View File

@@ -1,10 +1,13 @@
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { preparePackages } from '@pnpm/prepare'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm } from '../utils/index.js'
import {
execPnpm,
skipIfPacquet,
} from '../utils/index.js'
test('`pnpm recursive rebuild` specific dependencies', async () => {
skipIfPacquet('`pnpm recursive rebuild` specific dependencies', async () => {
const projects = preparePackages([
{
location: '.',

View File

@@ -1,11 +1,14 @@
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { preparePackages } from '@pnpm/prepare'
import { createTestIpcServer } from '@pnpm/test-ipc-server'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm } from '../utils/index.js'
import {
execPnpm,
skipIfPacquet,
} from '../utils/index.js'
test('pnpm recursive run finds bins from the root of the workspace', async () => {
skipIfPacquet('pnpm recursive run finds bins from the root of the workspace', async () => {
await using serverForBuild = await createTestIpcServer()
await using serverForPostInstall = await createTestIpcServer()
await using serverForTestBinPriority = await createTestIpcServer()

View File

@@ -1,14 +1,17 @@
import fs from 'node:fs'
import path from 'node:path'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { GLOBAL_LAYOUT_VERSION } from '@pnpm/constants'
import { tempDir } from '@pnpm/prepare'
import PATH_NAME from 'path-name'
import { execPnpmSync } from './utils/index.js'
import {
execPnpmSync,
skipIfPacquet,
} from './utils/index.js'
test('pnpm root', async () => {
skipIfPacquet('pnpm root', async () => {
tempDir()
fs.writeFileSync('package.json', '{}', 'utf8')
@@ -19,7 +22,7 @@ test('pnpm root', async () => {
expect(result.stdout.toString()).toBe(path.resolve('node_modules') + '\n')
})
test('pnpm root -g', async () => {
skipIfPacquet('pnpm root -g', async () => {
tempDir()
const global = path.resolve('global')

View File

@@ -1,17 +1,19 @@
import fs from 'node:fs'
import path from 'node:path'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { prepare, preparePackages } from '@pnpm/prepare'
import isWindows from 'is-windows'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm, execPnpmSync } from './utils/index.js'
import {
execPnpm,
execPnpmSync,
skipIfPacquet,
} from './utils/index.js'
const RECORD_ARGS_FILE = 'require(\'fs\').writeFileSync(\'args.json\', JSON.stringify(require(\'./args.json\').concat([process.argv.slice(2)])), \'utf8\')'
const testOnPosix = isWindows() ? test.skip : test
test('run -r: pass the args to the command that is specified in the build script', async () => {
skipIfPacquet('run -r: pass the args to the command that is specified in the build script', async () => {
preparePackages([{
name: 'project',
scripts: {
@@ -33,7 +35,7 @@ test('run -r: pass the args to the command that is specified in the build script
])
})
test('run: pass the args to the command that is specified in the build script', async () => {
skipIfPacquet('run: pass the args to the command that is specified in the build script', async () => {
prepare({
name: 'project',
scripts: {
@@ -58,7 +60,7 @@ test('run: pass the args to the command that is specified in the build script',
// Before pnpm v7, `--` was required to pass flags to a build script. Now all
// arguments after the script name should be passed to the build script, even
// `--`.
test('run: pass all arguments after script name to the build script, even --', async () => {
skipIfPacquet('run: pass all arguments after script name to the build script, even --', async () => {
prepare({
name: 'project',
scripts: {
@@ -80,7 +82,7 @@ test('run: pass all arguments after script name to the build script, even --', a
])
})
test('exit code of child process is preserved', async () => {
skipIfPacquet('exit code of child process is preserved', async () => {
prepare({
scripts: {
foo: 'exit 87',
@@ -90,7 +92,7 @@ test('exit code of child process is preserved', async () => {
expect(result.status).toBe(87)
})
test('recursive test: pass the args to the command that is specified in the build script of a package.json manifest', async () => {
skipIfPacquet('recursive test: pass the args to the command that is specified in the build script of a package.json manifest', async () => {
preparePackages([{
name: 'project',
scripts: {
@@ -105,7 +107,7 @@ test('recursive test: pass the args to the command that is specified in the buil
)
})
test('start: run "node server.js" by default', async () => {
skipIfPacquet('start: run "node server.js" by default', async () => {
prepare({}, { manifestFormat: 'YAML' })
fs.writeFileSync('server.js', 'console.log("Hello world!")', 'utf8')
@@ -115,7 +117,7 @@ test('start: run "node server.js" by default', async () => {
expect((result.stdout as Buffer).toString('utf8')).toMatch(/Hello world!/)
})
test('install-test: install dependencies and runs tests', async () => {
skipIfPacquet('install-test: install dependencies and runs tests', async () => {
prepare({
scripts: {
test: 'node -e "process.stdout.write(\'test\')" > ./output.txt',
@@ -128,7 +130,7 @@ test('install-test: install dependencies and runs tests', async () => {
expect(scriptsRan.trim()).toBe('test')
})
test('silent run only prints the output of the child process', async () => {
skipIfPacquet('silent run only prints the output of the child process', async () => {
prepare({
scripts: {
hi: 'echo hi && exit 1',
@@ -140,7 +142,7 @@ test('silent run only prints the output of the child process', async () => {
expect(result.stdout.toString().trim()).toBe('hi')
})
test('silent run does not print verifyDepsBeforeRun install output', async () => {
skipIfPacquet('silent run does not print verifyDepsBeforeRun install output', async () => {
prepare({
scripts: {
hi: 'echo hi',
@@ -158,7 +160,7 @@ test('silent run does not print verifyDepsBeforeRun install output', async () =>
expect(result.stdout.toString().trim()).toBe('hi')
})
testOnPosix('pnpm run with preferSymlinkedExecutables true', async () => {
skipIfPacquet('pnpm run with preferSymlinkedExecutables true', async () => {
prepare({
scripts: {
build: 'node -e "console.log(process.env.NODE_PATH)"',
@@ -174,7 +176,7 @@ testOnPosix('pnpm run with preferSymlinkedExecutables true', async () => {
expect(result.stdout.toString()).toContain(`project${path.sep}node_modules${path.sep}.pnpm${path.sep}node_modules`)
})
testOnPosix('pnpm run with preferSymlinkedExecutables and custom virtualStoreDir', async () => {
skipIfPacquet('pnpm run with preferSymlinkedExecutables and custom virtualStoreDir', async () => {
prepare({
scripts: {
build: 'node -e "console.log(process.env.NODE_PATH)"',
@@ -191,7 +193,7 @@ testOnPosix('pnpm run with preferSymlinkedExecutables and custom virtualStoreDir
expect(result.stdout.toString()).toContain(`${path.sep}foo${path.sep}bar${path.sep}node_modules`)
})
test('collapse output when running multiple scripts in one project', async () => {
skipIfPacquet('collapse output when running multiple scripts in one project', async () => {
prepare({
scripts: {
script1: 'echo 1',
@@ -221,7 +223,7 @@ test('do not collapse output when running multiple scripts in one project sequen
expect(output).not.toContain('script2: 2')
})
test('--parallel should work with single project', async () => {
skipIfPacquet('--parallel should work with single project', async () => {
prepare({
scripts: {
script1: 'echo 1',
@@ -236,7 +238,7 @@ test('--parallel should work with single project', async () => {
expect(output).toContain('script2: 2')
})
test('--reporter-hide-prefix should hide workspace prefix', async () => {
skipIfPacquet('--reporter-hide-prefix should hide workspace prefix', async () => {
prepare({
scripts: {
script1: 'echo 1',
@@ -253,7 +255,7 @@ test('--reporter-hide-prefix should hide workspace prefix', async () => {
expect(output).not.toContain('script2: 2')
})
test('hidden scripts (starting with .) cannot be run directly', () => {
skipIfPacquet('hidden scripts (starting with .) cannot be run directly', () => {
prepare({
scripts: {
'.build': 'echo hidden',
@@ -267,7 +269,7 @@ test('hidden scripts (starting with .) cannot be run directly', () => {
expect(output).toContain('HIDDEN_SCRIPT')
})
test('hidden scripts can be called from other scripts', () => {
skipIfPacquet('hidden scripts can be called from other scripts', () => {
prepare({
scripts: {
'.build': 'echo hidden-ok',
@@ -280,7 +282,7 @@ test('hidden scripts can be called from other scripts', () => {
expect(result.stdout.toString()).toContain('hidden-ok')
})
test('hidden scripts are not shown in pnpm run listing', () => {
skipIfPacquet('hidden scripts are not shown in pnpm run listing', () => {
prepare({
scripts: {
'.internal': 'echo hidden',
@@ -293,7 +295,7 @@ test('hidden scripts are not shown in pnpm run listing', () => {
expect(result.stdout.toString()).not.toContain('.internal')
})
test('regex selector skips hidden scripts', () => {
skipIfPacquet('regex selector skips hidden scripts', () => {
prepare({
scripts: {
'.build-internal': 'echo hidden',

View File

@@ -1,4 +1,4 @@
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import type { LockfileFile } from '@pnpm/lockfile.types'
import { prepare, preparePackages } from '@pnpm/prepare'
import { addDistTag } from '@pnpm/registry-mock'
@@ -7,9 +7,12 @@ import { loadJsonFileSync } from 'load-json-file'
import { readYamlFileSync } from 'read-yaml-file'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm } from './utils/index.js'
import {
execPnpm,
skipIfPacquet,
} from './utils/index.js'
test('--save-catalog adds catalogs to the manifest of a single package workspace', async () => {
skipIfPacquet('--save-catalog adds catalogs to the manifest of a single package workspace', async () => {
const manifest: ProjectManifest = {
name: 'test-save-catalog',
version: '0.0.0',
@@ -103,7 +106,7 @@ test('--save-catalog adds catalogs to the manifest of a single package workspace
})
})
test('--save-catalog adds catalogs to the manifest of a shared lockfile workspace', async () => {
skipIfPacquet('--save-catalog adds catalogs to the manifest of a shared lockfile workspace', async () => {
const manifests: ProjectManifest[] = [
{
name: 'project-0',
@@ -210,7 +213,7 @@ test('--save-catalog adds catalogs to the manifest of a shared lockfile workspac
})
})
test('--save-catalog adds catalogs to the manifest of a multi-lockfile workspace', async () => {
skipIfPacquet('--save-catalog adds catalogs to the manifest of a multi-lockfile workspace', async () => {
const manifests: ProjectManifest[] = [
{
name: 'project-0',
@@ -330,7 +333,7 @@ test('--save-catalog adds catalogs to the manifest of a multi-lockfile workspace
}
})
test('--save-catalog does not add local workspace dependency as a catalog', async () => {
skipIfPacquet('--save-catalog does not add local workspace dependency as a catalog', async () => {
const manifests: ProjectManifest[] = [
{
name: 'project-0',
@@ -389,7 +392,7 @@ test('--save-catalog does not add local workspace dependency as a catalog', asyn
}
})
test('--save-catalog does not affect new dependencies from package.json', async () => {
skipIfPacquet('--save-catalog does not affect new dependencies from package.json', async () => {
const manifest: ProjectManifest = {
name: 'test-save-catalog',
version: '0.0.0',
@@ -485,7 +488,7 @@ test('--save-catalog does not affect new dependencies from package.json', async
})
})
test('--save-catalog does not overwrite existing catalogs', async () => {
skipIfPacquet('--save-catalog does not overwrite existing catalogs', async () => {
const manifests: ProjectManifest[] = [
{
name: 'project-0',
@@ -590,7 +593,7 @@ test('--save-catalog does not overwrite existing catalogs', async () => {
})
})
test('--save-catalog creates new workspace manifest with the new catalog (recursive add)', async () => {
skipIfPacquet('--save-catalog creates new workspace manifest with the new catalog (recursive add)', async () => {
const manifests: ProjectManifest[] = [
{
name: 'project-0',
@@ -669,7 +672,7 @@ test('--save-catalog creates new workspace manifest with the new catalog (recurs
})
})
test('--save-catalog-name', async () => {
skipIfPacquet('--save-catalog-name', async () => {
const manifest: ProjectManifest = {
name: 'test-save-catalog',
version: '0.0.0',

View File

@@ -1,9 +1,13 @@
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { prepare } from '@pnpm/prepare'
import { execPnpm, execPnpmSync } from './utils/index.js'
import {
execPnpm,
execPnpmSync,
skipIfPacquet,
} from './utils/index.js'
test('pnpm sbom --sbom-format cyclonedx outputs valid JSON to stdout', async () => {
skipIfPacquet('pnpm sbom --sbom-format cyclonedx outputs valid JSON to stdout', async () => {
prepare({
dependencies: {
'is-positive': '3.1.0',
@@ -21,7 +25,7 @@ test('pnpm sbom --sbom-format cyclonedx outputs valid JSON to stdout', async ()
expect(parsed.components.length).toBeGreaterThan(0)
})
test('pnpm sbom --sbom-format spdx outputs valid JSON to stdout', async () => {
skipIfPacquet('pnpm sbom --sbom-format spdx outputs valid JSON to stdout', async () => {
prepare({
dependencies: {
'is-positive': '3.1.0',
@@ -38,7 +42,7 @@ test('pnpm sbom --sbom-format spdx outputs valid JSON to stdout', async () => {
expect(parsed.dataLicense).toBe('CC0-1.0')
})
test('pnpm sbom warnings go to stderr, not stdout', async () => {
skipIfPacquet('pnpm sbom warnings go to stderr, not stdout', async () => {
prepare({
dependencies: {
'is-positive': '3.1.0',

View File

@@ -7,9 +7,12 @@ import isWindows from 'is-windows'
import { writeJsonFileSync } from 'write-json-file'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpmSync } from './utils/index.js'
import {
execPnpmSync,
skipIfPacquet,
} from './utils/index.js'
test('switch to the pnpm version specified in the packageManager field of package.json', async () => {
skipIfPacquet('switch to the pnpm version specified in the packageManager field of package.json', async () => {
prepare()
const pnpmHome = path.resolve('pnpm')
const env = { PNPM_HOME: pnpmHome }
@@ -22,7 +25,7 @@ test('switch to the pnpm version specified in the packageManager field of packag
expect(stdout.toString()).toContain('Version 9.3.0')
})
test('packageManager field does not write pnpm resolution info to pnpm-lock.yaml', async () => {
skipIfPacquet('packageManager field does not write pnpm resolution info to pnpm-lock.yaml', async () => {
prepare()
const pnpmHome = path.resolve('pnpm')
const env = { PNPM_HOME: pnpmHome }
@@ -55,7 +58,7 @@ test('do not switch to the pnpm version specified in the packageManager field of
expect(stdout.toString()).not.toContain('Version 9.3.0')
})
test('do not switch to pnpm version that is specified not with a semver version', async () => {
skipIfPacquet('do not switch to pnpm version that is specified not with a semver version', async () => {
prepare()
const pnpmHome = path.resolve('pnpm')
const env = { PNPM_HOME: pnpmHome }
@@ -68,7 +71,7 @@ test('do not switch to pnpm version that is specified not with a semver version'
expect(stderr.toString()).toContain('"kevva/is-positive" is not a valid exact version')
})
test('do not switch to pnpm version that is specified starting with v', async () => {
skipIfPacquet('do not switch to pnpm version that is specified starting with v', async () => {
prepare()
const pnpmHome = path.resolve('pnpm')
const env = { PNPM_HOME: pnpmHome }
@@ -81,7 +84,7 @@ test('do not switch to pnpm version that is specified starting with v', async ()
expect(stderr.toString()).toContain('you need to specify the version as "9.15.5"')
})
test('do not switch to pnpm version when a range is specified in packageManager field', async () => {
skipIfPacquet('do not switch to pnpm version when a range is specified in packageManager field', async () => {
prepare()
const pnpmHome = path.resolve('pnpm')
const env = { PNPM_HOME: pnpmHome }
@@ -94,7 +97,7 @@ test('do not switch to pnpm version when a range is specified in packageManager
expect(stderr.toString()).toContain('not a valid exact version')
})
test('switch to the pnpm version resolved from devEngines.packageManager with onFail=download', async () => {
skipIfPacquet('switch to the pnpm version resolved from devEngines.packageManager with onFail=download', async () => {
prepare()
const pnpmHome = path.resolve('pnpm')
const env = { PNPM_HOME: pnpmHome }
@@ -113,7 +116,7 @@ test('switch to the pnpm version resolved from devEngines.packageManager with on
expect(stdout.toString()).toContain('Version 9.3.0')
})
test('switch to the pnpm version resolved from devEngines.packageManager with a range', async () => {
skipIfPacquet('switch to the pnpm version resolved from devEngines.packageManager with a range', async () => {
prepare()
const pnpmHome = path.resolve('pnpm')
const env = { PNPM_HOME: pnpmHome }
@@ -133,7 +136,7 @@ test('switch to the pnpm version resolved from devEngines.packageManager with a
expect(stdout.toString()).toContain('Version 9.1.3')
})
test('devEngines.packageManager with onFail=download reuses resolved version from env lockfile', async () => {
skipIfPacquet('devEngines.packageManager with onFail=download reuses resolved version from env lockfile', async () => {
prepare()
const pnpmHome = path.resolve('pnpm')
const env = { PNPM_HOME: pnpmHome }
@@ -159,7 +162,7 @@ test('devEngines.packageManager with onFail=download reuses resolved version fro
expect(fs.existsSync('pnpm-lock.yaml')).toBe(true)
})
test('devEngines.packageManager re-resolves when locked version no longer satisfies updated range', async () => {
skipIfPacquet('devEngines.packageManager re-resolves when locked version no longer satisfies updated range', async () => {
prepare()
const pnpmHome = path.resolve('pnpm')
const env = { PNPM_HOME: pnpmHome }
@@ -194,7 +197,7 @@ test('devEngines.packageManager re-resolves when locked version no longer satisf
expect(secondRun.stdout.toString()).toContain('Version 9.1.3')
})
test('devEngines.packageManager without onFail=download does not switch version', async () => {
skipIfPacquet('devEngines.packageManager without onFail=download does not switch version', async () => {
prepare()
const pnpmHome = path.resolve('pnpm')
const env = { PNPM_HOME: pnpmHome }
@@ -214,7 +217,7 @@ test('devEngines.packageManager without onFail=download does not switch version'
expect(stdout.toString()).not.toContain('Version 9.3.0')
})
test('throws error if pnpm binary in store is corrupt', () => {
skipIfPacquet('throws error if pnpm binary in store is corrupt', () => {
prepare()
const pnpmHome = path.resolve('pnpm')
const storeDir = path.resolve('store')

View File

@@ -1,12 +1,15 @@
import fs from 'node:fs'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { preparePackages } from '@pnpm/prepare'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm } from './utils/index.js'
import {
execPnpm,
skipIfPacquet,
} from './utils/index.js'
test('sync bin links after build script', async () => {
skipIfPacquet('sync bin links after build script', async () => {
preparePackages([
{
name: 'cli-tool',

View File

@@ -1,12 +1,15 @@
import fs from 'node:fs'
import path from 'node:path'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { preparePackages } from '@pnpm/prepare'
import { fixtures } from '@pnpm/test-fixtures'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm } from './utils/index.js'
import {
execPnpm,
skipIfPacquet,
} from './utils/index.js'
const f = fixtures(import.meta.dirname)
@@ -61,7 +64,7 @@ function prepareInjectedDepsWorkspace (syncInjectedDepsAfterScripts: string[]) {
})
}
test('with sync-injected-deps-after-scripts', async () => {
skipIfPacquet('with sync-injected-deps-after-scripts', async () => {
prepareInjectedDepsWorkspace(['build1', 'build2', 'build3'])
await execPnpm(['install'])
@@ -115,7 +118,7 @@ test('with sync-injected-deps-after-scripts', async () => {
}
})
test('without sync-injected-deps-after-scripts', async () => {
skipIfPacquet('without sync-injected-deps-after-scripts', async () => {
prepareInjectedDepsWorkspace([])
await execPnpm(['install'])
@@ -155,7 +158,7 @@ test('without sync-injected-deps-after-scripts', async () => {
}
})
test('filter scripts', async () => {
skipIfPacquet('filter scripts', async () => {
prepareInjectedDepsWorkspace(['build1'])
await execPnpm(['install'])
@@ -205,7 +208,7 @@ test('filter scripts', async () => {
}
})
test('directories and symlinks', async () => {
skipIfPacquet('directories and symlinks', async () => {
prepareInjectedDepsWorkspace(['build1', 'build2', 'build3'])
await execPnpm(['install'])

View File

@@ -1,14 +1,17 @@
import fs from 'node:fs'
import path from 'node:path'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { readPackageJsonFromDir } from '@pnpm/pkg-manifest.reader'
import { prepare } from '@pnpm/prepare'
import PATH from 'path-name'
import { execPnpm } from './utils/index.js'
import {
execPnpm,
skipIfPacquet,
} from './utils/index.js'
test('uninstall package and remove from appropriate property', async () => {
skipIfPacquet('uninstall package and remove from appropriate property', async () => {
const project = prepare()
await execPnpm(['install', '--save-optional', 'is-positive@3.1.0'])
@@ -28,7 +31,7 @@ test('uninstall package and remove from appropriate property', async () => {
expect(pkgJson.optionalDependencies).toBeUndefined()
})
test('uninstall global package with its bin files', async () => {
skipIfPacquet('uninstall global package with its bin files', async () => {
prepare()
const global = process.cwd()

View File

@@ -1,6 +1,6 @@
import path from 'node:path'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { readPackageJsonFromDir } from '@pnpm/pkg-manifest.reader'
import { prepare, preparePackages } from '@pnpm/prepare'
import { readYamlFileSync } from 'read-yaml-file'
@@ -9,9 +9,10 @@ import { writeYamlFileSync } from 'write-yaml-file'
import {
addDistTag,
execPnpm,
skipIfPacquet,
} from './utils/index.js'
test('update <dep>', async () => {
skipIfPacquet('update <dep>', async () => {
const project = prepare()
await addDistTag('@pnpm.e2e/dep-of-pkg-with-1-dep', '101.0.0', 'latest')
@@ -31,7 +32,7 @@ test('update <dep>', async () => {
expect(pkg.dependencies?.['@pnpm.e2e/dep-of-pkg-with-1-dep']).toBe('^101.0.0')
})
test('update --no-save', async () => {
skipIfPacquet('update --no-save', async () => {
await addDistTag('@pnpm.e2e/foo', '100.1.0', 'latest')
const project = prepare({
dependencies: {
@@ -48,7 +49,7 @@ test('update --no-save', async () => {
expect(pkg.dependencies?.['@pnpm.e2e/foo']).toBe('^100.0.0')
})
test('update', async () => {
skipIfPacquet('update', async () => {
await addDistTag('@pnpm.e2e/foo', '100.0.0', 'latest')
const project = prepare({
dependencies: {
@@ -69,7 +70,7 @@ test('update', async () => {
expect(pkg.dependencies?.['@pnpm.e2e/foo']).toBe('^100.1.0')
})
test('recursive update --no-save', async () => {
skipIfPacquet('recursive update --no-save', async () => {
await addDistTag('@pnpm.e2e/foo', '100.1.0', 'latest')
preparePackages([
{
@@ -92,7 +93,7 @@ test('recursive update --no-save', async () => {
expect(pkg.dependencies?.['@pnpm.e2e/foo']).toBe('^100.0.0')
})
test('recursive update', async () => {
skipIfPacquet('recursive update', async () => {
await addDistTag('@pnpm.e2e/foo', '100.1.0', 'latest')
preparePackages([
{
@@ -115,7 +116,7 @@ test('recursive update', async () => {
expect(pkg.dependencies?.['@pnpm.e2e/foo']).toBe('^100.1.0')
})
test('recursive update --no-shared-workspace-lockfile', async function () {
skipIfPacquet('recursive update --no-shared-workspace-lockfile', async function () {
await addDistTag('@pnpm.e2e/foo', '100.1.0', 'latest')
const projects = preparePackages([
{
@@ -140,7 +141,7 @@ test('recursive update --no-shared-workspace-lockfile', async function () {
expect(pkg.dependencies?.['@pnpm.e2e/foo']).toBe('^100.1.0')
})
test('update --latest', async function () {
skipIfPacquet('update --latest', async function () {
const project = prepare()
await Promise.all([
@@ -167,7 +168,7 @@ test('update --latest', async function () {
expect(pkg.dependencies?.['is-negative']).toBe('github:kevva/is-negative')
})
test('update --latest --save-exact', async function () {
skipIfPacquet('update --latest --save-exact', async function () {
const project = prepare()
await Promise.all([
@@ -194,7 +195,7 @@ test('update --latest --save-exact', async function () {
expect(pkg.dependencies?.['is-negative']).toBe('github:kevva/is-negative')
})
test('update --latest specific dependency', async function () {
skipIfPacquet('update --latest specific dependency', async function () {
const project = prepare()
await Promise.all([
@@ -222,7 +223,7 @@ test('update --latest specific dependency', async function () {
expect(pkg.dependencies?.['is-negative']).toBe('github:kevva/is-negative')
})
test('update --latest --prod', async function () {
skipIfPacquet('update --latest --prod', async function () {
const project = prepare()
await Promise.all([
@@ -246,7 +247,7 @@ test('update --latest --prod', async function () {
project.has('@pnpm.e2e/dep-of-pkg-with-1-dep') // not pruned
})
test('recursive update --latest on projects that do not share a lockfile', async () => {
skipIfPacquet('recursive update --latest on projects that do not share a lockfile', async () => {
await Promise.all([
addDistTag('@pnpm.e2e/dep-of-pkg-with-1-dep', '101.0.0', 'latest'),
addDistTag('@pnpm.e2e/bar', '100.1.0', 'latest'),
@@ -299,7 +300,7 @@ test('recursive update --latest on projects that do not share a lockfile', async
expect(lockfile2.importers['.'].dependencies?.['@pnpm.e2e/foo'].version).toBe('100.1.0')
})
test('recursive update --latest --prod on projects that do not share a lockfile', async () => {
skipIfPacquet('recursive update --latest --prod on projects that do not share a lockfile', async () => {
await Promise.all([
addDistTag('@pnpm.e2e/dep-of-pkg-with-1-dep', '101.0.0', 'latest'),
addDistTag('@pnpm.e2e/bar', '100.1.0', 'latest'),
@@ -366,7 +367,7 @@ test('recursive update --latest --prod on projects that do not share a lockfile'
projects['project-2'].has('@pnpm.e2e/foo')
})
test('recursive update --latest specific dependency on projects that do not share a lockfile', async () => {
skipIfPacquet('recursive update --latest specific dependency on projects that do not share a lockfile', async () => {
await Promise.all([
addDistTag('@pnpm.e2e/dep-of-pkg-with-1-dep', '101.0.0', 'latest'),
addDistTag('@pnpm.e2e/bar', '100.1.0', 'latest'),
@@ -423,7 +424,7 @@ test('recursive update --latest specific dependency on projects that do not shar
expect(lockfile2.importers['.'].dependencies?.['@pnpm.e2e/foo'].version).toBe('100.1.0')
})
test('recursive update --latest on projects with a shared a lockfile', async () => {
skipIfPacquet('recursive update --latest on projects with a shared a lockfile', async () => {
await Promise.all([
addDistTag('@pnpm.e2e/dep-of-pkg-with-1-dep', '101.0.0', 'latest'),
addDistTag('@pnpm.e2e/bar', '100.1.0', 'latest'),
@@ -475,7 +476,7 @@ test('recursive update --latest on projects with a shared a lockfile', async ()
expect(lockfile.importers['project-2'].dependencies['@pnpm.e2e/foo'].version).toBe('100.1.0')
})
test('recursive update --latest --prod on projects with a shared a lockfile', async () => {
skipIfPacquet('recursive update --latest --prod on projects with a shared a lockfile', async () => {
await Promise.all([
addDistTag('@pnpm.e2e/dep-of-pkg-with-1-dep', '101.0.0', 'latest'),
addDistTag('@pnpm.e2e/bar', '100.1.0', 'latest'),
@@ -540,7 +541,7 @@ test('recursive update --latest --prod on projects with a shared a lockfile', as
projects['project-2'].has('@pnpm.e2e/bar')
})
test('recursive update --latest specific dependency on projects with a shared a lockfile', async () => {
skipIfPacquet('recursive update --latest specific dependency on projects with a shared a lockfile', async () => {
await Promise.all([
addDistTag('@pnpm.e2e/dep-of-pkg-with-1-dep', '101.0.0', 'latest'),
addDistTag('@pnpm.e2e/bar', '100.1.0', 'latest'),
@@ -596,7 +597,7 @@ test('recursive update --latest specific dependency on projects with a shared a
expect(lockfile.importers['project-2'].dependencies['@pnpm.e2e/foo'].version).toBe('100.1.0')
})
test('deep update', async function () {
skipIfPacquet('deep update', async function () {
const project = prepare()
await addDistTag('@pnpm.e2e/dep-of-pkg-with-1-dep', '100.0.0', 'latest')
@@ -612,7 +613,7 @@ test('deep update', async function () {
project.storeHas('@pnpm.e2e/dep-of-pkg-with-1-dep', '100.1.0')
})
test('update to latest without downgrading already defined prerelease (#7436)', async function () {
skipIfPacquet('update to latest without downgrading already defined prerelease (#7436)', async function () {
prepare()
await addDistTag('@pnpm.e2e/has-prerelease', '2.0.0', 'latest')
@@ -656,7 +657,7 @@ test('update to latest without downgrading already defined prerelease (#7436)',
expect(lockfile3).not.toHaveProperty(['packages', '@pnpm.e2e/has-prerelease@2.0.0'])
})
test('update with tag @latest will downgrade prerelease', async function () {
skipIfPacquet('update with tag @latest will downgrade prerelease', async function () {
prepare()
await addDistTag('@pnpm.e2e/has-prerelease', '2.0.0', 'latest')
@@ -687,7 +688,7 @@ test('update with tag @latest will downgrade prerelease', async function () {
expect(lockfile2).toHaveProperty(['packages', '@pnpm.e2e/has-prerelease@2.0.0'])
})
test('update indirect dependency should not update package.json', async function () {
skipIfPacquet('update indirect dependency should not update package.json', async function () {
const project = prepare({
dependencies: {
'@pnpm.e2e/pkg-with-1-dep': '^100.0.0',
@@ -725,7 +726,7 @@ test('update indirect dependency should not update package.json', async function
expect(lockfile2.importers['.'].dependencies?.['@pnpm.e2e/pkg-with-1-dep'].version).toBe('100.0.0')
})
test('update to latest recursive workspace (outdated, updated, prerelease, outdated)', async function () {
skipIfPacquet('update to latest recursive workspace (outdated, updated, prerelease, outdated)', async function () {
await addDistTag('@pnpm.e2e/has-prerelease', '2.0.0', 'latest')
preparePackages([
@@ -804,7 +805,7 @@ test('update to latest recursive workspace (outdated, updated, prerelease, outda
expect(lockfile2).toHaveProperty(['packages', '@pnpm.e2e/has-prerelease@3.0.0-rc.0'])
})
test('update to latest recursive workspace (prerelease, outdated)', async function () {
skipIfPacquet('update to latest recursive workspace (prerelease, outdated)', async function () {
await addDistTag('@pnpm.e2e/has-prerelease', '2.0.0', 'latest')
preparePackages([

View File

@@ -11,6 +11,21 @@ export const binDir = path.join(import.meta.dirname, '../..', isWindows() ? 'dis
export const pnpmBinLocation = path.join(binDir, 'pnpm.mjs')
export const pnpxBinLocation = path.join(import.meta.dirname, '../../bin/pnpx.mjs')
/**
* When set, execPnpm spawns this binary directly instead of `node pnpm.mjs`.
* Lets the same test suite run against the pacquet Rust port for parity checks.
*/
const pnpmE2eBin = process.env.PNPM_E2E_BIN
export const isPacquetMode = pnpmE2eBin != null && pnpmE2eBin !== ''
function pnpmCommand (args: readonly string[]): { file: string, args: string[] } {
if (isPacquetMode) {
return { file: pnpmE2eBin!, args: [...args] }
}
return { file: process.execPath, args: [pnpmBinLocation, ...args] }
}
// The default timeout for tests is 4 minutes. Set a timeout for execPnpm calls
// for 3 minutes to make it more clear what specific part of a test is timing
// out.
@@ -26,7 +41,8 @@ export async function execPnpm (
}
): Promise<void> {
await new Promise<void>((resolve, reject) => {
const proc = crossSpawn.spawn(process.execPath, [pnpmBinLocation, ...args], {
const cmd = pnpmCommand(args)
const proc = crossSpawn.spawn(cmd.file, cmd.args, {
env: {
...createEnv(opts),
...opts?.env,
@@ -68,7 +84,8 @@ export function spawnPnpm (
storeDir?: string
}
): NodeChildProcess {
return crossSpawn.spawn(process.execPath, [pnpmBinLocation, ...args], {
const cmd = pnpmCommand(args)
return crossSpawn.spawn(cmd.file, cmd.args, {
env: {
...createEnv(opts),
...opts?.env,
@@ -141,7 +158,8 @@ export function execPnpmSync (
args: string[],
opts?: ExecPnpmSyncOpts
): ChildProcess {
const execResult = crossSpawn.sync(process.execPath, [pnpmBinLocation, ...args], {
const cmd = pnpmCommand(args)
const execResult = crossSpawn.sync(cmd.file, cmd.args, {
cwd: opts?.cwd,
env: {
...createEnv({ omitEnvDefaults: opts?.omitEnvDefaults }),

View File

@@ -5,24 +5,29 @@ import {
execPnpmSync,
execPnpx,
execPnpxSync,
isPacquetMode,
pnpmBinLocation,
pnpxBinLocation,
spawnPnpm,
spawnPnpx,
} from './execPnpm.js'
import { pathToLocalPkg } from './localPkg.js'
import { describeSkipIfPacquet, skipIfPacquet } from './skipIfPacquet.js'
import testDefaults from './testDefaults.js'
export {
addDistTag,
binDir,
describeSkipIfPacquet,
execPnpm,
execPnpmSync,
execPnpx,
execPnpxSync,
isPacquetMode,
pathToLocalPkg,
pnpmBinLocation,
pnpxBinLocation,
skipIfPacquet,
spawnPnpm,
spawnPnpx,
testDefaults,

View File

@@ -0,0 +1,13 @@
import { describe, test } from '@jest/globals'
import { isPacquetMode } from './execPnpm.js'
/**
* Use in place of `test()` for cases that fail when the test runs against the
* pacquet Rust port (selected via the `PNPM_E2E_BIN` env var). Pass-through
* when running against the bundled pnpm.
*/
export const skipIfPacquet = isPacquetMode ? test.skip : test
/** describe()-level variant for skipping whole suites that aren't in pacquet's surface yet. */
export const describeSkipIfPacquet = isPacquetMode ? describe.skip : describe

View File

@@ -1,11 +1,15 @@
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { preparePackages } from '@pnpm/prepare'
import type { ProjectManifest } from '@pnpm/types'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm, execPnpmSync } from '../utils/index.js'
import {
execPnpm,
execPnpmSync,
skipIfPacquet,
} from '../utils/index.js'
test('verify-deps-before-run does not emit unsupported engine warnings for workspace projects', async () => {
skipIfPacquet('verify-deps-before-run does not emit unsupported engine warnings for workspace projects', async () => {
const manifests: Record<string, ProjectManifest> = {
root: {
name: 'root',

View File

@@ -1,17 +1,21 @@
import fs from 'node:fs'
import path from 'node:path'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { prepare, preparePackages } from '@pnpm/prepare'
import type { ProjectManifest } from '@pnpm/types'
import { loadWorkspaceState } from '@pnpm/workspace.state'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm, execPnpmSync } from '../utils/index.js'
import {
execPnpm,
execPnpmSync,
skipIfPacquet,
} from '../utils/index.js'
const CONFIG = ['--config.verify-deps-before-run=error'] as const
test('single package workspace', async () => {
skipIfPacquet('single package workspace', async () => {
const manifest: ProjectManifest = {
name: 'root',
private: true,
@@ -98,7 +102,7 @@ test('single package workspace', async () => {
await execPnpm([...CONFIG, 'exec', 'node', '--eval', 'assert.strictEqual(process.env.pnpm_config_verify_deps_before_run, "false")'])
})
test('multi-project workspace', async () => {
skipIfPacquet('multi-project workspace', async () => {
const manifests: Record<string, ProjectManifest> = {
root: {
name: 'root',

View File

@@ -1,18 +1,22 @@
import fs from 'node:fs'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { prepare } from '@pnpm/prepare'
import type { ProjectManifest } from '@pnpm/types'
import { loadWorkspaceState } from '@pnpm/workspace.state'
import { execPnpm, execPnpmSync } from '../utils/index.js'
import {
execPnpm,
execPnpmSync,
skipIfPacquet,
} from '../utils/index.js'
const CONFIG = [
'--config.verify-deps-before-run=install',
'--reporter=append-only',
] as const
test('verify-deps-before-run=install reuses the same flags as specified by the workspace state (#9109)', async () => {
skipIfPacquet('verify-deps-before-run=install reuses the same flags as specified by the workspace state (#9109)', async () => {
const manifest: ProjectManifest = {
name: 'root',
private: true,

View File

@@ -1,15 +1,19 @@
import fs from 'node:fs'
import path from 'node:path'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { preparePackages } from '@pnpm/prepare'
import type { ProjectManifest } from '@pnpm/types'
import { loadWorkspaceState } from '@pnpm/workspace.state'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm, execPnpmSync } from '../utils/index.js'
import {
execPnpm,
execPnpmSync,
skipIfPacquet,
} from '../utils/index.js'
test('hoisted node linker and node_modules not exist (#9424)', async () => {
skipIfPacquet('hoisted node linker and node_modules not exist (#9424)', async () => {
const config = [
'--config.verify-deps-before-run=error',
'--config.node-linker=hoisted',

View File

@@ -1,17 +1,22 @@
import fs from 'node:fs'
import path from 'node:path'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { preparePackages } from '@pnpm/prepare'
import type { ProjectManifest } from '@pnpm/types'
import { loadWorkspaceState } from '@pnpm/workspace.state'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm, execPnpmSync, pnpmBinLocation } from '../utils/index.js'
import {
execPnpm,
execPnpmSync,
pnpmBinLocation,
skipIfPacquet,
} from '../utils/index.js'
const CONFIG = ['--config.verify-deps-before-run=error'] as const
test('single dependency', async () => {
skipIfPacquet('single dependency', async () => {
const checkEnv = 'node --eval "assert.strictEqual(process.env.pnpm_config_verify_deps_before_run, \'false\')"'
const manifests: Record<string, ProjectManifest> = {
@@ -302,7 +307,7 @@ test('single dependency', async () => {
await execPnpm([...CONFIG, '--recursive', 'run', 'checkEnv'])
})
test('multiple lockfiles', async () => {
skipIfPacquet('multiple lockfiles', async () => {
const manifests: Record<string, ProjectManifest> = {
root: {
name: 'root',
@@ -568,7 +573,7 @@ test('multiple lockfiles', async () => {
}
})
test('filtered install', async () => {
skipIfPacquet('filtered install', async () => {
const manifests: Record<string, ProjectManifest> = {
root: {
name: 'root',
@@ -647,7 +652,7 @@ test('filtered install', async () => {
}
})
test('no dependencies', async () => {
skipIfPacquet('no dependencies', async () => {
const manifests: Record<string, ProjectManifest> = {
root: {
name: 'root',
@@ -714,7 +719,7 @@ test('no dependencies', async () => {
}
})
test('nested `pnpm run` should not check for mutated manifest', async () => {
skipIfPacquet('nested `pnpm run` should not check for mutated manifest', async () => {
const manifests: Record<string, ProjectManifest> = {
foo: {
name: 'foo',
@@ -813,7 +818,7 @@ test('nested `pnpm run` should not check for mutated manifest', async () => {
}
})
test('should check for outdated catalogs', async () => {
skipIfPacquet('should check for outdated catalogs', async () => {
const manifests: Record<string, ProjectManifest> = {
root: {
name: 'root',
@@ -918,7 +923,7 @@ test('should check for outdated catalogs', async () => {
}
})
test('failed to install dependencies', async () => {
skipIfPacquet('failed to install dependencies', async () => {
const manifests: Record<string, ProjectManifest> = {
root: {
name: 'root',

View File

@@ -1,17 +1,22 @@
import fs from 'node:fs'
import path from 'node:path'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { prepare } from '@pnpm/prepare'
import type { ProjectManifest } from '@pnpm/types'
import { loadWorkspaceState } from '@pnpm/workspace.state'
import { writeYamlFileSync } from 'write-yaml-file'
import { execPnpm, execPnpmSync, pnpmBinLocation } from '../utils/index.js'
import {
execPnpm,
execPnpmSync,
pnpmBinLocation,
skipIfPacquet,
} from '../utils/index.js'
const CONFIG = ['--config.verify-deps-before-run=error'] as const
test('single dependency', async () => {
skipIfPacquet('single dependency', async () => {
const manifest: ProjectManifest = {
name: 'root',
private: true,
@@ -106,7 +111,7 @@ test('single dependency', async () => {
await execPnpm([...CONFIG, 'run', 'checkEnv'])
})
test('deleting node_modules after install', async () => {
skipIfPacquet('deleting node_modules after install', async () => {
const manifest: ProjectManifest = {
name: 'root',
private: true,
@@ -149,7 +154,7 @@ test('deleting node_modules after install', async () => {
}
})
test('no dependencies', async () => {
skipIfPacquet('no dependencies', async () => {
const manifest: ProjectManifest = {
name: 'root',
private: true,
@@ -180,7 +185,7 @@ test('no dependencies', async () => {
}
})
test('nested `pnpm run` should not check for mutated manifest', async () => {
skipIfPacquet('nested `pnpm run` should not check for mutated manifest', async () => {
const manifest: ProjectManifest = {
name: 'root',
private: true,

View File

@@ -1,12 +1,15 @@
import path from 'node:path'
import { expect, test } from '@jest/globals'
import { expect } from '@jest/globals'
import { prepare } from '@pnpm/prepare'
import { writeJsonFileSync } from 'write-json-file'
import { execPnpmSync } from './utils/index.js'
import {
execPnpmSync,
skipIfPacquet,
} from './utils/index.js'
test('pnpm with current runs the currently active pnpm even when the project pins a different version', () => {
skipIfPacquet('pnpm with current runs the currently active pnpm even when the project pins a different version', () => {
prepare()
const pnpmHome = path.resolve('pnpm')
const env = { PNPM_HOME: pnpmHome }
@@ -20,7 +23,7 @@ test('pnpm with current runs the currently active pnpm even when the project pin
expect(stdout.toString()).not.toContain('Version 9.3.0')
})
test('pnpm with current bypasses the packageManager check when an unrelated package manager is pinned', () => {
skipIfPacquet('pnpm with current bypasses the packageManager check when an unrelated package manager is pinned', () => {
prepare()
const pnpmHome = path.resolve('pnpm')
const env = { PNPM_HOME: pnpmHome }
@@ -34,7 +37,7 @@ test('pnpm with current bypasses the packageManager check when an unrelated pack
expect(stderr.toString()).not.toContain('This project is configured to use yarn')
})
test('pnpm with current bypasses devEngines.packageManager with onFail=download', () => {
skipIfPacquet('pnpm with current bypasses devEngines.packageManager with onFail=download', () => {
prepare()
const pnpmHome = path.resolve('pnpm')
const env = { PNPM_HOME: pnpmHome }
@@ -54,7 +57,7 @@ test('pnpm with current bypasses devEngines.packageManager with onFail=download'
expect(stdout.toString()).not.toContain('Version 9.3.0')
})
test('pnpm with forwards subsequent args to the child pnpm', () => {
skipIfPacquet('pnpm with forwards subsequent args to the child pnpm', () => {
prepare()
writeJsonFileSync('package.json', {
name: 'project',
@@ -67,7 +70,7 @@ test('pnpm with forwards subsequent args to the child pnpm', () => {
expect(stdout.toString().trim()).toMatch(/^\d+\.\d+\.\d+/)
})
test('pnpm with fails when no spec is provided', () => {
skipIfPacquet('pnpm with fails when no spec is provided', () => {
prepare()
const { status, stderr } = execPnpmSync(['with'])
@@ -76,7 +79,7 @@ test('pnpm with fails when no spec is provided', () => {
expect(stderr.toString()).toContain('Missing version argument')
})
test('pnpm with <version> downloads and runs the specified pnpm version', () => {
skipIfPacquet('pnpm with <version> downloads and runs the specified pnpm version', () => {
prepare()
const pnpmHome = path.resolve('pnpm')
const env = { PNPM_HOME: pnpmHome }
@@ -87,7 +90,7 @@ test('pnpm with <version> downloads and runs the specified pnpm version', () =>
expect(stdout.toString()).toContain('Version 9.3.0')
})
test('pnpm with <version> ignores the packageManager pin and uses the requested version', () => {
skipIfPacquet('pnpm with <version> ignores the packageManager pin and uses the requested version', () => {
prepare()
const pnpmHome = path.resolve('pnpm')
const env = { PNPM_HOME: pnpmHome }