[WPT] Check worker.onerror message

This CL checks that worker.onerror event's `message` field
contains the original exception's message, "TypeError", etc.

This is a regression test for crbug/590219, where Chromium
set the message to just "Uncaught ".

This CL also refactors `exception-in-onerror.js` and renames it
to `throw.js`, to share it from multiple test files.

Bug: 590219
Change-Id: I7184eba7a9a6a7f08b1ef6eed95bc49adb91fcdd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2368621
Commit-Queue: Hiroshige Hayashizaki <hiroshige@chromium.org>
Reviewed-by: Hiroki Nakagawa <nhiroki@chromium.org>
Reviewed-by: Dominic Farolino <dom@chromium.org>
Reviewed-by: Kenichi Ishibashi <bashi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#804142}
diff --git a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.html b/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.html
index d8aa02a0..5f3999db 100644
--- a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.html
+++ b/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.html
@@ -59,28 +59,28 @@
   const workerOptions = type === 'module' ? {type: 'module'}: {};
 
   const worker1 = new Worker(
-      'exception-in-onerror.js?throw-in-worker-initialization',
+      'throw.js?throw-in-toplevel&throw-in-onerror',
       workerOptions);
   expectErrors(
       worker1,
       'Throw in worker initialization: ' + type,
-      ['Throw in worker initialization', 'Throw in error handler']);
+      ['Throw in toplevel', 'Throw in error handler']);
 
   const worker2 = new Worker(
-      'exception-in-onerror.js?throw-in-setTimeout-function', workerOptions);
+      'throw.js?throw-in-setTimeout-function&throw-in-onerror', workerOptions);
   expectErrors(
       worker2,
       'Throw in setTimeout(function): ' + type,
       ['Throw in setTimeout function', 'Throw in error handler']);
 
   const worker3 = new Worker(
-      'exception-in-onerror.js?throw-in-setTimeout-string', workerOptions);
+      'throw.js?throw-in-setTimeout-string&throw-in-onerror', workerOptions);
   expectErrors(
       worker3,
       'Throw in setTimeout(string): ' + type,
       ['Throw in setTimeout string', 'Throw in error handler']);
 
-  const worker4 = new Worker('exception-in-onerror.js', workerOptions);
+  const worker4 = new Worker('throw.js?throw-in-onerror', workerOptions);
   worker4.postMessage('foo');
   expectErrors(
       worker4,
diff --git a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.js b/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.js
deleted file mode 100644
index 61a95dd..0000000
--- a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.js
+++ /dev/null
@@ -1,25 +0,0 @@
-onerror = function() {
-  throw new Error('Throw in error handler');
-  return false;
-};
-onmessage = function() {
-  throw new Error('Throw in message handler');
-  return false;
-};
-
-if (self.location.href.indexOf(
-        'throw-in-worker-initialization') >= 0) {
-  throw new Error('Throw in worker initialization');
-}
-
-if (self.location.href.indexOf(
-        'throw-in-setTimeout-function') >= 0) {
-  // To test the behavior of setTimeout(), raw setTimeout() is used.
-  setTimeout(() => { throw new Error('Throw in setTimeout function') }, 0);
-}
-
-if (self.location.href.indexOf(
-        'throw-in-setTimeout-string') >= 0) {
-  // To test the behavior of setTimeout(), raw setTimeout() is used.
-  setTimeout("throw new Error('Throw in setTimeout string')", 0);
-}
diff --git a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerGlobalScope/onerror/message-expected.txt b/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerGlobalScope/onerror/message-expected.txt
new file mode 100644
index 0000000..e1f334a0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerGlobalScope/onerror/message-expected.txt
@@ -0,0 +1,43 @@
+This is a testharness.js-based test.
+PASS Throw Error in toplevel: classic: listener
+PASS Throw Error in toplevel: classic: handler
+PASS Throw Error in toplevel: module: listener
+PASS Throw Error in toplevel: module: handler
+FAIL Throw DOMException-TypeError in toplevel: classic: listener assert_regexp_match: e.message should contain the message of the thrown error expected object "/Throw in/" but got "Uncaught "
+FAIL Throw DOMException-TypeError in toplevel: classic: handler assert_regexp_match: e.message should contain the message of the thrown error expected object "/Throw in/" but got "Uncaught "
+FAIL Throw DOMException-TypeError in toplevel: module: listener assert_regexp_match: e.message should contain the message of the thrown error expected object "/Throw in/" but got "Uncaught "
+FAIL Throw DOMException-TypeError in toplevel: module: handler assert_regexp_match: e.message should contain the message of the thrown error expected object "/Throw in/" but got "Uncaught "
+PASS Throw Error in setTimeout-function: classic: listener
+PASS Throw Error in setTimeout-function: classic: handler
+PASS Throw Error in setTimeout-function: module: listener
+PASS Throw Error in setTimeout-function: module: handler
+PASS Throw DOMException-TypeError in setTimeout-function: classic: listener
+PASS Throw DOMException-TypeError in setTimeout-function: classic: handler
+PASS Throw DOMException-TypeError in setTimeout-function: module: listener
+PASS Throw DOMException-TypeError in setTimeout-function: module: handler
+PASS Throw Error in setTimeout-string: classic: listener
+PASS Throw Error in setTimeout-string: classic: handler
+PASS Throw Error in setTimeout-string: module: listener
+PASS Throw Error in setTimeout-string: module: handler
+FAIL Throw DOMException-TypeError in setTimeout-string: classic: listener assert_regexp_match: e.message should contain the message of the thrown error expected object "/Throw in/" but got "Uncaught "
+FAIL Throw DOMException-TypeError in setTimeout-string: classic: handler assert_regexp_match: e.message should contain the message of the thrown error expected object "/Throw in/" but got "Uncaught "
+FAIL Throw DOMException-TypeError in setTimeout-string: module: listener assert_regexp_match: e.message should contain the message of the thrown error expected object "/Throw in/" but got "Uncaught "
+FAIL Throw DOMException-TypeError in setTimeout-string: module: handler assert_regexp_match: e.message should contain the message of the thrown error expected object "/Throw in/" but got "Uncaught "
+PASS Throw Error in onmessage: classic: listener
+PASS Throw Error in onmessage: classic: handler
+PASS Throw Error in onmessage: module: listener
+PASS Throw Error in onmessage: module: handler
+PASS Throw DOMException-TypeError in onmessage: classic: listener
+PASS Throw DOMException-TypeError in onmessage: classic: handler
+PASS Throw DOMException-TypeError in onmessage: module: listener
+PASS Throw DOMException-TypeError in onmessage: module: handler
+PASS Throw Error in onerror: classic: listener
+PASS Throw Error in onerror: classic: handler
+PASS Throw Error in onerror: module: listener
+PASS Throw Error in onerror: module: handler
+PASS Throw DOMException-TypeError in onerror: classic: listener
+PASS Throw DOMException-TypeError in onerror: classic: handler
+PASS Throw DOMException-TypeError in onerror: module: listener
+PASS Throw DOMException-TypeError in onerror: module: handler
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerGlobalScope/onerror/message.html b/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerGlobalScope/onerror/message.html
new file mode 100644
index 0000000..cdb1343
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerGlobalScope/onerror/message.html
@@ -0,0 +1,69 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+// The error's `message` values in Worker error event handlers are tested.
+// While not explicitly specified in the HTML spec, we expect some information
+// about thrown errors (e.g. original message, the string "TypeError", etc.)
+// to appear in the `message`.
+
+function prepareHandler(t, error, expectedCount) {
+  t.step_timeout(() => assert_unreached('timeout'), 2000);
+  let count = 0;
+  return t.step_func(e => {
+      e.preventDefault();
+
+      assert_regexp_match(
+          e.message,
+          /Throw in/,
+          'e.message should contain the message of the thrown error');
+
+      if (error === 'DOMException-TypeError') {
+        assert_regexp_match(e.message, /TypeError/);
+      }
+
+      ++count;
+      if (count >= expectedCount) {
+        t.done();
+      }
+    });
+}
+
+function expectErrors(worker, error, expectedCount, title) {
+  async_test(t => {
+      worker.addEventListener('error',
+                              prepareHandler(t, error, expectedCount));
+    }, title+ ': listener');
+  async_test(t => {
+      worker.onerror = prepareHandler(t, error, expectedCount);
+    }, title + ': handler');
+}
+
+for (const location of ['toplevel',
+                        'setTimeout-function',
+                        'setTimeout-string',
+                        'onmessage',
+                        'onerror']) {
+  for (const error of ['Error', 'DOMException-TypeError']) {
+    for (const type of ['classic', 'module']) {
+      const worker = new Worker(
+          'throw.js?throw-in-' + location + '&error=' + error,
+          {type});
+      let expectedCount = 1;
+      if (location === 'onmessage') {
+        // This makes the worker's message handler to throw an error.
+        worker.postMessage('foo');
+      }
+      if (location === 'onerror') {
+        // This makes the worker's message handler to throw an error,
+        // AND worker's error handler to throw another error.
+        // Therefore we expect two errors here.
+        worker.postMessage('foo');
+        expectedCount = 2;
+      }
+      expectErrors(worker, error, expectedCount,
+          'Throw ' + error + ' in ' + location + ': ' + type);
+    }
+  }
+}
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerGlobalScope/onerror/throw.js b/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerGlobalScope/onerror/throw.js
new file mode 100644
index 0000000..704098a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerGlobalScope/onerror/throw.js
@@ -0,0 +1,34 @@
+const params = new URL(self.location.href).searchParams;
+
+self.createError = (message) => {
+  if (params.get('error') === 'DOMException-TypeError') {
+    return new DOMException(message, 'TypeError');
+  } else {
+    return new Error(message);
+  }
+};
+
+onerror = function() {
+  if (params.has('throw-in-onerror')) {
+    throw createError('Throw in error handler');
+  }
+  return false;
+};
+onmessage = function() {
+  throw createError('Throw in message handler');
+  return false;
+};
+
+if (params.has('throw-in-toplevel')) {
+  throw createError('Throw in toplevel');
+}
+
+// We don't use step_timeout() here, because we have to test the behavior of
+// setTimeout() without wrappers.
+if (params.has('throw-in-setTimeout-function')) {
+  setTimeout(() => { throw createError('Throw in setTimeout function') }, 0);
+}
+
+if (params.has('throw-in-setTimeout-string')) {
+  setTimeout("throw createError('Throw in setTimeout string')", 0);
+}