Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 133 additions & 0 deletions src/cdp/domains/dom.zig
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ pub fn processMessage(cmd: anytype) !void {
performSearch,
getSearchResults,
discardSearchResults,
querySelector,
querySelectorAll,
resolveNode,
describeNode,
scrollIntoViewIfNeeded,
Expand All @@ -43,6 +45,8 @@ pub fn processMessage(cmd: anytype) !void {
.performSearch => return performSearch(cmd),
.getSearchResults => return getSearchResults(cmd),
.discardSearchResults => return discardSearchResults(cmd),
.querySelector => return querySelector(cmd),
.querySelectorAll => return querySelectorAll(cmd),
.resolveNode => return resolveNode(cmd),
.describeNode => return describeNode(cmd),
.scrollIntoViewIfNeeded => return scrollIntoViewIfNeeded(cmd),
Expand Down Expand Up @@ -188,6 +192,60 @@ fn getSearchResults(cmd: anytype) !void {
return cmd.sendResult(.{ .nodeIds = node_ids[params.fromIndex..params.toIndex] }, .{});
}

fn querySelector(cmd: anytype) !void {
const params = (try cmd.params(struct {
nodeId: Node.Id,
selector: []const u8,
})) orelse return error.InvalidParams;

const bc = cmd.browser_context orelse return error.BrowserContextNotLoaded;

const node = bc.node_registry.lookup_by_id.get(params.nodeId) orelse return error.UnknownNode;

const selected_node = try css.querySelector(
cmd.arena,
node._node,
params.selector,
) orelse return error.NodeNotFoundForGivenId;

const registered_node = try bc.node_registry.register(selected_node);

// Dispatch setChildNodesEvents to inform the client of the subpart of node tree covering the results.
var array = [1]*parser.Node{selected_node};
try dispatchSetChildNodes(cmd, array[0..]);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
try dispatchSetChildNodes(cmd, array[0..]);
try dispatchSetChildNodes(cmd, &.{selected_node});

This this will work.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not been able to find the right incantation..
try dispatchSetChildNodes(cmd, &.{selected_node});
results in:

error: expected type '[]*cimport.struct_dom_node_internal', found '*const [1]*cimport.struct_dom_node_internal'
    try dispatchSetChildNodes(cmd, &.{selected_node});
                                   ^~~~~~~~~~~~~~~~~
src/cdp/domains/dom.zig:216:36: note: cast discards const qualifier
src/cdp/domains/dom.zig:103:47: note: parameter type declared here
fn dispatchSetChildNodes(cmd: anytype, nodes: []*parser.Node) !void {


return cmd.sendResult(.{
.nodeId = registered_node.id,
}, .{});
}

fn querySelectorAll(cmd: anytype) !void {
const params = (try cmd.params(struct {
nodeId: Node.Id,
selector: []const u8,
})) orelse return error.InvalidParams;

const bc = cmd.browser_context orelse return error.BrowserContextNotLoaded;

const node = bc.node_registry.lookup_by_id.get(params.nodeId) orelse return error.UnknownNode;

const arena = cmd.arena;
const selected_nodes = try css.querySelectorAll(arena, node._node, params.selector);
const nodes = selected_nodes.nodes.items;

const node_ids = try arena.alloc(Node.Id, nodes.len);
for (nodes, node_ids) |selected_node, *node_id| {
node_id.* = (try bc.node_registry.register(selected_node)).id;
}

// Dispatch setChildNodesEvents to inform the client of the subpart of node tree covering the results.
try dispatchSetChildNodes(cmd, nodes);

return cmd.sendResult(.{
.nodeIds = node_ids,
}, .{});
}

fn resolveNode(cmd: anytype) !void {
const params = (try cmd.params(struct {
nodeId: ?Node.Id = null,
Expand Down Expand Up @@ -399,3 +457,78 @@ test "cdp.dom: search flow" {
.params = .{ .searchId = "0", .fromIndex = 0, .toIndex = 1 },
}));
}

test "cdp.dom: querySelector unknown search id" {
var ctx = testing.context();
defer ctx.deinit();

_ = try ctx.loadBrowserContext(.{ .id = "BID-A", .html = "<p>1</p> <p>2</p>" });

try testing.expectError(error.UnknownNode, ctx.processMessage(.{
.id = 9,
.method = "DOM.querySelector",
.params = .{ .nodeId = 99, .selector = "" },
}));
try testing.expectError(error.UnknownNode, ctx.processMessage(.{
.id = 9,
.method = "DOM.querySelectorAll",
.params = .{ .nodeId = 99, .selector = "" },
}));
}

test "cdp.dom: querySelector Node not found" {
var ctx = testing.context();
defer ctx.deinit();

_ = try ctx.loadBrowserContext(.{ .id = "BID-A", .html = "<p>1</p> <p>2</p>" });

try ctx.processMessage(.{ // Hacky way to make sure nodeId 0 exists in the registry
.id = 3,
.method = "DOM.performSearch",
.params = .{ .query = "p" },
});
try ctx.expectSentResult(.{ .searchId = "0", .resultCount = 2 }, .{ .id = 3 });

try testing.expectError(error.NodeNotFoundForGivenId, ctx.processMessage(.{
.id = 4,
.method = "DOM.querySelector",
.params = .{ .nodeId = 0, .selector = "a" },
}));

try ctx.processMessage(.{
.id = 5,
.method = "DOM.querySelectorAll",
.params = .{ .nodeId = 0, .selector = "a" },
});
try ctx.expectSentResult(.{ .nodeIds = &[_]u32{} }, .{ .id = 5 });
}

test "cdp.dom: querySelector Nodes found" {
var ctx = testing.context();
defer ctx.deinit();

_ = try ctx.loadBrowserContext(.{ .id = "BID-A", .html = "<div><p>2</p></div>" });

try ctx.processMessage(.{ // Hacky way to make sure nodeId 0 exists in the registry
.id = 3,
.method = "DOM.performSearch",
.params = .{ .query = "div" },
});
try ctx.expectSentResult(.{ .searchId = "0", .resultCount = 1 }, .{ .id = 3 });

try ctx.processMessage(.{
.id = 4,
.method = "DOM.querySelector",
.params = .{ .nodeId = 0, .selector = "p" },
});
try ctx.expectSentEvent("DOM.setChildNodes", null, .{});
try ctx.expectSentResult(.{ .nodeId = 5 }, .{ .id = 4 });

try ctx.processMessage(.{
.id = 5,
.method = "DOM.querySelectorAll",
.params = .{ .nodeId = 0, .selector = "p" },
});
try ctx.expectSentEvent("DOM.setChildNodes", null, .{});
try ctx.expectSentResult(.{ .nodeIds = &.{5} }, .{ .id = 5 });
}