Files
renovate/lib/modules/manager/deno/compat.spec.ts
Udit Karode 8a926e8cc7 fix(deno): only collect workspace members when workspaces are declared (#45394)
* fix(deno): only collect workspace members when workspaces are declared

A package.json with no workspaces field has no members to find, but the member
scan ran anyway, and find-packages with no patterns returns every package.json
in the tree. Standalone subprojects were picked up as members of the root lock,
which is what breaks lockFileMaintenance.

The scan now runs only when workspaces are declared.

* test(deno): use await expect().resolves

Required by the `vitest(prefer-expect-resolves)` oxlint rule enabled on
main since this branch was created.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Michael Kriese <michael.kriese@mend.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 12:43:29 +00:00

231 lines
6.5 KiB
TypeScript

import { findPackages } from 'find-packages';
import { fs } from '../../../../test/util.ts';
import { GlobalConfig } from '../../../config/global.ts';
import {
collectPackageJson,
extractDenoCompatiblePackageJson,
} from './compat.ts';
vi.mock('../../../util/fs/index.ts');
// used in detectNodeCompatWorkspaces()
vi.mock('find-packages', () => ({
findPackages: vi.fn(),
}));
describe('modules/manager/deno/compat', () => {
describe('extractDenoCompatiblePackageJson()', () => {
it('returns null if invalid package.json', async () => {
fs.getSiblingFileName.mockReturnValueOnce('package.json');
fs.readLocalFile.mockResolvedValueOnce('invalid');
const result = await extractDenoCompatiblePackageJson('package.json');
expect(result).toBeNull();
});
it('handles null response', async () => {
fs.getSiblingFileName.mockReturnValueOnce('package.json');
fs.readLocalFile.mockResolvedValueOnce(
// This package.json returns null from the extractor
JSON.stringify({
_id: 1,
_args: 1,
_from: 1,
}),
);
const result = await extractDenoCompatiblePackageJson('package.json');
expect(result).toBeNull();
});
});
describe('collectPackageJson()', () => {
beforeAll(() => {
GlobalConfig.set({ localDir: '' });
});
it('node-compat package.json', async () => {
vi.mocked(findPackages).mockResolvedValue([
{ dir: '.', manifest: {}, writeProjectManifest: Promise.resolve },
]);
fs.getSiblingFileName.mockReturnValueOnce('package.json');
fs.readLocalFile.mockResolvedValueOnce(
JSON.stringify({
dependencies: {
dep1: '1.0.0',
},
}),
);
await expect(collectPackageJson('deno.lock')).resolves.toEqual([
{
deps: [
{
currentValue: '1.0.0',
datasource: 'npm',
depName: 'dep1',
depType: 'dependencies',
prettyDepType: 'dependency',
},
],
extractedConstraints: {},
lockFiles: ['deno.lock'],
managerData: {
workspaces: undefined,
},
packageFile: 'package.json',
},
]);
});
it('skips nested package.json when no workspaces are declared', async () => {
vi.mocked(findPackages).mockResolvedValue([
{ dir: 'sub', manifest: {}, writeProjectManifest: Promise.resolve },
]);
fs.getSiblingFileName.mockReturnValueOnce('package.json');
fs.readLocalFile
.mockResolvedValueOnce(
JSON.stringify({
dependencies: {
dep1: '1.0.0',
},
}),
)
.mockResolvedValueOnce(
JSON.stringify({
dependencies: {
dep2: '2.0.0',
},
}),
);
await expect(collectPackageJson('deno.lock')).resolves.toEqual([
{
deps: [
{
currentValue: '1.0.0',
datasource: 'npm',
depName: 'dep1',
depType: 'dependencies',
prettyDepType: 'dependency',
},
],
extractedConstraints: {},
lockFiles: ['deno.lock'],
managerData: {
workspaces: undefined,
},
packageFile: 'package.json',
},
]);
});
it('handles workspaces with valid workspace member', async () => {
vi.mocked(findPackages).mockResolvedValue([
{
dir: 'packages/pkg1',
manifest: {},
writeProjectManifest: Promise.resolve,
},
]);
fs.getSiblingFileName.mockReturnValueOnce('package.json');
fs.readLocalFile
.mockResolvedValueOnce(
JSON.stringify({
workspaces: ['packages/*'],
dependencies: {
dep1: '1.0.0',
},
}),
)
.mockResolvedValueOnce(
JSON.stringify({
dependencies: {
dep2: '2.0.0',
},
}),
);
await expect(collectPackageJson('deno.lock')).resolves.toEqual([
{
deps: [
{
currentValue: '1.0.0',
datasource: 'npm',
depName: 'dep1',
depType: 'dependencies',
prettyDepType: 'dependency',
},
],
extractedConstraints: {},
lockFiles: ['deno.lock'],
managerData: {
workspaces: ['packages/*'],
},
packageFile: 'package.json',
},
{
deps: [
{
currentValue: '2.0.0',
datasource: 'npm',
depName: 'dep2',
depType: 'dependencies',
prettyDepType: 'dependency',
},
],
extractedConstraints: {},
lockFiles: ['deno.lock'],
managerData: {
packageName: undefined,
workspaces: undefined,
},
packageFile: 'packages/pkg1/package.json',
},
]);
});
it('returns empty array when rootPackageFile is null', async () => {
fs.getSiblingFileName.mockReturnValueOnce('package.json');
fs.readLocalFile.mockResolvedValueOnce(null);
const result = await collectPackageJson('deno.lock');
expect(result).toEqual([]);
});
it('handles null packageFile in workspace members', async () => {
vi.mocked(findPackages).mockResolvedValue([
{
dir: 'workspace',
manifest: {},
writeProjectManifest: Promise.resolve,
},
]);
fs.getSiblingFileName.mockReturnValueOnce('package.json');
fs.readLocalFile
.mockResolvedValueOnce(
JSON.stringify({
workspaces: ['workspace'],
dependencies: {
dep1: '1.0.0',
},
}),
)
.mockResolvedValueOnce(null);
const result = await collectPackageJson('deno.lock');
expect(result).toEqual([
{
deps: [
{
currentValue: '1.0.0',
datasource: 'npm',
depName: 'dep1',
depType: 'dependencies',
prettyDepType: 'dependency',
},
],
extractedConstraints: {},
lockFiles: ['deno.lock'],
managerData: {
workspaces: ['workspace'],
},
packageFile: 'package.json',
},
]);
});
});
});