<!DOCTYPE html>
<title>Credentials in WebBundle subresource loading</title>
<link
  rel="help"
  href="https://github.com/WICG/webpackage/blob/main/explainers/subresource-loading.md#requests-mode-and-credentials-mode"
/>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/test-helpers.js"></script>
<body>
  <script>
    // In this wpt, we test a request's credential mode, which controls
    // whether UA sends a credential or not to fetch a bundle.

    // If UA sends a credential, check-cookie-and-return-{cross-oriigin}-bundle.py
    // returns a valid format webbundle. Then, a subresource fetch should be successful.
    // Otherwise, a subresource fetch should be rejected.

    setup(() => {
      assert_true(HTMLScriptElement.supports("webbundle"));
    });

    document.cookie = "milk=1; path=/";

    // Make sure to set a cookie for a cross-origin domain from where a cross
    // origin bundle is served.
    const setCookiePromise = fetch(
      "https://{{domains[www1]}}:{{ports[https][0]}}/cookies/resources/set-cookie.py?name=milk&path=/web-bundle/resources/",
      {
        mode: "no-cors",
        credentials: "include",
      }
    );

    const same_origin_bundle = "../resources/check-cookie-and-return-bundle.py";
    const cross_origin_bundle =
      "https://{{domains[www1]}}:{{ports[https][0]}}/web-bundle/resources/check-cookie-and-return-bundle.py?bundle=cross-origin";

    const same_origin_bundle_subresource = "../resources/wbn/root.js";
    const cross_origin_bundle_subresource =
      "https://{{domains[www1]}}:{{ports[https][0]}}/web-bundle/resources/wbn/simple-cross-origin.txt";

    async function assertSubresourceCanBeFetched() {
      const response = await fetch(same_origin_bundle_subresource);
      const text = await response.text();
      assert_equals(text, "export * from './submodule.js';\n");
    }

    async function assertCrossOriginSubresourceCanBeFetched() {
      const response = await fetch(cross_origin_bundle_subresource);
      const text = await response.text();
      assert_equals(text, "hello from simple-cross-origin.txt");
    }

    function createScriptWebBundle(credentials) {
      const options = {};
      if (credentials) {
        options.credentials = credentials;
      }
      return createWebBundleElement(
        same_origin_bundle,
        [same_origin_bundle_subresource],
        options
      );
    }

    function createScriptWebBundleCrossOrigin(credentials) {
      const options = {};
      if (credentials) {
        options.credentials = credentials;
      }
      return createWebBundleElement(
        cross_origin_bundle,
        [cross_origin_bundle_subresource],
        options
      );
    }

    promise_test(async (t) => {
      const script = createScriptWebBundle();
      document.body.append(script);
      t.add_cleanup(() => script.remove());

      await assertSubresourceCanBeFetched();
    }, "The default should send a credential to a same origin bundle");

    promise_test(async (t) => {
      const script = createScriptWebBundle("invalid");
      document.body.append(script);
      t.add_cleanup(() => script.remove());

      await assertSubresourceCanBeFetched();
    }, "An invalid value should send a credential to a same origin bundle");

    promise_test(async (t) => {
      const script = createScriptWebBundle("omit");
      document.body.append(script);
      t.add_cleanup(() => script.remove());

      return promise_rejects_js(
        t,
        TypeError,
        fetch(same_origin_bundle_subresource)
      );
    }, "'omit' should not send a credential to a same origin bundle");

    promise_test(async (t) => {
      const script = createScriptWebBundle("same-origin");
      document.body.append(script);
      t.add_cleanup(() => script.remove());

      await assertSubresourceCanBeFetched();
    }, "'same-origin' should send a credential to a same origin bundle");

    promise_test(async (t) => {
      const script = createScriptWebBundle("include");
      document.body.append(script);
      t.add_cleanup(() => script.remove());

      await assertSubresourceCanBeFetched();
    }, "'include' should send a credential to a same origin bundle");

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

      const script = createScriptWebBundleCrossOrigin("omit");
      document.body.append(script);
      t.add_cleanup(() => script.remove());

      return promise_rejects_js(
        t,
        TypeError,
        fetch(cross_origin_bundle_subresource)
      );
    }, "'omit' should not send a credential to a cross origin bundle");

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

      const script = createScriptWebBundleCrossOrigin("same-origin");
      document.body.append(script);
      t.add_cleanup(() => script.remove());

      return promise_rejects_js(
        t,
        TypeError,
        fetch(cross_origin_bundle_subresource)
      );
    }, "'same-origin' should not send a credential to a cross origin bundle");

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

      const script = createScriptWebBundleCrossOrigin("include");
      document.body.append(script);
      t.add_cleanup(() => script.remove());

      await assertCrossOriginSubresourceCanBeFetched();
    }, "'include' should send a credential to a cross origin bundle");

    promise_test(async (t) => {
      const script = createScriptWebBundleCrossOrigin("invalid");
      document.body.append(script);
      t.add_cleanup(() => script.remove());

      return promise_rejects_js(
        t,
        TypeError,
        fetch(cross_origin_bundle_subresource)
      );
    }, "An invalid value should not send a credential to a cross origin bundle");
  </script>
</body>
