test(pnpm): group release-brittle tests under a shared describe block (#11767)

Three tests resolve the running pnpm version's integrity from registry-mock,
which proxies pnpm to npmjs. They fail every release between the version
bump commit and the matching npm publish ("No matching version found for
pnpm@<version>"), then pass again once the version lands on npmjs. Group
them under a 'release-brittle' describe in each file so the failure mode
is obvious from the test name and only stated once.
This commit is contained in:
Zoltan Kochan
2026-05-20 14:57:08 +02:00
committed by GitHub
parent 097983fbca
commit ef87f3ccff
2 changed files with 84 additions and 72 deletions

View File

@@ -1,7 +1,7 @@
import fs from 'node:fs'
import path from 'node:path'
import { expect, test } from '@jest/globals'
import { describe, expect, test } from '@jest/globals'
import { readEnvLockfile } from '@pnpm/lockfile.fs'
import { prepare } from '@pnpm/prepare'
import { getIntegrity } from '@pnpm/registry-mock'
@@ -149,21 +149,26 @@ test('package manager from the packageManager field is not saved into the lockfi
expect(envLockfile!.importers['.'].packageManagerDependencies).toBeUndefined()
})
test('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: {
packageManager: {
name: 'pnpm',
version: pnpmVersion,
// These tests resolve the running pnpm version's integrity from registry-mock,
// which proxies pnpm to npmjs. They fail between a release commit and the
// 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 () => {
const pnpmVersion = JSON.parse(fs.readFileSync(path.join(path.dirname(pnpmBinLocation), '..', 'package.json'), 'utf8')).version as string
prepare({
devEngines: {
packageManager: {
name: 'pnpm',
version: pnpmVersion,
},
},
},
})
})
// Seed the lockfile with a stale packageManagerDependencies entry that no
// longer satisfies devEngines.packageManager. Multi-document YAML: env
// lockfile is the first doc, the (empty) installer lockfile is the second.
fs.writeFileSync('pnpm-lock.yaml', `---
// Seed the lockfile with a stale packageManagerDependencies entry that no
// longer satisfies devEngines.packageManager. Multi-document YAML: env
// lockfile is the first doc, the (empty) installer lockfile is the second.
fs.writeFileSync('pnpm-lock.yaml', `---
lockfileVersion: '9.0'
importers:
'.':
@@ -178,16 +183,17 @@ snapshots: {}
---
`)
// COREPACK_ROOT used to skip the entire pm-handling block, leaving the stale
// 0.0.1 entry untouched. The sync must run regardless of how pnpm was
// invoked.
await execPnpm(['install'], {
env: { COREPACK_ROOT: '/fake/corepack' },
})
// COREPACK_ROOT used to skip the entire pm-handling block, leaving the
// stale 0.0.1 entry untouched. The sync must run regardless of how pnpm
// was invoked.
await execPnpm(['install'], {
env: { COREPACK_ROOT: '/fake/corepack' },
})
const envLockfile = await readEnvLockfile(process.cwd())
expect(envLockfile).not.toBeNull()
expect(envLockfile!.importers['.'].packageManagerDependencies?.['pnpm'].version).toBe(pnpmVersion)
const envLockfile = await readEnvLockfile(process.cwd())
expect(envLockfile).not.toBeNull()
expect(envLockfile!.importers['.'].packageManagerDependencies?.['pnpm'].version).toBe(pnpmVersion)
})
})
test('installing a new configurational dependency', async () => {

View File

@@ -1,4 +1,4 @@
import { expect, test } from '@jest/globals'
import { describe, expect, test } from '@jest/globals'
import { prepare, prepareEmpty } from '@pnpm/prepare'
import { writeYamlFileSync } from 'write-yaml-file'
@@ -185,38 +185,6 @@ test('devEngines.packageManager with a different PM name should fail with onFail
expect(stderr.toString()).toContain('This project is configured to use yarn')
})
test('pnpm --version exits promptly when devEngines.packageManager matches the running pnpm', async () => {
// Regression test: main.ts's `--version` short-circuit returned before
// the command-handler `finally` that calls finishWorkers(), and
// switchCliVersion had already spawned workers during integrity
// resolution. The worker pool then kept the Node event loop alive long
// past the version print.
// Read the running pnpm version from a fresh empty dir — the previous
// test's prepare() leaves cwd in a manifest with a failing pm check, and
// checkPackageManager runs before the --version short-circuit.
prepareEmpty()
const versionProcess = execPnpmSync(['--version'])
const pnpmVersion = versionProcess.stdout.toString().trim()
prepare({
devEngines: {
packageManager: {
name: 'pnpm',
version: pnpmVersion,
onFail: 'download',
},
},
})
// 30 s is comfortably above the post-fix exit time (~3 s) and far below
// the pre-fix hang. If the regression returns, spawnSync's timeout kicks
// in and execPnpmSync throws from its `error`/`signal` checks.
const { status, stdout } = execPnpmSync(['--version'], { timeout: 30_000 })
expect(status).toBe(0)
expect(stdout.toString().trim()).toBe(pnpmVersion)
})
test('devEngines.packageManager array selects the pnpm entry', async () => {
prepare({
devEngines: {
@@ -251,22 +219,6 @@ test('devEngines.packageManager array defaults onFail to ignore for non-last ele
expect(status).toBe(0)
})
test('devEngines.packageManager with version range should match current version', async () => {
prepare({
devEngines: {
packageManager: {
name: 'pnpm',
version: '>=1.0.0',
onFail: 'error',
},
},
})
const { status } = execPnpmSync(['install'])
expect(status).toBe(0)
})
test('devEngines.packageManager takes precedence over packageManager field', async () => {
const versionProcess = execPnpmSync(['--version'])
const pnpmVersion = versionProcess.stdout.toString().trim()
@@ -476,3 +428,57 @@ test.each([
expect(status).toBe(0)
expect(stderr.toString()).not.toContain('configured to use 0.0.1')
})
// These tests resolve the running pnpm version's integrity from registry-mock,
// which proxies pnpm to npmjs. They fail between a release commit and the
// 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('pnpm --version exits promptly when devEngines.packageManager matches the running pnpm', async () => {
// Regression test: main.ts's `--version` short-circuit returned before
// the command-handler `finally` that calls finishWorkers(), and
// switchCliVersion had already spawned workers during integrity
// resolution. The worker pool then kept the Node event loop alive long
// past the version print.
// Read the running pnpm version from a fresh empty dir — the previous
// test's prepare() leaves cwd in a manifest with a failing pm check, and
// checkPackageManager runs before the --version short-circuit.
prepareEmpty()
const versionProcess = execPnpmSync(['--version'])
const pnpmVersion = versionProcess.stdout.toString().trim()
prepare({
devEngines: {
packageManager: {
name: 'pnpm',
version: pnpmVersion,
onFail: 'download',
},
},
})
// 30 s is comfortably above the post-fix exit time (~3 s) and far below
// the pre-fix hang. If the regression returns, spawnSync's timeout kicks
// in and execPnpmSync throws from its `error`/`signal` checks.
const { status, stdout } = execPnpmSync(['--version'], { timeout: 30_000 })
expect(status).toBe(0)
expect(stdout.toString().trim()).toBe(pnpmVersion)
})
test('devEngines.packageManager with version range should match current version', async () => {
prepare({
devEngines: {
packageManager: {
name: 'pnpm',
version: '>=1.0.0',
onFail: 'error',
},
},
})
const { status } = execPnpmSync(['install'])
expect(status).toBe(0)
})
})