Skip to content

Commit a4b5321

Browse files
committed
Add tests to authTokenManagers.bearer()
1 parent 471ebd1 commit a4b5321

File tree

1 file changed

+138
-1
lines changed

1 file changed

+138
-1
lines changed

packages/core/test/auth-token-manager.test.ts

Lines changed: 138 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
* limitations under the License.
1818
*/
1919
import { auth } from '../src'
20-
import AuthTokenManager, { SecurityErrorCode, authTokenManagers } from '../src/auth-token-manager'
20+
import AuthTokenManager, { AuthTokenAndExpiration, SecurityErrorCode, authTokenManagers } from '../src/auth-token-manager'
2121
import { AuthToken } from '../src/types'
2222

2323
describe('authTokenManagers', () => {
@@ -158,6 +158,143 @@ describe('authTokenManagers', () => {
158158
})
159159
})
160160
})
161+
162+
describe('.bearer()', () => {
163+
const BEARER_HANDLED_ERROR_CODES = Object.freeze(['Neo.ClientError.Security.Unauthorized', 'Neo.ClientError.Security.TokenExpired'])
164+
const BEARER_NOT_HANDLED_ERROR_CODES = Object.freeze(SECURITY_ERROR_CODES.filter(code => !BEARER_HANDLED_ERROR_CODES.includes(code)))
165+
166+
it.each([
167+
undefined,
168+
null,
169+
{},
170+
{ tokenProvider: null },
171+
{ tokenProvider: undefined },
172+
{ tokenProvider: false },
173+
{ tokenProvider: auth.bearer('THE BEAR') }
174+
])('should throw when instantiate with wrong parameters (params=%o)', (param) => {
175+
// @ts-expect-error
176+
expect(() => authTokenManagers.bearer(param)).toThrowError(TypeError)
177+
})
178+
179+
it('should create an AuthTokenManager instance', () => {
180+
const bearer: AuthTokenManager = authTokenManagers.bearer({
181+
tokenProvider: async () => {
182+
return {
183+
token: auth.bearer('bearer my_bear')
184+
}
185+
}
186+
})
187+
188+
expect(bearer).toBeDefined()
189+
expect(bearer.getToken).toBeInstanceOf(Function)
190+
expect(bearer.handleSecurityException).toBeInstanceOf(Function)
191+
})
192+
193+
describe('.handleSecurityException()', () => {
194+
let bearer: AuthTokenManager
195+
let tokenProvider: jest.Mock<Promise<AuthTokenAndExpiration>>
196+
let authToken: AuthToken
197+
198+
beforeEach(async () => {
199+
authToken = auth.bearer('bearer my_bear')
200+
tokenProvider = jest.fn(async () => ({ token: authToken }))
201+
bearer = authTokenManagers.bearer({ tokenProvider })
202+
// init auth token
203+
await bearer.getToken()
204+
tokenProvider.mockReset()
205+
})
206+
207+
describe.each(BEARER_HANDLED_ERROR_CODES)('when error code equals to "%s"', (code: SecurityErrorCode) => {
208+
describe('and same auth token', () => {
209+
it('should call tokenProvider and return true', () => {
210+
const handled = bearer.handleSecurityException(authToken, code)
211+
212+
expect(handled).toBe(true)
213+
expect(tokenProvider).toHaveBeenCalled()
214+
})
215+
216+
it('should call tokenProvider only if there is not an ongoing call', async () => {
217+
const promise = { resolve: (_: AuthTokenAndExpiration) => { } }
218+
tokenProvider.mockReturnValue(new Promise<AuthTokenAndExpiration>((resolve) => { promise.resolve = resolve }))
219+
220+
expect(bearer.handleSecurityException(authToken, code)).toBe(true)
221+
expect(tokenProvider).toHaveBeenCalled()
222+
223+
await triggerEventLoop()
224+
225+
expect(bearer.handleSecurityException(authToken, code)).toBe(true)
226+
expect(tokenProvider).toHaveBeenCalledTimes(1)
227+
228+
promise.resolve({ token: authToken })
229+
await triggerEventLoop()
230+
231+
expect(bearer.handleSecurityException(authToken, code)).toBe(true)
232+
expect(tokenProvider).toHaveBeenCalledTimes(2)
233+
234+
promise.resolve({ token: authToken })
235+
})
236+
})
237+
238+
describe('and different auth token', () => {
239+
const otherAuthToken = auth.bearer('bearer another_bear')
240+
241+
it('should return true and not call the provider', () => {
242+
const handled = bearer.handleSecurityException(otherAuthToken, code)
243+
244+
expect(handled).toBe(true)
245+
expect(tokenProvider).not.toHaveBeenCalled()
246+
})
247+
})
248+
})
249+
250+
it.each(BEARER_NOT_HANDLED_ERROR_CODES)('should not handle "%s"', (code: SecurityErrorCode) => {
251+
const handled = bearer.handleSecurityException(authToken, code)
252+
253+
expect(handled).toBe(false)
254+
expect(tokenProvider).not.toHaveBeenCalled()
255+
})
256+
})
257+
258+
describe('.getToken()', () => {
259+
let bearer: AuthTokenManager
260+
let tokenProvider: jest.Mock<Promise<AuthTokenAndExpiration>>
261+
let authToken: AuthToken
262+
263+
beforeEach(async () => {
264+
authToken = auth.bearer('bearer my_bear')
265+
tokenProvider = jest.fn(async () => ({ token: authToken }))
266+
bearer = authTokenManagers.bearer({ tokenProvider })
267+
})
268+
269+
it('should call tokenProvider once and return the provided token many times', async () => {
270+
await expect(bearer.getToken()).resolves.toBe(authToken)
271+
272+
expect(tokenProvider).toHaveBeenCalledTimes(1)
273+
274+
await expect(bearer.getToken()).resolves.toBe(authToken)
275+
await expect(bearer.getToken()).resolves.toBe(authToken)
276+
277+
expect(tokenProvider).toHaveBeenCalledTimes(1)
278+
})
279+
280+
it.each(BEARER_HANDLED_ERROR_CODES)('should reflect the authToken refreshed by handleSecurityException(authToken, "%s")', async (code: SecurityErrorCode) => {
281+
const newAuthToken = auth.bearer('bearer another_bear')
282+
await expect(bearer.getToken()).resolves.toBe(authToken)
283+
284+
expect(tokenProvider).toHaveBeenCalledTimes(1)
285+
286+
tokenProvider.mockReturnValueOnce(Promise.resolve({ token: newAuthToken }))
287+
288+
bearer.handleSecurityException(authToken, code)
289+
expect(tokenProvider).toHaveBeenCalledTimes(2)
290+
291+
await expect(bearer.getToken()).resolves.toBe(newAuthToken)
292+
await expect(bearer.getToken()).resolves.toBe(newAuthToken)
293+
294+
expect(tokenProvider).toHaveBeenCalledTimes(2)
295+
})
296+
})
297+
})
161298
})
162299

163300
async function triggerEventLoop (): Promise<unknown> {

0 commit comments

Comments
 (0)