diff --git a/.changeset/serious-ravens-serve.md b/.changeset/serious-ravens-serve.md new file mode 100644 index 0000000000..66cbd795c0 --- /dev/null +++ b/.changeset/serious-ravens-serve.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +The scaffolder-module template now recommends usage of `createMockDirectory` instead of `mock-fs`. diff --git a/packages/cli/package.json b/packages/cli/package.json index 36aee311f7..315ca12352 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -158,7 +158,6 @@ "@types/http-proxy": "^1.17.4", "@types/inquirer": "^8.1.3", "@types/minimatch": "^5.0.0", - "@types/mock-fs": "^4.13.0", "@types/node": "^18.17.8", "@types/npm-packlist": "^3.0.0", "@types/recursive-readdir": "^2.2.0", @@ -169,7 +168,6 @@ "@types/terser-webpack-plugin": "^5.0.4", "@types/yarnpkg__lockfile": "^1.1.4", "del": "^7.0.0", - "mock-fs": "^5.2.0", "msw": "^1.0.0", "nodemon": "^3.0.1", "ts-node": "^10.0.0", diff --git a/packages/cli/src/commands/create-plugin/createPlugin.test.ts b/packages/cli/src/commands/create-plugin/createPlugin.test.ts index aa59f94fb4..84af6ebf69 100644 --- a/packages/cli/src/commands/create-plugin/createPlugin.test.ts +++ b/packages/cli/src/commands/create-plugin/createPlugin.test.ts @@ -16,23 +16,21 @@ import fs from 'fs-extra'; import path from 'path'; -import mockFs from 'mock-fs'; import { movePlugin } from './createPlugin'; +import { createMockDirectory } from '@backstage/backend-test-utils'; const id = 'testPluginMock'; describe('createPlugin', () => { - afterEach(() => { - mockFs.restore(); - }); + const mockDir = createMockDirectory(); describe('movePlugin', () => { it('should move the temporary plugin directory to its final place', async () => { - mockFs({ + mockDir.setContent({ [id]: {}, }); - const tempDir = id; - const pluginDir = path.join('test-temp', 'plugins', id); + const tempDir = mockDir.resolve(id); + const pluginDir = mockDir.resolve('test-temp/plugins', id); await movePlugin(tempDir, pluginDir, id); await expect(fs.pathExists(pluginDir)).resolves.toBe(true); diff --git a/packages/cli/src/commands/versions/bump.test.ts b/packages/cli/src/commands/versions/bump.test.ts index 7af6c6160b..d00b4ce8da 100644 --- a/packages/cli/src/commands/versions/bump.test.ts +++ b/packages/cli/src/commands/versions/bump.test.ts @@ -15,10 +15,7 @@ */ import fs from 'fs-extra'; -import mockFs from 'mock-fs'; import { Command } from 'commander'; -import { resolve as resolvePath } from 'path'; -import { paths } from '../../lib/paths'; import * as runObj from '../../lib/run'; import bump, { bumpBackstageJsonVersion, createVersionFinder } from './bump'; import { @@ -30,6 +27,10 @@ import { setupServer } from 'msw/node'; import { rest } from 'msw'; import { NotFoundError } from '@backstage/errors'; import { Lockfile } from '../../lib/versioning/Lockfile'; +import { + MockDirectory, + createMockDirectory, +} from '@backstage/backend-test-utils'; // Avoid mutating the global http(s) agent used in other tests jest.mock('global-agent/bootstrap', () => {}); @@ -56,6 +57,19 @@ jest.mock('ora', () => ({ }, })); +let mockDir: MockDirectory; + +jest.mock('../../lib/paths', () => ({ + paths: { + resolveTargetRoot(filename: string) { + return mockDir.resolve(filename); + }, + get targetDir() { + return mockDir.path; + }, + }, +})); + jest.mock('../../lib/run', () => { return { run: jest.fn(), @@ -117,7 +131,17 @@ const lockfileMockResult = `${HEADER} version "1.0.0" `; +// Avoid flakes by comparing sorted log lines. File system access is async, which leads to the log line order being indeterministic +const expectLogsToMatch = ( + recievedLogs: String[], + expected: String[], +): void => { + expect(recievedLogs.filter(Boolean).sort()).toEqual(expected.sort()); +}; + describe('bump', () => { + mockDir = createMockDirectory(); + beforeEach(() => { mockFetchPackageInfo.mockImplementation(async name => ({ name: name, @@ -128,7 +152,6 @@ describe('bump', () => { }); afterEach(() => { - mockFs.restore(); jest.resetAllMocks(); }); @@ -136,31 +159,34 @@ describe('bump', () => { setupRequestMockHandlers(worker); it('should bump backstage dependencies', async () => { - mockFs({ - '/yarn.lock': lockfileMock, - '/package.json': JSON.stringify({ + mockDir.setContent({ + 'yarn.lock': lockfileMock, + 'package.json': JSON.stringify({ workspaces: { packages: ['packages/*'], }, }), - '/packages/a/package.json': JSON.stringify({ - name: 'a', - dependencies: { - '@backstage/core': '^1.0.5', + packages: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + dependencies: { + '@backstage/core': '^1.0.5', + }, + }), }, - }), - '/packages/b/package.json': JSON.stringify({ - name: 'b', - dependencies: { - '@backstage/core': '^1.0.3', - '@backstage/theme': '^1.0.0', + b: { + 'package.json': JSON.stringify({ + name: 'b', + dependencies: { + '@backstage/core': '^1.0.3', + '@backstage/theme': '^1.0.0', + }, + }), }, - }), + }, }); - jest - .spyOn(paths, 'resolveTargetRoot') - .mockImplementation((...path) => resolvePath('/', ...path)); jest.spyOn(runObj, 'run').mockResolvedValue(undefined); worker.use( rest.get( @@ -177,7 +203,7 @@ describe('bump', () => { const { log: logs } = await withLogCollector(['log'], async () => { await bump({ pattern: null, release: 'main' } as unknown as Command); }); - expect(logs.filter(Boolean)).toEqual([ + expectLogsToMatch(logs, [ 'Using default pattern glob @backstage/*', 'Checking for updates of @backstage/core', 'Checking for updates of @backstage/theme', @@ -208,17 +234,24 @@ describe('bump', () => { expect.any(Object), ); - const lockfileContents = await fs.readFile('/yarn.lock', 'utf8'); + const lockfileContents = await fs.readFile( + mockDir.resolve('yarn.lock'), + 'utf8', + ); expect(lockfileContents).toBe(lockfileMockResult); - const packageA = await fs.readJson('/packages/a/package.json'); + const packageA = await fs.readJson( + mockDir.resolve('packages/a/package.json'), + ); expect(packageA).toEqual({ name: 'a', dependencies: { '@backstage/core': '^1.0.6', }, }); - const packageB = await fs.readJson('/packages/b/package.json'); + const packageB = await fs.readJson( + mockDir.resolve('packages/b/package.json'), + ); expect(packageB).toEqual({ name: 'b', dependencies: { @@ -229,31 +262,34 @@ describe('bump', () => { }); it('should bump backstage dependencies but not install them', async () => { - mockFs({ - '/yarn.lock': lockfileMock, - '/package.json': JSON.stringify({ + mockDir.setContent({ + 'yarn.lock': lockfileMock, + 'package.json': JSON.stringify({ workspaces: { packages: ['packages/*'], }, }), - '/packages/a/package.json': JSON.stringify({ - name: 'a', - dependencies: { - '@backstage/core': '^1.0.5', + packages: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + dependencies: { + '@backstage/core': '^1.0.5', + }, + }), }, - }), - '/packages/b/package.json': JSON.stringify({ - name: 'b', - dependencies: { - '@backstage/core': '^1.0.3', - '@backstage/theme': '^1.0.0', + b: { + 'package.json': JSON.stringify({ + name: 'b', + dependencies: { + '@backstage/core': '^1.0.3', + '@backstage/theme': '^1.0.0', + }, + }), }, - }), + }, }); - jest - .spyOn(paths, 'resolveTargetRoot') - .mockImplementation((...path) => resolvePath('/', ...path)); jest.spyOn(runObj, 'run').mockResolvedValue(undefined); worker.use( rest.get( @@ -274,7 +310,7 @@ describe('bump', () => { skipInstall: true, } as unknown as Command); }); - expect(logs.filter(Boolean)).toEqual([ + expectLogsToMatch(logs, [ 'Using default pattern glob @backstage/*', 'Checking for updates of @backstage/core', 'Checking for updates of @backstage/theme', @@ -304,17 +340,24 @@ describe('bump', () => { expect.any(Object), ); - const lockfileContents = await fs.readFile('/yarn.lock', 'utf8'); + const lockfileContents = await fs.readFile( + mockDir.resolve('yarn.lock'), + 'utf8', + ); expect(lockfileContents).toBe(lockfileMockResult); - const packageA = await fs.readJson('/packages/a/package.json'); + const packageA = await fs.readJson( + mockDir.resolve('packages/a/package.json'), + ); expect(packageA).toEqual({ name: 'a', dependencies: { '@backstage/core': '^1.0.6', }, }); - const packageB = await fs.readJson('/packages/b/package.json'); + const packageB = await fs.readJson( + mockDir.resolve('packages/b/package.json'), + ); expect(packageB).toEqual({ name: 'b', dependencies: { @@ -325,31 +368,34 @@ describe('bump', () => { }); it('should prefer dependency versions from release manifest', async () => { - mockFs({ - '/yarn.lock': lockfileMock, - '/package.json': JSON.stringify({ + mockDir.setContent({ + 'yarn.lock': lockfileMock, + 'package.json': JSON.stringify({ workspaces: { packages: ['packages/*'], }, }), - '/packages/a/package.json': JSON.stringify({ - name: 'a', - dependencies: { - '@backstage/core': '^1.0.5', + packages: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + dependencies: { + '@backstage/core': '^1.0.5', + }, + }), }, - }), - '/packages/b/package.json': JSON.stringify({ - name: 'b', - dependencies: { - '@backstage/core': '^1.0.3', - '@backstage/theme': '^1.0.0', + b: { + 'package.json': JSON.stringify({ + name: 'b', + dependencies: { + '@backstage/core': '^1.0.3', + '@backstage/theme': '^1.0.0', + }, + }), }, - }), + }, }); - jest - .spyOn(paths, 'resolveTargetRoot') - .mockImplementation((...path) => resolvePath('/', ...path)); jest.spyOn(runObj, 'run').mockResolvedValue(undefined); worker.use( rest.get( @@ -376,7 +422,7 @@ describe('bump', () => { const { log: logs } = await withLogCollector(['log'], async () => { await bump({ pattern: null, release: 'main' } as unknown as Command); }); - expect(logs.filter(Boolean)).toEqual([ + expectLogsToMatch(logs, [ 'Using default pattern glob @backstage/*', 'Checking for updates of @backstage/core', 'Checking for updates of @backstage/theme', @@ -408,17 +454,24 @@ describe('bump', () => { expect.any(Object), ); - const lockfileContents = await fs.readFile('/yarn.lock', 'utf8'); + const lockfileContents = await fs.readFile( + mockDir.resolve('yarn.lock'), + 'utf8', + ); expect(lockfileContents).toBe(lockfileMockResult); - const packageA = await fs.readJson('/packages/a/package.json'); + const packageA = await fs.readJson( + mockDir.resolve('packages/a/package.json'), + ); expect(packageA).toEqual({ name: 'a', dependencies: { '@backstage/core': '^1.0.6', }, }); - const packageB = await fs.readJson('/packages/b/package.json'); + const packageB = await fs.readJson( + mockDir.resolve('packages/b/package.json'), + ); expect(packageB).toEqual({ name: 'b', dependencies: { @@ -429,30 +482,33 @@ describe('bump', () => { }); it('should only bump packages in the manifest when a specific release is specified', async () => { - mockFs({ - '/yarn.lock': lockfileMock, - '/package.json': JSON.stringify({ + mockDir.setContent({ + 'yarn.lock': lockfileMock, + 'package.json': JSON.stringify({ workspaces: { packages: ['packages/*'], }, }), - '/packages/a/package.json': JSON.stringify({ - name: 'a', - dependencies: { - '@backstage/core': '^1.0.5', + packages: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + dependencies: { + '@backstage/core': '^1.0.5', + }, + }), }, - }), - '/packages/b/package.json': JSON.stringify({ - name: 'b', - dependencies: { - '@backstage/core': '^1.0.3', - '@backstage/theme': '^1.0.0', + b: { + 'package.json': JSON.stringify({ + name: 'b', + dependencies: { + '@backstage/core': '^1.0.3', + '@backstage/theme': '^1.0.0', + }, + }), }, - }), + }, }); - jest - .spyOn(paths, 'resolveTargetRoot') - .mockImplementation((...path) => resolvePath('/', ...path)); jest.spyOn(runObj, 'run').mockResolvedValue(undefined); worker.use( @@ -472,14 +528,18 @@ describe('bump', () => { expect(runObj.run).toHaveBeenCalledTimes(0); - const packageA = await fs.readJson('/packages/a/package.json'); + const packageA = await fs.readJson( + mockDir.resolve('packages/a/package.json'), + ); expect(packageA).toEqual({ name: 'a', dependencies: { '@backstage/core': '^1.0.5', }, }); - const packageB = await fs.readJson('/packages/b/package.json'); + const packageB = await fs.readJson( + mockDir.resolve('packages/b/package.json'), + ); expect(packageB).toEqual({ name: 'b', dependencies: { @@ -489,32 +549,36 @@ describe('bump', () => { }); }); + // eslint-disable-next-line jest/expect-expect it('should prefer versions from the highest manifest version when main is not specified', async () => { - mockFs({ - '/yarn.lock': lockfileMock, - '/package.json': JSON.stringify({ + mockDir.setContent({ + 'yarn.lock': lockfileMock, + 'package.json': JSON.stringify({ workspaces: { packages: ['packages/*'], }, }), - '/packages/a/package.json': JSON.stringify({ - name: 'a', - dependencies: { - '@backstage/core': '^1.0.5', + packages: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + dependencies: { + '@backstage/core': '^1.0.5', + }, + }), }, - }), - '/packages/b/package.json': JSON.stringify({ - name: 'b', - dependencies: { - '@backstage/core': '^1.0.3', - '@backstage/theme': '^1.0.0', + b: { + 'package.json': JSON.stringify({ + name: 'b', + dependencies: { + '@backstage/core': '^1.0.3', + '@backstage/theme': '^1.0.0', + }, + }), }, - }), + }, }); - jest - .spyOn(paths, 'resolveTargetRoot') - .mockImplementation((...path) => resolvePath('/', ...path)); jest.spyOn(runObj, 'run').mockResolvedValue(undefined); worker.use( rest.get( @@ -561,7 +625,7 @@ describe('bump', () => { const { log: logs } = await withLogCollector(['log'], async () => { await bump({ pattern: null, release: 'next' } as unknown as Command); }); - expect(logs.filter(Boolean)).toEqual([ + expectLogsToMatch(logs, [ 'Using default pattern glob @backstage/*', 'Checking for updates of @backstage/core', 'Checking for updates of @backstage/theme', @@ -609,35 +673,38 @@ describe('bump', () => { "@backstage/theme@^1.0.0": version "1.0.0" `; - mockFs({ - '/yarn.lock': customLockfileMock, - '/package.json': JSON.stringify({ + mockDir.setContent({ + 'yarn.lock': customLockfileMock, + 'package.json': JSON.stringify({ workspaces: { packages: ['packages/*'], }, }), - '/packages/a/package.json': JSON.stringify({ - name: 'a', - dependencies: { - '@backstage/core': '^1.0.5', - '@backstage-extra/custom': '^1.0.1', - '@backstage-extra/custom-two': '^1.0.0', + packages: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + dependencies: { + '@backstage/core': '^1.0.5', + '@backstage-extra/custom': '^1.0.1', + '@backstage-extra/custom-two': '^1.0.0', + }, + }), }, - }), - '/packages/b/package.json': JSON.stringify({ - name: 'b', - dependencies: { - '@backstage/core': '^1.0.3', - '@backstage/theme': '^1.0.0', - '@backstage-extra/custom': '^1.1.0', - '@backstage-extra/custom-two': '^1.0.0', + b: { + 'package.json': JSON.stringify({ + name: 'b', + dependencies: { + '@backstage/core': '^1.0.3', + '@backstage/theme': '^1.0.0', + '@backstage-extra/custom': '^1.1.0', + '@backstage-extra/custom-two': '^1.0.0', + }, + }), }, - }), + }, }); - jest - .spyOn(paths, 'resolveTargetRoot') - .mockImplementation((...path) => resolvePath('/', ...path)); jest.spyOn(runObj, 'run').mockResolvedValue(undefined); worker.use( rest.get( @@ -657,7 +724,7 @@ describe('bump', () => { release: 'main', } as any); }); - expect(logs.filter(Boolean)).toEqual([ + expectLogsToMatch(logs, [ 'Using custom pattern glob @{backstage,backstage-extra}/*', 'Checking for updates of @backstage/core', 'Checking for updates of @backstage-extra/custom', @@ -696,10 +763,15 @@ describe('bump', () => { expect.any(Object), ); - const lockfileContents = await fs.readFile('/yarn.lock', 'utf8'); + const lockfileContents = await fs.readFile( + mockDir.resolve('yarn.lock'), + 'utf8', + ); expect(lockfileContents).toEqual(customLockfileMockResult); - const packageA = await fs.readJson('/packages/a/package.json'); + const packageA = await fs.readJson( + mockDir.resolve('packages/a/package.json'), + ); expect(packageA).toEqual({ name: 'a', dependencies: { @@ -708,7 +780,9 @@ describe('bump', () => { '@backstage/core': '^1.0.6', }, }); - const packageB = await fs.readJson('/packages/b/package.json'); + const packageB = await fs.readJson( + mockDir.resolve('packages/b/package.json'), + ); expect(packageB).toEqual({ name: 'b', dependencies: { @@ -721,31 +795,34 @@ describe('bump', () => { }); it('should ignore not found packages', async () => { - mockFs({ - '/yarn.lock': lockfileMockResult, - '/package.json': JSON.stringify({ + mockDir.setContent({ + 'yarn.lock': lockfileMockResult, + 'package.json': JSON.stringify({ workspaces: { packages: ['packages/*'], }, }), - '/packages/a/package.json': JSON.stringify({ - name: 'a', - dependencies: { - '@backstage/core': '^1.0.5', + packages: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + dependencies: { + '@backstage/core': '^1.0.5', + }, + }), }, - }), - '/packages/b/package.json': JSON.stringify({ - name: 'b', - dependencies: { - '@backstage/core': '^1.0.3', - '@backstage/theme': '^2.0.0', + b: { + 'package.json': JSON.stringify({ + name: 'b', + dependencies: { + '@backstage/core': '^1.0.3', + '@backstage/theme': '^2.0.0', + }, + }), }, - }), + }, }); - jest - .spyOn(paths, 'resolveTargetRoot') - .mockImplementation((...path) => resolvePath('/', ...path)); mockFetchPackageInfo.mockRejectedValue(new NotFoundError('Nope')); jest.spyOn(runObj, 'run').mockResolvedValue(undefined); worker.use( @@ -763,7 +840,7 @@ describe('bump', () => { const { log: logs } = await withLogCollector(['log'], async () => { await bump({ pattern: null, release: 'main' } as unknown as Command); }); - expect(logs.filter(Boolean)).toEqual([ + expectLogsToMatch(logs, [ 'Using default pattern glob @backstage/*', 'Checking for updates of @backstage/core', 'Checking for updates of @backstage/theme', @@ -778,17 +855,24 @@ describe('bump', () => { expect(runObj.run).toHaveBeenCalledTimes(0); - const lockfileContents = await fs.readFile('/yarn.lock', 'utf8'); + const lockfileContents = await fs.readFile( + mockDir.resolve('yarn.lock'), + 'utf8', + ); expect(lockfileContents).toBe(lockfileMockResult); - const packageA = await fs.readJson('/packages/a/package.json'); + const packageA = await fs.readJson( + mockDir.resolve('packages/a/package.json'), + ); expect(packageA).toEqual({ name: 'a', dependencies: { '@backstage/core': '^1.0.5', // not bumped }, }); - const packageB = await fs.readJson('/packages/b/package.json'); + const packageB = await fs.readJson( + mockDir.resolve('packages/b/package.json'), + ); expect(packageB).toEqual({ name: 'b', dependencies: { @@ -798,6 +882,7 @@ describe('bump', () => { }); }); + // eslint-disable-next-line jest/expect-expect it('should log duplicates', async () => { jest.spyOn(Lockfile.prototype, 'analyze').mockReturnValue({ invalidRanges: [], @@ -826,31 +911,34 @@ describe('bump', () => { }, ], }); - mockFs({ - '/yarn.lock': lockfileMock, - '/package.json': JSON.stringify({ + mockDir.setContent({ + 'yarn.lock': lockfileMock, + 'package.json': JSON.stringify({ workspaces: { packages: ['packages/*'], }, }), - '/packages/a/package.json': JSON.stringify({ - name: 'a', - dependencies: { - '@backstage/core': '^1.0.5', + packages: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + dependencies: { + '@backstage/core': '^1.0.5', + }, + }), }, - }), - '/packages/b/package.json': JSON.stringify({ - name: 'b', - dependencies: { - '@backstage/core': '^1.0.3', - '@backstage/theme': '^1.0.0', + b: { + 'package.json': JSON.stringify({ + name: 'b', + dependencies: { + '@backstage/core': '^1.0.3', + '@backstage/theme': '^1.0.0', + }, + }), }, - }), + }, }); - jest - .spyOn(paths, 'resolveTargetRoot') - .mockImplementation((...path) => resolvePath('/', ...path)); jest.spyOn(runObj, 'run').mockResolvedValue(undefined); worker.use( rest.get( @@ -867,7 +955,7 @@ describe('bump', () => { const { log: logs } = await withLogCollector(['log'], async () => { await bump({ pattern: null, release: 'main' } as unknown as Command); }); - expect(logs.filter(Boolean)).toEqual([ + expectLogsToMatch(logs, [ 'Using default pattern glob @backstage/*', 'Checking for updates of @backstage/core', 'Checking for updates of @backstage/theme', @@ -891,24 +979,23 @@ describe('bump', () => { }); describe('bumpBackstageJsonVersion', () => { + mockDir = createMockDirectory(); + afterEach(() => { - mockFs.restore(); jest.resetAllMocks(); }); it('should bump version in backstage.json', async () => { - mockFs({ - '/backstage.json': JSON.stringify({ version: '0.0.1' }), + mockDir.setContent({ + 'backstage.json': JSON.stringify({ version: '0.0.1' }), }); - paths.targetDir = '/'; - jest - .spyOn(paths, 'resolveTargetRoot') - .mockImplementation((...path) => resolvePath('/', ...path)); const { log } = await withLogCollector(async () => { await bumpBackstageJsonVersion('1.4.1'); }); - expect(await fs.readJson('/backstage.json')).toEqual({ version: '1.4.1' }); + expect(await fs.readJson(mockDir.resolve('backstage.json'))).toEqual({ + version: '1.4.1', + }); expect(log).toEqual([ 'Upgraded from release 0.0.1 to 1.4.1, please review these template changes:', undefined, @@ -918,17 +1005,15 @@ describe('bumpBackstageJsonVersion', () => { }); it("should create backstage.json if doesn't exist", async () => { - mockFs({}); - paths.targetDir = '/'; + mockDir.clear(); // empty temp test folder const latest = '1.4.1'; - jest - .spyOn(paths, 'resolveTargetRoot') - .mockImplementation((...path) => resolvePath('/', ...path)); const { log } = await withLogCollector(async () => { await bumpBackstageJsonVersion(latest); }); - expect(await fs.readJson('/backstage.json')).toEqual({ version: latest }); + expect(await fs.readJson(mockDir.resolve('backstage.json'))).toEqual({ + version: latest, + }); expect(log).toEqual([ 'Your project is now at version 1.4.1, which has been written to backstage.json', ]); diff --git a/packages/cli/src/lib/builder/plugins.test.ts b/packages/cli/src/lib/builder/plugins.test.ts index dcbdc55cc0..f6984dd67e 100644 --- a/packages/cli/src/lib/builder/plugins.test.ts +++ b/packages/cli/src/lib/builder/plugins.test.ts @@ -15,7 +15,6 @@ */ import fs from 'fs-extra'; -import mockFs from 'mock-fs'; import { NormalizedOutputOptions, OutputAsset, @@ -24,6 +23,7 @@ import { } from 'rollup'; import { forwardFileImports } from './plugins'; +import { createMockDirectory } from '@backstage/backend-test-utils'; const context = { meta: { @@ -91,16 +91,18 @@ describe('forwardFileImports', () => { ); }); - describe('with mock fs', () => { - beforeEach(() => { - mockFs({ - '/dev/src/my-module.ts': '', - '/dev/src/dir/my-image.png': 'my-image', - }); - }); + describe('with createMockDirectory', () => { + const mockDir = createMockDirectory(); - afterEach(() => { - mockFs.restore(); + beforeEach(() => { + mockDir.setContent({ + dev: { + src: { + 'my-module.ts': '', + dir: { 'my-image.png': 'my-image' }, + }, + }, + }); }); it('should extract files', async () => { @@ -111,23 +113,33 @@ describe('forwardFileImports', () => { throw new Error('options.external is not a function'); } - expect(options.external('./my-module', '/dev/src/index.ts', false)).toBe( - false, - ); expect( - options.external('./my-image.png', '/dev/src/dir/index.ts', false), + options.external( + './my-module', + mockDir.resolve('dev/src/index.ts'), + false, + ), + ).toBe(false); + expect( + options.external( + './my-image.png', + mockDir.resolve('dev', 'src', 'dir', 'index.ts'), + false, + ), ).toBe(true); - const outPath = '/dev/dist/dir/my-image.png'; + const outPath = mockDir.resolve('dev', 'dist', 'dir', 'my-image.png'); await expect(fs.pathExists(outPath)).resolves.toBe(false); await plugin.generateBundle?.call( context, - { dir: '/dev/dist' } as NormalizedOutputOptions, + { + dir: mockDir.resolve('dev/dist'), + } as NormalizedOutputOptions, { ['index.js']: { type: 'chunk', - facadeModuleId: '/dev/src/index.ts', + facadeModuleId: mockDir.resolve('dev/src/index.ts'), } as OutputChunk, }, false, // isWrite = false -> no write @@ -136,7 +148,9 @@ describe('forwardFileImports', () => { await plugin.generateBundle?.call( context, - { dir: '/dev/dist' } as NormalizedOutputOptions, + { + dir: mockDir.resolve('dev/dist'), + } as NormalizedOutputOptions, { // output assets should not cause a write ['index.js']: { type: 'asset' } as OutputAsset, @@ -150,11 +164,13 @@ describe('forwardFileImports', () => { // output chunk + isWrite -> generate files await plugin.generateBundle?.call( context, - { dir: '/dev/dist' } as NormalizedOutputOptions, + { + dir: mockDir.resolve('dev/dist'), + } as NormalizedOutputOptions, { ['index.js']: { type: 'chunk', - facadeModuleId: '/dev/src/index.ts', + facadeModuleId: mockDir.resolve('dev/src/index.ts'), } as OutputChunk, }, true, @@ -164,11 +180,13 @@ describe('forwardFileImports', () => { // should not break when triggering another write await plugin.generateBundle?.call( context, - { file: '/dev/dist/my-output.js' } as NormalizedOutputOptions, + { + file: mockDir.resolve('dev/dist/my-output.js'), + } as NormalizedOutputOptions, { ['index.js']: { type: 'chunk', - facadeModuleId: '/dev/src/index.ts', + facadeModuleId: mockDir.resolve('dev/src/index.ts'), } as OutputChunk, }, true, diff --git a/packages/cli/src/lib/new/factories/backendModule.test.ts b/packages/cli/src/lib/new/factories/backendModule.test.ts index c633b1c1b2..78ef5f96bb 100644 --- a/packages/cli/src/lib/new/factories/backendModule.test.ts +++ b/packages/cli/src/lib/new/factories/backendModule.test.ts @@ -15,39 +15,38 @@ */ import fs from 'fs-extra'; -import mockFs from 'mock-fs'; -import { sep, resolve as resolvePath } from 'path'; -import { paths } from '../../paths'; +import { sep } from 'path'; import { Task } from '../../tasks'; import { FactoryRegistry } from '../FactoryRegistry'; -import { createMockOutputStream, mockPaths } from './common/testUtils'; +import { + createMockOutputStream, + expectLogsToMatch, + mockPaths, +} from './common/testUtils'; import { backendModule } from './backendModule'; +import { createMockDirectory } from '@backstage/backend-test-utils'; describe('backendModule factory', () => { + const mockDir = createMockDirectory(); + beforeEach(() => { mockPaths({ - targetRoot: '/root', + targetRoot: mockDir.path, }); }); afterEach(() => { - mockFs.restore(); jest.resetAllMocks(); }); it('should create a backend plugin', async () => { - mockFs({ - '/root': { - packages: { - backend: { - 'package.json': JSON.stringify({}), - }, + mockDir.setContent({ + packages: { + backend: { + 'package.json': JSON.stringify({}), }, - plugins: mockFs.directory(), }, - [paths.resolveOwn('templates')]: mockFs.load( - paths.resolveOwn('templates'), - ), + plugins: {}, }); const options = await FactoryRegistry.populateOptions(backendModule, { @@ -73,8 +72,7 @@ describe('backendModule factory', () => { expect(modified).toBe(true); - expect(output).toEqual([ - '', + expectLogsToMatch(output, [ 'Creating backend module backstage-plugin-test-backend-module-tester-two', 'Checking Prerequisites:', `availability plugins${sep}test-backend-module-tester-two`, @@ -91,14 +89,14 @@ describe('backendModule factory', () => { ]); await expect( - fs.readJson('/root/packages/backend/package.json'), + fs.readJson(mockDir.resolve('packages/backend/package.json')), ).resolves.toEqual({ dependencies: { 'backstage-plugin-test-backend-module-tester-two': '^1.0.0', }, }); const moduleFile = await fs.readFile( - '/root/plugins/test-backend-module-tester-two/src/module.ts', + mockDir.resolve('plugins/test-backend-module-tester-two/src/module.ts'), 'utf-8', ); @@ -110,11 +108,11 @@ describe('backendModule factory', () => { expect(Task.forCommand).toHaveBeenCalledTimes(2); expect(Task.forCommand).toHaveBeenCalledWith('yarn install', { - cwd: resolvePath('/root/plugins/test-backend-module-tester-two'), + cwd: mockDir.resolve('plugins/test-backend-module-tester-two'), optional: true, }); expect(Task.forCommand).toHaveBeenCalledWith('yarn lint --fix', { - cwd: resolvePath('/root/plugins/test-backend-module-tester-two'), + cwd: mockDir.resolve('plugins/test-backend-module-tester-two'), optional: true, }); }); diff --git a/packages/cli/src/lib/new/factories/backendPlugin.test.ts b/packages/cli/src/lib/new/factories/backendPlugin.test.ts index f326de88b8..5c1d496e49 100644 --- a/packages/cli/src/lib/new/factories/backendPlugin.test.ts +++ b/packages/cli/src/lib/new/factories/backendPlugin.test.ts @@ -15,39 +15,38 @@ */ import fs from 'fs-extra'; -import mockFs from 'mock-fs'; -import { sep, resolve as resolvePath } from 'path'; -import { paths } from '../../paths'; +import { sep } from 'path'; import { Task } from '../../tasks'; import { FactoryRegistry } from '../FactoryRegistry'; -import { createMockOutputStream, mockPaths } from './common/testUtils'; +import { + createMockOutputStream, + expectLogsToMatch, + mockPaths, +} from './common/testUtils'; import { backendPlugin } from './backendPlugin'; +import { createMockDirectory } from '@backstage/backend-test-utils'; describe('backendPlugin factory', () => { + const mockDir = createMockDirectory(); + beforeEach(() => { mockPaths({ - targetRoot: '/root', + targetRoot: mockDir.path, }); }); afterEach(() => { - mockFs.restore(); jest.resetAllMocks(); }); it('should create a backend plugin', async () => { - mockFs({ - '/root': { - packages: { - backend: { - 'package.json': JSON.stringify({}), - }, + mockDir.setContent({ + packages: { + backend: { + 'package.json': JSON.stringify({}), }, - plugins: mockFs.directory(), }, - [paths.resolveOwn('templates')]: mockFs.load( - paths.resolveOwn('templates'), - ), + plugins: {}, }); const options = await FactoryRegistry.populateOptions(backendPlugin, { @@ -72,8 +71,7 @@ describe('backendPlugin factory', () => { expect(modified).toBe(true); - expect(output).toEqual([ - '', + expectLogsToMatch(output, [ 'Creating backend plugin backstage-plugin-test-backend', 'Checking Prerequisites:', `availability plugins${sep}test-backend`, @@ -94,14 +92,14 @@ describe('backendPlugin factory', () => { ]); await expect( - fs.readJson('/root/packages/backend/package.json'), + fs.readJson(mockDir.resolve('packages/backend/package.json')), ).resolves.toEqual({ dependencies: { 'backstage-plugin-test-backend': '^1.0.0', }, }); const standaloneServerFile = await fs.readFile( - '/root/plugins/test-backend/src/service/standaloneServer.ts', + mockDir.resolve('plugins/test-backend/src/service/standaloneServer.ts'), 'utf-8', ); @@ -112,11 +110,11 @@ describe('backendPlugin factory', () => { expect(Task.forCommand).toHaveBeenCalledTimes(2); expect(Task.forCommand).toHaveBeenCalledWith('yarn install', { - cwd: resolvePath('/root/plugins/test-backend'), + cwd: mockDir.resolve('plugins/test-backend'), optional: true, }); expect(Task.forCommand).toHaveBeenCalledWith('yarn lint --fix', { - cwd: resolvePath('/root/plugins/test-backend'), + cwd: mockDir.resolve('plugins/test-backend'), optional: true, }); }); diff --git a/packages/cli/src/lib/new/factories/common/tasks.test.ts b/packages/cli/src/lib/new/factories/common/tasks.test.ts index 49381676e7..60783344fc 100644 --- a/packages/cli/src/lib/new/factories/common/tasks.test.ts +++ b/packages/cli/src/lib/new/factories/common/tasks.test.ts @@ -15,32 +15,37 @@ */ import fs from 'fs-extra'; -import mockFs from 'mock-fs'; import { sep } from 'path'; -import { createMockOutputStream, mockPaths } from './testUtils'; +import { + createMockOutputStream, + expectLogsToMatch, + mockPaths, +} from './testUtils'; import { CreateContext } from '../../types'; import { executePluginPackageTemplate } from './tasks'; +import { createMockDirectory } from '@backstage/backend-test-utils'; + +const mockDir = createMockDirectory(); mockPaths({ - ownDir: '/own', - targetRoot: '/root', + ownDir: mockDir.resolve('own'), + targetRoot: mockDir.resolve('root'), }); describe('executePluginPackageTemplate', () => { afterEach(() => { - mockFs.restore(); jest.resetAllMocks(); }); it('should execute template', async () => { - mockFs({ - '/root': { + mockDir.setContent({ + root: { 'yarn.lock': ` some-package@^1.1.0: version "1.5.0" `, }, - '/own': { + own: { templates: { 'test-template': { 'package.json.hbs': ` @@ -78,7 +83,7 @@ some-package@^1.1.0: } as CreateContext, { templateName: 'test-template', - targetDir: '/target', + targetDir: mockDir.resolve('target'), values: { id: 'testing', makePrivate: true, @@ -87,7 +92,7 @@ some-package@^1.1.0: ); expect(modified).toBe(true); - expect(output).toEqual([ + expectLogsToMatch(output, [ 'Checking Prerequisites:', `availability ..${sep}target`, 'creating temp dir', @@ -98,7 +103,8 @@ some-package@^1.1.0: 'Installing:', `moving ..${sep}target`, ]); - await expect(fs.readFile('/target/package.json', 'utf8')).resolves.toBe(`{ + await expect(fs.readFile(mockDir.resolve('target/package.json'), 'utf8')) + .resolves.toBe(`{ "name": "my-testing-plugin", "private": true, "description": "testing", @@ -109,10 +115,10 @@ some-package@^1.1.0: } `); await expect( - fs.readFile('/target/subdir/templated.txt', 'utf8'), + fs.readFile(mockDir.resolve('target/subdir/templated.txt'), 'utf8'), ).resolves.toBe('Hello testing!'); await expect( - fs.readFile('/target/subdir/not-templated.txt', 'utf8'), + fs.readFile(mockDir.resolve('target/subdir/not-templated.txt'), 'utf8'), ).resolves.toBe('Hello {{id}}!'); }); }); diff --git a/packages/cli/src/lib/new/factories/common/testUtils.ts b/packages/cli/src/lib/new/factories/common/testUtils.ts index 01081a7486..1ade13a996 100644 --- a/packages/cli/src/lib/new/factories/common/testUtils.ts +++ b/packages/cli/src/lib/new/factories/common/testUtils.ts @@ -73,3 +73,11 @@ export function createMockOutputStream() { } as unknown as WriteStream & { fd: any }, ] as const; } + +// Avoid flakes by comparing sorted log lines. File system access is async, which leads to the log line order being indeterministic +export function expectLogsToMatch( + recievedLogs: String[], + expected: String[], +): void { + expect(recievedLogs.filter(Boolean).sort()).toEqual(expected.sort()); +} diff --git a/packages/cli/src/lib/new/factories/frontendPlugin.test.ts b/packages/cli/src/lib/new/factories/frontendPlugin.test.ts index 8390eb192e..94d4a7eb4c 100644 --- a/packages/cli/src/lib/new/factories/frontendPlugin.test.ts +++ b/packages/cli/src/lib/new/factories/frontendPlugin.test.ts @@ -15,13 +15,16 @@ */ import fs from 'fs-extra'; -import mockFs from 'mock-fs'; -import { sep, resolve as resolvePath } from 'path'; -import { paths } from '../../paths'; +import { sep } from 'path'; import { Task } from '../../tasks'; import { FactoryRegistry } from '../FactoryRegistry'; -import { createMockOutputStream, mockPaths } from './common/testUtils'; +import { + createMockOutputStream, + expectLogsToMatch, + mockPaths, +} from './common/testUtils'; import { frontendPlugin } from './frontendPlugin'; +import { createMockDirectory } from '@backstage/backend-test-utils'; const appTsxContent = ` import { createApp } from '@backstage/app-defaults'; @@ -34,33 +37,29 @@ const router = ( `; describe('frontendPlugin factory', () => { + const mockDir = createMockDirectory(); + beforeEach(() => { mockPaths({ - targetRoot: '/root', + targetRoot: mockDir.path, }); }); afterEach(() => { - mockFs.restore(); jest.resetAllMocks(); }); it('should create a frontend plugin', async () => { - mockFs({ - '/root': { - packages: { - app: { - 'package.json': JSON.stringify({}), - src: { - 'App.tsx': appTsxContent, - }, + mockDir.setContent({ + packages: { + app: { + 'package.json': JSON.stringify({}), + src: { + 'App.tsx': appTsxContent, }, }, - plugins: mockFs.directory(), }, - [paths.resolveOwn('templates')]: mockFs.load( - paths.resolveOwn('templates'), - ), + plugins: {}, }); const options = await FactoryRegistry.populateOptions(frontendPlugin, { @@ -85,8 +84,7 @@ describe('frontendPlugin factory', () => { expect(modified).toBe(true); - expect(output).toEqual([ - '', + expectLogsToMatch(output, [ 'Creating frontend plugin backstage-plugin-test', 'Checking Prerequisites:', `availability plugins${sep}test`, @@ -114,15 +112,16 @@ describe('frontendPlugin factory', () => { ]); await expect( - fs.readJson('/root/packages/app/package.json'), + fs.readJson(mockDir.resolve('packages/app/package.json')), ).resolves.toEqual({ dependencies: { 'backstage-plugin-test': '^1.0.0', }, }); - await expect(fs.readFile('/root/packages/app/src/App.tsx', 'utf8')).resolves - .toBe(` + await expect( + fs.readFile(mockDir.resolve('packages/app/src/App.tsx'), 'utf8'), + ).resolves.toBe(` import { createApp } from '@backstage/app-defaults'; import { TestPage } from 'backstage-plugin-test'; @@ -136,32 +135,27 @@ const router = ( expect(Task.forCommand).toHaveBeenCalledTimes(2); expect(Task.forCommand).toHaveBeenCalledWith('yarn install', { - cwd: resolvePath('/root/plugins/test'), + cwd: mockDir.resolve('plugins/test'), optional: true, }); expect(Task.forCommand).toHaveBeenCalledWith('yarn lint --fix', { - cwd: resolvePath('/root/plugins/test'), + cwd: mockDir.resolve('plugins/test'), optional: true, }); }); it('should create a frontend plugin with more options and codeowners', async () => { - mockFs({ - '/root': { - CODEOWNERS: '', - packages: { - app: { - 'package.json': JSON.stringify({}), - src: { - 'App.tsx': appTsxContent, - }, + mockDir.setContent({ + CODEOWNERS: '', + packages: { + app: { + 'package.json': JSON.stringify({}), + src: { + 'App.tsx': appTsxContent, }, }, - plugins: mockFs.directory(), }, - [paths.resolveOwn('templates')]: mockFs.load( - paths.resolveOwn('templates'), - ), + plugins: {}, }); const options = await FactoryRegistry.populateOptions(frontendPlugin, { @@ -183,15 +177,16 @@ const router = ( }); await expect( - fs.readJson('/root/packages/app/package.json'), + fs.readJson(mockDir.resolve('packages/app/package.json')), ).resolves.toEqual({ dependencies: { '@internal/plugin-test': '^1.0.0', }, }); - await expect(fs.readFile('/root/packages/app/src/App.tsx', 'utf8')).resolves - .toBe(` + await expect( + fs.readFile(mockDir.resolve('packages/app/src/App.tsx'), 'utf8'), + ).resolves.toBe(` import { createApp } from '@backstage/app-defaults'; import { TestPage } from '@internal/plugin-test'; @@ -205,11 +200,11 @@ const router = ( expect(Task.forCommand).toHaveBeenCalledTimes(2); expect(Task.forCommand).toHaveBeenCalledWith('yarn install', { - cwd: resolvePath('/root/plugins/test'), + cwd: mockDir.resolve('plugins/test'), optional: true, }); expect(Task.forCommand).toHaveBeenCalledWith('yarn lint --fix', { - cwd: resolvePath('/root/plugins/test'), + cwd: mockDir.resolve('plugins/test'), optional: true, }); }); diff --git a/packages/cli/src/lib/new/factories/nodeLibraryPackage.test.ts b/packages/cli/src/lib/new/factories/nodeLibraryPackage.test.ts index d0b08f4f06..e3673d21ba 100644 --- a/packages/cli/src/lib/new/factories/nodeLibraryPackage.test.ts +++ b/packages/cli/src/lib/new/factories/nodeLibraryPackage.test.ts @@ -15,36 +15,35 @@ */ import fs from 'fs-extra'; -import mockFs from 'mock-fs'; -import { resolve as resolvePath, join as joinPath } from 'path'; -import { paths } from '../../paths'; +import { join as joinPath } from 'path'; import { Task } from '../../tasks'; import { FactoryRegistry } from '../FactoryRegistry'; -import { createMockOutputStream, mockPaths } from './common/testUtils'; +import { + createMockOutputStream, + expectLogsToMatch, + mockPaths, +} from './common/testUtils'; import { nodeLibraryPackage } from './nodeLibraryPackage'; +import { createMockDirectory } from '@backstage/backend-test-utils'; describe('nodeLibraryPackage factory', () => { + const mockDir = createMockDirectory(); + beforeEach(() => { mockPaths({ - targetRoot: '/root', + targetRoot: mockDir.path, }); }); afterEach(() => { - mockFs.restore(); jest.resetAllMocks(); }); it('should create a node library package', async () => { const expectedNodeLibraryPackageName = 'test'; - mockFs({ - '/root': { - packages: mockFs.directory(), - }, - [paths.resolveOwn('templates')]: mockFs.load( - paths.resolveOwn('templates'), - ), + mockDir.setContent({ + packages: {}, }); const options = await FactoryRegistry.populateOptions(nodeLibraryPackage, { @@ -69,8 +68,7 @@ describe('nodeLibraryPackage factory', () => { expect(modified).toBe(true); - expect(output).toEqual([ - '', + expectLogsToMatch(output, [ `Creating node-library package ${expectedNodeLibraryPackageName}`, 'Checking Prerequisites:', `availability ${joinPath('packages', expectedNodeLibraryPackageName)}`, @@ -87,7 +85,11 @@ describe('nodeLibraryPackage factory', () => { await expect( fs.readJson( - `/root/packages/${expectedNodeLibraryPackageName}/package.json`, + mockDir.resolve( + 'packages', + expectedNodeLibraryPackageName, + 'package.json', + ), ), ).resolves.toEqual( expect.objectContaining({ @@ -99,11 +101,11 @@ describe('nodeLibraryPackage factory', () => { expect(Task.forCommand).toHaveBeenCalledTimes(2); expect(Task.forCommand).toHaveBeenCalledWith('yarn install', { - cwd: resolvePath(`/root/packages/${expectedNodeLibraryPackageName}`), + cwd: mockDir.resolve('packages', expectedNodeLibraryPackageName), optional: true, }); expect(Task.forCommand).toHaveBeenCalledWith('yarn lint --fix', { - cwd: resolvePath(`/root/packages/${expectedNodeLibraryPackageName}`), + cwd: mockDir.resolve('packages', expectedNodeLibraryPackageName), optional: true, }); }); @@ -111,14 +113,9 @@ describe('nodeLibraryPackage factory', () => { it('should create a node library plugin with options and codeowners', async () => { const expectedNodeLibraryPackageName = 'test'; - mockFs({ - '/root': { - CODEOWNERS: '', - packages: mockFs.directory(), - }, - [paths.resolveOwn('templates')]: mockFs.load( - paths.resolveOwn('templates'), - ), + mockDir.setContent({ + CODEOWNERS: '', + packages: {}, }); const options = await FactoryRegistry.populateOptions(nodeLibraryPackage, { @@ -141,11 +138,11 @@ describe('nodeLibraryPackage factory', () => { expect(Task.forCommand).toHaveBeenCalledTimes(2); expect(Task.forCommand).toHaveBeenCalledWith('yarn install', { - cwd: resolvePath(`/root/${expectedNodeLibraryPackageName}`), + cwd: mockDir.resolve(expectedNodeLibraryPackageName), optional: true, }); expect(Task.forCommand).toHaveBeenCalledWith('yarn lint --fix', { - cwd: resolvePath(`/root/${expectedNodeLibraryPackageName}`), + cwd: mockDir.resolve(expectedNodeLibraryPackageName), optional: true, }); }); diff --git a/packages/cli/src/lib/new/factories/pluginCommon.test.ts b/packages/cli/src/lib/new/factories/pluginCommon.test.ts index 25b6b51905..d85e490510 100644 --- a/packages/cli/src/lib/new/factories/pluginCommon.test.ts +++ b/packages/cli/src/lib/new/factories/pluginCommon.test.ts @@ -15,34 +15,33 @@ */ import fs from 'fs-extra'; -import mockFs from 'mock-fs'; -import { sep, resolve as resolvePath } from 'path'; -import { paths } from '../../paths'; +import { sep } from 'path'; import { Task } from '../../tasks'; import { FactoryRegistry } from '../FactoryRegistry'; -import { createMockOutputStream, mockPaths } from './common/testUtils'; +import { + createMockOutputStream, + expectLogsToMatch, + mockPaths, +} from './common/testUtils'; import { pluginCommon } from './pluginCommon'; +import { createMockDirectory } from '@backstage/backend-test-utils'; describe('pluginCommon factory', () => { + const mockDir = createMockDirectory(); + beforeEach(() => { mockPaths({ - targetRoot: '/root', + targetRoot: mockDir.path, }); }); afterEach(() => { - mockFs.restore(); jest.resetAllMocks(); }); it('should create a common plugin package', async () => { - mockFs({ - '/root': { - plugins: mockFs.directory(), - }, - [paths.resolveOwn('templates')]: mockFs.load( - paths.resolveOwn('templates'), - ), + mockDir.setContent({ + plugins: {}, }); const options = await FactoryRegistry.populateOptions(pluginCommon, { @@ -67,8 +66,7 @@ describe('pluginCommon factory', () => { expect(modified).toBe(true); - expect(output).toEqual([ - '', + expectLogsToMatch(output, [ 'Creating backend plugin backstage-plugin-test-common', 'Checking Prerequisites:', `availability plugins${sep}test-common`, @@ -84,7 +82,7 @@ describe('pluginCommon factory', () => { ]); await expect( - fs.readJson('/root/plugins/test-common/package.json'), + fs.readJson(mockDir.resolve('plugins/test-common/package.json')), ).resolves.toEqual( expect.objectContaining({ name: 'backstage-plugin-test-common', @@ -96,11 +94,11 @@ describe('pluginCommon factory', () => { expect(Task.forCommand).toHaveBeenCalledTimes(2); expect(Task.forCommand).toHaveBeenCalledWith('yarn install', { - cwd: resolvePath('/root/plugins/test-common'), + cwd: mockDir.resolve('plugins/test-common'), optional: true, }); expect(Task.forCommand).toHaveBeenCalledWith('yarn lint --fix', { - cwd: resolvePath('/root/plugins/test-common'), + cwd: mockDir.resolve('plugins/test-common'), optional: true, }); }); diff --git a/packages/cli/src/lib/new/factories/pluginNode.test.ts b/packages/cli/src/lib/new/factories/pluginNode.test.ts index 50971ff191..d8d9ea33ab 100644 --- a/packages/cli/src/lib/new/factories/pluginNode.test.ts +++ b/packages/cli/src/lib/new/factories/pluginNode.test.ts @@ -15,34 +15,33 @@ */ import fs from 'fs-extra'; -import mockFs from 'mock-fs'; -import { sep, resolve as resolvePath } from 'path'; -import { paths } from '../../paths'; +import { sep } from 'path'; import { Task } from '../../tasks'; import { FactoryRegistry } from '../FactoryRegistry'; -import { createMockOutputStream, mockPaths } from './common/testUtils'; +import { + createMockOutputStream, + expectLogsToMatch, + mockPaths, +} from './common/testUtils'; import { pluginNode } from './pluginNode'; +import { createMockDirectory } from '@backstage/backend-test-utils'; describe('pluginNode factory', () => { + const mockDir = createMockDirectory(); + beforeEach(() => { mockPaths({ - targetRoot: '/root', + targetRoot: mockDir.path, }); }); afterEach(() => { - mockFs.restore(); jest.resetAllMocks(); }); it('should create a node plugin package', async () => { - mockFs({ - '/root': { - plugins: mockFs.directory(), - }, - [paths.resolveOwn('templates')]: mockFs.load( - paths.resolveOwn('templates'), - ), + mockDir.setContent({ + plugins: {}, }); const options = await FactoryRegistry.populateOptions(pluginNode, { @@ -67,8 +66,7 @@ describe('pluginNode factory', () => { expect(modified).toBe(true); - expect(output).toEqual([ - '', + expectLogsToMatch(output, [ 'Creating Node.js plugin library backstage-plugin-test-node', 'Checking Prerequisites:', `availability plugins${sep}test-node`, @@ -84,7 +82,7 @@ describe('pluginNode factory', () => { ]); await expect( - fs.readJson('/root/plugins/test-node/package.json'), + fs.readJson(mockDir.resolve('plugins/test-node/package.json')), ).resolves.toEqual( expect.objectContaining({ name: 'backstage-plugin-test-node', @@ -96,11 +94,11 @@ describe('pluginNode factory', () => { expect(Task.forCommand).toHaveBeenCalledTimes(2); expect(Task.forCommand).toHaveBeenCalledWith('yarn install', { - cwd: resolvePath('/root/plugins/test-node'), + cwd: mockDir.resolve('plugins/test-node'), optional: true, }); expect(Task.forCommand).toHaveBeenCalledWith('yarn lint --fix', { - cwd: resolvePath('/root/plugins/test-node'), + cwd: mockDir.resolve('plugins/test-node'), optional: true, }); }); diff --git a/packages/cli/src/lib/new/factories/pluginWeb.test.ts b/packages/cli/src/lib/new/factories/pluginWeb.test.ts index bcd62f3bcd..ff4211d8fa 100644 --- a/packages/cli/src/lib/new/factories/pluginWeb.test.ts +++ b/packages/cli/src/lib/new/factories/pluginWeb.test.ts @@ -15,34 +15,33 @@ */ import fs from 'fs-extra'; -import mockFs from 'mock-fs'; -import { sep, resolve as resolvePath } from 'path'; -import { paths } from '../../paths'; +import { sep } from 'path'; import { Task } from '../../tasks'; import { FactoryRegistry } from '../FactoryRegistry'; -import { createMockOutputStream, mockPaths } from './common/testUtils'; +import { + createMockOutputStream, + expectLogsToMatch, + mockPaths, +} from './common/testUtils'; import { pluginWeb } from './pluginWeb'; +import { createMockDirectory } from '@backstage/backend-test-utils'; describe('pluginWeb factory', () => { + const mockDir = createMockDirectory(); + beforeEach(() => { mockPaths({ - targetRoot: '/root', + targetRoot: mockDir.path, }); }); afterEach(() => { - mockFs.restore(); jest.resetAllMocks(); }); it('should create a react plugin package', async () => { - mockFs({ - '/root': { - plugins: mockFs.directory(), - }, - [paths.resolveOwn('templates')]: mockFs.load( - paths.resolveOwn('templates'), - ), + mockDir.setContent({ + plugins: {}, }); const options = await FactoryRegistry.populateOptions(pluginWeb, { @@ -67,8 +66,7 @@ describe('pluginWeb factory', () => { expect(modified).toBe(true); - expect(output).toEqual([ - '', + expectLogsToMatch(output, [ 'Creating web plugin library backstage-plugin-test-react', 'Checking Prerequisites:', `availability plugins${sep}test-react`, @@ -91,7 +89,7 @@ describe('pluginWeb factory', () => { ]); await expect( - fs.readJson('/root/plugins/test-react/package.json'), + fs.readJson(mockDir.resolve('plugins/test-react/package.json')), ).resolves.toEqual( expect.objectContaining({ name: 'backstage-plugin-test-react', @@ -103,11 +101,11 @@ describe('pluginWeb factory', () => { expect(Task.forCommand).toHaveBeenCalledTimes(2); expect(Task.forCommand).toHaveBeenCalledWith('yarn install', { - cwd: resolvePath('/root/plugins/test-react'), + cwd: mockDir.resolve('plugins/test-react'), optional: true, }); expect(Task.forCommand).toHaveBeenCalledWith('yarn lint --fix', { - cwd: resolvePath('/root/plugins/test-react'), + cwd: mockDir.resolve('plugins/test-react'), optional: true, }); }); diff --git a/packages/cli/src/lib/new/factories/scaffolderModule.test.ts b/packages/cli/src/lib/new/factories/scaffolderModule.test.ts index 38d1207a3f..b43946228b 100644 --- a/packages/cli/src/lib/new/factories/scaffolderModule.test.ts +++ b/packages/cli/src/lib/new/factories/scaffolderModule.test.ts @@ -15,34 +15,33 @@ */ import fs from 'fs-extra'; -import mockFs from 'mock-fs'; -import { sep, resolve as resolvePath } from 'path'; -import { paths } from '../../paths'; +import { sep } from 'path'; import { Task } from '../../tasks'; import { FactoryRegistry } from '../FactoryRegistry'; -import { createMockOutputStream, mockPaths } from './common/testUtils'; +import { + createMockOutputStream, + expectLogsToMatch, + mockPaths, +} from './common/testUtils'; import { scaffolderModule } from './scaffolderModule'; +import { createMockDirectory } from '@backstage/backend-test-utils'; describe('scaffolderModule factory', () => { + const mockDir = createMockDirectory(); + beforeEach(() => { mockPaths({ - targetRoot: '/root', + targetRoot: mockDir.path, }); }); afterEach(() => { - mockFs.restore(); jest.resetAllMocks(); }); it('should create a scaffolder backend module package', async () => { - mockFs({ - '/root': { - plugins: mockFs.directory(), - }, - [paths.resolveOwn('templates')]: mockFs.load( - paths.resolveOwn('templates'), - ), + mockDir.setContent({ + plugins: {}, }); const options = await FactoryRegistry.populateOptions(scaffolderModule, { @@ -67,8 +66,7 @@ describe('scaffolderModule factory', () => { expect(modified).toBe(true); - expect(output).toEqual([ - '', + expectLogsToMatch(output, [ 'Creating module backstage-plugin-scaffolder-backend-module-test', 'Checking Prerequisites:', `availability plugins${sep}scaffolder-backend-module-test`, @@ -87,7 +85,9 @@ describe('scaffolderModule factory', () => { ]); await expect( - fs.readJson('/root/plugins/scaffolder-backend-module-test/package.json'), + fs.readJson( + mockDir.resolve('plugins/scaffolder-backend-module-test/package.json'), + ), ).resolves.toEqual( expect.objectContaining({ name: 'backstage-plugin-scaffolder-backend-module-test', @@ -99,11 +99,11 @@ describe('scaffolderModule factory', () => { expect(Task.forCommand).toHaveBeenCalledTimes(2); expect(Task.forCommand).toHaveBeenCalledWith('yarn install', { - cwd: resolvePath('/root/plugins/scaffolder-backend-module-test'), + cwd: mockDir.resolve('plugins/scaffolder-backend-module-test'), optional: true, }); expect(Task.forCommand).toHaveBeenCalledWith('yarn lint --fix', { - cwd: resolvePath('/root/plugins/scaffolder-backend-module-test'), + cwd: mockDir.resolve('plugins/scaffolder-backend-module-test'), optional: true, }); }); diff --git a/packages/cli/src/lib/new/factories/webLibraryPackage.test.ts b/packages/cli/src/lib/new/factories/webLibraryPackage.test.ts index 50fef44a67..b0c8461189 100644 --- a/packages/cli/src/lib/new/factories/webLibraryPackage.test.ts +++ b/packages/cli/src/lib/new/factories/webLibraryPackage.test.ts @@ -15,36 +15,35 @@ */ import fs from 'fs-extra'; -import mockFs from 'mock-fs'; -import { resolve as resolvePath, join as joinPath } from 'path'; -import { paths } from '../../paths'; +import { join as joinPath } from 'path'; import { Task } from '../../tasks'; import { FactoryRegistry } from '../FactoryRegistry'; -import { createMockOutputStream, mockPaths } from './common/testUtils'; +import { + createMockOutputStream, + expectLogsToMatch, + mockPaths, +} from './common/testUtils'; import { webLibraryPackage } from './webLibraryPackage'; +import { createMockDirectory } from '@backstage/backend-test-utils'; describe('webLibraryPackage factory', () => { + const mockDir = createMockDirectory(); + beforeEach(() => { mockPaths({ - targetRoot: '/root', + targetRoot: mockDir.path, }); }); afterEach(() => { - mockFs.restore(); jest.resetAllMocks(); }); it('should create a web library package', async () => { const expectedwebLibraryPackageName = 'test'; - mockFs({ - '/root': { - packages: mockFs.directory(), - }, - [paths.resolveOwn('templates')]: mockFs.load( - paths.resolveOwn('templates'), - ), + mockDir.setContent({ + packages: {}, }); const options = await FactoryRegistry.populateOptions(webLibraryPackage, { @@ -69,8 +68,7 @@ describe('webLibraryPackage factory', () => { expect(modified).toBe(true); - expect(output).toEqual([ - '', + expectLogsToMatch(output, [ `Creating web-library package ${expectedwebLibraryPackageName}`, 'Checking Prerequisites:', `availability ${joinPath('packages', expectedwebLibraryPackageName)}`, @@ -87,7 +85,11 @@ describe('webLibraryPackage factory', () => { await expect( fs.readJson( - `/root/packages/${expectedwebLibraryPackageName}/package.json`, + mockDir.resolve( + 'packages', + expectedwebLibraryPackageName, + 'package.json', + ), ), ).resolves.toEqual( expect.objectContaining({ @@ -99,11 +101,11 @@ describe('webLibraryPackage factory', () => { expect(Task.forCommand).toHaveBeenCalledTimes(2); expect(Task.forCommand).toHaveBeenCalledWith('yarn install', { - cwd: resolvePath(`/root/packages/${expectedwebLibraryPackageName}`), + cwd: mockDir.resolve('packages', expectedwebLibraryPackageName), optional: true, }); expect(Task.forCommand).toHaveBeenCalledWith('yarn lint --fix', { - cwd: resolvePath(`/root/packages/${expectedwebLibraryPackageName}`), + cwd: mockDir.resolve('packages', expectedwebLibraryPackageName), optional: true, }); }); @@ -111,14 +113,9 @@ describe('webLibraryPackage factory', () => { it('should create a web library plugin with options and codeowners', async () => { const expectedwebLibraryPackageName = 'test'; - mockFs({ - '/root': { - CODEOWNERS: '', - packages: mockFs.directory(), - }, - [paths.resolveOwn('templates')]: mockFs.load( - paths.resolveOwn('templates'), - ), + mockDir.setContent({ + CODEOWNERS: '', + packages: {}, }); const options = await FactoryRegistry.populateOptions(webLibraryPackage, { @@ -141,11 +138,11 @@ describe('webLibraryPackage factory', () => { expect(Task.forCommand).toHaveBeenCalledTimes(2); expect(Task.forCommand).toHaveBeenCalledWith('yarn install', { - cwd: resolvePath(`/root/${expectedwebLibraryPackageName}`), + cwd: mockDir.resolve(expectedwebLibraryPackageName), optional: true, }); expect(Task.forCommand).toHaveBeenCalledWith('yarn lint --fix', { - cwd: resolvePath(`/root/${expectedwebLibraryPackageName}`), + cwd: mockDir.resolve(expectedwebLibraryPackageName), optional: true, }); }); diff --git a/packages/cli/src/lib/role.test.ts b/packages/cli/src/lib/role.test.ts index adca2d70b8..8163512b76 100644 --- a/packages/cli/src/lib/role.test.ts +++ b/packages/cli/src/lib/role.test.ts @@ -14,10 +14,20 @@ * limitations under the License. */ -import mockFs from 'mock-fs'; +import { createMockDirectory } from '@backstage/backend-test-utils'; import { Command } from 'commander'; import { findRoleFromCommand } from './role'; +const mockDir = createMockDirectory(); + +jest.mock('./paths', () => ({ + paths: { + resolveTarget(filename: string) { + return mockDir.resolve(filename); + }, + }, +})); + describe('findRoleFromCommand', () => { function mkCommand(args: string) { const parsed = new Command() @@ -27,7 +37,7 @@ describe('findRoleFromCommand', () => { } beforeEach(() => { - mockFs({ + mockDir.setContent({ 'package.json': JSON.stringify({ name: 'test', backstage: { @@ -37,10 +47,6 @@ describe('findRoleFromCommand', () => { }); }); - afterEach(() => { - mockFs.restore(); - }); - it('provides role info by role', async () => { await expect(findRoleFromCommand(mkCommand(''))).resolves.toEqual( 'web-library', diff --git a/packages/cli/src/lib/tasks.test.ts b/packages/cli/src/lib/tasks.test.ts index fb1f38536f..1119adb7f7 100644 --- a/packages/cli/src/lib/tasks.test.ts +++ b/packages/cli/src/lib/tasks.test.ts @@ -15,14 +15,11 @@ */ import fs from 'fs-extra'; -import mockFs from 'mock-fs'; -import { resolve as resolvePath } from 'path'; import { templatingTask } from './tasks'; +import { createMockDirectory } from '@backstage/backend-test-utils'; describe('templatingTask', () => { - afterEach(() => { - mockFs.restore(); - }); + const mockDir = createMockDirectory(); it('should template a directory with mix of regular files and templates', async () => { // Testing template directory @@ -36,7 +33,7 @@ describe('templatingTask', () => { const testVersionFileContent = "version: {{pluginVersion}} {{versionQuery 'mock-pkg'}}"; - mockFs({ + mockDir.setContent({ [tmplDir]: { sub: { 'version.txt.hbs': testVersionFileContent, @@ -47,8 +44,8 @@ describe('templatingTask', () => { }); await templatingTask( - tmplDir, - destDir, + mockDir.resolve(tmplDir), + mockDir.resolve(destDir), { pluginVersion: '0.0.0', }, @@ -57,10 +54,10 @@ describe('templatingTask', () => { ); await expect( - fs.readFile(resolvePath(destDir, 'test.txt'), 'utf8'), + fs.readFile(mockDir.resolve(destDir, 'test.txt'), 'utf8'), ).resolves.toBe(testFileContent); await expect( - fs.readFile(resolvePath(destDir, 'sub/version.txt'), 'utf8'), + fs.readFile(mockDir.resolve(destDir, 'sub/version.txt'), 'utf8'), ).resolves.toBe('version: 0.0.0 ^0.1.2'); }); }); diff --git a/packages/cli/src/lib/version.test.ts b/packages/cli/src/lib/version.test.ts index 604129679b..6b1aa391d5 100644 --- a/packages/cli/src/lib/version.test.ts +++ b/packages/cli/src/lib/version.test.ts @@ -14,15 +14,13 @@ * limitations under the License. */ -import mockFs from 'mock-fs'; import { packageVersions, createPackageVersionProvider } from './version'; import { Lockfile } from './versioning'; import corePluginApiPkg from '@backstage/core-plugin-api/package.json'; +import { createMockDirectory } from '@backstage/backend-test-utils'; describe('createPackageVersionProvider', () => { - afterEach(() => { - mockFs.restore(); - }); + const mockDir = createMockDirectory(); const HEADER = `# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. # yarn lockfile v1 @@ -30,7 +28,7 @@ describe('createPackageVersionProvider', () => { `; it('should provide package versions', async () => { - mockFs({ + mockDir.setContent({ 'yarn.lock': `${HEADER} "a@^0.1.0": version "0.1.5" @@ -55,7 +53,8 @@ describe('createPackageVersionProvider', () => { `, }); - const lockfile = await Lockfile.load('yarn.lock'); + const lockfilePath = mockDir.resolve('yarn.lock'); + const lockfile = await Lockfile.load(lockfilePath); const provider = createPackageVersionProvider(lockfile); expect(provider('a', '0.1.5')).toBe('^0.1.0'); diff --git a/packages/cli/src/lib/versioning/Lockfile.test.ts b/packages/cli/src/lib/versioning/Lockfile.test.ts index 909f8be9aa..a4267acdb7 100644 --- a/packages/cli/src/lib/versioning/Lockfile.test.ts +++ b/packages/cli/src/lib/versioning/Lockfile.test.ts @@ -15,9 +15,9 @@ */ import fs from 'fs-extra'; -import mockFs from 'mock-fs'; import { BackstagePackage } from '@backstage/cli-node'; import { Lockfile } from './Lockfile'; +import { createMockDirectory } from '@backstage/backend-test-utils'; const LEGACY_HEADER = `# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. # yarn lockfile v1 @@ -76,16 +76,14 @@ const mockBDedup = `${LEGACY_HEADER} `; describe('Lockfile', () => { - afterEach(() => { - mockFs.restore(); - }); + const mockDir = createMockDirectory(); it('should load and serialize mockA', async () => { - mockFs({ - '/yarn.lock': mockA, + mockDir.setContent({ + 'yarn.lock': mockA, }); - const lockfile = await Lockfile.load('/yarn.lock'); + const lockfile = await Lockfile.load(mockDir.resolve('yarn.lock')); expect(lockfile.get('a')).toEqual([ { range: '^1', version: '1.0.1', dataKey: 'a@^1' }, ]); @@ -97,11 +95,12 @@ describe('Lockfile', () => { }); it('should deduplicate and save mockA', async () => { - mockFs({ - '/yarn.lock': mockA, + mockDir.setContent({ + 'yarn.lock': mockA, }); - const lockfile = await Lockfile.load('/yarn.lock'); + const lockfilePath = mockDir.resolve('yarn.lock'); + const lockfile = await Lockfile.load(lockfilePath); const result = lockfile.analyze({ localPackages: new Map() }); expect(result).toEqual({ invalidRanges: [], @@ -120,17 +119,17 @@ describe('Lockfile', () => { lockfile.replaceVersions(result.newVersions); expect(lockfile.toString()).toBe(mockADedup); - await expect(fs.readFile('/yarn.lock', 'utf8')).resolves.toBe(mockA); - await expect(lockfile.save('/yarn.lock')).resolves.toBeUndefined(); - await expect(fs.readFile('/yarn.lock', 'utf8')).resolves.toBe(mockADedup); + await expect(fs.readFile(lockfilePath, 'utf8')).resolves.toBe(mockA); + await expect(lockfile.save(lockfilePath)).resolves.toBeUndefined(); + await expect(fs.readFile(lockfilePath, 'utf8')).resolves.toBe(mockADedup); }); it('should deduplicate mockB', async () => { - mockFs({ - '/yarn.lock': mockB, + mockDir.setContent({ + 'yarn.lock': mockB, }); - const lockfile = await Lockfile.load('/yarn.lock'); + const lockfile = await Lockfile.load(mockDir.resolve('yarn.lock')); const result = lockfile.analyze({ localPackages: new Map() }); expect(result).toEqual({ invalidRanges: [], @@ -226,16 +225,14 @@ b@^2: `; describe('New Lockfile', () => { - afterEach(() => { - mockFs.restore(); - }); + const mockDir = createMockDirectory(); it('should load and serialize mockANew', async () => { - mockFs({ - '/yarn.lock': mockANew, + mockDir.setContent({ + 'yarn.lock': mockANew, }); - const lockfile = await Lockfile.load('/yarn.lock'); + const lockfile = await Lockfile.load(mockDir.resolve('yarn.lock')); expect(lockfile.get('a')).toEqual([ { range: '^1', version: '1.0.1', dataKey: 'a@^1' }, ]); @@ -248,11 +245,12 @@ describe('New Lockfile', () => { }); it('should deduplicate and save mockANew', async () => { - mockFs({ - '/yarn.lock': mockANew, + mockDir.setContent({ + 'yarn.lock': mockANew, }); - const lockfile = await Lockfile.load('/yarn.lock'); + const lockfilePath = mockDir.resolve('yarn.lock'); + const lockfile = await Lockfile.load(lockfilePath); const result = lockfile.analyze({ localPackages: new Map() }); expect(result).toEqual({ invalidRanges: [], @@ -271,19 +269,20 @@ describe('New Lockfile', () => { lockfile.replaceVersions(result.newVersions); expect(lockfile.toString()).toBe(mockANewDedup); - await expect(fs.readFile('/yarn.lock', 'utf8')).resolves.toBe(mockANew); - await expect(lockfile.save('/yarn.lock')).resolves.toBeUndefined(); - await expect(fs.readFile('/yarn.lock', 'utf8')).resolves.toBe( + await expect(fs.readFile(lockfilePath, 'utf8')).resolves.toBe(mockANew); + await expect(lockfile.save(lockfilePath)).resolves.toBeUndefined(); + await expect(fs.readFile(lockfilePath, 'utf8')).resolves.toBe( mockANewDedup, ); }); it('should deduplicate and save mockANewLocal', async () => { - mockFs({ - '/yarn.lock': mockANewLocal, + mockDir.setContent({ + 'yarn.lock': mockANewLocal, }); - const lockfile = await Lockfile.load('/yarn.lock'); + const lockfilePath = mockDir.resolve('yarn.lock'); + const lockfile = await Lockfile.load(lockfilePath); const result = lockfile.analyze({ localPackages: new Map([ [ @@ -311,11 +310,11 @@ describe('New Lockfile', () => { lockfile.replaceVersions(result.newVersions); expect(lockfile.toString()).toBe(mockANewLocalDedup); - await expect(fs.readFile('/yarn.lock', 'utf8')).resolves.toBe( + await expect(fs.readFile(lockfilePath, 'utf8')).resolves.toBe( mockANewLocal, ); - await expect(lockfile.save('/yarn.lock')).resolves.toBeUndefined(); - await expect(fs.readFile('/yarn.lock', 'utf8')).resolves.toBe( + await expect(lockfile.save(lockfilePath)).resolves.toBeUndefined(); + await expect(fs.readFile(lockfilePath, 'utf8')).resolves.toBe( mockANewLocalDedup, ); }); diff --git a/packages/cli/src/lib/versioning/packages.test.ts b/packages/cli/src/lib/versioning/packages.test.ts index 5a255532f9..23ff927c48 100644 --- a/packages/cli/src/lib/versioning/packages.test.ts +++ b/packages/cli/src/lib/versioning/packages.test.ts @@ -14,12 +14,11 @@ * limitations under the License. */ -import mockFs from 'mock-fs'; -import path from 'path'; import * as runObj from '../run'; import * as yarn from '../yarn'; import { fetchPackageInfo, mapDependencies } from './packages'; import { NotFoundError } from '../errors'; +import { createMockDirectory } from '@backstage/backend-test-utils'; jest.mock('../run', () => { return { @@ -96,34 +95,41 @@ describe('fetchPackageInfo', () => { }); describe('mapDependencies', () => { + const mockDir = createMockDirectory(); + afterEach(() => { - mockFs.restore(); jest.resetAllMocks(); }); it('should read dependencies', async () => { - mockFs({ - '/root/package.json': JSON.stringify({ + mockDir.setContent({ + 'package.json': JSON.stringify({ workspaces: { packages: ['pkgs/*'], }, }), - '/root/pkgs/a/package.json': JSON.stringify({ - name: 'a', - dependencies: { - '@backstage/core': '1 || 2', + pkgs: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + dependencies: { + '@backstage/core': '1 || 2', + }, + }), }, - }), - '/root/pkgs/b/package.json': JSON.stringify({ - name: 'b', - dependencies: { - '@backstage/core': '3', - '@backstage/cli': '^0', + b: { + 'package.json': JSON.stringify({ + name: 'b', + dependencies: { + '@backstage/core': '3', + '@backstage/cli': '^0', + }, + }), }, - }), + }, }); - const dependencyMap = await mapDependencies('/root', '@backstage/*'); + const dependencyMap = await mapDependencies(mockDir.path, '@backstage/*'); expect(Array.from(dependencyMap)).toEqual([ [ '@backstage/core', @@ -131,12 +137,12 @@ describe('mapDependencies', () => { { name: 'a', range: '1 || 2', - location: path.resolve('/root/pkgs/a'), + location: mockDir.resolve('pkgs/a'), }, { name: 'b', range: '3', - location: path.resolve('/root/pkgs/b'), + location: mockDir.resolve('pkgs/b'), }, ], ], @@ -146,7 +152,7 @@ describe('mapDependencies', () => { { name: 'b', range: '^0', - location: path.resolve('/root/pkgs/b'), + location: mockDir.resolve('pkgs/b'), }, ], ], diff --git a/packages/cli/templates/scaffolder-module/src/actions/example/example.test.ts b/packages/cli/templates/scaffolder-module/src/actions/example/example.test.ts index 3f91a8f49d..242f93c2f3 100644 --- a/packages/cli/templates/scaffolder-module/src/actions/example/example.test.ts +++ b/packages/cli/templates/scaffolder-module/src/actions/example/example.test.ts @@ -22,7 +22,7 @@ describe('acme:example', () => { logStream: new PassThrough(), output: jest.fn(), createTemporaryDirectory() { - // Usage of mock-fs is recommended for testing of filesystem operations + // Usage of createMockDirectory is recommended for testing of filesystem operations throw new Error('Not implemented'); }, }); diff --git a/yarn.lock b/yarn.lock index 369b6c0356..4e26293aa8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3784,7 +3784,6 @@ __metadata: "@types/inquirer": ^8.1.3 "@types/jest": ^29.0.0 "@types/minimatch": ^5.0.0 - "@types/mock-fs": ^4.13.0 "@types/node": ^18.17.8 "@types/npm-packlist": ^3.0.0 "@types/recursive-readdir": ^2.2.0 @@ -3839,7 +3838,6 @@ __metadata: lodash: ^4.17.21 mini-css-extract-plugin: ^2.4.2 minimatch: ^5.1.1 - mock-fs: ^5.2.0 msw: ^1.0.0 node-fetch: ^2.6.7 node-libs-browser: ^2.2.1