<!DOCTYPE html>
<title>Service Worker: Registration update()</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/testharness-helpers.js"></script>
<script src="resources/test-helpers.sub.js"></script>
<script>
promise_test(function(t) {
    var scope = 'resources/simple.txt';
    var worker_url = 'resources/update-worker.py';
    var expected_url = normalizeURL(worker_url);
    var registration;
    var iframe;
    return service_worker_unregister_and_register(t, worker_url, scope)
      .then(function(r) {
          registration = r;
          return wait_for_state(t, registration.installing, 'activated');
        })
      .then(function() {
          assert_equals(registration.installing, null,
                        'installing should be null in the initial state.');
          assert_equals(registration.waiting, null,
                        'waiting should be null in the initial state.');
          assert_equals(registration.active.scriptURL, expected_url,
                        'active should exist in the initial state.');
          // A new worker (generated by update-worker.py) should be found.
          // The returned promise should resolve when a new worker script is
          // fetched and starts installing.
          return Promise.all([registration.update(),
                              wait_for_update(t, registration)]);
        })
      .then(function() {
          assert_equals(registration.installing.scriptURL, expected_url,
                        'new installing should be set after update resolves.');
          assert_equals(registration.waiting, null,
                        'waiting should still be null after update resolves.');
          assert_equals(registration.active.scriptURL, expected_url,
                        'active should still exist after update found.');
          return wait_for_state(t, registration.installing, 'installed');
        })
      .then(function() {
          assert_equals(registration.installing, null,
                        'installing should be null after installing.');
          if (registration.waiting) {
            assert_equals(registration.waiting.scriptURL, expected_url,
                          'waiting should be set after installing.');
            assert_equals(registration.active.scriptURL, expected_url,
                          'active should still exist after installing.');
            return wait_for_state(t, registration.waiting, 'activated');
          }
        })
      .then(function() {
          assert_equals(registration.installing, null,
                        'installing should be null after activated.');
          assert_equals(registration.waiting, null,
                        'waiting should be null after activated.');
          assert_equals(registration.active.scriptURL, expected_url,
                        'new worker should be promoted to active.');
        })
      .then(function() {
          // A new worker(generated by update-worker.py) should be found.
          // The returned promise should reject as update-worker.py sets the
          // mimetype to a disallowed value for this attempt.
          return registration.update();
        })
      .then(
        function() { assert_unreached("update() should reject."); },
        function(e) {
          assert_throws('SecurityError', function() { throw e; },
                        'Using a disallowed mimetype should make update() ' +
                        'promise reject with a SecurityError.');
          assert_equals(registration.active.scriptURL, expected_url,
                        'active should still exist after update failure.');

          // A new worker(generated by update-worker.py) should be found.
          // The returned promise should reject as update-worker.py returns
          // a worker script with a syntax error.
          return registration.update();
        })
      .then(
        function() { assert_unreached("update() should reject."); },
        function(e) {
          assert_throws({name: 'TypeError'}, function () { throw e; },
                        'A script syntax error should make update() ' +
                        'promise reject with a TypeError.');
          assert_equals(registration.active.scriptURL, expected_url,
                        'active should still exist after update failure.');

          // A new worker(generated by update-worker.py) should be found.
          // The returned promise should not reject, even though
          // update-worker.py returns a worker script that throws in the
          // install event handler.
          return Promise.all([registration.update(),
                              wait_for_update(t, registration)]);
        })
      .then(function() {
          assert_equals(registration.installing.scriptURL, expected_url,
                        'new installing should be set after update resolves.');
          assert_equals(registration.waiting, null,
                        'waiting should be null after activated.');
          assert_equals(registration.active.scriptURL, expected_url,
                        'active should still exist after update found.');

          // We need to hold a client alive so that unregister() below doesn't
          // remove the registration before update() has had a chance to look
          // at the pending uninstall flag.
          return with_iframe(scope);
        })
      .then(function(frame) {
          iframe = frame;

          return assert_promise_rejects(
              Promise.all([registration.unregister(), registration.update()]),
              new TypeError(),
              'Calling update() while the uninstalling flag is set ' +
              'should return a promise that rejects with a TypeError.');
        })
      .then(function() {
        iframe.remove();
        return t.done();
        });
  }, 'Update a registration.');
</script>