mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-07-31 01:36:15 -04:00
webapi: WebDriver.actionSequence resolves when the actions have run
Fixes WPT /dom/events/focus-event-document-move.html: testdriver's Actions().send() promise resolved immediately (the vendor glue returned Promise.resolve()) while the action sequence runs on the next scheduler tick, so tests asserting right after `await ...send()` observed the pre-action state. actionSequence now returns a promise that a persisted resolver settles once the input sources have been performed; the testdriver vendor glue returns it. The persisted resolver handle is page-managed (persist tracks it on the context), so the task does not reset it itself - doing so double-freed the v8 global at page teardown. Coverage: /dom/events/focus-event-document-move.html 0/1 -> 1/1 (fully green); /dom/events regression clean (201 files). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -84,7 +84,7 @@ pub fn click(_: *const WebDriver, element: *Element, frame: *Frame) !void {
|
||||
// { type: "pointer", actions: [{type: "pointerMove", x, y, origin}, ...] }
|
||||
// { type: "key", actions: [{type: "keyDown", value}, ...] }
|
||||
// { type: "wheel", actions: [{type: "scroll", deltaX, deltaY, origin}, ...] }
|
||||
pub fn actionSequence(_: *const WebDriver, sources: js.Value, frame: *Frame) !void {
|
||||
pub fn actionSequence(_: *const WebDriver, sources: js.Value, frame: *Frame) !js.Promise {
|
||||
if (sources.isArray() == false) {
|
||||
return error.InvalidArgument;
|
||||
}
|
||||
@@ -95,11 +95,16 @@ pub fn actionSequence(_: *const WebDriver, sources: js.Value, frame: *Frame) !vo
|
||||
const persisted = try sources.persist();
|
||||
errdefer persisted.release();
|
||||
|
||||
// Resolved once the actions have been performed, so testdriver's
|
||||
// Actions().send() promise doesn't settle before the events fired.
|
||||
const resolver = frame.js.local.?.createPromiseResolver();
|
||||
|
||||
const action_sequence = try arena.create(ActionSequence);
|
||||
action_sequence.* = .{
|
||||
.frame = frame,
|
||||
.arena = arena,
|
||||
.sources = persisted,
|
||||
.resolver = try resolver.persist(),
|
||||
};
|
||||
errdefer action_sequence.sources.release();
|
||||
|
||||
@@ -108,12 +113,15 @@ pub fn actionSequence(_: *const WebDriver, sources: js.Value, frame: *Frame) !vo
|
||||
.name = "WebDriver.actionSequence",
|
||||
.finalizer = ActionSequence.finalize,
|
||||
});
|
||||
|
||||
return resolver.promise();
|
||||
}
|
||||
|
||||
const ActionSequence = struct {
|
||||
frame: *Frame,
|
||||
arena: Allocator,
|
||||
sources: js.Value.Global,
|
||||
resolver: js.PromiseResolver.Global,
|
||||
|
||||
fn run(ptr: *anyopaque) !?u32 {
|
||||
const self: *ActionSequence = @ptrCast(@alignCast(ptr));
|
||||
@@ -141,6 +149,8 @@ const ActionSequence = struct {
|
||||
}
|
||||
// "none" sources only carry pauses, which have no observable effect here.
|
||||
}
|
||||
|
||||
ls.toLocal(self.resolver).resolve("WebDriver.actionSequence", {});
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -151,6 +161,8 @@ const ActionSequence = struct {
|
||||
|
||||
fn deinit(self: *ActionSequence) void {
|
||||
self.sources.release();
|
||||
// The persisted resolver handle is page-managed; resetting it here
|
||||
// too would double-free the v8 global at page teardown.
|
||||
self.frame.releaseArena(self.arena);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user