<!DOCTYPE HTML>
<meta name="timeout" content="long">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="scroll_support.js"></script>
<style>
html {
  height: 3000px;
  width: 3000px;
}
#targetDiv {
  width: 200px;
  height: 200px;
  overflow: scroll;
}

#innerDiv {
  width: 400px;
  height: 400px;
}
</style>

<body style="margin:0" onload=runTest()>
<div id="targetDiv">
  <div id="innerDiv">
  </div>
</div>
</body>
<script>
var element_scrollend_arrived = false;
var document_scrollend_arrived = false;

function onElementScrollEnd(event) {
  assert_false(event.cancelable);
  assert_false(event.bubbles);
  element_scrollend_arrived = true;
}

function onDocumentScrollEnd(event) {
  assert_false(event.cancelable);
  // scrollend events are bubbled when the target node is document.
  assert_true(event.bubbles);
  document_scrollend_arrived = true;
}

function callScrollFunction([scrollTarget, scrollFunction, args]) {
  scrollTarget[scrollFunction](args);
}

function runTest() {
  let root_element = document.scrollingElement;
  let target_div = document.getElementById("targetDiv");

  promise_test (async (t) => {
    await waitForCompositorCommit();
    target_div.addEventListener("scrollend", onElementScrollEnd);
    document.addEventListener("scrollend", onDocumentScrollEnd);

    let test_cases = [
      [target_div, 200, 200, [target_div, "scrollTo", { top: 200, left: 200, behavior: "auto" }]],
      [target_div, 0, 0, [target_div, "scrollTo", { top: 0, left: 0, behavior: "smooth" }]],
      [root_element, 200, 200, [root_element, "scrollTo", { top: 200, left: 200, behavior: "auto" }]],
      [root_element, 0, 0, [root_element, "scrollTo", { top: 0, left: 0, behavior: "smooth" }]],
      [target_div, 200, 200, [target_div, "scrollBy", { top: 200, left: 200, behavior: "auto" }]],
      [target_div, 0, 0, [target_div, "scrollBy", { top: -200, left: -200, behavior: "smooth" }]],
      [root_element, 200, 200, [root_element, "scrollBy", { top: 200, left: 200, behavior: "auto" }]],
      [root_element, 0, 0, [root_element, "scrollBy", { top: -200, left: -200, behavior: "smooth" }]]
    ];

    for(i = 0; i < test_cases.length; i++) {
      let t = test_cases[i];
      let target = t[0];
      let expected_x = t[1];
      let expected_y = t[2];
      let scroll_datas = t[3];

      callScrollFunction(scroll_datas);
      await waitFor(() => { return element_scrollend_arrived || document_scrollend_arrived; }, target.tagName + "." + scroll_datas[1] + " did not receive scrollend event.");
      if (target == root_element)
        assert_false(element_scrollend_arrived);
      else
        assert_false(document_scrollend_arrived);
      assert_equals(target.scrollLeft, expected_x, target.tagName + "." + scroll_datas[1] + " scrollLeft");
      assert_equals(target.scrollTop, expected_y, target.tagName + "." + scroll_datas[1] + " scrollTop");

      element_scrollend_arrived = false;
      document_scrollend_arrived = false;
    }
  }, "Tests scrollend event for calling scroll functions.");

  promise_test(async (t) => {
    await waitForCompositorCommit();

    let test_cases = [
      [target_div, "scrollTop"],
      [target_div, "scrollLeft"],
      [root_element, "scrollTop"],
      [root_element, "scrollLeft"]
    ];
    for (i = 0; i < test_cases.length; i++) {
      let t = test_cases[i];
      let target = t[0];
      let attribute = t[1];
      let position = 200;

      target.style.scrollBehavior = "smooth";
      target[attribute] = position;
      await waitFor(() => { return element_scrollend_arrived || document_scrollend_arrived; }, target.tagName + "." + attribute + " did not receive scrollend event.");
      if (target == root_element)
        assert_false(element_scrollend_arrived);
      else
        assert_false(document_scrollend_arrived);
      assert_equals(target[attribute], position, target.tagName + "." + attribute + " ");
      element_scrollend_arrived = false;
      document_scrollend_arrived = false;

      await waitForCompositorCommit();
      target.style.scrollBehavior = "auto";
      target[attribute] = 0;
      await waitFor(() => { return element_scrollend_arrived || document_scrollend_arrived; }, target.tagName + "." + attribute + " did not receive scrollend event.");
      if (target == root_element)
        assert_false(element_scrollend_arrived);
      else
        assert_false(document_scrollend_arrived);
      assert_equals(target[attribute], 0, target.tagName + "." + attribute + " ");
      element_scrollend_arrived = false;
      document_scrollend_arrived = false;
    }
  }, "Tests scrollend event for changing scroll attributes.");
}
</script>
