aboutsummaryrefslogtreecommitdiff
path: root/test/cdp/events-test.ts
blob: 3699bced13af97446aae1a95b326b2de67ce5013 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import { test, describe } from "node:test";
import assert from "node:assert/strict";
import { EVENTS, decodeEvent, isKnownEvent } from "../../src/cdp/events";
import { createConsoleBuffer } from "../../src/cdp/console-buffer";
import { createNetworkBuffer } from "../../src/cdp/network-buffer";

describe("cdp events", () => {
  test("decodes a dialog-opening event", () => {
    const r = decodeEvent("Page.javascriptDialogOpening", { type: "confirm", message: "Sure?" });
    assert.equal(r.success, true);
    if (r.success) assert.equal(r.data.type, "confirm");
  });

  test("rejects a malformed event payload", () => {
    const r = decodeEvent("Page.javascriptDialogOpening", { type: 5 });
    assert.equal(r.success, false);
    if (!r.success) {
      assert.equal(r.error.kind, "invalid_response");
      assert.equal(r.error.method, "Page.javascriptDialogOpening");
    }
  });

  test("tolerates unknown extra fields Chrome may add", () => {
    const r = decodeEvent("Target.targetDestroyed", { targetId: "t1", extra: true });
    assert.equal(r.success, true);
  });

  test("isKnownEvent gates unrecognised methods", () => {
    assert.equal(isKnownEvent("Page.loadEventFired"), true);
    assert.equal(isKnownEvent("Fetch.requestPaused"), false);
  });

  test("the table covers exactly the events the codebase dispatches on", () => {
    assert.deepEqual(Object.keys(EVENTS).sort(), [
      "Inspector.detached",
      "Log.entryAdded",
      "Network.loadingFailed",
      "Network.loadingFinished",
      "Network.requestWillBeSent",
      "Network.responseReceived",
      "Page.frameNavigated",
      "Page.javascriptDialogOpening",
      "Page.loadEventFired",
      "Runtime.consoleAPICalled",
      "Target.targetCreated",
      "Target.targetDestroyed",
    ]);
  });

  test("a non-object payload decodes to an error rather than throwing", () => {
    assert.equal(decodeEvent("Target.targetDestroyed", null).success, false);
    assert.equal(decodeEvent("Log.entryAdded", undefined).success, false);
  });

  test("targetCreated keeps openerId optional", () => {
    const r = decodeEvent("Target.targetCreated", {
      targetInfo: { targetId: "t1", type: "page", title: "x", url: "about:blank" },
    });
    assert.equal(r.success, true);
    if (r.success) assert.equal(r.data.targetInfo.openerId, undefined);
  });
});

describe("cdp events dropped payloads", () => {
  test("console buffer ignores a malformed Log.entryAdded without throwing", () => {
    const buf = createConsoleBuffer();
    buf.ingestLogEntry({ entry: { level: "error", text: 42 } });
    assert.deepEqual(buf.drain({}).records, []);
  });

  test("console buffer still records a well-formed Log.entryAdded", () => {
    const buf = createConsoleBuffer();
    buf.ingestLogEntry({ entry: { level: "error", text: "boom" } });
    const drained = buf.drain({});
    assert.equal(drained.records.length, 1);
    assert.equal(drained.records[0]?.text, "boom");
    assert.equal(drained.records[0]?.level, "error");
  });

  test("network buffer ignores a malformed requestWillBeSent without throwing", () => {
    const buf = createNetworkBuffer();
    buf.ingestRequestWillBeSent({ requestId: "r1", request: { url: 7, method: "GET" } });
    assert.deepEqual(buf.drain({}).records, []);
  });

  test("network buffer keeps an existing record when a later event is malformed", () => {
    const buf = createNetworkBuffer();
    buf.ingestRequestWillBeSent({ requestId: "r1", request: { url: "https://a/", method: "GET" } });
    buf.ingestResponseReceived({ requestId: "r1", response: { status: "200" } });
    const drained = buf.drain({});
    assert.equal(drained.records.length, 1);
    assert.equal(drained.records[0]?.status, undefined);
  });
});