From 6ae2cdaf2a17b7f997c3bae3a24e047c8a4116d1 Mon Sep 17 00:00:00 2001 From: Jared Wein Date: Thu, 3 May 2018 11:36:44 -0400 Subject: [PATCH] Bug 1440504 - Restrict fields on the payer contact page to those requested by the PaymentOptions object. r=MattN MozReview-Commit-ID: 1aW0eTo6HYM --HG-- extra : rebase_source : c42e58e33ede46f85d249526d0fadd106583eaed --- .../payments/res/containers/address-form.css | 21 ++ .../payments/res/containers/address-form.js | 9 +- .../payments/res/containers/address-picker.js | 1 + browser/components/payments/res/debugging.js | 2 +- .../payments/res/paymentRequest.xhtml | 1 + .../payments/test/PaymentTestUtils.jsm | 9 + .../test/browser/browser_address_edit.js | 184 +++++++++++++++++- .../test/mochitest/test_address_form.html | 36 ++++ 8 files changed, 258 insertions(+), 5 deletions(-) create mode 100644 browser/components/payments/res/containers/address-form.css diff --git a/browser/components/payments/res/containers/address-form.css b/browser/components/payments/res/containers/address-form.css new file mode 100644 index 000000000000..c38df5931b6f --- /dev/null +++ b/browser/components/payments/res/containers/address-form.css @@ -0,0 +1,21 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Hide all form fields that are not explicitly requested + * by the paymentOptions object. + */ +address-form[address-fields]:not([address-fields~='name']) #name-container, +address-form[address-fields] #organization-container, +address-form[address-fields] #street-address-container, +address-form[address-fields] #address-level2-container, +address-form[address-fields] #address-level1-container, +address-form[address-fields] #postal-code-container, +address-form[address-fields] #country-container, +address-form[address-fields] #country-warning-message, +address-form[address-fields]:not([address-fields~='email']) #email-container, +address-form[address-fields]:not([address-fields~='tel']) #tel-container { + /* !important is needed because autofillEditForms.js sets + inline styles on the form fields with display: flex; */ + display: none !important; +} diff --git a/browser/components/payments/res/containers/address-form.js b/browser/components/payments/res/containers/address-form.js index affc9c52916a..aae21c8d0012 100644 --- a/browser/components/payments/res/containers/address-form.js +++ b/browser/components/payments/res/containers/address-form.js @@ -81,6 +81,12 @@ export default class AddressForm extends PaymentStateSubscriberMixin(HTMLElement savedAddresses, } = state; + if (page.addressFields) { + this.setAttribute("address-fields", page.addressFields); + } else { + this.removeAttribute("address-fields"); + } + this.pageTitle.textContent = page.title; this.genericErrorText.textContent = page.error; @@ -130,7 +136,6 @@ export default class AddressForm extends PaymentStateSubscriberMixin(HTMLElement let record = this.formHandler.buildFormObject(); let { page, - selectedStateKey, } = this.requestStore.getState(); paymentRequest.updateAutofillRecord("addresses", record, page.guid, { @@ -141,7 +146,7 @@ export default class AddressForm extends PaymentStateSubscriberMixin(HTMLElement }, }, preserveOldProperties: true, - selectedStateKey, + selectedStateKey: page.selectedStateKey, successStateChange: { page: { id: "payment-summary", diff --git a/browser/components/payments/res/containers/address-picker.js b/browser/components/payments/res/containers/address-picker.js index 19a23fd85f19..5a3350a2e2df 100644 --- a/browser/components/payments/res/containers/address-picker.js +++ b/browser/components/payments/res/containers/address-picker.js @@ -166,6 +166,7 @@ export default class AddressPicker extends PaymentStateSubscriberMixin(HTMLEleme page: { id: "address-page", selectedStateKey: this.selectedStateKey, + addressFields: this.getAttribute("address-fields"), }, }; diff --git a/browser/components/payments/res/debugging.js b/browser/components/payments/res/debugging.js index e44f82f98558..be84e68a495b 100644 --- a/browser/components/payments/res/debugging.js +++ b/browser/components/payments/res/debugging.js @@ -66,7 +66,7 @@ let REQUEST_1 = { error: "", }, paymentOptions: { - requestPayerName: false, + requestPayerName: true, requestPayerEmail: false, requestPayerPhone: false, requestShipping: true, diff --git a/browser/components/payments/res/paymentRequest.xhtml b/browser/components/payments/res/paymentRequest.xhtml index 0b5957b5e379..ddf91d194d7a 100644 --- a/browser/components/payments/res/paymentRequest.xhtml +++ b/browser/components/payments/res/paymentRequest.xhtml @@ -59,6 +59,7 @@ + diff --git a/browser/components/payments/test/PaymentTestUtils.jsm b/browser/components/payments/test/PaymentTestUtils.jsm index f10737e87f23..3e25e52fd055 100644 --- a/browser/components/payments/test/PaymentTestUtils.jsm +++ b/browser/components/payments/test/PaymentTestUtils.jsm @@ -339,6 +339,15 @@ var PaymentTestUtils = { requestShippingOption: { requestShipping: true, }, + requestPayerNameAndEmail: { + requestPayerName: true, + requestPayerEmail: true, + }, + requestPayerNameEmailAndPhone: { + requestPayerName: true, + requestPayerEmail: true, + requestPayerPhone: true, + }, }, Addresses: { diff --git a/browser/components/payments/test/browser/browser_address_edit.js b/browser/components/payments/test/browser/browser_address_edit.js index ba449dbc5381..b5a1202e2655 100644 --- a/browser/components/payments/test/browser/browser_address_edit.js +++ b/browser/components/payments/test/browser/browser_address_edit.js @@ -38,12 +38,16 @@ add_task(async function test_add_link() { PaymentTestUtils: PTU, } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {}); + let state = await PTU.DialogContentUtils.waitForState(content, (state) => { + return Object.keys(state.savedAddresses).length == 0; + }, "No saved addresses when starting test"); + let addLink = content.document.querySelector("address-picker a"); is(addLink.textContent, "Add", "Add link text"); addLink.click(); - let state = await PTU.DialogContentUtils.waitForState(content, (state) => { + state = await PTU.DialogContentUtils.waitForState(content, (state) => { return state.page.id == "address-page" && !state.page.guid; }, "Check add page state"); @@ -116,12 +120,16 @@ add_task(async function test_edit_link() { PaymentTestUtils: PTU, } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {}); + let state = await PTU.DialogContentUtils.waitForState(content, (state) => { + return Object.keys(state.savedAddresses).length == 1; + }, "One saved address when starting test"); + let editLink = content.document.querySelector("address-picker a:nth-of-type(2)"); is(editLink.textContent, "Edit", "Edit link text"); editLink.click(); - let state = await PTU.DialogContentUtils.waitForState(content, (state) => { + state = await PTU.DialogContentUtils.waitForState(content, (state) => { return state.page.id == "address-page" && !!state.page.guid; }, "Check edit page state"); @@ -165,3 +173,175 @@ add_task(async function test_edit_link() { }); await cleanupFormAutofillStorage(); }); + +add_task(async function test_add_payer_contact_name_email_link() { + await BrowserTestUtils.withNewTab({ + gBrowser, + url: BLANK_PAGE_URL, + }, async browser => { + let {win, frame} = + await setupPaymentDialog(browser, { + methodData: [PTU.MethodData.basicCard], + details: PTU.Details.total60USD, + options: PTU.Options.requestPayerNameAndEmail, + merchantTaskFn: PTU.ContentTasks.createAndShowRequest, + } + ); + + const EXPECTED_ADDRESS = { + "given-name": "Deraj", + "family-name": "Niew", + "email": "test@example.com", + }; + + await spawnPaymentDialogTask(frame, async (address) => { + let { + PaymentTestUtils: PTU, + } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {}); + + let state = await PTU.DialogContentUtils.waitForState(content, (state) => { + return Object.keys(state.savedAddresses).length == 0; + }, "No saved addresses when starting test"); + + let addLink = content.document.querySelector("address-picker.payer-related a"); + is(addLink.textContent, "Add", "Add link text"); + + addLink.click(); + + state = await PTU.DialogContentUtils.waitForState(content, (state) => { + return state.page.id == "address-page" && !state.page.guid; + }, "Check add page state"); + + let title = content.document.querySelector("address-form h1"); + is(title.textContent, "Add Payer Contact", "Page title should be set"); + + info("filling fields"); + for (let [key, val] of Object.entries(address)) { + let field = content.document.getElementById(key); + if (!field) { + ok(false, `${key} field not found`); + } + field.value = val; + ok(!field.disabled, `Field #${key} shouldn't be disabled`); + } + + info("check that non-payer requested fields are hidden"); + for (let selector of ["#organization", "#tel"]) { + ok(content.document.querySelector(selector).getBoundingClientRect().height == 0, + selector + " should be hidden"); + } + + content.document.querySelector("address-form button:last-of-type").click(); + state = await PTU.DialogContentUtils.waitForState(content, (state) => { + return Object.keys(state.savedAddresses).length == 1; + }, "Check address was added"); + + let addressGUIDs = Object.keys(state.savedAddresses); + is(addressGUIDs.length, 1, "Check there is one addresses"); + let savedAddress = state.savedAddresses[addressGUIDs[0]]; + for (let [key, val] of Object.entries(address)) { + is(savedAddress[key], val, "Check " + key); + } + + state = await PTU.DialogContentUtils.waitForState(content, (state) => { + return state.page.id == "payment-summary"; + }, "Switched back to payment-summary"); + }, EXPECTED_ADDRESS); + + info("clicking cancel"); + spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel); + + await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed"); + }); +}); + +add_task(async function test_edit_payer_contact_name_email_phone_link() { + await BrowserTestUtils.withNewTab({ + gBrowser, + url: BLANK_PAGE_URL, + }, async browser => { + let {win, frame} = + await setupPaymentDialog(browser, { + methodData: [PTU.MethodData.basicCard], + details: PTU.Details.total60USD, + options: PTU.Options.requestPayerNameEmailAndPhone, + merchantTaskFn: PTU.ContentTasks.createAndShowRequest, + } + ); + + const EXPECTED_ADDRESS = { + "given-name": "Deraj", + "family-name": "Niew", + "email": "test@example.com", + "tel": "+15555551212", + }; + + await spawnPaymentDialogTask(frame, async (address) => { + let { + PaymentTestUtils: PTU, + } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {}); + + let state = await PTU.DialogContentUtils.waitForState(content, (state) => { + return Object.keys(state.savedAddresses).length == 1; + }, "One saved addresses when starting test"); + + let editLink = + content.document.querySelector("address-picker.payer-related a:nth-of-type(2)"); + is(editLink.textContent, "Edit", "Edit link text"); + + editLink.click(); + + state = await PTU.DialogContentUtils.waitForState(content, (state) => { + info("state.page.id: " + state.page.id + "; state.page.guid: " + state.page.guid); + return state.page.id == "address-page" && !!state.page.guid; + }, "Check edit page state"); + + let title = content.document.querySelector("address-form h1"); + is(title.textContent, "Edit Payer Contact", "Page title should be set"); + + info("overwriting field values"); + for (let [key, val] of Object.entries(address)) { + let field = content.document.getElementById(key); + field.value = val + "1"; + ok(!field.disabled, `Field #${key} shouldn't be disabled`); + } + + info("check that non-payer requested fields are hidden"); + let formElements = + content.document.querySelectorAll("address-form :-moz-any(input, select, textarea"); + let allowedFields = ["given-name", "additional-name", "family-name", "email", "tel"]; + for (let element of formElements) { + let shouldBeVisible = allowedFields.includes(element.id); + if (shouldBeVisible) { + ok(element.getBoundingClientRect().height > 0, element.id + " should be visible"); + } else { + ok(element.getBoundingClientRect().height == 0, element.id + " should be hidden"); + } + } + + content.document.querySelector("address-form button:last-of-type").click(); + + state = await PTU.DialogContentUtils.waitForState(content, (state) => { + let addresses = Object.entries(state.savedAddresses); + return addresses.length == 1 && + addresses[0][1]["given-name"] == address["given-name"] + "1"; + }, "Check address was edited"); + + let addressGUIDs = Object.keys(state.savedAddresses); + is(addressGUIDs.length, 1, "Check there is still one address"); + let savedAddress = state.savedAddresses[addressGUIDs[0]]; + for (let [key, val] of Object.entries(address)) { + is(savedAddress[key], val + "1", "Check updated " + key); + } + + await PTU.DialogContentUtils.waitForState(content, (state) => { + return state.page.id == "payment-summary"; + }, "Switched back to payment-summary"); + }, EXPECTED_ADDRESS); + + info("clicking cancel"); + spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel); + + await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed"); + }); +}); diff --git a/browser/components/payments/test/mochitest/test_address_form.html b/browser/components/payments/test/mochitest/test_address_form.html index b1d444fa9a3e..d6064a60558d 100644 --- a/browser/components/payments/test/mochitest/test_address_form.html +++ b/browser/components/payments/test/mochitest/test_address_form.html @@ -17,6 +17,7 @@ Test the address-form element +

@@ -228,6 +229,41 @@ add_task(async function test_edit() { form.remove(); }); + +add_task(async function test_restricted_address_fields() { + let form = new AddressForm(); + form.dataset.saveButtonLabel = "Save"; + form.dataset.errorGenericSave = "Generic error"; + await form.promiseReady; + display.appendChild(form); + await asyncElementRendered(); + form.setAttribute("address-fields", "name email tel"); + + ok(!isHidden(form.form.querySelector("#given-name")), + "given-name should be visible"); + ok(!isHidden(form.form.querySelector("#additional-name")), + "additional-name should be visible"); + ok(!isHidden(form.form.querySelector("#family-name")), + "family-name should be visible"); + ok(isHidden(form.form.querySelector("#organization")), + "organization should be hidden"); + ok(isHidden(form.form.querySelector("#street-address")), + "street-address should be hidden"); + ok(isHidden(form.form.querySelector("#address-level2")), + "address-level2 should be hidden"); + ok(isHidden(form.form.querySelector("#address-level1")), + "address-level1 should be hidden"); + ok(isHidden(form.form.querySelector("#postal-code")), + "postal-code should be hidden"); + ok(isHidden(form.form.querySelector("#country")), + "country should be hidden"); + ok(!isHidden(form.form.querySelector("#email")), + "email should be visible"); + ok(!isHidden(form.form.querySelector("#tel")), + "tel should be visible"); + + form.remove(); +});