-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(recaptcha v3 component): state update warning
* add component priv. prop to keep track of unmounting * check in grecaptcha.execute.then() for unmounting before proceeding * move getToken method call from constructor to componentDidMount * refactor tests to smaller files * add tests for provider being loaded before the component * add tests for unmount of component before the grecaptcha.execute resolves fix #32
- Loading branch information
Showing
4 changed files
with
218 additions
and
29 deletions.
There are no files selected for viewing
105 changes: 105 additions & 0 deletions
105
src/reCaptchaV3/component/ReCaptchaV3.test/withProviderLoaded.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import { render, RenderResult } from '@testing-library/react'; | ||
import * as React from 'react'; | ||
import { IContext } from 'src/provider/IContext'; | ||
import { ReCaptchaV3 } from 'src/reCaptchaV3/component/ReCaptchaV3'; | ||
import { TCallback } from 'src/reCaptchaV3/component/TCallback'; | ||
import { TRefreshToken } from 'src/reCaptchaV3/component/TRefreshToken'; | ||
|
||
// mocked global functions types | ||
declare let global: { | ||
grecaptcha: { | ||
render: jest.Mock; | ||
reset: jest.Mock; | ||
getResponse: jest.Mock; | ||
execute: jest.Mock<(siteKey: string, options?: options) => Promise<string>>; | ||
}; | ||
}; | ||
|
||
describe('ReCaptchaV3 component', (): void => { | ||
let callback: jest.Mock<TCallback>; | ||
let refreshTokenFn: TRefreshToken | undefined; | ||
let providerContext: IContext; | ||
let rr: RenderResult; | ||
let node: ChildNode | null; | ||
|
||
describe('with a V3 site key but providerContext.loaded:true', (): void => { | ||
beforeEach((): void => { | ||
callback = jest | ||
.fn() | ||
.mockImplementation( | ||
(token: string | void, refreshToken: TRefreshToken | void): void => { | ||
if (refreshToken) { | ||
refreshTokenFn = refreshToken; | ||
} | ||
} | ||
); | ||
refreshTokenFn = undefined; | ||
// mock the google reCaptcha object | ||
global.grecaptcha = { | ||
render: jest.fn(), | ||
reset: jest.fn(), | ||
getResponse: jest.fn(), | ||
execute: jest | ||
.fn() | ||
.mockImplementation( | ||
(siteKey: string, options?: options): Promise<string> => | ||
Promise.resolve('test-token') | ||
) | ||
}; | ||
providerContext = { | ||
siteKeyV2: undefined, | ||
siteKeyV3: 'test', | ||
loaded: true | ||
}; | ||
rr = render( | ||
<ReCaptchaV3 | ||
action="test-action" | ||
callback={callback} | ||
providerContext={providerContext} | ||
/> | ||
); | ||
node = rr.container.firstChild; | ||
}); | ||
|
||
it('renders nothing', (): void => { | ||
expect(node).toBeFalsy(); | ||
}); | ||
|
||
it('invokes the google reCaptcha execute once', (): void => { | ||
expect(global.grecaptcha.execute).toHaveBeenCalledTimes(1); | ||
}); | ||
|
||
it('invokes the callback twice', (): void => { | ||
expect(callback).toHaveBeenCalledTimes(2); | ||
}); | ||
|
||
it('invokes the callback without any arguments', (): void => { | ||
expect(callback).toHaveBeenNthCalledWith(1); | ||
}); | ||
|
||
it('invokes the callback with the token and refreshToken function', (): void => { | ||
expect(callback).toHaveBeenNthCalledWith( | ||
2, | ||
'test-token', | ||
expect.any(Function) | ||
); | ||
}); | ||
|
||
it('sets the refresh token function', (): void => { | ||
expect(refreshTokenFn).toBeInstanceOf(Function); | ||
}); | ||
|
||
describe('refresh token function', (): void => { | ||
beforeEach((): void => { | ||
global.grecaptcha.execute.mockClear(); | ||
if (refreshTokenFn) { | ||
refreshTokenFn(); | ||
} | ||
}); | ||
|
||
it('invokes the google reCaptcha execute once', (): void => { | ||
expect(global.grecaptcha.execute).toHaveBeenCalledTimes(1); | ||
}); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
32 changes: 32 additions & 0 deletions
32
src/reCaptchaV3/component/ReCaptchaV3.test/withoutV3SiteKey.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { IContext } from 'src/provider/IContext'; | ||
import { ReCaptchaV3 } from 'src/reCaptchaV3/component/ReCaptchaV3'; | ||
import { TCallback } from 'src/reCaptchaV3/component/TCallback'; | ||
|
||
describe('ReCaptchaV3 component', (): void => { | ||
let callback: jest.Mock<TCallback>; | ||
let providerContext: IContext; | ||
|
||
describe('without the V3 site key', (): void => { | ||
beforeEach((): void => { | ||
callback = jest.fn(); | ||
providerContext = { | ||
siteKeyV2: undefined, | ||
siteKeyV3: undefined, | ||
loaded: false | ||
}; | ||
}); | ||
|
||
it('throws an Error', (): void => { | ||
expect( | ||
(): ReCaptchaV3 => | ||
new ReCaptchaV3({ | ||
action: 'test-action', | ||
callback, | ||
providerContext: providerContext | ||
}) | ||
).toThrow( | ||
'The prop "siteKeyV3" must be set on the ReCaptchaProvider before using the ReCaptchaV3 component' | ||
); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters