<!DOCTYPE html>
<meta charset="utf-8">
<meta name="timeout" content="long">
<title>Tests for the 'secure-payment-confirmation' steps to validate payment method data</title>
<link rel="help" href="https://w3c.github.io/secure-payment-confirmation/#sctn-steps-to-validate-payment-method-data">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
'use strict';

const details = {total:
    {label: 'Total', amount: {value: '0.01', currency: 'USD'}}};

// This file contains tests for the 'steps to validate payment method data',
// which occurs during construction of the PaymentRequest. For general tests
// around construction, see constructor.https.html.

test(() => {
  assert_throws_js(RangeError, () => {
    new PaymentRequest([{
      supportedMethods: 'secure-payment-confirmation',
      data: {
        relyingPartyId: 'relying-party.example',
        // Empty credentialIds field.
        credentialIds: [],
        challenge: Uint8Array.from('x', c => c.charCodeAt(0)),
        payeeOrigin: window.location.origin,
        timeout: 60000,
        instrument: {
          displayName: 'X',
          icon: 'https://example.test/icon.png',
        },
        rpId: 'relying-party.example',
      },
    }], details);
  });
}, 'Empty credentialIds field throws exception.');

test(() => {
  assert_throws_js(RangeError, () => {
    new PaymentRequest([{
      supportedMethods: 'secure-payment-confirmation',
      data: {
        relyingPartyId: 'relying-party.example',
        credentialIds: [
          Uint8Array.from('c1', c => c.charCodeAt(0)),
          new Uint8Array(),  // Empty
          Uint8Array.from('c2', c => c.charCodeAt(0)),
        ],
        challenge: Uint8Array.from('x', c => c.charCodeAt(0)),
        payeeOrigin: window.location.origin,
        timeout: 60000,
        instrument: {
          displayName: 'X',
          icon: 'https://example.test/icon.png',
        },
        rpId: 'relying-party.example',
      },
    }], details);
  });
}, 'Empty ID within credentialIds field throws exception.');

test(() => {
  new PaymentRequest([{
    supportedMethods: 'secure-payment-confirmation',
    data: {
      credentialIds: [
        Uint8Array.from('c1', c => c.charCodeAt(0)),
        Uint8Array.from('c2', c => c.charCodeAt(0))
      ],
      challenge: Uint8Array.from('x', c => c.charCodeAt(0)),
      // Omitted payee origin, instead with payee name.
      payeeName: 'Example Merchant',
      timeout: 60000,
      instrument: {
        displayName: 'X',
        icon: 'https://example.test/icon.png',
      },
      rpId: 'relying-party.example',
    },
  }], details);
}, 'Multiple IDs in credentialIds is valid.');

test(() => {
  assert_throws_js(TypeError, () => {
    new PaymentRequest([{
      supportedMethods: 'secure-payment-confirmation',
      data: {
        // Large credentialIds value.
        credentialIds: [Uint8Array.from(
            'x'.repeat(1024 * 1024), c => c.charCodeAt(0))],
        challenge: Uint8Array.from('x', c => c.charCodeAt(0)),
        payeeOrigin: window.location.origin,
        timeout: 60000,
        instrument: {
          displayName: 'X',
          icon: 'https://example.test/icon.png',
        },
        rpId: 'relying-party.example',
      },
    }], details);
  });
}, 'Large credentialIds value throws exception.');

test(() => {
  assert_throws_js(TypeError, () => {
    new PaymentRequest([{
      supportedMethods: 'secure-payment-confirmation',
      data: {
        credentialIds: [Uint8Array.from('x', c => c.charCodeAt(0))],
        // Null challenge fields.
        challenge: null,
        payeeOrigin: window.location.origin,
        timeout: 60000,
        instrument: {
          displayName: 'X',
          icon: 'https://example.test/icon.png',
        },
        rpId: 'relying-party.example',
      },
    }], details);
  });
}, 'Null challenge field throws exception.');

test(() => {
  assert_throws_js(TypeError, () => {
    new PaymentRequest([{
      supportedMethods: 'secure-payment-confirmation',
      data: {
        credentialIds: [Uint8Array.from('x', c => c.charCodeAt(0))],
        // Empty challenge fields.
        challenge: [],
        payeeOrigin: window.location.origin,
        timeout: 60000,
        instrument: {
          displayName: 'X',
          icon: 'https://example.test/icon.png',
        },
        rpId: 'relying-party.example',
      },
    }], details);
  });
}, 'Empty challenge field throws exception.');

test(() => {
  assert_throws_js(TypeError, () => {
    new PaymentRequest([{
      supportedMethods: 'secure-payment-confirmation',
      data: {
        credentialIds: [Uint8Array.from('x', c => c.charCodeAt(0))],
        // Large challenge value.
        challenge: Uint8Array.from('x'.repeat(1024 * 1024), c => c.charCodeAt(0)),
        payeeOrigin: window.location.origin,
        timeout: 60000,
        instrument: {
          displayName: 'X',
          icon: 'https://example.test/icon.png',
        },
        rpId: 'relying-party.example',
      },
    }], details);
  });
}, 'Large challenge value throws exception.');

test(() => {
  assert_throws_js(TypeError, () => {
    new PaymentRequest([{
      supportedMethods: 'secure-payment-confirmation',
      data: {
        credentialIds: [Uint8Array.from('x', c => c.charCodeAt(0))],
        challenge: Uint8Array.from('x', c => c.charCodeAt(0)),
        payeeOrigin: window.location.origin,
        timeout: 60000,
        instrument: {
          displayName: '',
          icon: 'https://example.test/icon.png',
        },
        rpId: 'relying-party.example',
      },
    }], details);
  });
}, 'Empty instrument.displayName field throws exception.');

test(() => {
  assert_throws_js(TypeError, () => {
    new PaymentRequest([{
      supportedMethods: 'secure-payment-confirmation',
      data: {
        credentialIds: [Uint8Array.from('x', c => c.charCodeAt(0))],
        challenge: Uint8Array.from('x', c => c.charCodeAt(0)),
        payeeOrigin: window.location.origin,
        timeout: 60000,
        instrument: {
          displayName: 'X',
          icon: '',
        },
        rpId: 'relying-party.example',
      },
    }], details);
  });
}, 'Empty instrument.icon field throws exception.');

test(() => {
  assert_throws_js(TypeError, () => {
    new PaymentRequest([{
      supportedMethods: 'secure-payment-confirmation',
      data: {
        credentialIds: [Uint8Array.from('x', c => c.charCodeAt(0))],
        challenge: Uint8Array.from('x', c => c.charCodeAt(0)),
        payeeOrigin: window.location.origin,
        timeout: 60000,
        instrument: {
          displayName: 'X',
          icon: 'thisisnotaurl',
        },
        rpId: 'relying-party.example',
      },
    }], details);
  });
}, 'Invalid instrument.icon URL throws exception.');

test(() => {
  assert_throws_js(TypeError, () => {
    new PaymentRequest([{
      supportedMethods: 'secure-payment-confirmation',
      data: {
        credentialIds: [Uint8Array.from('x', c => c.charCodeAt(0))],
        challenge: Uint8Array.from('x', c => c.charCodeAt(0)),
        payeeOrigin: window.location.origin,
        timeout: 60000,
        instrument: {
          displayName: 'X',
          icon: 'https://example.test/icon.png',
        },
        rpId: 'domains cannot have spaces.com',
      },
    }], details);
  });
}, 'Invalid rpId field throws exception.');

test(() => {
  assert_throws_js(TypeError, () => {
    new PaymentRequest([{
      supportedMethods: 'secure-payment-confirmation',
      data: {
        // Omitted payee origin and payee name.
        credentialIds: [Uint8Array.from('x', c => c.charCodeAt(0))],
        challenge: Uint8Array.from('x', c => c.charCodeAt(0)),
        timeout: 60000,
        instrument: {
          displayName: 'X',
          icon: 'https://example.test/icon.png',
        },
        rpId: 'relying-party.example',
      },
    }], details);
  });
}, 'Omitting both payee origin and payee name throws exception.');

test(() => {
  new PaymentRequest([{
    supportedMethods: 'secure-payment-confirmation',
    data: {
      credentialIds: [Uint8Array.from('x', c => c.charCodeAt(0))],
      challenge: Uint8Array.from('x', c => c.charCodeAt(0)),
      // Omitted payee origin, instead with payee name.
      payeeName: 'Example Merchant',
      timeout: 60000,
      instrument: {
        displayName: 'X',
        icon: 'https://example.test/icon.png',
      },
      rpId: 'relying-party.example',
    },
  }], details);
}, 'Payee name without payee origin is valid.');

test(() => {
  new PaymentRequest([{
    supportedMethods: 'secure-payment-confirmation',
    data: {
      credentialIds: [Uint8Array.from('x', c => c.charCodeAt(0))],
      challenge: Uint8Array.from('x', c => c.charCodeAt(0)),
      // Both payee origin and payee name.
      payeeName: 'Example Merchant',
      payeeOrigin: window.location.origin,
      timeout: 60000,
      instrument: {
        displayName: 'X',
        icon: 'https://example.test/icon.png',
      },
      rpId: 'relying-party.example',
    },
  }], details);
}, 'Providing both payee name and payee origin is valid.');

test(() => {
  assert_throws_js(TypeError, () => {
    new PaymentRequest([{
      supportedMethods: 'secure-payment-confirmation',
      data: {
        credentialIds: [Uint8Array.from('x', c => c.charCodeAt(0))],
        challenge: Uint8Array.from('x', c => c.charCodeAt(0)),
        // Empty payee name
        payeeName: '',
        payeeOrigin: window.location.origin,
        timeout: 60000,
        instrument: {
          displayName: 'X',
          icon: 'https://example.test/icon.png',
        },
        rpId: 'relying-party.example',
      },
    }], details);
  });
}, 'Empty payee name throws exception.');

test(() => {
  assert_throws_js(TypeError, () => {
    new PaymentRequest([{
      supportedMethods: 'secure-payment-confirmation',
      data: {
        credentialIds: [Uint8Array.from('x', c => c.charCodeAt(0))],
        challenge: Uint8Array.from('x', c => c.charCodeAt(0)),
        payeeName: 'Example Merchant',
        // Empty payee origin
        payeeOrigin: '',
        timeout: 60000,
        instrument: {
          displayName: 'X',
          icon: 'https://example.test/icon.png',
        },
        rpId: 'relying-party.example',
      },
    }], details);
  });
}, 'Empty payee origin throws exception.');

test(() => {
  assert_throws_js(TypeError, () => {
    new PaymentRequest([{
      supportedMethods: 'secure-payment-confirmation',
      data: {
        credentialIds: [Uint8Array.from('x', c => c.charCodeAt(0))],
        challenge: Uint8Array.from('x', c => c.charCodeAt(0)),
        payeeName: 'Example Merchant',
        payeeOrigin: 'http://thepayee.com',
        timeout: 60000,
        instrument: {
          displayName: 'X',
          icon: 'https://example.test/icon.png',
        },
        rpId: 'relying-party.example',
      },
    }], details);
  });
}, 'Non-HTTPS payee origin throws exception.');
</script>
