| <!DOCTYPE html> | |
| <meta charset="utf-8"> | |
| <title>Tests for providing `deferredPaymentRequest` as part of `ApplePayModifier`.</title> | |
| <script src="/js-test-resources/ui-helper.js"></script> | |
| <script src="/resources/payment-request.js"></script> | |
| <script src="/resources/testharness.js"></script> | |
| <script src="/resources/testharnessreport.js"></script> | |
| <body> | |
| <script> | |
| setup({ explicit_done: true, explicit_timeout: true }); | |
| test((test) => { | |
| const method = validPaymentMethod(); | |
| method.data.features = ["paymentRequestDeferred"]; | |
| new PaymentRequest([method], validPaymentDetails()); | |
| }, "Should have a feature for `deferredPaymentRequest`."); | |
| function daysFromToday(days) { | |
| date = new Date(); | |
| date.setDate(date.getDate() + days); | |
| return date; | |
| } | |
| const paymentDescription = "paymentDescription"; | |
| const deferredBilling = { label: "deferredBilling", amount: "5", type: "final", paymentTiming: "deferred", deferredPaymentDate: daysFromToday(14) }; | |
| const deferredBillingOut = { ...deferredBilling, recurringPaymentIntervalUnit: "month", recurringPaymentIntervalCount: 1 }; | |
| const billingAgreement = "billingAgreement"; | |
| const managementURL = "http://managementURL.com"; | |
| const tokenNotificationURL = "http://tokenNotificationURL.com"; | |
| const freeCancellationDate = daysFromToday(7); | |
| const freeCancellationDateTimeZone = "America/Los_Angeles"; | |
| function modifiersWithData(data) { | |
| return [ { supportedMethods: 'https://apple.com/apple-pay', data } ]; | |
| } | |
| function testValidDeferredPaymentRequest(description, {initialDeferredPaymentRequest, expectedDeferredPaymentRequest}) { | |
| user_activation_test(async (test) => { | |
| let detailsInit = validPaymentDetails(); | |
| if (initialDeferredPaymentRequest !== undefined) | |
| detailsInit.modifiers = modifiersWithData({ deferredPaymentRequest: initialDeferredPaymentRequest }); | |
| let request = new PaymentRequest([validPaymentMethod()], detailsInit); | |
| request.addEventListener("merchantvalidation", (event) => { | |
| event.complete({ }); | |
| }); | |
| request.addEventListener("shippingaddresschange", (event) => { | |
| event.updateWith({ }); | |
| internals.mockPaymentCoordinator.acceptPayment(); | |
| }); | |
| let response = await request.show(); | |
| let actualDeferredPaymentRequest = internals.mockPaymentCoordinator.deferredPaymentRequest; | |
| if (actualDeferredPaymentRequest) | |
| assert_object_equals(actualDeferredPaymentRequest, expectedDeferredPaymentRequest, "check that the `deferredPaymentRequest` matches"); | |
| else | |
| assert_equals(actualDeferredPaymentRequest, expectedDeferredPaymentRequest, "check that the `deferredPaymentRequest` matches"); | |
| await response.complete("success"); | |
| }, description + " as part of the request."); | |
| user_activation_test(async (test) => { | |
| let request = new PaymentRequest([validPaymentMethod()], validPaymentDetails()); | |
| request.addEventListener("merchantvalidation", (event) => { | |
| event.complete({ }); | |
| }); | |
| request.addEventListener("shippingaddresschange", (event) => { | |
| let detailsUpdate = { }; | |
| if (initialDeferredPaymentRequest !== undefined) | |
| detailsUpdate.modifiers = modifiersWithData({ deferredPaymentRequest: initialDeferredPaymentRequest }); | |
| event.updateWith(detailsUpdate); | |
| internals.mockPaymentCoordinator.acceptPayment(); | |
| }); | |
| let response = await request.show(); | |
| let actualDeferredPaymentRequest = internals.mockPaymentCoordinator.deferredPaymentRequest; | |
| if (actualDeferredPaymentRequest) | |
| assert_object_equals(actualDeferredPaymentRequest, expectedDeferredPaymentRequest, "check that the `deferredPaymentRequest` matches"); | |
| else | |
| assert_equals(actualDeferredPaymentRequest, expectedDeferredPaymentRequest, "check that the `deferredPaymentRequest` matches"); | |
| await response.complete("success"); | |
| }, description + " as part of an update."); | |
| } | |
| testValidDeferredPaymentRequest("The default value of `deferredPaymentRequest` should be `null` if `data` is not provided", { | |
| initialDeferredPaymentRequest: undefined, | |
| expectedDeferredPaymentRequest: null, | |
| }); | |
| testValidDeferredPaymentRequest("Should not error if optional properties are not provided", { | |
| initialDeferredPaymentRequest: { paymentDescription, deferredBilling, managementURL }, | |
| expectedDeferredPaymentRequest: { paymentDescription, deferredBilling: deferredBillingOut, managementURL }, | |
| }); | |
| testValidDeferredPaymentRequest("Should not error if optional free-cancellation-date properties are not provided", { | |
| initialDeferredPaymentRequest: { paymentDescription, deferredBilling, billingAgreement, managementURL, tokenNotificationURL }, | |
| expectedDeferredPaymentRequest: { paymentDescription, deferredBilling: deferredBillingOut, billingAgreement, managementURL, tokenNotificationURL }, | |
| }); | |
| testValidDeferredPaymentRequest("Should propagate all data", { | |
| initialDeferredPaymentRequest: { paymentDescription, deferredBilling, billingAgreement, managementURL, tokenNotificationURL, freeCancellationDate, freeCancellationDateTimeZone }, | |
| expectedDeferredPaymentRequest: { paymentDescription, deferredBilling: deferredBillingOut, billingAgreement, managementURL, tokenNotificationURL, freeCancellationDate, freeCancellationDateTimeZone }, | |
| }); | |
| function testInvalidDeferredPaymentRequest(description, {deferredPaymentRequest, expectedErrorSubstring}) { | |
| user_activation_test(async (test) => { | |
| let detailsInit = validPaymentDetails(); | |
| detailsInit.modifiers = modifiersWithData({ deferredPaymentRequest }); | |
| let request = new PaymentRequest([validPaymentMethod()], detailsInit); | |
| try { | |
| let response = await request.show(); | |
| internals.mockPaymentCoordinator.cancelPayment(); | |
| assert_true(false, "should error about " + expectedErrorSubstring); | |
| } catch (e) { | |
| assert_true(e.message.includes(expectedErrorSubstring), "should error with '" + expectedErrorSubstring + "' but got '" + e.message + "'"); | |
| } | |
| }, description + " as part of the request."); | |
| user_activation_test(async (test) => { | |
| let request = new PaymentRequest([validPaymentMethod()], validPaymentDetails()); | |
| request.addEventListener("merchantvalidation", (event) => { | |
| event.complete({ }); | |
| }); | |
| request.addEventListener("shippingaddresschange", (event) => { | |
| event.updateWith({ modifiers: modifiersWithData({ deferredPaymentRequest }) }); | |
| }); | |
| try { | |
| let response = await request.show(); | |
| internals.mockPaymentCoordinator.cancelPayment(); | |
| assert_true(false, "should error about " + expectedErrorSubstring); | |
| } catch (e) { | |
| assert_true(e.message.includes(expectedErrorSubstring), "should error with '" + expectedErrorSubstring + "' but got '" + e.message + "'"); | |
| } | |
| }, description + " as part of an update."); | |
| } | |
| testInvalidDeferredPaymentRequest("Should error when `deferredBilling` is missing `paymentTiming`", { | |
| deferredPaymentRequest: { paymentDescription, deferredBilling: { } , managementURL }, | |
| expectedErrorSubstring: "'deferredBilling' must be a 'deferred' line item", | |
| }); | |
| testInvalidDeferredPaymentRequest("Should error when `deferredBilling` has an invalid `paymentTiming`", { | |
| deferredPaymentRequest: { paymentDescription, deferredBilling: { paymentTiming: "whenever" } , managementURL }, | |
| expectedErrorSubstring: "Type error", // Would have preferred "'deferredBilling' must be a 'deferred' line item", but the enum parser caught it first. | |
| }); | |
| testInvalidDeferredPaymentRequest("Should error when `deferredBilling.paymentTiming` is not 'deferred'", { | |
| deferredPaymentRequest: { paymentDescription, deferredBilling: { paymentTiming: "immediate" } , managementURL }, | |
| expectedErrorSubstring: "must be a 'deferred' line item", | |
| }); | |
| testInvalidDeferredPaymentRequest("Should error when `deferredBilling` is missing `label`", { | |
| deferredPaymentRequest: { paymentDescription, deferredBilling: { paymentTiming: "deferred" } , managementURL }, | |
| expectedErrorSubstring: "Missing label for 'deferredBilling'", | |
| }); | |
| testInvalidDeferredPaymentRequest("Should error when `deferredBilling` is missing `amount`", { | |
| deferredPaymentRequest: { paymentDescription, deferredBilling: { paymentTiming: "deferred", label: "deferredBillingBad" } , managementURL }, | |
| expectedErrorSubstring: "not a valid amount", | |
| }); | |
| testInvalidDeferredPaymentRequest("Should error when `deferredBilling` has an invalid `amount`", { | |
| deferredPaymentRequest: { paymentDescription, deferredBilling: { paymentTiming: "deferred", label: "deferredBillingBad", amount: "invalid" } , managementURL }, | |
| expectedErrorSubstring: "not a valid amount", | |
| }); | |
| testInvalidDeferredPaymentRequest("Should error when there is a `freeCancellationDate` without `freeCancellationDateTimeZone`", { | |
| deferredPaymentRequest: { paymentDescription, deferredBilling, managementURL, billingAgreement, freeCancellationDate }, | |
| expectedErrorSubstring: "Missing 'freeCancellationDateTimeZone' when 'freeCancellationDate' is set", | |
| }); | |
| testInvalidDeferredPaymentRequest("Should error when there is a `freeCancellationDateTimeZone` without `freeCancellationDate`", { | |
| deferredPaymentRequest: { paymentDescription, deferredBilling, managementURL, billingAgreement, freeCancellationDateTimeZone }, | |
| expectedErrorSubstring: "Unexpected 'freeCancellationDateTimeZone' when 'freeCancellationDate' is not set", | |
| }); | |
| testInvalidDeferredPaymentRequest("Should error when `freeCancellationDate` is not a valid Date", { | |
| deferredPaymentRequest: { paymentDescription, deferredBilling, managementURL, freeCancellationDate: "Tomorrow", freeCancellationDateTimeZone }, | |
| expectedErrorSubstring: "Unexpected 'freeCancellationDateTimeZone' when 'freeCancellationDate' is not set", // Would have preferred "not a valid date", but Date parser removed the property. | |
| }); | |
| testInvalidDeferredPaymentRequest("Should error when `freeCancellationDateTimeZone` is not a valid time zone", { | |
| deferredPaymentRequest: { paymentDescription, deferredBilling, managementURL, freeCancellationDate, freeCancellationDateTimeZone: "Backyard" }, | |
| expectedErrorSubstring: "not a valid time zone", | |
| }); | |
| testInvalidDeferredPaymentRequest("Should error when `managementURL` is not a valid URL", { | |
| deferredPaymentRequest: { paymentDescription, deferredBilling, managementURL: 42 }, | |
| expectedErrorSubstring: "not a valid URL", | |
| }); | |
| testInvalidDeferredPaymentRequest("Should error when `tokenNotificationURL` is not a valid URL", { | |
| deferredPaymentRequest: { paymentDescription, deferredBilling, managementURL, tokenNotificationURL: 42 }, | |
| expectedErrorSubstring: "not a valid URL", | |
| }); | |
| done(); | |
| </script> | |