mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-02-04 14:33:47 +00:00
Merge pull request #1399 from alexisbouchez/window-onerror
Some checks failed
nightly build / build-linux-x86_64 (push) Has been cancelled
nightly build / build-linux-aarch64 (push) Has been cancelled
nightly build / build-macos-aarch64 (push) Has been cancelled
nightly build / build-macos-x86_64 (push) Has been cancelled
wpt / web platform tests json output (push) Has been cancelled
wpt / perf-fmt (push) Has been cancelled
e2e-integration-test / zig build release (push) Has been cancelled
e2e-integration-test / demo-integration-scripts (push) Has been cancelled
Some checks failed
nightly build / build-linux-x86_64 (push) Has been cancelled
nightly build / build-linux-aarch64 (push) Has been cancelled
nightly build / build-macos-aarch64 (push) Has been cancelled
nightly build / build-macos-x86_64 (push) Has been cancelled
wpt / web platform tests json output (push) Has been cancelled
wpt / perf-fmt (push) Has been cancelled
e2e-integration-test / zig build release (push) Has been cancelled
e2e-integration-test / demo-integration-scripts (push) Has been cancelled
invoke window.onerror callback in reportError
This commit is contained in:
211
src/browser/tests/window/onerror.html
Normal file
211
src/browser/tests/window/onerror.html
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<script src="../testing.js"></script>
|
||||||
|
|
||||||
|
<script id=onerrorBasicCallback>
|
||||||
|
{
|
||||||
|
let callbackCalled = false;
|
||||||
|
let receivedArgs = null;
|
||||||
|
|
||||||
|
window.onerror = function(message, source, lineno, colno, error) {
|
||||||
|
callbackCalled = true;
|
||||||
|
receivedArgs = { message, source, lineno, colno, error };
|
||||||
|
};
|
||||||
|
|
||||||
|
const err = new Error('Test error');
|
||||||
|
window.reportError(err);
|
||||||
|
|
||||||
|
testing.expectEqual(true, callbackCalled);
|
||||||
|
testing.expectEqual(true, receivedArgs.message.includes('Test error'));
|
||||||
|
testing.expectEqual(err, receivedArgs.error);
|
||||||
|
|
||||||
|
window.onerror = null;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id=onerrorFiveArguments>
|
||||||
|
{
|
||||||
|
let argCount = 0;
|
||||||
|
|
||||||
|
window.onerror = function() {
|
||||||
|
argCount = arguments.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
window.reportError(new Error('Five args test'));
|
||||||
|
|
||||||
|
// Per WHATWG spec, onerror receives exactly 5 arguments
|
||||||
|
testing.expectEqual(5, argCount);
|
||||||
|
|
||||||
|
window.onerror = null;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id=onerrorReturnTrueCancelsEvent>
|
||||||
|
{
|
||||||
|
let listenerCalled = false;
|
||||||
|
|
||||||
|
window.onerror = function() {
|
||||||
|
return true; // Should cancel the event
|
||||||
|
};
|
||||||
|
|
||||||
|
const listener = function() {
|
||||||
|
listenerCalled = true;
|
||||||
|
};
|
||||||
|
window.addEventListener('error', listener);
|
||||||
|
|
||||||
|
window.reportError(new Error('Should be cancelled'));
|
||||||
|
|
||||||
|
// The event listener should still be called (onerror returning true
|
||||||
|
// only prevents default, not propagation)
|
||||||
|
testing.expectEqual(true, listenerCalled);
|
||||||
|
|
||||||
|
window.onerror = null;
|
||||||
|
window.removeEventListener('error', listener);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id=onerrorAndEventListenerBothCalled>
|
||||||
|
{
|
||||||
|
let onerrorCalled = false;
|
||||||
|
let listenerCalled = false;
|
||||||
|
|
||||||
|
window.onerror = function() {
|
||||||
|
onerrorCalled = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const listener = function() {
|
||||||
|
listenerCalled = true;
|
||||||
|
};
|
||||||
|
window.addEventListener('error', listener);
|
||||||
|
|
||||||
|
window.reportError(new Error('Both should fire'));
|
||||||
|
|
||||||
|
testing.expectEqual(true, onerrorCalled);
|
||||||
|
testing.expectEqual(true, listenerCalled);
|
||||||
|
|
||||||
|
window.onerror = null;
|
||||||
|
window.removeEventListener('error', listener);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id=onerrorCalledBeforeEventListener>
|
||||||
|
{
|
||||||
|
let callOrder = [];
|
||||||
|
|
||||||
|
window.onerror = function() {
|
||||||
|
callOrder.push('onerror');
|
||||||
|
};
|
||||||
|
|
||||||
|
const listener = function() {
|
||||||
|
callOrder.push('listener');
|
||||||
|
};
|
||||||
|
window.addEventListener('error', listener);
|
||||||
|
|
||||||
|
window.reportError(new Error('Order test'));
|
||||||
|
|
||||||
|
// onerror should be called before addEventListener handlers
|
||||||
|
testing.expectEqual('onerror', callOrder[0]);
|
||||||
|
testing.expectEqual('listener', callOrder[1]);
|
||||||
|
|
||||||
|
window.onerror = null;
|
||||||
|
window.removeEventListener('error', listener);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id=onerrorGetterSetter>
|
||||||
|
{
|
||||||
|
const handler = function() {};
|
||||||
|
|
||||||
|
testing.expectEqual(null, window.onerror);
|
||||||
|
|
||||||
|
window.onerror = handler;
|
||||||
|
testing.expectEqual(handler, window.onerror);
|
||||||
|
|
||||||
|
window.onerror = null;
|
||||||
|
testing.expectEqual(null, window.onerror);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id=onerrorWithNonFunction>
|
||||||
|
{
|
||||||
|
// Setting onerror to a non-function should not throw
|
||||||
|
// but should not be stored as the handler
|
||||||
|
window.onerror = "not a function";
|
||||||
|
testing.expectEqual(null, window.onerror);
|
||||||
|
|
||||||
|
window.onerror = {};
|
||||||
|
testing.expectEqual(null, window.onerror);
|
||||||
|
|
||||||
|
window.onerror = 123;
|
||||||
|
testing.expectEqual(null, window.onerror);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id=onerrorArgumentTypes>
|
||||||
|
{
|
||||||
|
let receivedTypes = null;
|
||||||
|
|
||||||
|
window.onerror = function(message, source, lineno, colno, error) {
|
||||||
|
receivedTypes = {
|
||||||
|
message: typeof message,
|
||||||
|
source: typeof source,
|
||||||
|
lineno: typeof lineno,
|
||||||
|
colno: typeof colno,
|
||||||
|
error: typeof error
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
window.reportError(new Error('Type check'));
|
||||||
|
|
||||||
|
testing.expectEqual('string', receivedTypes.message);
|
||||||
|
testing.expectEqual('string', receivedTypes.source);
|
||||||
|
testing.expectEqual('number', receivedTypes.lineno);
|
||||||
|
testing.expectEqual('number', receivedTypes.colno);
|
||||||
|
testing.expectEqual('object', receivedTypes.error);
|
||||||
|
|
||||||
|
window.onerror = null;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id=onerrorReturnFalseDoesNotCancel>
|
||||||
|
{
|
||||||
|
let eventDefaultPrevented = false;
|
||||||
|
|
||||||
|
window.onerror = function() {
|
||||||
|
return false; // Should NOT cancel the event
|
||||||
|
};
|
||||||
|
|
||||||
|
const listener = function(e) {
|
||||||
|
eventDefaultPrevented = e.defaultPrevented;
|
||||||
|
};
|
||||||
|
window.addEventListener('error', listener);
|
||||||
|
|
||||||
|
window.reportError(new Error('Return false test'));
|
||||||
|
|
||||||
|
testing.expectEqual(false, eventDefaultPrevented);
|
||||||
|
|
||||||
|
window.onerror = null;
|
||||||
|
window.removeEventListener('error', listener);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id=onerrorReturnTruePreventsDefault>
|
||||||
|
{
|
||||||
|
let eventDefaultPrevented = false;
|
||||||
|
|
||||||
|
window.onerror = function() {
|
||||||
|
return true; // Should cancel (prevent default)
|
||||||
|
};
|
||||||
|
|
||||||
|
const listener = function(e) {
|
||||||
|
eventDefaultPrevented = e.defaultPrevented;
|
||||||
|
};
|
||||||
|
window.addEventListener('error', listener);
|
||||||
|
|
||||||
|
window.reportError(new Error('Return true test'));
|
||||||
|
|
||||||
|
testing.expectEqual(true, eventDefaultPrevented);
|
||||||
|
|
||||||
|
window.onerror = null;
|
||||||
|
window.removeEventListener('error', listener);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -58,7 +58,7 @@ _storage_bucket: *storage.Bucket,
|
|||||||
_on_load: ?js.Function.Global = null,
|
_on_load: ?js.Function.Global = null,
|
||||||
_on_pageshow: ?js.Function.Global = null,
|
_on_pageshow: ?js.Function.Global = null,
|
||||||
_on_popstate: ?js.Function.Global = null,
|
_on_popstate: ?js.Function.Global = null,
|
||||||
_on_error: ?js.Function.Global = null, // TODO: invoke on error?
|
_on_error: ?js.Function.Global = null,
|
||||||
_on_unhandled_rejection: ?js.Function.Global = null, // TODO: invoke on error
|
_on_unhandled_rejection: ?js.Function.Global = null, // TODO: invoke on error
|
||||||
_location: *Location,
|
_location: *Location,
|
||||||
_timer_id: u30 = 0,
|
_timer_id: u30 = 0,
|
||||||
@@ -283,6 +283,32 @@ pub fn reportError(self: *Window, err: js.Value, page: *Page) !void {
|
|||||||
}, page);
|
}, page);
|
||||||
|
|
||||||
const event = error_event.asEvent();
|
const event = error_event.asEvent();
|
||||||
|
|
||||||
|
// Invoke window.onerror callback if set (per WHATWG spec, this is called
|
||||||
|
// with 5 arguments: message, source, lineno, colno, error)
|
||||||
|
// If it returns true, the event is cancelled.
|
||||||
|
if (self._on_error) |on_error| {
|
||||||
|
var ls: js.Local.Scope = undefined;
|
||||||
|
page.js.localScope(&ls);
|
||||||
|
defer ls.deinit();
|
||||||
|
|
||||||
|
const local_func = ls.toLocal(on_error);
|
||||||
|
const result = local_func.call(js.Value, .{
|
||||||
|
error_event._message,
|
||||||
|
error_event._filename,
|
||||||
|
error_event._line_number,
|
||||||
|
error_event._column_number,
|
||||||
|
err,
|
||||||
|
}) catch null;
|
||||||
|
|
||||||
|
// Per spec: returning true from onerror cancels the event
|
||||||
|
if (result) |r| {
|
||||||
|
if (r.isTrue()) {
|
||||||
|
event._prevent_default = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try page._event_manager.dispatch(self.asEventTarget(), event);
|
try page._event_manager.dispatch(self.asEventTarget(), event);
|
||||||
|
|
||||||
if (comptime builtin.is_test == false) {
|
if (comptime builtin.is_test == false) {
|
||||||
@@ -665,7 +691,7 @@ pub const JsApi = struct {
|
|||||||
pub const onload = bridge.accessor(Window.getOnLoad, Window.setOnLoad, .{});
|
pub const onload = bridge.accessor(Window.getOnLoad, Window.setOnLoad, .{});
|
||||||
pub const onpageshow = bridge.accessor(Window.getOnPageShow, Window.setOnPageShow, .{});
|
pub const onpageshow = bridge.accessor(Window.getOnPageShow, Window.setOnPageShow, .{});
|
||||||
pub const onpopstate = bridge.accessor(Window.getOnPopState, Window.setOnPopState, .{});
|
pub const onpopstate = bridge.accessor(Window.getOnPopState, Window.setOnPopState, .{});
|
||||||
pub const onerror = bridge.accessor(Window.getOnError, Window.getOnError, .{});
|
pub const onerror = bridge.accessor(Window.getOnError, Window.setOnError, .{});
|
||||||
pub const onunhandledrejection = bridge.accessor(Window.getOnUnhandledRejection, Window.setOnUnhandledRejection, .{});
|
pub const onunhandledrejection = bridge.accessor(Window.getOnUnhandledRejection, Window.setOnUnhandledRejection, .{});
|
||||||
pub const fetch = bridge.function(Window.fetch, .{});
|
pub const fetch = bridge.function(Window.fetch, .{});
|
||||||
pub const queueMicrotask = bridge.function(Window.queueMicrotask, .{});
|
pub const queueMicrotask = bridge.function(Window.queueMicrotask, .{});
|
||||||
|
|||||||
Reference in New Issue
Block a user