From 675932c65b2be38cf28323935aa3c363764d99e0 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Mon, 3 Mar 2025 17:16:10 +0100 Subject: [PATCH 1/3] cdp: improve playwright support The getTargetInfo result must return a `targetInfo` key. Here is an example returned by Chrome: ```json { "id": 16, "result": { "targetInfo": { "targetId": "d93a1bbc-f906-4bbb-bb4d-a2285234b091", "type": "browser", "title": "", "url": "", "attached": true, "canAccessOpener": false } } } ``` --- src/cdp/target.zig | 77 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 66 insertions(+), 11 deletions(-) diff --git a/src/cdp/target.zig b/src/cdp/target.zig index 1c278f3a..324da5c1 100644 --- a/src/cdp/target.zig +++ b/src/cdp/target.zig @@ -231,21 +231,25 @@ fn getTargetInfo(cmd: anytype) !void { } return cmd.sendResult(.{ - .targetId = target_id, - .type = "page", - .title = "", - .url = "", - .attached = true, - .canAccessOpener = false, + .targetInfo = .{ + .targetId = target_id, + .type = "page", + .title = "", + .url = "", + .attached = true, + .canAccessOpener = false, + }, }, .{ .include_session_id = false }); } return cmd.sendResult(.{ - .type = "browser", - .title = "", - .url = "", - .attached = true, - .canAccessOpener = false, + .targetInfo = .{ + .type = "browser", + .title = "", + .url = "", + .attached = true, + .canAccessOpener = false, + }, }, .{ .include_session_id = false }); } @@ -548,3 +552,54 @@ test "cdp.target: attachToTarget" { try ctx.expectSentEvent("Target.attachedToTarget", .{ .sessionId = session_id, .targetInfo = .{ .url = "chrome://newtab/", .title = "about:blank", .attached = true, .type = "page", .canAccessOpener = false, .browserContextId = "BID-9", .targetId = bc.target_id.? } }, .{}); } } + +test "cdp.target: getTargetInfo" { + var ctx = testing.context(); + defer ctx.deinit(); + + { + try ctx.processMessage(.{ .id = 9, .method = "Target.getTargetInfo" }); + try ctx.expectSentResult(.{ + .targetInfo = .{ + .type = "browser", + .title = "", + .url = "", + .attached = true, + .canAccessOpener = false, + }, + }, .{ .id = 9 }); + } + + { + try testing.expectError(error.BrowserContextNotLoaded, ctx.processMessage(.{ .id = 10, .method = "Target.getTargetInfo", .params = .{ .targetId = "X" } })); + try ctx.expectSentError(-31998, "BrowserContextNotLoaded", .{ .id = 10 }); + } + + const bc = try ctx.loadBrowserContext(.{ .id = "BID-9" }); + { + try testing.expectError(error.TargetNotLoaded, ctx.processMessage(.{ .id = 10, .method = "Target.getTargetInfo", .params = .{ .targetId = "TID-8" } })); + try ctx.expectSentError(-31998, "TargetNotLoaded", .{ .id = 10 }); + } + + // pretend we createdTarget first + _ = try bc.session.createPage(); + bc.target_id = "TID-A"; + { + try testing.expectError(error.UnknownTargetId, ctx.processMessage(.{ .id = 10, .method = "Target.getTargetInfo", .params = .{ .targetId = "TID-8" } })); + try ctx.expectSentError(-31998, "UnknownTargetId", .{ .id = 10 }); + } + + { + try ctx.processMessage(.{ .id = 11, .method = "Target.getTargetInfo", .params = .{ .targetId = "TID-A" } }); + try ctx.expectSentResult(.{ + .targetInfo = .{ + .targetId = "TID-A", + .type = "page", + .title = "", + .url = "", + .attached = true, + .canAccessOpener = false, + }, + }, .{ .id = 11 }); + } +} From f3a1a6a19124c49993614e9daa4e3b1f810a2585 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Mon, 3 Mar 2025 17:16:40 +0100 Subject: [PATCH 2/3] cdp: add a Page.getFrameTree unit test --- src/cdp/page.zig | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/cdp/page.zig b/src/cdp/page.zig index 3dfb2c44..1ba6ed92 100644 --- a/src/cdp/page.zig +++ b/src/cdp/page.zig @@ -262,3 +262,37 @@ fn navigate(cmd: anytype) !void { .frameId = bc.frame_id, }, .{ .session_id = session_id }); } + +const testing = @import("testing.zig"); +test "cdp.page: getFrameTree" { + var ctx = testing.context(); + defer ctx.deinit(); + + { + try testing.expectError(error.BrowserContextNotLoaded, ctx.processMessage(.{ .id = 10, .method = "Page.getFrameTree", .params = .{ .targetId = "X" } })); + try ctx.expectSentError(-31998, "BrowserContextNotLoaded", .{ .id = 10 }); + } + + const bc = try ctx.loadBrowserContext(.{ .id = "BID-9" }); + { + try ctx.processMessage(.{ .id = 11, .method = "Page.getFrameTree" }); + try ctx.expectSentResult(.{ + .frameTree = .{ + .frame = .{ + .id = bc.frame_id, + .loaderId = bc.loader_id, + .url = bc.url, + .domainAndRegistry = "", + .securityOrigin = bc.security_origin, + .mimeType = "text/html", + .adFrameStatus = .{ + .adFrameType = "none", + }, + .secureContextType = bc.secure_context_type, + .crossOriginIsolatedContextType = "NotIsolated", + .gatedAPIFeatures = [_][]const u8{}, + }, + }, + }, .{ .id = 11 }); + } +} From 6ca1e6c6dd81c67ac699c738fd971369626cc773 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Mon, 3 Mar 2025 17:16:53 +0100 Subject: [PATCH 3/3] cdp: let the inspector return the response When a command is forwarded to the inspector, it handles directly the reponse to the message. --- src/cdp/runtime.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cdp/runtime.zig b/src/cdp/runtime.zig index c054521e..5a6e2948 100644 --- a/src/cdp/runtime.zig +++ b/src/cdp/runtime.zig @@ -56,6 +56,7 @@ fn sendInspector(cmd: anytype, action: anytype) !void { } } + // the result to return is handled directly by the inspector. bc.session.callInspector(cmd.input.json); }