Add overrideTargetPaths test utility and fix rebase issues

Adds `overrideTargetPaths` to `@backstage/cli-common/testUtils` for
cleanly mocking `targetPaths` in tests without `jest.mock` or
`jest.spyOn`. Migrates all existing test mocks to use the new utility.

Also fixes translations module imports broken by the rebase.

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Patrik Oldsberg
2026-02-23 14:20:59 +01:00
parent 553e727d5f
commit ebc01ef04d
18 changed files with 210 additions and 121 deletions
+2 -8
View File
@@ -15,21 +15,15 @@
*/
import { createMockDirectory } from '@backstage/backend-test-utils';
import { targetPaths } from '@backstage/cli-common';
import { overrideTargetPaths } from '@backstage/cli-common/testUtils';
import { getHasYarnPlugin } from './yarnPlugin';
const mockDir = createMockDirectory();
overrideTargetPaths(mockDir.path);
describe('getHasYarnPlugin', () => {
beforeEach(() => {
mockDir.clear();
jest
.spyOn(targetPaths, 'resolveRoot')
.mockImplementation((...args: string[]) => mockDir.resolve(...args));
});
afterEach(() => {
jest.restoreAllMocks();
});
it('should return false when .yarnrc.yml does not exist', async () => {
@@ -16,8 +16,9 @@
import { PackageGraph } from '@backstage/cli-node';
import { findTargetPackages } from './start';
import { posix } from 'node:path';
import { targetPaths } from '@backstage/cli-common';
import { overrideTargetPaths } from '@backstage/cli-common/testUtils';
overrideTargetPaths({ dir: '/root', rootDir: '/root' });
const mocks = {
app: {
@@ -97,11 +98,6 @@ const mocks = {
describe('findTargetPackages', () => {
beforeEach(() => {
jest.clearAllMocks();
jest
.spyOn(targetPaths, 'resolveRoot')
.mockImplementation((...parts: string[]) => {
return posix.resolve('/root', ...parts);
});
});
it('should select default packages', async () => {
@@ -15,24 +15,12 @@
*/
import { createMockDirectory } from '@backstage/backend-test-utils';
import { overrideTargetPaths } from '@backstage/cli-common/testUtils';
import { Command } from 'commander';
import { findRoleFromCommand } from './role';
const mockDir = createMockDirectory();
jest.mock('@backstage/cli-common', () => ({
...jest.requireActual('@backstage/cli-common'),
targetPaths: {
get dir() {
return mockDir.path;
},
get rootDir() {
return mockDir.path;
},
resolve: (...args: string[]) => mockDir.resolve(...args),
resolveRoot: (...args: string[]) => mockDir.resolve(...args),
},
}));
overrideTargetPaths(mockDir.path);
describe('findRoleFromCommand', () => {
function mkCommand(args?: string) {
@@ -16,6 +16,7 @@
import fs from 'fs-extra';
import { Command } from 'commander';
import * as runObj from '@backstage/cli-common';
import { overrideTargetPaths } from '@backstage/cli-common/testUtils';
import bump, { bumpBackstageJsonVersion, createVersionFinder } from './bump';
import { registerMswTestHooks, withLogCollector } from '@backstage/test-utils';
import { YarnInfoInspectData } from '../../../../lib/versioning/packages';
@@ -64,16 +65,6 @@ jest.mock('@backstage/cli-common', () => {
const actual = jest.requireActual('@backstage/cli-common');
return {
...actual,
targetPaths: {
get dir() {
return mockDir.path;
},
get rootDir() {
return mockDir.path;
},
resolve: (...args: string[]) => mockDir.resolve(...args),
resolveRoot: (...args: string[]) => mockDir.resolve(...args),
},
findPaths: () => ({
resolveTargetRoot: (...args: string[]) => mockDir.resolve(...args),
get targetDir() {
@@ -147,6 +138,7 @@ const expectLogsToMatch = (
describe('bump', () => {
mockDir = createMockDirectory();
beforeAll(() => overrideTargetPaths(mockDir.path));
beforeEach(() => {
mockFetchPackageInfo.mockImplementation(async name => ({
@@ -953,6 +945,7 @@ describe('bump', () => {
describe('bumpBackstageJsonVersion', () => {
mockDir = createMockDirectory();
beforeAll(() => overrideTargetPaths(mockDir.path));
afterEach(() => {
jest.resetAllMocks();
@@ -1089,6 +1082,8 @@ describe('environment variables', () => {
const worker = setupServer();
registerMswTestHooks(worker);
beforeAll(() => overrideTargetPaths(mockDir.path));
beforeEach(() => {
delete process.env.BACKSTAGE_MANIFEST_FILE;
process.env.BACKSTAGE_VERSIONS_BASE_URL = 'https://custom.example.com';
@@ -18,6 +18,7 @@ import {
createMockDirectory,
} from '@backstage/backend-test-utils';
import * as runObj from '@backstage/cli-common';
import { overrideTargetPaths } from '@backstage/cli-common/testUtils';
import migrate from './migrate';
import { withLogCollector } from '@backstage/test-utils';
import fs from 'fs-extra';
@@ -37,16 +38,6 @@ jest.mock('@backstage/cli-common', () => {
const actual = jest.requireActual('@backstage/cli-common');
return {
...actual,
targetPaths: {
get dir() {
return mockDir.path;
},
get rootDir() {
return mockDir.path;
},
resolve: (...args: string[]) => mockDir.resolve(...args),
resolveRoot: (...args: string[]) => mockDir.resolve(...args),
},
findPaths: () => ({
resolveTargetRoot: (...args: string[]) => mockDir.resolve(...args),
get targetDir() {
@@ -66,6 +57,7 @@ function expectLogsToMatch(receivedLogs: String[], expected: String[]): void {
describe('versions:migrate', () => {
mockDir = createMockDirectory();
beforeAll(() => overrideTargetPaths(mockDir.path));
beforeEach(() => {
(runObj.run as jest.Mock).mockReturnValue({
@@ -17,7 +17,10 @@
import { relative as relativePath } from 'node:path';
import { writeTemplateContents } from './writeTemplateContents';
import { createMockDirectory } from '@backstage/backend-test-utils';
import { targetPaths } from '@backstage/cli-common';
import { overrideTargetPaths } from '@backstage/cli-common/testUtils';
const mockDir = createMockDirectory();
overrideTargetPaths(mockDir.path);
const baseConfig = {
version: '0.1.0',
@@ -26,14 +29,14 @@ const baseConfig = {
};
describe('writeTemplateContents', () => {
const mockDir = createMockDirectory();
beforeEach(() => {
mockDir.clear();
mockDir.setContent({
'package.json': JSON.stringify({
workspaces: { packages: ['packages/*', 'plugins/*'] },
}),
});
jest.resetAllMocks();
jest
.spyOn(targetPaths, 'resolveRoot')
.mockImplementation((...args: string[]) => mockDir.resolve(...args));
});
it('should write an empty template', async () => {
@@ -53,7 +56,11 @@ describe('writeTemplateContents', () => {
);
expect(relativePath(mockDir.path, targetDir)).toBe('plugins/plugin-test');
expect(mockDir.content()).toEqual({});
expect(mockDir.content()).toEqual({
'package.json': JSON.stringify({
workspaces: { packages: ['packages/*', 'plugins/*'] },
}),
});
});
it('should write template with various files', async () => {
@@ -87,6 +94,9 @@ describe('writeTemplateContents', () => {
);
expect(mockDir.content()).toEqual({
'package.json': JSON.stringify({
workspaces: { packages: ['packages/*', 'plugins/*'] },
}),
out: {
'test.txt': 'test',
'plugin.txt': 'id=test',
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { paths } from '../../../lib/paths';
import { targetPaths } from '@backstage/cli-common';
import fs from 'fs-extra';
import { dirname, resolve as resolvePath } from 'node:path';
import {
@@ -41,14 +41,14 @@ export default async (options: ExportOptions) => {
validatePattern(options.pattern);
const targetPackageJson = await readTargetPackage(
paths.targetDir,
paths.targetRoot,
targetPaths.dir,
targetPaths.rootDir,
);
const outputDir = resolvePath(paths.targetDir, options.output);
const outputDir = resolvePath(targetPaths.dir, options.output);
const manifestPath = resolvePath(outputDir, 'manifest.json');
const tsconfigPath = paths.resolveTargetRoot('tsconfig.json');
const tsconfigPath = targetPaths.resolveRoot('tsconfig.json');
if (!(await fs.pathExists(tsconfigPath))) {
throw new Error(
`No tsconfig.json found at ${tsconfigPath}. ` +
@@ -61,7 +61,7 @@ export default async (options: ExportOptions) => {
);
const packages = await discoverFrontendPackages(
targetPackageJson,
paths.targetDir,
targetPaths.dir,
);
console.log(`Found ${packages.length} frontend packages to scan`);
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { paths } from '../../../lib/paths';
import { targetPaths } from '@backstage/cli-common';
import fs from 'fs-extra';
import {
resolve as resolvePath,
@@ -45,11 +45,11 @@ interface Manifest {
}
export default async (options: ImportOptions) => {
await readTargetPackage(paths.targetDir, paths.targetRoot);
await readTargetPackage(targetPaths.dir, targetPaths.rootDir);
const inputDir = resolvePath(paths.targetDir, options.input);
const inputDir = resolvePath(targetPaths.dir, options.input);
const manifestPath = resolvePath(inputDir, 'manifest.json');
const outputPath = resolvePath(paths.targetDir, options.output);
const outputPath = resolvePath(targetPaths.dir, options.output);
if (!(await fs.pathExists(manifestPath))) {
throw new Error(