diff --git a/src/cdp/domains/page.zig b/src/cdp/domains/page.zig index a76fb716..1dd7f75b 100644 --- a/src/cdp/domains/page.zig +++ b/src/cdp/domains/page.zig @@ -159,6 +159,10 @@ fn addScriptToEvaluateOnNewDocument(cmd: anytype) !void { const bc = cmd.browser_context orelse return error.BrowserContextNotLoaded; + if (params.runImmediately) { + log.warn(.not_implemented, "addScriptOnNewDocument", .{ .param = "runImmediately" }); + } + const script_id = bc.next_script_id; bc.next_script_id += 1; @@ -191,7 +195,6 @@ fn removeScriptToEvaluateOnNewDocument(cmd: anytype) !void { break; } } - return cmd.sendResult(null, .{}); } @@ -524,8 +527,13 @@ pub fn pageNavigated(arena: Allocator, bc: anytype, event: *const Notification.P defer ls.deinit(); for (bc.scripts_on_new_document.items) |script| { + var try_catch: lp.js.TryCatch = undefined; + try_catch.init(&ls.local); + defer try_catch.deinit(); + ls.local.eval(script.source, null) catch |err| { - log.warn(.cdp, "script on new doc failed", .{ .err = err }); + const caught = try_catch.caughtOrError(arena, err); + log.warn(.cdp, "script on new doc", .{ .caught = caught }); }; } } @@ -893,7 +901,7 @@ test "cdp.page: addScriptToEvaluateOnNewDocument" { var ctx = try testing.context(); defer ctx.deinit(); - _ = try ctx.loadBrowserContext(.{ .id = "BID-9", .url = "hi.html", .target_id = "FID-000000000X".* }); + var bc = try ctx.loadBrowserContext(.{ .id = "BID-9", .url = "hi.html", .target_id = "FID-000000000X".* }); { // Register a script — should return unique identifier "1" @@ -922,4 +930,22 @@ test "cdp.page: addScriptToEvaluateOnNewDocument" { try ctx.processMessage(.{ .id = 23, .method = "Page.removeScriptToEvaluateOnNewDocument", .params = .{ .identifier = "999" } }); try ctx.expectSentResult(null, .{ .id = 23 }); } + + { + try ctx.processMessage(.{ .id = 34, .method = "Page.reload" }); + // wait for this event, which is sent after we've run the registered scripts + try ctx.expectSentEvent("Page.frameNavigated", .{ + .frame = .{.loaderId = "LID-0000000002"}, + }, .{}); + + const page = bc.session.currentPage() orelse unreachable; + + var ls: js.Local.Scope = undefined; + page.js.localScope(&ls); + defer ls.deinit(); + + const test_val = try ls.local.exec("window.__test2", null); + try testing.expectEqual(2, try test_val.toI32()); + } + } diff --git a/src/cdp/testing.zig b/src/cdp/testing.zig index 87639a6c..9d420bca 100644 --- a/src/cdp/testing.zig +++ b/src/cdp/testing.zig @@ -172,13 +172,26 @@ const TestContext = struct { index: ?usize = null, }; pub fn expectSent(self: *TestContext, expected: anytype, opts: SentOpts) !void { - const serialized = try json.Stringify.valueAlloc(base.arena_allocator, expected, .{ - .whitespace = .indent_2, - .emit_null_optional_fields = false, - }); + const expected_json = blk: { + // Zig makes this hard. When sendJSON is called, we're sending an anytype. + // We can't record that in an ArrayList(???), so we serialize it to JSON. + // Now, ideally, we could just take our expected structure, serialize it to + // json and check if the two are equal. + // Except serializing to JSON isn't deterministic. + // So we serialize the JSON then we deserialize to json.Value. And then we can + // compare our anytype expectation with the json.Value that we captured + + const serialized = try json.Stringify.valueAlloc(base.arena_allocator, expected, .{ + .whitespace = .indent_2, + .emit_null_optional_fields = false, + }); + + break :blk try std.json.parseFromSliceLeaky(json.Value, base.arena_allocator, serialized, .{}); + }; + for (0..5) |_| { for (self.received.items, 0..) |received, i| { - if (try compareExpectedToSent(serialized, received) == false) { + if (try base.isEqualJson(expected_json, received) == false) { continue; } @@ -191,6 +204,15 @@ const TestContext = struct { } return; } + + if (self.cdp_) |*cdp__| { + if (cdp__.browser_context) |*bc| { + if (bc.session.page != null) { + var runner = try bc.session.runner(.{}); + _ = try runner.tick(.{.ms = 1000}); + } + } + } std.Thread.sleep(5 * std.time.ns_per_ms); try self.read(); } @@ -303,17 +325,3 @@ pub fn context() !TestContext { .socket = pair[0], }; } - -// Zig makes this hard. When sendJSON is called, we're sending an anytype. -// We can't record that in an ArrayList(???), so we serialize it to JSON. -// Now, ideally, we could just take our expected structure, serialize it to -// json and check if the two are equal. -// Except serializing to JSON isn't deterministic. -// So we serialize the JSON then we deserialize to json.Value. And then we can -// compare our anytype expectation with the json.Value that we captured - -fn compareExpectedToSent(expected: []const u8, actual: json.Value) !bool { - const expected_value = try std.json.parseFromSlice(json.Value, std.testing.allocator, expected, .{}); - defer expected_value.deinit(); - return base.isEqualJson(expected_value.value, actual); -}