Files
rea/src/browser/PlaywrightElectronActiveProjection.test.ts
T
bf3475867f fix(electron): preserve native IPC listener behavior (#4389)
Preserve original-function removal, native IPC dispatch and argument identity, with explicit metadata ownership and Evidence verification. Runtime cleanup limitations remain documented.

Fixes #4390.

Co-authored-by: Adolanium <94890352+Adolanium@users.noreply.github.com>
Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
2026-10-17 04:17:11 +08:00

256 lines
7.7 KiB
TypeScript

import { expect, it } from "vitest";
import { projectElectronActiveCapture } from "./PlaywrightElectronActiveProjection.js";
const event = {
sequence: 1,
correlation_id: "capture:123:1",
kind: "main-handler-invocation" as const,
event: null,
phase: "observed" as const,
channel: "readiness:echo",
direction: "renderer-to-main" as const,
sender: null,
receiver: "main",
frame: null,
target: null,
argument_shapes: [],
result_shape: null,
process_type: "main",
source: "electron-active-hook",
capture_method: "api-wrapper" as const,
artifact_path: null,
artifact_sha256: null,
error: false,
};
it.each(["custom-apply", "listener-chain"])(
"keeps %s gaps distinct from captured IPC and retention loss",
(boundary) => {
const result = projectElectronActiveCapture(
{ executable: "/opt/electron", application: "/opt/app/main.js" },
[],
{
windows: [],
metrics: [],
electronVersion: "test-electron",
hookSnapshot: {
events: [
{
...event,
kind: "ipc-observation-gap",
event: boundary,
channel: "custom",
direction: null,
receiver: null,
target: "ipcMain.on",
},
],
retention_budget_bytes: 16 * 1024 * 1024,
estimated_retained_bytes: 1_024,
event_serialized_byte_upper_bound: 512,
retained: 1,
dropped: 2,
dropped_ipc: 0,
dropped_runtime: 2,
dropped_event_families: [{ family: "ipc-observation-gap", count: 2 }],
dropped_event_roles: [{ role: "main", count: 2 }],
observed: 3,
observed_ipc: 0,
observed_runtime: 3,
hook_error: false,
},
},
);
expect(result.ipc).toEqual({ events: [], observed: 0, dropped: 0 });
expect(result.timeline.events[0]).toMatchObject({
kind: "ipc-observation-gap",
channel: "custom",
});
expect(result.coverage.status).toBe("partial_attach");
expect(result.coverage.observed_event_families).toContain(
"ipc-observation-gap",
);
expect(result.coverage.unavailable_event_families).toContain("ipc");
expect(result.retention.dropped).toBe(2);
expect(result.limitations).toContainEqual(
expect.stringContaining("unobserved callback arguments and execution"),
);
expect(result.limitations).not.toContain(
"The active IPC hook could not be installed.",
);
},
);
it("projects hook retention and dropped event families through the result schema", () => {
const result = projectElectronActiveCapture(
{
executable: "/opt/electron",
application: "/opt/app/main.js",
},
[],
{
windows: [],
metrics: [],
electronVersion: "test-electron",
hookSnapshot: {
events: [event],
retention_budget_bytes: 16 * 1024 * 1024,
estimated_retained_bytes: 1_024,
event_serialized_byte_upper_bound: 512,
retained: 1,
dropped: 2,
dropped_ipc: 1,
dropped_runtime: 1,
dropped_event_families: [
{ family: "renderer-ipc", count: 1 },
{ family: "preload-configuration", count: 1 },
],
dropped_event_roles: [{ role: "renderer", count: 1 }],
observed: 3,
observed_ipc: 1,
observed_runtime: 1,
hook_error: false,
},
},
);
expect(result.retention).toMatchObject({
budget_bytes: 16 * 1024 * 1024,
estimated_retained_bytes: 1_024,
event_serialized_byte_upper_bound: 512,
retained: 1,
dropped: 2,
dropped_event_families: [
{ family: "renderer-ipc", count: 1 },
{ family: "preload-configuration", count: 1 },
],
dropped_event_roles: [{ role: "renderer", count: 1 }],
});
expect(result.ipc).toMatchObject({ observed: 1, dropped: 1 });
expect(result.timeline).toMatchObject({ observed: 3, dropped: 2 });
expect(result.coverage.observed_event_families).toContain("renderer-ipc");
expect(result.coverage.unavailable_event_families).not.toContain(
"renderer-ipc",
);
expect(result.coverage.observed_roles).toContain("renderer");
expect(result.coverage.observed_event_families).toContain(
"preload-configuration",
);
expect(result.coverage.unavailable_event_families).not.toContain(
"preload-configuration",
);
expect(result.limitations).not.toContain(
"Preload configuration was not exposed by the observed Electron window metadata. Preload paths and execution remain unavailable.",
);
});
it("keeps renderer coverage unavailable when only the main process was observed", () => {
const result = projectElectronActiveCapture(
{
executable: "/opt/electron",
application: "/opt/app/main.js",
},
[],
{
windows: [],
metrics: [],
electronVersion: "test-electron",
hookSnapshot: {
events: [
{
sequence: 1,
correlation_id: "capture:123:1",
kind: "app-lifecycle",
event: "ready",
phase: "observed",
channel: null,
direction: null,
sender: null,
receiver: null,
frame: null,
target: "app",
argument_shapes: [],
result_shape: null,
process_type: "main",
source: "electron-active-hook",
capture_method: "event-emitter",
artifact_path: null,
artifact_sha256: null,
error: false,
},
],
retention_budget_bytes: 16 * 1024 * 1024,
estimated_retained_bytes: 0,
event_serialized_byte_upper_bound: 0,
retained: 1,
dropped: 0,
dropped_ipc: 0,
dropped_runtime: 0,
dropped_event_families: [],
dropped_event_roles: [],
observed: 1,
observed_ipc: 0,
observed_runtime: 1,
hook_error: false,
},
},
);
expect(result.coverage.observed_roles).not.toContain("renderer");
expect(result.coverage.unavailable_event_families).toContain("renderer-ipc");
});
it("does not correlate legacy dropped families and roles", () => {
const result = projectElectronActiveCapture(
{
executable: "/opt/electron",
application: "/opt/app/main.js",
},
[],
{
windows: [],
metrics: [],
electronVersion: "test-electron",
hookSnapshot: {
events: [],
retention_budget_bytes: 16 * 1024 * 1024,
estimated_retained_bytes: 0,
event_serialized_byte_upper_bound: 0,
retained: 0,
dropped: 2,
dropped_ipc: 1,
dropped_runtime: 1,
dropped_event_families: [
{ family: "preload", count: 1 },
{ family: "renderer-ipc", count: 1 },
],
dropped_event_roles: [
{ role: "browser", count: 1 },
{ role: "renderer", count: 1 },
],
observed: 2,
observed_ipc: 1,
observed_runtime: 1,
hook_error: false,
},
},
);
expect(result.coverage.observed_event_families).toContain("preload");
expect(result.coverage.observed_event_families).not.toContain(
"preload-configuration",
);
expect(result.coverage.unavailable_event_families).toContain(
"preload-configuration",
);
expect(result.coverage.observed_roles).toEqual(["browser", "renderer"]);
expect(result.retention.dropped_event_families).toEqual([
{ family: "preload", count: 1 },
{ family: "renderer-ipc", count: 1 },
]);
expect(result.limitations).toContain(
"Dropped preload-family events were not attributed to preload configuration; independently aggregated event families and roles cannot establish that relationship.",
);
});