From 1c1fecf12e48a46d4b2e4ee6d7536d67064d91bb Mon Sep 17 00:00:00 2001 From: Stephen Daly Date: Tue, 4 Feb 2020 16:39:14 +0000 Subject: [PATCH 1/2] PP-6079 Don't collect billing address for moto payments Currently, we don't show fields to collect the billing address on the card details page if billing address collection is disabled for the service. Now, we also won't show these fields if a payment is a MOTO payment even if billing address collection is enabled for the service. Determine whether we should collect the address in the resolve_service middleware and add a field to res.locals so that we can access it in all templates and controllers that need this value. Add Cypress tests to test this and remove tests from charge_ui_tests which are now better covered by Cypress tests. --- app/controllers/charge_controller.js | 4 +- app/middleware/resolve_service.js | 2 + app/views/charge.njk | 2 +- app/views/includes/scripts.njk | 4 +- test/charge_ui_tests.js | 62 +------- .../charge_controller_create_test.js | 82 +++++++--- .../card/billing-address-collection.spec.js | 142 ++++++++++++++++++ .../integration/card/email-collection.spec.js | 13 +- test/cypress/utils/card-payment-stubs.js | 23 +-- test/fixtures/payment_fixtures.js | 22 ++- 10 files changed, 252 insertions(+), 104 deletions(-) create mode 100644 test/cypress/integration/card/billing-address-collection.spec.js diff --git a/app/controllers/charge_controller.js b/app/controllers/charge_controller.js index d442f4116..c17a56571 100644 --- a/app/controllers/charge_controller.js +++ b/app/controllers/charge_controller.js @@ -122,7 +122,7 @@ module.exports = { const cardModel = Card(req.chargeData.gateway_account.card_types, req.chargeData.gateway_account.block_prepaid_cards, req.headers[CORRELATION_HEADER]) const chargeOptions = { email_collection_mode: charge.gatewayAccount.emailCollectionMode, - collect_billing_address: res.locals.service.collectBillingAddress + collect_billing_address: res.locals.collectBillingAddress } const validator = chargeValidator(i18n.__('fieldErrors'), logger, cardModel, chargeOptions, getLoggingFields(req)) @@ -185,7 +185,7 @@ module.exports = { const correlationId = req.headers[CORRELATION_HEADER] || '' const payload = normalise.apiPayload(req, card) - if (res.locals.service.collectBillingAddress === false) { + if (res.locals.collectBillingAddress === false) { delete payload.address } try { diff --git a/app/middleware/resolve_service.js b/app/middleware/resolve_service.js index 89d5e59b8..2f4f8a6f9 100644 --- a/app/middleware/resolve_service.js +++ b/app/middleware/resolve_service.js @@ -25,6 +25,7 @@ module.exports = function resolveServiceMiddleware (req, res, next) { const cachedService = serviceCache.get(gatewayAccountId) if (cachedService) { res.locals.service = cachedService + res.locals.collectBillingAddress = res.locals.service.collectBillingAddress && !req.chargeData.moto next() } else { // @FIXME(sfount) tests shouldn't rely on middleware returning a value if @@ -34,6 +35,7 @@ module.exports = function resolveServiceMiddleware (req, res, next) { .then(service => { serviceCache.put(gatewayAccountId, service, SERVICE_CACHE_MAX_AGE) res.locals.service = service + res.locals.collectBillingAddress = res.locals.service.collectBillingAddress && !req.chargeData.moto next() }) .catch((err) => { diff --git a/app/views/charge.njk b/app/views/charge.njk index f113e0bf6..96a23d9b6 100644 --- a/app/views/charge.njk +++ b/app/views/charge.njk @@ -272,7 +272,7 @@ - {% if service.collectBillingAddress %} + {% if collectBillingAddress %}

{{ __p("cardDetails.billingAddress") }}

diff --git a/app/views/includes/scripts.njk b/app/views/includes/scripts.njk index e0e44740b..22a61b530 100644 --- a/app/views/includes/scripts.njk +++ b/app/views/includes/scripts.njk @@ -30,7 +30,7 @@ }; window.Charge = { email_collection_mode: '{{ gatewayAccount.emailCollectionMode | safe }}', - collect_billing_address: {{ "true" if service.collectBillingAddress else "false" }}, + collect_billing_address: {{ "true" if collectBillingAddress else "false" }}, worldpay_3ds_flex_ddc_jwt: '{{ worldpay3dsFlexDdcJwt }}', worldpay_3ds_flex_ddc_url: '{{ worldpay3dsFlexDdcUrl }}' } @@ -41,7 +41,7 @@ if (mainWrap.classList.contains('charge-new')) { window.payScripts.helpers.setGlobalChargeId(); showCardType().init(); - {% if service.collectBillingAddress %} + {% if collectBillingAddress %} window.payScripts.helpers.initialiseAddressCountryAutocomplete(); {% endif %} window.payScripts.inputConfirm.init(); diff --git a/test/charge_ui_tests.js b/test/charge_ui_tests.js index 17fe8eb82..f5a9c8e0f 100644 --- a/test/charge_ui_tests.js +++ b/test/charge_ui_tests.js @@ -41,7 +41,7 @@ const generateConfirmViewTemplateData = (templateData = {}) => { describe('The charge view', function () { it('should render the amount', function () { const templateData = { - 'amount': '50.00' + amount: '50.00' } const body = renderTemplate('charge', templateData) @@ -51,7 +51,7 @@ describe('The charge view', function () { it('should have a submit form.', function () { const postAction = '/post_card_path' const templateData = { - 'post_card_action': postAction + post_card_action: postAction } const body = renderTemplate('charge', templateData) @@ -72,9 +72,7 @@ describe('The charge view', function () { it('should show all input fields.', function () { const body = renderTemplate('charge', { id: '1234', - service: { - collectBillingAddress: true - } + collectBillingAddress: true }) body.should.containInputWithIdAndName('csrf', 'csrfToken', 'hidden') body.should.containInputWithIdAndName('card-no', 'cardNo', 'text').withAttribute('maxlength', '26').withLabel('card-no-lbl', 'Card number') @@ -91,30 +89,8 @@ describe('The charge view', function () { body.should.not.containSelector('.custom-branding-image') }) - it('should not show billing address for services not wanting to capture it', function () { - const body = renderTemplate('charge', { - id: '1234', - service: { - collectBillingAddress: false - } - }) - body.should.containInputWithIdAndName('csrf', 'csrfToken', 'hidden') - body.should.containInputWithIdAndName('card-no', 'cardNo', 'text').withAttribute('maxlength', '26').withLabel('card-no-lbl', 'Card number') - body.should.containInputWithIdAndName('cvc', 'cvc', 'text').withLabel('cvc-lbl', 'Card security code') - body.should.containInputWithIdAndName('expiry-month', 'expiryMonth', 'text') - body.should.containInputWithIdAndName('expiry-year', 'expiryYear', 'text') - body.should.containInputWithIdAndName('cardholder-name', 'cardholderName', 'text').withAttribute('maxlength', '200').withLabel('cardholder-name-lbl', 'Name on card') - body.should.not.containSelector('#address-country') - body.should.not.containSelector('#address-line-1') - body.should.not.containSelector('#address-line-2') - body.should.not.containSelector('#address-city') - body.should.not.containSelector('#address-postcode') - body.should.containInputWithIdAndName('charge-id', 'chargeId', 'hidden').withAttribute('value', '1234') - body.should.not.containSelector('.custom-branding-image') - }) - it('should display custom branding', () => { - const templateData = lodash.merge('charge', { 'id': '1234' }, customBrandingData) + const templateData = lodash.merge('charge', { id: '1234' }, customBrandingData) const body = renderTemplate('charge', templateData) body.should.containSelector('.custom-branding-image') @@ -133,9 +109,7 @@ describe('The charge view', function () { addressLine2: 'blah blah', addressCity: 'Leicester City', addressPostcode: 'CT16 1FB', - service: { - collectBillingAddress: true - } + collectBillingAddress: true } const body = renderTemplate('charge', responseData) @@ -164,28 +138,6 @@ describe('The confirm view', function () { body.should.containSelector('#address').withText('1 street lane, avenue city, AB1 3DF') }) - it('should not show billing address for services not wanting to capture it', function () { - const body = renderTemplate('confirm', generateConfirmViewTemplateData({ - service: { - collectBillingAddress: false - }, - charge: { - cardDetails: { - billingAddress: null - } - } - })) - const $ = cheerio.load(body) - $('#payment-description').html().should.contain('Payment Description & <xss attack> assessment') - body.should.containInputWithIdAndName('csrf', 'csrfToken', 'hidden') - body.should.containSelector('#card-number').withText('●●●●●●●●●●●●5100') - body.should.containSelector('#expiry-date').withText('11/99') - body.should.containSelector('#cardholder-name').withText('Francisco Blaya-Gonzalvez') - body.should.not.containSelector('#address').withText('1 street lane, avenue city, AB1 3DF') - body.should.containSelector('#payment-description').withText('Payment Description') - body.should.containSelector('#amount').withText('£10.00') - }) - it('should display custom branding', () => { const templateData = lodash.merge(successTemplateDataWithCollectBillingAddress, customBrandingData) const body = renderTemplate('confirm', templateData) @@ -199,7 +151,7 @@ describe('The confirm view', function () { }) it('should render a confirm button', function () { - const body = renderTemplate('confirm', { confirmPath: '/card_details/123/confirm', 'charge': { id: 1234, amount: 50 } }) + const body = renderTemplate('confirm', { confirmPath: '/card_details/123/confirm', charge: { id: 1234, amount: 50 } }) const $ = cheerio.load(body) body.should.containSelector('form#confirmation').withAttributes( { @@ -213,7 +165,7 @@ describe('The confirm view', function () { it('should have a cancel form.', function () { const postAction = '/post_cancel_path' const templateData = { - 'post_cancel_action': postAction + post_cancel_action: postAction } const body = renderTemplate('charge', templateData) diff --git a/test/controllers/charge_controller_create_test.js b/test/controllers/charge_controller_create_test.js index 2106d2dec..cab937e61 100644 --- a/test/controllers/charge_controller_create_test.js +++ b/test/controllers/charge_controller_create_test.js @@ -15,6 +15,19 @@ const chargeId = '42mdrsshtsk4chpeoifhlgf4lk' const card = paymentFixtures.validCardDetails() const chargeData = paymentFixtures.validChargeDetails({ emailCollectionMode: 'OFF' }).getPlain() +const paymentDetails = { + chargeId: chargeId, + cardNo: '4242424242424242', + expiryMonth: '01', + expiryYear: '20', + cardholderName: 'Joe Bloggs', + cvc: '111', + addressCountry: 'GB', + addressLine1: '1 Horse Guards', + addressCity: 'London', + addressPostcode: 'E1 8QS' +} + const mockedChargeValidationBackend = function () { const validation = { hasError: false @@ -38,7 +51,6 @@ describe('POST /card_details/{chargeId} endpoint', function () { let response let chargeAuthStub let mockedConnectorClient - let paymentDetails beforeEach(() => { chargeAuthStub = sinon.stub().resolves( @@ -56,28 +68,13 @@ describe('POST /card_details/{chargeId} endpoint', function () { response = { redirect: sinon.spy(), locals: { - service: { - collectBillingAddress: true - } - + collectBillingAddress: true } } - paymentDetails = { - 'chargeId': chargeId, - 'cardNo': '4242424242424242', - 'expiryMonth': '01', - 'expiryYear': '20', - 'cardholderName': 'Joe Bloggs', - 'cvc': '111', - 'addressCountry': 'GB', - 'addressLine1': '1 Horse Guards', - 'addressCity': 'London', - 'addressPostcode': 'E1 8QS' - } }) it('should send worldpay_3ds_flex_ddc_result to connector when the request includes a worldpay3dsFlexDdcResult parameter', async function () { - paymentDetails['worldpay3dsFlexDdcResult'] = 'a-worldpay-3ds-flex-ddc-result' + paymentDetails.worldpay3dsFlexDdcResult = 'a-worldpay-3ds-flex-ddc-result' const request = { chargeData: chargeData, body: paymentDetails, @@ -112,8 +109,8 @@ describe('POST /card_details/{chargeId} endpoint', function () { expect(chargeAuthStub.calledWith(sinon.match( // eslint-disable-line { - 'chargeId': chargeId, - 'payload': payload + chargeId: chargeId, + payload: payload } ))).to.be.true // eslint-disable-line }) @@ -148,12 +145,51 @@ describe('POST /card_details/{chargeId} endpoint', function () { delete payload.accept_header delete payload.user_agent_header - delete payload.worldpay_3ds_flex_ddc_result expect(chargeAuthStub.calledWith(sinon.match( // eslint-disable-line { - 'chargeId': chargeId, - 'payload': payload + chargeId: chargeId, + payload: payload + } + ))).to.be.true // eslint-disable-line + }) + + it('should not include billing address in authorisation request when billing address collection disabled', async function () { + response.locals.collectBillingAddress = false + + const request = { + chargeData: chargeData, + body: paymentDetails, + chargeId: chargeId, + header: sinon.spy(), + headers: { + 'x-request-id': 'unique-id', + 'x-forwarded-for': '127.0.0.1' + } + } + await requireChargeController(mockedConnectorClient).create(request, response) + + const payload = paymentFixtures.validAuthorisationRequest({ + cardNumber: paymentDetails.cardNo, + cvc: paymentDetails.cvc, + cardBrand: card.brand, + expiryDate: `${paymentDetails.expiryMonth}/${paymentDetails.expiryYear}`, + cardholderName: paymentDetails.cardholderName, + cardType: card.type, + corporateCard: card.corporate, + prepaid: card.prepaid, + noBillingAddress: true + }).getPlain() + + delete payload.accept_header + delete payload.user_agent_header + + console.log('PAYLOAD ' + JSON.stringify(payload)) + + expect(chargeAuthStub.calledWith(sinon.match( // eslint-disable-line + { + chargeId: chargeId, + payload: payload } ))).to.be.true // eslint-disable-line }) diff --git a/test/cypress/integration/card/billing-address-collection.spec.js b/test/cypress/integration/card/billing-address-collection.spec.js new file mode 100644 index 000000000..7400bc9e7 --- /dev/null +++ b/test/cypress/integration/card/billing-address-collection.spec.js @@ -0,0 +1,142 @@ +const lodash = require('lodash') +const cardPaymentStubs = require('../../utils/card-payment-stubs') + +const tokenId = 'be88a908-3b99-4254-9807-c855d53f6b2b' +const chargeId = 'ub8de8r5mh4pb49rgm1ismaqfv' + +const validPayment = { + cardNumber: '4444333322221111', + expiryMonth: '01', + expiryYear: '30', + name: 'Valid Paying Name', + securityCode: '012', + email: 'foo@example.com', + noBillingAddress: true +} + +describe('Billing address collection', () => { + describe('Billing address collection enabled for service', () => { + // get a random gateway account per test as service is cached against gateway account + const gatewayAccountId = lodash.random(999999999) + const serviceOpts = { collect_billing_address: true } + const chargeOpts = { moto: false } + const createPaymentChargeStubs = cardPaymentStubs.buildCreatePaymentChargeStubs( + tokenId, chargeId, 'en', gatewayAccountId, serviceOpts, {}, {}, chargeOpts) + + it('Should show the billing address section', () => { + cy.task('setupStubs', createPaymentChargeStubs) + cy.visit(`/secure/${tokenId}`) + + cy.get('h2').contains('Billing address').should('exist') + cy.get('#address-country-select').should('exist') + cy.get('#address-line-1').should('exist') + cy.get('#address-line-2').should('exist') + cy.get('#address-city').should('exist') + cy.get('#address-postcode').should('exist') + }) + }) + + describe('Billing address collection disabled for service', () => { + // get a random gateway account per test as service is cached against gateway account + const gatewayAccountId = lodash.random(999999999) + const serviceOpts = { collect_billing_address: false } + const chargeOpts = { moto: false } + const createPaymentChargeStubs = cardPaymentStubs.buildCreatePaymentChargeStubs( + tokenId, chargeId, 'en', gatewayAccountId, serviceOpts, {}, {}, chargeOpts) + + beforeEach(() => { + // preserve cookies so we can prodeed with payment flow + Cypress.Cookies.preserveOnce('frontend_state') + }) + + it('Should not show the billing address section', () => { + cy.task('setupStubs', createPaymentChargeStubs) + cy.visit(`/secure/${tokenId}`) + + cy.get('h2').contains('Billing address').should('not.exist') + cy.get('#address-country-select').should('not.exist') + cy.get('#address-line-1').should('not.exist') + cy.get('#address-line-2').should('not.exist') + cy.get('#address-city').should('not.exist') + cy.get('#address-postcode').should('not.exist') + }) + + it('Should enter card details', () => { + const checkCardDetailsStubs = cardPaymentStubs.checkCardDetailsStubs(chargeId) + cy.task('setupStubs', checkCardDetailsStubs) + + cy.server() + cy.route('POST', `/check_card/${chargeId}`).as('checkCard') + + cy.get('#card-no').type(validPayment.cardNumber) + cy.get('#card-no').blur() + cy.wait('@checkCard') + cy.get('#expiry-month').type(validPayment.expiryMonth) + cy.get('#expiry-year').type(validPayment.expiryYear) + cy.get('#cardholder-name').type(validPayment.name) + cy.get('#cvc').type(validPayment.securityCode) + cy.get('#email').type(validPayment.email) + }) + + it('Submitting confirmation with valid details should redirect to confirmation page', () => { + const confirmPaymentDetailsStubs = cardPaymentStubs.confirmPaymentDetailsStubs(chargeId, validPayment, gatewayAccountId, chargeOpts, serviceOpts) + cy.task('setupStubs', confirmPaymentDetailsStubs) + cy.get('#card-details').submit() + cy.location('pathname').should('eq', `/card_details/${chargeId}/confirm`) + + cy.get('th').contains('Billing address').should('not.exist') + }) + }) + + describe('MOTO payment with billing address enabled for service', () => { + // get a random gateway account per test as service is cached against gateway account + const gatewayAccountId = lodash.random(999999999) + const serviceOpts = { collect_billing_address: true } + const chargeOpts = { moto: true } + const createPaymentChargeStubs = cardPaymentStubs.buildCreatePaymentChargeStubs( + tokenId, chargeId, 'en', gatewayAccountId, serviceOpts, {}, {}, chargeOpts) + + beforeEach(() => { + // preserve cookies so we can proceed with payment flow + Cypress.Cookies.preserveOnce('frontend_state') + }) + + it('Should not show the billing address section', () => { + cy.task('setupStubs', createPaymentChargeStubs) + cy.visit(`/secure/${tokenId}`) + + cy.get('h2').contains('Billing address').should('not.exist') + cy.get('#address-country-select').should('not.exist') + cy.get('#address-line-1').should('not.exist') + cy.get('#address-line-2').should('not.exist') + cy.get('#address-city').should('not.exist') + cy.get('#address-postcode').should('not.exist') + }) + + it('Should enter card details', () => { + const checkCardDetailsStubs = cardPaymentStubs.checkCardDetailsStubs(chargeId) + cy.task('setupStubs', checkCardDetailsStubs) + + cy.server() + cy.route('POST', `/check_card/${chargeId}`).as('checkCard') + + cy.get('#card-no').type(validPayment.cardNumber) + cy.get('#card-no').blur() + cy.wait('@checkCard') + cy.get('#expiry-month').type(validPayment.expiryMonth) + cy.get('#expiry-year').type(validPayment.expiryYear) + cy.get('#cardholder-name').type(validPayment.name) + cy.get('#cvc').type(validPayment.securityCode) + cy.get('#email').type(validPayment.email) + }) + + it('Submitting confirmation with valid details should redirect to confirmation page', () => { + const confirmPaymentDetailsStubs = cardPaymentStubs.confirmPaymentDetailsStubs(chargeId, validPayment, gatewayAccountId, chargeOpts, serviceOpts) + cy.task('setupStubs', confirmPaymentDetailsStubs) + cy.get('#card-details').submit() + cy.location('pathname').should('eq', `/card_details/${chargeId}/confirm`) + + cy.get('th').contains('Billing address').should('not.exist') + }) + }) +}) diff --git a/test/cypress/integration/card/email-collection.spec.js b/test/cypress/integration/card/email-collection.spec.js index 5bb0abf66..ebc44daea 100644 --- a/test/cypress/integration/card/email-collection.spec.js +++ b/test/cypress/integration/card/email-collection.spec.js @@ -3,6 +3,7 @@ const cardPaymentStubs = require('../../utils/card-payment-stubs') const tokenId = 'be88a908-3b99-4254-9807-c855d53f6b2b' const chargeId = 'ub8de8r5mh4pb49rgm1ismaqfv' const checkCardDetailsStubs = cardPaymentStubs.checkCardDetailsStubs(chargeId) +const gatewayAccountId = 42 const validPayment = { cardNumber: '4444333322221111', @@ -24,8 +25,8 @@ describe('Standard card payment flow', () => { describe('Email collection off', () => { const createPaymentChargeStubs = cardPaymentStubs.buildCreatePaymentChargeStubs( - tokenId, chargeId, 'en', 42, {}, {}, { emailCollectionMode: 'OFF' }) - const confirmPaymentDetailsStubs = cardPaymentStubs.confirmPaymentDetailsStubs(chargeId, validPayment, 'OFF') + tokenId, chargeId, 'en', gatewayAccountId, {}, {}, { emailCollectionMode: 'OFF' }) + const confirmPaymentDetailsStubs = cardPaymentStubs.confirmPaymentDetailsStubs(chargeId, validPayment, gatewayAccountId, { emailCollectionMode: 'OFF' }) it('Should setup the payment and load the page', () => { cy.task('setupStubs', createPaymentChargeStubs) @@ -66,8 +67,8 @@ describe('Standard card payment flow', () => { }) describe('Email collection mandatory', () => { - const createPaymentChargeStubs = cardPaymentStubs.buildCreatePaymentChargeStubs(tokenId, chargeId, 'en', 42, {}, {}) - const confirmPaymentDetailsStubs = cardPaymentStubs.confirmPaymentDetailsStubs(chargeId, validPayment) + const createPaymentChargeStubs = cardPaymentStubs.buildCreatePaymentChargeStubs(tokenId, chargeId, 'en', gatewayAccountId, {}, {}) + const confirmPaymentDetailsStubs = cardPaymentStubs.confirmPaymentDetailsStubs(chargeId, validPayment, gatewayAccountId, { emailCollectionMode: 'MANDATORY' }) it('Should setup the payment and load the page', () => { cy.task('setupStubs', createPaymentChargeStubs) @@ -108,8 +109,8 @@ describe('Standard card payment flow', () => { describe('Email collection optional', () => { const createPaymentChargeStubs = cardPaymentStubs.buildCreatePaymentChargeStubs( - tokenId, chargeId, 'en', 42, {}, {}, { emailCollectionMode: 'OPTIONAL' }) - const confirmPaymentDetailsStubs = cardPaymentStubs.confirmPaymentDetailsStubs(chargeId, validPayment, 'OPTIONAL') + tokenId, chargeId, 'en', gatewayAccountId, {}, {}, { emailCollectionMode: 'OPTIONAL' }) + const confirmPaymentDetailsStubs = cardPaymentStubs.confirmPaymentDetailsStubs(chargeId, validPayment, gatewayAccountId, { emailCollectionMode: 'OPTIONAL' }) it('Should setup the payment and load the page', () => { cy.task('setupStubs', createPaymentChargeStubs) diff --git a/test/cypress/utils/card-payment-stubs.js b/test/cypress/utils/card-payment-stubs.js index 21c39877a..47f4a56f3 100644 --- a/test/cypress/utils/card-payment-stubs.js +++ b/test/cypress/utils/card-payment-stubs.js @@ -1,17 +1,20 @@ 'use strict' -const confirmPaymentDetailsStubs = function confirmPaymentDetailsStubs (chargeId, validPayment = {}, emailCollectionMode) { +const confirmPaymentDetailsStubs = function confirmPaymentDetailsStubs (chargeId, validPayment = {}, gatewayAccountId = 42, additionalChargeOpts = {}, serviceOpts = {}) { return [ - { name: 'adminUsersGetService', opts: {} }, + { name: 'adminUsersGetService', opts: serviceOpts }, { name: 'connectorMultipleSubsequentChargeDetails', opts: [{ + ...additionalChargeOpts, chargeId, + gatewayAccountId, status: 'ENTERING CARD DETAILS', - state: { finished: false, status: 'started' }, - emailCollectionMode: emailCollectionMode || 'MANDATORY' + state: { finished: false, status: 'started' } }, { + ...additionalChargeOpts, chargeId, + gatewayAccountId, paymentDetails: { cardNumber: validPayment.cardNumber, expiryMonth: validPayment.expiryMonth, @@ -21,11 +24,11 @@ const confirmPaymentDetailsStubs = function confirmPaymentDetailsStubs (chargeId addressLine1: validPayment.addressLine1, city: validPayment.city, postcode: validPayment.postcode, - email: validPayment.email + email: validPayment.email, + noBillingAddress: validPayment.noBillingAddress }, status: 'AUTHORISATION SUCCESS', - state: { finished: false, status: 'submitted' }, - emailCollectionMode: emailCollectionMode || 'MANDATORY' + state: { finished: false, status: 'submitted' } }] }, { name: 'cardIdValidCardDetails' }, @@ -33,12 +36,13 @@ const confirmPaymentDetailsStubs = function confirmPaymentDetailsStubs (chargeId ] } -const checkCardDetailsStubs = function checkCardDetailsStubs (chargeId) { +const checkCardDetailsStubs = function checkCardDetailsStubs (chargeId, gatewayAccountId = 42) { return [ { name: 'connectorGetChargeDetails', opts: { chargeId, + gatewayAccountId, status: 'ENTERING CARD DETAILS', state: { finished: false, status: 'started' } } @@ -68,7 +72,7 @@ const buildCancelChargeStub = function buildCancelChargeStub (chargeId, gatewayA } const buildCreatePaymentChargeStubs = function buildCreatePaymentChargeStubs (tokenId, chargeId, language = 'en', gatewayAccountId = 42, - serviceOpts = {}, providerOpts = {}, gatewayAccountOpts = {}) { + serviceOpts = {}, providerOpts = {}, gatewayAccountOpts = {}, additionalChargeOpts = {}) { return [ { name: 'connectorCreateChargeFromToken', @@ -83,6 +87,7 @@ const buildCreatePaymentChargeStubs = function buildCreatePaymentChargeStubs (to { name: 'connectorGetChargeDetails', opts: { + ...additionalChargeOpts, chargeId, gatewayAccountId, status: 'CREATED', diff --git a/test/fixtures/payment_fixtures.js b/test/fixtures/payment_fixtures.js index 8a43614e6..f14ee829d 100644 --- a/test/fixtures/payment_fixtures.js +++ b/test/fixtures/payment_fixtures.js @@ -117,16 +117,20 @@ const utilFormatPaymentDetails = function utilFormatPaymentDetails (details) { first_digits_card_number: details.cardNumber.substr(6), cardholder_name: details.name, expiry_date: `${details.expiryMonth}/${details.expiryYear}`, - billing_address: { + card_brand: 'Visa' + } + + if (!details.noBillingAddress) { + structure.billing_address = { line1: details.addressLine1, - line2: '', + line2: details.addressLine2 || '', postcode: details.postcode, city: details.city, county: null, - country: 'GB' - }, - card_brand: 'Visa' + country: details.country || 'GB' + } } + return structure } @@ -182,6 +186,7 @@ const buildChargeDetails = function buildChargeDetails (opts) { return_url: opts.returnUrl || '/?confirm', created_date: '2019-02-12T17:53:31.307Z', delayed_capture: false, + moto: opts.moto || false, gateway_account: buildGatewayAccount(opts) } @@ -231,6 +236,7 @@ const buildChargeDetailsWithPrefilledCardHolderDeatils = (opts) => { return_url: opts.returnUrl || '/?confirm', // 'created_date': '2019-02-12T17:53:31.307Z', delayed_capture: false, + moto: opts.moto || false, gateway_account: buildGatewayAccount(opts) } @@ -285,6 +291,7 @@ const fixtures = { status: opts.status || 'CREATED', version: 1, walletType: null, + moto: opts.moto || false, events: [{ gatewayEventDate: null, status: 'CREATED', @@ -321,10 +328,13 @@ const fixtures = { accept_header: 'text/html', user_agent_header: 'Mozilla/5.0', prepaid: opts.prepaid || 'NOT_PREPAID', - worldpay_3ds_flex_ddc_result: opts.worldpay3dsFlexDdcResult || '96c3fcf6-d90a-467e-a224-107f70052528', ip_address: opts.ipAddress || '127.0.0.1' } + if (opts.worldpay3dsFlexDdcResult) { + data.worldpay_3ds_flex_ddc_result = opts.worldpay3dsFlexDdcResult + } + if (!opts.noBillingAddress) { data.address = { line1: opts.addressLine1 || 'The Money Pool', From e8af858d7fa67387c0b9876835248b871dd6262e Mon Sep 17 00:00:00 2001 From: Stephen Daly Date: Wed, 5 Feb 2020 11:36:39 +0000 Subject: [PATCH 2/2] PP-6079 Amend charge controller test Don't include an address in request for test to check we don't send a billing address to connector to mimic real behaviour. --- .../charge_controller_create_test.js | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/test/controllers/charge_controller_create_test.js b/test/controllers/charge_controller_create_test.js index cab937e61..03914ff61 100644 --- a/test/controllers/charge_controller_create_test.js +++ b/test/controllers/charge_controller_create_test.js @@ -15,13 +15,17 @@ const chargeId = '42mdrsshtsk4chpeoifhlgf4lk' const card = paymentFixtures.validCardDetails() const chargeData = paymentFixtures.validChargeDetails({ emailCollectionMode: 'OFF' }).getPlain() -const paymentDetails = { +const paymentDetailsWithoutAddress = { chargeId: chargeId, cardNo: '4242424242424242', expiryMonth: '01', expiryYear: '20', cardholderName: 'Joe Bloggs', - cvc: '111', + cvc: '111' +} + +const paymentDetails = { + ...paymentDetailsWithoutAddress, addressCountry: 'GB', addressLine1: '1 Horse Guards', addressCity: 'London', @@ -159,7 +163,7 @@ describe('POST /card_details/{chargeId} endpoint', function () { const request = { chargeData: chargeData, - body: paymentDetails, + body: paymentDetailsWithoutAddress, chargeId: chargeId, header: sinon.spy(), headers: { @@ -170,11 +174,11 @@ describe('POST /card_details/{chargeId} endpoint', function () { await requireChargeController(mockedConnectorClient).create(request, response) const payload = paymentFixtures.validAuthorisationRequest({ - cardNumber: paymentDetails.cardNo, - cvc: paymentDetails.cvc, + cardNumber: paymentDetailsWithoutAddress.cardNo, + cvc: paymentDetailsWithoutAddress.cvc, cardBrand: card.brand, - expiryDate: `${paymentDetails.expiryMonth}/${paymentDetails.expiryYear}`, - cardholderName: paymentDetails.cardholderName, + expiryDate: `${paymentDetailsWithoutAddress.expiryMonth}/${paymentDetailsWithoutAddress.expiryYear}`, + cardholderName: paymentDetailsWithoutAddress.cardholderName, cardType: card.type, corporateCard: card.corporate, prepaid: card.prepaid, @@ -184,8 +188,6 @@ describe('POST /card_details/{chargeId} endpoint', function () { delete payload.accept_header delete payload.user_agent_header - console.log('PAYLOAD ' + JSON.stringify(payload)) - expect(chargeAuthStub.calledWith(sinon.match( // eslint-disable-line { chargeId: chargeId,