Skip to content

Commit

Permalink
Merge pull request #224 from recurly/three-d-secure-onready
Browse files Browse the repository at this point in the history
Adds onReady and re-render protection to ThreeDSecureAction
  • Loading branch information
douglasmiller authored May 13, 2024
2 parents b806c1c + 054cd52 commit 86d5a48
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 0 deletions.
15 changes: 15 additions & 0 deletions lib/three-d-secure-action.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ export default class ThreeDSecureAction extends React.PureComponent {
*/
actionTokenId: PropTypes.string,

/**
* Called when the 3-D Secure flow is ready for interaction
* @type {ThreeDSecureAction~onReady}
*/

/**
* @callback ThreeDSecureAction~onReady
*/
onReady: PropTypes.func,

/**
* Called when the user has completed the 3D Secure flow
* @type {ThreeDSecureAction~onToken}
Expand Down Expand Up @@ -47,6 +57,7 @@ export default class ThreeDSecureAction extends React.PureComponent {
id: undefined,
className: undefined,
actionTokenId: '',
onReady: () => {},
onToken: () => {},
onError: e => { throw e }
};
Expand All @@ -62,15 +73,19 @@ export default class ThreeDSecureAction extends React.PureComponent {

const { actionTokenId } = props;

this._attached = false;
this._container = React.createRef();
this._risk = this.context.recurly.Risk();
this._threeDSecure = this._risk.ThreeDSecure({ actionTokenId });
this._threeDSecure.on('ready', (...args) => this.props.onReady(...args));
this._threeDSecure.on('token', (...args) => this.props.onToken(...args));
this._threeDSecure.on('error', (...args) => this.props.onError(...args));
}

componentDidMount () {
if (this._attached) return;
this._threeDSecure.attach(this._container.current);
this._attached = true;
}

render () {
Expand Down
25 changes: 25 additions & 0 deletions test/three-d-secure-action.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,31 @@ describe('<ThreeDSecureAction />', function () {
describe('event handlers', function () {
const example = { arbitrary: 'properties' };

describe('[onReady]', function () {
it('is called when the underlying ThreeDSecure instance is ready', function () {
const subject = jest.fn();
let fixture;

render(withRecurlyProvider(
<ThreeDSecureAction
actionTokenId="test-action-token"
onReady={subject}
ref={ref => fixture = ref}
/>
));

const instance = getThreeDSecureInstanceFrom(fixture);

// stub strategy so that the readiness chain will not fall apart
instance.strategy = {
attach: () => {}
};

instance.emit('ready');
expect(subject).toHaveBeenCalled();
});
});

describe('[onToken]', function () {
it('is called when the underlying ThreeDSecure instance receives a token', function () {
const subject = jest.fn();
Expand Down
1 change: 1 addition & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ export type ThreeDSecureActionProps = {
id?: string;
className?: string;
actionTokenId?: string;
onReady?: () => void;
onToken?: (token: TokenPayload) => void;
onError?: (e: RecurlyError) => void;
};
Expand Down

0 comments on commit 86d5a48

Please sign in to comment.