import 'fast-text-encoding' import { MessageChannel } from 'worker_threads' import unfetch from 'unfetch' import { verify } from '../../src/jwt' import * as utils from '../../src/utils' import * as scope from '../../src/scope' // @ts-ignore import { TEST_ACCESS_TOKEN, TEST_CLIENT_ID, TEST_CODE_CHALLENGE, TEST_CODE_VERIFIER, TEST_ID_TOKEN, TEST_REDIRECT_URI, TEST_REFRESH_TOKEN, TEST_STATE, } from '../constants' import type { AuthcClientOptions } from '../../src' import { DEFAULT_AUTHC_CLIENT } from '../../src/constants' import { assertPostFn, fetchResponse, setupFn, setupMessageEventLister, } from './helpers' jest.mock('unfetch') jest.mock('es-cookie') jest.mock('../../src/jwt') jest.mock('../../src/worker/token.worker') const mockWindow = global const mockFetch = (mockWindow.fetch = unfetch) const mockVerify = verify const assertPost = assertPostFn(mockFetch) jest .spyOn(utils, 'bufferToBase64UrlEncoded') .mockReturnValue(TEST_CODE_CHALLENGE) jest.spyOn(utils, 'runPopup') const setup = setupFn(mockVerify) describe('AuthcClient', () => { const oldWindowLocation = window.location beforeEach(() => { // https://www.benmvp.com/blog/mocking-window-location-methods-jest-jsdom/ delete window.location window.location = Object.defineProperties( {}, { ...Object.getOwnPropertyDescriptors(oldWindowLocation), assign: { configurable: true, value: jest.fn(), }, }, ) as Location // -- mockWindow.open = jest.fn() mockWindow.addEventListener = jest.fn() mockWindow.crypto = { subtle: { digest: () => 'foo', }, getRandomValues() { return '123' }, } mockWindow.MessageChannel = MessageChannel mockWindow.Worker = {} jest.spyOn(scope, 'getUniqueScopes') sessionStorage.clear() }) afterEach(() => { mockFetch.mockReset() jest.clearAllMocks() window.location = oldWindowLocation }) describe('getTokenWithPopup()', () => { const localSetup = async (clientOptions?: Partial) => { const authc = setup(clientOptions) setupMessageEventLister(mockWindow, { state: TEST_STATE }) mockFetch.mockResolvedValueOnce( fetchResponse(true, { id_token: TEST_ID_TOKEN, refresh_token: TEST_REFRESH_TOKEN, access_token: TEST_ACCESS_TOKEN, expires_in: 86400, }), ) return authc } it('calls `loginWithPopup` with the correct default options', async () => { const authc = await localSetup() expect(await authc.getTokenWithPopup()).toEqual(TEST_ACCESS_TOKEN) }) it('respects customized scopes', async () => { const authc = await localSetup({ advancedOptions: { defaultScope: 'email', }, scope: 'read:email', }) const config = { popup: { location: { href: '', }, close: jest.fn(), }, } expect(await authc.getTokenWithPopup({}, config)).toEqual( TEST_ACCESS_TOKEN, ) expect(config.popup.location.href).toMatch( /openid%20email%20read%3Aemail/, ) }) it('passes custom login options', async () => { const authc = await localSetup() const loginOptions = { audience: 'other-audience', screen_hint: 'signup', } const config = { popup: { location: { href: '', }, close: jest.fn(), }, } await authc.getTokenWithPopup(loginOptions, config) expect(config.popup.location.href).toMatch(/other-audience/) expect(config.popup.location.href).toMatch(/screen_hint/) }) it('should use form data if useFormData is true', async () => { const authc = await localSetup({ useFormData: true, }) const loginOptions = { audience: 'other-audience', screen_hint: 'signup', } const config = { popup: { location: { href: '', }, close: jest.fn(), }, } await authc.getTokenWithPopup(loginOptions, config) assertPost( 'https://authc_domain/oauth/token', { redirect_uri: TEST_REDIRECT_URI, client_id: TEST_CLIENT_ID, code_verifier: TEST_CODE_VERIFIER, grant_type: 'authorization_code', }, { 'Authc-Client': btoa(JSON.stringify(DEFAULT_AUTHC_CLIENT)), 'Content-Type': 'application/x-www-form-urlencoded', }, 0, false, ) }) it('can use the global audience', async () => { const authc = await localSetup({ audience: 'global-audience', }) const config = { popup: { location: { href: '', }, close: jest.fn(), }, } await authc.getTokenWithPopup({}, config) expect(config.popup.location.href).toMatch(/global-audience/) }) }) })