158 lines
5.7 KiB
TypeScript
158 lines
5.7 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
|
|
import { analyzeJavaScriptStaticSource } from "./javascriptStaticAnalysis.js";
|
|
|
|
describe.each(["webPreferences", "serviceName"] as const)(
|
|
"Electron %s option lookup",
|
|
(name) => {
|
|
const value =
|
|
name === "webPreferences"
|
|
? '{ preload: "./kept.js", sandbox: true }'
|
|
: '"kept"';
|
|
const explicit = `${name}: ${value}`;
|
|
const method = `${name}() { return ${value}; }`;
|
|
const getter = `get ${name}() { return ${value}; }`;
|
|
const setter = `set ${name}(value) {}`;
|
|
|
|
const explicitCases = [
|
|
["plain key", explicit],
|
|
["quoted key", `"${name}": ${value}`],
|
|
["computed string key", `["${name}"]: ${value}`],
|
|
["duplicate key", `${name}: null, ${explicit}`],
|
|
["computed duplicate key", `${name}: null, ["${name}"]: ${value}`],
|
|
["earlier spread", `...options, ${explicit}`],
|
|
["earlier computed identifier", `[key]: null, ${explicit}`],
|
|
["earlier computed expression", `[getKey()]: null, ${explicit}`],
|
|
["earlier getter", `${getter}, ${explicit}`],
|
|
["earlier method", `${method}, ${explicit}`],
|
|
["unrelated later key", `${explicit}, title: "title"`],
|
|
["unrelated computed literal", `${explicit}, ["title"]: null`],
|
|
["unrelated numeric key", `${explicit}, [1]: null`],
|
|
["unrelated empty key", `${explicit}, [""]: null`],
|
|
["unrelated getter", `${explicit}, get title() { return "title"; }`],
|
|
];
|
|
|
|
it.each(explicitCases)(
|
|
"retains the explicit value with %s",
|
|
(_, members) => {
|
|
const analysis = analyzeOption(name, `{ ${members} }`);
|
|
expect(analysis.parse_status).toBe("complete");
|
|
if (name === "webPreferences") {
|
|
expect(analysis.electron.browser_windows).toEqual([
|
|
expect.objectContaining({
|
|
options_status: "object-literal",
|
|
web_preferences_status: "object-literal",
|
|
preload_path: "./kept.js",
|
|
preload_resolution_context: "module-specifier",
|
|
web_preferences: [
|
|
{ name: "preload", value: literal("./kept.js") },
|
|
{ name: "sandbox", value: literal(true) },
|
|
],
|
|
}),
|
|
]);
|
|
} else {
|
|
expect(analysis.electron.utility_processes).toEqual([
|
|
expect.objectContaining({ service_name: "kept" }),
|
|
]);
|
|
}
|
|
},
|
|
);
|
|
|
|
const dynamicCases = [
|
|
["same-spelled computed binding", `[${name}]: ${value}`],
|
|
["different computed binding", `[key]: ${value}`],
|
|
["computed expression", `[getKey()]: ${value}`],
|
|
["unevaluated template key", `[\`${name}\`]: ${value}`],
|
|
["spread only", "...options"],
|
|
["later spread", `${explicit}, ...options`],
|
|
["later computed binding", `${explicit}, [key]: null`],
|
|
["later computed expression", `${explicit}, [getKey()]: null`],
|
|
["exact getter", getter],
|
|
["exact setter", setter],
|
|
["exact method", method],
|
|
["computed string method", `["${name}"]() { return ${value}; }`],
|
|
["overriding getter", `${explicit}, ${getter}`],
|
|
["overriding setter", `${explicit}, ${setter}`],
|
|
["overriding method", `${explicit}, ${method}`],
|
|
["dynamic explicit value", `${name}: dynamicValue`],
|
|
["null explicit value", `${name}: null`],
|
|
["duplicate null value", `${explicit}, ${name}: null`],
|
|
];
|
|
|
|
it.each(dynamicCases)("preserves uncertainty for %s", (_, members) => {
|
|
expectUnknownOption(name, `{ ${members} }`, "object-literal");
|
|
});
|
|
|
|
it.each(["null", "options"])(
|
|
"preserves nonliteral options %s",
|
|
(options) => {
|
|
expectUnknownOption(name, options, "dynamic");
|
|
},
|
|
);
|
|
|
|
it.each(["", "{}", '{ title: "title", ["other"]: null }'])(
|
|
"reports an omitted option in %s without inventing a default",
|
|
(options) => {
|
|
const analysis = analyzeOption(name, options);
|
|
expect(analysis.parse_status).toBe("complete");
|
|
if (name === "webPreferences")
|
|
expect(analysis.electron.browser_windows[0]).toMatchObject({
|
|
options_status: options === "" ? "missing" : "object-literal",
|
|
web_preferences_status: "missing",
|
|
web_preferences: [],
|
|
preload_path: null,
|
|
preload_resolution_context: null,
|
|
});
|
|
else
|
|
expect(
|
|
analysis.electron.utility_processes[0]?.service_name,
|
|
).toBeNull();
|
|
},
|
|
);
|
|
},
|
|
);
|
|
|
|
type OptionName = "webPreferences" | "serviceName";
|
|
|
|
const analyzeOption = (name: OptionName, options: string) =>
|
|
analyzeJavaScriptStaticSource(`
|
|
const webPreferences = "title";
|
|
const serviceName = "env";
|
|
${
|
|
name === "webPreferences"
|
|
? `new BrowserWindow(${options});`
|
|
: `utilityProcess.fork("./worker.js", []${options === "" ? "" : `, ${options}`});`
|
|
}
|
|
`);
|
|
|
|
const literal = (value: string | boolean) => ({
|
|
status: "literal",
|
|
value,
|
|
expression: null,
|
|
});
|
|
|
|
const expectUnknownOption = (
|
|
name: OptionName,
|
|
options: string,
|
|
optionsStatus: "object-literal" | "dynamic",
|
|
): void => {
|
|
const analysis = analyzeOption(name, options);
|
|
expect(analysis.parse_status).toBe("partial");
|
|
expect(analysis.parse_error_count).toBe(0);
|
|
expect(analysis.limitations.join(" ")).toContain("remain unknown");
|
|
if (name === "webPreferences")
|
|
expect(analysis.electron.browser_windows[0]).toMatchObject({
|
|
options_status: optionsStatus,
|
|
web_preferences_status: "dynamic",
|
|
web_preferences: [],
|
|
preload_path: null,
|
|
preload_resolution_context: null,
|
|
});
|
|
else
|
|
expect(analysis.electron.utility_processes[0]).toMatchObject({
|
|
module_path: "./worker.js",
|
|
module_expression: null,
|
|
service_name: null,
|
|
});
|
|
};
|