Skip to content

Commit 4217486

Browse files
committed
test(migration): add unit tests for pnpm workspace yaml migration
Add tests for rewriteStandaloneProject covering: - Creates pnpm-workspace.yaml when no existing pnpm config - Keeps pnpm config in package.json when existing pnpm field present - Preserves custom peerDependencyRules (e.g., ignoreMissing) - Moves remaining non-Vite overrides to pnpm-workspace.yaml Also fix a bug where spreading peerDependencyRules dropped custom fields like ignoreMissing when merging Vite-managed entries.
1 parent 922463a commit 4217486

2 files changed

Lines changed: 144 additions & 0 deletions

File tree

packages/cli/src/migration/__tests__/migrator.spec.ts

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ vi.mock('../../utils/constants.js', async (importOriginal) => {
1616

1717
const {
1818
rewritePackageJson,
19+
rewriteStandaloneProject,
1920
parseNvmrcVersion,
2021
detectNodeVersionManagerFile,
2122
migrateNodeVersionManagerFile,
@@ -290,3 +291,145 @@ describe('migrateNodeVersionManagerFile', () => {
290291
expect(fs.existsSync(path.join(tmpDir, '.node-version'))).toBe(false);
291292
});
292293
});
294+
295+
function makeWorkspaceInfo(
296+
rootDir: string,
297+
packageManager: PackageManager,
298+
): import('../../types/index.js').WorkspaceInfo {
299+
return {
300+
rootDir,
301+
isMonorepo: false,
302+
monorepoScope: '',
303+
workspacePatterns: [],
304+
parentDirs: [],
305+
packageManager,
306+
packageManagerVersion: '10.33.0',
307+
downloadPackageManager: {
308+
name: 'pnpm',
309+
installDir: '/tmp',
310+
binPrefix: '/tmp/bin',
311+
packageName: 'pnpm',
312+
version: '10.33.0',
313+
},
314+
packages: [],
315+
};
316+
}
317+
318+
function readJson(filePath: string): Record<string, unknown> {
319+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
320+
}
321+
322+
function readYaml(filePath: string): string {
323+
return fs.readFileSync(filePath, 'utf8');
324+
}
325+
326+
describe('rewriteStandaloneProject pnpm workspace yaml', () => {
327+
let tmpDir: string;
328+
329+
beforeEach(() => {
330+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'vp-test-pnpm-'));
331+
});
332+
333+
afterEach(() => {
334+
fs.rmSync(tmpDir, { recursive: true, force: true });
335+
});
336+
337+
it('creates pnpm-workspace.yaml when no existing pnpm config in package.json', () => {
338+
fs.writeFileSync(
339+
path.join(tmpDir, 'package.json'),
340+
JSON.stringify({ name: 'test', devDependencies: { vite: '^7.0.0' } }),
341+
);
342+
rewriteStandaloneProject(tmpDir, makeWorkspaceInfo(tmpDir, PackageManager.pnpm), true, true);
343+
344+
// pnpm-workspace.yaml should be created
345+
expect(fs.existsSync(path.join(tmpDir, 'pnpm-workspace.yaml'))).toBe(true);
346+
const yaml = readYaml(path.join(tmpDir, 'pnpm-workspace.yaml'));
347+
expect(yaml).toContain('overrides:');
348+
expect(yaml).toContain('peerDependencyRules:');
349+
expect(yaml).toContain('catalog:');
350+
351+
// package.json should not have pnpm section
352+
const pkg = readJson(path.join(tmpDir, 'package.json'));
353+
expect(pkg.pnpm).toBeUndefined();
354+
355+
// devDependencies should use catalog:
356+
const devDeps = pkg.devDependencies as Record<string, string>;
357+
expect(devDeps.vite).toBe('catalog:');
358+
expect(devDeps['vite-plus']).toBe('catalog:');
359+
});
360+
361+
it('keeps pnpm config in package.json when existing pnpm field present', () => {
362+
fs.writeFileSync(
363+
path.join(tmpDir, 'package.json'),
364+
JSON.stringify({
365+
name: 'test',
366+
devDependencies: { vite: '^7.0.0' },
367+
pnpm: {
368+
overrides: { 'some-pkg': '1.0.0' },
369+
onlyBuiltDependencies: ['esbuild'],
370+
},
371+
}),
372+
);
373+
rewriteStandaloneProject(tmpDir, makeWorkspaceInfo(tmpDir, PackageManager.pnpm), true, true);
374+
375+
// pnpm-workspace.yaml should NOT be created
376+
expect(fs.existsSync(path.join(tmpDir, 'pnpm-workspace.yaml'))).toBe(false);
377+
378+
// package.json should have pnpm.overrides with both existing and vite overrides
379+
const pkg = readJson(path.join(tmpDir, 'package.json'));
380+
const pnpm = pkg.pnpm as Record<string, unknown>;
381+
expect(pnpm).toBeDefined();
382+
const overrides = pnpm.overrides as Record<string, string>;
383+
expect(overrides['some-pkg']).toBe('1.0.0');
384+
expect(overrides.vite).toBeDefined();
385+
expect(overrides.vitest).toBeDefined();
386+
387+
// peerDependencyRules should be present
388+
expect(pnpm.peerDependencyRules).toBeDefined();
389+
// onlyBuiltDependencies should be preserved
390+
expect(pnpm.onlyBuiltDependencies).toEqual(['esbuild']);
391+
});
392+
393+
it('preserves custom peerDependencyRules when migrating to pnpm-workspace.yaml', () => {
394+
// Project has peerDependencyRules but no pnpm.overrides -- pnpm field is present
395+
// so it should keep using package.json
396+
fs.writeFileSync(
397+
path.join(tmpDir, 'package.json'),
398+
JSON.stringify({
399+
name: 'test',
400+
devDependencies: { vite: '^7.0.0' },
401+
pnpm: {
402+
peerDependencyRules: {
403+
allowAny: ['react', 'vite'],
404+
allowedVersions: { react: '*', vite: '*' },
405+
ignoreMissing: ['@types/node'],
406+
},
407+
},
408+
}),
409+
);
410+
rewriteStandaloneProject(tmpDir, makeWorkspaceInfo(tmpDir, PackageManager.pnpm), true, true);
411+
412+
const pkg = readJson(path.join(tmpDir, 'package.json'));
413+
const pnpm = pkg.pnpm as Record<string, unknown>;
414+
const rules = pnpm.peerDependencyRules as Record<string, unknown>;
415+
// Custom entries preserved, Vite entries merged
416+
expect(rules.allowAny).toEqual(expect.arrayContaining(['react', 'vite', 'vitest']));
417+
// ignoreMissing preserved
418+
expect(rules.ignoreMissing).toEqual(['@types/node']);
419+
});
420+
421+
it('moves remaining non-Vite overrides to pnpm-workspace.yaml', () => {
422+
// Project has NO pnpm field, but we simulate re-migration by creating
423+
// the workspace yaml first, then calling with a package.json that has no pnpm
424+
fs.writeFileSync(
425+
path.join(tmpDir, 'package.json'),
426+
JSON.stringify({ name: 'test', devDependencies: { vite: '^7.0.0' } }),
427+
);
428+
rewriteStandaloneProject(tmpDir, makeWorkspaceInfo(tmpDir, PackageManager.pnpm), true, true);
429+
430+
// Verify workspace yaml has overrides
431+
const yaml = readYaml(path.join(tmpDir, 'pnpm-workspace.yaml'));
432+
expect(yaml).toContain("vite: 'catalog:'");
433+
expect(yaml).toContain("vitest: 'catalog:'");
434+
});
435+
});

packages/cli/src/migration/migrator.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,7 @@ export function rewriteStandaloneProject(
749749
...(isForceOverrideMode() ? { [VITE_PLUS_NAME]: VITE_PLUS_VERSION } : {}),
750750
},
751751
peerDependencyRules: {
752+
...pkg.pnpm?.peerDependencyRules,
752753
allowAny: [
753754
...new Set([...(pkg.pnpm?.peerDependencyRules?.allowAny ?? []), ...overrideKeys]),
754755
],

0 commit comments

Comments
 (0)