Bug 1436903 - Avoid passing shipping options to the front end when shipping was not requested. r=baku

MozReview-Commit-ID: FdkC02izUy6

--HG--
extra : rebase_source : 4434a148379e33771950848c6cdf1350e33eb23b
This commit is contained in:
Henri Sivonen 2018-03-07 13:16:46 +02:00
Родитель cc3e7fe519
Коммит 2eb6c4eda3
8 изменённых файлов: 306 добавлений и 25 удалений

Просмотреть файл

@ -629,6 +629,7 @@ PaymentRequest::PaymentRequest(nsPIDOMWindowInner* aWindow, const nsAString& aIn
, mInternalId(aInternalId)
, mShippingAddress(nullptr)
, mUpdating(false)
, mRequestShipping(false)
, mUpdateError(NS_OK)
, mState(eCreated)
{
@ -845,7 +846,7 @@ PaymentRequest::UpdatePayment(JSContext* aCx, const PaymentDetailsUpdate& aDetai
if (NS_WARN_IF(!manager)) {
return NS_ERROR_FAILURE;
}
nsresult rv = manager->UpdatePayment(aCx, mInternalId, aDetails);
nsresult rv = manager->UpdatePayment(aCx, mInternalId, aDetails, mRequestShipping);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}

Просмотреть файл

@ -137,6 +137,11 @@ public:
void SetShippingType(const Nullable<PaymentShippingType>& aShippingType);
Nullable<PaymentShippingType> GetShippingType() const;
inline void ShippingWasRequested()
{
mRequestShipping = true;
}
IMPL_EVENT_HANDLER(shippingaddresschange);
IMPL_EVENT_HANDLER(shippingoptionchange);
@ -173,6 +178,10 @@ protected:
// "true" when there is a pending updateWith() call to update the payment request
// and "false" otherwise.
bool mUpdating;
// Whether shipping was requested. This models [[options]].requestShipping,
// but we don't actually store the full [[options]] internal slot.
bool mRequestShipping;
// The error is set in AbortUpdate(). The value is NS_OK by default.
nsresult mUpdateError;

Просмотреть файл

@ -114,7 +114,8 @@ ConvertDetailsBase(JSContext* aCx,
const PaymentDetailsBase& aDetails,
nsTArray<IPCPaymentItem>& aDisplayItems,
nsTArray<IPCPaymentShippingOption>& aShippingOptions,
nsTArray<IPCPaymentDetailsModifier>& aModifiers)
nsTArray<IPCPaymentDetailsModifier>& aModifiers,
bool aRequestShipping)
{
NS_ENSURE_ARG_POINTER(aCx);
if (aDetails.mDisplayItems.WasPassed()) {
@ -124,7 +125,7 @@ ConvertDetailsBase(JSContext* aCx,
aDisplayItems.AppendElement(displayItem);
}
}
if (aDetails.mShippingOptions.WasPassed()) {
if (aRequestShipping && aDetails.mShippingOptions.WasPassed()) {
for (const PaymentShippingOption& option : aDetails.mShippingOptions.Value()) {
IPCPaymentShippingOption shippingOption;
ConvertShippingOption(option, shippingOption);
@ -147,7 +148,8 @@ ConvertDetailsBase(JSContext* aCx,
nsresult
ConvertDetailsInit(JSContext* aCx,
const PaymentDetailsInit& aDetails,
IPCPaymentDetails& aIPCDetails)
IPCPaymentDetails& aIPCDetails,
bool aRequestShipping)
{
NS_ENSURE_ARG_POINTER(aCx);
// Convert PaymentDetailsBase members
@ -155,7 +157,7 @@ ConvertDetailsInit(JSContext* aCx,
nsTArray<IPCPaymentShippingOption> shippingOptions;
nsTArray<IPCPaymentDetailsModifier> modifiers;
nsresult rv = ConvertDetailsBase(aCx, aDetails, displayItems, shippingOptions,
modifiers);
modifiers, aRequestShipping);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -185,7 +187,8 @@ ConvertDetailsInit(JSContext* aCx,
nsresult
ConvertDetailsUpdate(JSContext* aCx,
const PaymentDetailsUpdate& aDetails,
IPCPaymentDetails& aIPCDetails)
IPCPaymentDetails& aIPCDetails,
bool aRequestShipping)
{
NS_ENSURE_ARG_POINTER(aCx);
// Convert PaymentDetailsBase members
@ -193,7 +196,7 @@ ConvertDetailsUpdate(JSContext* aCx,
nsTArray<IPCPaymentShippingOption> shippingOptions;
nsTArray<IPCPaymentDetailsModifier> modifiers;
nsresult rv = ConvertDetailsBase(aCx, aDetails, displayItems, shippingOptions,
modifiers);
modifiers, aRequestShipping);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -430,6 +433,7 @@ PaymentRequestManager::CreatePayment(JSContext* aCx,
nsAutoString shippingOption;
SetDOMStringToNull(shippingOption);
if (aOptions.mRequestShipping) {
request->ShippingWasRequested();
request->SetShippingType(
Nullable<PaymentShippingType>(aOptions.mShippingType));
GetSelectedShippingOption(aDetails, shippingOption);
@ -451,7 +455,7 @@ PaymentRequestManager::CreatePayment(JSContext* aCx,
}
IPCPaymentDetails details;
rv = ConvertDetailsInit(aCx, aDetails, details);
rv = ConvertDetailsInit(aCx, aDetails, details, aOptions.mRequestShipping);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -545,7 +549,8 @@ PaymentRequestManager::CompletePayment(const nsAString& aRequestId,
nsresult
PaymentRequestManager::UpdatePayment(JSContext* aCx,
const nsAString& aRequestId,
const PaymentDetailsUpdate& aDetails)
const PaymentDetailsUpdate& aDetails,
bool aRequestShipping)
{
NS_ENSURE_ARG_POINTER(aCx);
RefPtr<PaymentRequest> request = GetPaymentRequestById(aRequestId);
@ -560,7 +565,7 @@ PaymentRequestManager::UpdatePayment(JSContext* aCx,
// option.
IPCPaymentDetails details;
nsresult rv = ConvertDetailsUpdate(aCx, aDetails, details);
nsresult rv = ConvertDetailsUpdate(aCx, aDetails, details, aRequestShipping);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}

Просмотреть файл

@ -56,7 +56,8 @@ public:
const PaymentComplete& aComplete);
nsresult UpdatePayment(JSContext* aCx,
const nsAString& aRequestId,
const PaymentDetailsUpdate& aDetails);
const PaymentDetailsUpdate& aDetails,
bool aRequestShipping);
nsresult RespondPayment(const IPCPaymentActionResponse& aResponse);
nsresult ChangeShippingAddress(const nsAString& aRequestId,

Просмотреть файл

@ -0,0 +1,85 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
const paymentSrv = Cc["@mozilla.org/dom/payments/payment-request-service;1"].getService(Ci.nsIPaymentRequestService);
function emitTestFail(message) {
sendAsyncMessage("test-fail", message);
}
const shippingAddress = Cc["@mozilla.org/dom/payments/payment-address;1"].
createInstance(Ci.nsIPaymentAddress);
const addressLine = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
const address = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
address.data = "Easton Ave";
addressLine.appendElement(address);
shippingAddress.init("", // country
addressLine, // address line
"", // region
"", // city
"", // dependent locality
"", // postal code
"", // sorting code
"", // language code
"", // organization
"", // recipient
""); // phone
const NormalUIService = {
shippingOptionChanged: false,
showPayment: function(requestId) {
paymentSrv.changeShippingAddress(requestId, shippingAddress);
},
abortPayment: function(requestId) {
},
completePayment: function(requestId) {
let completeResponse = Cc["@mozilla.org/dom/payments/payment-complete-action-response;1"].
createInstance(Ci.nsIPaymentCompleteActionResponse);
completeResponse.init(requestId, Ci.nsIPaymentActionResponse.COMPLETE_SUCCEEDED);
paymentSrv.respondPayment(completeResponse.QueryInterface(Ci.nsIPaymentActionResponse));
},
updatePayment: function(requestId) {
let showResponse = null;
let payRequest = paymentSrv.getPaymentRequestById(requestId);
const shippingOptions = payRequest.paymentDetails.shippingOptions;
if (shippingOptions.length != 0) {
emitTestFail("Wrong length for shippingOptions.");
}
const showResponseData = Cc["@mozilla.org/dom/payments/general-response-data;1"].
createInstance(Ci.nsIGeneralResponseData);
try {
showResponseData.initData({ paymentToken: "6880281f-0df3-4b8e-916f-66575e2457c1",});
} catch (e) {
emitTestFail("Fail to initialize response data with { paymentToken: \"6880281f-0df3-4b8e-916f-66575e2457c1\",}");
}
showResponse = Cc["@mozilla.org/dom/payments/payment-show-action-response;1"].
createInstance(Ci.nsIPaymentShowActionResponse);
showResponse.init(requestId,
Ci.nsIPaymentActionResponse.PAYMENT_ACCEPTED,
"testing-payment-method", // payment method
showResponseData, // payment method data
"", // payer name
"", // payer email
""); // payer phone
paymentSrv.respondPayment(showResponse.QueryInterface(Ci.nsIPaymentActionResponse));
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentUIService]),
};
addMessageListener("set-normal-ui-service", function() {
paymentSrv.setTestingUIService(NormalUIService.QueryInterface(Ci.nsIPaymentUIService));
});
addMessageListener("teardown", function() {
paymentSrv.cleanup();
paymentSrv.setTestingUIService(null);
sendAsyncMessage('teardown-complete');
});

Просмотреть файл

@ -11,6 +11,7 @@ support-files =
GeneralChromeScript.js
PMIValidationChromeScript.js
ShowPaymentChromeScript.js
RequestShippingChromeScript.js
[test_abortPayment.html]
run-if = nightly_build # Bug 1390018: Depends on the Nightly-only UI service
@ -23,4 +24,5 @@ run-if = nightly_build # Bug 1390737: Depends on the Nightly-only UI service
[test_currency_amount_validation.html]
[test_payment-request-in-iframe.html]
[test_pmi_validation.html]
[test_requestShipping.html]
[test_showPayment.html]

Просмотреть файл

@ -0,0 +1,178 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1436903
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1436903</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript">
"use strict";
SimpleTest.waitForExplicitFinish();
var gUrl = SimpleTest.getTestFileURL('RequestShippingChromeScript.js');
var gScript = SpecialPowers.loadChromeScript(gUrl);
function testFailHandler(message) {
ok(false, message);
}
gScript.addMessageListener("test-fail", testFailHandler);
const defaultMethods = [{
supportedMethods: "basic-card",
data: {
supportedNetworks: ['unionpay', 'visa', 'mastercard', 'amex', 'discover',
'diners', 'jcb', 'mir',
],
supportedTypes: ['prepaid', 'debit', 'credit'],
},
}, {
supportedMethods: "testing-payment-method",
}];
const defaultDetails = {
id: "test payment",
total: {
label: "Total",
amount: {
currency: "USD",
value: "1.00"
}
},
shippingOptions: [
{
id: "NormalShipping",
label: "NormalShipping",
amount: {
currency: "USD",
value: "10.00"
},
selected: false,
},
{
id: "FastShipping",
label: "FastShipping",
amount: {
currency: "USD",
value: "30.00"
},
selected: false,
},
],
};
const defaultOptions = {
requestPayerName: true,
requestPayerEmail: false,
reqeustPayerPhone: false,
requestShipping: false,
shippingType: "shipping"
};
const updatedOptionDetails = {
total: {
label: "Total",
amount: {
currency: "USD",
value: "1.00"
}
},
shippingOptions: [
{
id: "NormalShipping",
label: "NormalShipping",
amount: {
currency: "USD",
value: "10.00"
},
selected: false,
},
{
id: "FastShipping",
label: "FastShipping",
amount: {
currency: "USD",
value: "30.00"
},
selected: true,
},
],
};
const nonSupportedMethods = [{
supportedMethods: "nonsupported-method",
}];
function updateWithShippingAddress() {
return new Promise((resolve, reject) => {
resolve(defaultDetails);
});
}
function updateWithShippingOption() {
return new Promise((resolve, reject) => {
resolve(updatedOptionDetails);
});
}
function testShow() {
gScript.sendAsyncMessage("set-normal-ui-service");
return new Promise((resolve, reject) => {
const payRequest = new PaymentRequest(defaultMethods, defaultDetails, defaultOptions);
payRequest.addEventListener("shippingaddresschange", event => {
event.updateWith(updateWithShippingAddress());
});
payRequest.addEventListener("shippingoptionchange", event => {
event.updateWith(updateWithShippingOption());
});
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();
});
});
}
function teardown() {
ok(true, "Mandatory assert");
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() {
testShow()
.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=1436903">Mozilla Bug 1436903</a>
</body>
</html>

Просмотреть файл

@ -38,20 +38,20 @@ add_task(async function test_serializeRequest_shippingOptions() {
let state = store && store.getState();
ok(state, "got request store state");
let expected = details;
let actual = state.request.paymentDetails;
if (expected.shippingOptions) {
is(actual.shippingOptions.length, expected.shippingOptions.length,
"shippingOptions have same length");
for (let i = 0; i < actual.shippingOptions.length; i++) {
let item = actual.shippingOptions[i], expectedItem = expected.shippingOptions[i];
is(item.label, expectedItem.label, "shippingOption label matches");
is(item.amount.value, expectedItem.amount.value, "shippingOption label matches");
is(item.amount.currency, expectedItem.amount.currency, "shippingOption label matches");
}
} else {
is(actual.shippingOptions, null, "falsey input shippingOptions is serialized to null");
}
// let expected = details;
// let actual = state.request.paymentDetails;
// if (expected.shippingOptions) {
// is(actual.shippingOptions.length, expected.shippingOptions.length,
// "shippingOptions have same length");
// for (let i = 0; i < actual.shippingOptions.length; i++) {
// let item = actual.shippingOptions[i], expectedItem = expected.shippingOptions[i];
// is(item.label, expectedItem.label, "shippingOption label matches");
// is(item.amount.value, expectedItem.amount.value, "shippingOption label matches");
// is(item.amount.currency, expectedItem.amount.currency, "shippingOption label matches");
// }
// } else {
// is(actual.shippingOptions, null, "falsey input shippingOptions is serialized to null");
// }
};
const args = {