mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-28 15:40:04 +00:00
Improve async tests
testing.async(...) is pretty lame. It works for simple cases, where the microtask is very quickly resolved, but otherwise can't block the test from exiting. This adds an overload to testing.async and leverages the new Runner https://github.com/lightpanda-io/browser/pull/1958 to "tick" until completion (or timeout). The overloaded version of testing.async() (called without a callback) will increment a counter which is only decremented with the promise is resolved. The test runner will now `tick` until the counter == 0.
This commit is contained in:
@@ -3587,12 +3587,7 @@ test "WebApi: Page" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "WebApi: Frames" {
|
test "WebApi: Frames" {
|
||||||
// TOO FLAKY, disabled for now
|
try testing.htmlRunner("frames", .{});
|
||||||
|
|
||||||
// const filter: testing.LogFilter = .init(&.{.js});
|
|
||||||
// defer filter.deinit();
|
|
||||||
|
|
||||||
// try testing.htmlRunner("frames", .{});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test "WebApi: Integration" {
|
test "WebApi: Integration" {
|
||||||
|
|||||||
@@ -118,24 +118,24 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script id=link_click>
|
<script id=link_click type=module>
|
||||||
testing.async(async (restore) => {
|
const state = await testing.async();
|
||||||
let f6;
|
|
||||||
await new Promise((resolve) => {
|
let count = 0;
|
||||||
let count = 0;
|
let f6 = document.createElement('iframe');
|
||||||
f6 = document.createElement('iframe');
|
f6.id = 'f6';
|
||||||
f6.id = 'f6';
|
f6.addEventListener('load', () => {
|
||||||
f6.addEventListener('load', () => {
|
if (++count == 2) {
|
||||||
if (++count == 2) {
|
state.resolve();
|
||||||
resolve();
|
return;
|
||||||
return;
|
}
|
||||||
}
|
f6.contentDocument.querySelector('#link').click();
|
||||||
f6.contentDocument.querySelector('#link').click();
|
});
|
||||||
});
|
|
||||||
f6.src = "support/with_link.html";
|
f6.src = 'support/with_link.html';
|
||||||
document.documentElement.appendChild(f6);
|
document.documentElement.appendChild(f6);
|
||||||
});
|
|
||||||
restore();
|
await state.done(() => {
|
||||||
testing.expectEqual("<html><head></head><body>It was clicked!\n</body></html>", f6.contentDocument.documentElement.outerHTML);
|
testing.expectEqual("<html><head></head><body>It was clicked!\n</body></html>", f6.contentDocument.documentElement.outerHTML);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
{
|
{
|
||||||
let reply = null;
|
let reply = null;
|
||||||
window.addEventListener('message', (e) => {
|
window.addEventListener('message', (e) => {
|
||||||
console.warn('reply')
|
|
||||||
reply = e.data;
|
reply = e.data;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<script>
|
<script>
|
||||||
window.addEventListener('message', (e) => {
|
window.addEventListener('message', (e) => {
|
||||||
console.warn('Frame Message', e.data);
|
|
||||||
if (e.data === 'ping') {
|
if (e.data === 'ping') {
|
||||||
window.top.postMessage({data: 'pong', origin: e.origin}, '*');
|
window.top.postMessage({data: 'pong', origin: e.origin}, '*');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
let eventuallies = [];
|
let eventuallies = [];
|
||||||
let async_capture = null;
|
let async_capture = null;
|
||||||
let current_script_id = null;
|
let current_script_id = null;
|
||||||
|
let async_pending = 0;
|
||||||
|
|
||||||
function expectTrue(actual) {
|
function expectTrue(actual) {
|
||||||
expectEqual(true, actual);
|
expectEqual(true, actual);
|
||||||
@@ -64,6 +65,25 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function async(cb) {
|
async function async(cb) {
|
||||||
|
if (cb == undefined) {
|
||||||
|
let resolve = null
|
||||||
|
const promise = new Promise((r) => { resolve = r});
|
||||||
|
async_pending += 1;
|
||||||
|
|
||||||
|
return {
|
||||||
|
promise: promise,
|
||||||
|
resolve: resolve,
|
||||||
|
capture: {script_id: document.currentScript.id, stack: new Error().stack},
|
||||||
|
done: async function(cb) {
|
||||||
|
await this.promise;
|
||||||
|
async_pending -= 1;
|
||||||
|
async_capture = this.capture;
|
||||||
|
cb();
|
||||||
|
async_capture = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
let capture = {script_id: document.currentScript.id, stack: new Error().stack};
|
let capture = {script_id: document.currentScript.id, stack: new Error().stack};
|
||||||
await cb(() => { async_capture = capture; });
|
await cb(() => { async_capture = capture; });
|
||||||
async_capture = null;
|
async_capture = null;
|
||||||
@@ -74,6 +94,10 @@
|
|||||||
throw new Error('Failed');
|
throw new Error('Failed');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (async_pending > 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (let e of eventuallies) {
|
for (let e of eventuallies) {
|
||||||
current_script_id = e.script_id;
|
current_script_id = e.script_id;
|
||||||
e.callback();
|
e.callback();
|
||||||
@@ -97,6 +121,8 @@
|
|||||||
throw new Error(`script id: '${script_id}' failed: ${status || 'no assertions'}`);
|
throw new Error(`script id: '${script_id}' failed: ${status || 'no assertions'}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const IS_TEST_RUNNER = window.navigator.userAgent.startsWith("Lightpanda/");
|
const IS_TEST_RUNNER = window.navigator.userAgent.startsWith("Lightpanda/");
|
||||||
|
|||||||
@@ -410,21 +410,46 @@ fn runWebApiTest(test_file: [:0]const u8) !void {
|
|||||||
page.js.localScope(&ls);
|
page.js.localScope(&ls);
|
||||||
defer ls.deinit();
|
defer ls.deinit();
|
||||||
|
|
||||||
var try_catch: js.TryCatch = undefined;
|
{
|
||||||
try_catch.init(&ls.local);
|
var try_catch: js.TryCatch = undefined;
|
||||||
defer try_catch.deinit();
|
try_catch.init(&ls.local);
|
||||||
|
defer try_catch.deinit();
|
||||||
|
|
||||||
|
try page.navigate(url, .{});
|
||||||
|
}
|
||||||
|
|
||||||
try page.navigate(url, .{});
|
|
||||||
var runner = try test_session.runner(.{});
|
var runner = try test_session.runner(.{});
|
||||||
try runner.wait(.{ .ms = 2000 });
|
try runner.wait(.{ .ms = 2000 });
|
||||||
|
|
||||||
test_browser.runMicrotasks();
|
var wait_ms: u32 = 2000;
|
||||||
|
var timer = try std.time.Timer.start();
|
||||||
|
while (true) {
|
||||||
|
var try_catch: js.TryCatch = undefined;
|
||||||
|
try_catch.init(&ls.local);
|
||||||
|
defer try_catch.deinit();
|
||||||
|
|
||||||
ls.local.eval("testing.assertOk()", "testing.assertOk()") catch |err| {
|
const js_val = ls.local.exec("testing.assertOk()", "testing.assertOk()") catch |err| {
|
||||||
const caught = try_catch.caughtOrError(arena_allocator, err);
|
const caught = try_catch.caughtOrError(arena_allocator, err);
|
||||||
std.debug.print("{s}: test failure\nError: {f}\n", .{ test_file, caught });
|
std.debug.print("{s}: test failure\nError: {f}\n", .{ test_file, caught });
|
||||||
return err;
|
return err;
|
||||||
};
|
};
|
||||||
|
if (js_val.isTrue()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (try runner.tick(.{ .ms = 20 })) {
|
||||||
|
.done => return error.TestNeverSignaledCompletion,
|
||||||
|
.ok => |next_ms| {
|
||||||
|
const ms_elapsed = timer.lap() / 1_000_000;
|
||||||
|
if (ms_elapsed >= wait_ms) {
|
||||||
|
return error.TestTimedOut;
|
||||||
|
}
|
||||||
|
wait_ms -= @intCast(ms_elapsed);
|
||||||
|
if (next_ms > 0) {
|
||||||
|
std.Thread.sleep(std.time.ns_per_ms * next_ms);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used by a few CDP tests - wouldn't be sad to see this go.
|
// Used by a few CDP tests - wouldn't be sad to see this go.
|
||||||
|
|||||||
Reference in New Issue
Block a user