Files
pnpm/pnpm11/engine/runtime/system-version/test/getSystemNodeVersion.test.ts
Zoltan Kochan fc2f33912e refactor: move the TypeScript pnpm CLI into a pnpm11/ directory (#12537)
The TypeScript pnpm CLI freezes at v11; pnpm 12 will be the Rust pacquet
port. To make that split legible, all TypeScript source, test, and build
directories move under a new top-level pnpm11/ directory. The name states
the version boundary rather than implying a behavioral fork, since the two
stacks are meant to behave identically.

Scope is source-only: the shared workspace root stays at the repo root.
pnpm-workspace.yaml, package.json, pnpm-lock.yaml, .pnpmfile.cjs,
.meta-updater, __patches__, .changeset, .husky, and the lint/spell configs
remain in place, so one pnpm workspace and one Cargo workspace still span
all three products. pnpr/client and pacquet/tasks/registry-mock stay as
cross-product workspace members.

Rewiring the move required:
- pnpm-workspace.yaml globs prefixed with pnpm11/
- root package.json script paths, eslint.config.mjs, tsconfig.lint.json,
  .gitignore, and CODEOWNERS updated
- .meta-updater/src/index.ts literals repointed (pnpm11/pnpm/package.json,
  pnpm11/__utils__, pnpm11/__typings__, and the main package directory)
- regenerated every moved package's repository/homepage URL via meta-updater
- pnpm11/pnpm/bundle-deps.ts and __utils__/scripts/src/typecheck-only.ts
  climb one more level to reach the repo root

.meta-updater stays at the repo root because @pnpm/meta-updater resolves
its config at <cwd>/.meta-updater/main.mjs.

TS CI (.github/workflows/ci.yml) now only runs when pnpm11/-relevant paths
change, via a dorny/paths-filter changes job plus a TS CI / Success
aggregate gate; branch protection should require only that gate.
2026-06-20 14:36:25 +02:00

115 lines
4.3 KiB
TypeScript

import { expect, jest, test } from '@jest/globals'
let isSea = false
jest.unstable_mockModule('@pnpm/cli.meta', () => ({
detectIfCurrentPkgIsExecutable: jest.fn(() => isSea),
}))
jest.unstable_mockModule('execa', () => ({
sync: jest.fn(() => ({
stdout: 'v10.0.0',
})),
}))
const {
getSystemNodeVersionNonCached,
getSystemDenoVersionNonCached,
getSystemBunVersionNonCached,
getSystemRuntimeVersion,
engineName,
} = await import('../lib/index.js')
const execa = await import('execa')
test('getSystemNodeVersion() executed from an executable pnpm CLI', () => {
isSea = true
expect(getSystemNodeVersionNonCached()).toBe('v10.0.0')
expect(execa.sync).toHaveBeenCalledWith('node', ['--version'])
})
test('getSystemNodeVersion() from a non-executable pnpm CLI', () => {
isSea = false
expect(getSystemNodeVersionNonCached()).toBe(process.version)
})
test('getSystemNodeVersion() returns undefined if execa.sync throws an error', () => {
// Mock execa.sync to throw an error
jest.mocked(execa.sync).mockImplementationOnce(() => {
throw new Error('not found: node')
})
isSea = true
expect(getSystemNodeVersionNonCached()).toBeUndefined()
expect(execa.sync).toHaveBeenCalledWith('node', ['--version'])
})
test('getSystemDenoVersion() parses the first line of `deno --version`', () => {
jest.mocked(execa.sync).mockReturnValueOnce({
stdout: 'deno 1.40.0 (release, aarch64-apple-darwin)\nv8 12.1.285.27\ntypescript 5.3.3',
} as ReturnType<typeof execa.sync>)
expect(getSystemDenoVersionNonCached()).toBe('v1.40.0')
expect(execa.sync).toHaveBeenCalledWith('deno', ['--version'])
})
test('getSystemDenoVersion() returns undefined when deno is missing or output is unexpected', () => {
jest.mocked(execa.sync).mockImplementationOnce(() => {
throw new Error('not found: deno')
})
expect(getSystemDenoVersionNonCached()).toBeUndefined()
jest.mocked(execa.sync).mockReturnValueOnce({ stdout: 'unexpected output' } as ReturnType<typeof execa.sync>)
expect(getSystemDenoVersionNonCached()).toBeUndefined()
})
test('getSystemBunVersion() parses the bare version printed by `bun --version`', () => {
jest.mocked(execa.sync).mockReturnValueOnce({ stdout: '1.1.0\n' } as ReturnType<typeof execa.sync>)
expect(getSystemBunVersionNonCached()).toBe('v1.1.0')
expect(execa.sync).toHaveBeenCalledWith('bun', ['--version'])
})
test('getSystemBunVersion() returns undefined when bun is missing', () => {
jest.mocked(execa.sync).mockImplementationOnce(() => {
throw new Error('not found: bun')
})
expect(getSystemBunVersionNonCached()).toBeUndefined()
})
test('getSystemRuntimeVersion() dispatches to the per-runtime helpers', () => {
isSea = false
expect(getSystemRuntimeVersion('node')).toBe(process.version)
jest.mocked(execa.sync).mockReturnValueOnce({
stdout: 'deno 9.9.9 (release)',
} as ReturnType<typeof execa.sync>)
expect(getSystemRuntimeVersion('deno')).toBe('v9.9.9')
expect(execa.sync).toHaveBeenLastCalledWith('deno', ['--version'])
jest.mocked(execa.sync).mockReturnValueOnce({
stdout: '9.9.9\n',
} as ReturnType<typeof execa.sync>)
expect(getSystemRuntimeVersion('bun')).toBe('v9.9.9')
expect(execa.sync).toHaveBeenLastCalledWith('bun', ['--version'])
})
test('engineName() honours an explicit nodeVersion over the host probe', () => {
// The pinned-runtime override path: when a project's
// `engines.runtime` / `devEngines.runtime` resolves to a specific
// Node version, the caller forwards it to `engineName(version)`
// and the result reflects that pinned Node — not whatever pnpm
// itself is running on. Format-stable across `v`-prefixed and
// bare versions.
const major22 = `${process.platform};${process.arch};node22`
expect(engineName('22.11.0')).toBe(major22)
expect(engineName('v22.11.0')).toBe(major22)
})
test('engineName() falls back to the host Node when no override is provided', () => {
// No-arg call mirrors the pre-runtime-pin behaviour: anchor to
// `getSystemNodeVersion()` (which itself prefers shell `node` over
// `process.version` only when running as a SEA bundle — covered
// by the tests above). Non-SEA test environment, so the system
// version equals `process.version`.
isSea = false
const major = process.version.replace(/^v/, '').split('.')[0]
expect(engineName()).toBe(`${process.platform};${process.arch};node${major}`)
})