diff --git a/src/services/offlineService.test.ts b/src/services/offlineService.test.ts index c8fc4f49..df392ba4 100644 --- a/src/services/offlineService.test.ts +++ b/src/services/offlineService.test.ts @@ -7,10 +7,7 @@ import { MockFactory } from "../test/mockFactory"; import { OfflineService } from "./offlineService"; describe("Offline Service", () => { - - const mySpawn = mockSpawn(); - require("child_process").spawn = mySpawn; - mySpawn.setDefault(mySpawn.simple(0, "Exit code")); + let mySpawn; function createService(sls?: Serverless): OfflineService { return new OfflineService( @@ -21,12 +18,16 @@ describe("Offline Service", () => { beforeEach(() => { // Mocking the file system so that files are not created in project directory - mockFs({}) + mockFs({}); + + mySpawn = mockSpawn(); + require("child_process").spawn = mySpawn; + mySpawn.setDefault(mySpawn.simple(0, "Exit code")); }); afterEach(() => { mockFs.restore(); - }) + }); it("builds required files for offline execution", async () => { const sls = MockFactory.createTestServerless(); @@ -113,7 +114,12 @@ describe("Offline Service", () => { rmdirSpy.mockRestore(); }); - it("instructs users how to run locally", async () => { + it("calls func host start on Mac OS", async () => { + Object.defineProperty(process, "platform", { + value: "darwin", + writable: true, + }); + const sls = MockFactory.createTestServerless(); const service = createService(sls); await service.start(); @@ -123,4 +129,20 @@ describe("Offline Service", () => { expect(call.command).toEqual("func"); expect(call.args).toEqual(["host", "start"]); }); + + it("calls func host start on windows", async () => { + Object.defineProperty(process, "platform", { + value: "win32", + writable: true, + }); + + const sls = MockFactory.createTestServerless(); + const service = createService(sls); + await service.start(); + const calls = mySpawn.calls; + expect(calls).toHaveLength(1); + const call = calls[0]; + expect(call.command).toEqual("func.cmd"); + expect(call.args).toEqual(["host", "start"]); + }); }); diff --git a/src/services/offlineService.ts b/src/services/offlineService.ts index 40ac8551..996a1cc4 100644 --- a/src/services/offlineService.ts +++ b/src/services/offlineService.ts @@ -1,4 +1,4 @@ -import { spawn } from "child_process"; +import { spawn, SpawnOptions } from "child_process"; import fs from "fs"; import Serverless from "serverless"; import configConstants from "../config"; @@ -29,7 +29,7 @@ export class OfflineService extends BaseService { await this.packageService.createBindings(); const filenames = Object.keys(this.localFiles); for (const filename of filenames) { - if (!fs.existsSync(filename)){ + if (!fs.existsSync(filename)) { fs.writeFileSync( filename, this.localFiles[filename] @@ -44,7 +44,7 @@ export class OfflineService extends BaseService { await this.packageService.cleanUp(); const filenames = Object.keys(this.localFiles); for (const filename of filenames) { - if (fs.existsSync(filename)){ + if (fs.existsSync(filename)) { this.log(`Removing file '${filename}'`); fs.unlinkSync(filename) } @@ -62,59 +62,30 @@ export class OfflineService extends BaseService { /** * Spawn a Node child process with predefined environment variables * @param command CLI Command - NO ARGS - * @param args Array of arguments for CLI command - * @param env Additional environment variables to be set in addition to - * predefined variables in `serverless.yml` + * @param spawnArgs Array of arguments for CLI command */ - private spawn(command: string, args?: string[], env?: any): Promise { - env = { + private spawn(command: string, spawnArgs?: string[]): Promise { + if (process.platform === "win32") { + command += ".cmd"; + } + + const env = { + // Inherit environment from current process, most importantly, the PATH + ...process.env, + // Environment variables from serverless config are king ...this.serverless.service.provider["environment"], - ...env } - this.log(`Spawning process '${command} ${args.join(" ")}'`); + this.log(`Spawning process '${command} ${spawnArgs.join(" ")}'`); return new Promise((resolve, reject) => { - const childProcess = spawn(command, args, {env}); - - childProcess.stdout.on("data", (data) => { - this.log(data, { - color: configConstants.funcConsoleColor, - }, command); - }); - - childProcess.stderr.on("data", (data) => { - this.log(data, { - color: "red", - }, command); - }) - - childProcess.on("message", (message) => { - this.log(message, { - color: configConstants.funcConsoleColor, - }, command); - }); - - childProcess.on("error", (err) => { - this.log(`${err}`, { - color: "red" - }, command); - reject(err); - }); + const spawnOptions: SpawnOptions = { env, stdio: "inherit" }; + const childProcess = spawn(command, spawnArgs, spawnOptions); childProcess.on("exit", (code) => { - this.log(`Exited with code: ${code}`, { - color: (code === 0) ? "green" : "red", - }, command); - }); - - childProcess.on("close", (code) => { - this.log(`Closed with code: ${code}`, { - color: (code === 0) ? "green" : "red", - }, command); - resolve(); - }); - - childProcess.on("disconnect", () => { - this.log("Process disconnected"); + if (code === 0) { + resolve(); + } else { + reject(); + } }); }); }