<!doctype html>
<title>vertical-scroll test for touch-action</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/permissions-policy/experimental-features/resources/common.js"></script>
<script src="/permissions-policy/experimental-features/resources/vertical-scroll.js"></script>
<style>
html, body {
  height: 100%;
  width: 100%;
}

iframe {
  width: 90%;
  height: 90%;
  margin: 0;
  padding: 0;
}

.spacer {
  width: 100%;
  height: 100%;
  margin: 100%;
}
</style>
<iframe></iframe>
<br/>
<p>Spacers below to make page scrollable</p>
<br/>
<div class="spacer"></div>
<div class="spacer"></div>
<p> EOF </p>

<script>
  "use strict";

  let url = url_base + "vertical-scroll-touch-block.html";
  let iframeElement = document.querySelector("iframe");

  // Wait for the helper scripts to load.
  promise_test(async() => {
    if (window.input_api_ready)
      return Promise.resolve();
    await new Promise( (r) => {
      window.resolve_on_input_api_ready = r;
    });

  }, "Make sure input injection API is ready.");

  // Sanity-check: Verify we can scroll using the test-API. The <iframe> with no
  // query arguments would not preventDefault() any events.
  promise_test(async() => {
    window.scrollTo(0, 0);
    await loadUrlInIframe(iframeElement, url);

    await inject_scroll("down");
    assert_greater_than(window.scrollY, 0, "Page must have scrolled down.");

    await inject_scroll("right");
    assert_greater_than(window.scrollX, 0, "Page must have scrolled right.");
  }, "Verify that the page normally scrolls.");

  // Enable 'vertical-scroll': Blocking "touchstart" can block scrolling.
  promise_test(async() => {
    window.scrollTo(0, 0);
    setFeatureState(iframeElement, "vertical-scroll", "*");
    await loadUrlInIframe(iframeElement, url);
    await sendMessageAndGetResponse(iframeElement.contentWindow,
                                    {
                                      event_type: "touchstart",
                                      query: "#blocker",
                                      prevent: true
                                    });

    await inject_scroll("down");
    assert_equals(window.scrollY,
                  0,
                  "Main frame must not scroll vertically.");
  }, "Calling 'preventDefault' on 'touchstart' blocks vertical scroll when " +
     " the feature is enabled.");

  // Disable 'vertical-scroll': Blocking "touchstart" cannot block vertical
  // scroll.
  promise_test(async() => {
    window.scrollTo(0, 0);
    setFeatureState(iframeElement, "vertical-scroll", "'none'");
    await loadUrlInIframe(iframeElement, url);
    await sendMessageAndGetResponse(iframeElement.contentWindow,
                                    {
                                      event_type: "touchstart",
                                      query: "#blocker",
                                      prevent: true
                                    });

    await inject_scroll("down");
    assert_greater_than(window.scrollY,
                        0,
                        "Main frame must scroll vertically.");

    // Horizontal scrolling must still be blocked.
    window.scrollTo(0, 0);
    await inject_scroll("right");
    assert_equals(window.scrollX,
                  0,
                  "Main frame must not scroll horizontally.");
  }, "When feature is disabled, calling 'preventDefault' on 'touchstart' does" +
     " not block vertical scroll, but still bocks horizontal scroll.");

  // Enable 'vertical-scroll': Blocking "touchmove" can block scrolling.
  promise_test(async() => {
    // Make sure <window> can scroll both towards right and bottom.
    window.scrollTo(0, 0);
    setFeatureState(iframeElement, "vertical-scroll", "*");
    await loadUrlInIframe(iframeElement, url);
    await sendMessageAndGetResponse(iframeElement.contentWindow,
                                    {
                                      event_type: "touchmove",
                                      query: "#blocker",
                                      prevent: true
                                    });

    await inject_scroll("down");
    assert_equals(window.scrollY,
                  0,
                  "Main frame must not scroll vertically");
  }, "Calling 'preventDefault' on 'touchmove' blocks vertical scroll when " +
     "the feature is enabled.");

  // Disable 'vertical-scroll': Blocking "touchmove" cannot block vertical
  // scroll.
  promise_test(async() => {
    window.scrollTo(0, 0);
    setFeatureState(iframeElement, "vertical-scroll", "'none'");
    await loadUrlInIframe(iframeElement, url);
    await sendMessageAndGetResponse(iframeElement.contentWindow,
                                    {
                                      event_type: "touchmove",
                                      query: "#blocker",
                                      prevent: true
                                    });
    await new Promise((r) => {
      window.setTimeout(r, 100);
    });

    await inject_scroll("down");
    assert_greater_than(window.scrollY,
                        0,
                        "Main frame must scroll vertically.");
  }, "When feature is disabled, calling 'preventDefault' on 'touchmove' does" +
     " not block vertical scroll.");

  // Disable 'vertical-scroll': Add a non-preventing handler, and then a
  // preventing handler and verify vertical scroll is possible and horizontal
  // is blocked.
  promise_test(async() => {
    setFeatureState(iframeElement, "vertical-scroll", "'none'");
    await loadUrlInIframe(iframeElement, url);

    // Add a non-blocking handler.
    await sendMessageAndGetResponse(iframeElement.contentWindow,
                                    {
                                      event_type: "touchstart",
                                      query: "#blocker",
                                      prevent: false
                                    });

    window.scrollTo(0, 0);
    await inject_scroll("down");
    assert_greater_than(window.scrollY, 0, "Page must have scrolled down.");

    window.scrollTo(0, 0);
    await inject_scroll("right");
    assert_greater_than(window.scrollX, 0, "Page must have scrolled right.");

    // Add a blocking handler.
    await sendMessageAndGetResponse(iframeElement.contentWindow,
                                    {
                                      event_type: "touchstart",
                                      query: "#blocker",
                                      prevent: true
                                    });
    window.scrollTo(0, 0);
    await inject_scroll("down");
    assert_greater_than(window.scrollY,
                        0,
                        "Page must have scrolled down (preventing handler).");

    window.scrollTo(0, 0);
    await inject_scroll("right");
    assert_equals(window.scrollX,
                  0,
                  "Page must not have scrolled horizontally.");
  }, "Verify that starting with a non-preventing listener and then switching" +
     " to a preventing one works as intended.");

  // Disable 'vertical-scroll': A preventing 'touchstart' handler does not allow
  // other multi-touch actions such as 'pinch-zoom'.
  promise_test(async() => {
    assert_true(!!window.visualViewport,
                "'visualViewport' is needed for this test.");

    setFeatureState(iframeElement, "vertical-scroll", "'none'");
    await loadUrlInIframe(iframeElement, url);
    await sendMessageAndGetResponse(iframeElement.contentWindow,
                                    {
                                      event_type: "touchstart",
                                      query: "#blocker",
                                      prevent: false
                                    });

    // Sanity check: Pinch zoom in should work since 'touchstart' is not
    // preventing.
    let current_scale_factor = window.visualViewport.scale;
    await inject_zoom("in");
    let new_scale_factor = window.visualViewport.scale;
    assert_greater_than(
        new_scale_factor,
        current_scale_factor,
        "Pinch zoom should work since 'touchstart' is not prevented.");

    // Add a preventing handler and verify pinch zoom is now blocked.
    await sendMessageAndGetResponse(iframeElement.contentWindow,
                                    {
                                      event_type: "touchstart",
                                      query: "#blocker",
                                      prevent: true
                                    });
    current_scale_factor = new_scale_factor;
    await inject_zoom("out");
    new_scale_factor = window.visualViewport.scale;
    assert_equals(
        new_scale_factor,
        current_scale_factor,
        "Pinch zoom must be blocked.");
  }, "Verify that pinch zoom is blocked in frames with 'vertical-scroll' none'" +
     " where 'touchstart' is prevent defaulted.");
</script>
