<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1389418
-->
<head>
  <meta charset="utf-8">
  <title>Test for PaymentRequest API payment method identifier validation</title>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
  <script src="/tests/SimpleTest/SimpleTest.js"></script>
  <script type="application/javascript">

  "use strict";
  SimpleTest.waitForExplicitFinish();

  var gUrl = SimpleTest.getTestFileURL('PMIValidationChromeScript.js');
  var gScript = SpecialPowers.loadChromeScript(gUrl);

  function testFailHandler(message) {
    ok(false, message);
  }
  gScript.addMessageListener("test-fail", testFailHandler);

  const defaultMethods = [{
    supportedMethods: "basic-card",
  }];

  const defaultDetails = {
    total: {
      label: "total",
      amount: {
        currency: "usd",
        value: "1.00",
      },
    },
  };

  const validPMIs = [
    "https://wpt",
    "https://wpt.fyi/",
    "https://wpt.fyi/payment",
    "https://wpt.fyi/payment-request",
    "https://wpt.fyi/payment-request?",
    "https://wpt.fyi/payment-request?this=is",
    "https://wpt.fyi/payment-request?this=is&totally",
    "https://wpt.fyi:443/payment-request?this=is&totally",
    "https://wpt.fyi:443/payment-request?this=is&totally#fine",
    "https://:@wpt.fyi:443/payment-request?this=is&totally#👍",
    " \thttps://wpt\n ",
    "https://xn--c1yn36f",
    "https://點看",
    "e",
    "n6jzof05mk2g4lhxr-u-q-w1-c-i-pa-ty-bdvs9-ho-ae7-p-md8-s-wq3-h-qd-e-q-sa",
    "a-b-q-n-s-pw0",
    "m-u",
    "s-l5",
    "k9-f",
    "m-l",
    "u4-n-t",
    "i488jh6-g18-fck-yb-v7-i",
    "x-x-t-t-c34-o",
    "basic-card",
  ];

  const invalidPMIs = [
    "https://:password@example.com",
    "https://username@example.com",
    "https://username:password@example.com/pay",
    "http://username:password@example.com/pay",
    "https://:@example.com:100000000/pay",
    "https://foo.com:100000000/pay",
    "basic-💳",
    "not-https://wpt.fyi/payment-request",
    "../realitive/url",
    "/absolute/../path?",
    "https://",
    "¡basic-*-card!",
    "Basic-Card",
    "0",
    "-",
    "--",
    "a--b",
    "-a--b",
    "a-b-",
    "0-",
    "0-a",
    "a0--",
    "A-",
    "A-B",
    "A-b",
    "a-0",
    "a-0b",
    " a-b",
    "\t\na-b",
    "a-b ",
    "a-b\n\t",
  ];

  function testWithValidPMIs() {
    return new Promise((resolve, reject) => {
      for (const validPMI of validPMIs) {
        try {
          const validMethods = [{supportedMethods: validPMI},];
          const payRequest = new PaymentRequest(validMethods, defaultDetails);
          resolve();
        } catch (e) {
          ok(false, "Unexpected error '" + e.name + "'.");
          resolve();
        }
      }
    });
  }

  function testWithInvalidPMIs() {
    return new Promise((resolve, reject) => {
      for (const invalidPMI of invalidPMIs) {
        try {
          const invalidMethods = [{supportedMethods: invalidPMI},];
          const payRequest = new PaymentRequest(invalidMethods, defaultDetails);
          ok(false, "Expected throw 'RangeError', but got resolved");
          resolve();
        } catch (e) {
          is(e.name, "RangeError", "Expected 'RangeError'.");
          resolve();
        }
      }
    });
  }

  function testUpdateWithValidPMI() {
    const handler = SpecialPowers.getDOMWindowUtils(window).setHandlingUserInput(true);

    gScript.sendAsyncMessage("set-ui-service");
    return new Promise((resolve, reject) => {
      const payRequest = new PaymentRequest(defaultMethods, defaultDetails);
      payRequest.addEventListener("shippingoptionchange", event => {
        const validDetails = {
          total: {
            label: "total",
            amount: {
              currency: "USD",
              value: "1.00",
            },
          },
          modifiers: [{
            supportedMethods: "https://example.com",
            total: {
              label: "total",
              amount: {
                currency: "USD",
                value: "1.00",
              },
            }
          },],
        }
        event.updateWith(validDetails);
      });
      payRequest.show().then((response) => {
        response.complete("success").then(() => {
          resolve();
        }).catch((e) => {
          ok(false, "Unexpected error '" + e.name + "'.");
          resolve();
        });
      }).catch((e) => {
        ok(false, "Unexpected error '" + e.name + "'.");
        resolve();
      }).finally(handler.destruct);
    });
  }

  function testUpdateWithInvalidPMI() {
    const handler = SpecialPowers.getDOMWindowUtils(window).setHandlingUserInput(true);

    gScript.sendAsyncMessage("set-ui-service");
    return new Promise((resolve, reject) => {
      const payRequest = new PaymentRequest(defaultMethods, defaultDetails);
      payRequest.addEventListener("shippingoptionchange", event => {
        const invalidDetails = {
          total: {
            label: "total",
            amount: {
              currency: "USD",
              value: "1.00",
            },
          },
          modifiers: [{
            supportedMethods: "https://username:password@example.com",
            total: {
              label: "total",
              amount: {
                currency: "USD",
                value: "1.00",
              },
            },
          },],
        }
        event.updateWith(invalidDetails);
      });
      payRequest.show().then((result) => {
        ok(false, "Expected throw 'RangeError', but got resolved.");
        resolve();
      }).catch((e) => {
        is(e.name, "RangeError", "Expected 'RangeError'.");
        resolve();
      }).finally(handler.destruct);
    });
  }

  function teardown() {
    gScript.addMessageListener("teardown-complete", function teardownCompleteHandler() {
      gScript.removeMessageListener("teardown-complete", teardownCompleteHandler);
      gScript.removeMessageListener("test-fail", testFailHandler)
      gScript.destroy();
      SimpleTest.finish();
    });
    gScript.sendAsyncMessage("teardown");
  }

  function runTests() {
    testWithValidPMIs()
    .then(testWithInvalidPMIs)
    .then(testUpdateWithValidPMI)
    .then(testUpdateWithInvalidPMI)
    .then(teardown)
    .catch( e => {
      ok(false, "Unexpected error: " + e.name);
      SimpleTest.finish();
    });
  }

  window.addEventListener('load', function() {
    SpecialPowers.pushPrefEnv({
      'set': [
        ['dom.payments.request.enabled', true],
      ]
    }, runTests);
  });

  </script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1389418">Mozilla Bug 1389418</a>
</body>
</html>
