bridge-node-server/node_server/utils/acquirers/worldpay_acquirer.spec.js
Martin Donnelly 57bd6c8e6a init
2018-06-24 21:15:03 +01:00

358 lines
13 KiB
JavaScript

/* globals describe, beforeEach, afterEach, it */
/**
* Unit testing file for the worldpay_acquirer
*/
/* eslint-disable import/no-unassigned-import */
/* eslint-disable mocha/no-hooks-for-single-case */
/* eslint-disable global-require */
/* eslint-disable promise/always-return */
/* eslint-disable no-throw-literal */
/* eslint max-nested-callbacks: ["error", 99] */
'use strict';
require('../../tools/test/testGlobals.js');
const _ = require('lodash');
const chai = require('chai');
const sinon = require('sinon');
const sinonChai = require('sinon-chai');
const chaiAsPromised = require('chai-as-promised');
const expect = chai.expect;
chai.use(sinonChai);
chai.use(chaiAsPromised);
const utils = require(global.pathPrefix + 'utils.js');
const worldpay = require(global.pathPrefix + 'worldpay.js');
const wpAcquirer = require('./worldpay_acquirer.js');
const acqErrors = require(global.pathPrefix + '../utils/acquirers/acquirer_errors.js');
/**
* Some constants and variables to help with tests
*/
const TEST_SERVICE_KEY = 'A Worldpay Key';
const VALID_SERVICE_KEY = utils.encryptDataV1(TEST_SERVICE_KEY);
const INVALID_SERVICE_KEY = 'BROKEN';
const VOID_UUID = '00000000-0000-0000-0000-000000000000';
const TRANSACTION_ID = '123456789abcdef0';
const CLIENT_KEY = '012345678abcdef';
const CLIENT_ID = '0123456789abcdef01234567';
const TEST_CARD_NO = '5555555555554444';
const VALID_CARD = utils.encryptDataV3(TEST_CARD_NO, CLIENT_KEY, CLIENT_ID);
const VALID_EXPIRY = utils.encryptDataV3('01-23', CLIENT_KEY, CLIENT_ID);
let account = null;
describe('worldpay_acquirer', () => {
describe('validateMerchantAccount', () => {
afterEach(() => {
worldpay.worldpayFunction.restore();
});
describe('basic successes', () => {
beforeEach(() => {
sinon.stub(worldpay, 'worldpayFunction')
.callsArgWith(5, {
customCode: 'ORDER_NOT_FOUND'
});
account = {
AcquirerCipher: VALID_SERVICE_KEY
};
});
it('should resolve ok', () => {
return expect(wpAcquirer.validateMerchantAccount(account))
.to.eventually.be.fulfilled;
});
it('should call the worldpayFunction', () => {
return wpAcquirer.validateMerchantAccount(account).finally(() => {
return expect(worldpay.worldpayFunction).to.be.called;
});
});
it('should make a GET request to /orders/<null UUID>', () => {
return wpAcquirer.validateMerchantAccount(account).finally(() => {
return expect(worldpay.worldpayFunction)
.to.be.calledWith('GET', '/orders/00000000-0000-0000-0000-000000000000');
});
});
});
describe('broken merchant key', () => {
beforeEach(() => {
sinon.stub(worldpay, 'worldpayFunction')
.callsArgWith(5, {
customCode: 'ORDER_NOT_FOUND'
});
account = {
AcquirerCipher: INVALID_SERVICE_KEY
};
});
it('should reject with invalid merchant details', () => {
return expect(wpAcquirer.validateMerchantAccount(account))
.to.eventually.be.rejectedWith({
name: acqErrors.INVALID_MERCHANT_ACCOUNT_DETAILS
});
});
});
describe('invalid merchant key', () => {
beforeEach(() => {
sinon.stub(worldpay, 'worldpayFunction')
.callsArgWith(5, {
customCode: 'UNAUTHORISED'
});
account = {
AcquirerCipher: VALID_SERVICE_KEY
};
});
it('should be rejected as unauthorised', () => {
return expect(wpAcquirer.validateMerchantAccount(account))
.to.eventually.be.rejectedWith({
name: acqErrors.ACQUIRER_UNAUTHORIZED
});
});
});
});
/**
* Tests for the payTransaction request
*/
describe('payTransaction', () => {
const DEFAULT_DATA = {
client: {
_id: CLIENT_ID,
ClientName: 'a@example.com',
KYC: [{
FirstName: 'John',
LastName: 'Doe'
}]
},
device: {
SessionToken: 'a session token'
},
data: {
ClientKey: CLIENT_KEY,
ipAddress: '127.0.0.1'
},
transaction: {
_id: TRANSACTION_ID,
TotalAmount: 123
},
merchantInfo: {
account: {
AcquirerName: 'worldpay',
AccountType: 'Credit/Debit Receiving Account',
AcquirerCipher: VALID_SERVICE_KEY
},
address: {}
},
customerInfo: {
account: {
AcquirerName: 'worldpay',
AccountType: 'Credit/Debit Payment Card',
CardPANEncrypted: VALID_CARD,
CardExpiryEncrypted: VALID_EXPIRY
},
address: {}
}
};
let testData;
afterEach(() => {
worldpay.worldpayFunction.restore();
});
describe('basic success', () => {
beforeEach(() => {
sinon.stub(worldpay, 'worldpayFunction')
.callsArgWith(5, null, {
orderCode: VOID_UUID,
customerOrderCode: TRANSACTION_ID,
riskScore: {
value: 1
},
paymentStatus: 'SUCCESS'
});
testData = _.cloneDeep(DEFAULT_DATA);
});
it('should resolve ok with valid data', () => {
return expect(
wpAcquirer.payTransaction(
testData.client,
testData.device,
testData.data,
testData.transaction,
testData.merchantInfo,
testData.customerInfo
)
).to.eventually.deep.equal({
SaleReference: VOID_UUID,
SaleAuthCode: TRANSACTION_ID,
RiskScore: 1,
AVSResponse: '',
GatewayResponse: 'SUCCESS'
});
});
it('should call the worldpayFunction once', () => {
return wpAcquirer.payTransaction(
testData.client,
testData.device,
testData.data,
testData.transaction,
testData.merchantInfo,
testData.customerInfo
).then(() => {
return expect(worldpay.worldpayFunction).to.be.calledOnce;
});
});
it('should request a POST to "orders"', () => {
return wpAcquirer.payTransaction(
testData.client,
testData.device,
testData.data,
testData.transaction,
testData.merchantInfo,
testData.customerInfo
).then(() => {
return expect(worldpay.worldpayFunction).to.be.calledWith('POST', 'orders');
});
});
it('should pass the correct key and worldpay body', () => {
return wpAcquirer.payTransaction(
testData.client,
testData.device,
testData.data,
testData.transaction,
testData.merchantInfo,
testData.customerInfo
).then(() => {
return expect(worldpay.worldpayFunction).to.be.calledWith(
'POST',
'orders',
TEST_SERVICE_KEY, // Properly decrypted
null, // No additional headers
sinon.match({
amount: 123, // Still in pennies
billingAddress: sinon.match.object,
deliveryAddress: sinon.match.object,
currencyCode: 'GBP',
name: 'John Doe', // Concatenated
orderDescription: sinon.match.string,
orderType: 'ECOM',
paymentMethod: sinon.match({
cardNumber: TEST_CARD_NO, // Properly decrypted
expiryMonth: '01', // Decrypted && split
expiryYear: '2023' // Decrypted, split && formatted
}),
settlementCurrency: 'GBP',
shopperEmailAddress: sinon.match.string,
shopperIpAddress: sinon.match.string,
shopperSessionID: sinon.match.string
})
);
});
});
});
describe('basic failures', () => {
beforeEach(() => {
sinon.stub(worldpay, 'worldpayFunction')
.callsArgWith(5, null, {
orderCode: VOID_UUID,
customerOrderCode: TRANSACTION_ID,
riskScore: {
value: 1
},
paymentStatus: 'SUCCESS'
});
testData = _.cloneDeep(DEFAULT_DATA);
});
it('should reject demo cards', () => {
testData.customerInfo.account.AccountType = 'Demo';
return expect(
wpAcquirer.payTransaction(
testData.client,
testData.device,
testData.data,
testData.transaction,
testData.merchantInfo,
testData.customerInfo
)
).to.eventually.be.rejected;
});
it('should reject if cant decrypt card number', () => {
testData.customerInfo.account.CardPANEncrypted = 'NotValid';
return expect(
wpAcquirer.payTransaction(
testData.client,
testData.device,
testData.data,
testData.transaction,
testData.merchantInfo,
testData.customerInfo
)
).to.eventually.be.rejected;
});
it('should reject if card expiry is missing', () => {
delete testData.customerInfo.account.CardExpiryEncrypted;
return expect(
wpAcquirer.payTransaction(
testData.client,
testData.device,
testData.data,
testData.transaction,
testData.merchantInfo,
testData.customerInfo
)
).to.eventually.be.rejected;
});
it('should reject if cant decrypt merchant service key', () => {
testData.merchantInfo.account.AcquirerCipher = 'NotValid';
return expect(
wpAcquirer.payTransaction(
testData.client,
testData.device,
testData.data,
testData.transaction,
testData.merchantInfo,
testData.customerInfo
)
).to.eventually.be.rejected;
});
it('should reject if not given a credit card', () => {
testData.customerInfo.account.AccountType = 'Credit/ Debit Receiving Account';
return expect(
wpAcquirer.payTransaction(
testData.client,
testData.device,
testData.data,
testData.transaction,
testData.merchantInfo,
testData.customerInfo
)
).to.eventually.be.rejected;
});
});
});
});