From 28c9eeec36ae105cd0231a998636ba6d255fd8a3 Mon Sep 17 00:00:00 2001 From: Iku-turso Date: Wed, 31 May 2023 17:28:02 +0300 Subject: [PATCH] feat: Make lens-webpack-build cope long lasting processes, eg. watch Co-authored-by: Janne Savolainen Signed-off-by: Mikko Aspiala Signed-off-by: Iku-turso --- .../src/scripts/do-webpack-build.test.ts | 76 +++++++------------ .../webpack/src/scripts/do-webpack-build.ts | 19 ++--- .../webpack/src/scripts/exec.injectable.ts | 7 +- 3 files changed, 38 insertions(+), 64 deletions(-) diff --git a/packages/infrastructure/webpack/src/scripts/do-webpack-build.test.ts b/packages/infrastructure/webpack/src/scripts/do-webpack-build.test.ts index c428de1e21..d388c1fbb4 100644 --- a/packages/infrastructure/webpack/src/scripts/do-webpack-build.test.ts +++ b/packages/infrastructure/webpack/src/scripts/do-webpack-build.test.ts @@ -1,5 +1,5 @@ import { getDi } from "./get-di"; -import { Exec, execInjectable } from "./exec.injectable"; +import { execInjectable } from "./exec.injectable"; import asyncFn, { AsyncFnMock } from "@async-fn/jest"; import { DoWebpackBuild, doWebpackBuildInjectable } from "./do-webpack-build"; import { getPromiseStatus } from "@ogre-tools/test-utils"; @@ -7,16 +7,22 @@ import { LogSuccess, logSuccessInjectable } from "./log-success.injectable"; import { LogWarning, logWarningInjectable } from "./log-warning.injectable"; describe("do-webpack-build", () => { - let execMock: AsyncFnMock; + let execMock: jest.Mock; let doWebpackBuild: DoWebpackBuild; let logSuccessMock: AsyncFnMock; let logWarningMock: AsyncFnMock; + let execResultStub: { stdout: { on: any }; stderr: { on: any }; on: any }; beforeEach(() => { const di = getDi(); - execMock = asyncFn(); - di.override(execInjectable, () => execMock); + execResultStub = { + stdout: { on: jest.fn() }, + stderr: { on: jest.fn() }, + on: jest.fn(), + }; + execMock = jest.fn().mockReturnValue(execResultStub); + di.override(execInjectable, () => execMock as any); logSuccessMock = asyncFn(); di.override(logSuccessInjectable, () => logSuccessMock); logWarningMock = asyncFn(); @@ -36,58 +42,32 @@ describe("do-webpack-build", () => { expect(execMock).toHaveBeenCalledWith("webpack"); }); - it("does not resolve yet", async () => { + it("data in stdout logs as success", () => { + const listeners = execResultStub.stdout.on.mock.calls; + + expect(listeners).toEqual([["data", logSuccessMock]]); + }); + + it("data in stderr logs as warning", () => { + const listeners = execResultStub.stderr.on.mock.calls; + + expect(listeners).toEqual([["data", logWarningMock]]); + }); + + it("script is not done yet", async () => { const promiseStatus = await getPromiseStatus(actualPromise); expect(promiseStatus.fulfilled).toBe(false); }); - describe("when webpack resolves with stdout", () => { - beforeEach(async () => { - await execMock.resolve({ stdout: "some-stdout", stderr: "" }); - }); + it("when execution of webpack exits, script is done", async () => { + const [[eventName, finishWebpack]] = execResultStub.on.mock.calls; - it("logs the stdout", () => { - expect(logSuccessMock).toHaveBeenCalledWith("some-stdout"); - }); + eventName === "exit" && finishWebpack(); - it("script is done", async () => { - const promiseStatus = await getPromiseStatus(actualPromise); + const promiseStatus = await getPromiseStatus(actualPromise); - expect(promiseStatus.fulfilled).toBe(true); - }); - }); - - describe("when webpack resolves with stderr", () => { - beforeEach(() => { - execMock.resolve({ stdout: "", stderr: "some-stderr" }); - }); - - it("does not log success", () => { - actualPromise.catch(() => {}); - - expect(logSuccessMock).not.toHaveBeenCalled(); - }); - - it("logs a warning", () => { - expect(logWarningMock).toBeCalledWith("Warning while executing \"webpack\": some-stderr"); - }); - }); - - describe("when webpack rejects", () => { - beforeEach(async () => { - execMock.reject(new Error("some-error")); - }); - - it("does not log success", () => { - actualPromise.catch(() => {}); - - expect(logSuccessMock).not.toHaveBeenCalled(); - }); - - it("throws", () => { - return expect(actualPromise).rejects.toThrow("some-error"); - }); + expect(promiseStatus.fulfilled).toBe(true); }); }); }); diff --git a/packages/infrastructure/webpack/src/scripts/do-webpack-build.ts b/packages/infrastructure/webpack/src/scripts/do-webpack-build.ts index d2118256f7..6252536f4c 100644 --- a/packages/infrastructure/webpack/src/scripts/do-webpack-build.ts +++ b/packages/infrastructure/webpack/src/scripts/do-webpack-build.ts @@ -13,18 +13,15 @@ export const doWebpackBuildInjectable = getInjectable({ const logSuccess = di.inject(logSuccessInjectable); const logWarning = di.inject(logWarningInjectable); - const execWithResultHandling = async (command: string) => { - const { stdout, stderr } = await exec(command); - - if (stderr) { - logWarning(`Warning while executing "${command}": ${stderr}`); - } else if (stdout) { - logSuccess(stdout); - } - }; - return async () => { - await execWithResultHandling("webpack"); + const execResult = exec("webpack"); + + execResult.stdout?.on("data", logSuccess); + execResult.stderr?.on("data", logWarning); + + return new Promise((resolve) => { + execResult.on("exit", resolve); + }); }; }, }); diff --git a/packages/infrastructure/webpack/src/scripts/exec.injectable.ts b/packages/infrastructure/webpack/src/scripts/exec.injectable.ts index 893520fcc0..4797a55edf 100644 --- a/packages/infrastructure/webpack/src/scripts/exec.injectable.ts +++ b/packages/infrastructure/webpack/src/scripts/exec.injectable.ts @@ -1,12 +1,9 @@ import { getInjectable } from "@ogre-tools/injectable"; import { exec } from "child_process"; -import { promisify } from "util"; -const promisifiedExec = promisify(exec); - -export type Exec = typeof promisifiedExec; +export type Exec = typeof exec; export const execInjectable = getInjectable({ id: "exec", - instantiate: () => promisifiedExec, + instantiate: () => exec, });