diff --git a/src/index.test.ts b/src/index.test.ts index 49c0172..c9eaf95 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -1,3 +1,4 @@ +import * as child_process from "child_process" import * as mockfs from "fs" jest.mock("node-fetch", () => () => Promise.resolve({ @@ -13,6 +14,7 @@ import yarn, { checkForRelease, checkForTypesInDeps, getNPMMetadataForDep, + getYarnMetadataForDep, } from "./index" const RealDate = Date @@ -38,6 +40,12 @@ beforeEach(() => { } } } + jest.spyOn(child_process, "execFile").mockImplementation( + ((file, args, callback) => { + callback(null, `{"type":"activityEnd","data":{"id":0}}\n{"type":"info","data":""}`, "") + return {} as any + }) as any + ) }) afterEach(() => { @@ -46,6 +54,10 @@ afterEach(() => { global.fail = undefined global.markdown = undefined global.Date = RealDate + const execFileSpy = child_process.execFile as any + if (execFileSpy.mockRestore) { + execFileSpy.mockRestore() + } }) describe("checkForRelease", () => { @@ -145,6 +157,27 @@ describe("npm metadata", () => { }) }) +describe("yarn metadata", () => { + it("passes dependency names to yarn why without using a shell command string", async () => { + const dep = "danger'; touch SUCCESS; #" + const execFileSpy = child_process.execFile as any + execFileSpy.mockClear() + execFileSpy.mockImplementation( + ((file, args, callback) => { + expect(file).toBe(process.platform === "win32" ? "yarn.cmd" : "yarn") + expect(args).toEqual(["why", dep, "--json"]) + callback(null, `{"type":"activityEnd","data":{"id":0}}\n{"type":"info","data":"Found why output"}`, "") + return {} as any + }) as any + ) + + const result = await getYarnMetadataForDep(dep) + + expect(execFileSpy).toHaveBeenCalledTimes(1) + expect(result).toContain("Found why output") + }) +}) + describe("Feature Flags", () => { it("should skip checkForRelease if options.disableCheckForRelease is provided", async () => { await _operateOnSingleDiff( diff --git a/src/index.ts b/src/index.ts index 7f50dd6..928387f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -99,7 +99,8 @@ export const findNewDependencies = (packageDiff: JSONDiff) => { export const getYarnMetadataForDep = async dep => { return new Promise(resolve => { - child_process.exec(`yarn why '${dep}' --json`, (err, output) => { + const yarnExecutable = process.platform === "win32" ? "yarn.cmd" : "yarn" + child_process.execFile(yarnExecutable, ["why", dep, "--json"], (err, output) => { if (output) { // Comes as a series of little JSON messages const usefulJSONContents = output.toString().split(`{"type":"activityEnd","data":{"id":0}}`).pop() as string