From 316361bd3c444e6d8f58aaa69bfc2c5402aa7ecd Mon Sep 17 00:00:00 2001 From: lonelyhentxi Date: Fri, 31 Jan 2025 03:23:45 +0800 Subject: [PATCH] fix: fix observable --- biome.jsonc | 3 + package.json | 1 + pnpm-lock.yaml | 43 +-- scripts/code-transform.ts | 29 +- src/api/data.service.spec.ts | 57 ++-- src/auth-state/check-auth.service.spec.ts | 220 ++++++------- .../auto-login-partial-routes.guard.spec.ts | 184 +++++------ .../code-flow-callback.service.spec.ts | 28 +- .../implicit-flow-callback.service.spec.ts | 24 +- ...resh-session-refresh-token.service.spec.ts | 14 +- src/callback/refresh-session.service.spec.ts | 224 ++++++------- .../auth-well-known-data.service.spec.ts | 96 +++--- .../auth-well-known.service.spec.ts | 28 +- src/config/config.service.spec.ts | 126 ++++---- src/config/loader/config-loader.spec.ts | 37 +-- ...code-flow-callback-handler.service.spec.ts | 41 +-- ...-jwt-keys-callback-handler.service.spec.ts | 55 ++-- ...icit-flow-callback-handler.service.spec.ts | 32 +- ...h-session-callback-handler.service.spec.ts | 8 +- ...esh-token-callback-handler.service.spec.ts | 30 +- ...alidation-callback-handler.service.spec.ts | 8 +- .../user-callback-handler.service.spec.ts | 88 +++--- src/flows/flows.service.spec.ts | 70 ++-- src/http/index.ts | 7 +- src/iframe/check-session.service.spec.ts | 12 +- .../refresh-session-iframe.service.spec.ts | 8 +- src/iframe/silent-renew.service.spec.ts | 22 +- src/index.ts | 1 + src/interceptor/auth.interceptor.spec.ts | 45 ++- src/interceptor/auth.interceptor.ts | 6 +- src/login/login.service.spec.ts | 37 +-- src/login/par/par-login.service.spec.ts | 22 +- src/login/par/par.service.spec.ts | 10 +- src/login/popup/popup-login.service.spec.ts | 85 +++-- src/login/popup/popup.service.spec.ts | 8 +- .../logoff-revocation.service.spec.ts | 110 +++---- src/oidc.security.service.spec.ts | 5 +- .../public-events.service.spec.ts | 24 +- src/testing/http.ts | 9 + src/testing/index.ts | 1 + src/utils/url/url.service.spec.ts | 164 +++++----- .../jwk-window-crypto.service.spec.ts | 25 +- .../jwt-window-crypto.service.spec.ts | 5 +- .../state-validation.service.spec.ts | 298 ++++++++---------- .../token-validation.service.spec.ts | 89 ++---- 45 files changed, 1084 insertions(+), 1355 deletions(-) create mode 100644 src/testing/http.ts diff --git a/biome.jsonc b/biome.jsonc index 201671e..b6d086e 100644 --- a/biome.jsonc +++ b/biome.jsonc @@ -9,6 +9,9 @@ "suspicious": { "noExplicitAny": "off" }, + "complexity": { + "noForEach": "info" + }, "correctness": { "noUnusedImports": { "fix": "none", diff --git a/package.json b/package.json index 0a3e117..be9da36 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "@playwright/test": "^1.49.1", "@rslib/core": "^0.3.1", "@types/lodash-es": "^4.17.12", + "@types/node": "^22.12.0", "@vitest/coverage-v8": "^3.0.1", "commander": "^13.1.0", "lodash-es": "^4.17.21", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 36e0d79..d755b82 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -39,9 +39,12 @@ importers: '@types/lodash-es': specifier: ^4.17.12 version: 4.17.12 + '@types/node': + specifier: ^22.12.0 + version: 22.12.0 '@vitest/coverage-v8': specifier: ^3.0.1 - version: 3.0.1(vitest@3.0.1(@types/node@22.10.7)(tsx@4.19.2)) + version: 3.0.1(vitest@3.0.1(@types/node@22.12.0)(tsx@4.19.2)) commander: specifier: ^13.1.0 version: 13.1.0 @@ -71,7 +74,7 @@ importers: version: 4.1.15 vitest: specifier: ^3.0.1 - version: 3.0.1(@types/node@22.10.7)(tsx@4.19.2) + version: 3.0.1(@types/node@22.12.0)(tsx@4.19.2) packages: @@ -756,8 +759,8 @@ packages: '@types/lodash@4.17.15': resolution: {integrity: sha512-w/P33JFeySuhN6JLkysYUK2gEmy9kHHFN7E8ro0tkfmlDOgxBDzWEZ/J8cWA+fHqFevpswDTFZnDx+R9lbL6xw==} - '@types/node@22.10.7': - resolution: {integrity: sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg==} + '@types/node@22.12.0': + resolution: {integrity: sha512-Fll2FZ1riMjNmlmJOdAyY5pUbkftXslB5DgEzlIuNaiWhXd00FhWxVC/r4yV/4wBb9JfImTu+jiSvXTkJ7F/gA==} '@vitest/coverage-v8@3.0.1': resolution: {integrity: sha512-WpbI1QtkWpzMQTP5S3IneIWN714bOPcPFYp9Q9tXK9YgAtmMsrzKut0mFwSAu31CmbY0Q6Xsp15biO7Tjwp7UQ==} @@ -1741,12 +1744,11 @@ snapshots: '@types/lodash@4.17.15': {} - '@types/node@22.10.7': + '@types/node@22.12.0': dependencies: undici-types: 6.20.0 - optional: true - '@vitest/coverage-v8@3.0.1(vitest@3.0.1(@types/node@22.10.7)(tsx@4.19.2))': + '@vitest/coverage-v8@3.0.1(vitest@3.0.1(@types/node@22.12.0)(tsx@4.19.2))': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 1.0.2 @@ -1760,7 +1762,7 @@ snapshots: std-env: 3.8.0 test-exclude: 7.0.1 tinyrainbow: 2.0.0 - vitest: 3.0.1(@types/node@22.10.7)(tsx@4.19.2) + vitest: 3.0.1(@types/node@22.12.0)(tsx@4.19.2) transitivePeerDependencies: - supports-color @@ -1771,13 +1773,13 @@ snapshots: chai: 5.1.2 tinyrainbow: 2.0.0 - '@vitest/mocker@3.0.1(vite@6.0.7(@types/node@22.10.7)(tsx@4.19.2))': + '@vitest/mocker@3.0.1(vite@6.0.7(@types/node@22.12.0)(tsx@4.19.2))': dependencies: '@vitest/spy': 3.0.1 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: - vite: 6.0.7(@types/node@22.10.7)(tsx@4.19.2) + vite: 6.0.7(@types/node@22.12.0)(tsx@4.19.2) '@vitest/pretty-format@3.0.1': dependencies: @@ -2233,21 +2235,20 @@ snapshots: dependencies: commander: 12.1.0 - undici-types@6.20.0: - optional: true + undici-types@6.20.0: {} unplugin@1.16.1: dependencies: acorn: 8.14.0 webpack-virtual-modules: 0.6.2 - vite-node@3.0.1(@types/node@22.10.7)(tsx@4.19.2): + vite-node@3.0.1(@types/node@22.12.0)(tsx@4.19.2): dependencies: cac: 6.7.14 debug: 4.4.0 es-module-lexer: 1.6.0 pathe: 2.0.1 - vite: 6.0.7(@types/node@22.10.7)(tsx@4.19.2) + vite: 6.0.7(@types/node@22.12.0)(tsx@4.19.2) transitivePeerDependencies: - '@types/node' - jiti @@ -2262,20 +2263,20 @@ snapshots: - tsx - yaml - vite@6.0.7(@types/node@22.10.7)(tsx@4.19.2): + vite@6.0.7(@types/node@22.12.0)(tsx@4.19.2): dependencies: esbuild: 0.24.2 postcss: 8.5.1 rollup: 4.30.1 optionalDependencies: - '@types/node': 22.10.7 + '@types/node': 22.12.0 fsevents: 2.3.3 tsx: 4.19.2 - vitest@3.0.1(@types/node@22.10.7)(tsx@4.19.2): + vitest@3.0.1(@types/node@22.12.0)(tsx@4.19.2): dependencies: '@vitest/expect': 3.0.1 - '@vitest/mocker': 3.0.1(vite@6.0.7(@types/node@22.10.7)(tsx@4.19.2)) + '@vitest/mocker': 3.0.1(vite@6.0.7(@types/node@22.12.0)(tsx@4.19.2)) '@vitest/pretty-format': 3.0.1 '@vitest/runner': 3.0.1 '@vitest/snapshot': 3.0.1 @@ -2291,11 +2292,11 @@ snapshots: tinyexec: 0.3.2 tinypool: 1.0.2 tinyrainbow: 2.0.0 - vite: 6.0.7(@types/node@22.10.7)(tsx@4.19.2) - vite-node: 3.0.1(@types/node@22.10.7)(tsx@4.19.2) + vite: 6.0.7(@types/node@22.12.0)(tsx@4.19.2) + vite-node: 3.0.1(@types/node@22.12.0)(tsx@4.19.2) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 22.10.7 + '@types/node': 22.12.0 transitivePeerDependencies: - jiti - less diff --git a/scripts/code-transform.ts b/scripts/code-transform.ts index cc7c005..1adccd6 100644 --- a/scripts/code-transform.ts +++ b/scripts/code-transform.ts @@ -1,11 +1,6 @@ import assert from 'node:assert/strict'; import fsp from 'node:fs/promises'; -import { - type ClassElement, - type MagicString, - type Statement, - parseSync, -} from 'oxc-parser'; +import { type MagicString, type Statement, parseSync } from 'oxc-parser'; import { type Node, walk } from 'oxc-walker'; function sourceTextFromNode( @@ -35,6 +30,22 @@ export async function rewriteObservableSubscribeToLastValueFrom( const newChildren: T = [] as any as T; for (const child of children) { if ( + child.type === 'ExpressionStatement' && + child.expression.type === 'CallExpression' && + child.expression.callee.type === 'StaticMemberExpression' && + child.expression.callee.property.name === 'subscribe' && + child.expression.arguments.length === 0 + ) { + const newContent = `await lastValueFrom(${sourceTextFromNode(context, child.expression.callee.object)});`; + + const newStatements = parseSync('index.ts', newContent).program + .body as any[]; + + magicString.remove(child.start, child.end); + magicString.appendRight(child.start, newContent); + + newChildren.push(...newStatements); + } else if ( child.type === 'ExpressionStatement' && child.expression.type === 'CallExpression' && child.expression.callee.type === 'StaticMemberExpression' && @@ -72,7 +83,6 @@ export async function rewriteObservableSubscribeToLastValueFrom( } else { newChildren.push(child as any); } - return newChildren; } return newChildren; }; @@ -85,7 +95,6 @@ export async function rewriteObservableSubscribeToLastValueFrom( 'type' in node.body && node.body.type === 'FunctionBody' ) { - console.error('xxx', node.body.type); const children = node.body.statements; node.body.statements = transformExprs(children)!; } @@ -102,11 +111,7 @@ export async function rewriteAllObservableSubscribeToLastValueFrom( ) { const files = fsp.glob(pattern); for await (const file of files) { - const source = await fsp.readFile(file, 'utf-8'); const result = await rewriteObservableSubscribeToLastValueFrom(file); - if (source !== result) { - console.error('not equal'); - } await fsp.writeFile(file, result, 'utf-8'); } diff --git a/src/api/data.service.spec.ts b/src/api/data.service.spec.ts index 2061ae9..8caadb5 100644 --- a/src/api/data.service.spec.ts +++ b/src/api/data.service.spec.ts @@ -1,15 +1,9 @@ -import { TestBed } from '@/testing/testbed'; -import { - HttpHeaders, - provideHttpClient, - withInterceptorsFromDi, -} from '@ngify/http'; -import { - HttpTestingController, - provideHttpClientTesting, -} from '@ngify/http/testing'; +import { TestBed } from '@/testing'; +import { provideHttpClientTesting } from '@/testing/http'; +import { HttpHeaders } from '@ngify/http'; +import { HttpTestingController } from '@ngify/http/testing'; +import { provideHttpClient, withInterceptorsFromDi } from 'oidc-client-rx'; import { lastValueFrom } from 'rxjs'; -import { vi } from 'vitest'; import { DataService } from './data.service'; import { HttpBaseService } from './http-base.service'; @@ -39,11 +33,10 @@ describe('Data Service', () => { it('get call sets the accept header', async () => { const url = 'testurl'; - dataService - .get(url, { configId: 'configId1' }) - .subscribe((data: unknown) => { - expect(data).toBe('bodyData'); - }); + const data = await lastValueFrom( + dataService.get(url, { configId: 'configId1' }) + ); + expect(data).toBe('bodyData'); const req = httpMock.expectOne(url); expect(req.request.method).toBe('GET'); @@ -58,11 +51,10 @@ describe('Data Service', () => { const url = 'testurl'; const token = 'token'; - dataService - .get(url, { configId: 'configId1' }, token) - .subscribe((data: unknown) => { - expect(data).toBe('bodyData'); - }); + const data = await lastValueFrom( + dataService.get(url, { configId: 'configId1' }, token) + ); + expect(data).toBe('bodyData'); const req = httpMock.expectOne(url); expect(req.request.method).toBe('GET'); @@ -77,11 +69,10 @@ describe('Data Service', () => { it('call without ngsw-bypass param by default', async () => { const url = 'testurl'; - dataService - .get(url, { configId: 'configId1' }) - .subscribe((data: unknown) => { - expect(data).toBe('bodyData'); - }); + const data = await lastValueFrom( + dataService.get(url, { configId: 'configId1' }) + ); + expect(data).toBe('bodyData'); const req = httpMock.expectOne(url); expect(req.request.method).toBe('GET'); @@ -96,11 +87,10 @@ describe('Data Service', () => { it('call with ngsw-bypass param', async () => { const url = 'testurl'; - dataService - .get(url, { configId: 'configId1', ngswBypass: true }) - .subscribe((data: unknown) => { - expect(data).toBe('bodyData'); - }); + const data = await lastValueFrom( + dataService.get(url, { configId: 'configId1', ngswBypass: true }) + ); + expect(data).toBe('bodyData'); const req = httpMock.expectOne(`${url}?ngsw-bypass=`); expect(req.request.method).toBe('GET'); @@ -117,9 +107,8 @@ describe('Data Service', () => { it('call sets the accept header when no other params given', async () => { const url = 'testurl'; - dataService - .post(url, { some: 'thing' }, { configId: 'configId1' }) - .subscribe(); + await lastValueFrom(dataService + .post(url, { some: 'thing' }, { configId: 'configId1' })); const req = httpMock.expectOne(url); expect(req.request.method).toBe('POST'); diff --git a/src/auth-state/check-auth.service.spec.ts b/src/auth-state/check-auth.service.spec.ts index bef3f70..adac39f 100644 --- a/src/auth-state/check-auth.service.spec.ts +++ b/src/auth-state/check-auth.service.spec.ts @@ -153,13 +153,12 @@ describe('CheckAuthService', () => { ]; const spy = vi.spyOn(checkAuthService as any, 'checkAuthWithConfig'); - checkAuthService.checkAuth(allConfigs[0]!, allConfigs).subscribe(() => { - expect(spy).toHaveBeenCalledExactlyOnceWith( + await lastValueFrom(checkAuthService.checkAuth(allConfigs[0]!, allConfigs)); +expect(spy).toHaveBeenCalledExactlyOnceWith( { configId: 'configId1', authority: 'some-authority' }, allConfigs, undefined ); - }); }); it('returns null and sendMessageToMainWindow if currently in a popup', async () => { @@ -181,19 +180,17 @@ describe('CheckAuthService', () => { vi.spyOn(popUpService, 'isCurrentlyInPopup').mockReturnValue(true); const popupSpy = vi.spyOn(popUpService, 'sendMessageToMainWindow'); - checkAuthService - .checkAuth(allConfigs[0]!, allConfigs) - .subscribe((result) => { - expect(result).toEqual({ + const result = await lastValueFrom(checkAuthService + .checkAuth(allConfigs[0]!, allConfigs)); +expect(result).toEqual({ isAuthenticated: false, errorMessage: '', userData: null, idToken: '', accessToken: '', configId: '', - }); - expect(popupSpy).toHaveBeenCalled(); - }); + });; +expect(popupSpy).toHaveBeenCalled(); }); it('returns isAuthenticated: false with error message in case handleCallbackAndFireEvents throws an error', async () => { @@ -214,19 +211,17 @@ describe('CheckAuthService', () => { 'http://localhost:4200' ); - checkAuthService - .checkAuth(allConfigs[0]!, allConfigs) - .subscribe((result) => { - expect(result).toEqual({ + const result = await lastValueFrom(checkAuthService + .checkAuth(allConfigs[0]!, allConfigs)); +expect(result).toEqual({ isAuthenticated: false, errorMessage: 'ERROR', configId: 'configId1', idToken: '', userData: null, accessToken: '', - }); - expect(spy).toHaveBeenCalled(); - }); + });; +expect(spy).toHaveBeenCalled(); }); it('calls callbackService.handlePossibleStsCallback with current url when callback is true', async () => { @@ -248,18 +243,16 @@ describe('CheckAuthService', () => { .spyOn(callBackService, 'handleCallbackAndFireEvents') .mockReturnValue(of({} as CallbackContext)); - checkAuthService - .checkAuth(allConfigs[0]!, allConfigs) - .subscribe((result) => { - expect(result).toEqual({ + const result = await lastValueFrom(checkAuthService + .checkAuth(allConfigs[0]!, allConfigs)); +expect(result).toEqual({ isAuthenticated: true, userData: undefined, accessToken: 'at', configId: 'configId1', idToken: 'idt', - }); - expect(spy).toHaveBeenCalled(); - }); + });; +expect(spy).toHaveBeenCalled(); }); it('does NOT call handleCallbackAndFireEvents with current url when callback is false', async () => { @@ -282,18 +275,16 @@ describe('CheckAuthService', () => { vi.spyOn(authStateService, 'getAccessToken').mockReturnValue('at'); vi.spyOn(authStateService, 'getIdToken').mockReturnValue('idt'); - checkAuthService - .checkAuth(allConfigs[0]!, allConfigs) - .subscribe((result) => { - expect(result).toEqual({ + const result = await lastValueFrom(checkAuthService + .checkAuth(allConfigs[0]!, allConfigs)); +expect(result).toEqual({ isAuthenticated: true, userData: undefined, accessToken: 'at', configId: 'configId1', idToken: 'idt', - }); - expect(spy).not.toHaveBeenCalled(); - }); + });; +expect(spy).not.toHaveBeenCalled(); }); it('does fire the auth and user data events when it is not a callback from the security token service and is authenticated', async () => { @@ -323,10 +314,9 @@ describe('CheckAuthService', () => { ); const userServiceSpy = vi.spyOn(userService, 'publishUserDataIfExists'); - checkAuthService - .checkAuth(allConfigs[0]!, allConfigs) - .subscribe((result) => { - expect(result).toEqual({ + const result = await lastValueFrom(checkAuthService + .checkAuth(allConfigs[0]!, allConfigs)); +expect(result).toEqual({ isAuthenticated: true, userData: { some: 'user-data', @@ -334,10 +324,9 @@ describe('CheckAuthService', () => { accessToken: 'at', configId: 'configId1', idToken: 'idt', - }); - expect(setAuthorizedAndFireEventSpy).toHaveBeenCalled(); - expect(userServiceSpy).toHaveBeenCalled(); - }); + });; +expect(setAuthorizedAndFireEventSpy).toHaveBeenCalled();; +expect(userServiceSpy).toHaveBeenCalled(); }); it('does NOT fire the auth and user data events when it is not a callback from the security token service and is NOT authenticated', async () => { @@ -364,19 +353,17 @@ describe('CheckAuthService', () => { ); const userServiceSpy = vi.spyOn(userService, 'publishUserDataIfExists'); - checkAuthService - .checkAuth(allConfigs[0]!, allConfigs) - .subscribe((result) => { - expect(result).toEqual({ + const result = await lastValueFrom(checkAuthService + .checkAuth(allConfigs[0]!, allConfigs)); +expect(result).toEqual({ isAuthenticated: false, userData: undefined, accessToken: 'at', configId: 'configId1', idToken: 'it', - }); - expect(setAuthorizedAndFireEventSpy).not.toHaveBeenCalled(); - expect(userServiceSpy).not.toHaveBeenCalled(); - }); + });; +expect(setAuthorizedAndFireEventSpy).not.toHaveBeenCalled();; +expect(userServiceSpy).not.toHaveBeenCalled(); }); it('if authenticated return true', async () => { @@ -396,17 +383,15 @@ describe('CheckAuthService', () => { true ); - checkAuthService - .checkAuth(allConfigs[0]!, allConfigs) - .subscribe((result) => { - expect(result).toEqual({ + const result = await lastValueFrom(checkAuthService + .checkAuth(allConfigs[0]!, allConfigs)); +expect(result).toEqual({ isAuthenticated: true, userData: undefined, accessToken: 'at', configId: 'configId1', idToken: 'idt', }); - }); }); it('if authenticated set auth and fires event ', async () => { @@ -424,9 +409,8 @@ describe('CheckAuthService', () => { const spy = vi.spyOn(authStateService, 'setAuthenticatedAndFireEvent'); - checkAuthService.checkAuth(allConfigs[0]!, allConfigs).subscribe(() => { - expect(spy).toHaveBeenCalled(); - }); + await lastValueFrom(checkAuthService.checkAuth(allConfigs[0]!, allConfigs)); +expect(spy).toHaveBeenCalled(); }); it('if authenticated publishUserdataIfExists', async () => { @@ -446,9 +430,8 @@ describe('CheckAuthService', () => { const spy = vi.spyOn(userService, 'publishUserDataIfExists'); - checkAuthService.checkAuth(allConfigs[0]!, allConfigs).subscribe(() => { - expect(spy).toHaveBeenCalled(); - }); + await lastValueFrom(checkAuthService.checkAuth(allConfigs[0]!, allConfigs)); +expect(spy).toHaveBeenCalled(); }); it('if authenticated callbackService startTokenValidationPeriodically', async () => { @@ -472,9 +455,8 @@ describe('CheckAuthService', () => { 'startTokenValidationPeriodically' ); - checkAuthService.checkAuth(allConfigs[0]!, allConfigs).subscribe(() => { - expect(spy).toHaveBeenCalled(); - }); + await lastValueFrom(checkAuthService.checkAuth(allConfigs[0]!, allConfigs)); +expect(spy).toHaveBeenCalled(); }); it('if isCheckSessionConfigured call checkSessionService.start()', async () => { @@ -496,9 +478,8 @@ describe('CheckAuthService', () => { ); const spy = vi.spyOn(checkSessionService, 'start'); - checkAuthService.checkAuth(allConfigs[0]!, allConfigs).subscribe(() => { - expect(spy).toHaveBeenCalled(); - }); + await lastValueFrom(checkAuthService.checkAuth(allConfigs[0]!, allConfigs)); +expect(spy).toHaveBeenCalled(); }); it('if isSilentRenewConfigured call getOrCreateIframe()', async () => { @@ -520,9 +501,8 @@ describe('CheckAuthService', () => { ); const spy = vi.spyOn(silentRenewService, 'getOrCreateIframe'); - checkAuthService.checkAuth(allConfigs[0]!, allConfigs).subscribe(() => { - expect(spy).toHaveBeenCalled(); - }); + await lastValueFrom(checkAuthService.checkAuth(allConfigs[0]!, allConfigs)); +expect(spy).toHaveBeenCalled(); }); it('calls checkSavedRedirectRouteAndNavigate if authenticated', async () => { @@ -544,10 +524,9 @@ describe('CheckAuthService', () => { 'checkSavedRedirectRouteAndNavigate' ); - checkAuthService.checkAuth(allConfigs[0]!, allConfigs).subscribe(() => { - expect(spy).toHaveBeenCalledTimes(1); - expect(spy).toHaveBeenCalledExactlyOnceWith(allConfigs[0]); - }); + await lastValueFrom(checkAuthService.checkAuth(allConfigs[0]!, allConfigs)); +expect(spy).toHaveBeenCalledTimes(1);; +expect(spy).toHaveBeenCalledExactlyOnceWith(allConfigs[0]); }); it('does not call checkSavedRedirectRouteAndNavigate if not authenticated', async () => { @@ -566,9 +545,8 @@ describe('CheckAuthService', () => { 'checkSavedRedirectRouteAndNavigate' ); - checkAuthService.checkAuth(allConfigs[0]!, allConfigs).subscribe(() => { - expect(spy).toHaveBeenCalledTimes(0); - }); + await lastValueFrom(checkAuthService.checkAuth(allConfigs[0]!, allConfigs)); +expect(spy).toHaveBeenCalledTimes(0); }); it('fires CheckingAuth-Event on start and finished event on end', async () => { @@ -585,12 +563,11 @@ describe('CheckAuthService', () => { const fireEventSpy = vi.spyOn(publicEventsService, 'fireEvent'); - checkAuthService.checkAuth(allConfigs[0]!, allConfigs).subscribe(() => { - expect(fireEventSpy).toHaveBeenCalledWith([ + await lastValueFrom(checkAuthService.checkAuth(allConfigs[0]!, allConfigs)); +expect(fireEventSpy).toHaveBeenCalledWith([ [EventTypes.CheckingAuth], [EventTypes.CheckingAuthFinished], ]); - }); }); it('fires CheckingAuth-Event on start and CheckingAuthFinishedWithError event on end if exception occurs', async () => { @@ -607,12 +584,11 @@ describe('CheckAuthService', () => { 'http://localhost:4200' ); - checkAuthService.checkAuth(allConfigs[0]!, allConfigs).subscribe(() => { - expect(fireEventSpy).toHaveBeenCalledWith([ + await lastValueFrom(checkAuthService.checkAuth(allConfigs[0]!, allConfigs)); +expect(fireEventSpy).toHaveBeenCalledWith([ [EventTypes.CheckingAuth], [EventTypes.CheckingAuthFinishedWithError, 'ERROR'], ]); - }); }); it('fires CheckingAuth-Event on start and finished event on end if not authenticated', async () => { @@ -629,12 +605,11 @@ describe('CheckAuthService', () => { const fireEventSpy = vi.spyOn(publicEventsService, 'fireEvent'); - checkAuthService.checkAuth(allConfigs[0]!, allConfigs).subscribe(() => { - expect(fireEventSpy).toBeCalledWith([ + await lastValueFrom(checkAuthService.checkAuth(allConfigs[0]!, allConfigs)); +expect(fireEventSpy).toBeCalledWith([ [EventTypes.CheckingAuth], [EventTypes.CheckingAuthFinished], ]); - }); }); }); @@ -659,11 +634,9 @@ describe('CheckAuthService', () => { ); const spy = vi.spyOn(silentRenewService, 'getOrCreateIframe'); - checkAuthService - .checkAuthIncludingServer(allConfigs[0]!, allConfigs) - .subscribe(() => { - expect(spy).toHaveBeenCalled(); - }); + await lastValueFrom(checkAuthService + .checkAuthIncludingServer(allConfigs[0]!, allConfigs)); +expect(spy).toHaveBeenCalled(); }); it('does forceRefreshSession get called and is NOT authenticated', async () => { @@ -689,11 +662,9 @@ describe('CheckAuthService', () => { }) ); - checkAuthService - .checkAuthIncludingServer(allConfigs[0]!, allConfigs) - .subscribe((result) => { - expect(result).toBeTruthy(); - }); + const result = await lastValueFrom(checkAuthService + .checkAuthIncludingServer(allConfigs[0]!, allConfigs)); +expect(result).toBeTruthy(); }); it('should start check session and validation after forceRefreshSession has been called and is authenticated after forcing with silentrenew', async () => { @@ -738,17 +709,15 @@ describe('CheckAuthService', () => { }) ); - checkAuthService - .checkAuthIncludingServer(allConfigs[0]!, allConfigs) - .subscribe(() => { - expect(checkSessionServiceStartSpy).toHaveBeenCalledExactlyOnceWith( + await lastValueFrom(checkAuthService + .checkAuthIncludingServer(allConfigs[0]!, allConfigs)); +expect(checkSessionServiceStartSpy).toHaveBeenCalledExactlyOnceWith( + allConfigs[0] + );; +expect(periodicallyTokenCheckServiceSpy).toHaveBeenCalledTimes(1);; +expect(getOrCreateIframeSpy).toHaveBeenCalledExactlyOnceWith( allConfigs[0] ); - expect(periodicallyTokenCheckServiceSpy).toHaveBeenCalledTimes(1); - expect(getOrCreateIframeSpy).toHaveBeenCalledExactlyOnceWith( - allConfigs[0] - ); - }); }); it('should start check session and validation after forceRefreshSession has been called and is authenticated after forcing without silentrenew', async () => { @@ -793,15 +762,13 @@ describe('CheckAuthService', () => { }) ); - checkAuthService - .checkAuthIncludingServer(allConfigs[0]!, allConfigs) - .subscribe(() => { - expect(checkSessionServiceStartSpy).toHaveBeenCalledExactlyOnceWith( + await lastValueFrom(checkAuthService + .checkAuthIncludingServer(allConfigs[0]!, allConfigs)); +expect(checkSessionServiceStartSpy).toHaveBeenCalledExactlyOnceWith( allConfigs[0] - ); - expect(periodicallyTokenCheckServiceSpy).toHaveBeenCalledTimes(1); - expect(getOrCreateIframeSpy).not.toHaveBeenCalled(); - }); + );; +expect(periodicallyTokenCheckServiceSpy).toHaveBeenCalledTimes(1);; +expect(getOrCreateIframeSpy).not.toHaveBeenCalled(); }); }); @@ -823,20 +790,19 @@ describe('CheckAuthService', () => { ); const spy = vi.spyOn(checkAuthService as any, 'checkAuthWithConfig'); - checkAuthService.checkAuthMultiple(allConfigs).subscribe((result) => { - expect(Array.isArray(result)).toBe(true); - expect(spy).toHaveBeenCalledTimes(2); - expect(vi.mocked(spy).mock.calls[0]).toEqual([ + const result = await lastValueFrom(checkAuthService.checkAuthMultiple(allConfigs)); +expect(Array.isArray(result)).toBe(true);; +expect(spy).toHaveBeenCalledTimes(2);; +expect(vi.mocked(spy).mock.calls[0]).toEqual([ allConfigs[0]!, allConfigs, undefined, - ]); - expect(vi.mocked(spy).mock.calls[1]).toEqual([ + ]);; +expect(vi.mocked(spy).mock.calls[1]).toEqual([ allConfigs[1], allConfigs, undefined, ]); - }); }); it('uses config from passed configId if configId was passed and returns all results', async () => { @@ -852,9 +818,9 @@ describe('CheckAuthService', () => { const spy = vi.spyOn(checkAuthService as any, 'checkAuthWithConfig'); - checkAuthService.checkAuthMultiple(allConfigs).subscribe((result) => { - expect(Array.isArray(result)).toBe(true); - expect(spy).toBeCalledWith([ + const result = await lastValueFrom(checkAuthService.checkAuthMultiple(allConfigs)); +expect(Array.isArray(result)).toBe(true);; +expect(spy).toBeCalledWith([ [ { configId: 'configId1', authority: 'some-authority1' }, allConfigs, @@ -866,7 +832,6 @@ describe('CheckAuthService', () => { undefined, ], ]); - }); }); it('runs through all configs if no parameter is passed and has no state in url', async () => { @@ -882,20 +847,19 @@ describe('CheckAuthService', () => { const spy = vi.spyOn(checkAuthService as any, 'checkAuthWithConfig'); - checkAuthService.checkAuthMultiple(allConfigs).subscribe((result) => { - expect(Array.isArray(result)).toBe(true); - expect(spy).toHaveBeenCalledTimes(2); - expect(vi.mocked(spy).mock.calls[0]).toEqual([ + const result = await lastValueFrom(checkAuthService.checkAuthMultiple(allConfigs)); +expect(Array.isArray(result)).toBe(true);; +expect(spy).toHaveBeenCalledTimes(2);; +expect(vi.mocked(spy).mock.calls[0]).toEqual([ { configId: 'configId1', authority: 'some-authority1' }, allConfigs, undefined, - ]); - expect(vi.mocked(spy).mock.calls[1]).toEqual([ + ]);; +expect(vi.mocked(spy).mock.calls[1]).toEqual([ { configId: 'configId2', authority: 'some-authority2' }, allConfigs, undefined, ]); - }); }); it('throws error if url has state param but no config could be found', async () => { diff --git a/src/auto-login/auto-login-partial-routes.guard.spec.ts b/src/auto-login/auto-login-partial-routes.guard.spec.ts index 3e0b55c..a4a791c 100644 --- a/src/auto-login/auto-login-partial-routes.guard.spec.ts +++ b/src/auto-login/auto-login-partial-routes.guard.spec.ts @@ -83,23 +83,21 @@ describe('AutoLoginPartialRoutesGuard', () => { ); const loginSpy = vi.spyOn(loginService, 'login'); - guard + await lastValueFrom(guard .canActivate( {} as ActivatedRouteSnapshot, { url: 'some-url1' } as RouterStateSnapshot - ) - .subscribe(() => { - expect(saveRedirectRouteSpy).toHaveBeenCalledExactlyOnceWith( + )); +expect(saveRedirectRouteSpy).toHaveBeenCalledExactlyOnceWith( { configId: 'configId1' }, 'some-url1' - ); - expect(loginSpy).toHaveBeenCalledExactlyOnceWith({ + );; +expect(loginSpy).toHaveBeenCalledExactlyOnceWith({ configId: 'configId1', - }); - expect( + });; +expect( checkSavedRedirectRouteAndNavigateSpy ).not.toHaveBeenCalled(); - }); }); it('should save current route and call `login` if not authenticated already and add custom params', async () => { @@ -116,24 +114,22 @@ describe('AutoLoginPartialRoutesGuard', () => { ); const loginSpy = vi.spyOn(loginService, 'login'); - guard + await lastValueFrom(guard .canActivate( { data: { custom: 'param' } } as unknown as ActivatedRouteSnapshot, { url: 'some-url1' } as RouterStateSnapshot - ) - .subscribe(() => { - expect(saveRedirectRouteSpy).toHaveBeenCalledExactlyOnceWith( + )); +expect(saveRedirectRouteSpy).toHaveBeenCalledExactlyOnceWith( { configId: 'configId1' }, 'some-url1' - ); - expect(loginSpy).toHaveBeenCalledExactlyOnceWith( + );; +expect(loginSpy).toHaveBeenCalledExactlyOnceWith( { configId: 'configId1' }, { customParams: { custom: 'param' } } - ); - expect( + );; +expect( checkSavedRedirectRouteAndNavigateSpy ).not.toHaveBeenCalled(); - }); }); it('should call `checkSavedRedirectRouteAndNavigate` if authenticated already', async () => { @@ -150,18 +146,16 @@ describe('AutoLoginPartialRoutesGuard', () => { ); const loginSpy = vi.spyOn(loginService, 'login'); - guard + await lastValueFrom(guard .canActivate( {} as ActivatedRouteSnapshot, { url: 'some-url1' } as RouterStateSnapshot - ) - .subscribe(() => { - expect(saveRedirectRouteSpy).not.toHaveBeenCalled(); - expect(loginSpy).not.toHaveBeenCalled(); - expect( + )); +expect(saveRedirectRouteSpy).not.toHaveBeenCalled();; +expect(loginSpy).not.toHaveBeenCalled();; +expect( checkSavedRedirectRouteAndNavigateSpy ).toHaveBeenCalledExactlyOnceWith({ configId: 'configId1' }); - }); }); }); @@ -180,23 +174,21 @@ describe('AutoLoginPartialRoutesGuard', () => { ); const loginSpy = vi.spyOn(loginService, 'login'); - guard + await lastValueFrom(guard .canActivateChild( {} as ActivatedRouteSnapshot, { url: 'some-url1' } as RouterStateSnapshot - ) - .subscribe(() => { - expect(saveRedirectRouteSpy).toHaveBeenCalledExactlyOnceWith( + )); +expect(saveRedirectRouteSpy).toHaveBeenCalledExactlyOnceWith( { configId: 'configId1' }, 'some-url1' - ); - expect(loginSpy).toHaveBeenCalledExactlyOnceWith({ + );; +expect(loginSpy).toHaveBeenCalledExactlyOnceWith({ configId: 'configId1', - }); - expect( + });; +expect( checkSavedRedirectRouteAndNavigateSpy ).not.toHaveBeenCalled(); - }); }); it('should save current route and call `login` if not authenticated already with custom params', async () => { @@ -213,24 +205,22 @@ describe('AutoLoginPartialRoutesGuard', () => { ); const loginSpy = vi.spyOn(loginService, 'login'); - guard + await lastValueFrom(guard .canActivateChild( { data: { custom: 'param' } } as unknown as ActivatedRouteSnapshot, { url: 'some-url1' } as RouterStateSnapshot - ) - .subscribe(() => { - expect(saveRedirectRouteSpy).toHaveBeenCalledExactlyOnceWith( + )); +expect(saveRedirectRouteSpy).toHaveBeenCalledExactlyOnceWith( { configId: 'configId1' }, 'some-url1' - ); - expect(loginSpy).toHaveBeenCalledExactlyOnceWith( + );; +expect(loginSpy).toHaveBeenCalledExactlyOnceWith( { configId: 'configId1' }, { customParams: { custom: 'param' } } - ); - expect( + );; +expect( checkSavedRedirectRouteAndNavigateSpy ).not.toHaveBeenCalled(); - }); }); it('should call `checkSavedRedirectRouteAndNavigate` if authenticated already', async () => { @@ -247,18 +237,16 @@ describe('AutoLoginPartialRoutesGuard', () => { ); const loginSpy = vi.spyOn(loginService, 'login'); - guard + await lastValueFrom(guard .canActivateChild( {} as ActivatedRouteSnapshot, { url: 'some-url1' } as RouterStateSnapshot - ) - .subscribe(() => { - expect(saveRedirectRouteSpy).not.toHaveBeenCalled(); - expect(loginSpy).not.toHaveBeenCalled(); - expect( + )); +expect(saveRedirectRouteSpy).not.toHaveBeenCalled();; +expect(loginSpy).not.toHaveBeenCalled();; +expect( checkSavedRedirectRouteAndNavigateSpy ).toHaveBeenCalledExactlyOnceWith({ configId: 'configId1' }); - }); }); }); @@ -277,16 +265,15 @@ describe('AutoLoginPartialRoutesGuard', () => { ); const loginSpy = vi.spyOn(loginService, 'login'); - guard.canLoad().subscribe(() => { - expect(saveRedirectRouteSpy).toHaveBeenCalledExactlyOnceWith( + await lastValueFrom(guard.canLoad()); +expect(saveRedirectRouteSpy).toHaveBeenCalledExactlyOnceWith( { configId: 'configId1' }, '' - ); - expect(loginSpy).toHaveBeenCalledExactlyOnceWith({ + );; +expect(loginSpy).toHaveBeenCalledExactlyOnceWith({ configId: 'configId1', - }); - expect(checkSavedRedirectRouteAndNavigateSpy).not.toHaveBeenCalled(); - }); + });; +expect(checkSavedRedirectRouteAndNavigateSpy).not.toHaveBeenCalled(); }); it('should save current route (with router extractedUrl) and call `login` if not authenticated already', async () => { @@ -314,16 +301,15 @@ describe('AutoLoginPartialRoutesGuard', () => { trigger: 'imperative', }); - guard.canLoad().subscribe(() => { - expect(saveRedirectRouteSpy).toHaveBeenCalledExactlyOnceWith( + await lastValueFrom(guard.canLoad()); +expect(saveRedirectRouteSpy).toHaveBeenCalledExactlyOnceWith( { configId: 'configId1' }, 'some-url12/with/some-param?queryParam=true' - ); - expect(loginSpy).toHaveBeenCalledExactlyOnceWith({ + );; +expect(loginSpy).toHaveBeenCalledExactlyOnceWith({ configId: 'configId1', - }); - expect(checkSavedRedirectRouteAndNavigateSpy).not.toHaveBeenCalled(); - }); + });; +expect(checkSavedRedirectRouteAndNavigateSpy).not.toHaveBeenCalled(); }); it('should call `checkSavedRedirectRouteAndNavigate` if authenticated already', async () => { @@ -340,13 +326,12 @@ describe('AutoLoginPartialRoutesGuard', () => { ); const loginSpy = vi.spyOn(loginService, 'login'); - guard.canLoad().subscribe(() => { - expect(saveRedirectRouteSpy).not.toHaveBeenCalled(); - expect(loginSpy).not.toHaveBeenCalled(); - expect( + await lastValueFrom(guard.canLoad()); +expect(saveRedirectRouteSpy).not.toHaveBeenCalled();; +expect(loginSpy).not.toHaveBeenCalled();; +expect( checkSavedRedirectRouteAndNavigateSpy ).toHaveBeenCalledExactlyOnceWith({ configId: 'configId1' }); - }); }); }); }); @@ -398,16 +383,15 @@ describe('AutoLoginPartialRoutesGuard', () => { autoLoginPartialRoutesGuard ); - guard$.subscribe(() => { - expect(saveRedirectRouteSpy).toHaveBeenCalledExactlyOnceWith( + await lastValueFrom(guard$); +expect(saveRedirectRouteSpy).toHaveBeenCalledExactlyOnceWith( { configId: 'configId1' }, '' - ); - expect(loginSpy).toHaveBeenCalledExactlyOnceWith({ + );; +expect(loginSpy).toHaveBeenCalledExactlyOnceWith({ configId: 'configId1', - }); - expect(checkSavedRedirectRouteAndNavigateSpy).not.toHaveBeenCalled(); - }); + });; +expect(checkSavedRedirectRouteAndNavigateSpy).not.toHaveBeenCalled(); }); it('should save current route (with router extractedUrl) and call `login` if not authenticated already', async () => { @@ -439,16 +423,15 @@ describe('AutoLoginPartialRoutesGuard', () => { autoLoginPartialRoutesGuard ); - guard$.subscribe(() => { - expect(saveRedirectRouteSpy).toHaveBeenCalledExactlyOnceWith( + await lastValueFrom(guard$); +expect(saveRedirectRouteSpy).toHaveBeenCalledExactlyOnceWith( { configId: 'configId1' }, 'some-url12/with/some-param?queryParam=true' - ); - expect(loginSpy).toHaveBeenCalledExactlyOnceWith({ + );; +expect(loginSpy).toHaveBeenCalledExactlyOnceWith({ configId: 'configId1', - }); - expect(checkSavedRedirectRouteAndNavigateSpy).not.toHaveBeenCalled(); - }); + });; +expect(checkSavedRedirectRouteAndNavigateSpy).not.toHaveBeenCalled(); }); it('should save current route and call `login` if not authenticated already and add custom params', async () => { @@ -471,17 +454,16 @@ describe('AutoLoginPartialRoutesGuard', () => { } as unknown as ActivatedRouteSnapshot) ); - guard$.subscribe(() => { - expect(saveRedirectRouteSpy).toHaveBeenCalledExactlyOnceWith( + await lastValueFrom(guard$); +expect(saveRedirectRouteSpy).toHaveBeenCalledExactlyOnceWith( { configId: 'configId1' }, '' - ); - expect(loginSpy).toHaveBeenCalledExactlyOnceWith( + );; +expect(loginSpy).toHaveBeenCalledExactlyOnceWith( { configId: 'configId1' }, { customParams: { custom: 'param' } } - ); - expect(checkSavedRedirectRouteAndNavigateSpy).not.toHaveBeenCalled(); - }); + );; +expect(checkSavedRedirectRouteAndNavigateSpy).not.toHaveBeenCalled(); }); it('should call `checkSavedRedirectRouteAndNavigate` if authenticated already', async () => { @@ -502,13 +484,12 @@ describe('AutoLoginPartialRoutesGuard', () => { autoLoginPartialRoutesGuard ); - guard$.subscribe(() => { - expect(saveRedirectRouteSpy).not.toHaveBeenCalled(); - expect(loginSpy).not.toHaveBeenCalled(); - expect( + await lastValueFrom(guard$); +expect(saveRedirectRouteSpy).not.toHaveBeenCalled();; +expect(loginSpy).not.toHaveBeenCalled();; +expect( checkSavedRedirectRouteAndNavigateSpy ).toHaveBeenCalledExactlyOnceWith({ configId: 'configId1' }); - }); }); }); @@ -556,16 +537,15 @@ describe('AutoLoginPartialRoutesGuard', () => { autoLoginPartialRoutesGuardWithConfig('configId1') ); - guard$.subscribe(() => { - expect(saveRedirectRouteSpy).toHaveBeenCalledExactlyOnceWith( + await lastValueFrom(guard$); +expect(saveRedirectRouteSpy).toHaveBeenCalledExactlyOnceWith( { configId: 'configId1' }, '' - ); - expect(loginSpy).toHaveBeenCalledExactlyOnceWith({ + );; +expect(loginSpy).toHaveBeenCalledExactlyOnceWith({ configId: 'configId1', - }); - expect(checkSavedRedirectRouteAndNavigateSpy).not.toHaveBeenCalled(); - }); + });; +expect(checkSavedRedirectRouteAndNavigateSpy).not.toHaveBeenCalled(); }); }); }); diff --git a/src/callback/code-flow-callback.service.spec.ts b/src/callback/code-flow-callback.service.spec.ts index 81c3438..ff979d3 100644 --- a/src/callback/code-flow-callback.service.spec.ts +++ b/src/callback/code-flow-callback.service.spec.ts @@ -85,15 +85,13 @@ describe('CodeFlowCallbackService ', () => { triggerAuthorizationResultEvent: true, }; - codeFlowCallbackService - .authenticatedCallbackWithCode('some-url2', config, [config]) - .subscribe(() => { - expect(spy).toHaveBeenCalledExactlyOnceWith('some-url2', config, [ + await lastValueFrom(codeFlowCallbackService + .authenticatedCallbackWithCode('some-url2', config, [config])); +expect(spy).toHaveBeenCalledExactlyOnceWith('some-url2', config, [ config, - ]); - expect(routerSpy).not.toHaveBeenCalled(); - expect(flowsDataSpy).toHaveBeenCalled(); - }); + ]);; +expect(routerSpy).not.toHaveBeenCalled();; +expect(flowsDataSpy).toHaveBeenCalled(); }); it('calls router and resetCodeFlowInProgress if triggerAuthorizationResultEvent is false and isRenewProcess is false', async () => { @@ -122,15 +120,13 @@ describe('CodeFlowCallbackService ', () => { postLoginRoute: 'postLoginRoute', }; - codeFlowCallbackService - .authenticatedCallbackWithCode('some-url3', config, [config]) - .subscribe(() => { - expect(spy).toHaveBeenCalledExactlyOnceWith('some-url3', config, [ + await lastValueFrom(codeFlowCallbackService + .authenticatedCallbackWithCode('some-url3', config, [config])); +expect(spy).toHaveBeenCalledExactlyOnceWith('some-url3', config, [ config, - ]); - expect(routerSpy).toHaveBeenCalledExactlyOnceWith('postLoginRoute'); - expect(flowsDataSpy).toHaveBeenCalled(); - }); + ]);; +expect(routerSpy).toHaveBeenCalledExactlyOnceWith('postLoginRoute');; +expect(flowsDataSpy).toHaveBeenCalled(); }); it('resetSilentRenewRunning, resetCodeFlowInProgress and stopPeriodicallTokenCheck in case of error', async () => { diff --git a/src/callback/implicit-flow-callback.service.spec.ts b/src/callback/implicit-flow-callback.service.spec.ts index ebe7f1c..94f697d 100644 --- a/src/callback/implicit-flow-callback.service.spec.ts +++ b/src/callback/implicit-flow-callback.service.spec.ts @@ -81,16 +81,14 @@ describe('ImplicitFlowCallbackService ', () => { triggerAuthorizationResultEvent: true, }; - implicitFlowCallbackService - .authenticatedImplicitFlowCallback(config, [config], 'some-hash') - .subscribe(() => { - expect(spy).toHaveBeenCalledExactlyOnceWith( + await lastValueFrom(implicitFlowCallbackService + .authenticatedImplicitFlowCallback(config, [config], 'some-hash')); +expect(spy).toHaveBeenCalledExactlyOnceWith( config, [config], 'some-hash' - ); - expect(routerSpy).not.toHaveBeenCalled(); - }); + );; +expect(routerSpy).not.toHaveBeenCalled(); }); it('calls router if triggerAuthorizationResultEvent is false and isRenewProcess is false', async () => { @@ -115,16 +113,14 @@ describe('ImplicitFlowCallbackService ', () => { postLoginRoute: 'postLoginRoute', }; - implicitFlowCallbackService - .authenticatedImplicitFlowCallback(config, [config], 'some-hash') - .subscribe(() => { - expect(spy).toHaveBeenCalledExactlyOnceWith( + await lastValueFrom(implicitFlowCallbackService + .authenticatedImplicitFlowCallback(config, [config], 'some-hash')); +expect(spy).toHaveBeenCalledExactlyOnceWith( config, [config], 'some-hash' - ); - expect(routerSpy).toHaveBeenCalledExactlyOnceWith('postLoginRoute'); - }); + );; +expect(routerSpy).toHaveBeenCalledExactlyOnceWith('postLoginRoute'); }); it('resetSilentRenewRunning and stopPeriodicallyTokenCheck in case of error', async () => { diff --git a/src/callback/refresh-session-refresh-token.service.spec.ts b/src/callback/refresh-session-refresh-token.service.spec.ts index d4847ba..d44f54c 100644 --- a/src/callback/refresh-session-refresh-token.service.spec.ts +++ b/src/callback/refresh-session-refresh-token.service.spec.ts @@ -1,5 +1,5 @@ import { TestBed } from '@/testing'; -import { of, throwError } from 'rxjs'; +import { lastValueFrom, of, throwError } from 'rxjs'; import { vi } from 'vitest'; import type { CallbackContext } from '../flows/callback-context'; import { FlowsService } from '../flows/flows.service'; @@ -44,13 +44,13 @@ describe('RefreshSessionRefreshTokenService', () => { .spyOn(flowsService, 'processRefreshToken') .mockReturnValue(of({} as CallbackContext)); - refreshSessionRefreshTokenService - .refreshSessionWithRefreshTokens({ configId: 'configId1' }, [ + await lastValueFrom( + refreshSessionRefreshTokenService.refreshSessionWithRefreshTokens( { configId: 'configId1' }, - ]) - .subscribe(() => { - expect(spy).toHaveBeenCalled(); - }); + [{ configId: 'configId1' }] + ) + ); + expect(spy).toHaveBeenCalled(); }); it('resetAuthorizationData in case of error', async () => { diff --git a/src/callback/refresh-session.service.spec.ts b/src/callback/refresh-session.service.spec.ts index 167194e..9e4a31e 100644 --- a/src/callback/refresh-session.service.spec.ts +++ b/src/callback/refresh-session.service.spec.ts @@ -91,15 +91,18 @@ describe('RefreshSessionService ', () => { const extraCustomParams = { extra: 'custom' }; - refreshSessionService - .userForceRefreshSession(allConfigs[0]!, allConfigs, extraCustomParams) - .subscribe(() => { - expect(writeSpy).toHaveBeenCalledExactlyOnceWith( - 'storageCustomParamsRefresh', - extraCustomParams, - allConfigs[0] - ); - }); + await lastValueFrom( + refreshSessionService.userForceRefreshSession( + allConfigs[0]!, + allConfigs, + extraCustomParams + ) + ); + expect(writeSpy).toHaveBeenCalledExactlyOnceWith( + 'storageCustomParamsRefresh', + extraCustomParams, + allConfigs[0] + ); }); it('should persist storageCustomParamsAuthRequest when extra custom params given and useRefreshToken is false', async () => { @@ -125,15 +128,18 @@ describe('RefreshSessionService ', () => { const extraCustomParams = { extra: 'custom' }; - refreshSessionService - .userForceRefreshSession(allConfigs[0]!, allConfigs, extraCustomParams) - .subscribe(() => { - expect(writeSpy).toHaveBeenCalledExactlyOnceWith( - 'storageCustomParamsAuthRequest', - extraCustomParams, - allConfigs[0] - ); - }); + await lastValueFrom( + refreshSessionService.userForceRefreshSession( + allConfigs[0]!, + allConfigs, + extraCustomParams + ) + ); + expect(writeSpy).toHaveBeenCalledExactlyOnceWith( + 'storageCustomParamsAuthRequest', + extraCustomParams, + allConfigs[0] + ); }); it('should NOT persist customparams if no customparams are given', async () => { @@ -157,11 +163,13 @@ describe('RefreshSessionService ', () => { ]; const writeSpy = vi.spyOn(storagePersistenceService, 'write'); - refreshSessionService - .userForceRefreshSession(allConfigs[0]!, allConfigs) - .subscribe(() => { - expect(writeSpy).not.toHaveBeenCalled(); - }); + await lastValueFrom( + refreshSessionService.userForceRefreshSession( + allConfigs[0]!, + allConfigs + ) + ); + expect(writeSpy).not.toHaveBeenCalled(); }); it('should call resetSilentRenewRunning in case of an error', async () => { @@ -247,12 +255,11 @@ describe('RefreshSessionService ', () => { }, ]; - refreshSessionService - .forceRefreshSession(allConfigs[0]!, allConfigs) - .subscribe((result) => { - expect(result.idToken).toEqual('id-token'); - expect(result.accessToken).toEqual('access-token'); - }); + const result = await lastValueFrom( + refreshSessionService.forceRefreshSession(allConfigs[0]!, allConfigs) + ); + expect(result.idToken).toEqual('id-token'); + expect(result.accessToken).toEqual('access-token'); }); it('only calls start refresh session and returns null if auth is false', async () => { @@ -274,18 +281,17 @@ describe('RefreshSessionService ', () => { }, ]; - refreshSessionService - .forceRefreshSession(allConfigs[0]!, allConfigs) - .subscribe((result) => { - expect(result).toEqual({ - isAuthenticated: false, - errorMessage: '', - userData: null, - idToken: '', - accessToken: '', - configId: 'configId1', - }); - }); + const result = await lastValueFrom( + refreshSessionService.forceRefreshSession(allConfigs[0]!, allConfigs) + ); + expect(result).toEqual({ + isAuthenticated: false, + errorMessage: '', + userData: null, + idToken: '', + accessToken: '', + configId: 'configId1', + }); }); it('calls start refresh session and waits for completed, returns idtoken and accesstoken if auth is true', async () => { @@ -318,12 +324,11 @@ describe('RefreshSessionService ', () => { }, ]; - refreshSessionService - .forceRefreshSession(allConfigs[0]!, allConfigs) - .subscribe((result) => { - expect(result.idToken).toBeDefined(); - expect(result.accessToken).toBeDefined(); - }); + const result = await lastValueFrom( + refreshSessionService.forceRefreshSession(allConfigs[0]!, allConfigs) + ); + expect(result.idToken).toBeDefined(); + expect(result.accessToken).toBeDefined(); }); it('calls start refresh session and waits for completed, returns LoginResponse if auth is false', async () => { @@ -349,18 +354,17 @@ describe('RefreshSessionService ', () => { }, ]; - refreshSessionService - .forceRefreshSession(allConfigs[0]!, allConfigs) - .subscribe((result) => { - expect(result).toEqual({ - isAuthenticated: false, - errorMessage: '', - userData: null, - idToken: '', - accessToken: '', - configId: 'configId1', - }); - }); + const result = await lastValueFrom( + refreshSessionService.forceRefreshSession(allConfigs[0]!, allConfigs) + ); + expect(result).toEqual({ + isAuthenticated: false, + errorMessage: '', + userData: null, + idToken: '', + accessToken: '', + configId: 'configId1', + }); }); it('occurs timeout error and retry mechanism exhausted max retry count throws error', async () => { @@ -483,18 +487,17 @@ describe('RefreshSessionService ', () => { 'refreshSessionWithIFrameCompleted$' ).mockReturnValue(of(null)); - refreshSessionService - .forceRefreshSession(allConfigs[0]!, allConfigs) - .subscribe((result) => { - expect(result).toEqual({ - isAuthenticated: false, - errorMessage: '', - userData: null, - idToken: '', - accessToken: '', - configId: 'configId1', - }); - }); + const result = await lastValueFrom( + refreshSessionService.forceRefreshSession(allConfigs[0]!, allConfigs) + ); + expect(result).toEqual({ + isAuthenticated: false, + errorMessage: '', + userData: null, + idToken: '', + accessToken: '', + configId: 'configId1', + }); }); it('return value only returns once', async () => { @@ -528,18 +531,17 @@ describe('RefreshSessionService ', () => { .spyOn(authStateService, 'areAuthStorageTokensValid') .mockReturnValue(true); - refreshSessionService - .forceRefreshSession(allConfigs[0]!, allConfigs) - .subscribe((result) => { - expect(result).toEqual({ - idToken: 'some-id_token', - accessToken: 'some-access_token', - isAuthenticated: true, - userData: undefined, - configId: 'configId1', - }); - expect(spyInsideMap).toHaveBeenCalledTimes(1); - }); + const result = await lastValueFrom( + refreshSessionService.forceRefreshSession(allConfigs[0]!, allConfigs) + ); + expect(result).toEqual({ + idToken: 'some-id_token', + accessToken: 'some-access_token', + isAuthenticated: true, + userData: undefined, + configId: 'configId1', + }); + expect(spyInsideMap).toHaveBeenCalledTimes(1); }); }); }); @@ -548,21 +550,19 @@ describe('RefreshSessionService ', () => { it('returns null if no auth well known endpoint defined', async () => { vi.spyOn(flowsDataService, 'isSilentRenewRunning').mockReturnValue(true); - (refreshSessionService as any) - .startRefreshSession() - .subscribe((result: any) => { - expect(result).toBe(null); - }); + const result = await lastValueFrom( + (refreshSessionService as any).startRefreshSession() + ); + expect(result).toBe(null); }); it('returns null if silent renew Is running', async () => { vi.spyOn(flowsDataService, 'isSilentRenewRunning').mockReturnValue(true); - (refreshSessionService as any) - .startRefreshSession() - .subscribe((result: any) => { - expect(result).toBe(null); - }); + const result = await lastValueFrom( + (refreshSessionService as any).startRefreshSession() + ); + expect(result).toBe(null); }); it('calls `setSilentRenewRunning` when should be executed', async () => { @@ -592,11 +592,13 @@ describe('RefreshSessionService ', () => { 'refreshSessionWithRefreshTokens' ).mockReturnValue(of({} as CallbackContext)); - (refreshSessionService as any) - .startRefreshSession(allConfigs[0]!, allConfigs) - .subscribe(() => { - expect(setSilentRenewRunningSpy).toHaveBeenCalled(); - }); + await lastValueFrom( + (refreshSessionService as any).startRefreshSession( + allConfigs[0]!, + allConfigs + ) + ); + expect(setSilentRenewRunningSpy).toHaveBeenCalled(); }); it('calls refreshSessionWithRefreshTokens when current flow is codeflow with refresh tokens', async () => { @@ -625,11 +627,13 @@ describe('RefreshSessionService ', () => { ) .mockReturnValue(of({} as CallbackContext)); - (refreshSessionService as any) - .startRefreshSession(allConfigs[0]!, allConfigs) - .subscribe(() => { - expect(refreshSessionWithRefreshTokensSpy).toHaveBeenCalled(); - }); + await lastValueFrom( + (refreshSessionService as any).startRefreshSession( + allConfigs[0]!, + allConfigs + ) + ); + expect(refreshSessionWithRefreshTokensSpy).toHaveBeenCalled(); }); it('calls refreshSessionWithIframe when current flow is NOT codeflow with refresh tokens', async () => { @@ -662,12 +666,14 @@ describe('RefreshSessionService ', () => { .spyOn(refreshSessionIframeService, 'refreshSessionWithIframe') .mockReturnValue(of(false)); - (refreshSessionService as any) - .startRefreshSession(allConfigs[0]!, allConfigs) - .subscribe(() => { - expect(refreshSessionWithRefreshTokensSpy).not.toHaveBeenCalled(); - expect(refreshSessionWithIframeSpy).toHaveBeenCalled(); - }); + await lastValueFrom( + (refreshSessionService as any).startRefreshSession( + allConfigs[0]!, + allConfigs + ) + ); + expect(refreshSessionWithRefreshTokensSpy).not.toHaveBeenCalled(); + expect(refreshSessionWithIframeSpy).toHaveBeenCalled(); }); }); }); diff --git a/src/config/auth-well-known/auth-well-known-data.service.spec.ts b/src/config/auth-well-known/auth-well-known-data.service.spec.ts index 7fe6736..0f781ac 100644 --- a/src/config/auth-well-known/auth-well-known-data.service.spec.ts +++ b/src/config/auth-well-known/auth-well-known-data.service.spec.ts @@ -1,5 +1,5 @@ import { TestBed } from '@/testing'; -import { of, throwError } from 'rxjs'; +import { lastValueFrom, of, throwError } from 'rxjs'; import { vi } from 'vitest'; import { DataService } from '../../api/data.service'; import { LoggerService } from '../../logging/logger.service'; @@ -59,16 +59,14 @@ describe('AuthWellKnownDataService', () => { const urlWithoutSuffix = 'myUrl'; const urlWithSuffix = `${urlWithoutSuffix}/.well-known/openid-configuration`; - (service as any) - .getWellKnownDocument(urlWithoutSuffix, { configId: 'configId1' }) - .subscribe(() => { - expect(dataServiceSpy).toHaveBeenCalledExactlyOnceWith( - urlWithSuffix, - { - configId: 'configId1', - } - ); - }); + await lastValueFrom( + (service as any).getWellKnownDocument(urlWithoutSuffix, { + configId: 'configId1', + }) + ); + expect(dataServiceSpy).toHaveBeenCalledExactlyOnceWith(urlWithSuffix, { + configId: 'configId1', + }); }); it('should not add suffix if it does exist on current url', async () => { @@ -77,16 +75,14 @@ describe('AuthWellKnownDataService', () => { .mockReturnValue(of(null)); const urlWithSuffix = `myUrl/.well-known/openid-configuration`; - (service as any) - .getWellKnownDocument(urlWithSuffix, { configId: 'configId1' }) - .subscribe(() => { - expect(dataServiceSpy).toHaveBeenCalledExactlyOnceWith( - urlWithSuffix, - { - configId: 'configId1', - } - ); - }); + await lastValueFrom( + (service as any).getWellKnownDocument(urlWithSuffix, { + configId: 'configId1', + }) + ); + expect(dataServiceSpy).toHaveBeenCalledExactlyOnceWith(urlWithSuffix, { + configId: 'configId1', + }); }); it('should not add suffix if it does exist in the middle of current url', async () => { @@ -95,16 +91,14 @@ describe('AuthWellKnownDataService', () => { .mockReturnValue(of(null)); const urlWithSuffix = `myUrl/.well-known/openid-configuration/and/some/more/stuff`; - (service as any) - .getWellKnownDocument(urlWithSuffix, { configId: 'configId1' }) - .subscribe(() => { - expect(dataServiceSpy).toHaveBeenCalledExactlyOnceWith( - urlWithSuffix, - { - configId: 'configId1', - } - ); - }); + await lastValueFrom( + (service as any).getWellKnownDocument(urlWithSuffix, { + configId: 'configId1', + }) + ); + expect(dataServiceSpy).toHaveBeenCalledExactlyOnceWith(urlWithSuffix, { + configId: 'configId1', + }); }); it('should use the custom suffix provided in the config', async () => { @@ -114,20 +108,16 @@ describe('AuthWellKnownDataService', () => { const urlWithoutSuffix = `myUrl`; const urlWithSuffix = `${urlWithoutSuffix}/.well-known/test-openid-configuration`; - (service as any) - .getWellKnownDocument(urlWithoutSuffix, { + await lastValueFrom( + (service as any).getWellKnownDocument(urlWithoutSuffix, { configId: 'configId1', authWellknownUrlSuffix: '/.well-known/test-openid-configuration', }) - .subscribe(() => { - expect(dataServiceSpy).toHaveBeenCalledExactlyOnceWith( - urlWithSuffix, - { - configId: 'configId1', - authWellknownUrlSuffix: '/.well-known/test-openid-configuration', - } - ); - }); + ); + expect(dataServiceSpy).toHaveBeenCalledExactlyOnceWith(urlWithSuffix, { + configId: 'configId1', + authWellknownUrlSuffix: '/.well-known/test-openid-configuration', + }); }); it('should retry once', async () => { @@ -193,16 +183,15 @@ describe('AuthWellKnownDataService', () => { const spy = vi.spyOn(service as any, 'getWellKnownDocument')(); - service - .getWellKnownEndPointsForConfig({ + const result = await lastValueFrom( + service.getWellKnownEndPointsForConfig({ configId: 'configId1', authWellknownEndpointUrl: 'any-url', }) - .subscribe((result) => { - expect(spy).toHaveBeenCalled(); - expect((result as any).jwks_uri).toBeUndefined(); - expect(result.jwksUri).toBe('jwks_uri'); - }); + ); + expect(spy).toHaveBeenCalled(); + expect((result as any).jwks_uri).toBeUndefined(); + expect(result.jwksUri).toBe('jwks_uri'); }); it('throws error and logs if no authwellknownUrl is given', async () => { @@ -234,8 +223,8 @@ describe('AuthWellKnownDataService', () => { jwksUri: DUMMY_WELL_KNOWN_DOCUMENT.jwks_uri, }; - service - .getWellKnownEndPointsForConfig({ + const result = await lastValueFrom( + service.getWellKnownEndPointsForConfig({ configId: 'configId1', authWellknownEndpointUrl: 'any-url', authWellknownEndpoints: { @@ -243,9 +232,8 @@ describe('AuthWellKnownDataService', () => { revocationEndpoint: 'config-revocationEndpoint', }, }) - .subscribe((result) => { - expect(result).toEqual(jasmine.objectContaining(expected)); - }); + ); + expect(result).toEqual(jasmine.objectContaining(expected)); }); }); }); diff --git a/src/config/auth-well-known/auth-well-known.service.spec.ts b/src/config/auth-well-known/auth-well-known.service.spec.ts index b35130e..f96fe88 100644 --- a/src/config/auth-well-known/auth-well-known.service.spec.ts +++ b/src/config/auth-well-known/auth-well-known.service.spec.ts @@ -1,5 +1,5 @@ import { TestBed, mockImplementationWhenArgsEqual } from '@/testing'; -import { of, throwError } from 'rxjs'; +import { lastValueFrom, of, throwError } from 'rxjs'; import { vi } from 'vitest'; import { EventTypes } from '../../public-events/event-types'; import { PublicEventsService } from '../../public-events/public-events.service'; @@ -57,13 +57,12 @@ describe('AuthWellKnownService', () => { () => ({ issuer: 'anything' }) ); - service - .queryAndStoreAuthWellKnownEndPoints({ configId: 'configId1' }) - .subscribe((result) => { - expect(storagePersistenceService.read).not.toHaveBeenCalled(); - expect(dataServiceSpy).toHaveBeenCalled(); - expect(result).toEqual({ issuer: 'anything' }); - }); + const result = await lastValueFrom( + service.queryAndStoreAuthWellKnownEndPoints({ configId: 'configId1' }) + ); + expect(storagePersistenceService.read).not.toHaveBeenCalled(); + expect(dataServiceSpy).toHaveBeenCalled(); + expect(result).toEqual({ issuer: 'anything' }); }); it('getAuthWellKnownEndPoints stored the result if http call is made', async () => { @@ -78,13 +77,12 @@ describe('AuthWellKnownService', () => { ); const storeSpy = vi.spyOn(service, 'storeWellKnownEndpoints'); - service - .queryAndStoreAuthWellKnownEndPoints({ configId: 'configId1' }) - .subscribe((result) => { - expect(dataServiceSpy).toHaveBeenCalled(); - expect(storeSpy).toHaveBeenCalled(); - expect(result).toEqual({ issuer: 'anything' }); - }); + const result = await lastValueFrom( + service.queryAndStoreAuthWellKnownEndPoints({ configId: 'configId1' }) + ); + expect(dataServiceSpy).toHaveBeenCalled(); + expect(storeSpy).toHaveBeenCalled(); + expect(result).toEqual({ issuer: 'anything' }); }); it('throws `ConfigLoadingFailed` event when error happens from http', async () => { diff --git a/src/config/config.service.spec.ts b/src/config/config.service.spec.ts index 8862ba9..7998233 100644 --- a/src/config/config.service.spec.ts +++ b/src/config/config.service.spec.ts @@ -1,5 +1,5 @@ import { TestBed } from '@/testing'; -import { of } from 'rxjs'; +import { lastValueFrom, of } from 'rxjs'; import { vi } from 'vitest'; import { LoggerService } from '../logging/logger.service'; import { EventTypes } from '../public-events/event-types'; @@ -93,10 +93,11 @@ describe('Configuration Service', () => { }; const spy = vi.spyOn(configService as any, 'loadConfigs'); - configService.getOpenIDConfiguration('configId1').subscribe((config) => { - expect(config).toBeTruthy(); - expect(spy).not.toHaveBeenCalled(); - }); + const config = await lastValueFrom( + configService.getOpenIDConfiguration('configId1') + ); + expect(config).toBeTruthy(); + expect(spy).not.toHaveBeenCalled(); }); it(`if config is NOT already saved 'loadConfigs' is called`, async () => { @@ -107,10 +108,11 @@ describe('Configuration Service', () => { vi.spyOn(configValidationService, 'validateConfig').mockReturnValue(true); - configService.getOpenIDConfiguration('configId1').subscribe((config) => { - expect(config).toBeTruthy(); - expect(spy).toHaveBeenCalled(); - }); + const config = await lastValueFrom( + configService.getOpenIDConfiguration('configId1') + ); + expect(config).toBeTruthy(); + expect(spy).toHaveBeenCalled(); }); it('returns null if config is not valid', async () => { @@ -124,12 +126,13 @@ describe('Configuration Service', () => { ); const consoleSpy = vi.spyOn(console, 'warn'); - configService.getOpenIDConfiguration('configId1').subscribe((config) => { - expect(config).toBeNull(); - expect(consoleSpy).toHaveBeenCalledExactlyOnceWith( - `[oidc-client-rx] No configuration found for config id 'configId1'.` - ); - }); + const config = await lastValueFrom( + configService.getOpenIDConfiguration('configId1') + ); + expect(config).toBeNull(); + expect(consoleSpy).toHaveBeenCalledExactlyOnceWith( + `[oidc-client-rx] No configuration found for config id 'configId1'.` + ); }); it('returns null if configs are stored but not existing ID is passed', async () => { @@ -138,11 +141,10 @@ describe('Configuration Service', () => { configId2: { configId: 'configId2' }, }; - configService - .getOpenIDConfiguration('notExisting') - .subscribe((config) => { - expect(config).toBeNull(); - }); + const config = await lastValueFrom( + configService.getOpenIDConfiguration('notExisting') + ); + expect(config).toBeNull(); }); it('sets authWellKnownEndPoints on config if authWellKnownEndPoints is stored', async () => { @@ -158,12 +160,13 @@ describe('Configuration Service', () => { issuer: 'auth-well-known', }); - configService.getOpenIDConfiguration('configId1').subscribe((config) => { - expect(config?.authWellknownEndpoints).toEqual({ - issuer: 'auth-well-known', - }); - expect(consoleSpy).not.toHaveBeenCalled(); + const config = await lastValueFrom( + configService.getOpenIDConfiguration('configId1') + ); + expect(config?.authWellknownEndpoints).toEqual({ + issuer: 'auth-well-known', }); + expect(consoleSpy).not.toHaveBeenCalled(); }); it('fires ConfigLoaded if authWellKnownEndPoints is stored', async () => { @@ -179,12 +182,11 @@ describe('Configuration Service', () => { const spy = vi.spyOn(publicEventsService, 'fireEvent'); - configService.getOpenIDConfiguration('configId1').subscribe(() => { - expect(spy).toHaveBeenCalledExactlyOnceWith( - EventTypes.ConfigLoaded, - expect.anything() - ); - }); + await lastValueFrom(configService.getOpenIDConfiguration('configId1')); + expect(spy).toHaveBeenCalledExactlyOnceWith( + EventTypes.ConfigLoaded, + expect.anything() + ); }); it('stores, uses and fires event when authwellknownendpoints are passed', async () => { @@ -207,19 +209,20 @@ describe('Configuration Service', () => { 'storeWellKnownEndpoints' ); - configService.getOpenIDConfiguration('configId1').subscribe((config) => { - expect(config).toBeTruthy(); - expect(fireEventSpy).toHaveBeenCalledExactlyOnceWith( - EventTypes.ConfigLoaded, - expect.anything() - ); - expect(storeWellKnownEndpointsSpy).toHaveBeenCalledExactlyOnceWith( - config as OpenIdConfiguration, - { - issuer: 'auth-well-known', - } - ); - }); + const config = await lastValueFrom( + configService.getOpenIDConfiguration('configId1') + ); + expect(config).toBeTruthy(); + expect(fireEventSpy).toHaveBeenCalledExactlyOnceWith( + EventTypes.ConfigLoaded, + expect.anything() + ); + expect(storeWellKnownEndpointsSpy).toHaveBeenCalledExactlyOnceWith( + config as OpenIdConfiguration, + { + issuer: 'auth-well-known', + } + ); }); }); @@ -234,10 +237,11 @@ describe('Configuration Service', () => { vi.spyOn(configValidationService, 'validateConfig').mockReturnValue(true); - configService.getOpenIDConfigurations('configId1').subscribe((result) => { - expect(result.allConfigs.length).toEqual(2); - expect(result.currentConfig).toBeTruthy(); - }); + const result = await lastValueFrom( + configService.getOpenIDConfigurations('configId1') + ); + expect(result.allConfigs.length).toEqual(2); + expect(result.currentConfig).toBeTruthy(); }); it('created configId when configId is not set', async () => { @@ -250,15 +254,14 @@ describe('Configuration Service', () => { vi.spyOn(configValidationService, 'validateConfig').mockReturnValue(true); - configService.getOpenIDConfigurations().subscribe((result) => { - expect(result.allConfigs.length).toEqual(2); - const allConfigIds = result.allConfigs.map((x) => x.configId); - - expect(allConfigIds).toEqual(['0-clientId1', '1-clientId2']); - - expect(result.currentConfig).toBeTruthy(); - expect(result.currentConfig?.configId).toBeTruthy(); - }); + const result = await lastValueFrom( + configService.getOpenIDConfigurations() + ); + expect(result.allConfigs.length).toEqual(2); + const allConfigIds = result.allConfigs.map((x) => x.configId); + expect(allConfigIds).toEqual(['0-clientId1', '1-clientId2']); + expect(result.currentConfig).toBeTruthy(); + expect(result.currentConfig?.configId).toBeTruthy(); }); it('returns empty array if config is not valid', async () => { @@ -273,12 +276,9 @@ describe('Configuration Service', () => { false ); - configService - .getOpenIDConfigurations() - .subscribe(({ allConfigs, currentConfig }) => { - expect(allConfigs).toEqual([]); - expect(currentConfig).toBeNull(); - }); + await lastValueFrom(configService.getOpenIDConfigurations()); + expect(allConfigs).toEqual([]); + expect(currentConfig).toBeNull(); }); }); diff --git a/src/config/loader/config-loader.spec.ts b/src/config/loader/config-loader.spec.ts index dc1b069..0d96379 100644 --- a/src/config/loader/config-loader.spec.ts +++ b/src/config/loader/config-loader.spec.ts @@ -1,5 +1,5 @@ import { waitForAsync } from '@/testing'; -import { of } from 'rxjs'; +import { lastValueFrom, of } from 'rxjs'; import type { OpenIdConfiguration } from '../openid-configuration'; import { StsConfigHttpLoader, StsConfigStaticLoader } from './config-loader'; @@ -16,9 +16,8 @@ describe('ConfigLoader', () => { const result$ = loader.loadConfigs(); - result$.subscribe((result) => { - expect(Array.isArray(result)).toBeTruthy(); - }); + const result = await lastValueFrom(result$); + expect(Array.isArray(result)).toBeTruthy(); }); it('returns an array if only one config is passed', async () => { @@ -28,9 +27,8 @@ describe('ConfigLoader', () => { const result$ = loader.loadConfigs(); - result$.subscribe((result) => { - expect(Array.isArray(result)).toBeTruthy(); - }); + const result = await lastValueFrom(result$); + expect(Array.isArray(result)).toBeTruthy(); }); }); }); @@ -46,11 +44,10 @@ describe('ConfigLoader', () => { const result$ = loader.loadConfigs(); - result$.subscribe((result) => { - expect(Array.isArray(result)).toBeTruthy(); - expect(result[0].configId).toBe('configId1'); - expect(result[1].configId).toBe('configId2'); - }); + const result = await lastValueFrom(result$); + expect(Array.isArray(result)).toBeTruthy(); + expect(result[0].configId).toBe('configId1'); + expect(result[1].configId).toBe('configId2'); }); it('returns an array if an observable with a config array is passed', async () => { @@ -62,11 +59,10 @@ describe('ConfigLoader', () => { const result$ = loader.loadConfigs(); - result$.subscribe((result) => { - expect(Array.isArray(result)).toBeTruthy(); - expect(result[0].configId).toBe('configId1'); - expect(result[1].configId).toBe('configId2'); - }); + const result = await lastValueFrom(result$); + expect(Array.isArray(result)).toBeTruthy(); + expect(result[0].configId).toBe('configId1'); + expect(result[1].configId).toBe('configId2'); }); it('returns an array if only one config is passed', async () => { @@ -76,10 +72,9 @@ describe('ConfigLoader', () => { const result$ = loader.loadConfigs(); - result$.subscribe((result) => { - expect(Array.isArray(result)).toBeTruthy(); - expect(result[0].configId).toBe('configId1'); - }); + const result = await lastValueFrom(result$); + expect(Array.isArray(result)).toBeTruthy(); + expect(result[0].configId).toBe('configId1'); }); }); }); diff --git a/src/flows/callback-handling/code-flow-callback-handler.service.spec.ts b/src/flows/callback-handling/code-flow-callback-handler.service.spec.ts index 2c5f362..a14f7e2 100644 --- a/src/flows/callback-handling/code-flow-callback-handler.service.spec.ts +++ b/src/flows/callback-handling/code-flow-callback-handler.service.spec.ts @@ -98,11 +98,9 @@ describe('CodeFlowCallbackHandlerService', () => { existingIdToken: null, } as CallbackContext; - service - .codeFlowCallback('test-url', { configId: 'configId1' }) - .subscribe((callbackContext) => { - expect(callbackContext).toEqual(expectedCallbackContext); - }); + const callbackContext = await lastValueFrom(service + .codeFlowCallback('test-url', { configId: 'configId1' })); +expect(callbackContext).toEqual(expectedCallbackContext); }); }); @@ -184,16 +182,14 @@ describe('CodeFlowCallbackHandlerService', () => { 'validateStateFromHashCallback' ).mockReturnValue(true); - service - .codeFlowCodeRequest({} as CallbackContext, { configId: 'configId1' }) - .subscribe(() => { - expect(postSpy).toHaveBeenCalledExactlyOnceWith( + await lastValueFrom(service + .codeFlowCodeRequest({} as CallbackContext, { configId: 'configId1' })); +expect(postSpy).toHaveBeenCalledExactlyOnceWith( 'tokenEndpoint', undefined, { configId: 'configId1' }, expect.any(HttpHeaders) ); - }); }); it('calls url service with custom token params', async () => { @@ -219,14 +215,12 @@ describe('CodeFlowCallbackHandlerService', () => { const postSpy = vi.spyOn(dataService, 'post').mockReturnValue(of({})); - service - .codeFlowCodeRequest({ code: 'foo' } as CallbackContext, config) - .subscribe(() => { - expect(urlServiceSpy).toHaveBeenCalledExactlyOnceWith('foo', config, { + await lastValueFrom(service + .codeFlowCodeRequest({ code: 'foo' } as CallbackContext, config)); +expect(urlServiceSpy).toHaveBeenCalledExactlyOnceWith('foo', config, { foo: 'bar', - }); - expect(postSpy).toHaveBeenCalledTimes(1); - }); + });; +expect(postSpy).toHaveBeenCalledTimes(1); }); it('calls dataService with correct headers if all params are good', async () => { @@ -247,16 +241,13 @@ describe('CodeFlowCallbackHandlerService', () => { 'validateStateFromHashCallback' ).mockReturnValue(true); - service - .codeFlowCodeRequest({} as CallbackContext, config) - .subscribe(() => { - const httpHeaders = postSpy.calls.mostRecent().args[3] as HttpHeaders; - - expect(httpHeaders.has('Content-Type')).toBeTruthy(); - expect(httpHeaders.get('Content-Type')).toBe( + await lastValueFrom(service + .codeFlowCodeRequest({} as CallbackContext, config)); +const httpHeaders = postSpy.calls.mostRecent().args[3] as HttpHeaders;; +expect(httpHeaders.has('Content-Type')).toBeTruthy();; +expect(httpHeaders.get('Content-Type')).toBe( 'application/x-www-form-urlencoded' ); - }); }); it('returns error in case of http error', async () => { diff --git a/src/flows/callback-handling/history-jwt-keys-callback-handler.service.spec.ts b/src/flows/callback-handling/history-jwt-keys-callback-handler.service.spec.ts index dd65080..e266536 100644 --- a/src/flows/callback-handling/history-jwt-keys-callback-handler.service.spec.ts +++ b/src/flows/callback-handling/history-jwt-keys-callback-handler.service.spec.ts @@ -83,20 +83,17 @@ describe('HistoryJwtKeysCallbackHandlerService', () => { vi.spyOn(signInKeyDataService, 'getSigningKeys').mockReturnValue( of({ keys: [] } as JwtKeys) ); - service + await lastValueFrom(service .callbackHistoryAndResetJwtKeys( callbackContext, allConfigs[0]!, allConfigs - ) - .subscribe(() => { - expect(storagePersistenceServiceSpy).toBeCalledWith([ + )); +expect(storagePersistenceServiceSpy).toBeCalledWith([ ['authnResult', DUMMY_AUTH_RESULT, allConfigs[0]], ['jwtKeys', { keys: [] }, allConfigs[0]], - ]); - // write authnResult & jwtKeys - expect(storagePersistenceServiceSpy).toHaveBeenCalledTimes(2); - }); + ]);; +expect(storagePersistenceServiceSpy).toHaveBeenCalledTimes(2); }); it('writes refresh_token into the storage without reuse (refresh token rotation)', async () => { @@ -123,20 +120,17 @@ describe('HistoryJwtKeysCallbackHandlerService', () => { of({ keys: [] } as JwtKeys) ); - service + await lastValueFrom(service .callbackHistoryAndResetJwtKeys( callbackContext, allConfigs[0]!, allConfigs - ) - .subscribe(() => { - expect(storagePersistenceServiceSpy).toBeCalledWith([ + )); +expect(storagePersistenceServiceSpy).toBeCalledWith([ ['authnResult', DUMMY_AUTH_RESULT, allConfigs[0]], ['jwtKeys', { keys: [] }, allConfigs[0]], - ]); - // write authnResult & refresh_token & jwtKeys - expect(storagePersistenceServiceSpy).toHaveBeenCalledTimes(2); - }); + ]);; +expect(storagePersistenceServiceSpy).toHaveBeenCalledTimes(2); }); it('writes refresh_token into the storage with reuse (without refresh token rotation)', async () => { @@ -163,21 +157,18 @@ describe('HistoryJwtKeysCallbackHandlerService', () => { vi.spyOn(signInKeyDataService, 'getSigningKeys').mockReturnValue( of({ keys: [] } as JwtKeys) ); - service + await lastValueFrom(service .callbackHistoryAndResetJwtKeys( callbackContext, allConfigs[0]!, allConfigs - ) - .subscribe(() => { - expect(storagePersistenceServiceSpy).toBeCalledWith([ + )); +expect(storagePersistenceServiceSpy).toBeCalledWith([ ['authnResult', DUMMY_AUTH_RESULT, allConfigs[0]], ['reusable_refresh_token', 'dummy_refresh_token', allConfigs[0]], ['jwtKeys', { keys: [] }, allConfigs[0]], - ]); - // write authnResult & refresh_token & jwtKeys - expect(storagePersistenceServiceSpy).toHaveBeenCalledTimes(3); - }); + ]);; +expect(storagePersistenceServiceSpy).toHaveBeenCalledTimes(3); }); it('resetBrowserHistory if historyCleanup is turned on and is not in a renewProcess', async () => { @@ -200,15 +191,13 @@ describe('HistoryJwtKeysCallbackHandlerService', () => { vi.spyOn(signInKeyDataService, 'getSigningKeys').mockReturnValue( of({ keys: [] } as JwtKeys) ); - service + await lastValueFrom(service .callbackHistoryAndResetJwtKeys( callbackContext, allConfigs[0]!, allConfigs - ) - .subscribe(() => { - expect(windowSpy).toHaveBeenCalledTimes(1); - }); + )); +expect(windowSpy).toHaveBeenCalledTimes(1); }); it('returns callbackContext with jwtkeys filled if everything works fine', async () => { @@ -230,19 +219,17 @@ describe('HistoryJwtKeysCallbackHandlerService', () => { vi.spyOn(signInKeyDataService, 'getSigningKeys').mockReturnValue( of({ keys: [{ kty: 'henlo' } as JwtKey] } as JwtKeys) ); - service + const result = await lastValueFrom(service .callbackHistoryAndResetJwtKeys( callbackContext, allConfigs[0]!, allConfigs - ) - .subscribe((result) => { - expect(result).toEqual({ + )); +expect(result).toEqual({ isRenewProcess: false, authResult: DUMMY_AUTH_RESULT, jwtKeys: { keys: [{ kty: 'henlo' }] }, } as CallbackContext); - }); }); it('returns error if no jwtKeys have been in the call --> keys are null', async () => { diff --git a/src/flows/callback-handling/implicit-flow-callback-handler.service.spec.ts b/src/flows/callback-handling/implicit-flow-callback-handler.service.spec.ts index 8120d0f..57b37b0 100644 --- a/src/flows/callback-handling/implicit-flow-callback-handler.service.spec.ts +++ b/src/flows/callback-handling/implicit-flow-callback-handler.service.spec.ts @@ -57,11 +57,9 @@ describe('ImplicitFlowCallbackHandlerService', () => { }, ]; - service - .implicitFlowCallback(allConfigs[0]!, allConfigs, 'any-hash') - .subscribe(() => { - expect(resetAuthorizationDataSpy).toHaveBeenCalled(); - }); + await lastValueFrom(service + .implicitFlowCallback(allConfigs[0]!, allConfigs, 'any-hash')); +expect(resetAuthorizationDataSpy).toHaveBeenCalled(); }); it('does NOT calls "resetAuthorizationData" if silent renew is running', async () => { @@ -76,11 +74,9 @@ describe('ImplicitFlowCallbackHandlerService', () => { }, ]; - service - .implicitFlowCallback(allConfigs[0]!, allConfigs, 'any-hash') - .subscribe(() => { - expect(resetAuthorizationDataSpy).not.toHaveBeenCalled(); - }); + await lastValueFrom(service + .implicitFlowCallback(allConfigs[0]!, allConfigs, 'any-hash')); +expect(resetAuthorizationDataSpy).not.toHaveBeenCalled(); }); it('returns callbackContext if all params are good', async () => { @@ -103,11 +99,9 @@ describe('ImplicitFlowCallbackHandlerService', () => { }, ]; - service - .implicitFlowCallback(allConfigs[0]!, allConfigs, 'anyHash') - .subscribe((callbackContext) => { - expect(callbackContext).toEqual(expectedCallbackContext); - }); + const callbackContext = await lastValueFrom(service + .implicitFlowCallback(allConfigs[0]!, allConfigs, 'anyHash')); +expect(callbackContext).toEqual(expectedCallbackContext); }); it('uses window location hash if no hash is passed', async () => { @@ -130,11 +124,9 @@ describe('ImplicitFlowCallbackHandlerService', () => { }, ]; - service - .implicitFlowCallback(allConfigs[0]!, allConfigs) - .subscribe((callbackContext) => { - expect(callbackContext).toEqual(expectedCallbackContext); - }); + const callbackContext = await lastValueFrom(service + .implicitFlowCallback(allConfigs[0]!, allConfigs)); +expect(callbackContext).toEqual(expectedCallbackContext); }); }); }); diff --git a/src/flows/callback-handling/refresh-session-callback-handler.service.spec.ts b/src/flows/callback-handling/refresh-session-callback-handler.service.spec.ts index 3c7553e..7ae7789 100644 --- a/src/flows/callback-handling/refresh-session-callback-handler.service.spec.ts +++ b/src/flows/callback-handling/refresh-session-callback-handler.service.spec.ts @@ -56,11 +56,9 @@ describe('RefreshSessionCallbackHandlerService', () => { existingIdToken: 'henlo-legger', } as CallbackContext; - service - .refreshSessionWithRefreshTokens({ configId: 'configId1' }) - .subscribe((callbackContext) => { - expect(callbackContext).toEqual(expectedCallbackContext); - }); + const callbackContext = await lastValueFrom(service + .refreshSessionWithRefreshTokens({ configId: 'configId1' })); +expect(callbackContext).toEqual(expectedCallbackContext); }); it('throws error if no refresh token is given', async () => { diff --git a/src/flows/callback-handling/refresh-token-callback-handler.service.spec.ts b/src/flows/callback-handling/refresh-token-callback-handler.service.spec.ts index dda12bd..ad7b648 100644 --- a/src/flows/callback-handling/refresh-token-callback-handler.service.spec.ts +++ b/src/flows/callback-handling/refresh-token-callback-handler.service.spec.ts @@ -66,24 +66,21 @@ describe('RefreshTokenCallbackHandlerService', () => { () => ({ tokenEndpoint: 'tokenEndpoint' }) ); - service + await lastValueFrom(service .refreshTokensRequestTokens({} as CallbackContext, { configId: 'configId1', - }) - .subscribe(() => { - expect(postSpy).toHaveBeenCalledExactlyOnceWith( + })); +expect(postSpy).toHaveBeenCalledExactlyOnceWith( 'tokenEndpoint', undefined, { configId: 'configId1' }, expect.any(HttpHeaders) - ); - const httpHeaders = postSpy.calls.mostRecent().args[3] as HttpHeaders; - - expect(httpHeaders.has('Content-Type')).toBeTruthy(); - expect(httpHeaders.get('Content-Type')).toBe( + );; +const httpHeaders = postSpy.calls.mostRecent().args[3] as HttpHeaders;; +expect(httpHeaders.has('Content-Type')).toBeTruthy();; +expect(httpHeaders.get('Content-Type')).toBe( 'application/x-www-form-urlencoded' ); - }); }); it('calls data service with correct headers if all params are good', async () => { @@ -95,18 +92,15 @@ describe('RefreshTokenCallbackHandlerService', () => { () => ({ tokenEndpoint: 'tokenEndpoint' }) ); - service + await lastValueFrom(service .refreshTokensRequestTokens({} as CallbackContext, { configId: 'configId1', - }) - .subscribe(() => { - const httpHeaders = postSpy.calls.mostRecent().args[3] as HttpHeaders; - - expect(httpHeaders.has('Content-Type')).toBeTruthy(); - expect(httpHeaders.get('Content-Type')).toBe( + })); +const httpHeaders = postSpy.calls.mostRecent().args[3] as HttpHeaders;; +expect(httpHeaders.has('Content-Type')).toBeTruthy();; +expect(httpHeaders.get('Content-Type')).toBe( 'application/x-www-form-urlencoded' ); - }); }); it('returns error in case of http error', async () => { diff --git a/src/flows/callback-handling/state-validation-callback-handler.service.spec.ts b/src/flows/callback-handling/state-validation-callback-handler.service.spec.ts index 2be057d..7913d80 100644 --- a/src/flows/callback-handling/state-validation-callback-handler.service.spec.ts +++ b/src/flows/callback-handling/state-validation-callback-handler.service.spec.ts @@ -69,20 +69,18 @@ describe('StateValidationCallbackHandlerService', () => { ); const allConfigs = [{ configId: 'configId1' }]; - service + const newCallbackContext = await lastValueFrom(service .callbackStateValidation( {} as CallbackContext, allConfigs[0]!, allConfigs - ) - .subscribe((newCallbackContext) => { - expect(newCallbackContext).toEqual({ + )); +expect(newCallbackContext).toEqual({ validationResult: { idToken: 'idTokenJustForTesting', authResponseIsValid: true, }, } as CallbackContext); - }); }); it('logs error in case of an error', async () => { diff --git a/src/flows/callback-handling/user-callback-handler.service.spec.ts b/src/flows/callback-handling/user-callback-handler.service.spec.ts index b8b464d..12bdc22 100644 --- a/src/flows/callback-handling/user-callback-handler.service.spec.ts +++ b/src/flows/callback-handling/user-callback-handler.service.spec.ts @@ -73,12 +73,10 @@ describe('UserCallbackHandlerService', () => { const spy = vi.spyOn(flowsDataService, 'setSessionState'); - service - .callbackUser(callbackContext, allConfigs[0]!, allConfigs) - .subscribe((resultCallbackContext) => { - expect(spy).toHaveBeenCalledExactlyOnceWith('mystate', allConfigs[0]); - expect(resultCallbackContext).toEqual(callbackContext); - }); + const resultCallbackContext = await lastValueFrom(service + .callbackUser(callbackContext, allConfigs[0]!, allConfigs)); +expect(spy).toHaveBeenCalledExactlyOnceWith('mystate', allConfigs[0]);; +expect(resultCallbackContext).toEqual(callbackContext); }); it('does NOT call flowsDataService.setSessionState if autoUserInfo is false, isRenewProcess is true and refreshToken is null', async () => { @@ -107,12 +105,10 @@ describe('UserCallbackHandlerService', () => { ]; const spy = vi.spyOn(flowsDataService, 'setSessionState'); - service - .callbackUser(callbackContext, allConfigs[0]!, allConfigs) - .subscribe((resultCallbackContext) => { - expect(spy).not.toHaveBeenCalled(); - expect(resultCallbackContext).toEqual(callbackContext); - }); + const resultCallbackContext = await lastValueFrom(service + .callbackUser(callbackContext, allConfigs[0]!, allConfigs)); +expect(spy).not.toHaveBeenCalled();; +expect(resultCallbackContext).toEqual(callbackContext); }); it('does NOT call flowsDataService.setSessionState if autoUserInfo is false isRenewProcess is false, refreshToken has value', async () => { @@ -141,12 +137,10 @@ describe('UserCallbackHandlerService', () => { ]; const spy = vi.spyOn(flowsDataService, 'setSessionState'); - service - .callbackUser(callbackContext, allConfigs[0]!, allConfigs) - .subscribe((resultCallbackContext) => { - expect(spy).not.toHaveBeenCalled(); - expect(resultCallbackContext).toEqual(callbackContext); - }); + const resultCallbackContext = await lastValueFrom(service + .callbackUser(callbackContext, allConfigs[0]!, allConfigs)); +expect(spy).not.toHaveBeenCalled();; +expect(resultCallbackContext).toEqual(callbackContext); }); it('does NOT call flowsDataService.setSessionState if autoUserInfo is false isRenewProcess is false, refreshToken has value, id_token is false', async () => { @@ -171,12 +165,10 @@ describe('UserCallbackHandlerService', () => { const spy = vi.spyOn(flowsDataService, 'setSessionState'); - service - .callbackUser(callbackContext, allConfigs[0]!, allConfigs) - .subscribe((resultCallbackContext) => { - expect(spy).not.toHaveBeenCalled(); - expect(resultCallbackContext).toEqual(callbackContext); - }); + const resultCallbackContext = await lastValueFrom(service + .callbackUser(callbackContext, allConfigs[0]!, allConfigs)); +expect(spy).not.toHaveBeenCalled();; +expect(resultCallbackContext).toEqual(callbackContext); }); it('calls authStateService.updateAndPublishAuthState with correct params if autoUserInfo is false', async () => { @@ -210,16 +202,14 @@ describe('UserCallbackHandlerService', () => { 'updateAndPublishAuthState' ); - service - .callbackUser(callbackContext, allConfigs[0]!, allConfigs) - .subscribe((resultCallbackContext) => { - expect(updateAndPublishAuthStateSpy).toHaveBeenCalledExactlyOnceWith({ + const resultCallbackContext = await lastValueFrom(service + .callbackUser(callbackContext, allConfigs[0]!, allConfigs)); +expect(updateAndPublishAuthStateSpy).toHaveBeenCalledExactlyOnceWith({ isAuthenticated: true, validationResult: ValidationResult.NotSet, isRenewProcess: false, - }); - expect(resultCallbackContext).toEqual(callbackContext); - }); + });; +expect(resultCallbackContext).toEqual(callbackContext); }); it('calls userService.getAndPersistUserDataInStore with correct params if autoUserInfo is true', async () => { @@ -252,10 +242,9 @@ describe('UserCallbackHandlerService', () => { .spyOn(userService, 'getAndPersistUserDataInStore') .mockReturnValue(of({ user: 'some_data' })); - service - .callbackUser(callbackContext, allConfigs[0]!, allConfigs) - .subscribe((resultCallbackContext) => { - expect( + const resultCallbackContext = await lastValueFrom(service + .callbackUser(callbackContext, allConfigs[0]!, allConfigs)); +expect( getAndPersistUserDataInStoreSpy ).toHaveBeenCalledExactlyOnceWith( allConfigs[0]!, @@ -263,9 +252,8 @@ describe('UserCallbackHandlerService', () => { false, 'idtoken', 'decoded' - ); - expect(resultCallbackContext).toEqual(callbackContext); - }); + );; +expect(resultCallbackContext).toEqual(callbackContext); }); it('calls authStateService.updateAndPublishAuthState with correct params if autoUserInfo is true', async () => { @@ -303,16 +291,14 @@ describe('UserCallbackHandlerService', () => { 'updateAndPublishAuthState' ); - service - .callbackUser(callbackContext, allConfigs[0]!, allConfigs) - .subscribe((resultCallbackContext) => { - expect(updateAndPublishAuthStateSpy).toHaveBeenCalledExactlyOnceWith({ + const resultCallbackContext = await lastValueFrom(service + .callbackUser(callbackContext, allConfigs[0]!, allConfigs)); +expect(updateAndPublishAuthStateSpy).toHaveBeenCalledExactlyOnceWith({ isAuthenticated: true, validationResult: ValidationResult.MaxOffsetExpired, isRenewProcess: false, - }); - expect(resultCallbackContext).toEqual(callbackContext); - }); + });; +expect(resultCallbackContext).toEqual(callbackContext); }); it('calls flowsDataService.setSessionState with correct params if user data is present and NOT refresh token', async () => { @@ -347,15 +333,13 @@ describe('UserCallbackHandlerService', () => { ); const setSessionStateSpy = vi.spyOn(flowsDataService, 'setSessionState'); - service - .callbackUser(callbackContext, allConfigs[0]!, allConfigs) - .subscribe((resultCallbackContext) => { - expect(setSessionStateSpy).toHaveBeenCalledExactlyOnceWith( + const resultCallbackContext = await lastValueFrom(service + .callbackUser(callbackContext, allConfigs[0]!, allConfigs)); +expect(setSessionStateSpy).toHaveBeenCalledExactlyOnceWith( 'mystate', allConfigs[0] - ); - expect(resultCallbackContext).toEqual(callbackContext); - }); + );; +expect(resultCallbackContext).toEqual(callbackContext); }); it('calls authStateService.publishUnauthorizedState with correct params if user info which are coming back are null', async () => { diff --git a/src/flows/flows.service.spec.ts b/src/flows/flows.service.spec.ts index cd36d28..d08c6f7 100644 --- a/src/flows/flows.service.spec.ts +++ b/src/flows/flows.service.spec.ts @@ -90,19 +90,17 @@ describe('Flows Service', () => { }, ]; - service - .processCodeFlowCallback('some-url1234', allConfigs[0]!, allConfigs) - .subscribe((value) => { - expect(value).toEqual({} as CallbackContext); - expect(codeFlowCallbackSpy).toHaveBeenCalledExactlyOnceWith( + const value = await lastValueFrom(service + .processCodeFlowCallback('some-url1234', allConfigs[0]!, allConfigs)); +expect(value).toEqual({} as CallbackContext);; +expect(codeFlowCallbackSpy).toHaveBeenCalledExactlyOnceWith( 'some-url1234', allConfigs[0] - ); - expect(codeFlowCodeRequestSpy).toHaveBeenCalledTimes(1); - expect(callbackHistoryAndResetJwtKeysSpy).toHaveBeenCalledTimes(1); - expect(callbackStateValidationSpy).toHaveBeenCalledTimes(1); - expect(callbackUserSpy).toHaveBeenCalledTimes(1); - }); + );; +expect(codeFlowCodeRequestSpy).toHaveBeenCalledTimes(1);; +expect(callbackHistoryAndResetJwtKeysSpy).toHaveBeenCalledTimes(1);; +expect(callbackStateValidationSpy).toHaveBeenCalledTimes(1);; +expect(callbackUserSpy).toHaveBeenCalledTimes(1); }); }); @@ -129,19 +127,17 @@ describe('Flows Service', () => { }, ]; - service + const value = await lastValueFrom(service .processSilentRenewCodeFlowCallback( {} as CallbackContext, allConfigs[0]!, allConfigs - ) - .subscribe((value) => { - expect(value).toEqual({} as CallbackContext); - expect(codeFlowCodeRequestSpy).toHaveBeenCalled(); - expect(callbackHistoryAndResetJwtKeysSpy).toHaveBeenCalled(); - expect(callbackStateValidationSpy).toHaveBeenCalled(); - expect(callbackUserSpy).toHaveBeenCalled(); - }); + )); +expect(value).toEqual({} as CallbackContext);; +expect(codeFlowCodeRequestSpy).toHaveBeenCalled();; +expect(callbackHistoryAndResetJwtKeysSpy).toHaveBeenCalled();; +expect(callbackStateValidationSpy).toHaveBeenCalled();; +expect(callbackUserSpy).toHaveBeenCalled(); }); }); @@ -168,15 +164,13 @@ describe('Flows Service', () => { }, ]; - service - .processImplicitFlowCallback(allConfigs[0]!, allConfigs, 'any-hash') - .subscribe((value) => { - expect(value).toEqual({} as CallbackContext); - expect(implicitFlowCallbackSpy).toHaveBeenCalled(); - expect(callbackHistoryAndResetJwtKeysSpy).toHaveBeenCalled(); - expect(callbackStateValidationSpy).toHaveBeenCalled(); - expect(callbackUserSpy).toHaveBeenCalled(); - }); + const value = await lastValueFrom(service + .processImplicitFlowCallback(allConfigs[0]!, allConfigs, 'any-hash')); +expect(value).toEqual({} as CallbackContext);; +expect(implicitFlowCallbackSpy).toHaveBeenCalled();; +expect(callbackHistoryAndResetJwtKeysSpy).toHaveBeenCalled();; +expect(callbackStateValidationSpy).toHaveBeenCalled();; +expect(callbackUserSpy).toHaveBeenCalled(); }); }); @@ -209,16 +203,14 @@ describe('Flows Service', () => { }, ]; - service - .processRefreshToken(allConfigs[0]!, allConfigs) - .subscribe((value) => { - expect(value).toEqual({} as CallbackContext); - expect(refreshSessionWithRefreshTokensSpy).toHaveBeenCalled(); - expect(refreshTokensRequestTokensSpy).toHaveBeenCalled(); - expect(callbackHistoryAndResetJwtKeysSpy).toHaveBeenCalled(); - expect(callbackStateValidationSpy).toHaveBeenCalled(); - expect(callbackUserSpy).toHaveBeenCalled(); - }); + const value = await lastValueFrom(service + .processRefreshToken(allConfigs[0]!, allConfigs)); +expect(value).toEqual({} as CallbackContext);; +expect(refreshSessionWithRefreshTokensSpy).toHaveBeenCalled();; +expect(refreshTokensRequestTokensSpy).toHaveBeenCalled();; +expect(callbackHistoryAndResetJwtKeysSpy).toHaveBeenCalled();; +expect(callbackStateValidationSpy).toHaveBeenCalled();; +expect(callbackUserSpy).toHaveBeenCalled(); }); }); }); diff --git a/src/http/index.ts b/src/http/index.ts index ad689bb..a400ba2 100644 --- a/src/http/index.ts +++ b/src/http/index.ts @@ -1,4 +1,9 @@ -import type { HttpFeature } from '@ngify/http'; +import type { HttpFeature, HttpInterceptor } from '@ngify/http'; +import { InjectionToken } from 'injection-js'; + +export const HTTP_INTERCEPTORS = new InjectionToken( + 'HTTP_INTERCEPTORS' +); export function provideHttpClient() { // todo diff --git a/src/iframe/check-session.service.spec.ts b/src/iframe/check-session.service.spec.ts index 4a1f9d1..1178241 100644 --- a/src/iframe/check-session.service.spec.ts +++ b/src/iframe/check-session.service.spec.ts @@ -320,9 +320,8 @@ describe('CheckSessionService', () => { serviceAsAny.lastIFrameRefresh = lastRefresh; serviceAsAny.iframeRefreshInterval = lastRefresh; - serviceAsAny.init().subscribe((result: any) => { - expect(result).toBeUndefined(); - }); + const result = await lastValueFrom(serviceAsAny.init()); +expect(result).toBeUndefined(); }); }); @@ -364,10 +363,9 @@ expect(result).toBe(false); const expectedResultsInOrder = [false, true]; let counter = 0; - checkSessionService.checkSessionChanged$.subscribe((result) => { - expect(result).toBe(expectedResultsInOrder[counter]); - counter++; - }); + const result = await lastValueFrom(checkSessionService.checkSessionChanged$); +expect(result).toBe(expectedResultsInOrder[counter]);; +counter++; (checkSessionService as any).checkSessionChangedInternal$.next(true); }); diff --git a/src/iframe/refresh-session-iframe.service.spec.ts b/src/iframe/refresh-session-iframe.service.spec.ts index a398159..9069bb8 100644 --- a/src/iframe/refresh-session-iframe.service.spec.ts +++ b/src/iframe/refresh-session-iframe.service.spec.ts @@ -41,17 +41,15 @@ describe('RefreshSessionIframeService ', () => { .mockReturnValue(of(null)); const allConfigs = [{ configId: 'configId1' }]; - refreshSessionIframeService - .refreshSessionWithIframe(allConfigs[0]!, allConfigs) - .subscribe(() => { - expect( + await lastValueFrom(refreshSessionIframeService + .refreshSessionWithIframe(allConfigs[0]!, allConfigs)); +expect( sendAuthorizeRequestUsingSilentRenewSpy ).toHaveBeenCalledExactlyOnceWith( 'a-url', allConfigs[0]!, allConfigs ); - }); }); }); diff --git a/src/iframe/silent-renew.service.spec.ts b/src/iframe/silent-renew.service.spec.ts index 53719fb..afb6981 100644 --- a/src/iframe/silent-renew.service.spec.ts +++ b/src/iframe/silent-renew.service.spec.ts @@ -152,15 +152,13 @@ describe('SilentRenewService ', () => { const urlParts = 'code=some-code&state=some-state&session_state=some-session-state'; - silentRenewService - .codeFlowCallbackSilentRenewIframe([url, urlParts], config, allConfigs) - .subscribe(() => { - expect(spy).toHaveBeenCalledExactlyOnceWith( + await lastValueFrom(silentRenewService + .codeFlowCallbackSilentRenewIframe([url, urlParts], config, allConfigs)); +expect(spy).toHaveBeenCalledExactlyOnceWith( expectedContext, config, allConfigs ); - }); }); it('throws error if url has error param and resets everything on error', async () => { @@ -308,13 +306,10 @@ describe('SilentRenewService ', () => { const eventData = { detail: 'detail?detail2' } as CustomEvent; const allConfigs = [{ configId: 'configId1' }]; - silentRenewService.refreshSessionWithIFrameCompleted$.subscribe( - (result) => { - expect(result).toEqual({ + const result = await lastValueFrom(silentRenewService.refreshSessionWithIFrameCompleted$); +expect(result).toEqual({ refreshToken: 'callbackContext', } as CallbackContext); - } - ); silentRenewService.silentRenewEventHandler( eventData, @@ -357,11 +352,8 @@ describe('SilentRenewService ', () => { const eventData = { detail: 'detail?detail2' } as CustomEvent; const allConfigs = [{ configId: 'configId1' }]; - silentRenewService.refreshSessionWithIFrameCompleted$.subscribe( - (result) => { - expect(result).toBeNull(); - } - ); + const result = await lastValueFrom(silentRenewService.refreshSessionWithIFrameCompleted$); +expect(result).toBeNull(); silentRenewService.silentRenewEventHandler( eventData, diff --git a/src/index.ts b/src/index.ts index f35cfe4..8a94a73 100644 --- a/src/index.ts +++ b/src/index.ts @@ -30,3 +30,4 @@ export * from './validation/state-validation-result'; export * from './validation/validation-result'; export * from './injection'; export * from './router'; +export * from './http'; diff --git a/src/interceptor/auth.interceptor.spec.ts b/src/interceptor/auth.interceptor.spec.ts index 9250759..cb759a2 100644 --- a/src/interceptor/auth.interceptor.spec.ts +++ b/src/interceptor/auth.interceptor.spec.ts @@ -103,9 +103,8 @@ describe(`AuthHttpInterceptor`, () => { true ); - httpClient.get(actionUrl).subscribe((response) => { - expect(response).toBeTruthy(); - }); + const response = await lastValueFrom(httpClient.get(actionUrl)); +expect(response).toBeTruthy(); const httpRequest = httpTestingController.expectOne(actionUrl); @@ -130,9 +129,8 @@ describe(`AuthHttpInterceptor`, () => { true ); - httpClient.get(actionUrl).subscribe((response) => { - expect(response).toBeTruthy(); - }); + const response = await lastValueFrom(httpClient.get(actionUrl)); +expect(response).toBeTruthy(); const httpRequest = httpTestingController.expectOne(actionUrl); @@ -159,9 +157,8 @@ describe(`AuthHttpInterceptor`, () => { 'thisIsAToken' ); - httpClient.get(actionUrl).subscribe((response) => { - expect(response).toBeTruthy(); - }); + const response = await lastValueFrom(httpClient.get(actionUrl)); +expect(response).toBeTruthy(); const httpRequest = httpTestingController.expectOne(actionUrl); @@ -185,9 +182,8 @@ describe(`AuthHttpInterceptor`, () => { true ); - httpClient.get(actionUrl).subscribe((response) => { - expect(response).toBeTruthy(); - }); + const response = await lastValueFrom(httpClient.get(actionUrl)); +expect(response).toBeTruthy(); const httpRequest = httpTestingController.expectOne(actionUrl); @@ -212,9 +208,8 @@ describe(`AuthHttpInterceptor`, () => { ); vi.spyOn(authStateService, 'getAccessToken').mockReturnValue(''); - httpClient.get(actionUrl).subscribe((response) => { - expect(response).toBeTruthy(); - }); + const response = await lastValueFrom(httpClient.get(actionUrl)); +expect(response).toBeTruthy(); const httpRequest = httpTestingController.expectOne(actionUrl); @@ -231,9 +226,8 @@ describe(`AuthHttpInterceptor`, () => { false ); - httpClient.get(actionUrl).subscribe((response) => { - expect(response).toBeTruthy(); - }); + const response = await lastValueFrom(httpClient.get(actionUrl)); +expect(response).toBeTruthy(); const httpRequest = httpTestingController.expectOne(actionUrl); @@ -263,9 +257,8 @@ describe(`AuthHttpInterceptor`, () => { matchingConfig: null, }); - httpClient.get(actionUrl).subscribe((response) => { - expect(response).toBeTruthy(); - }); + const response = await lastValueFrom(httpClient.get(actionUrl)); +expect(response).toBeTruthy(); const httpRequest = httpTestingController.expectOne(actionUrl); @@ -290,13 +283,11 @@ describe(`AuthHttpInterceptor`, () => { true ); - httpClient.get(actionUrl).subscribe((response) => { - expect(response).toBeTruthy(); - }); + const response = await lastValueFrom(httpClient.get(actionUrl)); +expect(response).toBeTruthy(); - httpClient.get(actionUrl2).subscribe((response) => { - expect(response).toBeTruthy(); - }); + const response = await lastValueFrom(httpClient.get(actionUrl2)); +expect(response).toBeTruthy(); const httpRequest = httpTestingController.expectOne(actionUrl); diff --git a/src/interceptor/auth.interceptor.ts b/src/interceptor/auth.interceptor.ts index b9afedc..22ab04f 100644 --- a/src/interceptor/auth.interceptor.ts +++ b/src/interceptor/auth.interceptor.ts @@ -1,4 +1,4 @@ -import { +import type { HttpEvent, HttpHandler, HttpHandlerFn, @@ -6,8 +6,8 @@ import { HttpInterceptorFn, HttpRequest, } from '@ngify/http'; -import { inject, Injectable } from 'injection-js'; -import { Observable } from 'rxjs'; +import { Injectable, inject } from 'injection-js'; +import type { Observable } from 'rxjs'; import { AuthStateService } from '../auth-state/auth-state.service'; import { ConfigurationService } from '../config/config.service'; import { LoggerService } from '../logging/logger.service'; diff --git a/src/login/login.service.spec.ts b/src/login/login.service.spec.ts index cc98702..87b098e 100644 --- a/src/login/login.service.spec.ts +++ b/src/login/login.service.spec.ts @@ -118,11 +118,9 @@ describe('LoginService', () => { .mockReturnValue(of({} as LoginResponse)); // act - service.loginWithPopUp(config, [config]).subscribe(() => { - // assert - expect(loginWithPopUpPar).toHaveBeenCalledTimes(1); - expect(loginWithPopUpStandardSpy).not.toHaveBeenCalled(); - }); + await lastValueFrom(service.loginWithPopUp(config, [config])); +expect(loginWithPopUpPar).toHaveBeenCalledTimes(1);; +expect(loginWithPopUpStandardSpy).not.toHaveBeenCalled(); }); it('calls standardLoginService loginstandard if usePushedAuthorisationRequests is false', async () => { @@ -136,11 +134,9 @@ describe('LoginService', () => { .mockReturnValue(of({} as LoginResponse)); // act - service.loginWithPopUp(config, [config]).subscribe(() => { - // assert - expect(loginWithPopUpPar).not.toHaveBeenCalled(); - expect(loginWithPopUpStandardSpy).toHaveBeenCalledTimes(1); - }); + await lastValueFrom(service.loginWithPopUp(config, [config])); +expect(loginWithPopUpPar).not.toHaveBeenCalled();; +expect(loginWithPopUpStandardSpy).toHaveBeenCalledTimes(1); }); it('stores the customParams to the storage if customParams are given', async () => { @@ -157,14 +153,12 @@ describe('LoginService', () => { ); // act - service.loginWithPopUp(config, [config], authOptions).subscribe(() => { - // assert - expect(storagePersistenceServiceSpy).toHaveBeenCalledExactlyOnceWith( + await lastValueFrom(service.loginWithPopUp(config, [config], authOptions)); +expect(storagePersistenceServiceSpy).toHaveBeenCalledExactlyOnceWith( 'storageCustomParamsAuthRequest', { custom: 'params' }, config ); - }); }); it('returns error if there is already a popup open', () => { @@ -181,16 +175,13 @@ describe('LoginService', () => { vi.spyOn(popUpService, 'isCurrentlyInPopup').mockReturnValue(true); // act - service - .loginWithPopUp(config, [config], authOptions) - .subscribe((result) => { - // assert - expect(result).toEqual({ + const result = await lastValueFrom(service + .loginWithPopUp(config, [config], authOptions)); +expect(result).toEqual({ errorMessage: 'There is already a popup open.', - } as LoginResponse); - expect(loginWithPopUpPar).not.toHaveBeenCalled(); - expect(loginWithPopUpStandardSpy).not.toHaveBeenCalled(); - }); + } as LoginResponse);; +expect(loginWithPopUpPar).not.toHaveBeenCalled();; +expect(loginWithPopUpStandardSpy).not.toHaveBeenCalled(); }); }); }); diff --git a/src/login/par/par-login.service.spec.ts b/src/login/par/par-login.service.spec.ts index 53475ec..c028f4e 100644 --- a/src/login/par/par-login.service.spec.ts +++ b/src/login/par/par-login.service.spec.ts @@ -368,13 +368,12 @@ describe('ParLoginService', () => { ); const spy = vi.spyOn(popupService, 'openPopUp'); - service.loginWithPopUpPar(config, allConfigs).subscribe(() => { - expect(spy).toHaveBeenCalledExactlyOnceWith( + await lastValueFrom(service.loginWithPopUpPar(config, allConfigs)); +expect(spy).toHaveBeenCalledExactlyOnceWith( 'some-par-url', undefined, config ); - }); }); it('returns correct properties if URL is received', async () => { @@ -419,21 +418,19 @@ describe('ParLoginService', () => { spyOnProperty(popupService, 'result$').mockReturnValue(of(popupResult)); - service.loginWithPopUpPar(config, allConfigs).subscribe((result) => { - expect(checkAuthSpy).toHaveBeenCalledExactlyOnceWith( + const result = await lastValueFrom(service.loginWithPopUpPar(config, allConfigs)); +expect(checkAuthSpy).toHaveBeenCalledExactlyOnceWith( config, allConfigs, 'someUrl' - ); - - expect(result).toEqual({ + );; +expect(result).toEqual({ isAuthenticated: true, configId: 'configId1', idToken: '', userData: { any: 'userData' }, accessToken: 'anyAccessToken', }); - }); }); it('returns correct properties if popup was closed by user', async () => { @@ -465,9 +462,9 @@ describe('ParLoginService', () => { spyOnProperty(popupService, 'result$').mockReturnValue(of(popupResult)); - service.loginWithPopUpPar(config, allConfigs).subscribe((result) => { - expect(checkAuthSpy).not.toHaveBeenCalled(); - expect(result).toEqual({ + const result = await lastValueFrom(service.loginWithPopUpPar(config, allConfigs)); +expect(checkAuthSpy).not.toHaveBeenCalled();; +expect(result).toEqual({ isAuthenticated: false, errorMessage: 'User closed popup', configId: 'configId1', @@ -475,7 +472,6 @@ describe('ParLoginService', () => { userData: null, accessToken: '', }); - }); }); }); }); diff --git a/src/login/par/par.service.spec.ts b/src/login/par/par.service.spec.ts index 4e1faed..eb61b95 100644 --- a/src/login/par/par.service.spec.ts +++ b/src/login/par/par.service.spec.ts @@ -91,14 +91,13 @@ describe('ParService', () => { .spyOn(dataService, 'post') .mockReturnValue(of({})); - service.postParRequest({ configId: 'configId1' }).subscribe(() => { - expect(dataServiceSpy).toHaveBeenCalledExactlyOnceWith( + await lastValueFrom(service.postParRequest({ configId: 'configId1' })); +expect(dataServiceSpy).toHaveBeenCalledExactlyOnceWith( 'parEndpoint', 'some-url123', { configId: 'configId1' }, expect.any(HttpHeaders) ); - }); }); it('Gives back correct object properties', async () => { @@ -113,9 +112,8 @@ describe('ParService', () => { vi.spyOn(dataService, 'post').mockReturnValue( of({ expires_in: 123, request_uri: 'request_uri' }) ); - service.postParRequest({ configId: 'configId1' }).subscribe((result) => { - expect(result).toEqual({ expiresIn: 123, requestUri: 'request_uri' }); - }); + const result = await lastValueFrom(service.postParRequest({ configId: 'configId1' })); +expect(result).toEqual({ expiresIn: 123, requestUri: 'request_uri' }); }); it('throws error if data service has got an error', async () => { diff --git a/src/login/popup/popup-login.service.spec.ts b/src/login/popup/popup-login.service.spec.ts index 97d5862..2ddf343 100644 --- a/src/login/popup/popup-login.service.spec.ts +++ b/src/login/popup/popup-login.service.spec.ts @@ -1,6 +1,5 @@ -import { TestBed } from '@/testing'; -import { CommonModule } from '@angular/common'; -import { of } from 'rxjs'; +import { TestBed, spyOnProperty } from '@/testing'; +import { lastValueFrom, of } from 'rxjs'; import { vi } from 'vitest'; import { CheckAuthService } from '../../auth-state/check-auth.service'; import { AuthWellKnownService } from '../../config/auth-well-known/auth-well-known.service'; @@ -24,7 +23,7 @@ describe('PopUpLoginService', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [CommonModule], + imports: [], providers: [ PopUpLoginService, mockProvider(LoggerService), @@ -35,9 +34,6 @@ describe('PopUpLoginService', () => { mockProvider(CheckAuthService), ], }); - }); - - beforeEach(() => { popUpLoginService = TestBed.inject(PopUpLoginService); urlService = TestBed.inject(UrlService); loggerService = TestBed.inject(LoggerService); @@ -93,11 +89,10 @@ describe('PopUpLoginService', () => { of({} as LoginResponse) ); - popUpLoginService - .loginWithPopUpStandard(config, [config]) - .subscribe(() => { - expect(urlService.getAuthorizeUrl).toHaveBeenCalled(); - }); + await lastValueFrom( + popUpLoginService.loginWithPopUpStandard(config, [config]) + ); + expect(urlService.getAuthorizeUrl).toHaveBeenCalled(); }); it('opens popup if everything fits', async () => { @@ -123,11 +118,10 @@ describe('PopUpLoginService', () => { ); const popupSpy = vi.spyOn(popupService, 'openPopUp'); - popUpLoginService - .loginWithPopUpStandard(config, [config]) - .subscribe(() => { - expect(popupSpy).toHaveBeenCalled(); - }); + await lastValueFrom( + popUpLoginService.loginWithPopUpStandard(config, [config]) + ); + expect(popupSpy).toHaveBeenCalled(); }); it('returns three properties when popupservice received an url', async () => { @@ -164,23 +158,21 @@ describe('PopUpLoginService', () => { spyOnProperty(popupService, 'result$').mockReturnValue(of(popupResult)); - popUpLoginService - .loginWithPopUpStandard(config, [config]) - .subscribe((result) => { - expect(checkAuthSpy).toHaveBeenCalledExactlyOnceWith( - config, - [config], - 'someUrl' - ); - - expect(result).toEqual({ - isAuthenticated: true, - configId: 'configId1', - idToken: '', - userData: { any: 'userData' }, - accessToken: 'anyAccessToken', - }); - }); + const result = await lastValueFrom( + popUpLoginService.loginWithPopUpStandard(config, [config]) + ); + expect(checkAuthSpy).toHaveBeenCalledExactlyOnceWith( + config, + [config], + 'someUrl' + ); + expect(result).toEqual({ + isAuthenticated: true, + configId: 'configId1', + idToken: '', + userData: { any: 'userData' }, + accessToken: 'anyAccessToken', + }); }); it('returns two properties if popup was closed by user', async () => { @@ -207,19 +199,18 @@ describe('PopUpLoginService', () => { spyOnProperty(popupService, 'result$').mockReturnValue(of(popupResult)); - popUpLoginService - .loginWithPopUpStandard(config, [config]) - .subscribe((result) => { - expect(checkAuthSpy).not.toHaveBeenCalled(); - expect(result).toEqual({ - isAuthenticated: false, - errorMessage: 'User closed popup', - configId: 'configId1', - idToken: '', - userData: null, - accessToken: '', - }); - }); + const result = await lastValueFrom( + popUpLoginService.loginWithPopUpStandard(config, [config]) + ); + expect(checkAuthSpy).not.toHaveBeenCalled(); + expect(result).toEqual({ + isAuthenticated: false, + errorMessage: 'User closed popup', + configId: 'configId1', + idToken: '', + userData: null, + accessToken: '', + }); }); }); }); diff --git a/src/login/popup/popup.service.spec.ts b/src/login/popup/popup.service.spec.ts index 0a9ea67..28d677d 100644 --- a/src/login/popup/popup.service.spec.ts +++ b/src/login/popup/popup.service.spec.ts @@ -112,9 +112,8 @@ describe('PopUpService', () => { receivedUrl: 'some-url1111', }; - popUpService.result$.subscribe((result) => { - expect(result).toBe(popupResult); - }); + const result = await lastValueFrom(popUpService.result$); +expect(result).toBe(popupResult); (popUpService as any).resultInternal$.next(popupResult); }); @@ -195,7 +194,8 @@ describe('PopUpService', () => { popupResult = {} as PopupResult; - popUpService.result$.subscribe((result) => (popupResult = result)); + const result = await lastValueFrom(popUpService.result$); +(popupResult = result) }); it('message received with data', async () => { diff --git a/src/logoff-revoke/logoff-revocation.service.spec.ts b/src/logoff-revoke/logoff-revocation.service.spec.ts index 2601739..5341f8f 100644 --- a/src/logoff-revoke/logoff-revocation.service.spec.ts +++ b/src/logoff-revoke/logoff-revocation.service.spec.ts @@ -123,11 +123,9 @@ describe('Logout and Revoke Service', () => { const config = { configId: 'configId1' }; // Act - service.revokeAccessToken(config).subscribe((result) => { - // Assert - expect(result).toEqual({ data: 'anything' }); - expect(loggerSpy).toHaveBeenCalled(); - }); + const result = await lastValueFrom(service.revokeAccessToken(config)); +expect(result).toEqual({ data: 'anything' });; +expect(loggerSpy).toHaveBeenCalled(); }); it('loggs error when request is negative', async () => { @@ -310,11 +308,9 @@ describe('Logout and Revoke Service', () => { const config = { configId: 'configId1' }; // Act - service.revokeRefreshToken(config).subscribe((result) => { - // Assert - expect(result).toEqual({ data: 'anything' }); - expect(loggerSpy).toHaveBeenCalled(); - }); + const result = await lastValueFrom(service.revokeRefreshToken(config)); +expect(result).toEqual({ data: 'anything' });; +expect(loggerSpy).toHaveBeenCalled(); }); it('loggs error when request is negative', async () => { @@ -442,9 +438,8 @@ describe('Logout and Revoke Service', () => { const result$ = service.logoff(config, [config]); // Assert - result$.subscribe(() => { - expect(serverStateChangedSpy).not.toHaveBeenCalled(); - }); + await lastValueFrom(result$); +expect(serverStateChangedSpy).not.toHaveBeenCalled(); }); it('logs and returns if `serverStateChanged` is true', async () => { @@ -459,9 +454,8 @@ describe('Logout and Revoke Service', () => { const result$ = service.logoff(config, [config]); // Assert - result$.subscribe(() => { - expect(redirectSpy).not.toHaveBeenCalled(); - }); + await lastValueFrom(result$); +expect(redirectSpy).not.toHaveBeenCalled(); }); it('calls urlHandler if urlhandler is passed', async () => { @@ -486,11 +480,10 @@ describe('Logout and Revoke Service', () => { const result$ = service.logoff(config, [config], { urlHandler }); // Assert - result$.subscribe(() => { - expect(redirectSpy).not.toHaveBeenCalled(); - expect(spy).toHaveBeenCalledExactlyOnceWith('someValue'); - expect(resetAuthorizationDataSpy).toHaveBeenCalled(); - }); + await lastValueFrom(result$); +expect(redirectSpy).not.toHaveBeenCalled();; +expect(spy).toHaveBeenCalledExactlyOnceWith('someValue');; +expect(resetAuthorizationDataSpy).toHaveBeenCalled(); }); it('calls redirect service if no logoutOptions are passed', async () => { @@ -508,9 +501,8 @@ describe('Logout and Revoke Service', () => { const result$ = service.logoff(config, [config]); // Assert - result$.subscribe(() => { - expect(redirectSpy).toHaveBeenCalledExactlyOnceWith('someValue'); - }); + await lastValueFrom(result$); +expect(redirectSpy).toHaveBeenCalledExactlyOnceWith('someValue'); }); it('calls redirect service if logoutOptions are passed and method is GET', async () => { @@ -528,9 +520,8 @@ describe('Logout and Revoke Service', () => { const result$ = service.logoff(config, [config], { logoffMethod: 'GET' }); // Assert - result$.subscribe(() => { - expect(redirectSpy).toHaveBeenCalledExactlyOnceWith('someValue'); - }); + await lastValueFrom(result$); +expect(redirectSpy).toHaveBeenCalledExactlyOnceWith('someValue'); }); it('calls dataservice post if logoutOptions are passed and method is POST', async () => { @@ -561,9 +552,9 @@ describe('Logout and Revoke Service', () => { }); // Assert - result$.subscribe(() => { - expect(redirectSpy).not.toHaveBeenCalled(); - expect(postSpy).toHaveBeenCalledExactlyOnceWith( + await lastValueFrom(result$); +expect(redirectSpy).not.toHaveBeenCalled();; +expect(postSpy).toHaveBeenCalledExactlyOnceWith( 'some-url', { id_token_hint: 'id-token', @@ -572,15 +563,12 @@ describe('Logout and Revoke Service', () => { }, config, expect.anything() - ); - - const httpHeaders = postSpy.calls.mostRecent().args[3] as HttpHeaders; - - expect(httpHeaders.has('Content-Type')).toBeTruthy(); - expect(httpHeaders.get('Content-Type')).toBe( + );; +const httpHeaders = postSpy.calls.mostRecent().args[3] as HttpHeaders;; +expect(httpHeaders.has('Content-Type')).toBeTruthy();; +expect(httpHeaders.get('Content-Type')).toBe( 'application/x-www-form-urlencoded' ); - }); }); it('calls dataservice post if logoutOptions with customParams are passed and method is POST', async () => { @@ -616,9 +604,9 @@ describe('Logout and Revoke Service', () => { }); // Assert - result$.subscribe(() => { - expect(redirectSpy).not.toHaveBeenCalled(); - expect(postSpy).toHaveBeenCalledExactlyOnceWith( + await lastValueFrom(result$); +expect(redirectSpy).not.toHaveBeenCalled();; +expect(postSpy).toHaveBeenCalledExactlyOnceWith( 'some-url', { id_token_hint: 'id-token', @@ -630,15 +618,12 @@ describe('Logout and Revoke Service', () => { }, config, expect.anything() - ); - - const httpHeaders = postSpy.calls.mostRecent().args[3] as HttpHeaders; - - expect(httpHeaders.has('Content-Type')).toBeTruthy(); - expect(httpHeaders.get('Content-Type')).toBe( + );; +const httpHeaders = postSpy.calls.mostRecent().args[3] as HttpHeaders;; +expect(httpHeaders.has('Content-Type')).toBeTruthy();; +expect(httpHeaders.get('Content-Type')).toBe( 'application/x-www-form-urlencoded' ); - }); }); }); @@ -681,11 +666,9 @@ describe('Logout and Revoke Service', () => { .mockReturnValue(of({ any: 'thing' })); // Act - service.logoffAndRevokeTokens(config, [config]).subscribe(() => { - // Assert - expect(revokeRefreshTokenSpy).toHaveBeenCalled(); - expect(revokeAccessTokenSpy).toHaveBeenCalled(); - }); + await lastValueFrom(service.logoffAndRevokeTokens(config, [config])); +expect(revokeRefreshTokenSpy).toHaveBeenCalled();; +expect(revokeAccessTokenSpy).toHaveBeenCalled(); }); it('logs error when revokeaccesstoken throws an error', async () => { @@ -736,10 +719,8 @@ describe('Logout and Revoke Service', () => { const config = { configId: 'configId1' }; // Act - service.logoffAndRevokeTokens(config, [config]).subscribe(() => { - // Assert - expect(logoffSpy).toHaveBeenCalled(); - }); + await lastValueFrom(service.logoffAndRevokeTokens(config, [config])); +expect(logoffSpy).toHaveBeenCalled(); }); it('calls logoff with urlhandler in case of success', async () => { @@ -760,14 +741,11 @@ describe('Logout and Revoke Service', () => { const config = { configId: 'configId1' }; // Act - service - .logoffAndRevokeTokens(config, [config], { urlHandler }) - .subscribe(() => { - // Assert - expect(logoffSpy).toHaveBeenCalledExactlyOnceWith(config, [config], { + await lastValueFrom(service + .logoffAndRevokeTokens(config, [config], { urlHandler })); +expect(logoffSpy).toHaveBeenCalledExactlyOnceWith(config, [config], { urlHandler, }); - }); }); it('calls revokeAccessToken when storage does not hold a refreshtoken', async () => { @@ -789,11 +767,9 @@ describe('Logout and Revoke Service', () => { .mockReturnValue(of({ any: 'thing' })); // Act - service.logoffAndRevokeTokens(config, [config]).subscribe(() => { - // Assert - expect(revokeRefreshTokenSpy).not.toHaveBeenCalled(); - expect(revokeAccessTokenSpy).toHaveBeenCalled(); - }); + await lastValueFrom(service.logoffAndRevokeTokens(config, [config])); +expect(revokeRefreshTokenSpy).not.toHaveBeenCalled();; +expect(revokeAccessTokenSpy).toHaveBeenCalled(); }); it('logs error when revokeaccesstoken throws an error', async () => { diff --git a/src/oidc.security.service.spec.ts b/src/oidc.security.service.spec.ts index 818e59b..d7f3890 100644 --- a/src/oidc.security.service.spec.ts +++ b/src/oidc.security.service.spec.ts @@ -225,9 +225,8 @@ describe('OidcSecurityService', () => { some: 'thing', }); - oidcSecurityService.getUserData('configId').subscribe((result) => { - expect(result).toEqual({ some: 'thing' }); - }); + const result = await lastValueFrom(oidcSecurityService.getUserData('configId')); +expect(result).toEqual({ some: 'thing' }); }); }); diff --git a/src/public-events/public-events.service.spec.ts b/src/public-events/public-events.service.spec.ts index f0e6766..1e16310 100644 --- a/src/public-events/public-events.service.spec.ts +++ b/src/public-events/public-events.service.spec.ts @@ -22,23 +22,21 @@ describe('Events Service', () => { }); it('registering to single event with one event emit works', async () => { - eventsService.registerForEvents().subscribe((firedEvent) => { - expect(firedEvent).toBeTruthy(); - expect(firedEvent).toEqual({ + const firedEvent = await lastValueFrom(eventsService.registerForEvents()); +expect(firedEvent).toBeTruthy();; +expect(firedEvent).toEqual({ type: EventTypes.ConfigLoaded, value: { myKey: 'myValue' }, }); - }); eventsService.fireEvent(EventTypes.ConfigLoaded, { myKey: 'myValue' }); }); it('registering to single event with multiple same event emit works', async () => { const spy = jasmine.createSpy('spy'); - eventsService.registerForEvents().subscribe((firedEvent) => { - spy(firedEvent); - expect(firedEvent).toBeTruthy(); - }); + const firedEvent = await lastValueFrom(eventsService.registerForEvents()); +spy(firedEvent);; +expect(firedEvent).toBeTruthy(); eventsService.fireEvent(EventTypes.ConfigLoaded, { myKey: 'myValue' }); eventsService.fireEvent(EventTypes.ConfigLoaded, { myKey: 'myValue2' }); @@ -54,16 +52,14 @@ describe('Events Service', () => { }); it('registering to single event with multiple emit works', async () => { - eventsService + const firedEvent = await lastValueFrom(eventsService .registerForEvents() - .pipe(filter((x) => x.type === EventTypes.ConfigLoaded)) - .subscribe((firedEvent) => { - expect(firedEvent).toBeTruthy(); - expect(firedEvent).toEqual({ + .pipe(filter((x) => x.type === EventTypes.ConfigLoaded))); +expect(firedEvent).toBeTruthy();; +expect(firedEvent).toEqual({ type: EventTypes.ConfigLoaded, value: { myKey: 'myValue' }, }); - }); eventsService.fireEvent(EventTypes.ConfigLoaded, { myKey: 'myValue' }); eventsService.fireEvent(EventTypes.NewAuthenticationResult, true); }); diff --git a/src/testing/http.ts b/src/testing/http.ts new file mode 100644 index 0000000..c94b2b9 --- /dev/null +++ b/src/testing/http.ts @@ -0,0 +1,9 @@ +import { HttpFeatureKind } from '@ngify/http'; +import { HttpClientTestingBackend } from '@ngify/http/testing'; + +export function provideHttpClientTesting() { + return { + provide: HttpFeatureKind.Backend, + useClass: HttpClientTestingBackend, + }; +} diff --git a/src/testing/index.ts b/src/testing/index.ts index 9482c09..48ebc61 100644 --- a/src/testing/index.ts +++ b/src/testing/index.ts @@ -6,3 +6,4 @@ export { } from './spy'; export { createRetriableStream } from './create-retriable-stream.helper'; export { MockRouter, mockRouterProvider } from './router'; +export { provideHttpClientTesting } from './http'; diff --git a/src/utils/url/url.service.spec.ts b/src/utils/url/url.service.spec.ts index 24c2429..6d3a3af 100644 --- a/src/utils/url/url.service.spec.ts +++ b/src/utils/url/url.service.spec.ts @@ -29,9 +29,6 @@ describe('UrlService Tests', () => { mockProvider(JwtWindowCryptoService), ], }); - }); - - beforeEach(() => { service = TestBed.inject(UrlService); loggerService = TestBed.inject(LoggerService); flowHelper = TestBed.inject(FlowHelper); @@ -53,15 +50,15 @@ describe('UrlService Tests', () => { { key: 'blep', value: 'blep' }, ]; - params.forEach((p) => { + for (const p of params) { url.searchParams.set(p.key, p.value); - }); + } const sut = service.getUrlWithoutQueryParameters(url); - params.forEach((p) => { + for (const p of params) { expect(sut.searchParams.has(p.key)).toBeFalsy(); - }); + } }); }); @@ -73,9 +70,9 @@ describe('UrlService Tests', () => { { key: 'blep', value: 'blep' }, ]; - params.forEach((p) => { + for (const p of params) { expected.set(p.key, p.value); - }); + } const matchingUrls = [ new URL('https://any.url?doot=boop&blep=blep'), @@ -87,21 +84,21 @@ describe('UrlService Tests', () => { new URL('https://any.url?blep=blep&woop=doot'), ]; - matchingUrls.forEach((mu) => { + for (const mu of matchingUrls) { it(`should return true for ${mu.toString()}`, () => { expect( service.queryParametersExist(expected, mu.searchParams) ).toBeTruthy(); }); - }); + } - nonMatchingUrls.forEach((nmu) => { + for (const nmu of nonMatchingUrls) { it(`should return false for ${nmu.toString()}`, () => { expect( service.queryParametersExist(expected, nmu.searchParams) ).toBeFalsy(); }); - }); + } }); describe('isCallbackFromSts', () => { @@ -130,9 +127,9 @@ describe('UrlService Tests', () => { }, ]; - nonMatchingUrls.forEach((nmu) => { + for (const nmu of nonMatchingUrls) { expect(service.isCallbackFromSts(nmu.url, nmu.config)).toBeFalsy(); - }); + } }); const testingValues = [ @@ -143,7 +140,7 @@ describe('UrlService Tests', () => { { param: 'some_param', isCallbackFromSts: false }, ]; - testingValues.forEach(({ param, isCallbackFromSts }) => { + for (const { param, isCallbackFromSts } of testingValues) { it(`should return ${isCallbackFromSts} when param is ${param}`, () => { const result = service.isCallbackFromSts( `https://any.url/?${param}=anyvalue` @@ -151,7 +148,7 @@ describe('UrlService Tests', () => { expect(result).toBe(isCallbackFromSts); }); - }); + } }); describe('getUrlParameter', () => { @@ -1051,9 +1048,10 @@ describe('UrlService Tests', () => { it('returns null if current flow is code flow and no redirect url is defined', async () => { vi.spyOn(flowHelper, 'isCurrentFlowCodeFlow').mockReturnValue(true); - service.getAuthorizeUrl({ configId: 'configId1' }).subscribe((result) => { - expect(result).toBeNull(); - }); + const result = await lastValueFrom( + service.getAuthorizeUrl({ configId: 'configId1' }) + ); + expect(result).toBeNull(); }); it('returns empty string if current flow is code flow, config disabled pkce and there is a redirecturl', async () => { @@ -1064,9 +1062,8 @@ describe('UrlService Tests', () => { redirectUrl: 'some-redirectUrl', } as OpenIdConfiguration; - service.getAuthorizeUrl(config).subscribe((result) => { - expect(result).toBe(''); - }); + const result = await lastValueFrom(service.getAuthorizeUrl(config)); + expect(result).toBe(''); }); it('returns url if current flow is code flow, config disabled pkce, there is a redirecturl and awkep are given', async () => { @@ -1093,11 +1090,10 @@ describe('UrlService Tests', () => { () => ({ authorizationEndpoint }) ); - service.getAuthorizeUrl(config).subscribe((result) => { - expect(result).toBe( - 'authorizationEndpoint?client_id=some-clientId&redirect_uri=some-redirectUrl&response_type=testResponseType&scope=testScope&nonce=undefined&state=undefined&code_challenge=some-code-challenge&code_challenge_method=S256' - ); - }); + const result = await lastValueFrom(service.getAuthorizeUrl(config)); + expect(result).toBe( + 'authorizationEndpoint?client_id=some-clientId&redirect_uri=some-redirectUrl&response_type=testResponseType&scope=testScope&nonce=undefined&state=undefined&code_challenge=some-code-challenge&code_challenge_method=S256' + ); }); it('calls createUrlImplicitFlowAuthorize if current flow is NOT code flow', async () => { @@ -1111,10 +1107,9 @@ describe('UrlService Tests', () => { 'createUrlImplicitFlowAuthorize' ); - service.getAuthorizeUrl({ configId: 'configId1' }).subscribe(() => { - expect(spyCreateUrlCodeFlowAuthorize).not.toHaveBeenCalled(); - expect(spyCreateUrlImplicitFlowAuthorize).toHaveBeenCalled(); - }); + await lastValueFrom(service.getAuthorizeUrl({ configId: 'configId1' })); + expect(spyCreateUrlCodeFlowAuthorize).not.toHaveBeenCalled(); + expect(spyCreateUrlImplicitFlowAuthorize).toHaveBeenCalled(); }); it('return empty string if flow is not code flow and createUrlImplicitFlowAuthorize returns falsy', async () => { @@ -1124,10 +1119,9 @@ describe('UrlService Tests', () => { .mockReturnValue(''); const resultObs$ = service.getAuthorizeUrl({ configId: 'configId1' }); - resultObs$.subscribe((result) => { - expect(spy).toHaveBeenCalled(); - expect(result).toBe(''); - }); + const result = await lastValueFrom(resultObs$); + expect(spy).toHaveBeenCalled(); + expect(result).toBe(''); }); }); @@ -1165,10 +1159,9 @@ describe('UrlService Tests', () => { configId: 'configId1', }); - resultObs$.subscribe((result) => { - expect(spy).toHaveBeenCalled(); - expect(result).toBe(''); - }); + const result = await lastValueFrom(resultObs$); + expect(spy).toHaveBeenCalled(); + expect(result).toBe(''); }); }); @@ -1351,9 +1344,8 @@ describe('UrlService Tests', () => { redirectUrl: '', }); - resultObs$.subscribe((result) => { - expect(result).toBe(null); - }); + const result = await lastValueFrom(resultObs$); + expect(result).toBe(null); }); it('returns basic URL with no extras if properties are given', async () => { @@ -1380,11 +1372,10 @@ describe('UrlService Tests', () => { const resultObs$ = service.createBodyForParCodeFlowRequest(config); - resultObs$.subscribe((result) => { - expect(result).toBe( - 'client_id=testClientId&redirect_uri=testRedirectUrl&response_type=testResponseType&scope=testScope&nonce=testNonce&state=testState&code_challenge=testCodeChallenge&code_challenge_method=S256' - ); - }); + const result = await lastValueFrom(resultObs$); + expect(result).toBe( + 'client_id=testClientId&redirect_uri=testRedirectUrl&response_type=testResponseType&scope=testScope&nonce=testNonce&state=testState&code_challenge=testCodeChallenge&code_challenge_method=S256' + ); }); it('returns basic URL with hdParam if properties are given', async () => { @@ -1411,11 +1402,10 @@ describe('UrlService Tests', () => { const resultObs$ = service.createBodyForParCodeFlowRequest(config); - resultObs$.subscribe((result) => { - expect(result).toBe( - 'client_id=testClientId&redirect_uri=testRedirectUrl&response_type=testResponseType&scope=testScope&nonce=testNonce&state=testState&code_challenge=testCodeChallenge&code_challenge_method=S256&hd=testHdParam' - ); - }); + const result = await lastValueFrom(resultObs$); + expect(result).toBe( + 'client_id=testClientId&redirect_uri=testRedirectUrl&response_type=testResponseType&scope=testScope&nonce=testNonce&state=testState&code_challenge=testCodeChallenge&code_challenge_method=S256&hd=testHdParam' + ); }); it('returns basic URL with hdParam and custom params if properties are given', async () => { @@ -1442,11 +1432,10 @@ describe('UrlService Tests', () => { const resultObs$ = service.createBodyForParCodeFlowRequest(config); - resultObs$.subscribe((result) => { - expect(result).toBe( - 'client_id=testClientId&redirect_uri=testRedirectUrl&response_type=testResponseType&scope=testScope&nonce=testNonce&state=testState&code_challenge=testCodeChallenge&code_challenge_method=S256&hd=testHdParam&any=thing' - ); - }); + const result = await lastValueFrom(resultObs$); + expect(result).toBe( + 'client_id=testClientId&redirect_uri=testRedirectUrl&response_type=testResponseType&scope=testScope&nonce=testNonce&state=testState&code_challenge=testCodeChallenge&code_challenge_method=S256&hd=testHdParam&any=thing' + ); }); it('returns basic URL with hdParam and custom params and passed cutom params if properties are given', async () => { @@ -1477,11 +1466,10 @@ describe('UrlService Tests', () => { }, }); - resultObs$.subscribe((result) => { - expect(result).toBe( - 'client_id=testClientId&redirect_uri=testRedirectUrl&response_type=testResponseType&scope=testScope&nonce=testNonce&state=testState&code_challenge=testCodeChallenge&code_challenge_method=S256&hd=testHdParam&any=thing&any=otherThing' - ); - }); + const result = await lastValueFrom(resultObs$); + expect(result).toBe( + 'client_id=testClientId&redirect_uri=testRedirectUrl&response_type=testResponseType&scope=testScope&nonce=testNonce&state=testState&code_challenge=testCodeChallenge&code_challenge_method=S256&hd=testHdParam&any=thing&any=otherThing' + ); }); }); @@ -1489,6 +1477,7 @@ describe('UrlService Tests', () => { it('returns null if silentrenewUrl is falsy', () => { const state = 'testState'; const nonce = 'testNonce'; + // biome-ignore lint/suspicious/noEvolvingTypes: const silentRenewUrl = null; vi.spyOn( @@ -1582,6 +1571,7 @@ describe('UrlService Tests', () => { it('returns empty string if silentrenewUrl is falsy', async () => { const state = 'testState'; const nonce = 'testNonce'; + // biome-ignore lint/suspicious/noEvolvingTypes: const silentRenewUrl = null; const codeVerifier = 'codeVerifier'; const codeChallenge = 'codeChallenge '; @@ -1606,9 +1596,8 @@ describe('UrlService Tests', () => { const resultObs$ = serviceAsAny.createUrlCodeFlowWithSilentRenew(config); - resultObs$.subscribe((result: any) => { - expect(result).toBe(''); - }); + const result = await lastValueFrom(resultObs$); + expect(result).toBe(''); }); it('returns correct URL if wellknownendpoints are given', async () => { @@ -1650,11 +1639,10 @@ describe('UrlService Tests', () => { const resultObs$ = serviceAsAny.createUrlCodeFlowWithSilentRenew(config); - resultObs$.subscribe((result: any) => { - expect(result).toBe( - `authorizationEndpoint?client_id=${clientId}&redirect_uri=http%3A%2F%2Fany-url.com&response_type=${responseType}&scope=${scope}&nonce=${nonce}&state=${state}&prompt=none` - ); - }); + const result = await lastValueFrom(resultObs$); + expect(result).toBe( + `authorizationEndpoint?client_id=${clientId}&redirect_uri=http%3A%2F%2Fany-url.com&response_type=${responseType}&scope=${scope}&nonce=${nonce}&state=${state}&prompt=none` + ); }); it('returns empty string if no wellknownendpoints are given', async () => { @@ -1692,9 +1680,8 @@ describe('UrlService Tests', () => { const resultObs$ = serviceAsAny.createUrlCodeFlowWithSilentRenew(config); - resultObs$.subscribe((result: any) => { - expect(result).toBe(''); - }); + const result = await lastValueFrom(resultObs$); + expect(result).toBe(''); }); }); @@ -1793,6 +1780,7 @@ describe('UrlService Tests', () => { it('returns null if redirectUrl is falsy', async () => { const state = 'testState'; const nonce = 'testNonce'; + // biome-ignore lint/suspicious/noEvolvingTypes: const redirectUrl = null; const config = { redirectUrl, @@ -1808,9 +1796,8 @@ describe('UrlService Tests', () => { const resultObs$ = serviceAsAny.createUrlCodeFlowAuthorize(config); - resultObs$.subscribe((result: any) => { - expect(result).toBeNull(); - }); + const result = await lastValueFrom(resultObs$); + expect(result).toBeNull(); }); it('returns correct URL if wellknownendpoints are given', async () => { @@ -1851,11 +1838,10 @@ describe('UrlService Tests', () => { const resultObs$ = serviceAsAny.createUrlCodeFlowAuthorize(config); - resultObs$.subscribe((result: any) => { - expect(result).toBe( - `authorizationEndpoint?client_id=clientId&redirect_uri=http%3A%2F%2Fany-url.com&response_type=${responseType}&scope=${scope}&nonce=${nonce}&state=${state}` - ); - }); + const result = await lastValueFrom(resultObs$); + expect(result).toBe( + `authorizationEndpoint?client_id=clientId&redirect_uri=http%3A%2F%2Fany-url.com&response_type=${responseType}&scope=${scope}&nonce=${nonce}&state=${state}` + ); }); it('returns correct URL if wellknownendpoints and custom params are given', async () => { @@ -1901,11 +1887,10 @@ describe('UrlService Tests', () => { customParams: { to: 'add', as: 'well' }, }); - resultObs$.subscribe((result: any) => { - expect(result).toBe( - `authorizationEndpoint?client_id=clientId&redirect_uri=http%3A%2F%2Fany-url.com&response_type=${responseType}&scope=${scope}&nonce=${nonce}&state=${state}&to=add&as=well` - ); - }); + const result = await lastValueFrom(resultObs$); + expect(result).toBe( + `authorizationEndpoint?client_id=clientId&redirect_uri=http%3A%2F%2Fany-url.com&response_type=${responseType}&scope=${scope}&nonce=${nonce}&state=${state}&to=add&as=well` + ); }); it('returns empty string if no wellknownendpoints are given', async () => { @@ -1939,9 +1924,8 @@ describe('UrlService Tests', () => { const resultObs$ = serviceAsAny.createUrlCodeFlowAuthorize(config); - resultObs$.subscribe((result: any) => { - expect(result).toBe(''); - }); + const result = await lastValueFrom(resultObs$); + expect(result).toBe(''); }); }); diff --git a/src/validation/jwk-window-crypto.service.spec.ts b/src/validation/jwk-window-crypto.service.spec.ts index 9aa8489..64ea09c 100644 --- a/src/validation/jwk-window-crypto.service.spec.ts +++ b/src/validation/jwk-window-crypto.service.spec.ts @@ -1,6 +1,5 @@ import { TestBed } from '@/testing'; import { base64url } from 'rfc4648'; -import { vi } from 'vitest'; import { CryptoService } from '../utils/crypto/crypto.service'; import { JwkWindowCryptoService } from './jwk-window-crypto.service'; @@ -42,9 +41,6 @@ describe('JwkWindowCryptoService', () => { imports: [], providers: [JwkWindowCryptoService, CryptoService], }); - }); - - beforeEach(async () => { service = TestBed.inject(JwkWindowCryptoService); }); @@ -53,22 +49,21 @@ describe('JwkWindowCryptoService', () => { }); describe('importVerificationKey', () => { - it('returns instance of CryptoKey when valid input is provided', (done) => { + it('returns instance of CryptoKey when valid input is provided', async () => { const promises = keys.map((key) => service.importVerificationKey(key, alg) ); Promise.all(promises).then((values) => { - values.forEach((value) => { + for (const value of values) { expect(value).toBeInstanceOf(CryptoKey); - }); - done(); + } }); }); }); describe('verifyKey', () => { - it('returns true when valid input is provided', (done) => { + it('returns true when valid input is provided', async () => { const headerAndPayloadString = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0'; const signatureString = @@ -77,17 +72,13 @@ describe('JwkWindowCryptoService', () => { loose: true, }); - service + const value = await service .importVerificationKey(key3, alg) .then((c) => service.verifyKey(alg, c, signature, headerAndPayloadString) - ) - .then((value) => { - expect(value).toEqual(true); - }) - .finally(() => { - done(); - }); + ); + + expect(value).toEqual(true); }); }); }); diff --git a/src/validation/jwt-window-crypto.service.spec.ts b/src/validation/jwt-window-crypto.service.spec.ts index ec9eab0..1e74c01 100644 --- a/src/validation/jwt-window-crypto.service.spec.ts +++ b/src/validation/jwt-window-crypto.service.spec.ts @@ -28,9 +28,8 @@ describe('JwtWindowCryptoService', () => { '44445543344242132145455aaabbdc3b4' ); - observable.subscribe((value) => { - expect(value).toBe(outcome); - }); + const value = await lastValueFrom(observable); +expect(value).toBe(outcome); }); }); }); diff --git a/src/validation/state-validation.service.spec.ts b/src/validation/state-validation.service.spec.ts index 32e9e4f..6e5b906 100644 --- a/src/validation/state-validation.service.spec.ts +++ b/src/validation/state-validation.service.spec.ts @@ -693,9 +693,8 @@ describe('State Validation Service', () => { config ); - isValidObs$.subscribe((isValid) => { - expect(isValid.authResponseIsValid).toBe(false); - }); + const isValid = await lastValueFrom(isValidObs$); +expect(isValid.authResponseIsValid).toBe(false); }); it('should return invalid context error', async () => { @@ -730,9 +729,8 @@ describe('State Validation Service', () => { config ); - isValidObs$.subscribe((isValid) => { - expect(isValid.authResponseIsValid).toBe(false); - }); + const isValid = await lastValueFrom(isValidObs$); +expect(isValid.authResponseIsValid).toBe(false); }); it('should return invalid result if validateIdTokenExpNotExpired is false', async () => { @@ -826,16 +824,15 @@ describe('State Validation Service', () => { config ); - stateObs$.subscribe((state) => { - expect(logWarningSpy).toHaveBeenCalledExactlyOnceWith( + const state = await lastValueFrom(stateObs$); +expect(logWarningSpy).toHaveBeenCalledExactlyOnceWith( config, 'authCallback id token expired' - ); - expect(state.accessToken).toBe('access_tokenTEST'); - expect(state.idToken).toBe('id_tokenTEST'); - expect(state.decodedIdToken).toBe('decoded_id_token'); - expect(state.authResponseIsValid).toBe(false); - }); + );; +expect(state.accessToken).toBe('access_tokenTEST');; +expect(state.idToken).toBe('id_tokenTEST');; +expect(state.decodedIdToken).toBe('decoded_id_token');; +expect(state.authResponseIsValid).toBe(false); }); it('should return invalid result if validateStateFromHashCallback is false', async () => { @@ -879,16 +876,15 @@ describe('State Validation Service', () => { tokenValidationService.validateStateFromHashCallback ).toHaveBeenCalled(); - stateObs$.subscribe((state) => { - expect(logWarningSpy).toHaveBeenCalledExactlyOnceWith( + const state = await lastValueFrom(stateObs$); +expect(logWarningSpy).toHaveBeenCalledExactlyOnceWith( config, 'authCallback incorrect state' - ); - expect(state.accessToken).toBe(''); - expect(state.authResponseIsValid).toBe(false); - expect(state.decodedIdToken).toBeDefined(); - expect(state.idToken).toBe(''); - }); + );; +expect(state.accessToken).toBe('');; +expect(state.authResponseIsValid).toBe(false);; +expect(state.decodedIdToken).toBeDefined();; +expect(state.idToken).toBe(''); }); it('access_token should equal result.access_token and is valid if response_type is "id_token token"', async () => { @@ -977,12 +973,11 @@ describe('State Validation Service', () => { config ); - stateObs$.subscribe((state) => { - expect(state.accessToken).toBe('access_tokenTEST'); - expect(state.idToken).toBe('id_tokenTEST'); - expect(state.decodedIdToken).toBe('decoded_id_token'); - expect(state.authResponseIsValid).toBe(true); - }); + const state = await lastValueFrom(stateObs$); +expect(state.accessToken).toBe('access_tokenTEST');; +expect(state.idToken).toBe('id_tokenTEST');; +expect(state.decodedIdToken).toBe('decoded_id_token');; +expect(state.authResponseIsValid).toBe(true); }); it('should return invalid result if validateSignatureIdToken is false', async () => { @@ -1031,17 +1026,15 @@ describe('State Validation Service', () => { config ); - stateObs$.subscribe((state) => { - expect(logDebugSpy).toBeCalledWith([ + const state = await lastValueFrom(stateObs$); +expect(logDebugSpy).toBeCalledWith([ [config, 'authCallback Signature validation failed id_token'], [config, 'authCallback token(s) invalid'], - ]); - - expect(state.accessToken).toBe('access_tokenTEST'); - expect(state.idToken).toBe('id_tokenTEST'); - expect(state.decodedIdToken).toBe('decoded_id_token'); - expect(state.authResponseIsValid).toBe(false); - }); + ]);; +expect(state.accessToken).toBe('access_tokenTEST');; +expect(state.idToken).toBe('id_tokenTEST');; +expect(state.decodedIdToken).toBe('decoded_id_token');; +expect(state.authResponseIsValid).toBe(false); }); it('should return invalid result if validateIdTokenNonce is false', async () => { @@ -1093,16 +1086,15 @@ describe('State Validation Service', () => { config ); - stateObs$.subscribe((state) => { - expect(logWarningSpy).toHaveBeenCalledExactlyOnceWith( + const state = await lastValueFrom(stateObs$); +expect(logWarningSpy).toHaveBeenCalledExactlyOnceWith( config, 'authCallback incorrect nonce, did you call the checkAuth() method multiple times?' - ); - expect(state.accessToken).toBe('access_tokenTEST'); - expect(state.idToken).toBe('id_tokenTEST'); - expect(state.decodedIdToken).toBe('decoded_id_token'); - expect(state.authResponseIsValid).toBe(false); - }); + );; +expect(state.accessToken).toBe('access_tokenTEST');; +expect(state.idToken).toBe('id_tokenTEST');; +expect(state.decodedIdToken).toBe('decoded_id_token');; +expect(state.authResponseIsValid).toBe(false); }); it('should return invalid result if validateRequiredIdToken is false', async () => { @@ -1162,20 +1154,19 @@ describe('State Validation Service', () => { config ); - stateObs$.subscribe((state) => { - expect(logDebugSpy).toHaveBeenCalledWith( + const state = await lastValueFrom(stateObs$); +expect(logDebugSpy).toHaveBeenCalledWith( config, 'authCallback Validation, one of the REQUIRED properties missing from id_token' - ); - expect(logDebugSpy).toHaveBeenCalledWith( + );; +expect(logDebugSpy).toHaveBeenCalledWith( config, 'authCallback token(s) invalid' - ); - expect(state.accessToken).toBe('access_tokenTEST'); - expect(state.idToken).toBe('id_tokenTEST'); - expect(state.decodedIdToken).toBe('decoded_id_token'); - expect(state.authResponseIsValid).toBe(false); - }); + );; +expect(state.accessToken).toBe('access_tokenTEST');; +expect(state.idToken).toBe('id_tokenTEST');; +expect(state.decodedIdToken).toBe('decoded_id_token');; +expect(state.authResponseIsValid).toBe(false); }); it('should return invalid result if validateIdTokenIatMaxOffset is false', async () => { @@ -1238,16 +1229,15 @@ describe('State Validation Service', () => { config ); - stateObs$.subscribe((state) => { - expect(logWarningSpy).toHaveBeenCalledExactlyOnceWith( + const state = await lastValueFrom(stateObs$); +expect(logWarningSpy).toHaveBeenCalledExactlyOnceWith( config, 'authCallback Validation, iat rejected id_token was issued too far away from the current time' - ); - expect(state.accessToken).toBe('access_tokenTEST'); - expect(state.idToken).toBe('id_tokenTEST'); - expect(state.decodedIdToken).toBe('decoded_id_token'); - expect(state.authResponseIsValid).toBe(false); - }); + );; +expect(state.accessToken).toBe('access_tokenTEST');; +expect(state.idToken).toBe('id_tokenTEST');; +expect(state.decodedIdToken).toBe('decoded_id_token');; +expect(state.authResponseIsValid).toBe(false); }); it('should return invalid result if validateIdTokenIss is false and has authWellKnownEndPoints', async () => { @@ -1317,16 +1307,15 @@ describe('State Validation Service', () => { config ); - stateObs$.subscribe((state) => { - expect(logWarningSpy).toHaveBeenCalledExactlyOnceWith( + const state = await lastValueFrom(stateObs$); +expect(logWarningSpy).toHaveBeenCalledExactlyOnceWith( config, 'authCallback incorrect iss does not match authWellKnownEndpoints issuer' - ); - expect(state.accessToken).toBe('access_tokenTEST'); - expect(state.idToken).toBe('id_tokenTEST'); - expect(state.decodedIdToken).toBe('decoded_id_token'); - expect(state.authResponseIsValid).toBe(false); - }); + );; +expect(state.accessToken).toBe('access_tokenTEST');; +expect(state.idToken).toBe('id_tokenTEST');; +expect(state.decodedIdToken).toBe('decoded_id_token');; +expect(state.authResponseIsValid).toBe(false); }); it('should return invalid result if validateIdTokenIss is false and has no authWellKnownEndPoints', async () => { @@ -1384,18 +1373,16 @@ describe('State Validation Service', () => { config ); - stateObs$.subscribe((state) => { - expect(logWarningSpy).toHaveBeenCalledExactlyOnceWith( + const state = await lastValueFrom(stateObs$); +expect(logWarningSpy).toHaveBeenCalledExactlyOnceWith( config, 'authWellKnownEndpoints is undefined' - ); - - expect(state.accessToken).toBe('access_tokenTEST'); - expect(state.idToken).toBe('id_tokenTEST'); - expect(state.decodedIdToken).toBe('decoded_id_token'); - expect(state.authResponseIsValid).toBe(false); - expect(state.state).toBe(ValidationResult.NoAuthWellKnownEndPoints); - }); + );; +expect(state.accessToken).toBe('access_tokenTEST');; +expect(state.idToken).toBe('id_tokenTEST');; +expect(state.decodedIdToken).toBe('decoded_id_token');; +expect(state.authResponseIsValid).toBe(false);; +expect(state.state).toBe(ValidationResult.NoAuthWellKnownEndPoints); }); it('should return invalid result if validateIdTokenAud is false', async () => { @@ -1463,16 +1450,15 @@ describe('State Validation Service', () => { config ); - stateObs$.subscribe((state) => { - expect(logWarningSpy).toHaveBeenCalledExactlyOnceWith( + const state = await lastValueFrom(stateObs$); +expect(logWarningSpy).toHaveBeenCalledExactlyOnceWith( config, 'authCallback incorrect aud' - ); - expect(state.accessToken).toBe('access_tokenTEST'); - expect(state.idToken).toBe('id_tokenTEST'); - expect(state.decodedIdToken).toBe('decoded_id_token'); - expect(state.authResponseIsValid).toBe(false); - }); + );; +expect(state.accessToken).toBe('access_tokenTEST');; +expect(state.idToken).toBe('id_tokenTEST');; +expect(state.decodedIdToken).toBe('decoded_id_token');; +expect(state.authResponseIsValid).toBe(false); }); it('should return invalid result if validateIdTokenAzpExistsIfMoreThanOneAud is false', async () => { @@ -1544,17 +1530,16 @@ describe('State Validation Service', () => { config ); - stateObs$.subscribe((state) => { - expect(logWarningSpy).toHaveBeenCalledExactlyOnceWith( + const state = await lastValueFrom(stateObs$); +expect(logWarningSpy).toHaveBeenCalledExactlyOnceWith( config, 'authCallback missing azp' - ); - expect(state.accessToken).toBe('access_tokenTEST'); - expect(state.idToken).toBe('id_tokenTEST'); - expect(state.decodedIdToken).toBe('decoded_id_token'); - expect(state.authResponseIsValid).toBe(false); - expect(state.state).toBe(ValidationResult.IncorrectAzp); - }); + );; +expect(state.accessToken).toBe('access_tokenTEST');; +expect(state.idToken).toBe('id_tokenTEST');; +expect(state.decodedIdToken).toBe('decoded_id_token');; +expect(state.authResponseIsValid).toBe(false);; +expect(state.state).toBe(ValidationResult.IncorrectAzp); }); it('should return invalid result if validateIdTokenAzpValid is false', async () => { @@ -1630,17 +1615,16 @@ describe('State Validation Service', () => { config ); - stateObs$.subscribe((state) => { - expect(logWarningSpy).toHaveBeenCalledExactlyOnceWith( + const state = await lastValueFrom(stateObs$); +expect(logWarningSpy).toHaveBeenCalledExactlyOnceWith( config, 'authCallback incorrect azp' - ); - expect(state.accessToken).toBe('access_tokenTEST'); - expect(state.idToken).toBe('id_tokenTEST'); - expect(state.decodedIdToken).toBe('decoded_id_token'); - expect(state.authResponseIsValid).toBe(false); - expect(state.state).toBe(ValidationResult.IncorrectAzp); - }); + );; +expect(state.accessToken).toBe('access_tokenTEST');; +expect(state.idToken).toBe('id_tokenTEST');; +expect(state.decodedIdToken).toBe('decoded_id_token');; +expect(state.authResponseIsValid).toBe(false);; +expect(state.state).toBe(ValidationResult.IncorrectAzp); }); it('should return invalid result if isIdTokenAfterRefreshTokenRequestValid is false', async () => { @@ -1720,19 +1704,18 @@ describe('State Validation Service', () => { config ); - stateObs$.subscribe((state) => { - expect(logWarningSpy).toHaveBeenCalledExactlyOnceWith( + const state = await lastValueFrom(stateObs$); +expect(logWarningSpy).toHaveBeenCalledExactlyOnceWith( config, 'authCallback pre, post id_token claims do not match in refresh' - ); - expect(state.accessToken).toBe('access_tokenTEST'); - expect(state.idToken).toBe('id_tokenTEST'); - expect(state.decodedIdToken).toBe('decoded_id_token'); - expect(state.authResponseIsValid).toBe(false); - expect(state.state).toBe( + );; +expect(state.accessToken).toBe('access_tokenTEST');; +expect(state.idToken).toBe('id_tokenTEST');; +expect(state.decodedIdToken).toBe('decoded_id_token');; +expect(state.authResponseIsValid).toBe(false);; +expect(state.state).toBe( ValidationResult.IncorrectIdTokenClaimsAfterRefresh ); - }); }); it('Reponse is valid if authConfiguration.response_type does not equal "id_token token"', async () => { @@ -1824,20 +1807,19 @@ describe('State Validation Service', () => { config ); - stateObs$.subscribe((state) => { - expect(logDebugSpy).toHaveBeenCalledWith( + const state = await lastValueFrom(stateObs$); +expect(logDebugSpy).toHaveBeenCalledWith( config, 'authCallback token(s) validated, continue' - ); - expect(logDebugSpy).toHaveBeenCalledWith( + );; +expect(logDebugSpy).toHaveBeenCalledWith( config, 'authCallback token(s) invalid' - ); - expect(state.accessToken).toBe(''); - expect(state.idToken).toBe('id_tokenTEST'); - expect(state.decodedIdToken).toBe('decoded_id_token'); - expect(state.authResponseIsValid).toBe(true); - }); + );; +expect(state.accessToken).toBe('');; +expect(state.idToken).toBe('id_tokenTEST');; +expect(state.decodedIdToken).toBe('decoded_id_token');; +expect(state.authResponseIsValid).toBe(true); }); it('Response is invalid if validateIdTokenAtHash is false', async () => { @@ -1930,16 +1912,15 @@ describe('State Validation Service', () => { config ); - stateObs$.subscribe((state) => { - expect(logWarningSpy).toHaveBeenCalledExactlyOnceWith( + const state = await lastValueFrom(stateObs$); +expect(logWarningSpy).toHaveBeenCalledExactlyOnceWith( config, 'authCallback incorrect at_hash' - ); - expect(state.accessToken).toBe('access_tokenTEST'); - expect(state.idToken).toBe('id_tokenTEST'); - expect(state.decodedIdToken).toBe('decoded_id_token'); - expect(state.authResponseIsValid).toBe(false); - }); + );; +expect(state.accessToken).toBe('access_tokenTEST');; +expect(state.idToken).toBe('id_tokenTEST');; +expect(state.decodedIdToken).toBe('decoded_id_token');; +expect(state.authResponseIsValid).toBe(false); }); it('should return valid result if validateIdTokenIss is false and iss_validation_off is true', async () => { @@ -2028,17 +2009,16 @@ describe('State Validation Service', () => { config ); - stateObs$.subscribe((state) => { - expect(logDebugSpy).toBeCalledWith([ + const state = await lastValueFrom(stateObs$); +expect(logDebugSpy).toBeCalledWith([ [config, 'iss validation is turned off, this is not recommended!'], [config, 'authCallback token(s) validated, continue'], - ]); - expect(state.state).toBe(ValidationResult.Ok); - expect(state.accessToken).toBe('access_tokenTEST'); - expect(state.authResponseIsValid).toBe(true); - expect(state.decodedIdToken).toBeDefined(); - expect(state.idToken).toBe('id_tokenTEST'); - }); + ]);; +expect(state.state).toBe(ValidationResult.Ok);; +expect(state.accessToken).toBe('access_tokenTEST');; +expect(state.authResponseIsValid).toBe(true);; +expect(state.decodedIdToken).toBeDefined();; +expect(state.idToken).toBe('id_tokenTEST'); }); it('should return valid if there is no id_token', async () => { @@ -2114,12 +2094,11 @@ describe('State Validation Service', () => { config ); - stateObs$.subscribe((state) => { - expect(state.accessToken).toBe('access_tokenTEST'); - expect(state.idToken).toBe(''); - expect(state.decodedIdToken).toBeDefined(); - expect(state.authResponseIsValid).toBe(true); - }); + const state = await lastValueFrom(stateObs$); +expect(state.accessToken).toBe('access_tokenTEST');; +expect(state.idToken).toBe('');; +expect(state.decodedIdToken).toBeDefined();; +expect(state.authResponseIsValid).toBe(true); }); it('should return OK if disableIdTokenValidation is true', async () => { @@ -2154,10 +2133,9 @@ describe('State Validation Service', () => { config ); - isValidObs$.subscribe((isValid) => { - expect(isValid.state).toBe(ValidationResult.Ok); - expect(isValid.authResponseIsValid).toBe(true); - }); + const isValid = await lastValueFrom(isValidObs$); +expect(isValid.state).toBe(ValidationResult.Ok);; +expect(isValid.authResponseIsValid).toBe(true); }); it('should return OK if disableIdTokenValidation is true', async () => { @@ -2192,10 +2170,9 @@ describe('State Validation Service', () => { config ); - isValidObs$.subscribe((isValid) => { - expect(isValid.state).toBe(ValidationResult.Ok); - expect(isValid.authResponseIsValid).toBe(true); - }); + const isValid = await lastValueFrom(isValidObs$); +expect(isValid.state).toBe(ValidationResult.Ok);; +expect(isValid.authResponseIsValid).toBe(true); }); it('should return OK if disableIdTokenValidation is false but inrefreshtokenflow and no id token is returned', async () => { @@ -2230,10 +2207,9 @@ describe('State Validation Service', () => { config ); - isValidObs$.subscribe((isValid) => { - expect(isValid.state).toBe(ValidationResult.Ok); - expect(isValid.authResponseIsValid).toBe(true); - }); + const isValid = await lastValueFrom(isValidObs$); +expect(isValid.state).toBe(ValidationResult.Ok);; +expect(isValid.authResponseIsValid).toBe(true); }); }); }); diff --git a/src/validation/token-validation.service.spec.ts b/src/validation/token-validation.service.spec.ts index 8dfcb8f..8b13049 100644 --- a/src/validation/token-validation.service.spec.ts +++ b/src/validation/token-validation.service.spec.ts @@ -28,9 +28,6 @@ describe('TokenValidationService', () => { CryptoService, ], }); - }); - - beforeEach(() => { tokenValidationService = TestBed.inject(TokenValidationService); tokenHelperService = TestBed.inject(TokenHelperService); jwtWindowCryptoService = TestBed.inject(JwtWindowCryptoService); @@ -506,9 +503,8 @@ describe('TokenValidationService', () => { { configId: 'configId1' } ); - valueFalse$.subscribe((valueFalse) => { - expect(valueFalse).toEqual(false); - }); + const valueFalse = await lastValueFrom(valueFalse$); + expect(valueFalse).toEqual(false); }); it('returns true if no idToken is passed', async () => { @@ -518,9 +514,8 @@ describe('TokenValidationService', () => { { configId: 'configId1' } ); - valueFalse$.subscribe((valueFalse) => { - expect(valueFalse).toEqual(true); - }); + const valueFalse = await lastValueFrom(valueFalse$); + expect(valueFalse).toEqual(true); }); it('returns false if jwtkeys has no keys-property', async () => { @@ -530,9 +525,8 @@ describe('TokenValidationService', () => { { configId: 'configId1' } ); - valueFalse$.subscribe((valueFalse) => { - expect(valueFalse).toEqual(false); - }); + const valueFalse = await lastValueFrom(valueFalse$); + expect(valueFalse).toEqual(false); }); it('returns false if header data has no header data', async () => { @@ -548,9 +542,8 @@ describe('TokenValidationService', () => { { configId: 'configId1' } ); - valueFalse$.subscribe((valueFalse) => { - expect(valueFalse).toEqual(false); - }); + const valueFalse = await lastValueFrom(valueFalse$); + expect(valueFalse).toEqual(false); }); it('returns false if header data alg property does not exist in keyalgorithms', async () => { @@ -568,12 +561,11 @@ describe('TokenValidationService', () => { { configId: 'configId1' } ); - valueFalse$.subscribe((valueFalse) => { - expect(valueFalse).toEqual(false); - }); + const valueFalse = await lastValueFrom(valueFalse$); + expect(valueFalse).toEqual(false); }); - it('returns false if header data has kid property and jwtKeys has same kid property but they are not valid with the token', (done) => { + it('returns false if header data has kid property and jwtKeys has same kid property but they are not valid with the token', async () => { const kid = '5626CE6A8F4F5FCD79C6642345282CA76D337548'; vi.spyOn(tokenHelperService, 'getHeaderFromToken').mockReturnValue({ @@ -605,13 +597,11 @@ describe('TokenValidationService', () => { { configId: 'configId1' } ); - valueFalse$.subscribe((valueFalse) => { - expect(valueFalse).toEqual(false); - done(); - }); + const valueFalse = await lastValueFrom(valueFalse$); + expect(valueFalse).toEqual(false); }); - it('should return true if valid input is provided', (done) => { + it('should return true if valid input is provided', async () => { const idToken = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2V4YW1wbGUuY29tIiwic3ViIjoiMTIzNDU2IiwiYXVkIjoibXlfY2xpZW50X2lkIiwiZXhwIjoxMzExMjgxOTcwLCJpYXQiOjEzMTEyODA5NzAsIm5hbWUiOiJKYW5lIERvZSIsImdpdmVuX25hbWUiOiJKYW5lIiwiZmFtaWx5X25hbWUiOiJEb2UiLCJiaXJ0aGRhdGUiOiIxOTkwLTEwLTMxIiwiZW1haWwiOiJqYW5lZG9lQGV4YW1wbGUuY29tIiwicGljdHVyZSI6Imh0dHBzOi8vZXhhbXBsZS5jb20vamFuZWRvZS9tZS5qcGcifQ.SY0ilps7yKYmYCc41zNOatfmAFhOtDYwuIT80qrHMl_4FEO2WFWSv-aDl4QfTSKY9A6MMP6xy0Z_8Kk7NeRwIV7FVScMLnPvVzs9pxza0e_rl6hmZLb5P5n4AEINwn46X9XmRB5W3EZO_x2LG65_g3NZFiPrzOC1Fs_6taJl7TfI8lOveYDoJyXCWYQMS3Oh5MM9S8W-Hc29_qJLH-kixm1S01qoICRPDGMRwhtAu1DHjwWQp9Ycfz6g3uyb7N1imBvI49t1CwWy02_mQ3g-7e7bOP1Ax2kgrwnJgsVBDULnyCZG9PE8T0CHZl_fErZtvbJJ0jdoZ1fyr48906am2w'; const idTokenParts = idToken.split('.'); @@ -644,15 +634,13 @@ describe('TokenValidationService', () => { { configId: 'configId1' } ); - valueTrue$.subscribe((valueTrue) => { - expect(valueTrue).toEqual(true); - done(); - }); + const valueTrue = await lastValueFrom(valueTrue$); + expect(valueTrue).toEqual(true); }); }); describe('validateIdTokenAtHash', () => { - it('returns true if sha is sha256 and generated hash equals atHash param', (done) => { + it('returns true if sha is sha256 and generated hash equals atHash param', async () => { const accessToken = 'iGU3DhbPoDljiYtr0oepxi7zpT8BsjdU7aaXcdq-DPk'; const atHash = '-ODC_7Go_UIUTC8nP4k2cA'; @@ -663,10 +651,8 @@ describe('TokenValidationService', () => { { configId: 'configId1' } ); - result$.subscribe((result) => { - expect(result).toEqual(true); - done(); - }); + const result = await lastValueFrom(result$); + expect(result).toEqual(true); }); it('returns false if sha is sha256 and generated hash does not equal atHash param', async () => { @@ -686,15 +672,14 @@ describe('TokenValidationService', () => { expect(result).toEqual(false); }); - it('returns true if sha is sha256 and generated hash does equal atHash param', (done) => { + it('returns true if sha is sha256 and generated hash does equal atHash param', async () => { const accessToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ilg1ZVhrNHh5b2pORnVtMWtsMll0djhkbE5QNC1jNTdkTzZRR1RWQndhTmsifQ.eyJleHAiOjE1ODkyMTAwODYsIm5iZiI6MTU4OTIwNjQ4NiwidmVyIjoiMS4wIiwiaXNzIjoiaHR0cHM6Ly9kYW1pZW5ib2QuYjJjbG9naW4uY29tL2EwOTU4ZjQ1LTE5NWItNDAzNi05MjU5LWRlMmY3ZTU5NGRiNi92Mi4wLyIsInN1YiI6ImY4MzZmMzgwLTNjNjQtNDgwMi04ZGJjLTAxMTk4MWMwNjhmNSIsImF1ZCI6ImYxOTM0YTZlLTk1OGQtNDE5OC05ZjM2LTYxMjdjZmM0Y2RiMyIsIm5vbmNlIjoiMDA3YzQxNTNiNmEwNTE3YzBlNDk3NDc2ZmIyNDk5NDhlYzVjbE92UVEiLCJpYXQiOjE1ODkyMDY0ODYsImF1dGhfdGltZSI6MTU4OTIwNjQ4NiwibmFtZSI6ImRhbWllbmJvZCIsImVtYWlscyI6WyJkYW1pZW5AZGFtaWVuYm9kLm9ubWljcm9zb2Z0LmNvbSJdLCJ0ZnAiOiJCMkNfMV9iMmNwb2xpY3lkYW1pZW4iLCJhdF9oYXNoIjoiWmswZktKU19wWWhPcE04SUJhMTJmdyJ9.E5Z-0kOzNU7LBkeVHHMyNoER8TUapGzUUfXmW6gVu4v6QMM5fQ4sJ7KC8PHh8lBFYiCnaDiTtpn3QytUwjXEFnLDAX5qcZT1aPoEgL_OmZMC-8y-4GyHp35l7VFD4iNYM9fJmLE8SYHTVl7eWPlXSyz37Ip0ciiV0Fd6eoksD_aVc-hkIqngDfE4fR8ZKfv4yLTNN_SfknFfuJbZ56yN-zIBL4GkuHsbQCBYpjtWQ62v98p1jO7NhHKV5JP2ec_Ge6oYc_bKTrE6OIX38RJ2rIm7zU16mtdjnl_350Nw3ytHcTPnA1VpP_VLElCfe83jr5aDHc_UQRYaAcWlOgvmVg'; const atHash = 'good'; - vi.spyOn(jwtWindowCryptoService, 'generateAtHash').mockReturnValues( - of('notEqualsGood'), - of('good') - ); + vi.spyOn(jwtWindowCryptoService, 'generateAtHash') + .mockReturnValueOnce(of('notEqualsGood')) + .mockReturnValueOnce(of('good')); const result$ = tokenValidationService.validateIdTokenAtHash( accessToken, @@ -703,13 +688,11 @@ describe('TokenValidationService', () => { { configId: 'configId1' } ); - result$.subscribe((result) => { - expect(result).toEqual(true); - done(); - }); + const result = await lastValueFrom(result$); + expect(result).toEqual(true); }); - it('returns false if sha is sha384 and generated hash does not equal atHash param', (done) => { + it('returns false if sha is sha384 and generated hash does not equal atHash param', async () => { const accessToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ilg1ZVhrNHh5b2pORnVtMWtsMll0djhkbE5QNC1jNTdkTzZRR1RWQndhTmsifQ.eyJleHAiOjE1ODkyMTAwODYsIm5iZiI6MTU4OTIwNjQ4NiwidmVyIjoiMS4wIiwiaXNzIjoiaHR0cHM6Ly9kYW1pZW5ib2QuYjJjbG9naW4uY29tL2EwOTU4ZjQ1LTE5NWItNDAzNi05MjU5LWRlMmY3ZTU5NGRiNi92Mi4wLyIsInN1YiI6ImY4MzZmMzgwLTNjNjQtNDgwMi04ZGJjLTAxMTk4MWMwNjhmNSIsImF1ZCI6ImYxOTM0YTZlLTk1OGQtNDE5OC05ZjM2LTYxMjdjZmM0Y2RiMyIsIm5vbmNlIjoiMDA3YzQxNTNiNmEwNTE3YzBlNDk3NDc2ZmIyNDk5NDhlYzVjbE92UVEiLCJpYXQiOjE1ODkyMDY0ODYsImF1dGhfdGltZSI6MTU4OTIwNjQ4NiwibmFtZSI6ImRhbWllbmJvZCIsImVtYWlscyI6WyJkYW1pZW5AZGFtaWVuYm9kLm9ubWljcm9zb2Z0LmNvbSJdLCJ0ZnAiOiJCMkNfMV9iMmNwb2xpY3lkYW1pZW4iLCJhdF9oYXNoIjoiWmswZktKU19wWWhPcE04SUJhMTJmdyJ9.E5Z-0kOzNU7LBkeVHHMyNoER8TUapGzUUfXmW6gVu4v6QMM5fQ4sJ7KC8PHh8lBFYiCnaDiTtpn3QytUwjXEFnLDAX5qcZT1aPoEgL_OmZMC-8y-4GyHp35l7VFD4iNYM9fJmLE8SYHTVl7eWPlXSyz37Ip0ciiV0Fd6eoksD_aVc-hkIqngDfE4fR8ZKfv4yLTNN_SfknFfuJbZ56yN-zIBL4GkuHsbQCBYpjtWQ62v98p1jO7NhHKV5JP2ec_Ge6oYc_bKTrE6OIX38RJ2rIm7zU16mtdjnl_350Nw3ytHcTPnA1VpP_VLElCfe83jr5aDHc_UQRYaAcWlOgvmVg'; const atHash = 'bad'; @@ -721,13 +704,11 @@ describe('TokenValidationService', () => { { configId: 'configId1' } ); - result$.subscribe((result) => { - expect(result).toEqual(false); - done(); - }); + const result = await lastValueFrom(result$); + expect(result).toEqual(false); }); - it('returns false if sha is sha512 and generated hash does not equal atHash param', (done) => { + it('returns false if sha is sha512 and generated hash does not equal atHash param', async () => { const accessToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ilg1ZVhrNHh5b2pORnVtMWtsMll0djhkbE5QNC1jNTdkTzZRR1RWQndhTmsifQ.eyJleHAiOjE1ODkyMTAwODYsIm5iZiI6MTU4OTIwNjQ4NiwidmVyIjoiMS4wIiwiaXNzIjoiaHR0cHM6Ly9kYW1pZW5ib2QuYjJjbG9naW4uY29tL2EwOTU4ZjQ1LTE5NWItNDAzNi05MjU5LWRlMmY3ZTU5NGRiNi92Mi4wLyIsInN1YiI6ImY4MzZmMzgwLTNjNjQtNDgwMi04ZGJjLTAxMTk4MWMwNjhmNSIsImF1ZCI6ImYxOTM0YTZlLTk1OGQtNDE5OC05ZjM2LTYxMjdjZmM0Y2RiMyIsIm5vbmNlIjoiMDA3YzQxNTNiNmEwNTE3YzBlNDk3NDc2ZmIyNDk5NDhlYzVjbE92UVEiLCJpYXQiOjE1ODkyMDY0ODYsImF1dGhfdGltZSI6MTU4OTIwNjQ4NiwibmFtZSI6ImRhbWllbmJvZCIsImVtYWlscyI6WyJkYW1pZW5AZGFtaWVuYm9kLm9ubWljcm9zb2Z0LmNvbSJdLCJ0ZnAiOiJCMkNfMV9iMmNwb2xpY3lkYW1pZW4iLCJhdF9oYXNoIjoiWmswZktKU19wWWhPcE04SUJhMTJmdyJ9.E5Z-0kOzNU7LBkeVHHMyNoER8TUapGzUUfXmW6gVu4v6QMM5fQ4sJ7KC8PHh8lBFYiCnaDiTtpn3QytUwjXEFnLDAX5qcZT1aPoEgL_OmZMC-8y-4GyHp35l7VFD4iNYM9fJmLE8SYHTVl7eWPlXSyz37Ip0ciiV0Fd6eoksD_aVc-hkIqngDfE4fR8ZKfv4yLTNN_SfknFfuJbZ56yN-zIBL4GkuHsbQCBYpjtWQ62v98p1jO7NhHKV5JP2ec_Ge6oYc_bKTrE6OIX38RJ2rIm7zU16mtdjnl_350Nw3ytHcTPnA1VpP_VLElCfe83jr5aDHc_UQRYaAcWlOgvmVg'; const atHash = 'bad'; @@ -739,10 +720,8 @@ describe('TokenValidationService', () => { { configId: 'configId1' } ); - result$.subscribe((result) => { - expect(result).toEqual(false); - done(); - }); + const result = await lastValueFrom(result$); + expect(result).toEqual(false); }); }); @@ -817,8 +796,8 @@ describe('TokenValidationService', () => { }, ]; - testCases.forEach(({ date, offsetSeconds, expectedResult }) => { - it(`returns ${expectedResult} if ${date} is given with an offset of ${offsetSeconds}`, () => { + for (const { date, offsetSeconds, expectedResult } of testCases) { + it(`returns $expectedResultif ${date} is given with an offset of $offsetSeconds`, () => { const notExpired = tokenValidationService.validateAccessTokenNotExpired( date as Date, { configId: 'configId1' }, @@ -827,7 +806,7 @@ describe('TokenValidationService', () => { expect(notExpired).toEqual(expectedResult); }); - }); + } }); describe('hasIdTokenExpired', () => {