358 lines
13 KiB
JavaScript
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;
|
|
});
|
|
});
|
|
});
|
|
});
|