<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="resources/helpers.js"></script>

<div id="d" style="height: 100px; width: 100px;"></div>
<script>
promise_test(async t => {
  const events = [];
  const freeWatcher = createRecordingCloseWatcher(t, events, "freeWatcher");

  await test_driver.bless("call close()", () => freeWatcher.close());

  assert_array_equals(events, ["freeWatcher cancel", "freeWatcher close"]);
}, "CloseWatchers created without user activation, but close()d via user activation, fires cancel");

promise_test(async t => {
  const events = [];
  const freeWatcher = createRecordingCloseWatcher(t, events, "freeWatcher");
  freeWatcher.addEventListener("cancel", e => e.preventDefault());

  await test_driver.bless("call close()", () => freeWatcher.close());

  assert_array_equals(events, ["freeWatcher cancel"]);
}, "CloseWatchers created without user activation, but close()d via user activation, fires cancel, which can be preventDefault()ed");

promise_test(async t => {
  const events = [];
  const freeWatcher = createRecordingCloseWatcher(t, events, "freeWatcher");

  await test_driver.bless("grant user activation", () => sendCloseSignal());

  assert_array_equals(events, ["freeWatcher cancel", "freeWatcher close"]);
}, "CloseWatchers created without user activation, but closed via a close signal after user activation, fires cancel");

promise_test(async t => {
  const events = [];
  const freeWatcher = createRecordingCloseWatcher(t, events, "freeWatcher");
  freeWatcher.addEventListener("cancel", e => e.preventDefault());

  await test_driver.bless("grant user activation", () => sendCloseSignal());

  assert_array_equals(events, ["freeWatcher cancel"]);
}, "CloseWatchers created without user activation, but closed via a close signal after user activation, fires cancel, which can be preventDefault()ed");

promise_test(async t => {
  const events = [];
  createRecordingCloseWatcher(t, events, "freeWatcher");
  createRecordingCloseWatcher(t, events, "watcher1");
  createRecordingCloseWatcher(t, events, "watcher2");

  await sendCloseSignal();
  assert_array_equals(events, ["watcher2 close", "watcher1 close", "freeWatcher close"]);
}, "Multiple CloseWatchers created without user activation close together (with no cancel)");

promise_test(async t => {
  const events = [];
  createRecordingCloseWatcher(t, events, "freeWatcher");
  await createBlessedRecordingCloseWatcher(t, events, "activationWatcher");

  await sendCloseSignal();
  assert_array_equals(events, ["activationWatcher close"]);

  await sendCloseSignal();
  assert_array_equals(events, ["activationWatcher close", "freeWatcher close"]);
}, "Creating a CloseWatcher from user activation keeps it separate from the free CloseWatcher, but they don't fire cancel");

promise_test(async t => {
  const events = [];
  const freeWatcher = createRecordingCloseWatcher(t, events, "freeWatcher");
  const activationWatcher = await createBlessedRecordingCloseWatcher(t, events, "activationWatcher");

  await test_driver.bless("call activationWatcher.close()", () => activationWatcher.close());
  assert_array_equals(events, ["activationWatcher cancel", "activationWatcher close"]);

  await test_driver.bless("call freeWatcher.close()", () => freeWatcher.close());
  assert_array_equals(events, ["activationWatcher cancel", "activationWatcher close", "freeWatcher cancel", "freeWatcher close"]);
}, "Creating a CloseWatcher from user activation, and close()ing CloseWatchers with user activation, fires cancel");

promise_test(async t => {
  const events = [];
  const freeWatcher = createRecordingCloseWatcher(t, events, "freeWatcher");
  const activationWatcher = await createBlessedRecordingCloseWatcher(t, events, "activationWatcher");

  await test_driver.bless("grant user activation", () => sendCloseSignal());
  assert_array_equals(events, ["activationWatcher cancel", "activationWatcher close"]);

  await test_driver.bless("grant user activation", () => sendCloseSignal());
  assert_array_equals(events, ["activationWatcher cancel", "activationWatcher close", "freeWatcher cancel", "freeWatcher close"]);
}, "Creating a CloseWatcher from user activation, and closing CloseWatchers with a close signal after user activation, fires cancel");

promise_test(async t => {
  const events = [];
  createRecordingCloseWatcher(t, events, "freeWatcher");
  await createBlessedRecordingCloseWatcher(t, events, "activationWatcher1");
  await createBlessedRecordingCloseWatcher(t, events, "activationWatcher2");

  await sendCloseSignal();
  assert_array_equals(events, ["activationWatcher2 close"]);

  await sendCloseSignal();
  assert_array_equals(events, ["activationWatcher2 close", "activationWatcher1 close"]);
}, "Multiple CloseWatchers created with user activation close in reverse order");

promise_test(async t => {
  const events = [];
  createRecordingCloseWatcher(t, events, "freeWatcher");
  await createBlessedRecordingCloseWatcher(t, events, "activationWatcher1");
  await createBlessedRecordingCloseWatcher(t, events, "activationWatcher2");
  await createBlessedRecordingCloseWatcher(t, events, "activationWatcher3");
  createRecordingCloseWatcher(t, events, "watcher4");

  await sendCloseSignal();
  assert_array_equals(events, ["watcher4 close", "activationWatcher3 close"]);

  await sendCloseSignal();
  assert_array_equals(events, ["watcher4 close", "activationWatcher3 close", "activationWatcher2 close"]);

  await sendCloseSignal();
  assert_array_equals(events, ["watcher4 close", "activationWatcher3 close", "activationWatcher2 close", "activationWatcher1 close"]);

  await sendCloseSignal();
  assert_array_equals(events, ["watcher4 close", "activationWatcher3 close", "activationWatcher2 close", "activationWatcher1 close", "freeWatcher close"]);
}, "3 user activations let you have 3 + 1 = 4 ungrouped close watchers/0 cancel events");

promise_test(async t => {
  const events = [];
  const freeWatcher = createRecordingCloseWatcher(t, events, "freeWatcher");
  const activationWatcher1 = await createBlessedRecordingCloseWatcher(t, events, "activationWatcher1");
  activationWatcher1.addEventListener("cancel", e => e.preventDefault());

  await test_driver.bless("call activationWatcher1.close()", () => activationWatcher1.close());
  assert_array_equals(events, ["activationWatcher1 cancel"]);

  // This time we go straight to close, without a second cancel.
  activationWatcher1.close();
  assert_array_equals(events, ["activationWatcher1 cancel", "activationWatcher1 close"]);

  freeWatcher.close();
  assert_array_equals(events, ["activationWatcher1 cancel", "activationWatcher1 close", "freeWatcher close"]);
}, "3 user activations let you have 2 close watchers with 1 cancel event, even if the first cancel event is prevented");

promise_test(async t => {
  const events = [];
  const freeWatcher1 = createRecordingCloseWatcher(t, events, "freeWatcher1");

  freeWatcher1.destroy();
  assert_array_equals(events, []);

  const freeWatcher2 = createRecordingCloseWatcher(t, events, "freeWatcher2");

  await sendCloseSignal();
  assert_array_equals(events, ["freeWatcher2 close"]);
}, "destroy()ing the free CloseWatcher allows a new free one to be created without user activation, and it receives the close signal");

promise_test(async t => {
  const events = [];
  const freeWatcher1 = createRecordingCloseWatcher(t, events, "freeWatcher1");

  freeWatcher1.close();
  assert_array_equals(events, ["freeWatcher1 close"]);

  const freeWatcher2 = createRecordingCloseWatcher(t, events, "freeWatcher2");

  await sendCloseSignal();
  assert_array_equals(events, ["freeWatcher1 close", "freeWatcher2 close"]);
}, "close()ing the free CloseWatcher allows a new free one to be created without user activation, and it receives the close signal");

promise_test(async t => {
  const events = [];
  const freeWatcher1 = createRecordingCloseWatcher(t, events, "freeWatcher1");

  await sendCloseSignal();
  assert_array_equals(events, ["freeWatcher1 close"]);

  const freeWatcher2 = createRecordingCloseWatcher(t, events, "freeWatcher2");

  await sendCloseSignal();
  assert_array_equals(events, ["freeWatcher1 close", "freeWatcher2 close"]);
}, "closing the free CloseWatcher via a close signal allows a new free one to be created without user activation, and it receives a second close signal");

promise_test(async t => {
  const events = [];
  const activationWatcher = await createBlessedRecordingCloseWatcher(t, events, "activationWatcher");
  const freeWatcher = createRecordingCloseWatcher(t, events, "freeWatcher");

  await sendCloseSignal();
  assert_array_equals(events, ["freeWatcher close"]);

  await sendCloseSignal();
  assert_array_equals(events, ["freeWatcher close", "activationWatcher close"]);
}, "The second watcher can be the free watcher, if the first is created with user activation");

promise_test(async t => {
  const events = [];
  const activationWatcher1 = await createBlessedRecordingCloseWatcher(t, events, "activationWatcher1");
  const activationWatcher2 = await createBlessedRecordingCloseWatcher(t, events, "activationWatcher2");
  const freeWatcher = createRecordingCloseWatcher(t, events, "freeWatcher");

  await sendCloseSignal();
  assert_array_equals(events, ["freeWatcher close"]);

  await sendCloseSignal();
  assert_array_equals(events, ["freeWatcher close", "activationWatcher2 close"]);

  await sendCloseSignal();
  assert_array_equals(events, ["freeWatcher close", "activationWatcher2 close", "activationWatcher1 close"]);
}, "The third watcher can be the free watcher, if the first two are created with user activation");
</script>
