Skip to content
This repository has been archived by the owner on Mar 15, 2024. It is now read-only.

Commit

Permalink
feat: support jest
Browse files Browse the repository at this point in the history
Remaining changes to support jest:
- Hook jest command/environment in the `configuration-accessor`
component.
- Add `jest` as a valid recorder in schema
- Add `jest` as a supported recorder in `receptor-file` component.
  • Loading branch information
lachrist committed Dec 7, 2022
1 parent 979b781 commit 26ed907
Show file tree
Hide file tree
Showing 10 changed files with 200 additions and 4 deletions.
1 change: 1 addition & 0 deletions components/configuration-accessor/default/.ordering
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
escape.mjs
package.mjs
mocha.mjs
jest.mjs
node.mjs
process.mjs
remote.mjs
Expand Down
46 changes: 46 additions & 0 deletions components/configuration-accessor/default/jest.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { coalesce } from "../../util/index.mjs";
import { convertFileUrlToPath } from "../../path/index.mjs";
import { toAbsoluteUrl } from "../../url/index.mjs";
import { escapeNodeOption, escapeShell } from "./escape.mjs";
import { generateParseSource, generateSplitTokens } from "./package.mjs";

const { canParseSource, parseSource } = generateParseSource("jest");
const { canSplitTokens, splitTokens } = generateSplitTokens("jest");

export const name = "jest";
export const recursive = null;

export const doesSupportSource = canParseSource;
export const doesSupportTokens = canSplitTokens;

export const hookCommandSource = (source, shell, base) => {
const groups = parseSource(source);
return [
`${groups.before} --runInBand --setupFilesAfterEnv ${escapeShell(
shell,
convertFileUrlToPath(toAbsoluteUrl("lib/node/recorder-jest.mjs", base)),
)}${groups.after}`,
];
};

export const hookCommandTokens = (tokens, base) => {
const { before, after } = splitTokens(tokens);
return [
...before,
"--runInBand",
"--setupFilesAfterEnv",
convertFileUrlToPath(toAbsoluteUrl("lib/node/recorder-jest.mjs", base)),
...after,
];
};

export const hookEnvironment = (env, base) => ({
...env,
NODE_OPTIONS: `${coalesce(
env,
"NODE_OPTIONS",
"",
)} --experimental-vm-modules --experimental-loader=${escapeNodeOption(
convertFileUrlToPath(toAbsoluteUrl("lib/node/loader-standalone.mjs", base)),
)}`,
});
49 changes: 49 additions & 0 deletions components/configuration-accessor/default/jest.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { assertDeepEqual, assertEqual } from "../../__fixture__.mjs";
import { fileURLToPath } from "node:url";
import {
doesSupportSource,
doesSupportTokens,
hookCommandSource,
hookCommandTokens,
hookEnvironment,
} from "./jest.mjs";

const base = "file:///A:/base/";
const recorder_path = fileURLToPath(
"file:///A:/base/lib/node/recorder-jest.mjs",
);
const loader_path = fileURLToPath(
"file:///A:/base/lib/node/loader-standalone.mjs",
);

//////////////////
// mocha --argv //
//////////////////

// source //
assertEqual(doesSupportSource("jest --argv"), true);
assertDeepEqual(hookCommandSource("jest --argv", "/bin/sh", base), [
`jest --runInBand --setupFilesAfterEnv ${recorder_path} --argv`,
]);

// tokens //
assertEqual(doesSupportTokens(["jest", "--argv"]), true);
assertDeepEqual(hookCommandTokens(["jest", "--argv"], base), [
"jest",
"--runInBand",
"--setupFilesAfterEnv",
recorder_path,
"--argv",
]);

/////////////////////
// hookEnvironment //
/////////////////////

assertDeepEqual(
hookEnvironment({ FOO: "bar", NODE_OPTIONS: "options" }, base),
{
FOO: "bar",
NODE_OPTIONS: `options --experimental-vm-modules --experimental-loader=${loader_path}`,
},
);
10 changes: 7 additions & 3 deletions components/receptor-file/default/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export const openReceptorAsync = async ({
appmap_dir: directory,
}) => {
assert(
recorder === "mocha" || recorder === "process",
recorder === "jest" || recorder === "mocha" || recorder === "process",
"invalid recorder for receptor-file",
InternalAppmapError,
);
Expand All @@ -90,9 +90,13 @@ export const openReceptorAsync = async ({
socket.removeAllListeners("message");
const configuration = parseJSON(content);
const { recorder } = configuration;
if (recorder !== "process" && recorder !== "mocha") {
if (
recorder !== "jest" &&
recorder !== "process" &&
recorder !== "mocha"
) {
logError(
"File receptor expected process/mocha recorder but got: %j",
"File receptor expected process/mocha/jest recorder but got: %j",
recorder,
);
socket.destroy();
Expand Down
1 change: 1 addition & 0 deletions components/receptor/default/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const Recepters = new Map([
["remote", ReceptorHttp],
["process", ReceptorFile],
["mocha", ReceptorFile],
["jest", ReceptorFile],
]);

export const minifyReceptorConfiguration = (configuration) => {
Expand Down
3 changes: 2 additions & 1 deletion components/recorder-jest/default/index.test.mjs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import process from "node:process";
import { platform as getPlatform } from "node:os";
import { spawn } from "child_process";

const { String, Error } = globalThis;

const child = spawn(
"npx",
getPlatform() === "win32" ? "npx.cmd" : "npx",
[
"jest",
"--runInBand",
Expand Down
9 changes: 9 additions & 0 deletions lib/node/recorder-jest.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { default as process } from "node:process";
import "./error.mjs";
import { configuration } from "./configuration.mjs";

const {
RecorderJest: { main },
} = await import("../../dist/bundles/recorder-cli.mjs");

main(process, configuration);
1 change: 1 addition & 0 deletions schema/definitions/recorder.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
enum:
- process
- mocha
- jest
- manual
- remote
1 change: 1 addition & 0 deletions test/system/cli/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ for (const name of [
"event-query",
"npx",
"mocha",
"jest",
// "remote",
]) {
stdout.write(`${"\n"}${name}${"\n"}`);
Expand Down
83 changes: 83 additions & 0 deletions test/system/cli/jest.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import {
writeFile as writeFileAsync,
readdir as readdirAsync,
} from "fs/promises";
import { platform as getPlatform } from "os";
import { strict as Assert } from "assert";
import { join as joinPath } from "path";
import { spawnStrictAsync } from "../../spawn.mjs";
import { runAsync } from "./__fixture__.mjs";

const { Set } = globalThis;

const { deepEqual: assertDeepEqual } = Assert;

await runAsync(
null,
{
command: [
getPlatform() === "win32" ? "npx.cmd" : "npx",
"jest",
"--testMatch",
"**/*.test.mjs",
],
recorder: "jest",
packages: { glob: "*" },
hooks: {
esm: true,
cjs: false,
apply: true,
http: false,
},
},
async (repository) => {
await spawnStrictAsync(
getPlatform() === "win32" ? "npm.cmd" : "npm",
["install", "jest"],
{ cwd: repository, stdio: "inherit" },
);
await writeFileAsync(
joinPath(repository, "main.mjs"),
`
export const main = () => "main";
export const mainAsync = async () => "main";
`,
"utf8",
);
await writeFileAsync(
joinPath(repository, "main.test.mjs"),
`
import * as Jest from "@jest/globals";
import { main, mainAsync } from "./main.mjs";
const { test, expect } = Jest;
test("main-sync", () => {
expect(main()).toBe("main");
});
test("main-async", async () => {
expect(await mainAsync()).toBe("main");
});
test("main-callback", (done) => {
mainAsync().then((res) => {
try {
expect(res).toBe("main");
done();
} catch (error) {
done(error);
}
});
});
`,
"utf8",
);
},
async (directory) => {
assertDeepEqual(
new Set(await readdirAsync(joinPath(directory, "tmp", "appmap", "jest"))),
new Set([
"main-sync.appmap.json",
"main-async.appmap.json",
"main-callback.appmap.json",
]),
);
},
);

0 comments on commit 26ed907

Please sign in to comment.