diff --git a/Libraries/LibWeb/Bindings/MainThreadVM.cpp b/Libraries/LibWeb/Bindings/MainThreadVM.cpp index 0270ceba9a20b..30abb76b9be69 100644 --- a/Libraries/LibWeb/Bindings/MainThreadVM.cpp +++ b/Libraries/LibWeb/Bindings/MainThreadVM.cpp @@ -739,7 +739,7 @@ void queue_mutation_observer_microtask(DOM::Document const& document) } } - // 4. If records is not empty, then invoke mo’s callback with « records, mo », and mo. If this throws an exception, catch it, and report the exception. + // 4. If records is not empty, then invoke mo’s callback with « records, mo » and "report", and with callback this value mo. if (!records.is_empty()) { auto& callback = mutation_observer->callback(); auto& realm = callback.callback_context; @@ -751,9 +751,7 @@ void queue_mutation_observer_microtask(DOM::Document const& document) MUST(wrapped_records->create_data_property(property_index, record.ptr())); } - auto result = WebIDL::invoke_callback(callback, mutation_observer, wrapped_records, mutation_observer); - if (result.is_abrupt()) - HTML::report_exception(result, realm); + (void)WebIDL::invoke_callback(callback, mutation_observer, WebIDL::ExceptionBehavior::Report, wrapped_records, mutation_observer); } } @@ -827,12 +825,8 @@ void invoke_custom_element_reactions(Vector>& element_que }, [&](DOM::CustomElementCallbackReaction& custom_element_callback_reaction) -> void { // -> callback reaction - // Invoke reaction's callback function with reaction's arguments, and with element as the callback this value. - auto result = WebIDL::invoke_callback(*custom_element_callback_reaction.callback, element.ptr(), custom_element_callback_reaction.arguments); - // FIXME: The error from CustomElementCallbackReaction is supposed - // to use the new steps for IDL callback error reporting - if (result.is_abrupt()) - HTML::report_exception(result, element->realm()); + // Invoke reaction's callback function with reaction's arguments and "report", and callback this value set to element. + (void)WebIDL::invoke_callback(*custom_element_callback_reaction.callback, element.ptr(), WebIDL::ExceptionBehavior::Report, custom_element_callback_reaction.arguments); }); } } diff --git a/Libraries/LibWeb/DOM/Document.cpp b/Libraries/LibWeb/DOM/Document.cpp index 7fd6559910594..f3e6dfd561d30 100644 --- a/Libraries/LibWeb/DOM/Document.cpp +++ b/Libraries/LibWeb/DOM/Document.cpp @@ -3983,9 +3983,8 @@ void Document::queue_intersection_observer_task() auto& callback = observer->callback(); // 5. Invoke callback with queue as the first argument, observer as the second argument, and observer as the callback this value. If this throws an exception, report the exception. - auto completion = WebIDL::invoke_callback(callback, observer.ptr(), wrapped_queue, observer.ptr()); - if (completion.is_abrupt()) - HTML::report_exception(completion, realm); + // NOTE: This does not follow the spec as written precisely, but this is the same thing we do elsewhere and there is a WPT test that relies on this. + (void)WebIDL::invoke_callback(callback, observer.ptr(), WebIDL::ExceptionBehavior::Report, wrapped_queue, observer.ptr()); } })); } diff --git a/Libraries/LibWeb/HTML/HTMLCanvasElement.cpp b/Libraries/LibWeb/HTML/HTMLCanvasElement.cpp index 05e9cb80bcff6..ebc5f0b0fd0f0 100644 --- a/Libraries/LibWeb/HTML/HTMLCanvasElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLCanvasElement.cpp @@ -357,8 +357,8 @@ WebIDL::ExceptionOr HTMLCanvasElement::to_blob(GC::Refbuffer, TRY_OR_THROW_OOM(vm(), String::from_utf8(file_result->mime_type))); - // 2. Invoke callback with « result ». - TRY(WebIDL::invoke_callback(*callback, {}, move(blob_result))); + // 2. Invoke callback with « result » and "report". + TRY(WebIDL::invoke_callback(*callback, {}, WebIDL::ExceptionBehavior::Report, move(blob_result))); return {}; }); if (maybe_error.is_throw_completion()) diff --git a/Libraries/LibWeb/HTML/UniversalGlobalScope.cpp b/Libraries/LibWeb/HTML/UniversalGlobalScope.cpp index a655e333a2112..3199611b7feff 100644 --- a/Libraries/LibWeb/HTML/UniversalGlobalScope.cpp +++ b/Libraries/LibWeb/HTML/UniversalGlobalScope.cpp @@ -84,11 +84,9 @@ void UniversalGlobalScopeMixin::queue_microtask(WebIDL::CallbackType& callback) if (is(this_impl())) document = &static_cast(this_impl()).associated_document(); - // The queueMicrotask(callback) method must queue a microtask to invoke callback, and if callback throws an exception, report the exception. - HTML::queue_a_microtask(document, GC::create_function(realm.heap(), [&callback, &realm] { - auto result = WebIDL::invoke_callback(callback, {}); - if (result.is_error()) - HTML::report_exception(result, realm); + // The queueMicrotask(callback) method must queue a microtask to invoke callback with « » and "report". + HTML::queue_a_microtask(document, GC::create_function(realm.heap(), [&callback] { + (void)WebIDL::invoke_callback(callback, {}, WebIDL::ExceptionBehavior::Report); })); } diff --git a/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.cpp b/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.cpp index b15db69ce8b42..0773f7ff0a6fe 100644 --- a/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.cpp +++ b/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.cpp @@ -258,7 +258,7 @@ i32 WindowOrWorkerGlobalScopeMixin::run_timer_initialization_steps(TimerHandler { // 1. Let thisArg be global if that is a WorkerGlobalScope object; otherwise let thisArg be the WindowProxy that corresponds to global. - // 2. If previousId was given, let id be previousId; otherwise, let id be an implementation-defined integer that is greater than zero and does not already exist in global's map of active timers. + // 2. If previousId was given, let id be previousId; otherwise, let id be an implementation-defined integer that is greater than zero and does not already exist in global's map of setTimeout and setInterval IDs. auto id = previous_id.has_value() ? previous_id.value() : m_timer_id_allocator.allocate(); // FIXME: 3. If the surrounding agent's event loop's currently running task is a task that was created by this algorithm, then let nesting level be the task's timer nesting level. Otherwise, let nesting level be zero. @@ -268,42 +268,60 @@ i32 WindowOrWorkerGlobalScopeMixin::run_timer_initialization_steps(TimerHandler timeout = 0; // FIXME: 5. If nesting level is greater than 5, and timeout is less than 4, then set timeout to 4. - - // 6. Let callerRealm be the current Realm Record, and calleeRealm be global's relevant Realm. - // FIXME: Implement this when step 9.3.2 is implemented. + // FIXME: 6. Let realm be global's relevant realm. // 7. Let initiating script be the active script. auto const* initiating_script = Web::Bindings::active_script(); auto& vm = this_impl().vm(); - // 8. Let task be a task that runs the following substeps: - auto task = GC::create_function(vm.heap(), Function([this, handler = move(handler), timeout, arguments = move(arguments), repeat, id, initiating_script]() { - // 1. If id does not exist in global's map of active timers, then abort these steps. + // FIXME 8. Let uniqueHandle be null. + + // 9. Let task be a task that runs the following substeps: + auto task = GC::create_function(vm.heap(), Function([this, handler = move(handler), timeout, arguments = move(arguments), repeat, id, initiating_script, previous_id]() { + // FIXME: 1. Assert: uniqueHandle is a unique internal value, not null. + + // 2. If id does not exist in global's map of setTimeout and setInterval IDs, then abort these steps. if (!m_timers.contains(id)) return; + // FIXME: 3. If global's map of setTimeout and setInterval IDs[id] does not equal uniqueHandle, then abort these steps. + // FIXME: 4. Record timing info for timer handler given handler, global's relevant settings object, and repeat. + handler.visit( - // 2. If handler is a Function, then invoke handler given arguments with the callback this value set to thisArg. If this throws an exception, catch it, and report the exception. + // 5. If handler is a Function, then invoke handler given arguments and "report", and with callback this value set to thisArg. [&](GC::Root const& callback) { - if (auto result = WebIDL::invoke_callback(*callback, &this_impl(), arguments); result.is_error()) - report_exception(result, this_impl().realm()); + (void)WebIDL::invoke_callback(*callback, &this_impl(), WebIDL::ExceptionBehavior::Report, arguments); }, - // 3. Otherwise: + // 6. Otherwise: [&](String const& source) { - // 1. Assert: handler is a string. - // FIXME: 2. Perform HostEnsureCanCompileStrings(callerRealm, calleeRealm). If this throws an exception, catch it, report the exception, and abort these steps. + // 1. If previousId was not given: + if (!previous_id.has_value()) { + // 1. Let globalName be "Window" if global is a Window object; "Worker" otherwise. + auto global_name = is(this_impl()) ? "Window"sv : "Worker"sv; + + // 2. Let methodName be "setInterval" if repeat is true; "setTimeout" otherwise. + auto method_name = repeat == Repeat::Yes ? "setInterval"sv : "setTimeout"sv; + + // 3. Let sink be a concatenation of globalName, U+0020 SPACE, and methodName. + [[maybe_unused]] auto sink = String::formatted("{} {}", global_name, method_name); - // 3. Let settings object be global's relevant settings object. + // FIXME: 4. Set handler to the result of invoking the Get Trusted Type compliant string algorithm with TrustedScript, global, handler, sink, and "script". + } + + // FIXME: 2. Assert: handler is a string. + // FIXME: 3. Perform EnsureCSPDoesNotBlockStringCompilation(realm, « », handler, handler, timer, « », handler). If this throws an exception, catch it, report it for global, and abort these steps. + + // 4. Let settings object be global's relevant settings object. auto& settings_object = relevant_settings_object(this_impl()); - // 4. Let fetch options be the default classic script fetch options. + // 5. Let fetch options be the default classic script fetch options. ScriptFetchOptions options {}; - // 5. Let base URL be settings object's API base URL. + // 6. Let base URL be settings object's API base URL. auto base_url = settings_object.api_base_url(); - // 6. If initiating script is not null, then: + // 7. If initiating script is not null, then: if (initiating_script) { // FIXME: 1. Set fetch options to a script fetch options whose cryptographic nonce is initiating script's fetch options's cryptographic nonce, // integrity metadata is the empty string, parser metadata is "not-parser-inserted", credentials mode is initiating script's fetch @@ -316,36 +334,38 @@ i32 WindowOrWorkerGlobalScopeMixin::run_timer_initialization_steps(TimerHandler // done by eval(). That is, module script fetches via import() will behave the same in both contexts. } - // 7. Let script be the result of creating a classic script given handler, realm, base URL, and fetch options. + // 8. Let script be the result of creating a classic script given handler, realm, base URL, and fetch options. // FIXME: Pass fetch options. auto basename = base_url.basename(); auto script = ClassicScript::create(basename, source, this_impl().realm(), move(base_url)); - // 8. Run the classic script script. + // 9. Run the classic script script. (void)script->run(); }); - // 4. If id does not exist in global's map of active timers, then abort these steps. + // 7. If id does not exist in global's map of setTimeout and setInterval IDs, then abort these steps. if (!m_timers.contains(id)) return; + // FIXME: 8. If global's map of setTimeout and setInterval IDs[id] does not equal uniqueHandle, then abort these steps. + switch (repeat) { - // 5. If repeat is true, then perform the timer initialization steps again, given global, handler, timeout, arguments, true, and id. + // 9. If repeat is true, then perform the timer initialization steps again, given global, handler, timeout, arguments, true, and id. case Repeat::Yes: run_timer_initialization_steps(handler, timeout, move(arguments), repeat, id); break; - // 6. Otherwise, remove global's map of active timers[id]. + // 10. Otherwise, remove global's map of active timers[id]. case Repeat::No: m_timers.remove(id); break; } })); - // FIXME: 9. Increment nesting level by one. - // FIXME: 10. Set task's timer nesting level to nesting level. + // FIXME: 10. Increment nesting level by one. + // FIXME: 11. Set task's timer nesting level to nesting level. - // 11. Let completionStep be an algorithm step which queues a global task on the timer task source given global to run task. + // 12. Let completionStep be an algorithm step which queues a global task on the timer task source given global to run task. Function completion_step = [this, task = move(task)]() mutable { queue_global_task(Task::Source::TimerTask, this_impl(), GC::create_function(this_impl().heap(), [this, task] { HTML::TemporaryExecutionContext execution_context { this_impl().realm(), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes }; @@ -353,10 +373,13 @@ i32 WindowOrWorkerGlobalScopeMixin::run_timer_initialization_steps(TimerHandler })); }; - // 12. Run steps after a timeout given global, "setTimeout/setInterval", timeout, completionStep, and id. + // 13. Set uniqueHandle to the result of running steps after a timeout given global, "setTimeout/setInterval", timeout, completionStep. + // FIXME: run_steps_after_a_timeout() needs to be updated to return a unique internal value that can be used here. run_steps_after_a_timeout_impl(timeout, move(completion_step), id); - // 13. Return id. + // FIXME: 14. Set global's map of setTimeout and setInterval IDs[id] to uniqueHandle. + + // 15. Return id. return id; } diff --git a/Libraries/LibWeb/ResizeObserver/ResizeObserver.cpp b/Libraries/LibWeb/ResizeObserver/ResizeObserver.cpp index 0a26d455397e3..6100cfd1db91c 100644 --- a/Libraries/LibWeb/ResizeObserver/ResizeObserver.cpp +++ b/Libraries/LibWeb/ResizeObserver/ResizeObserver.cpp @@ -109,9 +109,7 @@ void ResizeObserver::invoke_callback(ReadonlySpan> MUST(wrapped_records->create_data_property(property_index, record.ptr())); } - auto result = WebIDL::invoke_callback(callback, JS::js_undefined(), wrapped_records); - if (result.is_abrupt()) - HTML::report_exception(result, realm); + (void)WebIDL::invoke_callback(callback, JS::js_undefined(), WebIDL::ExceptionBehavior::Report, wrapped_records); } } diff --git a/Libraries/LibWeb/WebIDL/AbstractOperations.cpp b/Libraries/LibWeb/WebIDL/AbstractOperations.cpp index 5476c6cc79056..2163839c6c296 100644 --- a/Libraries/LibWeb/WebIDL/AbstractOperations.cpp +++ b/Libraries/LibWeb/WebIDL/AbstractOperations.cpp @@ -254,8 +254,16 @@ JS::ThrowCompletionOr to_usv_string(JS::VM& vm, JS::Value value) // https://webidl.spec.whatwg.org/#invoke-a-callback-function // https://whatpr.org/webidl/1437.html#invoke-a-callback-function -JS::Completion invoke_callback(WebIDL::CallbackType& callback, Optional this_argument, GC::MarkedVector args) +JS::Completion invoke_callback(WebIDL::CallbackType& callback, Optional this_argument, ExceptionBehavior exception_behavior, GC::MarkedVector args) { + // https://webidl.spec.whatwg.org/#js-invoking-callback-functions + // The exceptionBehavior argument must be supplied if, and only if, callable’s return type is not a promise type. If callable’s return type is neither undefined nor any, it must be "rethrow". + // NOTE: Until call sites are updated to respect this, specifications which fail to provide a value here when it would be mandatory should be understood as supplying "rethrow". + if (exception_behavior == ExceptionBehavior::NotSpecified && callback.operation_returns_promise == OperationReturnsPromise::No) + exception_behavior = ExceptionBehavior::Rethrow; + + VERIFY(exception_behavior == ExceptionBehavior::NotSpecified || callback.operation_returns_promise == OperationReturnsPromise::No); + // 1. Let completion be an uninitialized variable. JS::Completion completion; @@ -275,36 +283,84 @@ JS::Completion invoke_callback(WebIDL::CallbackType& callback, Optionalshape().realm(); - // 6. Let stored realm be value’s callback context. + // 6. Let stored realm be callable’s callback context. auto& stored_realm = callback.callback_context; - // 8. Prepare to run script with relevant realm. + // 7. Prepare to run script with relevant realm. HTML::prepare_to_run_script(relevant_realm); - // 9. Prepare to run a callback with stored realm. + // 8. Prepare to run a callback with stored realm. HTML::prepare_to_run_callback(stored_realm); - // FIXME: 10. Let esArgs be the result of converting args to an ECMAScript arguments list. If this throws an exception, set completion to the completion value representing the thrown exception and jump to the step labeled return. - // For simplicity, we currently make the caller do this. However, this means we can't throw exceptions at this point like the spec wants us to. + // FIXME: 9. Let jsArgs be the result of converting args to a JavaScript arguments list. + // If this throws an exception, set completion to the completion value representing the thrown exception and jump to the step labeled return. - // 11. Let callResult be Call(F, thisArg, esArgs). + // 10. Let callResult be Call(F, thisArg, jsArgs). auto& vm = function_object->vm(); auto call_result = JS::call(vm, verify_cast(*function_object), this_argument.value(), args.span()); - // 12. If callResult is an abrupt completion, set completion to callResult and jump to the step labeled return. + auto return_steps = [&](JS::Completion completion) -> JS::Completion { + // 1. Clean up after running a callback with stored realm. + HTML::clean_up_after_running_callback(stored_realm); + + // 2. Clean up after running script with relevant realm. + // FIXME: This method follows an older version of the spec, which takes a realm, so we use F's associated realm instead. + HTML::clean_up_after_running_script(relevant_realm); + + // 3. If completion is an IDL value, return completion. + if (!completion.is_abrupt()) + return completion; + + // 4. Assert: completion is an abrupt completion. + VERIFY(completion.is_abrupt()); + + // 5. If exceptionBehavior is "rethrow", throw completion.[[Value]]. + if (exception_behavior == ExceptionBehavior::Rethrow) { + TRY(JS::throw_completion(*completion.release_value())); + } + // 6. Otherwise, if exceptionBehavior is "report": + else if (exception_behavior == ExceptionBehavior::Report) { + // FIXME: 1. Assert: callable’s return type is undefined or any. + + // 2. Report an exception completion.[[Value]] for relevant realm’s global object. + auto* window_or_worker = dynamic_cast(&relevant_realm.global_object()); + VERIFY(window_or_worker); + window_or_worker->report_an_exception(*completion.release_value()); + + // 3. Return the unique undefined IDL value. + return JS::js_undefined(); + } + + // 7. Assert: callable’s return type is a promise type. + VERIFY(callback.operation_returns_promise == OperationReturnsPromise::Yes); + + // 8. Let rejectedPromise be ! Call(%Promise.reject%, %Promise%, «completion.[[Value]]»). + auto rejected_promise = create_rejected_promise(relevant_realm, *completion.release_value()); + + // 9. Return the result of converting rejectedPromise to the callback function’s return type. + return JS::Value { rejected_promise->promise() }; + }; + + // 11. If callResult is an abrupt completion, set completion to callResult and jump to the step labeled return. if (call_result.is_throw_completion()) { completion = call_result.throw_completion(); - return clean_up_on_return(stored_realm, relevant_realm, completion, callback.operation_returns_promise); + return return_steps(completion); } - // 13. Set completion to the result of converting callResult.[[Value]] to an IDL value of the same type as the operation’s return type. + // 12. Set completion to the result of converting callResult.[[Value]] to an IDL value of the same type as callable’s return type. + // If this throws an exception, set completion to the completion value representing the thrown exception. // FIXME: This does no conversion. completion = call_result.value(); - return clean_up_on_return(stored_realm, relevant_realm, completion, callback.operation_returns_promise); + return return_steps(completion); +} + +JS::Completion invoke_callback(WebIDL::CallbackType& callback, Optional this_argument, GC::MarkedVector args) +{ + return invoke_callback(callback, move(this_argument), ExceptionBehavior::NotSpecified, move(args)); } JS::Completion construct(WebIDL::CallbackType& callback, GC::MarkedVector args) diff --git a/Libraries/LibWeb/WebIDL/AbstractOperations.h b/Libraries/LibWeb/WebIDL/AbstractOperations.h index 7728588a3d8b5..301055f071481 100644 --- a/Libraries/LibWeb/WebIDL/AbstractOperations.h +++ b/Libraries/LibWeb/WebIDL/AbstractOperations.h @@ -39,18 +39,31 @@ JS::Completion call_user_object_operation(WebIDL::CallbackType& callback, String return call_user_object_operation(callback, operation_name, move(this_argument), move(arguments_list)); } +enum class ExceptionBehavior { + NotSpecified, + Report, + Rethrow, +}; + +JS::Completion invoke_callback(WebIDL::CallbackType& callback, Optional this_argument, ExceptionBehavior exception_behavior, GC::MarkedVector args); JS::Completion invoke_callback(WebIDL::CallbackType& callback, Optional this_argument, GC::MarkedVector args); // https://webidl.spec.whatwg.org/#invoke-a-callback-function template -JS::Completion invoke_callback(WebIDL::CallbackType& callback, Optional this_argument, Args&&... args) +JS::Completion invoke_callback(WebIDL::CallbackType& callback, Optional this_argument, ExceptionBehavior exception_behavior, Args&&... args) { auto& function_object = callback.callback; GC::MarkedVector arguments_list { function_object->heap() }; (arguments_list.append(forward(args)), ...); - return invoke_callback(callback, move(this_argument), move(arguments_list)); + return invoke_callback(callback, move(this_argument), exception_behavior, move(arguments_list)); +} + +template +JS::Completion invoke_callback(WebIDL::CallbackType& callback, Optional this_argument, Args&&... args) +{ + return invoke_callback(callback, move(this_argument), ExceptionBehavior::NotSpecified, forward(args)...); } JS::Completion construct(WebIDL::CallbackType& callback, GC::MarkedVector args); diff --git a/Tests/LibWeb/Text/expected/wpt-import/custom-elements/cross-realm-callback-report-exception.txt b/Tests/LibWeb/Text/expected/wpt-import/custom-elements/cross-realm-callback-report-exception.txt new file mode 100644 index 0000000000000..f8866dd7d64e8 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/custom-elements/cross-realm-callback-report-exception.txt @@ -0,0 +1,11 @@ +Harness status: OK + +Found 5 tests + +4 Pass +1 Fail +Fail constructor +Pass connectedCallback +Pass disconnectedCallback +Pass attributeChangedCallback +Pass adoptedCallback \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/nodes/MutationObserver-cross-realm-callback-report-exception.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/nodes/MutationObserver-cross-realm-callback-report-exception.txt new file mode 100644 index 0000000000000..7348cd8846477 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/dom/nodes/MutationObserver-cross-realm-callback-report-exception.txt @@ -0,0 +1,6 @@ +Harness status: OK + +Found 1 tests + +1 Pass +Pass MutationObserver reports the exception from its callback in the callback's global object \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/html/semantics/embedded-content/the-canvas-element/toBlob-cross-realm-callback-report-exception.txt b/Tests/LibWeb/Text/expected/wpt-import/html/semantics/embedded-content/the-canvas-element/toBlob-cross-realm-callback-report-exception.txt new file mode 100644 index 0000000000000..b03164168bb55 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/html/semantics/embedded-content/the-canvas-element/toBlob-cross-realm-callback-report-exception.txt @@ -0,0 +1,6 @@ +Harness status: OK + +Found 1 tests + +1 Pass +Pass toBlob() reports the exception from its callback in the callback's global object \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/html/webappapis/microtask-queuing/queue-microtask-cross-realm-callback-report-exception.txt b/Tests/LibWeb/Text/expected/wpt-import/html/webappapis/microtask-queuing/queue-microtask-cross-realm-callback-report-exception.txt new file mode 100644 index 0000000000000..1519c3376f638 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/html/webappapis/microtask-queuing/queue-microtask-cross-realm-callback-report-exception.txt @@ -0,0 +1,6 @@ +Harness status: OK + +Found 1 tests + +1 Pass +Pass queueMicrotask() reports the exception from its callback in the callback's global object \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/html/webappapis/timers/setinterval-cross-realm-callback-report-exception.txt b/Tests/LibWeb/Text/expected/wpt-import/html/webappapis/timers/setinterval-cross-realm-callback-report-exception.txt new file mode 100644 index 0000000000000..bf3e0cdcbce1d --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/html/webappapis/timers/setinterval-cross-realm-callback-report-exception.txt @@ -0,0 +1,6 @@ +Harness status: OK + +Found 1 tests + +1 Pass +Pass window.setInterval() reports the exception from its callback in the callback's global object \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/html/webappapis/timers/settimeout-cross-realm-callback-report-exception.txt b/Tests/LibWeb/Text/expected/wpt-import/html/webappapis/timers/settimeout-cross-realm-callback-report-exception.txt new file mode 100644 index 0000000000000..030fced17aeb9 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/html/webappapis/timers/settimeout-cross-realm-callback-report-exception.txt @@ -0,0 +1,6 @@ +Harness status: OK + +Found 1 tests + +1 Pass +Pass window.setTimeout() reports the exception from its callback in the callback's global object \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/intersection-observer/callback-cross-realm-report-exception.txt b/Tests/LibWeb/Text/expected/wpt-import/intersection-observer/callback-cross-realm-report-exception.txt new file mode 100644 index 0000000000000..0047e60d5b4fe --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/intersection-observer/callback-cross-realm-report-exception.txt @@ -0,0 +1,6 @@ +Harness status: OK + +Found 1 tests + +1 Pass +Pass IntersectionObserver reports the exception from its callback in the callback's global object \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/resize-observer/callback-cross-realm-report-exception.txt b/Tests/LibWeb/Text/expected/wpt-import/resize-observer/callback-cross-realm-report-exception.txt new file mode 100644 index 0000000000000..3ee00764f5149 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/resize-observer/callback-cross-realm-report-exception.txt @@ -0,0 +1,6 @@ +Harness status: OK + +Found 1 tests + +1 Pass +Pass ResizeObserver reports the exception from its callback in the callback's global object \ No newline at end of file diff --git a/Tests/LibWeb/Text/input/wpt-import/custom-elements/cross-realm-callback-report-exception.html b/Tests/LibWeb/Text/input/wpt-import/custom-elements/cross-realm-callback-report-exception.html new file mode 100644 index 0000000000000..f20481aa6cb32 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/custom-elements/cross-realm-callback-report-exception.html @@ -0,0 +1,83 @@ + + +Exceptions raised in constructors / lifecycle callbacks are reported in their global objects + + + + + + diff --git a/Tests/LibWeb/Text/input/wpt-import/dom/nodes/MutationObserver-cross-realm-callback-report-exception.html b/Tests/LibWeb/Text/input/wpt-import/dom/nodes/MutationObserver-cross-realm-callback-report-exception.html new file mode 100644 index 0000000000000..946c795bd34bc --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/dom/nodes/MutationObserver-cross-realm-callback-report-exception.html @@ -0,0 +1,32 @@ + + +MutationObserver reports the exception from its callback in the callback's global object + + + + + + diff --git a/Tests/LibWeb/Text/input/wpt-import/html/semantics/embedded-content/the-canvas-element/toBlob-cross-realm-callback-report-exception.html b/Tests/LibWeb/Text/input/wpt-import/html/semantics/embedded-content/the-canvas-element/toBlob-cross-realm-callback-report-exception.html new file mode 100644 index 0000000000000..9e7faad6ff9d0 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/html/semantics/embedded-content/the-canvas-element/toBlob-cross-realm-callback-report-exception.html @@ -0,0 +1,29 @@ + + +toBlob() reports the exception from its callback in the callback's global object + + + + + + diff --git a/Tests/LibWeb/Text/input/wpt-import/html/webappapis/microtask-queuing/queue-microtask-cross-realm-callback-report-exception.html b/Tests/LibWeb/Text/input/wpt-import/html/webappapis/microtask-queuing/queue-microtask-cross-realm-callback-report-exception.html new file mode 100644 index 0000000000000..9c1113eab8a91 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/html/webappapis/microtask-queuing/queue-microtask-cross-realm-callback-report-exception.html @@ -0,0 +1,28 @@ + + +queueMicrotask() reports the exception from its callback in the callback's global object + + + + + + diff --git a/Tests/LibWeb/Text/input/wpt-import/html/webappapis/timers/setinterval-cross-realm-callback-report-exception.html b/Tests/LibWeb/Text/input/wpt-import/html/webappapis/timers/setinterval-cross-realm-callback-report-exception.html new file mode 100644 index 0000000000000..165184cbbf42f --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/html/webappapis/timers/setinterval-cross-realm-callback-report-exception.html @@ -0,0 +1,31 @@ + + +window.setInterval() reports the exception from its callback in the callback's global object + + + + + + diff --git a/Tests/LibWeb/Text/input/wpt-import/html/webappapis/timers/settimeout-cross-realm-callback-report-exception.html b/Tests/LibWeb/Text/input/wpt-import/html/webappapis/timers/settimeout-cross-realm-callback-report-exception.html new file mode 100644 index 0000000000000..6c10af5a682ff --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/html/webappapis/timers/settimeout-cross-realm-callback-report-exception.html @@ -0,0 +1,27 @@ + + +window.setTimeout() reports the exception from its callback in the callback's global object + + + + + + diff --git a/Tests/LibWeb/Text/input/wpt-import/intersection-observer/callback-cross-realm-report-exception.html b/Tests/LibWeb/Text/input/wpt-import/intersection-observer/callback-cross-realm-report-exception.html new file mode 100644 index 0000000000000..f60d60327c4a5 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/intersection-observer/callback-cross-realm-report-exception.html @@ -0,0 +1,30 @@ + + +IntersectionObserver reports the exception from its callback in the callback's global object + + + + + + diff --git a/Tests/LibWeb/Text/input/wpt-import/resize-observer/callback-cross-realm-report-exception.html b/Tests/LibWeb/Text/input/wpt-import/resize-observer/callback-cross-realm-report-exception.html new file mode 100644 index 0000000000000..2e21fc61fc14f --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/resize-observer/callback-cross-realm-report-exception.html @@ -0,0 +1,30 @@ + + +ResizeObserver reports the exception from its callback in the callback's global object + + + + + +