<!doctype html>
<title>Synthetic click event "magic"</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id=log></div>
<div id=dump style=display:none></div>
<script>
var dump = document.getElementById("dump")

async_test(function(t) {
  var input = document.createElement("input")
  input.type = "checkbox"
  dump.appendChild(input)
  input.onclick = t.step_func_done(function() {
    assert_true(input.checked)
  })
  input.click()
}, "basic with click()")

async_test(function(t) {
  var input = document.createElement("input")
  input.type = "checkbox"
  dump.appendChild(input)
  input.onclick = t.step_func_done(function() {
    assert_true(input.checked)
  })
  input.dispatchEvent(new MouseEvent("click", {bubbles:true})) // equivalent to the above
}, "basic with dispatchEvent()")

async_test(function(t) {
  var input = document.createElement("input")
  input.type = "checkbox"
  dump.appendChild(input)
  input.onclick = t.step_func_done(function() {
    assert_false(input.checked)
  })
  input.dispatchEvent(new Event("click", {bubbles:true})) // no MouseEvent
}, "basic with wrong event class")

async_test(function(t) {
  var input = document.createElement("input")
  input.type = "checkbox"
  dump.appendChild(input)
  var child = input.appendChild(new Text("does not matter"))
  child.dispatchEvent(new MouseEvent("click")) // does not bubble
  assert_false(input.checked)
  t.done()
}, "look at parents only when event bubbles")

async_test(function(t) {
  var input = document.createElement("input")
  input.type = "checkbox"
  dump.appendChild(input)
  input.onclick = t.step_func_done(function() {
    assert_true(input.checked)
  })
  var child = input.appendChild(new Text("does not matter"))
  child.dispatchEvent(new MouseEvent("click", {bubbles:true}))
}, "look at parents when event bubbles")

async_test(function(t) {
  var input = document.createElement("input")
  input.type = "checkbox"
  dump.appendChild(input)
  input.onclick = t.step_func(function() {
    assert_false(input.checked, "input pre-click must not be triggered")
  })
  var child = input.appendChild(document.createElement("input"))
  child.type = "checkbox"
  child.onclick = t.step_func(function() {
    assert_true(child.checked, "child pre-click must be triggered")
  })
  child.dispatchEvent(new MouseEvent("click", {bubbles:true}))
  t.done()
}, "pick the first with activation behavior <input type=checkbox>")

async_test(function(t) { // as above with <a>
  window.hrefComplete = t.step_func(function(a) {
    assert_equals(a, 'child');
    t.done();
  });
  var link = document.createElement("a")
  link.href = "javascript:hrefComplete('link')" // must not be triggered
  dump.appendChild(link)
  var child = link.appendChild(document.createElement("a"))
  child.href = "javascript:hrefComplete('child')"
  child.dispatchEvent(new MouseEvent("click", {bubbles:true}))
}, "pick the first with activation behavior <a href>")

async_test(function(t) {
  var input = document.createElement("input")
  input.type = "radio"
  dump.appendChild(input)
  input.onclick = t.step_func(function() {
    assert_false(input.checked, "input pre-click must not be triggered")
  })
  var child = input.appendChild(document.createElement("input"))
  child.type = "radio"
  child.onclick = t.step_func(function() {
    assert_true(child.checked, "child pre-click must be triggered")
  })
  child.dispatchEvent(new MouseEvent("click", {bubbles:true}))
  t.done()
}, "pick the first with activation behavior <input type=radio>")

async_test(function(t) {
  var input = document.createElement("input")
  input.type = "checkbox"
  dump.appendChild(input)
  var clickEvent = new MouseEvent("click")
  input.onchange = t.step_func_done(function() {
    assert_false(clickEvent.defaultPrevented)
    assert_true(clickEvent.returnValue)
    assert_equals(clickEvent.eventPhase, 0)
    assert_equals(clickEvent.currentTarget, null)
    assert_equals(clickEvent.target, input)
    assert_equals(clickEvent.srcElement, input)
    assert_equals(clickEvent.composedPath().length, 0)
  })
  input.dispatchEvent(clickEvent)
}, "event state during post-click handling")

async_test(function(t) {
  var input = document.createElement("input")
  input.type = "checkbox"
  dump.appendChild(input)
  var clickEvent = new MouseEvent("click")
  var finalTarget = document.createElement("doesnotmatter")
  finalTarget.onclick = t.step_func_done(function() {
    assert_equals(clickEvent.target, finalTarget)
    assert_equals(clickEvent.srcElement, finalTarget)
  })
  input.onchange = t.step_func(function() {
    finalTarget.dispatchEvent(clickEvent)
  })
  input.dispatchEvent(clickEvent)
}, "redispatch during post-click handling")

async_test(function(t) {
  var input = document.createElement("input")
  input.type = "checkbox"
  dump.appendChild(input)
  var child = input.appendChild(document.createElement("input"))
  child.type = "checkbox"
  child.disabled = true
  child.click()
  assert_false(input.checked)
  assert_false(child.checked)
  t.done()
}, "disabled checkbox still has activation behavior")

async_test(function(t) {
  var state = "start"

  var form = document.createElement("form")
  form.onsubmit = t.step_func(() => {
    if(state == "start" || state == "checkbox") {
      state = "failure"
    } else if(state == "form") {
      state = "done"
    }
    return false
  })
  dump.appendChild(form)
  var button = form.appendChild(document.createElement("button"))
  button.type = "submit"
  var checkbox = button.appendChild(document.createElement("input"))
  checkbox.type = "checkbox"
  checkbox.onclick = t.step_func(() => {
    if(state == "start") {
      assert_unreached()
    } else if(state == "checkbox") {
      assert_true(checkbox.checked)
    }
  })
  checkbox.disabled = true
  checkbox.click()
  assert_equals(state, "start")

  state = "checkbox"
  checkbox.disabled = false
  checkbox.click()
  assert_equals(state, "checkbox")

  state = "form"
  button.click()
  assert_equals(state, "done")

  t.done()
}, "disabled checkbox still has activation behavior, part 2")

async_test(function(t) {
  var state = "start"

  var form = document.createElement("form")
  form.onsubmit = t.step_func(() => {
    if(state == "start" || state == "radio") {
      state = "failure"
    } else if(state == "form") {
      state = "done"
    }
    return false
  })
  dump.appendChild(form)
  var button = form.appendChild(document.createElement("button"))
  button.type = "submit"
  var radio = button.appendChild(document.createElement("input"))
  radio.type = "radio"
  radio.onclick = t.step_func(() => {
    if(state == "start") {
      assert_unreached()
    } else if(state == "radio") {
      assert_true(radio.checked)
    }
  })
  radio.disabled = true
  radio.click()
  assert_equals(state, "start")

  state = "radio"
  radio.disabled = false
  radio.click()
  assert_equals(state, "radio")

  state = "form"
  button.click()
  assert_equals(state, "done")

  t.done()
}, "disabled radio still has activation behavior")

async_test(function(t) {
  var input = document.createElement("input")
  input.type = "checkbox"
  input.onclick = t.step_func_done(function() {
    assert_true(input.checked)
  })
  input.click()
}, "disconnected checkbox should be checked")

async_test(function(t) {
  var input = document.createElement("input")
  input.type = "radio"
  input.onclick = t.step_func_done(function() {
    assert_true(input.checked)
  })
  input.click()
}, "disconnected radio should be checked")

async_test(t => {
  const input = document.createElement('input');
  input.type = 'checkbox';
  input.onclick = t.step_func_done(() => {
    assert_true(input.checked);
  });
  input.dispatchEvent(new MouseEvent('click'));
}, `disconnected checkbox should be checked from dispatchEvent(new MouseEvent('click'))`);

async_test(t => {
  const input = document.createElement('input');
  input.type = 'radio';
  input.onclick = t.step_func_done(() => {
    assert_true(input.checked);
  });
  input.dispatchEvent(new MouseEvent('click'));
}, `disconnected radio should be checked from dispatchEvent(new MouseEvent('click'))`);

test(() => {
  const input = document.createElement("input");
  input.type = "checkbox";
  input.disabled = true;
  input.dispatchEvent(new MouseEvent("click"));
  assert_true(input.checked);
}, `disabled checkbox should be checked from dispatchEvent(new MouseEvent("click"))`);

test(() => {
  const input = document.createElement("input");
  input.type = "radio";
  input.disabled = true;
  input.dispatchEvent(new MouseEvent("click"));
  assert_true(input.checked);
}, `disabled radio should be checked from dispatchEvent(new MouseEvent("click"))`);

async_test(t => {
  const input = document.createElement("input");
  input.type = "checkbox";
  input.disabled = true;
  input.onclick = t.step_func_done();
  input.dispatchEvent(new MouseEvent("click"));
}, `disabled checkbox should fire onclick`);

async_test(t => {
  const input = document.createElement("input");
  input.type = "radio";
  input.disabled = true;
  input.onclick = t.step_func_done();
  input.dispatchEvent(new MouseEvent("click"));
}, `disabled radio should fire onclick`);

async_test(t => {
  const input = document.createElement("input");
  input.type = "checkbox";
  input.disabled = true;
  input.onclick = t.step_func(ev => {
    assert_true(input.checked);
    ev.preventDefault();
    queueMicrotask(t.step_func_done(() => {
      assert_false(input.checked);
    }));
  });
  input.dispatchEvent(new MouseEvent("click", { cancelable: true }));
}, `disabled checkbox should get legacy-canceled-activation behavior`);

async_test(t => {
  const input = document.createElement("input");
  input.type = "radio";
  input.disabled = true;
  input.onclick = t.step_func(ev => {
    assert_true(input.checked);
    ev.preventDefault();
    queueMicrotask(t.step_func_done(() => {
      assert_false(input.checked);
    }));
  });
  input.dispatchEvent(new MouseEvent("click", { cancelable: true }));
}, `disabled radio should get legacy-canceled-activation behavior`);

test(t => {
  const input = document.createElement("input");
  input.type = "checkbox";
  input.disabled = true;
  const ev = new MouseEvent("click", { cancelable: true });
  ev.preventDefault();
  input.dispatchEvent(ev);
  assert_false(input.checked);
}, `disabled checkbox should get legacy-canceled-activation behavior 2`);

test(t => {
  const input = document.createElement("input");
  input.type = "radio";
  input.disabled = true;
  const ev = new MouseEvent("click", { cancelable: true });
  ev.preventDefault();
  input.dispatchEvent(ev);
  assert_false(input.checked);
}, `disabled radio should get legacy-canceled-activation behavior 2`);

for (const type of ["checkbox", "radio"]) {
  for (const handler of ["oninput", "onchange"]) {
    async_test(t => {
      const input = document.createElement("input");
      input.type = type;
      input.onclick = t.step_func(ev => {
        input.disabled = true;
      });
      input[handler] = t.step_func(ev => {
        assert_equals(input.checked, true);
        t.done();
      });
      dump.append(input);
      input.click();
    }, `disabling ${type} in onclick listener shouldn't suppress ${handler}`);
  }
}

async_test(function(t) {
  var form = document.createElement("form")
  var didSubmit = false
  form.onsubmit = t.step_func(() => {
    didSubmit = true
    return false
  })
  var input = form.appendChild(document.createElement("input"))
  input.type = "submit"
  input.click()
  assert_false(didSubmit)
  t.done()
}, "disconnected form should not submit")

async_test(t => {
  const form = document.createElement("form");
  form.onsubmit = t.step_func(ev => {
    ev.preventDefault();
    assert_unreached("The form is unexpectedly submitted.");
  });
  dump.append(form);
  const input = form.appendChild(document.createElement("input"));
  input.type = "submit"
  input.disabled = true;
  input.dispatchEvent(new MouseEvent("click", { cancelable: true }));
  t.done();
}, "disabled submit button should not activate");

async_test(t => {
  const form = document.createElement("form");
  form.onsubmit = t.step_func(ev => {
    ev.preventDefault();
    assert_unreached("The form is unexpectedly submitted.");
  });
  dump.append(form);
  const input = form.appendChild(document.createElement("input"));
  input.onclick = t.step_func(() => {
    input.disabled = true;
  });
  input.type = "submit"
  input.dispatchEvent(new MouseEvent("click", { cancelable: true }));
  t.done();
}, "submit button should not activate if the event listener disables it");

async_test(t => {
  const form = document.createElement("form");
  form.onsubmit = t.step_func(ev => {
    ev.preventDefault();
    assert_unreached("The form is unexpectedly submitted.");
  });
  dump.append(form);
  const input = form.appendChild(document.createElement("input"));
  input.onclick = t.step_func(() => {
    input.type = "submit"
    input.disabled = true;
  });
  input.click();
  t.done();
}, "submit button that morphed from checkbox should not activate");
</script>
