Skip to content

Commit

Permalink
Revert "Remove shipping related things from payment-request (#28830)" (
Browse files Browse the repository at this point in the history
  • Loading branch information
marcoscaceres authored Apr 2, 2024
1 parent 3602a64 commit cd418e2
Show file tree
Hide file tree
Showing 33 changed files with 4,154 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@

function checkRedaction(billingAddress) {
assert_true(
billingAddress instanceof PaymentAddress,
"Expected instance of PaymentAddress"
billingAddress instanceof ContactAddress,
"Expected instance of ContactAddress"
);
for (const item of ["organization", "phone", "recipient"]) {
assert_equals(
Expand Down Expand Up @@ -134,7 +134,7 @@ <h2>Request billing address</h2>
<button onclick="requestBillingAddress()">
When billing address is
requested,`PaymentMethodChangeEvent.methodData.billingAddress` is a
`PaymentAddress`.
`ContactAddress`.
</button>
</li>
<li><button onclick="done()">Done!</button></li>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<!doctype html>
<meta charset="utf8">
<link rel="help" href="https://www.w3.org/TR/payment-request/#ContactAddress-interface">
<title>
PaymentResponse.prototype.shippingAddress
</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../payment-response/helpers.js"></script>
<script>
const options = { requestShipping: true };
function runManualTest(button, expected = {}) {
button.disabled = true;
promise_test(async () => {
const { response } = await getPaymentRequestResponse(options);
await response.complete();
assert_idl_attribute(response, "shippingAddress");
const { shippingAddress: addr } = response;
assert_true(
addr instanceof ContactAddress,
"Expect instance of ContactAddress"
);
// An [ISO3166] alpha-2 code. The canonical form is upper case.
const { country } = addr;
assert_equals(country.length, 2, "Expected length is 2");
assert_true(/^[A-Z]{2}$/.test(country), "Canonical form is upper case");
assert_true(
addr.addressLine instanceof Array,
"Expected addressLine to be an array"
);
assert_throws_js(
TypeError,
() => {
addr.addressLine.push("this must throw");
},
"Array must be frozen"
);
for (let [attr, expectedValue] of Object.entries(expected)) {
assert_idl_attribute(addr, attr);
const msg = `Expected ContactAddress.${attr} to equal ${expectedValue}.`;
//.toString() flattens array addressLine,
//.toLowerCase() because case can't be enforced for some attributes
const actualValue = addr[attr].toString().toLowerCase();
expectedValue = expectedValue.toString().toLowerCase();
assert_equals(actualValue, expectedValue, msg);
}
// Check toJSON result
for (let [prop, jsonValue] of Object.entries(addr.toJSON())) {
const actualValue = jsonValue.toString().toLowerCase();
const expectedValue = expected[prop].toString().toLowerCase();
const msg = `Expected JSON ${prop} to be ${expectedValue}`;
assert_equals(actualValue, expectedValue, msg);
}
}, button.textContent.trim());
done();
}
</script>
<h2>ContactAddress interface</h2>
<p>
Click on each button in sequence from top to bottom without refreshing the page.
Each button will bring up the Payment Request UI window.
</p>
<p>
When prompted, please enter addresses as follows...
</p>
<ol>
<li>
<button onclick="
const expectedAddress = {
country: 'AU',
regionCode: 'QLD',
addressLine: '55 test st',
city: 'Chapel Hill',
dependentLocality: '',
postalCode: '6095',
region: 'QLD',
sortingCode: '',
organization: 'w3c',
recipient: 'web platform test',
phone: '+61733780000',
};
runManualTest(this, expectedAddress);">
If the requestShipping member is true, then shippingAddress's ContactAddress must match the expected values.
</button>
Please use:
<dl>
<dt>Recipient:</dt>
<dd>web platform test</dd>
<dt>Address line:</dt>
<dd>55 test st</dd>
<dt>Country</dt>
<dd>Australia</dd>
<dt>City</dt>
<dd>Chapel Hill</dd>
<dd>State/Region</dd>
<dd>Queensland</dd>
<dt>postal code </dt>
<dd>6095</dd>
<dt>organization</dt>
<dd>w3c</dd>
<dt>Phone number</dt>
<dd>+61 7 3378 0000</dd>
</dl>
</li>
</ol>
<small>
If you find a buggy test, please <a href="https://github.com/web-platform-tests/wpt/issues">file a bug</a>
and tag one of the <a href="https://github.com/web-platform-tests/wpt/blob/master/payment-request/META.yml">suggested reviewers</a>.
</small>
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
<!doctype html>
<meta charset="utf8">
<link rel="help" href="https://www.w3.org/TR/payment-request/#updatewith()-method">
<link rel="help" href="https://github.com/w3c/payment-request/pull/591">
<title>
PaymentRequestUpdateEvent.updateWith() needs to be called immediately
</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
setup({ explicit_done: true, explicit_timeout: true });
const applePay = Object.freeze({
supportedMethods: "https://apple.com/apple-pay",
data: {
version: 3,
merchantIdentifier: "merchant.com.example",
countryCode: "US",
merchantCapabilities: ["supports3DS"],
supportedNetworks: ["visa"],
}
});
const validMethod = Object.freeze({ supportedMethods: "basic-card" });
const validMethods = Object.freeze([validMethod, applePay]);
const validAmount = Object.freeze({ currency: "USD", value: "5.00" });
const validTotal = Object.freeze({
label: "label",
amount: validAmount,
});
const validShippingOptionA = Object.freeze({
id: "a-shipping-option",
label: "A shipping option",
amount: validAmount,
selected: true,
});
const validShippingOptionB = Object.freeze({
id: "b-shipping-option",
label: "B shipping option",
amount: validAmount,
});
const validDetails = Object.freeze({
total: validTotal,
shippingOptions: [validShippingOptionA, validShippingOptionB],
});
const validOptions = Object.freeze({
requestShipping: true,
});

function testImmediateUpdate({ textContent: testName }) {
promise_test(async t => {
const request = new PaymentRequest(
validMethods,
validDetails,
validOptions
);
const eventPromise = new Promise((resolve, reject) => {
request.addEventListener(
"shippingaddresschange",
ev => {
// Forces updateWith() to be run in the next event loop tick so that
// [[waitForUpdate]] is already true when it runs.
t.step_timeout(() => {
try {
ev.updateWith(validDetails);
resolve(); // This is bad.
} catch (err) {
reject(err); // this is good.
}
});
},
{ once: true }
);
});
const acceptPromise = request.show();
await promise_rejects_dom(
t,
"InvalidStateError",
eventPromise,
"The event loop already spun, so [[waitForUpdate]] is now true"
);
const response = await acceptPromise;
await response.complete();
}, testName.trim());
}

function testSubsequentUpdateWithCalls({ textContent: testName }) {
promise_test(async t => {
const request = new PaymentRequest(
validMethods,
validDetails,
validOptions
);
const eventPromise = new Promise((resolve, reject) => {
request.addEventListener("shippingaddresschange", async ev => {
const p = Promise.resolve(validDetails);
ev.updateWith(p);
await p;
try {
ev.updateWith(validDetails);
resolve(); // this is bad, we should never get to here.
} catch (err) {
reject(err); // this is good!
}
});
});
const responsePromise = request.show();
await promise_rejects_dom(
t,
"InvalidStateError",
eventPromise,
"Expected eventPromise to have rejected, because updateWith() was a called twice"
);
const response = await responsePromise;
await response.complete();
}, testName.trim());
}

function testRecycleEvents({ textContent: testName }) {
promise_test(async t => {
const request = new PaymentRequest(
validMethods,
validDetails,
validOptions
);

// Register both listeners.
const addressChangedPromise = new Promise(resolve => {
request.addEventListener("shippingaddresschange", resolve, {
once: true,
});
});

const optionChangedPromise = new Promise(resolve => {
request.addEventListener("shippingoptionchange", resolve, {
once: true,
});
});

const responsePromise = request.show();

// Let's wait for the address to change.
const addressChangeEvent = await addressChangedPromise;

// Sets [[waitingForUpdate]] to true.
addressChangeEvent.updateWith(validDetails);

// Let's wait for the shippingOption.
const optionChangeEvent = await optionChangedPromise;

// Here, we try to be sneaky, and reuse the addressChangeEvent to perform the update.
// However, addressChangeEvent [[waitingForUpdate]] is true, so it throws.
assert_throws_dom(
"InvalidStateError",
() => {
addressChangeEvent.updateWith(validDetails);
},
"addressChangeEvent [[waitingForUpdate]] is true, so it must throw"
);

// But optionChangeEvent is still usable tho, so...
optionChangeEvent.updateWith(validDetails);

assert_throws_dom(
"InvalidStateError",
() => {
optionChangeEvent.updateWith(validDetails);
},
"optionChangeEvent [[waitingForUpdate]] is true, so it must throw"
);

const response = await responsePromise;
await response.complete();
}, testName.trim());
}
</script>
<h2>updateWith() method</h2>
<p>
Click on each button in sequence from top to bottom without refreshing the page.
Each button will bring up the Payment Request UI window.
</p>
<p>
When the payment sheet is shown, select a different shipping address once. Then pay.
</p>
<ol>
<li id="test-0">
<button onclick="testImmediateUpdate(this);">
updateWith() must be called immediately, otherwise must throw an InvalidStateError.
</button>
</li>
<li id="test-1">
<button onclick="testSubsequentUpdateWithCalls(this);">
Once the event has performed an update, subsequent calls to updateWith() must throw InvalidStateError.
</button>
</li>
<li id="test-2">
<button onclick="testRecycleEvents(this);">
Recycling events must not be possible.
</button> When the payment sheet is shown, select a different shipping address once, then change shipping option once. Then pay.
</li>
<li>
<button onclick="done();">Done!</button>
</li>
</ol>
<small>
If you find a buggy test, please <a href="https://github.com/web-platform-tests/wpt/issues">file a bug</a>
and tag one of the <a href="https://github.com/web-platform-tests/wpt/blob/master/payment-request/META.yml">suggested reviewers</a>.
</small>
Loading

0 comments on commit cd418e2

Please sign in to comment.