<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
// 1. Exception is thrown somewhere in a Worker.
//    Various contexts are tested: from worker initialization,
//    from setTimeout, from event handlers, etc.
// 2. WorkerGlobalScope.onerror event handler is called.
//    (i.e. `onerror` in the worker script)
// 3. From the event handler, another exception is thrown.
// 4. Each of Worker.onerror handler (on the parent Document) and
//            Worker error event listener should be called twice:
//    once for each of the exceptions thrown in Step 1 and 2, respectively.
//    (We don't check the ordering of two Worker.onerror calls, because
//    browsers fires them in different orders)

function prepareHandler(t, messages) {
  const fired = {};
  let fired_count = 0;
  t.step_timeout(() => {
    if (fired_count < messages.length) {
      let error_description = 'Worker.onerror not fired for:';
      for (const message of messages) {
        if (!fired[message]) {
          error_description += ' ';
          error_description += message;
        }
      }
      assert_unreached(error_description);
    }
  }, 2000);
  return t.step_func(e => {
      e.preventDefault();
      for (const message of messages) {
        if (!fired[message] && e.message.indexOf(message) >= 0) {
          fired[message] = true;
          ++fired_count;
          if (fired_count === messages.length) {
            // Worker.onerror is fired for all messages.
            t.done();
          }
          return;
        }
      }
      assert_unreached("Unexpected worker.onerror message: " + e.message);
    });
}

function expectErrors(worker, title, messages) {
  async_test(t => {
      worker.addEventListener('error', prepareHandler(t, messages));
    }, title+ ': listener');
  async_test(t => {
      worker.onerror = prepareHandler(t, messages);
    }, title + ': handler');
}

for (const type of ['classic', 'module']) {
  const workerOptions = type === 'module' ? {type: 'module'}: {};

  const worker1 = new Worker(
      'throw.js?throw-in-toplevel&throw-in-onerror',
      workerOptions);
  expectErrors(
      worker1,
      'Throw in worker initialization: ' + type,
      ['Throw in toplevel', 'Throw in error handler']);

  const worker2 = new Worker(
      '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(
      '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('throw.js?throw-in-onerror', workerOptions);
  worker4.postMessage('foo');
  expectErrors(
      worker4,
      'Throw in message handler: ' + type,
      ['Throw in message handler', 'Throw in error handler']);

}
</script>
