diff --git a/Tests/LibWeb/Text/expected/HTML/WindowOrWorkerGlobalScope-reportError.txt b/Tests/LibWeb/Text/expected/HTML/WindowOrWorkerGlobalScope-reportError.txt
new file mode 100644
index 00000000000..9d7a5126046
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/HTML/WindowOrWorkerGlobalScope-reportError.txt
@@ -0,0 +1,5 @@
+message = Reporting an Error!
+filename =
+lineno = 0
+colno = 0
+error = Error: Reporting an Error!
diff --git a/Tests/LibWeb/Text/input/HTML/WindowOrWorkerGlobalScope-reportError.html b/Tests/LibWeb/Text/input/HTML/WindowOrWorkerGlobalScope-reportError.html
new file mode 100644
index 00000000000..64cf70b730a
--- /dev/null
+++ b/Tests/LibWeb/Text/input/HTML/WindowOrWorkerGlobalScope-reportError.html
@@ -0,0 +1,16 @@
+
+
diff --git a/Userland/Libraries/LibWeb/HTML/Window.h b/Userland/Libraries/LibWeb/HTML/Window.h
index 44422e4d9f4..51ab20ced3c 100644
--- a/Userland/Libraries/LibWeb/HTML/Window.h
+++ b/Userland/Libraries/LibWeb/HTML/Window.h
@@ -64,6 +64,7 @@ public:
using WindowOrWorkerGlobalScopeMixin::create_image_bitmap;
using WindowOrWorkerGlobalScopeMixin::fetch;
using WindowOrWorkerGlobalScopeMixin::queue_microtask;
+ using WindowOrWorkerGlobalScopeMixin::report_error;
using WindowOrWorkerGlobalScopeMixin::set_interval;
using WindowOrWorkerGlobalScopeMixin::set_timeout;
using WindowOrWorkerGlobalScopeMixin::structured_clone;
diff --git a/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.cpp b/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.cpp
index 128fcfa6a6b..ecbb0ec8b71 100644
--- a/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.cpp
+++ b/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.cpp
@@ -17,6 +17,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -742,4 +743,92 @@ JS::NonnullGCPtr WindowOrWorkerGlobalScopeMixin::supported_entry_typ
return *m_supported_entry_types_array;
}
+// https://html.spec.whatwg.org/multipage/webappapis.html#dom-reporterror
+void WindowOrWorkerGlobalScopeMixin::report_error(JS::Value e)
+{
+ auto& target = static_cast(this_impl());
+ auto& realm = relevant_realm(target);
+ auto& vm = realm.vm();
+ auto script_or_module = vm.get_active_script_or_module();
+
+ // FIXME: Get the current position in the script.
+ auto line = 0;
+ auto col = 0;
+
+ // 1. If target is in error reporting mode, then return; the error is not handled.
+ if (m_error_reporting_mode) {
+ report_exception_to_console(e, realm, ErrorInPromise::No);
+ return;
+ }
+
+ // 2. Let target be in error reporting mode.
+ m_error_reporting_mode = true;
+
+ // 3. Let message be an implementation-defined string describing the error in a helpful manner.
+ auto message = [&] {
+ if (e.is_object()) {
+ auto& object = e.as_object();
+ if (MUST(object.has_own_property(vm.names.message))) {
+ auto message = object.get_without_side_effects(vm.names.message);
+ return message.to_string_without_side_effects();
+ }
+ }
+
+ return MUST(String::formatted("Uncaught exception: {}", e.to_string_without_side_effects()));
+ }();
+
+ // 4. Let errorValue be the value that represents the error: in the case of an uncaught exception,
+ // that would be the value that was thrown; in the case of a JavaScript error that would be an Error object
+ // If there is no corresponding value, then the null value must be used instead.
+ auto error_value = e;
+
+ // 5. Let urlString be the result of applying the URL serializer to the URL record that corresponds to the resource from which script was obtained.
+ // FIXME: Use the URL of the current running script.
+ auto url_string = String {};
+
+ // 6. If script is a classic script and script's muted errors is true, then set message to "Script error.",
+ // urlString to the empty string, line and col to 0, and errorValue to null.
+ script_or_module.visit(
+ [&](const JS::NonnullGCPtr& js_script) {
+ if (verify_cast(js_script->host_defined())->muted_errors() == ClassicScript::MutedErrors::Yes) {
+ message = "Script error."_string;
+ url_string = String {};
+ line = 0;
+ col = 0;
+ error_value = JS::js_null();
+ }
+ },
+ [](auto const&) {});
+
+ // 7. Let notHandled be true.
+ auto not_handled = true;
+
+ // 8. If target implements EventTarget, then set notHandled to the result of firing an event named error at target,
+ // using ErrorEvent, with the cancelable attribute initialized to true, the message attribute initialized to message,
+ // the filename attribute initialized to urlString, the lineno attribute initialized to line, the colno attribute initialized to col,
+ // and the error attribute initialized to errorValue.
+ ErrorEventInit event_init = {};
+ event_init.cancelable = true;
+ event_init.message = message;
+ event_init.filename = url_string;
+ event_init.lineno = line;
+ event_init.colno = col;
+ event_init.error = error_value;
+
+ not_handled = target.dispatch_event(ErrorEvent::create(realm, EventNames::error, event_init));
+
+ // 9. Let target no longer be in error reporting mode.
+ m_error_reporting_mode = false;
+
+ // 10. If notHandled is false, then the error is handled. Otherwise, the error is not handled.
+ if (not_handled) {
+ // When the user agent is to report an exception E, the user agent must report the error for the relevant script,
+ // with the problematic position (line number and column number) in the resource containing the script,
+ // using the global object specified by the script's settings object as the target.
+ // If the error is still not handled after this, then the error may be reported to a developer console.
+ // https://html.spec.whatwg.org/multipage/webappapis.html#report-the-exception
+ report_exception_to_console(e, realm, ErrorInPromise::No);
+ }
+}
+
}
diff --git a/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.h b/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.h
index 5dbdd307e33..2e008ac107c 100644
--- a/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.h
+++ b/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.h
@@ -76,6 +76,8 @@ public:
JS::NonnullGCPtr indexed_db();
+ void report_error(JS::Value e);
+
protected:
void initialize(JS::Realm&);
void visit_edges(JS::Cell::Visitor&);
@@ -114,6 +116,8 @@ private:
JS::GCPtr m_indexed_db;
mutable JS::GCPtr m_supported_entry_types_array;
+
+ bool m_error_reporting_mode { false };
};
}
diff --git a/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.idl b/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.idl
index 36a47862683..6ec57d8596a 100644
--- a/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.idl
+++ b/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.idl
@@ -17,7 +17,8 @@ interface mixin WindowOrWorkerGlobalScope {
readonly attribute boolean isSecureContext;
readonly attribute boolean crossOriginIsolated;
- [FIXME] undefined reportError(any e);
+ // https://html.spec.whatwg.org/multipage/webappapis.html#dom-reporterror
+ undefined reportError(any e);
// base64 utility methods
DOMString btoa(DOMString data);