Skip to content

Commit 4322d8e

Browse files
committed
dom.querySelector
1 parent 3a15790 commit 4322d8e

File tree

1 file changed

+134
-0
lines changed

1 file changed

+134
-0
lines changed

src/cdp/domains/dom.zig

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ pub fn processMessage(cmd: anytype) !void {
3131
performSearch,
3232
getSearchResults,
3333
discardSearchResults,
34+
querySelector,
35+
querySelectorAll,
3436
resolveNode,
3537
describeNode,
3638
scrollIntoViewIfNeeded,
@@ -43,6 +45,8 @@ pub fn processMessage(cmd: anytype) !void {
4345
.performSearch => return performSearch(cmd),
4446
.getSearchResults => return getSearchResults(cmd),
4547
.discardSearchResults => return discardSearchResults(cmd),
48+
.querySelector => return querySelector(cmd),
49+
.querySelectorAll => return querySelectorAll(cmd),
4650
.resolveNode => return resolveNode(cmd),
4751
.describeNode => return describeNode(cmd),
4852
.scrollIntoViewIfNeeded => return scrollIntoViewIfNeeded(cmd),
@@ -188,6 +192,61 @@ fn getSearchResults(cmd: anytype) !void {
188192
return cmd.sendResult(.{ .nodeIds = node_ids[params.fromIndex..params.toIndex] }, .{});
189193
}
190194

195+
fn querySelector(cmd: anytype) !void {
196+
const params = (try cmd.params(struct {
197+
nodeId: Node.Id,
198+
selector: []const u8,
199+
})) orelse return error.InvalidParams;
200+
201+
const bc = cmd.browser_context orelse return error.BrowserContextNotLoaded;
202+
203+
const node = bc.node_registry.lookup_by_id.get(params.nodeId) orelse return error.UnknownNode;
204+
205+
const selected_node = try css.querySelector(
206+
cmd.arena,
207+
node._node,
208+
params.selector,
209+
) orelse return error.NodeNotFoundForGivenId;
210+
211+
const registered_node = try bc.node_registry.register(selected_node);
212+
213+
// Dispatch setChildNodesEvents to inform the client of the subpart of node tree covering the results.
214+
var array = [1]*parser.Node{selected_node};
215+
try dispatchSetChildNodes(cmd, array[0..]);
216+
217+
return cmd.sendResult(.{
218+
.nodeId = registered_node.id,
219+
}, .{});
220+
}
221+
222+
fn querySelectorAll(cmd: anytype) !void {
223+
const params = (try cmd.params(struct {
224+
nodeId: Node.Id,
225+
selector: []const u8,
226+
})) orelse return error.InvalidParams;
227+
228+
const bc = cmd.browser_context orelse return error.BrowserContextNotLoaded;
229+
230+
const node = bc.node_registry.lookup_by_id.get(params.nodeId) orelse return error.UnknownNode;
231+
232+
const arena = cmd.arena;
233+
var selected_nodes = try css.querySelectorAll(arena, node._node, params.selector);
234+
defer selected_nodes.deinit(arena);
235+
236+
const nodes = selected_nodes.nodes.items;
237+
const node_ids = try arena.alloc(Node.Id, nodes.len);
238+
for (nodes, node_ids) |selected_node, *node_id| {
239+
node_id.* = (try bc.node_registry.register(selected_node)).id;
240+
}
241+
242+
// Dispatch setChildNodesEvents to inform the client of the subpart of node tree covering the results.
243+
try dispatchSetChildNodes(cmd, nodes);
244+
245+
return cmd.sendResult(.{
246+
.nodeIds = node_ids,
247+
}, .{});
248+
}
249+
191250
fn resolveNode(cmd: anytype) !void {
192251
const params = (try cmd.params(struct {
193252
nodeId: ?Node.Id = null,
@@ -399,3 +458,78 @@ test "cdp.dom: search flow" {
399458
.params = .{ .searchId = "0", .fromIndex = 0, .toIndex = 1 },
400459
}));
401460
}
461+
462+
test "cdp.dom: querySelector unknown search id" {
463+
var ctx = testing.context();
464+
defer ctx.deinit();
465+
466+
_ = try ctx.loadBrowserContext(.{ .id = "BID-A", .html = "<p>1</p> <p>2</p>" });
467+
468+
try testing.expectError(error.UnknownNode, ctx.processMessage(.{
469+
.id = 9,
470+
.method = "DOM.querySelector",
471+
.params = .{ .nodeId = 99, .selector = "" },
472+
}));
473+
try testing.expectError(error.UnknownNode, ctx.processMessage(.{
474+
.id = 9,
475+
.method = "DOM.querySelectorAll",
476+
.params = .{ .nodeId = 99, .selector = "" },
477+
}));
478+
}
479+
480+
test "cdp.dom: querySelector Node not found" {
481+
var ctx = testing.context();
482+
defer ctx.deinit();
483+
484+
_ = try ctx.loadBrowserContext(.{ .id = "BID-A", .html = "<p>1</p> <p>2</p>" });
485+
486+
try ctx.processMessage(.{ // Hacky way to make sure nodeId 0 exists in the registry
487+
.id = 3,
488+
.method = "DOM.performSearch",
489+
.params = .{ .query = "p" },
490+
});
491+
try ctx.expectSentResult(.{ .searchId = "0", .resultCount = 2 }, .{ .id = 3 });
492+
493+
try testing.expectError(error.NodeNotFoundForGivenId, ctx.processMessage(.{
494+
.id = 4,
495+
.method = "DOM.querySelector",
496+
.params = .{ .nodeId = 0, .selector = "a" },
497+
}));
498+
499+
try ctx.processMessage(.{
500+
.id = 5,
501+
.method = "DOM.querySelectorAll",
502+
.params = .{ .nodeId = 0, .selector = "a" },
503+
});
504+
try ctx.expectSentResult(.{ .nodeIds = &[_]u32{} }, .{ .id = 5 });
505+
}
506+
507+
test "cdp.dom: querySelector Nodes found" {
508+
var ctx = testing.context();
509+
defer ctx.deinit();
510+
511+
_ = try ctx.loadBrowserContext(.{ .id = "BID-A", .html = "<div><p>2</p></div>" });
512+
513+
try ctx.processMessage(.{ // Hacky way to make sure nodeId 0 exists in the registry
514+
.id = 3,
515+
.method = "DOM.performSearch",
516+
.params = .{ .query = "div" },
517+
});
518+
try ctx.expectSentResult(.{ .searchId = "0", .resultCount = 1 }, .{ .id = 3 });
519+
520+
try ctx.processMessage(.{
521+
.id = 4,
522+
.method = "DOM.querySelector",
523+
.params = .{ .nodeId = 0, .selector = "p" },
524+
});
525+
// TODO Check 1 or more "DOM.setChildNodes" was send
526+
try ctx.expectSentResult(.{ .nodeId = 5 }, .{ .id = 4 });
527+
528+
try ctx.processMessage(.{
529+
.id = 5,
530+
.method = "DOM.querySelectorAll",
531+
.params = .{ .nodeId = 0, .selector = "p" },
532+
});
533+
// TODO Check 1 or more "DOM.setChildNodes" was send
534+
try ctx.expectSentResult(.{ .nodeIds = &.{5} }, .{ .id = 5 });
535+
}

0 commit comments

Comments
 (0)