Files
renovate/lib/modules/manager/npm/post-update/pnpm.spec.ts
Aron Strandberg 6f0b6a56d3 fix(manager/npm): pass --no-frozen-lockfile to pnpm lock file updates (#44676)
* fix(manager/npm): pass --no-frozen-lockfile to pnpm lock file updates

pnpm applies an explicitly-set frozenLockfile: true from
pnpm-workspace.yaml even to 'pnpm install --lockfile-only', so lock file
regeneration always fails with ERR_PNPM_OUTDATED_LOCKFILE in repos that
set it: pnpm's CI frozen default has a --lockfile-only carve-out, but
explicitly-set values skip that carve-out, and only CLI flags take
precedence over pnpm-workspace.yaml settings. 'pnpm update' is not
affected by frozen mode (and rejects the flag), so only the install
command gets it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: less verbose comment

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-09-07 18:03:12 +00:00

753 lines
24 KiB
TypeScript

import { codeBlock } from 'common-tags';
import { envMock, mockExecAll } from '~test/exec-util.ts';
import { Fixtures } from '~test/fixtures.ts';
import { env, fs, partial } from '~test/util.ts';
import { GlobalConfig } from '../../../../config/global.ts';
import type { PostUpdateConfig, Upgrade } from '../../types.ts';
import { getNodeToolConstraint } from './node-version.ts';
import * as pnpmHelper from './pnpm.ts';
vi.mock('../../../../util/exec/env.ts');
vi.mock('../../../../util/fs/index.ts');
vi.mock('./node-version.ts');
delete process.env.NPM_CONFIG_CACHE;
process.env.CONTAINERBASE = 'true';
function mockPnpmFiles(workspaceFileContent?: string) {
fs.getSiblingFileName.mockReturnValue('some-folder/pnpm-workspace.yaml');
fs.readLocalFile.mockImplementation((fileName: string): Promise<string> => {
if (fileName === 'some-folder/pnpm-lock.yaml') {
return Promise.resolve('package-lock-contents');
}
if (
fileName === 'some-folder/pnpm-workspace.yaml' &&
workspaceFileContent
) {
return Promise.resolve(workspaceFileContent);
}
return Promise.resolve('unexpected file name');
});
fs.localPathExists.mockResolvedValueOnce(workspaceFileContent !== undefined); // pnpm-workspace.yaml
}
describe('modules/manager/npm/post-update/pnpm', () => {
let config: PostUpdateConfig;
const upgrades: Upgrade[] = [{}];
beforeEach(() => {
config = partial<PostUpdateConfig>({ constraints: { pnpm: '^2.0.0' } });
env.getChildProcessEnv.mockReturnValue(envMock.basic);
GlobalConfig.set({ localDir: '', binarySource: 'global' });
vi.mocked(getNodeToolConstraint).mockResolvedValueOnce({
toolName: 'node',
constraint: '16.16.0',
});
});
it('does nothing when no upgrades', async () => {
const execSnapshots = mockExecAll();
fs.readLocalFile.mockResolvedValue('package-lock-contents');
await pnpmHelper.generateLockFile('some-dir', {}, config);
expect(execSnapshots).toMatchObject([]);
});
it('generates lock files', async () => {
const execSnapshots = mockExecAll();
fs.readLocalFile.mockResolvedValue('package-lock-contents');
const res = await pnpmHelper.generateLockFile(
'some-dir',
{},
config,
upgrades,
);
expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchObject([
{
cmd: 'pnpm install --lockfile-only --ignore-scripts --ignore-pnpmfile --no-frozen-lockfile',
options: { cwd: 'some-dir' },
},
]);
});
it('catches errors', async () => {
const execSnapshots = mockExecAll();
fs.readLocalFile.mockImplementation(() => {
throw new Error('not found');
});
const res = await pnpmHelper.generateLockFile(
'some-dir',
{},
config,
upgrades,
);
expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
expect(res.error).toBeTrue();
expect(res.lockFile).toBeUndefined();
expect(execSnapshots).toMatchObject([
{
cmd: 'pnpm install --lockfile-only --ignore-scripts --ignore-pnpmfile --no-frozen-lockfile',
options: { cwd: 'some-dir' },
},
]);
});
it('finds pnpm globally', async () => {
const execSnapshots = mockExecAll();
fs.readLocalFile.mockResolvedValue('package-lock-contents');
const res = await pnpmHelper.generateLockFile(
'some-dir',
{},
config,
upgrades,
);
expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchObject([
{
cmd: 'pnpm install --lockfile-only --ignore-scripts --ignore-pnpmfile --no-frozen-lockfile',
options: { cwd: 'some-dir' },
},
]);
});
it('performs lock file updates', async () => {
const execSnapshots = mockExecAll();
fs.readLocalFile.mockResolvedValue('package-lock-contents');
const res = await pnpmHelper.generateLockFile('some-folder', {}, config, [
{ packageName: 'some-dep', newVersion: '1.0.1', isLockfileUpdate: true },
{
packageName: 'some-other-dep',
newVersion: '1.1.0',
isLockfileUpdate: true,
},
]);
expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchObject([
{
cmd: 'pnpm update --no-save some-dep@1.0.1 some-other-dep@1.1.0 --lockfile-only --ignore-scripts --ignore-pnpmfile',
},
]);
});
it('performs lock file updates for workspace with packages', async () => {
const execSnapshots = mockExecAll();
mockPnpmFiles(
codeBlock`
packages:
- pkg-a
`,
);
const res = await pnpmHelper.generateLockFile('some-folder', {}, config, [
{ packageName: 'some-dep', newVersion: '1.0.1', isLockfileUpdate: true },
{
packageName: 'some-other-dep',
newVersion: '1.1.0',
isLockfileUpdate: true,
},
]);
expect(fs.readLocalFile).toHaveBeenCalledTimes(2);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchObject([
{
cmd: 'pnpm update --no-save some-dep@1.0.1 some-other-dep@1.1.0 --lockfile-only --recursive --ignore-scripts --ignore-pnpmfile',
},
]);
});
it('performs lock file updates for workspace with packages using pnpm 10.x', async () => {
const execSnapshots = mockExecAll();
mockPnpmFiles(
codeBlock`
packages:
- pkg-a
- pkg-b
`,
);
const res = await pnpmHelper.generateLockFile(
'some-folder',
{},
{ ...config, constraints: { pnpm: '10.x' } },
[
{
packageName: 'some-dep',
newVersion: '1.0.1',
isLockfileUpdate: true,
},
{
packageName: 'some-other-dep',
newVersion: '1.1.0',
isLockfileUpdate: true,
},
],
);
expect(fs.readLocalFile).toHaveBeenCalledTimes(2);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchObject([
{
cmd: 'pnpm update --no-save some-dep@1.0.1 some-other-dep@1.1.0 --lockfile-only --recursive --ignore-scripts --ignore-pnpmfile',
},
]);
});
it('performs lock file updates for non workspace using pnpm 10.x', async () => {
const execSnapshots = mockExecAll();
mockPnpmFiles(); // no workspace file
const res = await pnpmHelper.generateLockFile(
'some-folder',
{},
{ ...config, constraints: { pnpm: '10.x' } },
[
{
packageName: 'some-dep',
newVersion: '1.0.1',
isLockfileUpdate: true,
},
{
packageName: 'some-other-dep',
newVersion: '1.1.0',
isLockfileUpdate: true,
},
],
);
expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchObject([
{
cmd: 'pnpm update --no-save some-dep@1.0.1 some-other-dep@1.1.0 --lockfile-only --ignore-scripts --ignore-pnpmfile',
},
]);
});
it('performs lock file updates for workspace with empty package list', async () => {
const execSnapshots = mockExecAll();
mockPnpmFiles(codeBlock`packages: []`);
const res = await pnpmHelper.generateLockFile('some-folder', {}, config, [
{
packageName: 'some-dep',
newVersion: '1.0.1',
isLockfileUpdate: true,
},
{
packageName: 'some-other-dep',
newVersion: '1.1.0',
isLockfileUpdate: true,
},
]);
expect(fs.readLocalFile).toHaveBeenCalledTimes(2);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchObject([
{
cmd: 'pnpm update --no-save some-dep@1.0.1 some-other-dep@1.1.0 --lockfile-only --ignore-scripts --ignore-pnpmfile',
},
]);
});
it('performs lock file updates for workspace with config but no package list', async () => {
const execSnapshots = mockExecAll();
mockPnpmFiles(codeBlock`
overrides:
"foo@1.0.0>bar": "-"
`);
const res = await pnpmHelper.generateLockFile('some-folder', {}, config, [
{
packageName: 'some-dep',
newVersion: '1.0.1',
isLockfileUpdate: true,
},
{
packageName: 'some-other-dep',
newVersion: '1.1.0',
isLockfileUpdate: true,
},
]);
expect(fs.readLocalFile).toHaveBeenCalledTimes(2);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchObject([
{
cmd: 'pnpm update --no-save some-dep@1.0.1 some-other-dep@1.1.0 --lockfile-only --ignore-scripts --ignore-pnpmfile',
},
]);
});
it('performs lock file updates and install when lock file updates mixed with regular updates', async () => {
const execSnapshots = mockExecAll();
fs.readLocalFile.mockResolvedValue('package-lock-contents');
const res = await pnpmHelper.generateLockFile('some-folder', {}, config, [
{
sharedVariableName: 'some-group',
packageName: 'some-dep',
newVersion: '1.1.0',
isLockfileUpdate: true,
},
{
sharedVariableName: 'some-group',
packageName: 'some-other-dep',
newVersion: '1.1.0',
isLockfileUpdate: false,
},
]);
expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchObject([
{
cmd: 'pnpm install --lockfile-only --ignore-scripts --ignore-pnpmfile --no-frozen-lockfile',
},
{
cmd: 'pnpm update --no-save some-dep@1.1.0 --lockfile-only --ignore-scripts --ignore-pnpmfile',
},
]);
});
it('performs lock file maintenance', async () => {
const execSnapshots = mockExecAll();
fs.readLocalFile.mockResolvedValue('package-lock-contents');
const res = await pnpmHelper.generateLockFile('some-dir', {}, config, [
{ isLockFileMaintenance: true },
]);
expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
expect(fs.deleteLocalFile).toHaveBeenCalledTimes(1);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchObject([
{
cmd: 'pnpm install --lockfile-only --ignore-scripts --ignore-pnpmfile --no-frozen-lockfile',
options: { cwd: 'some-dir' },
},
]);
});
it('performs dedupe', async () => {
const execSnapshots = mockExecAll();
fs.readLocalFile.mockResolvedValue('package-lock-contents');
const postUpdateOptions = ['pnpmDedupe'];
const res = await pnpmHelper.generateLockFile(
'some-dir',
{},
{ ...config, postUpdateOptions },
upgrades,
);
expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchObject([
{
cmd: 'pnpm install --lockfile-only --ignore-scripts --ignore-pnpmfile --no-frozen-lockfile',
},
{
cmd: 'pnpm dedupe --lockfile-only --ignore-scripts --ignore-pnpmfile',
},
]);
});
it('performs dedupe without --recursive for workspaces', async () => {
const execSnapshots = mockExecAll();
mockPnpmFiles(
codeBlock`
packages:
- pkg-a
`,
);
const postUpdateOptions = ['pnpmDedupe'];
const res = await pnpmHelper.generateLockFile(
'some-folder',
{},
{ ...config, postUpdateOptions },
upgrades,
);
expect(fs.readLocalFile).toHaveBeenCalledTimes(2);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchObject([
{
cmd: 'pnpm install --lockfile-only --recursive --ignore-scripts --ignore-pnpmfile --no-frozen-lockfile',
},
{
cmd: 'pnpm dedupe --lockfile-only --ignore-scripts --ignore-pnpmfile',
},
]);
});
it('uses the new version if packageManager is updated', async () => {
const execSnapshots = mockExecAll();
fs.readLocalFile.mockResolvedValue('package-lock-contents');
const res = await pnpmHelper.generateLockFile('some-dir', {}, config, [
{
depType: 'packageManager',
depName: 'pnpm',
newValue: '6.16.1',
newVersion: '6.16.1',
},
]);
expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchObject([
{
cmd: 'pnpm install --lockfile-only --ignore-scripts --ignore-pnpmfile --no-frozen-lockfile',
options: { cwd: 'some-dir' },
},
]);
// TODO: check docker preCommands
});
it('uses constraint version if parent json has constraints', async () => {
const execSnapshots = mockExecAll();
const configTemp = partial<PostUpdateConfig>();
const fileContent = Fixtures.get('parent/package.json');
fs.readLocalFile
.mockResolvedValueOnce(fileContent)
.mockResolvedValue('package-lock-contents');
const res = await pnpmHelper.generateLockFile(
'some-folder',
{},
configTemp,
[
{
depType: 'packageManager',
depName: 'pnpm',
},
],
);
expect(fs.readLocalFile).toHaveBeenCalledTimes(2);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchObject([
{
cmd: 'pnpm install --lockfile-only --ignore-scripts --ignore-pnpmfile --no-frozen-lockfile',
options: {
cwd: 'some-folder',
env: {
HTTP_PROXY: 'http://example.com',
HTTPS_PROXY: 'https://example.com',
NO_PROXY: 'localhost',
HOME: '/home/user',
PATH: '/tmp/path',
LANG: 'en_US.UTF-8',
LC_ALL: 'en_US',
},
maxBuffer: 10485760,
timeout: 900000,
stdin: 'pipe',
stdout: 'pipe',
stderr: 'pipe',
},
},
]);
});
it('uses packageManager version and puts it into constraint', async () => {
const execSnapshots = mockExecAll();
const configTemp = partial<PostUpdateConfig>();
const fileContent = Fixtures.get('manager-field/package.json');
fs.readLocalFile
.mockResolvedValueOnce(fileContent)
.mockResolvedValue('package-lock-contents');
const res = await pnpmHelper.generateLockFile(
'some-folder',
{},
configTemp,
[
{
depType: 'packageManager',
depName: 'pnpm',
},
],
);
expect(fs.readLocalFile).toHaveBeenCalledTimes(2);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchObject([
{
cmd: 'pnpm install --lockfile-only --ignore-scripts --ignore-pnpmfile --no-frozen-lockfile',
options: {
cwd: 'some-folder',
env: {
HTTP_PROXY: 'http://example.com',
HTTPS_PROXY: 'https://example.com',
NO_PROXY: 'localhost',
HOME: '/home/user',
PATH: '/tmp/path',
LANG: 'en_US.UTF-8',
LC_ALL: 'en_US',
},
maxBuffer: 10485760,
timeout: 900000,
stdin: 'pipe',
stdout: 'pipe',
stderr: 'pipe',
},
},
]);
});
it('uses volta version and puts it into constraint', async () => {
const execSnapshots = mockExecAll();
const configTemp = partial<PostUpdateConfig>();
const fileContent = codeBlock`
{
"name": "parent",
"version": "1.0.0",
"engines": {
"pnpm": "^6.0.0"
},
"engine-strict": true,
"volta": {
"pnpm": "6.15.0"
}
}
`;
fs.readLocalFile
.mockResolvedValueOnce(fileContent)
.mockResolvedValue('package-lock-contents');
const res = await pnpmHelper.generateLockFile(
'some-folder',
{},
configTemp,
[
{
depType: 'volta',
depName: 'pnpm',
},
],
);
expect(fs.readLocalFile).toHaveBeenCalledTimes(2);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchObject([
{
cmd: 'pnpm install --lockfile-only --ignore-scripts --ignore-pnpmfile --no-frozen-lockfile',
options: {
cwd: 'some-folder',
env: {
HTTP_PROXY: 'http://example.com',
HTTPS_PROXY: 'https://example.com',
NO_PROXY: 'localhost',
HOME: '/home/user',
PATH: '/tmp/path',
LANG: 'en_US.UTF-8',
LC_ALL: 'en_US',
},
maxBuffer: 10485760,
timeout: 900000,
stdin: 'pipe',
stdout: 'pipe',
stderr: 'pipe',
},
},
]);
});
it('uses skips pnpm v7 if lockfileVersion indicates <7', async () => {
mockExecAll();
const configTemp = partial<PostUpdateConfig>();
fs.readLocalFile
.mockResolvedValueOnce('{}') // package.json
.mockResolvedValue('lockfileVersion: 5.3\n'); // pnpm-lock.yaml
const res = await pnpmHelper.generateLockFile(
'some-folder',
{},
configTemp,
[],
);
expect(fs.readLocalFile).toHaveBeenCalledTimes(3);
expect(res.lockFile).toBe('lockfileVersion: 5.3\n');
});
it('works for docker mode', async () => {
GlobalConfig.set({
localDir: '',
cacheDir: '/tmp',
binarySource: 'docker',
allowScripts: true,
dockerSidecarImage: 'ghcr.io/renovatebot/base-image',
});
const execSnapshots = mockExecAll();
fs.readLocalFile.mockResolvedValue('package-lock-contents');
const res = await pnpmHelper.generateLockFile(
'some-dir',
{},
{ ...config, constraints: { pnpm: '6.0.0' } },
upgrades,
);
expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchObject([
{ cmd: 'docker pull ghcr.io/renovatebot/base-image' },
{ cmd: 'docker ps --filter name=renovate_sidecar -aq' },
{
cmd:
'docker run --rm --name=renovate_sidecar --label=renovate_child ' +
'-v "/tmp":"/tmp" ' +
'-e CI ' +
'-e CONTAINERBASE_CACHE_DIR ' +
'-w "some-dir" ' +
'ghcr.io/renovatebot/base-image ' +
"bash -l -c '" +
'install-tool node 16.16.0 ' +
'&& install-tool pnpm 6.0.0 ' +
'&& pnpm install --lockfile-only --no-frozen-lockfile' +
"'",
},
]);
});
it('works for install mode', async () => {
GlobalConfig.set({
localDir: '',
cacheDir: '/tmp',
binarySource: 'install',
});
const execSnapshots = mockExecAll();
fs.readLocalFile.mockResolvedValue('package-lock-contents');
const res = await pnpmHelper.generateLockFile(
'some-dir',
{},
{ ...config, constraints: { pnpm: '6.0.0' } },
upgrades,
);
expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchObject([
{ cmd: 'install-tool node 16.16.0' },
{ cmd: 'install-tool pnpm 6.0.0' },
{
cmd: 'pnpm install --lockfile-only --ignore-scripts --ignore-pnpmfile --no-frozen-lockfile',
},
]);
});
it('allows pnpmfile even if ignoring scripts', async () => {
GlobalConfig.set({
localDir: '',
cacheDir: '/tmp',
binarySource: 'install',
allowScripts: true,
});
const execSnapshots = mockExecAll();
fs.readLocalFile.mockResolvedValue('package-lock-contents');
const res = await pnpmHelper.generateLockFile(
'some-dir',
{},
{ ...config, constraints: { pnpm: '6.0.0' }, ignoreScripts: true },
upgrades,
);
expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchObject([
{ cmd: 'install-tool node 16.16.0' },
{ cmd: 'install-tool pnpm 6.0.0' },
{
cmd: 'pnpm install --lockfile-only --ignore-scripts --no-frozen-lockfile',
},
]);
});
describe('passes NODE_OPTIONS', () => {
it('if nodeMaxMemory set on global config', async () => {
GlobalConfig.set({
localDir: '',
toolSettings: {
nodeMaxMemory: 1234,
},
binarySource: 'global',
});
const execSnapshots = mockExecAll();
fs.readLocalFile.mockResolvedValue('package-lock-contents');
const res = await pnpmHelper.generateLockFile(
'some-dir',
{},
{
...config,
},
upgrades,
);
expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchObject([
{
cmd: 'pnpm install --lockfile-only --ignore-scripts --ignore-pnpmfile --no-frozen-lockfile',
},
]);
expect(execSnapshots[0].options?.env?.NODE_OPTIONS).toEqual(
'--max-old-space-size=1234',
);
});
it('if nodeMaxMemory set on repo config', async () => {
const execSnapshots = mockExecAll();
fs.readLocalFile.mockResolvedValue('package-lock-contents');
const res = await pnpmHelper.generateLockFile(
'some-dir',
{},
{
...config,
toolSettings: {
nodeMaxMemory: 1234,
},
},
upgrades,
);
expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchObject([
{
cmd: 'pnpm install --lockfile-only --ignore-scripts --ignore-pnpmfile --no-frozen-lockfile',
},
]);
expect(execSnapshots[0].options?.env?.NODE_OPTIONS).toEqual(
'--max-old-space-size=1234',
);
});
});
describe('getConstraintsFromLockFile()', () => {
it('returns null if no lock file', async () => {
fs.readLocalFile.mockResolvedValueOnce(null);
const res = await pnpmHelper.getConstraintFromLockFile('some-file-name');
expect(res).toBeNull();
});
it('returns null when error reading lock file', async () => {
fs.readLocalFile.mockRejectedValueOnce(new Error('foo'));
const res = await pnpmHelper.getConstraintFromLockFile('some-file-name');
expect(res).toBeNull();
});
it('returns null if no lockfileVersion', async () => {
fs.readLocalFile.mockResolvedValueOnce('foo: bar\n');
const res = await pnpmHelper.getConstraintFromLockFile('some-file-name');
expect(res).toBeNull();
});
it('returns null if lockfileVersion is not a number or numeric string', async () => {
fs.readLocalFile.mockResolvedValueOnce('lockfileVersion: foo\n');
const res = await pnpmHelper.getConstraintFromLockFile('some-file-name');
expect(res).toBeNull();
});
it('returns default if lockfileVersion is 1', async () => {
fs.readLocalFile.mockResolvedValueOnce('lockfileVersion: 1\n');
const res = await pnpmHelper.getConstraintFromLockFile('some-file-name');
expect(res).toBe('>=3 <3.5.0');
});
it('maps supported versions', async () => {
fs.readLocalFile.mockResolvedValueOnce('lockfileVersion: 5.3\n');
const res = await pnpmHelper.getConstraintFromLockFile('some-file-name');
expect(res).toBe('>=6 <7');
});
it('maps supported versions for v6', async () => {
fs.readLocalFile.mockResolvedValueOnce("lockfileVersion: '6.0'\n");
const res = await pnpmHelper.getConstraintFromLockFile('some-file-name');
expect(res).toBe('>=7.24.2 <9');
});
it('maps supported versions for v9', async () => {
fs.readLocalFile.mockResolvedValueOnce("lockfileVersion: '9.0'\n");
const res = await pnpmHelper.getConstraintFromLockFile('some-file-name');
expect(res).toBe('>=9');
});
});
});