Skip to content

Conversation

mookums
Copy link
Contributor

@mookums mookums commented Oct 10, 2025

This is still pretty rough around the edges for now (and is incomplete)

This implements the Navigation WebAPI. History is now a compatibility layer over Navigation, allowing them to share the same underlying entries. testing has been changed, using fetchWait and loading a secondary testing html file that checks for the appropriate conditions when we need to load a secondary page (such as with History or Navigation. the navigateFromWebAPI has also been changed, adding a field, that allows it so serve as the central way to navigate with proper hooks into Navigation.

There are a few Events that need to be completed so far, such as NavigateEvent, and a lot of conditions that need extra testing (such as reloading).


Looking to get this merged soon, just to prevent this from drifting off too far. There is still a good chunk of work left to be fully WPT compliant (such as firing events at the proper time), but a lot of these WPTs depend on other browser features (like pageshow) that have to be implemented separately. I'm going to continue working on Navigation, specifically on getting most of the tests to pass.

@mookums mookums force-pushed the navigation branch 4 times, most recently from 620a5d3 to fee8f5c Compare October 16, 2025 06:10
@mookums mookums marked this pull request as ready for review October 16, 2025 06:16
@krichprollsch
Copy link
Member

Duckduckgo integration test is failing on this branch, even after a rebase against main.

$ node integration/duckduckgo.js
file:///home/pierre/wrk/demo/node_modules/puppeteer-core/lib/esm/puppeteer/util/Deferred.js:57
            this.#timeoutError = new TimeoutError(opts.message);
                                 ^

TimeoutError: Navigation timeout of 30000 ms exceeded
    at new Deferred (file:///home/pierre/wrk/demo/node_modules/puppeteer-core/lib/esm/puppeteer/util/Deferred.js:57:34)
    at Deferred.create (file:///home/pierre/wrk/demo/node_modules/puppeteer-core/lib/esm/puppeteer/util/Deferred.js:18:16)
    at new LifecycleWatcher (file:///home/pierre/wrk/demo/node_modules/puppeteer-core/lib/esm/puppeteer/cdp/LifecycleWatcher.js:70:46)
    at CdpFrame.waitForNavigation (file:///home/pierre/wrk/demo/node_modules/puppeteer-core/lib/esm/puppeteer/cdp/Frame.js:193:29)
    at CdpFrame.<anonymous> (file:///home/pierre/wrk/demo/node_modules/puppeteer-core/lib/esm/puppeteer/util/decorators.js:101:27)
    at CdpPage.waitForNavigation (file:///home/pierre/wrk/demo/node_modules/puppeteer-core/lib/esm/puppeteer/api/Page.js:601:43)
    at file:///home/pierre/wrk/demo/integration/duckduckgo.js:34:8

Node.js v22.19.0

pub fn pushEntry(self: *Navigation, _url: ?[]const u8, state: ?[]const u8, page: *Page, dispatch: bool) !*NavigationHistoryEntry {
const arena = page.session.arena;

const url = if (_url) |u| try arena.dupe(u8, u) else null;
Copy link
Member

Choose a reason for hiding this comment

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

Does it make sense to accept a null url here?
I didn't see a place where pushEntry is called with a nullable url. Maybe we could remove that from the signature but also from the entry?

if (is_same_document) {
page.url = new_url;

try committed.resolve({});
Copy link
Member

Choose a reason for hiding this comment

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

Is it ok to return on error here w/o calling finished.resolve?

};

pub fn _traverseTo(self: *Navigation, key: []const u8, _: ?TraverseToOptions, page: *Page) !NavigationReturn {
// const opts = _opts orelse TraverseToOptions{};
Copy link
Member

Choose a reason for hiding this comment

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

Consider to add a not implemented debug log

typ: []const u8,
listener: EventHandler.Listener,
) !?js.Function {
const target = @as(*parser.EventTarget, @ptrCast(self));
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you see if:

parser.toEventTarget(NavigationEventTarget, self),

works? I think that's the safer version, but I know we don't use it everywhere we ought to.


pub fn set_oncurrententrychange(self: *NavigationEventTarget, listener: ?EventHandler.Listener, page: *Page) !void {
if (self.oncurrententrychange_cbk) |cbk| try self.unregister("currententrychange", cbk.id);
if (listener) |listen| {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we make this mistake in other places. If listener is null, we never set oncurrententrychange_cbk back to null!

.@"enum" => {
const T = @TypeOf(value);
if (@hasDecl(T, "toString")) {
// This should be deprecated in favor of the ENUM_JS_USE_TAG.
Copy link
Collaborator

Choose a reason for hiding this comment

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

That could work, but the JS values often require escaping in Zig, e.g. largest-contentful-paint. Who likes typing @"largest-contentful-paint" ? On the flip side, these are pretty rare and they tend to be isolated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants