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_CLIENT_ID, TEST_CODE_CHALLENGE, TEST_DOMAIN } from '../constants' import type { ICache } from '../../src/cache' import { assertUrlEquals, loginWithRedirectFn, setupFn } 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 mockCache: ICache = { set: jest.fn().mockResolvedValue(null), get: jest.fn().mockResolvedValue(null), remove: jest.fn().mockResolvedValue(null), } 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('constructor', () => { it('automatically adds the online_access scope during construction', () => { const authc = setup({ useRefreshTokens: true, scope: 'test-scope', }) expect((authc).scope).toBe('test-scope online_access') }) it('ensures the openid scope is defined when customizing default scopes', () => { const authc = setup({ advancedOptions: { defaultScope: 'test-scope', }, }) expect((authc).defaultScope).toBe('openid test-scope') }) it('allows an empty custom default scope', () => { const authc = setup({ advancedOptions: { defaultScope: null, }, }) expect((authc).defaultScope).toBe('openid') }) it('should create issuer from domain', () => { const authc = setup({ domain: 'test.dev', }) expect((authc).tokenIssuer).toEqual('https://test.dev') }) it('should allow issuer as a domain', () => { const authc = setup({ issuer: 'foo.bar.com', }) expect((authc).tokenIssuer).toEqual('https://foo.bar.com') }) it('should allow issuer as a fully qualified url', () => { const authc = setup({ issuer: 'https://some.issuer.com/', }) expect((authc).tokenIssuer).toEqual('https://some.issuer.com/') }) it('should allow specifying domain with http scheme', () => { const authc = setup({ domain: 'http://localhost', }) expect((authc).domainUrl).toEqual('http://localhost') }) it('should allow specifying domain with https scheme', () => { const authc = setup({ domain: 'https://localhost', }) expect((authc).domainUrl).toEqual('https://localhost') }) it('uses a custom cache if one was given in the configuration', async () => { const authc = setup({ cache: mockCache, }) await loginWithRedirectFn(mockWindow, mockFetch)(authc) expect(mockCache.set).toHaveBeenCalled() }) it('uses a custom cache if both `cache` and `cacheLocation` were specified', async () => { const authc = setup({ cache: mockCache, cacheLocation: 'localstorage', }) await loginWithRedirectFn(mockWindow, mockFetch)(authc) expect(mockCache.set).toHaveBeenCalled() }) }) describe('buildLogoutUrl', () => { it('creates correct query params with empty options', async () => { const authc = setup() const url = authc.buildLogoutUrl() assertUrlEquals(url, TEST_DOMAIN, '/oauth/logout', { client_id: TEST_CLIENT_ID, }) }) it('creates correct query params with `options.client_id` is null', async () => { const authc = setup() const url = new URL(authc.buildLogoutUrl({ client_id: null })) expect(url.searchParams.get('client_id')).toBeNull() }) it('creates correct query params with `options.client_id` defined', async () => { const authc = setup() const url = authc.buildLogoutUrl({ client_id: 'another-client-id' }) assertUrlEquals(url, TEST_DOMAIN, '/oauth/logout', { client_id: 'another-client-id', }) }) it('creates correct query params with `options.returnTo` defined', async () => { const authc = setup() const url = authc.buildLogoutUrl({ returnTo: 'https://return.to', client_id: null, }) assertUrlEquals(url, TEST_DOMAIN, '/oauth/logout', { returnTo: 'https://return.to', }) }) it('creates correct query params when `options.federated` is true', async () => { const authc = setup() const url = authc.buildLogoutUrl({ federated: true, client_id: null }) assertUrlEquals(url, TEST_DOMAIN, '/oauth/logout', { federated: '', }) }) }) })