From 1e31e45bcf627d1bd6ef28ab94cc75638610af4e Mon Sep 17 00:00:00 2001 From: raj921 Date: Wed, 22 Jul 2026 17:15:25 +0530 Subject: [PATCH] cdp: preserve node IDs across child frame navigation --- src/cdp/domains/page.zig | 42 +++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/src/cdp/domains/page.zig b/src/cdp/domains/page.zig index fd626fc80..c718b576d 100644 --- a/src/cdp/domains/page.zig +++ b/src/cdp/domains/page.zig @@ -455,12 +455,14 @@ pub fn frameNavigate(bc: *CDP.BrowserContext, event: *const Notification.FrameNa // things, but no session. const session_id = bc.session_id orelse return; - // is_pending_root means this navigation is in flight against a pending - // Page while the OLD page is still alive and addressable. Don't blow - // away the node_registry — the OLD page's nodes are still referenced - // by client-held objectIds. The reset moves to frameRemove (commit). + // Child-frame navigations must not invalidate node IDs owned by other + // frames. A pending root keeps its old page addressable until frameRemove; + // other root navigations can clear the registry immediately. if (!event.is_pending_root) { - bc.reset(); + const root_frame = bc.mainFrame() orelse return error.FrameNotLoaded; + if (event.frame_id == root_frame._frame_id) { + bc.reset(); + } } const frame_id = &id.toFrameId(event.frame_id); @@ -1090,6 +1092,36 @@ test "cdp.frame: frameAttached" { }, .{ .session_id = "SID-X" }); } +test "cdp.frame: child navigation preserves node registry" { + var ctx = try testing.context(); + defer ctx.deinit(); + + const bc = try ctx.loadBrowserContext(.{ .url = "hi.html" }); + const root_frame = bc.mainFrame().?; + const node = try bc.node_registry.register(root_frame.window._document.asNode()); + const node_id = node.id; + + try frameNavigate(bc, &.{ + .req_id = 1, + .frame_id = root_frame._frame_id + 1, + .loader_id = 2, + .timestamp = 0, + .url = "about:blank", + .opts = .{}, + }); + try testing.expectEqual(node, bc.node_registry.lookup_by_id.get(node_id).?); + + try frameNavigate(bc, &.{ + .req_id = 2, + .frame_id = root_frame._frame_id, + .loader_id = 3, + .timestamp = 0, + .url = "about:blank", + .opts = .{}, + }); + try testing.expectEqual(null, bc.node_registry.lookup_by_id.get(node_id)); +} + test "cdp.frame: captureScreenshot" { const LogFilter = @import("../../testing.zig").LogFilter; const filter: LogFilter = .init(&.{.not_implemented});