import { transformer } from "../src/transforms/add-package-manager"; import { setupTestFixtures } from "@turbo/test-utils"; import fs from "fs-extra"; import * as getPackageManager from "../src/utils/getPackageManager"; import * as getPackageManagerVersion from "../src/utils/getPackageManagerVersion"; describe("add-package-manager", () => { const { useFixture } = setupTestFixtures({ directory: __dirname, test: "add-package-manager", }); test("no package manager - basic", () => { // load the fixture for the test const { root, read } = useFixture({ fixture: "no-package-manager" }); const packageManager = "pnpm"; const packageManagerVersion = "1.2.3"; // mock out workspace and version detection so we're not dependent on our actual repo const mockGetPackageManagerVersion = jest .spyOn(getPackageManagerVersion, "default") .mockReturnValue(packageManagerVersion); const mockGetPackageManager = jest .spyOn(getPackageManager, "default") .mockReturnValue(packageManager); // package manager should not exist expect( JSON.parse(read("package.json") || "{}").packageManager ).toBeUndefined(); // run the transformer const result = transformer({ root, options: { force: false, dry: false, print: false }, }); expect(mockGetPackageManager).toHaveBeenCalledWith({ directory: root }); expect(mockGetPackageManagerVersion).toHaveBeenCalledWith( packageManager, root ); // package manager should now exist expect(JSON.parse(read("package.json") || "{}").packageManager).toBe( `${packageManager}@${packageManagerVersion}` ); // result should be correct expect(result.changes).toMatchInlineSnapshot(` Object { "package.json": Object { "action": "modified", "additions": 1, "deletions": 0, }, } `); mockGetPackageManagerVersion.mockRestore(); mockGetPackageManager.mockRestore(); }); test("no package manager - repeat run", () => { // load the fixture for the test const { root, read } = useFixture({ fixture: "no-package-manager" }); const packageManager = "pnpm"; const packageManagerVersion = "1.2.3"; // mock out workspace and version detection so we're not dependent on our actual repo const mockGetPackageManagerVersion = jest .spyOn(getPackageManagerVersion, "default") .mockReturnValue(packageManagerVersion); const mockGetPackageManager = jest .spyOn(getPackageManager, "default") .mockReturnValue(packageManager); // package manager should not exist expect( JSON.parse(read("package.json") || "{}").packageManager ).toBeUndefined(); // run the transformer const result = transformer({ root, options: { force: false, dry: false, print: false }, }); expect(mockGetPackageManager).toHaveBeenCalledWith({ directory: root }); expect(mockGetPackageManagerVersion).toHaveBeenCalled(); expect(mockGetPackageManagerVersion).toHaveBeenCalledWith( packageManager, root ); // package manager should now exist expect(JSON.parse(read("package.json") || "{}").packageManager).toBe( `${packageManager}@${packageManagerVersion}` ); // result should be correct expect(result.fatalError).toBeUndefined(); expect(result.changes).toMatchInlineSnapshot(` Object { "package.json": Object { "action": "modified", "additions": 1, "deletions": 0, }, } `); // run the transformer again to ensure nothing changes on a second run const repeatResult = transformer({ root, options: { force: false, dry: false, print: false }, }); expect(repeatResult.fatalError).toBeUndefined(); expect(repeatResult.changes).toMatchInlineSnapshot(` Object { "package.json": Object { "action": "unchanged", "additions": 0, "deletions": 0, }, } `); mockGetPackageManagerVersion.mockRestore(); mockGetPackageManager.mockRestore(); }); test("no package manager - dry", () => { // load the fixture for the test const { root, read } = useFixture({ fixture: "no-package-manager" }); const packageManager = "npm"; const packageManagerVersion = "1.2.3"; // mock out workspace and version detection so we're not dependent on our actual repo const mockGetPackageManagerVersion = jest .spyOn(getPackageManagerVersion, "default") .mockReturnValue(packageManagerVersion); const mockGetPackageManager = jest .spyOn(getPackageManager, "default") .mockReturnValue(packageManager); // package manager should not exist expect( JSON.parse(read("package.json") || "{}").packageManager ).toBeUndefined(); // run the transformer const result = transformer({ root, options: { force: false, dry: true, print: false }, }); expect(mockGetPackageManager).toHaveBeenCalledWith({ directory: root }); expect(mockGetPackageManagerVersion).toHaveBeenCalledWith( packageManager, root ); // package manager should not exist expect( JSON.parse(read("package.json") || "{}").packageManager ).toBeUndefined(); // result should be correct expect(result.changes).toMatchInlineSnapshot(` Object { "package.json": Object { "action": "skipped", "additions": 1, "deletions": 0, }, } `); mockGetPackageManagerVersion.mockRestore(); }); test("no package manager - print", () => { // load the fixture for the test const { root, read } = useFixture({ fixture: "no-package-manager" }); const packageManager = "yarn"; const packageManagerVersion = "1.2.3"; // mock out workspace and version detection so we're not dependent on our actual repo const mockGetPackageManagerVersion = jest .spyOn(getPackageManagerVersion, "default") .mockReturnValue(packageManagerVersion); const mockGetPackageManager = jest .spyOn(getPackageManager, "default") .mockReturnValue(packageManager); // package manager should not exist expect( JSON.parse(read("package.json") || "{}").packageManager ).toBeUndefined(); // run the transformer const result = transformer({ root, options: { force: false, dry: false, print: true }, }); expect(mockGetPackageManager).toHaveBeenCalledWith({ directory: root }); expect(mockGetPackageManagerVersion).toHaveBeenCalledWith( packageManager, root ); // package manager should now exist expect(JSON.parse(read("package.json") || "{}").packageManager).toBe( `${packageManager}@${packageManagerVersion}` ); // result should be correct expect(result.changes).toMatchInlineSnapshot(` Object { "package.json": Object { "action": "modified", "additions": 1, "deletions": 0, }, } `); mockGetPackageManagerVersion.mockRestore(); }); test("no package manager - dry & print", () => { // load the fixture for the test const { root, read } = useFixture({ fixture: "no-package-manager" }); const packageManager = "npm"; const packageManagerVersion = "1.2.3"; // mock out workspace and version detection so we're not dependent on our actual repo const mockGetPackageManagerVersion = jest .spyOn(getPackageManagerVersion, "default") .mockReturnValue(packageManagerVersion); const mockGetPackageManager = jest .spyOn(getPackageManager, "default") .mockReturnValue(packageManager); // package manager should not exist expect( JSON.parse(read("package.json") || "{}").packageManager ).toBeUndefined(); // run the transformer const result = transformer({ root, options: { force: false, dry: true, print: true }, }); expect(mockGetPackageManager).toHaveBeenCalledWith({ directory: root }); expect(mockGetPackageManagerVersion).toHaveBeenCalledWith( packageManager, root ); // package manager should not exist expect( JSON.parse(read("package.json") || "{}").packageManager ).toBeUndefined(); // result should be correct expect(result.changes).toMatchInlineSnapshot(` Object { "package.json": Object { "action": "skipped", "additions": 1, "deletions": 0, }, } `); mockGetPackageManagerVersion.mockRestore(); mockGetPackageManager.mockRestore(); }); test("package manager already exists", () => { // load the fixture for the test const { root, read } = useFixture({ fixture: "has-package-manager" }); const packageManager = "npm"; const packageManagerVersion = "1.2.3"; // mock out workspace and version detection so we're not dependent on our actual repo const mockGetPackageManagerVersion = jest .spyOn(getPackageManagerVersion, "default") .mockReturnValue(packageManagerVersion); const mockGetPackageManager = jest .spyOn(getPackageManager, "default") .mockReturnValue(packageManager); // package manager should exist expect(JSON.parse(read("package.json") || "{}").packageManager).toBe( `${packageManager}@${packageManagerVersion}` ); // run the transformer const result = transformer({ root, options: { force: false, dry: false, print: false }, }); expect(mockGetPackageManager).toHaveBeenCalledWith({ directory: root }); expect(mockGetPackageManagerVersion).toHaveBeenCalledWith( packageManager, root ); // package manager should still exist expect(JSON.parse(read("package.json") || "{}").packageManager).toBe( `${packageManager}@${packageManagerVersion}` ); // result should be correct expect(result.changes).toMatchInlineSnapshot(` Object { "package.json": Object { "action": "unchanged", "additions": 0, "deletions": 0, }, } `); mockGetPackageManagerVersion.mockRestore(); mockGetPackageManager.mockRestore(); }); test("package manager exists but is wrong", () => { // load the fixture for the test const { root, read } = useFixture({ fixture: "wrong-package-manager" }); const packageManager = "pnpm"; const packageManagerVersion = "1.2.3"; // mock out workspace and version detection so we're not dependent on our actual repo const mockGetPackageManagerVersion = jest .spyOn(getPackageManagerVersion, "default") .mockReturnValue(packageManagerVersion); const mockGetPackageManager = jest .spyOn(getPackageManager, "default") .mockReturnValue(packageManager); // package manager should exist expect(JSON.parse(read("package.json") || "{}").packageManager).toBe( "turbo@1.7.0" ); // run the transformer const result = transformer({ root, options: { force: false, dry: false, print: false }, }); expect(mockGetPackageManager).toHaveBeenCalledWith({ directory: root }); expect(mockGetPackageManagerVersion).toHaveBeenCalledWith( packageManager, root ); // package manager should still exist expect(JSON.parse(read("package.json") || "{}").packageManager).toBe( `${packageManager}@${packageManagerVersion}` ); // result should be correct expect(result.changes).toMatchInlineSnapshot(` Object { "package.json": Object { "action": "modified", "additions": 1, "deletions": 1, }, } `); mockGetPackageManagerVersion.mockRestore(); mockGetPackageManager.mockRestore(); }); test("errors when unable to determine workspace manager", () => { // load the fixture for the test const { root, read } = useFixture({ fixture: "no-package-manager" }); const mockGetPackageManager = jest .spyOn(getPackageManager, "default") .mockReturnValue(undefined); // package manager should not exist expect( JSON.parse(read("package.json") || "{}").packageManager ).toBeUndefined(); // run the transformer const result = transformer({ root, options: { force: false, dry: false, print: false }, }); expect(mockGetPackageManager).toHaveBeenCalledTimes(1); expect(mockGetPackageManager).toHaveBeenCalledWith({ directory: root }); // result should be correct // result should be correct expect(result.fatalError?.message).toMatch( /Unable to determine package manager for .*?/ ); mockGetPackageManager.mockRestore(); }); test("errors when unable to determine package manager", () => { // load the fixture for the test const { root, read } = useFixture({ fixture: "no-package-manager" }); const mockGetPackageManagerVersion = jest .spyOn(getPackageManagerVersion, "default") .mockImplementation(() => { throw new Error("package manager not supported"); }); // package manager should not exist expect( JSON.parse(read("package.json") || "{}").packageManager ).toBeUndefined(); // run the transformer const result = transformer({ root, options: { force: false, dry: false, print: false }, }); expect(mockGetPackageManagerVersion).toHaveBeenCalledTimes(1); // result should be correct expect(result.fatalError?.message).toMatch( /Unable to determine package manager version for .*?/ ); mockGetPackageManagerVersion.mockRestore(); }); test("errors when unable to write json", () => { // load the fixture for the test const { root, read } = useFixture({ fixture: "no-package-manager" }); const packageManager = "pnpm"; const packageManagerVersion = "1.2.3"; // mock out workspace and version detection so we're not dependent on our actual repo const mockGetPackageManagerVersion = jest .spyOn(getPackageManagerVersion, "default") .mockReturnValue(packageManagerVersion); const mockGetPackageManager = jest .spyOn(getPackageManager, "default") .mockReturnValue(packageManager); const mockWriteJsonSync = jest .spyOn(fs, "writeJsonSync") .mockImplementation(() => { throw new Error("could not write file"); }); // package manager should not exist expect( JSON.parse(read("package.json") || "{}").packageManager ).toBeUndefined(); // run the transformer const result = transformer({ root, options: { force: false, dry: false, print: false }, }); expect(mockGetPackageManager).toHaveBeenCalledWith({ directory: root }); expect(mockGetPackageManagerVersion).toHaveBeenCalledWith( packageManager, root ); // package manager should still not exist (we couldn't write it) expect( JSON.parse(read("package.json") || "{}").packageManager ).toBeUndefined(); // result should be correct expect(result.fatalError?.message).toMatch( "Encountered an error while transforming files" ); expect(result.changes).toMatchInlineSnapshot(` Object { "package.json": Object { "action": "error", "additions": 1, "deletions": 0, "error": [Error: could not write file], }, } `); mockWriteJsonSync.mockRestore(); mockGetPackageManagerVersion.mockRestore(); mockGetPackageManager.mockRestore(); }); });