mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-28 14:43:28 +00:00
fix navigation and related tests
This commit is contained in:
@@ -81,7 +81,9 @@ fn _dispatchPopStateEvent(state: ?[]const u8, page: *Page) !void {
|
||||
pub fn _pushState(_: *const History, state: js.Object, _: ?[]const u8, _url: ?[]const u8, page: *Page) !void {
|
||||
const arena = page.session.arena;
|
||||
const url = if (_url) |u| try arena.dupe(u8, u) else try arena.dupe(u8, page.url.raw);
|
||||
_ = try page.session.navigation.pushEntry(url, .{ .state = state }, page);
|
||||
|
||||
const json = state.toJson(arena) catch return error.DataClone;
|
||||
_ = try page.session.navigation.pushEntry(url, json, page);
|
||||
}
|
||||
|
||||
pub fn _replaceState(_: *const History, state: js.Object, _: ?[]const u8, _url: ?[]const u8, page: *Page) !void {
|
||||
@@ -113,7 +115,7 @@ pub fn go(_: *const History, delta: i32, page: *Page) !void {
|
||||
}
|
||||
}
|
||||
|
||||
_ = try entry.navigate(page, .force);
|
||||
_ = try page.session.navigation.navigate(entry.url, .{ .traverse = index }, page);
|
||||
}
|
||||
|
||||
pub fn _go(self: *History, _delta: ?i32, page: *Page) !void {
|
||||
|
||||
@@ -34,16 +34,24 @@ const Navigation = @This();
|
||||
pub const Interfaces = .{
|
||||
Navigation,
|
||||
NavigationActivation,
|
||||
NavigationTransition,
|
||||
NavigationHistoryEntry,
|
||||
};
|
||||
|
||||
pub const NavigationKind = union(enum) {
|
||||
initial,
|
||||
push: ?[]const u8,
|
||||
replace,
|
||||
traverse: usize,
|
||||
reload,
|
||||
};
|
||||
|
||||
pub const prototype = *EventTarget;
|
||||
base: parser.EventTargetTBase = parser.EventTargetTBase{ .internal_target_type = .plain },
|
||||
|
||||
index: usize = 0,
|
||||
entries: std.ArrayListUnmanaged(NavigationHistoryEntry) = .empty,
|
||||
next_entry_id: usize = 0,
|
||||
// TODO: key->index mapping
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/NavigationHistoryEntry
|
||||
const NavigationHistoryEntry = struct {
|
||||
@@ -91,49 +99,17 @@ const NavigationHistoryEntry = struct {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn navigate(entry: NavigationHistoryEntry, reload: enum { none, force }, page: *Page) !NavigationReturn {
|
||||
const arena = page.session.arena;
|
||||
const url = entry.url orelse return error.MissingURL;
|
||||
|
||||
// https://github.com/WICG/navigation-api/issues/95
|
||||
//
|
||||
// These will only settle on same-origin navigation (mostly intended for SPAs).
|
||||
// It is fine (and expected) for these to not settle on cross-origin requests :)
|
||||
const committed = try page.js.createPromiseResolver(.page);
|
||||
const finished = try page.js.createPromiseResolver(.page);
|
||||
|
||||
const new_url = try URL.parse(url, null);
|
||||
if (try page.url.eqlDocument(&new_url, arena) or reload == .force) {
|
||||
page.url = new_url;
|
||||
try committed.resolve({});
|
||||
|
||||
// todo: Fire navigate event
|
||||
|
||||
try finished.resolve({});
|
||||
} else {
|
||||
// TODO: Change to history
|
||||
try page.navigateFromWebAPI(url, .{ .reason = .history });
|
||||
}
|
||||
|
||||
return .{
|
||||
.committed = committed.promise(),
|
||||
.finished = finished.promise(),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/NavigationActivation
|
||||
const NavigationActivation = struct {
|
||||
const NavigationActivationType = enum {
|
||||
pub const ENUM_JS_USE_TAG = true;
|
||||
|
||||
push,
|
||||
reload,
|
||||
replace,
|
||||
traverse,
|
||||
|
||||
pub fn toString(self: NavigationActivationType) []const u8 {
|
||||
return @tagName(self);
|
||||
}
|
||||
};
|
||||
|
||||
entry: NavigationHistoryEntry,
|
||||
@@ -153,6 +129,13 @@ const NavigationActivation = struct {
|
||||
}
|
||||
};
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/NavigationTransition
|
||||
const NavigationTransition = struct {
|
||||
finished: js.Promise,
|
||||
from: NavigationHistoryEntry,
|
||||
navigation_type: NavigationActivation.NavigationActivationType,
|
||||
};
|
||||
|
||||
pub fn get_canGoBack(self: *const Navigation) bool {
|
||||
return self.index > 0;
|
||||
}
|
||||
@@ -169,6 +152,11 @@ pub fn get_currentEntry(self: *const Navigation) NavigationHistoryEntry {
|
||||
return self.entries.items[self.index];
|
||||
}
|
||||
|
||||
pub fn get_transition(_: *const Navigation) ?NavigationTransition {
|
||||
// For now, all transitions are just considered complete.
|
||||
return null;
|
||||
}
|
||||
|
||||
const NavigationReturn = struct {
|
||||
committed: js.Promise,
|
||||
finished: js.Promise,
|
||||
@@ -183,7 +171,7 @@ pub fn _back(self: *Navigation, page: *Page) !NavigationReturn {
|
||||
const next_entry = self.entries.items[new_index];
|
||||
self.index = new_index;
|
||||
|
||||
return next_entry.navigate(.none, page);
|
||||
return self.navigate(next_entry.url, .{ .traverse = new_index }, page);
|
||||
}
|
||||
|
||||
pub fn _entries(self: *const Navigation) []NavigationHistoryEntry {
|
||||
@@ -199,15 +187,33 @@ pub fn _forward(self: *Navigation, page: *Page) !NavigationReturn {
|
||||
const next_entry = self.entries.items[new_index];
|
||||
self.index = new_index;
|
||||
|
||||
return next_entry.navigate(.none, page);
|
||||
return self.navigate(next_entry.url, .{ .traverse = new_index }, page);
|
||||
}
|
||||
|
||||
// This is for after true navigation processing, where we need to ensure that our entries are up to date.
|
||||
pub fn processNavigation(self: *Navigation, url: []const u8, kind: NavigationKind, page: *Page) !void {
|
||||
switch (kind) {
|
||||
.initial => {
|
||||
_ = try self.pushEntry(url, null, page);
|
||||
},
|
||||
.replace => {
|
||||
// When replacing, we just update the URL but the state is nullified.
|
||||
const entry = self.currentEntry();
|
||||
entry.url = url;
|
||||
entry.state = null;
|
||||
},
|
||||
.push => |state| {
|
||||
_ = try self.pushEntry(url, state, page);
|
||||
},
|
||||
.traverse, .reload => {},
|
||||
}
|
||||
}
|
||||
|
||||
/// Pushes an entry into the Navigation stack WITHOUT actually navigating to it.
|
||||
/// For that, use `navigate`.
|
||||
pub fn pushEntry(self: *Navigation, _url: ?[]const u8, _opts: ?NavigateOptions, page: *Page) !NavigationHistoryEntry {
|
||||
pub fn pushEntry(self: *Navigation, _url: ?[]const u8, state: ?[]const u8, page: *Page) !NavigationHistoryEntry {
|
||||
const arena = page.session.arena;
|
||||
|
||||
const options = _opts orelse NavigateOptions{};
|
||||
const url = if (_url) |u| try arena.dupe(u8, u) else null;
|
||||
|
||||
// truncates our history here.
|
||||
@@ -221,14 +227,6 @@ pub fn pushEntry(self: *Navigation, _url: ?[]const u8, _opts: ?NavigateOptions,
|
||||
|
||||
const id_str = try std.fmt.allocPrint(arena, "{d}", .{id});
|
||||
|
||||
const state: ?[]const u8 = blk: {
|
||||
if (options.state) |s| {
|
||||
break :blk s.toJson(arena) catch return error.DataClone;
|
||||
} else {
|
||||
break :blk null;
|
||||
}
|
||||
};
|
||||
|
||||
const entry = NavigationHistoryEntry{
|
||||
.id = id_str,
|
||||
.key = id_str,
|
||||
@@ -237,7 +235,6 @@ pub fn pushEntry(self: *Navigation, _url: ?[]const u8, _opts: ?NavigateOptions,
|
||||
};
|
||||
|
||||
try self.entries.append(arena, entry);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
@@ -255,9 +252,67 @@ const NavigateOptions = struct {
|
||||
history: NavigateOptionsHistory = .auto,
|
||||
};
|
||||
|
||||
pub fn navigate(
|
||||
self: *Navigation,
|
||||
_url: ?[]const u8,
|
||||
kind: NavigationKind,
|
||||
page: *Page,
|
||||
) !NavigationReturn {
|
||||
const arena = page.session.arena;
|
||||
const url = _url orelse return error.MissingURL;
|
||||
|
||||
// https://github.com/WICG/navigation-api/issues/95
|
||||
//
|
||||
// These will only settle on same-origin navigation (mostly intended for SPAs).
|
||||
// It is fine (and expected) for these to not settle on cross-origin requests :)
|
||||
const committed = try page.js.createPromiseResolver(.page);
|
||||
const finished = try page.js.createPromiseResolver(.page);
|
||||
|
||||
const new_url = try URL.parse(url, null);
|
||||
const is_same_document = try page.url.eqlDocument(&new_url, arena);
|
||||
|
||||
switch (kind) {
|
||||
.push => |state| {
|
||||
if (is_same_document) {
|
||||
page.url = new_url;
|
||||
try committed.resolve({});
|
||||
// todo: Fire navigate event
|
||||
try finished.resolve({});
|
||||
|
||||
_ = try self.pushEntry(url, state, page);
|
||||
} else {
|
||||
try page.navigateFromWebAPI(url, .{ .reason = .navigation }, kind);
|
||||
}
|
||||
},
|
||||
.traverse => |index| {
|
||||
self.index = index;
|
||||
|
||||
if (is_same_document) {
|
||||
page.url = new_url;
|
||||
|
||||
try committed.resolve({});
|
||||
// todo: Fire navigate event
|
||||
try finished.resolve({});
|
||||
} else {
|
||||
try page.navigateFromWebAPI(url, .{ .reason = .navigation }, kind);
|
||||
}
|
||||
},
|
||||
.reload => {
|
||||
try page.navigateFromWebAPI(url, .{ .reason = .navigation }, kind);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
|
||||
return .{
|
||||
.committed = committed.promise(),
|
||||
.finished = finished.promise(),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn _navigate(self: *Navigation, _url: []const u8, _opts: ?NavigateOptions, page: *Page) !NavigationReturn {
|
||||
const entry = try self.pushEntry(_url, _opts, page);
|
||||
return entry.navigate(.none, page);
|
||||
const opts = _opts orelse NavigateOptions{};
|
||||
const json = if (opts.state) |state| state.toJson(page.session.arena) catch return error.DataClone else null;
|
||||
return try self.navigate(_url, .{ .push = json }, page);
|
||||
}
|
||||
|
||||
pub const ReloadOptions = struct {
|
||||
@@ -274,15 +329,23 @@ pub fn _reload(self: *Navigation, _opts: ?ReloadOptions, page: *Page) !Navigatio
|
||||
entry.state = state.toJson(arena) catch return error.DataClone;
|
||||
}
|
||||
|
||||
return entry.navigate(.force, page);
|
||||
return self.navigate(entry.url, .reload, page);
|
||||
}
|
||||
|
||||
pub fn _transition(_: *const Navigation) !NavigationReturn {
|
||||
unreachable;
|
||||
pub const TraverseToOptions = struct {
|
||||
info: ?js.Object = null,
|
||||
};
|
||||
|
||||
pub fn _traverseTo(self: *Navigation, key: []const u8, _: ?TraverseToOptions, page: *Page) !NavigationReturn {
|
||||
// const opts = _opts orelse TraverseToOptions{};
|
||||
|
||||
for (self.entries.items, 0..) |entry, i| {
|
||||
if (std.mem.eql(u8, key, entry.key)) {
|
||||
return try self.navigate(entry.url, .{ .traverse = i }, page);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn _traverseTo(_: *const Navigation, _: []const u8) !NavigationReturn {
|
||||
unreachable;
|
||||
return error.InvalidStateError;
|
||||
}
|
||||
|
||||
pub const UpdateCurrentEntryOptions = struct {
|
||||
|
||||
@@ -195,7 +195,7 @@ pub const HTMLDocument = struct {
|
||||
}
|
||||
|
||||
pub fn set_location(_: *const parser.DocumentHTML, url: []const u8, page: *Page) !void {
|
||||
return page.navigateFromWebAPI(url, .{ .reason = .script });
|
||||
return page.navigateFromWebAPI(url, .{ .reason = .script }, .{ .push = null });
|
||||
}
|
||||
|
||||
pub fn get_designMode(_: *parser.DocumentHTML) []const u8 {
|
||||
|
||||
@@ -74,15 +74,15 @@ pub const Location = struct {
|
||||
}
|
||||
|
||||
pub fn _assign(_: *const Location, url: []const u8, page: *Page) !void {
|
||||
return page.navigateFromWebAPI(url, .{ .reason = .script });
|
||||
return page.navigateFromWebAPI(url, .{ .reason = .script }, .{ .push = null });
|
||||
}
|
||||
|
||||
pub fn _replace(_: *const Location, url: []const u8, page: *Page) !void {
|
||||
return page.navigateFromWebAPI(url, .{ .reason = .script });
|
||||
return page.navigateFromWebAPI(url, .{ .reason = .script }, .replace);
|
||||
}
|
||||
|
||||
pub fn _reload(_: *const Location, page: *Page) !void {
|
||||
return page.navigateFromWebAPI(page.url.raw, .{ .reason = .script });
|
||||
return page.navigateFromWebAPI(page.url.raw, .{ .reason = .script }, .reload);
|
||||
}
|
||||
|
||||
pub fn _toString(self: *Location, page: *Page) ![]const u8 {
|
||||
|
||||
@@ -143,7 +143,7 @@ pub const Window = struct {
|
||||
}
|
||||
|
||||
pub fn set_location(_: *const Window, url: []const u8, page: *Page) !void {
|
||||
return page.navigateFromWebAPI(url, .{ .reason = .script });
|
||||
return page.navigateFromWebAPI(url, .{ .reason = .script }, .{ .push = null });
|
||||
}
|
||||
|
||||
// frames return the window itself, but accessing it via a pseudo
|
||||
|
||||
@@ -34,6 +34,7 @@ const Http = @import("../http/Http.zig");
|
||||
const ScriptManager = @import("ScriptManager.zig");
|
||||
const SlotChangeMonitor = @import("SlotChangeMonitor.zig");
|
||||
const HTMLDocument = @import("html/document.zig").HTMLDocument;
|
||||
const NavigationKind = @import("html/Navigation.zig").NavigationKind;
|
||||
|
||||
const js = @import("js/js.zig");
|
||||
const URL = @import("../url.zig").URL;
|
||||
@@ -815,8 +816,8 @@ pub const Page = struct {
|
||||
},
|
||||
}
|
||||
|
||||
// Push the navigation after a successful load.
|
||||
_ = try self.session.navigation.pushEntry(self.url.raw, null, self);
|
||||
// We need to handle different navigation types differently.
|
||||
try self.session.navigation.processNavigation(self.url.raw, self.session.navigation_kind, self);
|
||||
}
|
||||
|
||||
fn pageErrorCallback(ctx: *anyopaque, err: anyerror) void {
|
||||
@@ -906,7 +907,7 @@ pub const Page = struct {
|
||||
.a => {
|
||||
const element: *parser.Element = @ptrCast(node);
|
||||
const href = (try parser.elementGetAttribute(element, "href")) orelse return;
|
||||
try self.navigateFromWebAPI(href, .{});
|
||||
try self.navigateFromWebAPI(href, .{}, .{ .push = null });
|
||||
},
|
||||
.input => {
|
||||
const element: *parser.Element = @ptrCast(node);
|
||||
@@ -1043,7 +1044,7 @@ pub const Page = struct {
|
||||
// As such we schedule the function to be called as soon as possible.
|
||||
// The page.arena is safe to use here, but the transfer_arena exists
|
||||
// specifically for this type of lifetime.
|
||||
pub fn navigateFromWebAPI(self: *Page, url: []const u8, opts: NavigateOpts) !void {
|
||||
pub fn navigateFromWebAPI(self: *Page, url: []const u8, opts: NavigateOpts, kind: NavigationKind) !void {
|
||||
const session = self.session;
|
||||
if (session.queued_navigation != null) {
|
||||
// It might seem like this should never happen. And it might not,
|
||||
@@ -1070,6 +1071,8 @@ pub const Page = struct {
|
||||
.url = try URL.stitch(session.transfer_arena, url, self.url.raw, .{ .alloc = .always }),
|
||||
};
|
||||
|
||||
session.navigation_kind = kind;
|
||||
|
||||
self.http_client.abort();
|
||||
|
||||
// In v8, this throws an exception which JS code cannot catch.
|
||||
@@ -1120,7 +1123,7 @@ pub const Page = struct {
|
||||
} else {
|
||||
action = try URL.concatQueryString(transfer_arena, action, buf.items);
|
||||
}
|
||||
try self.navigateFromWebAPI(action, opts);
|
||||
try self.navigateFromWebAPI(action, opts, .{ .push = null });
|
||||
}
|
||||
|
||||
pub fn isNodeAttached(self: *const Page, node: *parser.Node) bool {
|
||||
@@ -1178,6 +1181,7 @@ pub const NavigateReason = enum {
|
||||
form,
|
||||
script,
|
||||
history,
|
||||
navigation,
|
||||
};
|
||||
|
||||
pub const NavigateOpts = struct {
|
||||
|
||||
@@ -22,6 +22,7 @@ const Allocator = std.mem.Allocator;
|
||||
|
||||
const js = @import("js/js.zig");
|
||||
const Page = @import("page.zig").Page;
|
||||
const NavigationKind = @import("html/Navigation.zig").NavigationKind;
|
||||
const Browser = @import("browser.zig").Browser;
|
||||
const NavigateOpts = @import("page.zig").NavigateOpts;
|
||||
const History = @import("html/History.zig");
|
||||
@@ -59,6 +60,7 @@ pub const Session = struct {
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/History
|
||||
history: History = .{},
|
||||
navigation: Navigation = .{},
|
||||
navigation_kind: NavigationKind = .initial,
|
||||
|
||||
page: ?Page = null,
|
||||
|
||||
|
||||
@@ -174,7 +174,7 @@ pub fn pageNavigate(arena: Allocator, bc: anytype, event: *const Notification.Pa
|
||||
var cdp = bc.cdp;
|
||||
const reason_: ?[]const u8 = switch (event.opts.reason) {
|
||||
.anchor => "anchorClick",
|
||||
.script, .history => "scriptInitiated",
|
||||
.script, .history, .navigation => "scriptInitiated",
|
||||
.form => switch (event.opts.method) {
|
||||
.GET => "formSubmissionGet",
|
||||
.POST => "formSubmissionPost",
|
||||
|
||||
@@ -402,19 +402,13 @@ pub fn htmlRunner(file: []const u8) !void {
|
||||
|
||||
const url = try std.fmt.allocPrint(arena_allocator, "http://localhost:9582/src/tests/{s}", .{file});
|
||||
try page.navigate(url, .{});
|
||||
_ = page.wait(2000);
|
||||
test_session.fetchWait(2000);
|
||||
|
||||
// page exits more aggressively in tests. We want to make sure this is called
|
||||
// at lease once.
|
||||
page.session.browser.runMicrotasks();
|
||||
page.session.browser.runMessageLoop();
|
||||
|
||||
const needs_second_wait = try js_context.exec("testing._onPageWait.length > 0", "check_onPageWait");
|
||||
if (needs_second_wait.value.toBool(page.js.isolate)) {
|
||||
// sets the isSecondWait flag in testing.
|
||||
_ = js_context.exec("testing._isSecondWait = true", "set_second_wait_flag") catch {};
|
||||
_ = page.wait(2000);
|
||||
}
|
||||
|
||||
@import("root").js_runner_duration += std.time.Instant.since(try std.time.Instant.now(), start);
|
||||
|
||||
const value = js_context.exec("testing.getStatus()", "testing.getStatus()") catch |err| {
|
||||
|
||||
@@ -11,10 +11,12 @@
|
||||
testing.expectEqual('auto', history.scrollRestoration);
|
||||
testing.expectEqual(null, history.state)
|
||||
|
||||
history.pushState({ testInProgress: true }, null, 'http://127.0.0.1:9582/xhr/json');
|
||||
history.pushState({ testInProgress: true }, null, 'http://127.0.0.1:9582/src/tests/html/history2.html');
|
||||
testing.expectEqual({ testInProgress: true }, history.state);
|
||||
|
||||
history.pushState({ testInProgress: false }, null, 'http://127.0.0.1:9582/xhr/json');
|
||||
history.replaceState({ "new": "field", testComplete: true }, null);
|
||||
|
||||
let state = { "new": "field", testComplete: true };
|
||||
testing.expectEqual(state, history.state);
|
||||
|
||||
@@ -31,10 +33,5 @@
|
||||
testing.expectEqual(state, popstateEventState);
|
||||
})
|
||||
|
||||
testing.onPageWait(() => {
|
||||
testing.expectEqual(true, history.state && history.state.testComplete);
|
||||
testing.expectEqual(state, history.state);
|
||||
});
|
||||
|
||||
testing.expectEqual(undefined, history.go());
|
||||
history.back();
|
||||
</script>
|
||||
|
||||
6
src/tests/html/history2.html
Normal file
6
src/tests/html/history2.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<script src="../testing.js"></script>
|
||||
|
||||
<script id=history2>
|
||||
testing.expectEqual(true, history.state && history.state.testInProgress);
|
||||
</script>
|
||||
@@ -1,5 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<script src="../testing.js"></script>
|
||||
|
||||
<script id=navigation>
|
||||
testing.expectEqual('object', typeof navigation);
|
||||
testing.expectEqual('object', typeof navigation.currentEntry);
|
||||
@@ -7,43 +8,11 @@
|
||||
testing.expectEqual('string', typeof navigation.currentEntry.id);
|
||||
testing.expectEqual('string', typeof navigation.currentEntry.key);
|
||||
testing.expectEqual('string', typeof navigation.currentEntry.url);
|
||||
testing.expectEqual(0, navigation.currentEntry.index);
|
||||
testing.expectEqual(true, navigation.currentEntry.sameDocument);
|
||||
|
||||
let result = navigation.navigate('http://127.0.0.1:9582/xhr/json', {
|
||||
state: { testInProgress: true }
|
||||
});
|
||||
testing.expectEqual('object', typeof result);
|
||||
testing.expectEqual('object', typeof result.committed);
|
||||
testing.expectEqual('object', typeof result.finished);
|
||||
const currentIndex = navigation.currentEntry.index;
|
||||
|
||||
testing.expectEqual({ testInProgress: true }, navigation.currentEntry.getState());
|
||||
testing.expectEqual(1, navigation.currentEntry.index);
|
||||
|
||||
testing.expectEqual(true, navigation.canGoBack);
|
||||
testing.expectEqual(false, navigation.canGoForward);
|
||||
|
||||
testing.expectEqual(undefined, navigation.back());
|
||||
|
||||
testing.onPageWait(() => {
|
||||
testing.expectEqual(0, navigation.currentEntry.index);
|
||||
testing.expectEqual(true, navigation.canGoForward);
|
||||
|
||||
testing.expectEqual(undefined, navigation.forward());
|
||||
});
|
||||
|
||||
testing.onPageWait(() => {
|
||||
testing.expectEqual(1, navigation.currentEntry.index);
|
||||
testing.expectEqual({ testInProgress: true }, navigation.currentEntry.getState());
|
||||
|
||||
let targetKey = navigation.currentEntry.key;
|
||||
testing.expectEqual(undefined, navigation.traverseTo(targetKey));
|
||||
});
|
||||
|
||||
navigation.updateCurrentEntry({ state: { updated: true, testComplete: true } });
|
||||
testing.expectEqual({ updated: true, testComplete: true }, navigation.currentEntry.getState());
|
||||
|
||||
testing.onPageWait(() => {
|
||||
testing.expectEqual(true, navigation.currentEntry.getState().testComplete);
|
||||
});
|
||||
navigation.navigate(
|
||||
'http://127.0.0.1:9582/src/tests/html/navigation2.html',
|
||||
{ state: { currentIndex: currentIndex, navTestInProgress: true } }
|
||||
);
|
||||
</script>
|
||||
|
||||
8
src/tests/html/navigation2.html
Normal file
8
src/tests/html/navigation2.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<script src="../testing.js"></script>
|
||||
|
||||
<script id=navigation2>
|
||||
const state = navigation.currentEntry.getState();
|
||||
testing.expectEqual(true, state.navTestInProgress);
|
||||
testing.expectEqual(state.currentIndex + 1, navigation.currentEntry.index);
|
||||
</script>
|
||||
@@ -51,14 +51,6 @@
|
||||
// if we're already in a fail state, return fail, nothing can recover this
|
||||
if (testing._status === 'fail') return 'fail';
|
||||
|
||||
if (testing._isSecondWait) {
|
||||
for (const pw of (testing._onPageWait)) {
|
||||
testing._captured = pw[1];
|
||||
pw[0]();
|
||||
testing._captured = null;
|
||||
}
|
||||
}
|
||||
|
||||
// run any eventually's that we've captured
|
||||
for (const ev of testing._eventually) {
|
||||
testing._captured = ev[1];
|
||||
@@ -101,18 +93,6 @@
|
||||
_registerErrorCallback();
|
||||
}
|
||||
|
||||
// Set expectations to happen on the next time that `page.wait` is executed.
|
||||
//
|
||||
// History specifically uses this as it queues navigation that needs to be checked
|
||||
// when the next page is loaded.
|
||||
function onPageWait(fn) {
|
||||
// Store callbacks to run when page.wait() happens
|
||||
testing._onPageWait.push([fn, {
|
||||
script_id: document.currentScript.id,
|
||||
stack: new Error().stack,
|
||||
}]);
|
||||
}
|
||||
|
||||
async function async(promise, cb) {
|
||||
const script_id = document.currentScript ? document.currentScript.id : '<script id is unavailable in browsers>';
|
||||
const stack = new Error().stack;
|
||||
@@ -192,15 +172,12 @@
|
||||
window.testing = {
|
||||
_status: 'empty',
|
||||
_eventually: [],
|
||||
_onPageWait: [],
|
||||
_executed_scripts: new Set(),
|
||||
_captured: null,
|
||||
_isSecondWait: false,
|
||||
skip: skip,
|
||||
async: async,
|
||||
getStatus: getStatus,
|
||||
eventually: eventually,
|
||||
onPageWait: onPageWait,
|
||||
expectEqual: expectEqual,
|
||||
expectError: expectError,
|
||||
withError: withError,
|
||||
|
||||
Reference in New Issue
Block a user