diff --git a/lib/recurly/risk/risk.js b/lib/recurly/risk/risk.js index 37b67bf5..c9affe8e 100644 --- a/lib/recurly/risk/risk.js +++ b/lib/recurly/risk/risk.js @@ -56,7 +56,15 @@ export class Risk { * @return {Promise} */ static preflight ({ recurly, number, month, year, cvv }) { - return recurly.request.get({ route: Risk.resolveRoute(recurly) }) + function resolveRoute (recurly) { + let route = '/risk/preflights' + if (recurly.config.risk.threeDSecure.proactive.enabled) { + route += `?proactive=true&gatewayCode=${recurly.config.risk.threeDSecure.proactive.gateway_code}` + } + return route + } + + return recurly.request.get({ route: resolveRoute(recurly) }) .then(({ preflights }) => { debug('received preflight instructions', preflights); return ThreeDSecure.preflight({ recurly, number, month, year, cvv, preflights }); @@ -70,14 +78,6 @@ export class Risk { })); } - static resolveRoute (recurly) { - let route = '/risk/preflights' - if (recurly.config.risk.threeDSecure.proactive.enabled) { - route += `?proactive=true&gatewayCode=${recurly.config.risk.threeDSecure.proactive.gateway_code}` - } - return route; - } - constructor ({ recurly }) { this.recurly = recurly; this.concerns = []; diff --git a/lib/util/readiness-emitter.js b/lib/util/readiness-emitter.js index 206f0edd..d6135669 100644 --- a/lib/util/readiness-emitter.js +++ b/lib/util/readiness-emitter.js @@ -19,6 +19,7 @@ export default class ReadinessEmitter extends Emitter { * @return {[type]} [description] */ markReady () { + console.log('look we are ready') this._ready = true; this.emit('ready'); } diff --git a/packages/public-api-fixture-server/fixtures/tokens/proactive-token-test.json b/packages/public-api-fixture-server/fixtures/tokens/proactive-token-test.json new file mode 100644 index 00000000..98d1209d --- /dev/null +++ b/packages/public-api-fixture-server/fixtures/tokens/proactive-token-test.json @@ -0,0 +1,13 @@ +{ + "type": "three_d_secure_proactive_action", + "id": "proactive-token-test", + "gateway": { + "code": "1234567890", + "type": "test" + }, + "three_d_secure": { + "params": { + "challengeType": "challenge" + } + } +} diff --git a/test/unit/risk.test.js b/test/unit/risk.test.js index 674bbcf0..61d89565 100644 --- a/test/unit/risk.test.js +++ b/test/unit/risk.test.js @@ -85,6 +85,19 @@ describe('Risk', function () { }); }); + it('appends proactive data to the preflight request when enabled', function (done) { + const { recurly, sandbox, bin } = this; + recurly.config.risk.threeDSecure.proactive.enabled = true; + recurly.config.risk.threeDSecure.proactive.gateway_code = 'test-gateway-code'; + sandbox.spy(recurly.request, 'get'); + Risk.preflight({ recurly, bin }) + .done(results => { + assert(recurly.request.get.calledOnce); + assert(recurly.request.get.calledWithMatch({ route: '/risk/preflights?proactive=true&gatewayCode=test-gateway-code' })); + done(); + }); + }); + describe('when some results are timeouts', function () { beforeEach(function () { this.stubPreflightResults = [ diff --git a/test/unit/risk/three-d-secure.test.js b/test/unit/risk/three-d-secure.test.js index d453d175..a65abb87 100644 --- a/test/unit/risk/three-d-secure.test.js +++ b/test/unit/risk/three-d-secure.test.js @@ -19,6 +19,7 @@ describe('ThreeDSecure', function () { beforeEach(function (done) { const actionTokenId = this.actionTokenId = 'action-token-test'; + const proactiveTokenId = this.proactiveTokenId = 'proactive-token-test'; const recurly = this.recurly = initRecurly(); const risk = this.risk = { add: sinon.stub(), remove: sinon.stub(),concerns: [], recurly }; const sandbox = this.sandbox = sinon.createSandbox(); @@ -179,9 +180,17 @@ describe('ThreeDSecure', function () { new ThreeDSecure({ risk }); }, /Option actionTokenId must be a three_d_secure_action_token_id/); }); + + it('does not throw an error if proactiveTokenId is provided instead', function () { + const { risk, proactiveTokenId } = this; + + assert.doesNotThrow(() => { + new ThreeDSecure({ risk, proactiveTokenId }); + }); + }); }); - describe('when an actionTokenId is valid', function () { + describe.only('when an actionTokenId is valid', function () { it('sets the strategy according to the gateway type of the action token', function (done) { const { risk } = this; [ @@ -242,6 +251,68 @@ describe('ThreeDSecure', function () { }); }); + describe.only('when a proactiveTokenId is provided', function () { + it('throws an error if it is not valid', function (done) { + const { risk } = this; + const threeDSecure = new ThreeDSecure({ risk, proactiveTokenId: 'invalid-token-id' }); + + threeDSecure.on('error', err => { + assert.strictEqual(err.code, 'not-found'); + assert.strictEqual(err.message, 'Token not found'); + done(); + }); + }); + + it('sets the strategy to TestStrategy', function (done) { + const { risk, proactiveTokenId } = this; + const threeDSecure = new ThreeDSecure({ risk, proactiveTokenId }); + threeDSecure.whenReady(() => { + assert(threeDSecure.strategy instanceof TestStrategy); + done(); + }); + }); + + it('constructs the strategy with the proactive token', function (done) { + const { risk, proactiveTokenId } = this; + const threeDSecure = new ThreeDSecure({ risk, proactiveTokenId }); + threeDSecure.whenReady(() => { + const { strategy } = threeDSecure; + assert(strategy instanceof TestStrategy); + assert.strictEqual(strategy.proactiveToken.id, proactiveTokenId); + done(); + }); + }); + + it('reports the strategy name', function (done) { + const { risk, proactiveTokenId } = this; + + const threeDSecure = new ThreeDSecure({ risk, proactiveTokenId }); + risk.recurly.reporter.send.reset(); + + threeDSecure.whenReady(() => { + assert(risk.recurly.reporter.send.calledOnce); + assert(risk.recurly.reporter.send.calledWithMatch( + 'three-d-secure:ready', + { concernId: threeDSecure.id, strategy: 'test' } + )); + done(); + }); + }); + + it('calls onStrategyDone when a strategy completes', function (done) { + const { sandbox, threeDSecure } = this; + const example = { arbitrary: 'test-payload' }; + sandbox.spy(threeDSecure, 'onStrategyDone'); + + threeDSecure.whenReady(() => { + threeDSecure.strategy.emit('done', example); + assert(threeDSecure.onStrategyDone.calledOnce); + assert(threeDSecure.onStrategyDone.calledWithMatch(example)); + done(); + }); + }); + }); + describe('challengeWindowSize', function() { it('validates', function () { const challengeWindowSize = 'xx'; diff --git a/test/unit/token.test.js b/test/unit/token.test.js index cc468012..cdb412a5 100644 --- a/test/unit/token.test.js +++ b/test/unit/token.test.js @@ -8,7 +8,7 @@ import { Recurly } from '../../lib/recurly'; import { applyFixtures } from './support/fixtures'; import { initRecurly, testBed } from './support/helpers'; -describe.only(`Recurly.token`, function () { +describe(`Recurly.token`, function () { // Some of these tests can take a while to stand up fields and receive reponses this.timeout(15000); @@ -317,7 +317,7 @@ describe.only(`Recurly.token`, function () { }); }); - describe.only('when given an invalid json response', function () { + describe('when given an invalid json response', function () { prepareExample(Object.assign({}, valid, { number: '5454545454545454' }), builder);