Re: [w3c/payment-request] Add way to update `total` and `displayItems` before `.show()` (#639)

>  It falls out of some assumptions about the API rather than specific contracts.

It's true that the spec does not specify when the scan for the payment apps should happen. There's a fine line between predictability of API behavior and tying the hands of browser manufacturers. I see your point here, though. Perhaps this is good behavior to standardize across browsers, so that web developers can rely on it. @ianbjacobs Can we put this on agenda for the next call or the face-to-face in November?

> Right now, it looks like the Payment Handler spec says that handlers receive total.

The [`PaymentRequestEvent`](https://www.w3.org/TR/payment-handler/#the-paymentrequestevent) is fired in the selected payment handler when the user clicks the [Pay] button in the browser payment sheet UI. Constructing `PaymentRequest`, calling `canMakePayment()`, or calling `show()` will not trigger the `PaymentRequestEvent`. So the payment handler does not get the `total` until after user consent.

I have a [proposal](https://github.com/w3c/payment-handler/pull/170) in the works to optionally fire `CanMakePaymentEvent` in the payment handler. This would be fired during `PaymentRequest` construction while scanning the locally installed payment apps. This event will not contain the `total`. 

In summary, the corresponding events between the merchant and the payment app are:

User | Merchant | Payment Handler
--|----------|--------------------------------------------------------------------------------------
Visit page. | `pr = new PaymentRequest();` | App scan: If the payment handler supports [standardized payment method identifier](https://w3c.github.io/payment-method-id/#standardized-payment-method-identifiers) (e.g., `"basic-card"`), then the browser compares merchant's request to capabilities of the payment handler and stores matching payment handlers in `apps` list in memory. If the payment handler supports only [URL-based payment method identifiers](https://w3c.github.io/payment-method-id/#url-based-payment-method-identifiers) (e.g., `https://android.com/pay`), then the browser fires `CanMakePaymentEvent` event in the payment handler and stores the ones that returned `true` in the `apps` list in memory.
No action required. | `pr.canMakePayment();` | Wait until app scan completes, then return `!apps.empty()`. 
Click [Buy_Now] button on the page. | `pr.show();` | Show the payment sheet UI with a "Loading..." spinner, wait until the app scan completes, then show the `apps` in the sheet.
Click [Pay] in the browser payment sheet UI. | | Fire `PaymentRequestEvent` in the selected payment handler.

>  There doesn't seem to be anything stopping a browser from forcing `canMakePayment()` being called before `show()`.

This can get a little confusing, so let's clarify a bit. According to the spec, calling `show()` without calling `canMakePayment()` is OK, but calling `canMakePayment()` after calling `show()` on the same instance of `PaymentRequest` will throw `InvalidStateError`. 

```javascript
// CASE 1: This is fine:
pr = new PaymentRequest();
pr.canMakePayment();
pr.show();

// CASE 2: This is also fine:
pr = new PaymentRequest();
pr.show();

// CASE 3: This will throw in canMakePayment():
pr = new PaymentRequest();
pr.show();
pr.canMakePayment();  // InvalidStateError
```

Is it possible, however, that a browser implements the PaymentRequest spec correctly, but does not work in `CASE 2` above? The answer is "No". Although this is not explicitly stated in the spec, this is prevented by the definitions of the algorithms for [`canMakePayment()`](https://w3c.github.io/payment-request/#canmakepayment()-method) and [`show()`](https://w3c.github.io/payment-request/#show()-method). The `canMakePayment()` algorithm does not change any internal state, so there's nothing for the `show()` algorithm to check. We can enforce this via an explicit [web platform test](https://w3c-test.org/payment-request/), as well.

Note that the opposite is not true. The `show()` algorithm sets the internal field _request_.[[state]] to "interactive" and `canMakePayment()` throws `InvalidStateError` with this state. In practice this means that you can't run `canMakePayment()` after `show()` was called on the same instance of `PaymentRequest`, as shown in `CASE 3` above.

I hope this information is useful. Please let me know if I can help with any other concerns you might have.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/w3c/payment-request/issues/639#issuecomment-334801601

Received on Friday, 6 October 2017 16:17:33 UTC