Skip to content

Commit

Permalink
Merge pull request #72 from gadget-inc/child-process-ignore
Browse files Browse the repository at this point in the history
Child process should ignore files that are specified in the ignore array
  • Loading branch information
jasong689 committed May 25, 2023
2 parents 8604c92 + 5b30ac2 commit b343562
Show file tree
Hide file tree
Showing 12 changed files with 224 additions and 69 deletions.
66 changes: 25 additions & 41 deletions spec/Supervisor.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ChildProcess, spawn } from "child_process";
import * as path from "path";
import { range } from "lodash";
import * as path from "path";

const childExit = (child: ChildProcess) => {
return new Promise<void>((resolve) => {
Expand All @@ -9,44 +9,40 @@ const childExit = (child: ChildProcess) => {
expect(code).toEqual(0);
});
});
}
};

test("it proxies ipc messages", async () => {
const binPath = path.join(__dirname, "../pkg/wds.bin.js");
const scriptPath = path.join(__dirname, "fixtures/src/add.ts");

const child = spawn(
"node",
[binPath, scriptPath],
{
stdio: ["inherit", "inherit", "inherit", "ipc"],
env: process.env,
}
);
const child = spawn("node", [binPath, scriptPath], {
stdio: ["inherit", "inherit", "inherit", "ipc"],
env: process.env,
});

const childHasBooted = new Promise<void>((resolve) => {
const handler = () => {
resolve();
child.off("message", handler)
child.off("message", handler);
};
child.on("message", handler)
})
child.on("message", handler);
});
await childHasBooted;

const messagesToChild = range(0, 3);
const messagesFromChild: Array<number> = [];

const promise = new Promise<void>((resolve) => {
child.on("message", (message: any) => {
messagesFromChild.push(message)
messagesFromChild.push(message);

if (messagesFromChild.length === messagesToChild.length) {
resolve();
}
});
});

for (let number of messagesToChild) {
for (const number of messagesToChild) {
child.send(number);
}

Expand All @@ -55,20 +51,16 @@ test("it proxies ipc messages", async () => {
await promise;

expect(messagesFromChild).toEqual([1, 2, 3]);
})
});

test("it doesn't setup ipc if it wasn't setup with ipc itself", async () => {
const binPath = path.join(__dirname, "../pkg/wds.bin.js");
const scriptPath = path.join(__dirname, "fixtures/src/no-ipc.ts");

const child = spawn(
"node",
[binPath, scriptPath],
{
stdio: ["inherit", "inherit", "inherit"],
env: process.env,
}
);
const child = spawn("node", [binPath, scriptPath], {
stdio: ["inherit", "inherit", "inherit"],
env: process.env,
});

await childExit(child);
});
Expand All @@ -77,13 +69,9 @@ test("it inherits stdin if WDS was started without terminal commands", async ()
const binPath = path.join(__dirname, "../pkg/wds.bin.js");
const scriptPath = path.join(__dirname, "fixtures/src/echo.ts");

const child = spawn(
"node",
[binPath, scriptPath],
{
env: process.env,
}
);
const child = spawn("node", [binPath, scriptPath], {
env: process.env,
});

let output = "";

Expand All @@ -92,7 +80,7 @@ test("it inherits stdin if WDS was started without terminal commands", async ()

child.stdout.on("data", (data) => {
output += data;
})
});

await childExit(child);
expect(output).toEqual("test");
Expand All @@ -102,13 +90,9 @@ test("it doesn't have any stdin if wds is started with terminal commands", async
const binPath = path.join(__dirname, "../pkg/wds.bin.js");
const scriptPath = path.join(__dirname, "fixtures/src/echo.ts");

const child = spawn(
"node",
[binPath, scriptPath, "--commands"],
{
env: process.env,
}
);
const child = spawn("node", [binPath, scriptPath, "--commands"], {
env: process.env,
});

let output = "";

Expand All @@ -117,9 +101,9 @@ test("it doesn't have any stdin if wds is started with terminal commands", async

child.stdout.on("data", (data) => {
output += data;
})
});

await childExit(child);

expect(output).toEqual("");
})
});
62 changes: 54 additions & 8 deletions spec/SwcCompiler.test.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,86 @@
import { MissingDestinationError, SwcCompiler } from '../src/SwcCompiler'
import * as fs from "fs/promises";
import os from "os";
import path from "path";
import { MissingDestinationError, SwcCompiler } from "../src/SwcCompiler";
import { log } from "../src/utils";

const compile = async (filename: string, root = "fixtures/src") => {
const workDir = await fs.mkdtemp(path.join(os.tmpdir(), "wds-test"));
const rootDir = path.join(__dirname, root);
const fullPath = path.join(rootDir, filename);

const compiler = new SwcCompiler(rootDir, workDir)
const compiler = new SwcCompiler(rootDir, workDir);
await compiler.compile(fullPath);
const compiledFilePath = (await compiler.fileGroup(fullPath))[fullPath]!;

return await fs.readFile(compiledFilePath, "utf-8");
}
};

test("compiles simple files", async () => {
const content = await compile("./simple.ts");
expect(content).toContain('console.log("success")')
expect(content).toContain('console.log("success")');
});

test("throws if the compilation fails", async () => {
await expect(compile("./failing/failing.ts", "fixtures/failing")).rejects.toThrow(MissingDestinationError);
})
});

test("throws if the file is ignored", async () => {
let error: MissingDestinationError | null = null;
try {
await compile("./files_with_config/ignored.ts");
} catch (e) {
if (e instanceof MissingDestinationError) {
error = e;
} else {
throw e;
}
}

expect(error).toBeDefined();
expect(error?.ignoredFile).toBeTruthy();
expect(error?.message).toMatch(
/File .+ignored\.ts is imported but not being built because it is explicitly ignored in the wds project config\. It is being ignored by the provided glob pattern '!ignored\.ts', remove this pattern from the project config or don't import this file to fix./
);
});

test("logs error when a file in group fails compilation but continues", async () => {
const errorLogs: any[] = [];

const mock = jest.spyOn(log, "error").mockImplementation((...args: any[]) => {
errorLogs.push(args);
});

const workDir = await fs.mkdtemp(path.join(os.tmpdir(), "wds-test"));
const rootDir = path.join(__dirname, "fixtures/failing");
const fullPath = path.join(rootDir, "successful.ts");
const compiler = new SwcCompiler(rootDir, workDir);
await compiler.compile(fullPath);
const group = await compiler.fileGroup(fullPath);

expect(group[fullPath]).toBeDefined();
expect(Object.entries(group).filter(([path]) => /.+(bar|successful)\.ts$/.test(path))).toHaveLength(2);
const error = errorLogs[0][0];
expect(error.code).toBe("GenericFailure");
expect(error.message).toMatch(/.+failing\.ts/);
expect(error.message).toMatch(/Syntax Error/);

mock.mockRestore();
});

test("compiles lazy import", async () => {
const content = await compile("./lazy_import.ts");
expect(content).toContain(`
expect(content).toContain(
`
function _child_process() {
const data = require(\"child_process\");
const data = require("child_process");
_child_process = function() {
return data;
};
return data;
}
`.trim());
`.trim()
);
});

test("uses the swc config file from wds.js", async () => {
Expand Down
1 change: 1 addition & 0 deletions spec/fixtures/failing/bar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const foo = "foo";
3 changes: 3 additions & 0 deletions spec/fixtures/failing/successful.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function success() {
return !!(1 + 1);
}
1 change: 1 addition & 0 deletions spec/fixtures/src/files_with_config/ignored.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// this is ignored
3 changes: 2 additions & 1 deletion spec/fixtures/src/files_with_config/wds.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ module.exports = {
"type": "commonjs",
"strictMode": false
}
}
},
ignore: ["ignored.ts"]
}
2 changes: 1 addition & 1 deletion spec/fixtures/src/wds.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ module.exports = {
"strictMode": true,
"lazy": true
}
}
},
}
90 changes: 90 additions & 0 deletions spec/wds.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import assert from "assert";
import type { ChildProcess } from "child_process";
import http from "http";
import path from "path";
import { Supervisor } from "../src/Supervisor";
import { wds } from "../src/index";

describe("wds", () => {
let cwd: any;
let supervisorRestart: any;
let socketPath: string;

const sendCompileRequest = async (filename: string) => {
assert(socketPath, "socketPath must be set");
const result = await new Promise((resolve, reject) => {
const request = http.request({ socketPath, path: "/compile", method: "POST", timeout: 200 }, (resp) => {
let data = "";
if (resp.statusCode !== 200) {
return reject(`Error compiling`);
}
resp.on("data", (chunk: string) => (data += chunk));
resp.on("end", () => resolve(JSON.parse(data).filenames));
});

request.on("error", (error) => {
reject(error);
});
request.write(filename);
request.end();
});

return result;
};

beforeEach(() => {
cwd = jest.spyOn(process, "cwd").mockImplementation(() => {
return path.resolve(__dirname, "fixtures/src/files_with_config");
});

supervisorRestart = jest.spyOn(Supervisor.prototype, "restart").mockImplementation(function () {
const self = this as unknown as Supervisor;
socketPath = self.socketPath;
self.process = {
on: jest.fn(),
} as unknown as ChildProcess;
return self.process;
});
});

afterEach(() => {
cwd.mockRestore();
supervisorRestart.mockRestore();
});

test("server responds to ignored files", async () => {
const server = await wds({
argv: [],
terminalCommands: false,
reloadOnChanges: false,
});
const result = (await sendCompileRequest(path.resolve(__dirname, "fixtures/src/files_with_config/ignored.ts"))) as Record<
string,
string | { ignored: boolean }
>;
const compiledKeys = Object.keys(result).filter((k) => /spec\/fixtures\/src\/files_with_config\/ignored\.ts/.test(k));
expect(compiledKeys).toHaveLength(1);
expect(result[compiledKeys[0]]).toEqual({
ignored: true,
});

server.close();
});

test("server responds to included files", async () => {
const server = await wds({
argv: [],
terminalCommands: false,
reloadOnChanges: false,
});
const result = (await sendCompileRequest(path.resolve(__dirname, "fixtures/src/files_with_config/simple.ts"))) as Record<
string,
string | { ignored: boolean }
>;
const compiledKeys = Object.keys(result).filter((k) => /spec\/fixtures\/src\/files_with_config\/simple\.ts/.test(k));
expect(compiledKeys).toHaveLength(1);
expect(typeof result[compiledKeys[0]]).toBe("string");

server.close();
});
});
Loading

0 comments on commit b343562

Please sign in to comment.