feat: init

This commit is contained in:
2025-01-30 20:02:28 +08:00
parent da0d9855da
commit 1785df25e2
125 changed files with 8601 additions and 4725 deletions

View File

@@ -1,14 +1,15 @@
import { HttpErrorResponse, HttpHeaders } from '@angular/common/http';
import { TestBed, waitForAsync } from '@angular/core/testing';
import { TestBed, mockImplementationWhenArgsEqual } from '@/testing';
import { HttpErrorResponse, HttpHeaders } from '@ngify/http';
import { of, throwError } from 'rxjs';
import { mockProvider } from '../../../test/auto-mock';
import { createRetriableStream } from '../../../test/create-retriable-stream.helper';
import { vi } from 'vitest';
import { DataService } from '../../api/data.service';
import { LoggerService } from '../../logging/logger.service';
import { StoragePersistenceService } from '../../storage/storage-persistence.service';
import { createRetriableStream } from '../../testing/create-retriable-stream.helper';
import { mockProvider } from '../../testing/mock';
import { UrlService } from '../../utils/url/url.service';
import { TokenValidationService } from '../../validation/token-validation.service';
import { CallbackContext } from '../callback-context';
import type { CallbackContext } from '../callback-context';
import { FlowsDataService } from '../flows-data.service';
import { CodeFlowCallbackHandlerService } from './code-flow-callback-handler.service';
@@ -46,13 +47,16 @@ describe('CodeFlowCallbackHandlerService', () => {
});
describe('codeFlowCallback', () => {
it('throws error if no state is given', waitForAsync(() => {
const getUrlParameterSpy = spyOn(
urlService,
'getUrlParameter'
).and.returnValue('params');
it('throws error if no state is given', async () => {
const getUrlParameterSpy = vi
.spyOn(urlService, 'getUrlParameter')
.mockReturnValue('params');
getUrlParameterSpy.withArgs('test-url', 'state').and.returnValue('');
mockImplementationWhenArgsEqual(
getUrlParameterSpy,
['test-url', 'state'],
() => ''
);
service
.codeFlowCallback('test-url', { configId: 'configId1' })
@@ -61,15 +65,14 @@ describe('CodeFlowCallbackHandlerService', () => {
expect(err).toBeTruthy();
},
});
}));
});
it('throws error if no code is given', waitForAsync(() => {
const getUrlParameterSpy = spyOn(
urlService,
'getUrlParameter'
).and.returnValue('params');
it('throws error if no code is given', async () => {
const getUrlParameterSpy = vi
.spyOn(urlService, 'getUrlParameter')
.mockReturnValue('params');
getUrlParameterSpy.withArgs('test-url', 'code').and.returnValue('');
getUrlParameterSpy.withArgs('test-url', 'code').mockReturnValue('');
service
.codeFlowCallback('test-url', { configId: 'configId1' })
@@ -78,10 +81,10 @@ describe('CodeFlowCallbackHandlerService', () => {
expect(err).toBeTruthy();
},
});
}));
});
it('returns callbackContext if all params are good', waitForAsync(() => {
spyOn(urlService, 'getUrlParameter').and.returnValue('params');
it('returns callbackContext if all params are good', async () => {
vi.spyOn(urlService, 'getUrlParameter').mockReturnValue('params');
const expectedCallbackContext = {
code: 'params',
@@ -100,7 +103,7 @@ describe('CodeFlowCallbackHandlerService', () => {
.subscribe((callbackContext) => {
expect(callbackContext).toEqual(expectedCallbackContext);
});
}));
});
});
describe('codeFlowCodeRequest ', () => {
@@ -112,11 +115,11 @@ describe('CodeFlowCallbackHandlerService', () => {
url: 'https://identity-server.test/openid-connect/token',
});
it('throws error if state is not correct', waitForAsync(() => {
spyOn(
it('throws error if state is not correct', async () => {
vi.spyOn(
tokenValidationService,
'validateStateFromHashCallback'
).and.returnValue(false);
).mockReturnValue(false);
service
.codeFlowCodeRequest({} as CallbackContext, { configId: 'configId1' })
@@ -125,16 +128,18 @@ describe('CodeFlowCallbackHandlerService', () => {
expect(err).toBeTruthy();
},
});
}));
});
it('throws error if authWellknownEndpoints is null is given', waitForAsync(() => {
spyOn(
it('throws error if authWellknownEndpoints is null is given', async () => {
vi.spyOn(
tokenValidationService,
'validateStateFromHashCallback'
).and.returnValue(true);
spyOn(storagePersistenceService, 'read')
.withArgs('authWellKnownEndPoints', { configId: 'configId1' })
.and.returnValue(null);
).mockReturnValue(true);
mockImplementationWhenArgsEqual(
vi.spyOn(storagePersistenceService, 'read'),
['authWellKnownEndPoints', { configId: 'configId1' }],
() => null
);
service
.codeFlowCodeRequest({} as CallbackContext, { configId: 'configId1' })
@@ -143,16 +148,18 @@ describe('CodeFlowCallbackHandlerService', () => {
expect(err).toBeTruthy();
},
});
}));
});
it('throws error if tokenendpoint is null is given', waitForAsync(() => {
spyOn(
it('throws error if tokenendpoint is null is given', async () => {
vi.spyOn(
tokenValidationService,
'validateStateFromHashCallback'
).and.returnValue(true);
spyOn(storagePersistenceService, 'read')
.withArgs('authWellKnownEndPoints', { configId: 'configId1' })
.and.returnValue({ tokenEndpoint: null });
).mockReturnValue(true);
mockImplementationWhenArgsEqual(
vi.spyOn(storagePersistenceService, 'read'),
['authWellKnownEndPoints', { configId: 'configId1' }],
() => ({ tokenEndpoint: null })
);
service
.codeFlowCodeRequest({} as CallbackContext, { configId: 'configId1' })
@@ -161,34 +168,36 @@ describe('CodeFlowCallbackHandlerService', () => {
expect(err).toBeTruthy();
},
});
}));
});
it('calls dataService if all params are good', waitForAsync(() => {
const postSpy = spyOn(dataService, 'post').and.returnValue(of({}));
it('calls dataService if all params are good', async () => {
const postSpy = vi.spyOn(dataService, 'post').mockReturnValue(of({}));
spyOn(storagePersistenceService, 'read')
.withArgs('authWellKnownEndPoints', { configId: 'configId1' })
.and.returnValue({ tokenEndpoint: 'tokenEndpoint' });
mockImplementationWhenArgsEqual(
vi.spyOn(storagePersistenceService, 'read'),
['authWellKnownEndPoints', { configId: 'configId1' }],
() => ({ tokenEndpoint: 'tokenEndpoint' })
);
spyOn(
vi.spyOn(
tokenValidationService,
'validateStateFromHashCallback'
).and.returnValue(true);
).mockReturnValue(true);
service
.codeFlowCodeRequest({} as CallbackContext, { configId: 'configId1' })
.subscribe(() => {
expect(postSpy).toHaveBeenCalledOnceWith(
expect(postSpy).toHaveBeenCalledExactlyOnceWith(
'tokenEndpoint',
undefined,
{ configId: 'configId1' },
jasmine.any(HttpHeaders)
expect.any(HttpHeaders)
);
});
}));
});
it('calls url service with custom token params', waitForAsync(() => {
const urlServiceSpy = spyOn(
it('calls url service with custom token params', async () => {
const urlServiceSpy = vi.spyOn(
urlService,
'createBodyForCodeFlowCodeRequest'
);
@@ -197,76 +206,84 @@ describe('CodeFlowCallbackHandlerService', () => {
customParamsCodeRequest: { foo: 'bar' },
};
spyOn(storagePersistenceService, 'read')
.withArgs('authWellKnownEndPoints', config)
.and.returnValue({ tokenEndpoint: 'tokenEndpoint' });
mockImplementationWhenArgsEqual(
vi.spyOn(storagePersistenceService, 'read'),
['authWellKnownEndPoints', config],
() => ({ tokenEndpoint: 'tokenEndpoint' })
);
spyOn(
vi.spyOn(
tokenValidationService,
'validateStateFromHashCallback'
).and.returnValue(true);
).mockReturnValue(true);
const postSpy = spyOn(dataService, 'post').and.returnValue(of({}));
const postSpy = vi.spyOn(dataService, 'post').mockReturnValue(of({}));
service
.codeFlowCodeRequest({ code: 'foo' } as CallbackContext, config)
.subscribe(() => {
expect(urlServiceSpy).toHaveBeenCalledOnceWith('foo', config, {
expect(urlServiceSpy).toHaveBeenCalledExactlyOnceWith('foo', config, {
foo: 'bar',
});
expect(postSpy).toHaveBeenCalledTimes(1);
});
}));
});
it('calls dataService with correct headers if all params are good', waitForAsync(() => {
const postSpy = spyOn(dataService, 'post').and.returnValue(of({}));
it('calls dataService with correct headers if all params are good', async () => {
const postSpy = vi.spyOn(dataService, 'post').mockReturnValue(of({}));
const config = {
configId: 'configId1',
customParamsCodeRequest: { foo: 'bar' },
};
spyOn(storagePersistenceService, 'read')
.withArgs('authWellKnownEndPoints', config)
.and.returnValue({ tokenEndpoint: 'tokenEndpoint' });
mockImplementationWhenArgsEqual(
vi.spyOn(storagePersistenceService, 'read'),
['authWellKnownEndPoints', config],
() => ({ tokenEndpoint: 'tokenEndpoint' })
);
spyOn(
vi.spyOn(
tokenValidationService,
'validateStateFromHashCallback'
).and.returnValue(true);
).mockReturnValue(true);
service
.codeFlowCodeRequest({} as CallbackContext, config)
.subscribe(() => {
const httpHeaders = postSpy.calls.mostRecent().args[3] as HttpHeaders;
expect(httpHeaders.has('Content-Type')).toBeTrue();
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', waitForAsync(() => {
spyOn(dataService, 'post').and.returnValue(throwError(() => HTTP_ERROR));
it('returns error in case of http error', async () => {
vi.spyOn(dataService, 'post').mockReturnValue(
throwError(() => HTTP_ERROR)
);
const config = {
configId: 'configId1',
customParamsCodeRequest: { foo: 'bar' },
authority: 'authority',
};
spyOn(storagePersistenceService, 'read')
.withArgs('authWellKnownEndPoints', config)
.and.returnValue({ tokenEndpoint: 'tokenEndpoint' });
mockImplementationWhenArgsEqual(
vi.spyOn(storagePersistenceService, 'read'),
['authWellKnownEndPoints', config],
() => ({ tokenEndpoint: 'tokenEndpoint' })
);
service.codeFlowCodeRequest({} as CallbackContext, config).subscribe({
error: (err) => {
expect(err).toBeTruthy();
},
});
}));
});
it('retries request in case of no connection http error and succeeds', waitForAsync(() => {
const postSpy = spyOn(dataService, 'post').and.returnValue(
it('retries request in case of no connection http error and succeeds', async () => {
const postSpy = vi.spyOn(dataService, 'post').mockReturnValue(
createRetriableStream(
throwError(() => CONNECTION_ERROR),
of({})
@@ -278,14 +295,16 @@ describe('CodeFlowCallbackHandlerService', () => {
authority: 'authority',
};
spyOn(storagePersistenceService, 'read')
.withArgs('authWellKnownEndPoints', config)
.and.returnValue({ tokenEndpoint: 'tokenEndpoint' });
mockImplementationWhenArgsEqual(
vi.spyOn(storagePersistenceService, 'read'),
['authWellKnownEndPoints', config],
() => ({ tokenEndpoint: 'tokenEndpoint' })
);
spyOn(
vi.spyOn(
tokenValidationService,
'validateStateFromHashCallback'
).and.returnValue(true);
).mockReturnValue(true);
service.codeFlowCodeRequest({} as CallbackContext, config).subscribe({
next: (res) => {
@@ -297,10 +316,10 @@ describe('CodeFlowCallbackHandlerService', () => {
expect(err).toBeFalsy();
},
});
}));
});
it('retries request in case of no connection http error and fails because of http error afterwards', waitForAsync(() => {
const postSpy = spyOn(dataService, 'post').and.returnValue(
it('retries request in case of no connection http error and fails because of http error afterwards', async () => {
const postSpy = vi.spyOn(dataService, 'post').mockReturnValue(
createRetriableStream(
throwError(() => CONNECTION_ERROR),
throwError(() => HTTP_ERROR)
@@ -312,14 +331,16 @@ describe('CodeFlowCallbackHandlerService', () => {
authority: 'authority',
};
spyOn(storagePersistenceService, 'read')
.withArgs('authWellKnownEndPoints', config)
.and.returnValue({ tokenEndpoint: 'tokenEndpoint' });
mockImplementationWhenArgsEqual(
vi.spyOn(storagePersistenceService, 'read'),
['authWellKnownEndPoints', config],
() => ({ tokenEndpoint: 'tokenEndpoint' })
);
spyOn(
vi.spyOn(
tokenValidationService,
'validateStateFromHashCallback'
).and.returnValue(true);
).mockReturnValue(true);
service.codeFlowCodeRequest({} as CallbackContext, config).subscribe({
next: (res) => {
@@ -331,6 +352,6 @@ describe('CodeFlowCallbackHandlerService', () => {
expect(postSpy).toHaveBeenCalledTimes(1);
},
});
}));
});
});
});

View File

@@ -1,4 +1,4 @@
import { HttpErrorResponse } from '@angular/common/http';
import { HttpErrorResponse } from '@ngify/http';
import { isNetworkError } from './error-helper';
describe('error helper', () => {
@@ -27,31 +27,31 @@ describe('error helper', () => {
});
it('returns true on http error with status = 0', () => {
expect(isNetworkError(CONNECTION_ERROR)).toBeTrue();
expect(isNetworkError(CONNECTION_ERROR)).toBeTruthy();
});
it('returns true on http error with status = 0 and unknown error', () => {
expect(isNetworkError(UNKNOWN_CONNECTION_ERROR)).toBeTrue();
expect(isNetworkError(UNKNOWN_CONNECTION_ERROR)).toBeTruthy();
});
it('returns true on http error with status <> 0 and error ProgressEvent', () => {
expect(isNetworkError(PARTIAL_CONNECTION_ERROR)).toBeTrue();
expect(isNetworkError(PARTIAL_CONNECTION_ERROR)).toBeTruthy();
});
it('returns false on non http error', () => {
expect(isNetworkError(new Error('not a HttpErrorResponse'))).toBeFalse();
expect(isNetworkError(new Error('not a HttpErrorResponse'))).toBeFalsy();
});
it('returns false on string error', () => {
expect(isNetworkError('not a HttpErrorResponse')).toBeFalse();
expect(isNetworkError('not a HttpErrorResponse')).toBeFalsy();
});
it('returns false on undefined', () => {
expect(isNetworkError(undefined)).toBeFalse();
expect(isNetworkError(undefined)).toBeFalsy();
});
it('returns false on empty http error', () => {
expect(isNetworkError(HTTP_ERROR)).toBeFalse();
expect(isNetworkError(HTTP_ERROR)).toBeFalsy();
});
});
});

View File

@@ -1,12 +1,13 @@
import { TestBed, waitForAsync } from '@angular/core/testing';
import { TestBed } from '@/testing';
import { of, throwError } from 'rxjs';
import { mockProvider } from '../../../test/auto-mock';
import { vi } from 'vitest';
import { AuthStateService } from '../../auth-state/auth-state.service';
import { LoggerService } from '../../logging/logger.service';
import { StoragePersistenceService } from '../../storage/storage-persistence.service';
import { JwtKey, JwtKeys } from '../../validation/jwtkeys';
import { mockProvider } from '../../testing/mock';
import type { JwtKey, JwtKeys } from '../../validation/jwtkeys';
import { ValidationResult } from '../../validation/validation-result';
import { AuthResult, CallbackContext } from '../callback-context';
import type { AuthResult, CallbackContext } from '../callback-context';
import { FlowsDataService } from '../flows-data.service';
import { ResetAuthDataService } from '../reset-auth-data.service';
import { SigninKeyDataService } from '../signin-key-data.service';
@@ -46,9 +47,6 @@ describe('HistoryJwtKeysCallbackHandlerService', () => {
mockProvider(ResetAuthDataService),
],
});
});
beforeEach(() => {
service = TestBed.inject(HistoryJwtKeysCallbackHandlerService);
storagePersistenceService = TestBed.inject(StoragePersistenceService);
resetAuthDataService = TestBed.inject(ResetAuthDataService);
@@ -62,8 +60,8 @@ describe('HistoryJwtKeysCallbackHandlerService', () => {
});
describe('callbackHistoryAndResetJwtKeys', () => {
it('writes authResult into the storage', waitForAsync(() => {
const storagePersistenceServiceSpy = spyOn(
it('writes authResult into the storage', async () => {
const storagePersistenceServiceSpy = vi.spyOn(
storagePersistenceService,
'write'
);
@@ -75,86 +73,86 @@ describe('HistoryJwtKeysCallbackHandlerService', () => {
const callbackContext = {
authResult: DUMMY_AUTH_RESULT,
} as CallbackContext;
const allconfigs = [
const allConfigs = [
{
configId: 'configId1',
historyCleanupOff: true,
},
];
spyOn(signInKeyDataService, 'getSigningKeys').and.returnValue(
vi.spyOn(signInKeyDataService, 'getSigningKeys').mockReturnValue(
of({ keys: [] } as JwtKeys)
);
service
.callbackHistoryAndResetJwtKeys(
callbackContext,
allconfigs[0],
allconfigs
allConfigs[0]!,
allConfigs
)
.subscribe(() => {
expect(storagePersistenceServiceSpy.calls.allArgs()).toEqual([
['authnResult', DUMMY_AUTH_RESULT, allconfigs[0]],
['jwtKeys', { keys: [] }, allconfigs[0]],
expect(storagePersistenceServiceSpy).toBeCalledWith([
['authnResult', DUMMY_AUTH_RESULT, allConfigs[0]],
['jwtKeys', { keys: [] }, allConfigs[0]],
]);
// write authnResult & jwtKeys
expect(storagePersistenceServiceSpy).toHaveBeenCalledTimes(2);
});
}));
});
it('writes refresh_token into the storage without reuse (refresh token rotation)', waitForAsync(() => {
it('writes refresh_token into the storage without reuse (refresh token rotation)', async () => {
const DUMMY_AUTH_RESULT = {
refresh_token: 'dummy_refresh_token',
id_token: 'some-id-token',
};
const storagePersistenceServiceSpy = spyOn(
const storagePersistenceServiceSpy = vi.spyOn(
storagePersistenceService,
'write'
);
const callbackContext = {
authResult: DUMMY_AUTH_RESULT,
} as CallbackContext;
const allconfigs = [
const allConfigs = [
{
configId: 'configId1',
historyCleanupOff: true,
},
];
spyOn(signInKeyDataService, 'getSigningKeys').and.returnValue(
vi.spyOn(signInKeyDataService, 'getSigningKeys').mockReturnValue(
of({ keys: [] } as JwtKeys)
);
service
.callbackHistoryAndResetJwtKeys(
callbackContext,
allconfigs[0],
allconfigs
allConfigs[0]!,
allConfigs
)
.subscribe(() => {
expect(storagePersistenceServiceSpy.calls.allArgs()).toEqual([
['authnResult', DUMMY_AUTH_RESULT, allconfigs[0]],
['jwtKeys', { keys: [] }, allconfigs[0]],
expect(storagePersistenceServiceSpy).toBeCalledWith([
['authnResult', DUMMY_AUTH_RESULT, allConfigs[0]],
['jwtKeys', { keys: [] }, allConfigs[0]],
]);
// write authnResult & refresh_token & jwtKeys
expect(storagePersistenceServiceSpy).toHaveBeenCalledTimes(2);
});
}));
});
it('writes refresh_token into the storage with reuse (without refresh token rotation)', waitForAsync(() => {
it('writes refresh_token into the storage with reuse (without refresh token rotation)', async () => {
const DUMMY_AUTH_RESULT = {
refresh_token: 'dummy_refresh_token',
id_token: 'some-id-token',
};
const storagePersistenceServiceSpy = spyOn(
const storagePersistenceServiceSpy = vi.spyOn(
storagePersistenceService,
'write'
);
const callbackContext = {
authResult: DUMMY_AUTH_RESULT,
} as CallbackContext;
const allconfigs = [
const allConfigs = [
{
configId: 'configId1',
historyCleanupOff: true,
@@ -162,27 +160,27 @@ describe('HistoryJwtKeysCallbackHandlerService', () => {
},
];
spyOn(signInKeyDataService, 'getSigningKeys').and.returnValue(
vi.spyOn(signInKeyDataService, 'getSigningKeys').mockReturnValue(
of({ keys: [] } as JwtKeys)
);
service
.callbackHistoryAndResetJwtKeys(
callbackContext,
allconfigs[0],
allconfigs
allConfigs[0]!,
allConfigs
)
.subscribe(() => {
expect(storagePersistenceServiceSpy.calls.allArgs()).toEqual([
['authnResult', DUMMY_AUTH_RESULT, allconfigs[0]],
['reusable_refresh_token', 'dummy_refresh_token', allconfigs[0]],
['jwtKeys', { keys: [] }, allconfigs[0]],
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);
});
}));
});
it('resetBrowserHistory if historyCleanup is turned on and is not in a renewProcess', waitForAsync(() => {
it('resetBrowserHistory if historyCleanup is turned on and is not in a renewProcess', async () => {
const DUMMY_AUTH_RESULT = {
id_token: 'some-id-token',
};
@@ -190,30 +188,30 @@ describe('HistoryJwtKeysCallbackHandlerService', () => {
isRenewProcess: false,
authResult: DUMMY_AUTH_RESULT,
} as CallbackContext;
const allconfigs = [
const allConfigs = [
{
configId: 'configId1',
historyCleanupOff: false,
},
];
const windowSpy = spyOn(window.history, 'replaceState');
const windowSpy = vi.spyOn(window.history, 'replaceState');
spyOn(signInKeyDataService, 'getSigningKeys').and.returnValue(
vi.spyOn(signInKeyDataService, 'getSigningKeys').mockReturnValue(
of({ keys: [] } as JwtKeys)
);
service
.callbackHistoryAndResetJwtKeys(
callbackContext,
allconfigs[0],
allconfigs
allConfigs[0]!,
allConfigs
)
.subscribe(() => {
expect(windowSpy).toHaveBeenCalledTimes(1);
});
}));
});
it('returns callbackContext with jwtkeys filled if everything works fine', waitForAsync(() => {
it('returns callbackContext with jwtkeys filled if everything works fine', async () => {
const DUMMY_AUTH_RESULT = {
id_token: 'some-id-token',
};
@@ -222,21 +220,21 @@ describe('HistoryJwtKeysCallbackHandlerService', () => {
isRenewProcess: false,
authResult: DUMMY_AUTH_RESULT,
} as CallbackContext;
const allconfigs = [
const allConfigs = [
{
configId: 'configId1',
historyCleanupOff: false,
},
];
spyOn(signInKeyDataService, 'getSigningKeys').and.returnValue(
vi.spyOn(signInKeyDataService, 'getSigningKeys').mockReturnValue(
of({ keys: [{ kty: 'henlo' } as JwtKey] } as JwtKeys)
);
service
.callbackHistoryAndResetJwtKeys(
callbackContext,
allconfigs[0],
allconfigs
allConfigs[0]!,
allConfigs
)
.subscribe((result) => {
expect(result).toEqual({
@@ -245,9 +243,9 @@ describe('HistoryJwtKeysCallbackHandlerService', () => {
jwtKeys: { keys: [{ kty: 'henlo' }] },
} as CallbackContext);
});
}));
});
it('returns error if no jwtKeys have been in the call --> keys are null', waitForAsync(() => {
it('returns error if no jwtKeys have been in the call --> keys are null', async () => {
const DUMMY_AUTH_RESULT = {
id_token: 'some-id-token',
};
@@ -256,32 +254,32 @@ describe('HistoryJwtKeysCallbackHandlerService', () => {
isRenewProcess: false,
authResult: DUMMY_AUTH_RESULT,
} as CallbackContext;
const allconfigs = [
const allConfigs = [
{
configId: 'configId1',
historyCleanupOff: false,
},
];
spyOn(signInKeyDataService, 'getSigningKeys').and.returnValue(
vi.spyOn(signInKeyDataService, 'getSigningKeys').mockReturnValue(
of({} as JwtKeys)
);
service
.callbackHistoryAndResetJwtKeys(
callbackContext,
allconfigs[0],
allconfigs
allConfigs[0]!,
allConfigs
)
.subscribe({
error: (err) => {
expect(err.message).toEqual(
`Failed to retrieve signing key with error: Error: Failed to retrieve signing key`
'Failed to retrieve signing key with error: Error: Failed to retrieve signing key'
);
},
});
}));
});
it('returns error if no jwtKeys have been in the call --> keys throw an error', waitForAsync(() => {
it('returns error if no jwtKeys have been in the call --> keys throw an error', async () => {
const DUMMY_AUTH_RESULT = {
id_token: 'some-id-token',
};
@@ -289,36 +287,36 @@ describe('HistoryJwtKeysCallbackHandlerService', () => {
isRenewProcess: false,
authResult: DUMMY_AUTH_RESULT,
} as CallbackContext;
const allconfigs = [
const allConfigs = [
{
configId: 'configId1',
historyCleanupOff: false,
},
];
spyOn(signInKeyDataService, 'getSigningKeys').and.returnValue(
vi.spyOn(signInKeyDataService, 'getSigningKeys').mockReturnValue(
throwError(() => new Error('error'))
);
service
.callbackHistoryAndResetJwtKeys(
callbackContext,
allconfigs[0],
allconfigs
allConfigs[0]!,
allConfigs
)
.subscribe({
error: (err) => {
expect(err.message).toEqual(
`Failed to retrieve signing key with error: Error: Error: error`
'Failed to retrieve signing key with error: Error: Error: error'
);
},
});
}));
});
it('returns error if callbackContext.authresult has an error property filled', waitForAsync(() => {
it('returns error if callbackContext.authresult has an error property filled', async () => {
const callbackContext = {
authResult: { error: 'someError' },
} as CallbackContext;
const allconfigs = [
const allConfigs = [
{
configId: 'configId1',
historyCleanupOff: true,
@@ -328,36 +326,36 @@ describe('HistoryJwtKeysCallbackHandlerService', () => {
service
.callbackHistoryAndResetJwtKeys(
callbackContext,
allconfigs[0],
allconfigs
allConfigs[0]!,
allConfigs
)
.subscribe({
error: (err) => {
expect(err.message).toEqual(
`AuthCallback AuthResult came with error: someError`
'AuthCallback AuthResult came with error: someError'
);
},
});
}));
});
it('calls resetAuthorizationData, resets nonce and authStateService in case of an error', waitForAsync(() => {
it('calls resetAuthorizationData, resets nonce and authStateService in case of an error', async () => {
const callbackContext = {
authResult: { error: 'someError' },
isRenewProcess: false,
} as CallbackContext;
const allconfigs = [
const allConfigs = [
{
configId: 'configId1',
historyCleanupOff: true,
},
];
const resetAuthorizationDataSpy = spyOn(
const resetAuthorizationDataSpy = vi.spyOn(
resetAuthDataService,
'resetAuthorizationData'
);
const setNonceSpy = spyOn(flowsDataService, 'setNonce');
const updateAndPublishAuthStateSpy = spyOn(
const setNonceSpy = vi.spyOn(flowsDataService, 'setNonce');
const updateAndPublishAuthStateSpy = vi.spyOn(
authStateService,
'updateAndPublishAuthState'
);
@@ -365,40 +363,42 @@ describe('HistoryJwtKeysCallbackHandlerService', () => {
service
.callbackHistoryAndResetJwtKeys(
callbackContext,
allconfigs[0],
allconfigs
allConfigs[0]!,
allConfigs
)
.subscribe({
error: () => {
expect(resetAuthorizationDataSpy).toHaveBeenCalledTimes(1);
expect(setNonceSpy).toHaveBeenCalledTimes(1);
expect(updateAndPublishAuthStateSpy).toHaveBeenCalledOnceWith({
expect(
updateAndPublishAuthStateSpy
).toHaveBeenCalledExactlyOnceWith({
isAuthenticated: false,
validationResult: ValidationResult.SecureTokenServerError,
isRenewProcess: false,
});
},
});
}));
});
it('calls authStateService.updateAndPublishAuthState with login required if the error is `login_required`', waitForAsync(() => {
it('calls authStateService.updateAndPublishAuthState with login required if the error is `login_required`', async () => {
const callbackContext = {
authResult: { error: 'login_required' },
isRenewProcess: false,
} as CallbackContext;
const allconfigs = [
const allConfigs = [
{
configId: 'configId1',
historyCleanupOff: true,
},
];
const resetAuthorizationDataSpy = spyOn(
const resetAuthorizationDataSpy = vi.spyOn(
resetAuthDataService,
'resetAuthorizationData'
);
const setNonceSpy = spyOn(flowsDataService, 'setNonce');
const updateAndPublishAuthStateSpy = spyOn(
const setNonceSpy = vi.spyOn(flowsDataService, 'setNonce');
const updateAndPublishAuthStateSpy = vi.spyOn(
authStateService,
'updateAndPublishAuthState'
);
@@ -406,23 +406,25 @@ describe('HistoryJwtKeysCallbackHandlerService', () => {
service
.callbackHistoryAndResetJwtKeys(
callbackContext,
allconfigs[0],
allconfigs
allConfigs[0]!,
allConfigs
)
.subscribe({
error: () => {
expect(resetAuthorizationDataSpy).toHaveBeenCalledTimes(1);
expect(setNonceSpy).toHaveBeenCalledTimes(1);
expect(updateAndPublishAuthStateSpy).toHaveBeenCalledOnceWith({
expect(
updateAndPublishAuthStateSpy
).toHaveBeenCalledExactlyOnceWith({
isAuthenticated: false,
validationResult: ValidationResult.LoginRequired,
isRenewProcess: false,
});
},
});
}));
});
it('should store jwtKeys', waitForAsync(() => {
it('should store jwtKeys', async () => {
const DUMMY_AUTH_RESULT = {
id_token: 'some-id-token',
};
@@ -430,33 +432,33 @@ describe('HistoryJwtKeysCallbackHandlerService', () => {
const initialCallbackContext = {
authResult: DUMMY_AUTH_RESULT,
} as CallbackContext;
const allconfigs = [
const allConfigs = [
{
configId: 'configId1',
historyCleanupOff: true,
},
];
const storagePersistenceServiceSpy = spyOn(
const storagePersistenceServiceSpy = vi.spyOn(
storagePersistenceService,
'write'
);
spyOn(signInKeyDataService, 'getSigningKeys').and.returnValue(
vi.spyOn(signInKeyDataService, 'getSigningKeys').mockReturnValue(
of(DUMMY_JWT_KEYS)
);
service
.callbackHistoryAndResetJwtKeys(
initialCallbackContext,
allconfigs[0],
allconfigs
allConfigs[0]!,
allConfigs
)
.subscribe({
next: (callbackContext: CallbackContext) => {
expect(storagePersistenceServiceSpy).toHaveBeenCalledTimes(2);
expect(storagePersistenceServiceSpy.calls.allArgs()).toEqual([
['authnResult', DUMMY_AUTH_RESULT, allconfigs[0]],
['jwtKeys', DUMMY_JWT_KEYS, allconfigs[0]],
expect(storagePersistenceServiceSpy).toBeCalledWith([
['authnResult', DUMMY_AUTH_RESULT, allConfigs[0]],
['jwtKeys', DUMMY_JWT_KEYS, allConfigs[0]],
]);
expect(callbackContext.jwtKeys).toEqual(DUMMY_JWT_KEYS);
@@ -465,9 +467,9 @@ describe('HistoryJwtKeysCallbackHandlerService', () => {
expect(err).toBeFalsy();
},
});
}));
});
it('should not store jwtKeys on error', waitForAsync(() => {
it('should not store jwtKeys on error', async () => {
const authResult = {
id_token: 'some-id-token',
access_token: 'some-access-token',
@@ -476,26 +478,26 @@ describe('HistoryJwtKeysCallbackHandlerService', () => {
authResult,
} as CallbackContext;
const allconfigs = [
const allConfigs = [
{
configId: 'configId1',
historyCleanupOff: true,
},
];
const storagePersistenceServiceSpy = spyOn(
const storagePersistenceServiceSpy = vi.spyOn(
storagePersistenceService,
'write'
);
spyOn(signInKeyDataService, 'getSigningKeys').and.returnValue(
vi.spyOn(signInKeyDataService, 'getSigningKeys').mockReturnValue(
throwError(() => new Error('Error'))
);
service
.callbackHistoryAndResetJwtKeys(
initialCallbackContext,
allconfigs[0],
allconfigs
allConfigs[0]!,
allConfigs
)
.subscribe({
next: (callbackContext: CallbackContext) => {
@@ -505,16 +507,18 @@ describe('HistoryJwtKeysCallbackHandlerService', () => {
expect(err).toBeTruthy();
// storagePersistenceService.write() should not have been called with jwtKeys
expect(storagePersistenceServiceSpy).toHaveBeenCalledOnceWith(
expect(
storagePersistenceServiceSpy
).toHaveBeenCalledExactlyOnceWith(
'authnResult',
authResult,
allconfigs[0]
allConfigs[0]
);
},
});
}));
});
it('should fallback to stored jwtKeys on error', waitForAsync(() => {
it('should fallback to stored jwtKeys on error', async () => {
const authResult = {
id_token: 'some-id-token',
access_token: 'some-access-token',
@@ -523,66 +527,65 @@ describe('HistoryJwtKeysCallbackHandlerService', () => {
authResult,
} as CallbackContext;
const allconfigs = [
const allConfigs = [
{
configId: 'configId1',
historyCleanupOff: true,
},
];
const storagePersistenceServiceSpy = spyOn(
const storagePersistenceServiceSpy = vi.spyOn(
storagePersistenceService,
'read'
);
storagePersistenceServiceSpy.and.returnValue(DUMMY_JWT_KEYS);
spyOn(signInKeyDataService, 'getSigningKeys').and.returnValue(
storagePersistenceServiceSpy.mockReturnValue(DUMMY_JWT_KEYS);
vi.spyOn(signInKeyDataService, 'getSigningKeys').mockReturnValue(
throwError(() => new Error('Error'))
);
service
.callbackHistoryAndResetJwtKeys(
initialCallbackContext,
allconfigs[0],
allconfigs
allConfigs[0]!,
allConfigs
)
.subscribe({
next: (callbackContext: CallbackContext) => {
expect(storagePersistenceServiceSpy).toHaveBeenCalledOnceWith(
'jwtKeys',
allconfigs[0]
);
expect(
storagePersistenceServiceSpy
).toHaveBeenCalledExactlyOnceWith('jwtKeys', allConfigs[0]);
expect(callbackContext.jwtKeys).toEqual(DUMMY_JWT_KEYS);
},
error: (err) => {
expect(err).toBeFalsy();
},
});
}));
});
it('should throw error if no jwtKeys are stored', waitForAsync(() => {
it('should throw error if no jwtKeys are stored', async () => {
const authResult = {
id_token: 'some-id-token',
access_token: 'some-access-token',
} as AuthResult;
const initialCallbackContext = { authResult } as CallbackContext;
const allconfigs = [
const allConfigs = [
{
configId: 'configId1',
historyCleanupOff: true,
},
];
spyOn(storagePersistenceService, 'read').and.returnValue(null);
spyOn(signInKeyDataService, 'getSigningKeys').and.returnValue(
vi.spyOn(storagePersistenceService, 'read').mockReturnValue(null);
vi.spyOn(signInKeyDataService, 'getSigningKeys').mockReturnValue(
throwError(() => new Error('Error'))
);
service
.callbackHistoryAndResetJwtKeys(
initialCallbackContext,
allconfigs[0],
allconfigs
allConfigs[0]!,
allConfigs
)
.subscribe({
next: (callbackContext: CallbackContext) => {
@@ -592,7 +595,7 @@ describe('HistoryJwtKeysCallbackHandlerService', () => {
expect(err).toBeTruthy();
},
});
}));
});
});
describe('historyCleanUpTurnedOn ', () => {

View File

@@ -1,14 +1,14 @@
import { DOCUMENT } from '../../dom';
import { inject, Injectable } from 'injection-js';
import { Observable, of, throwError } from 'rxjs';
import { Injectable, inject } from 'injection-js';
import { type Observable, of, throwError } from 'rxjs';
import { catchError, switchMap, tap } from 'rxjs/operators';
import { AuthStateService } from '../../auth-state/auth-state.service';
import { OpenIdConfiguration } from '../../config/openid-configuration';
import type { OpenIdConfiguration } from '../../config/openid-configuration';
import { DOCUMENT } from '../../dom';
import { LoggerService } from '../../logging/logger.service';
import { StoragePersistenceService } from '../../storage/storage-persistence.service';
import { JwtKeys } from '../../validation/jwtkeys';
import type { JwtKeys } from '../../validation/jwtkeys';
import { ValidationResult } from '../../validation/validation-result';
import { CallbackContext } from '../callback-context';
import type { CallbackContext } from '../callback-context';
import { FlowsDataService } from '../flows-data.service';
import { ResetAuthDataService } from '../reset-auth-data.service';
import { SigninKeyDataService } from '../signin-key-data.service';

View File

@@ -1,8 +1,9 @@
import { TestBed } from '@/testing';
import { vi } from 'vitest';
import { DOCUMENT } from '../../dom';
import { TestBed, waitForAsync } from '@angular/core/testing';
import { mockProvider } from '../../../test/auto-mock';
import { LoggerService } from '../../logging/logger.service';
import { CallbackContext } from '../callback-context';
import { mockProvider } from '../../testing/mock';
import type { CallbackContext } from '../callback-context';
import { FlowsDataService } from '../flows-data.service';
import { ResetAuthDataService } from '../reset-auth-data.service';
import { ImplicitFlowCallbackHandlerService } from './implicit-flow-callback-handler.service';
@@ -34,9 +35,6 @@ describe('ImplicitFlowCallbackHandlerService', () => {
},
],
});
});
beforeEach(() => {
service = TestBed.inject(ImplicitFlowCallbackHandlerService);
flowsDataService = TestBed.inject(FlowsDataService);
resetAuthDataService = TestBed.inject(ResetAuthDataService);
@@ -47,46 +45,46 @@ describe('ImplicitFlowCallbackHandlerService', () => {
});
describe('implicitFlowCallback', () => {
it('calls "resetAuthorizationData" if silent renew is not running', waitForAsync(() => {
spyOn(flowsDataService, 'isSilentRenewRunning').and.returnValue(false);
const resetAuthorizationDataSpy = spyOn(
it('calls "resetAuthorizationData" if silent renew is not running', async () => {
vi.spyOn(flowsDataService, 'isSilentRenewRunning').mockReturnValue(false);
const resetAuthorizationDataSpy = vi.spyOn(
resetAuthDataService,
'resetAuthorizationData'
);
const allconfigs = [
const allConfigs = [
{
configId: 'configId1',
},
];
service
.implicitFlowCallback(allconfigs[0], allconfigs, 'any-hash')
.implicitFlowCallback(allConfigs[0]!, allConfigs, 'any-hash')
.subscribe(() => {
expect(resetAuthorizationDataSpy).toHaveBeenCalled();
});
}));
});
it('does NOT calls "resetAuthorizationData" if silent renew is running', waitForAsync(() => {
spyOn(flowsDataService, 'isSilentRenewRunning').and.returnValue(true);
const resetAuthorizationDataSpy = spyOn(
it('does NOT calls "resetAuthorizationData" if silent renew is running', async () => {
vi.spyOn(flowsDataService, 'isSilentRenewRunning').mockReturnValue(true);
const resetAuthorizationDataSpy = vi.spyOn(
resetAuthDataService,
'resetAuthorizationData'
);
const allconfigs = [
const allConfigs = [
{
configId: 'configId1',
},
];
service
.implicitFlowCallback(allconfigs[0], allconfigs, 'any-hash')
.implicitFlowCallback(allConfigs[0]!, allConfigs, 'any-hash')
.subscribe(() => {
expect(resetAuthorizationDataSpy).not.toHaveBeenCalled();
});
}));
});
it('returns callbackContext if all params are good', waitForAsync(() => {
spyOn(flowsDataService, 'isSilentRenewRunning').and.returnValue(true);
it('returns callbackContext if all params are good', async () => {
vi.spyOn(flowsDataService, 'isSilentRenewRunning').mockReturnValue(true);
const expectedCallbackContext = {
code: '',
refreshToken: '',
@@ -99,21 +97,21 @@ describe('ImplicitFlowCallbackHandlerService', () => {
existingIdToken: null,
} as CallbackContext;
const allconfigs = [
const allConfigs = [
{
configId: 'configId1',
},
];
service
.implicitFlowCallback(allconfigs[0], allconfigs, 'anyHash')
.implicitFlowCallback(allConfigs[0]!, allConfigs, 'anyHash')
.subscribe((callbackContext) => {
expect(callbackContext).toEqual(expectedCallbackContext);
});
}));
});
it('uses window location hash if no hash is passed', waitForAsync(() => {
spyOn(flowsDataService, 'isSilentRenewRunning').and.returnValue(true);
it('uses window location hash if no hash is passed', async () => {
vi.spyOn(flowsDataService, 'isSilentRenewRunning').mockReturnValue(true);
const expectedCallbackContext = {
code: '',
refreshToken: '',
@@ -126,17 +124,17 @@ describe('ImplicitFlowCallbackHandlerService', () => {
existingIdToken: null,
} as CallbackContext;
const allconfigs = [
const allConfigs = [
{
configId: 'configId1',
},
];
service
.implicitFlowCallback(allconfigs[0], allconfigs)
.implicitFlowCallback(allConfigs[0]!, allConfigs)
.subscribe((callbackContext) => {
expect(callbackContext).toEqual(expectedCallbackContext);
});
}));
});
});
});

View File

@@ -1,9 +1,9 @@
import { Injectable, inject } from 'injection-js';
import { type Observable, of } from 'rxjs';
import type { OpenIdConfiguration } from '../../config/openid-configuration';
import { DOCUMENT } from '../../dom';
import { inject, Injectable } from 'injection-js';
import { Observable, of } from 'rxjs';
import { OpenIdConfiguration } from '../../config/openid-configuration';
import { LoggerService } from '../../logging/logger.service';
import { AuthResult, CallbackContext } from '../callback-context';
import type { AuthResult, CallbackContext } from '../callback-context';
import { FlowsDataService } from '../flows-data.service';
import { ResetAuthDataService } from '../reset-auth-data.service';

View File

@@ -1,8 +1,9 @@
import { TestBed, waitForAsync } from '@angular/core/testing';
import { mockProvider } from '../../../test/auto-mock';
import { TestBed } from '@/testing';
import { vi } from 'vitest';
import { AuthStateService } from '../../auth-state/auth-state.service';
import { LoggerService } from '../../logging/logger.service';
import { CallbackContext } from '../callback-context';
import { mockProvider } from '../../testing/mock';
import type { CallbackContext } from '../callback-context';
import { FlowsDataService } from '../flows-data.service';
import { RefreshSessionCallbackHandlerService } from './refresh-session-callback-handler.service';
@@ -33,15 +34,15 @@ describe('RefreshSessionCallbackHandlerService', () => {
});
describe('refreshSessionWithRefreshTokens', () => {
it('returns callbackContext if all params are good', waitForAsync(() => {
spyOn(
it('returns callbackContext if all params are good', async () => {
vi.spyOn(
flowsDataService,
'getExistingOrCreateAuthStateControl'
).and.returnValue('state-data');
spyOn(authStateService, 'getRefreshToken').and.returnValue(
).mockReturnValue('state-data');
vi.spyOn(authStateService, 'getRefreshToken').mockReturnValue(
'henlo-furiend'
);
spyOn(authStateService, 'getIdToken').and.returnValue('henlo-legger');
vi.spyOn(authStateService, 'getIdToken').mockReturnValue('henlo-legger');
const expectedCallbackContext = {
code: '',
@@ -60,15 +61,15 @@ describe('RefreshSessionCallbackHandlerService', () => {
.subscribe((callbackContext) => {
expect(callbackContext).toEqual(expectedCallbackContext);
});
}));
});
it('throws error if no refresh token is given', waitForAsync(() => {
spyOn(
it('throws error if no refresh token is given', async () => {
vi.spyOn(
flowsDataService,
'getExistingOrCreateAuthStateControl'
).and.returnValue('state-data');
spyOn(authStateService, 'getRefreshToken').and.returnValue('');
spyOn(authStateService, 'getIdToken').and.returnValue('henlo-legger');
).mockReturnValue('state-data');
vi.spyOn(authStateService, 'getRefreshToken').mockReturnValue('');
vi.spyOn(authStateService, 'getIdToken').mockReturnValue('henlo-legger');
service
.refreshSessionWithRefreshTokens({ configId: 'configId1' })
@@ -77,6 +78,6 @@ describe('RefreshSessionCallbackHandlerService', () => {
expect(err).toBeTruthy();
},
});
}));
});
});
});

View File

@@ -1,13 +1,14 @@
import { HttpErrorResponse, HttpHeaders } from '@angular/common/http';
import { TestBed, waitForAsync } from '@angular/core/testing';
import { TestBed, mockImplementationWhenArgsEqual } from '@/testing';
import { HttpErrorResponse, HttpHeaders } from '@ngify/http';
import { of, throwError } from 'rxjs';
import { mockProvider } from '../../../test/auto-mock';
import { createRetriableStream } from '../../../test/create-retriable-stream.helper';
import { vi } from 'vitest';
import { DataService } from '../../api/data.service';
import { LoggerService } from '../../logging/logger.service';
import { StoragePersistenceService } from '../../storage/storage-persistence.service';
import { createRetriableStream } from '../../testing/create-retriable-stream.helper';
import { mockProvider } from '../../testing/mock';
import { UrlService } from '../../utils/url/url.service';
import { CallbackContext } from '../callback-context';
import type { CallbackContext } from '../callback-context';
import { RefreshTokenCallbackHandlerService } from './refresh-token-callback-handler.service';
describe('RefreshTokenCallbackHandlerService', () => {
@@ -46,7 +47,7 @@ describe('RefreshTokenCallbackHandlerService', () => {
url: 'https://identity-server.test/openid-connect/token',
});
it('throws error if no tokenEndpoint is given', waitForAsync(() => {
it('throws error if no tokenEndpoint is given', async () => {
(service as any)
.refreshTokensRequestTokens({} as CallbackContext)
.subscribe({
@@ -54,41 +55,45 @@ describe('RefreshTokenCallbackHandlerService', () => {
expect(err).toBeTruthy();
},
});
}));
});
it('calls data service if all params are good', waitForAsync(() => {
const postSpy = spyOn(dataService, 'post').and.returnValue(of({}));
it('calls data service if all params are good', async () => {
const postSpy = vi.spyOn(dataService, 'post').mockReturnValue(of({}));
spyOn(storagePersistenceService, 'read')
.withArgs('authWellKnownEndPoints', { configId: 'configId1' })
.and.returnValue({ tokenEndpoint: 'tokenEndpoint' });
mockImplementationWhenArgsEqual(
vi.spyOn(storagePersistenceService, 'read'),
['authWellKnownEndPoints', { configId: 'configId1' }],
() => ({ tokenEndpoint: 'tokenEndpoint' })
);
service
.refreshTokensRequestTokens({} as CallbackContext, {
configId: 'configId1',
})
.subscribe(() => {
expect(postSpy).toHaveBeenCalledOnceWith(
expect(postSpy).toHaveBeenCalledExactlyOnceWith(
'tokenEndpoint',
undefined,
{ configId: 'configId1' },
jasmine.any(HttpHeaders)
expect.any(HttpHeaders)
);
const httpHeaders = postSpy.calls.mostRecent().args[3] as HttpHeaders;
expect(httpHeaders.has('Content-Type')).toBeTrue();
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', waitForAsync(() => {
const postSpy = spyOn(dataService, 'post').and.returnValue(of({}));
it('calls data service with correct headers if all params are good', async () => {
const postSpy = vi.spyOn(dataService, 'post').mockReturnValue(of({}));
spyOn(storagePersistenceService, 'read')
.withArgs('authWellKnownEndPoints', { configId: 'configId1' })
.and.returnValue({ tokenEndpoint: 'tokenEndpoint' });
mockImplementationWhenArgsEqual(
vi.spyOn(storagePersistenceService, 'read'),
['authWellKnownEndPoints', { configId: 'configId1' }],
() => ({ tokenEndpoint: 'tokenEndpoint' })
);
service
.refreshTokensRequestTokens({} as CallbackContext, {
@@ -97,20 +102,24 @@ describe('RefreshTokenCallbackHandlerService', () => {
.subscribe(() => {
const httpHeaders = postSpy.calls.mostRecent().args[3] as HttpHeaders;
expect(httpHeaders.has('Content-Type')).toBeTrue();
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', waitForAsync(() => {
spyOn(dataService, 'post').and.returnValue(throwError(() => HTTP_ERROR));
it('returns error in case of http error', async () => {
vi.spyOn(dataService, 'post').mockReturnValue(
throwError(() => HTTP_ERROR)
);
const config = { configId: 'configId1', authority: 'authority' };
spyOn(storagePersistenceService, 'read')
.withArgs('authWellKnownEndPoints', config)
.and.returnValue({ tokenEndpoint: 'tokenEndpoint' });
mockImplementationWhenArgsEqual(
vi.spyOn(storagePersistenceService, 'read'),
['authWellKnownEndPoints', config],
() => ({ tokenEndpoint: 'tokenEndpoint' })
);
service
.refreshTokensRequestTokens({} as CallbackContext, config)
@@ -119,10 +128,10 @@ describe('RefreshTokenCallbackHandlerService', () => {
expect(err).toBeTruthy();
},
});
}));
});
it('retries request in case of no connection http error and succeeds', waitForAsync(() => {
const postSpy = spyOn(dataService, 'post').and.returnValue(
it('retries request in case of no connection http error and succeeds', async () => {
const postSpy = vi.spyOn(dataService, 'post').mockReturnValue(
createRetriableStream(
throwError(() => CONNECTION_ERROR),
of({})
@@ -130,9 +139,11 @@ describe('RefreshTokenCallbackHandlerService', () => {
);
const config = { configId: 'configId1', authority: 'authority' };
spyOn(storagePersistenceService, 'read')
.withArgs('authWellKnownEndPoints', config)
.and.returnValue({ tokenEndpoint: 'tokenEndpoint' });
mockImplementationWhenArgsEqual(
vi.spyOn(storagePersistenceService, 'read'),
['authWellKnownEndPoints', config],
() => ({ tokenEndpoint: 'tokenEndpoint' })
);
service
.refreshTokensRequestTokens({} as CallbackContext, config)
@@ -146,10 +157,10 @@ describe('RefreshTokenCallbackHandlerService', () => {
expect(err).toBeFalsy();
},
});
}));
});
it('retries request in case of no connection http error and fails because of http error afterwards', waitForAsync(() => {
const postSpy = spyOn(dataService, 'post').and.returnValue(
it('retries request in case of no connection http error and fails because of http error afterwards', async () => {
const postSpy = vi.spyOn(dataService, 'post').mockReturnValue(
createRetriableStream(
throwError(() => CONNECTION_ERROR),
throwError(() => HTTP_ERROR)
@@ -157,9 +168,11 @@ describe('RefreshTokenCallbackHandlerService', () => {
);
const config = { configId: 'configId1', authority: 'authority' };
spyOn(storagePersistenceService, 'read')
.withArgs('authWellKnownEndPoints', config)
.and.returnValue({ tokenEndpoint: 'tokenEndpoint' });
mockImplementationWhenArgsEqual(
vi.spyOn(storagePersistenceService, 'read'),
['authWellKnownEndPoints', config],
() => ({ tokenEndpoint: 'tokenEndpoint' })
);
service
.refreshTokensRequestTokens({} as CallbackContext, config)
@@ -173,6 +186,6 @@ describe('RefreshTokenCallbackHandlerService', () => {
expect(postSpy).toHaveBeenCalledTimes(1);
},
});
}));
});
});
});

View File

@@ -1,13 +1,14 @@
import { DOCUMENT } from '../../dom';
import { TestBed, waitForAsync } from '@angular/core/testing';
import { TestBed } from '@/testing';
import { of } from 'rxjs';
import { mockProvider } from '../../../test/auto-mock';
import { vi } from 'vitest';
import { AuthStateService } from '../../auth-state/auth-state.service';
import { DOCUMENT } from '../../dom';
import { LoggerService } from '../../logging/logger.service';
import { StateValidationResult } from '../../validation/state-validation-result';
import { mockProvider } from '../../testing/mock';
import type { StateValidationResult } from '../../validation/state-validation-result';
import { StateValidationService } from '../../validation/state-validation.service';
import { ValidationResult } from '../../validation/validation-result';
import { CallbackContext } from '../callback-context';
import type { CallbackContext } from '../callback-context';
import { ResetAuthDataService } from '../reset-auth-data.service';
import { StateValidationCallbackHandlerService } from './state-validation-callback-handler.service';
@@ -56,8 +57,11 @@ describe('StateValidationCallbackHandlerService', () => {
});
describe('callbackStateValidation', () => {
it('returns callbackContext with validationResult if validationResult is valid', waitForAsync(() => {
spyOn(stateValidationService, 'getValidatedStateResult').and.returnValue(
it('returns callbackContext with validationResult if validationResult is valid', async () => {
vi.spyOn(
stateValidationService,
'getValidatedStateResult'
).mockReturnValue(
of({
idToken: 'idTokenJustForTesting',
authResponseIsValid: true,
@@ -68,7 +72,7 @@ describe('StateValidationCallbackHandlerService', () => {
service
.callbackStateValidation(
{} as CallbackContext,
allConfigs[0],
allConfigs[0]!,
allConfigs
)
.subscribe((newCallbackContext) => {
@@ -79,47 +83,53 @@ describe('StateValidationCallbackHandlerService', () => {
},
} as CallbackContext);
});
}));
});
it('logs error in case of an error', waitForAsync(() => {
spyOn(stateValidationService, 'getValidatedStateResult').and.returnValue(
it('logs error in case of an error', async () => {
vi.spyOn(
stateValidationService,
'getValidatedStateResult'
).mockReturnValue(
of({
authResponseIsValid: false,
} as StateValidationResult)
);
const loggerSpy = spyOn(loggerService, 'logWarning');
const loggerSpy = vi.spyOn(loggerService, 'logWarning');
const allConfigs = [{ configId: 'configId1' }];
service
.callbackStateValidation(
{} as CallbackContext,
allConfigs[0],
allConfigs[0]!,
allConfigs
)
.subscribe({
error: () => {
expect(loggerSpy).toHaveBeenCalledOnceWith(
allConfigs[0],
expect(loggerSpy).toHaveBeenCalledExactlyOnceWith(
allConfigs[0]!,
'authorizedCallback, token(s) validation failed, resetting. Hash: &anyFakeHash'
);
},
});
}));
});
it('calls resetAuthDataService.resetAuthorizationData and authStateService.updateAndPublishAuthState in case of an error', waitForAsync(() => {
spyOn(stateValidationService, 'getValidatedStateResult').and.returnValue(
it('calls resetAuthDataService.resetAuthorizationData and authStateService.updateAndPublishAuthState in case of an error', async () => {
vi.spyOn(
stateValidationService,
'getValidatedStateResult'
).mockReturnValue(
of({
authResponseIsValid: false,
state: ValidationResult.LoginRequired,
} as StateValidationResult)
);
const resetAuthorizationDataSpy = spyOn(
const resetAuthorizationDataSpy = vi.spyOn(
resetAuthDataService,
'resetAuthorizationData'
);
const updateAndPublishAuthStateSpy = spyOn(
const updateAndPublishAuthStateSpy = vi.spyOn(
authStateService,
'updateAndPublishAuthState'
);
@@ -128,19 +138,21 @@ describe('StateValidationCallbackHandlerService', () => {
service
.callbackStateValidation(
{ isRenewProcess: true } as CallbackContext,
allConfigs[0],
allConfigs[0]!,
allConfigs
)
.subscribe({
error: () => {
expect(resetAuthorizationDataSpy).toHaveBeenCalledTimes(1);
expect(updateAndPublishAuthStateSpy).toHaveBeenCalledOnceWith({
expect(
updateAndPublishAuthStateSpy
).toHaveBeenCalledExactlyOnceWith({
isAuthenticated: false,
validationResult: ValidationResult.LoginRequired,
isRenewProcess: true,
});
},
});
}));
});
});
});

View File

@@ -1,13 +1,13 @@
import { DOCUMENT } from '../../dom';
import { inject, Injectable } from 'injection-js';
import { Observable } from 'rxjs';
import { Injectable, inject } from 'injection-js';
import type { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { AuthStateService } from '../../auth-state/auth-state.service';
import { OpenIdConfiguration } from '../../config/openid-configuration';
import type { OpenIdConfiguration } from '../../config/openid-configuration';
import { DOCUMENT } from '../../dom';
import { LoggerService } from '../../logging/logger.service';
import { StateValidationResult } from '../../validation/state-validation-result';
import type { StateValidationResult } from '../../validation/state-validation-result';
import { StateValidationService } from '../../validation/state-validation.service';
import { CallbackContext } from '../callback-context';
import type { CallbackContext } from '../callback-context';
import { ResetAuthDataService } from '../reset-auth-data.service';
@Injectable()

View File

@@ -1,12 +1,13 @@
import { TestBed, waitForAsync } from '@angular/core/testing';
import { TestBed } from '@/testing';
import { of } from 'rxjs';
import { mockProvider } from '../../../test/auto-mock';
import { vi } from 'vitest';
import { AuthStateService } from '../../auth-state/auth-state.service';
import { LoggerService } from '../../logging/logger.service';
import { mockProvider } from '../../testing/mock';
import { UserService } from '../../user-data/user.service';
import { StateValidationResult } from '../../validation/state-validation-result';
import { ValidationResult } from '../../validation/validation-result';
import { CallbackContext } from '../callback-context';
import type { CallbackContext } from '../callback-context';
import { FlowsDataService } from '../flows-data.service';
import { ResetAuthDataService } from '../reset-auth-data.service';
import { UserCallbackHandlerService } from './user-callback-handler.service';
@@ -44,7 +45,7 @@ describe('UserCallbackHandlerService', () => {
});
describe('callbackUser', () => {
it('calls flowsDataService.setSessionState with correct params if autoUserInfo is false, isRenewProcess is false and refreshToken is null', waitForAsync(() => {
it('calls flowsDataService.setSessionState with correct params if autoUserInfo is false, isRenewProcess is false and refreshToken is null', async () => {
const svr = new StateValidationResult(
'accesstoken',
'idtoken',
@@ -70,17 +71,17 @@ describe('UserCallbackHandlerService', () => {
},
];
const spy = spyOn(flowsDataService, 'setSessionState');
const spy = vi.spyOn(flowsDataService, 'setSessionState');
service
.callbackUser(callbackContext, allConfigs[0], allConfigs)
.callbackUser(callbackContext, allConfigs[0]!, allConfigs)
.subscribe((resultCallbackContext) => {
expect(spy).toHaveBeenCalledOnceWith('mystate', allConfigs[0]);
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', waitForAsync(() => {
it('does NOT call flowsDataService.setSessionState if autoUserInfo is false, isRenewProcess is true and refreshToken is null', async () => {
const svr = new StateValidationResult(
'accesstoken',
'idtoken',
@@ -104,17 +105,17 @@ describe('UserCallbackHandlerService', () => {
autoUserInfo: false,
},
];
const spy = spyOn(flowsDataService, 'setSessionState');
const spy = vi.spyOn(flowsDataService, 'setSessionState');
service
.callbackUser(callbackContext, allConfigs[0], allConfigs)
.callbackUser(callbackContext, allConfigs[0]!, allConfigs)
.subscribe((resultCallbackContext) => {
expect(spy).not.toHaveBeenCalled();
expect(resultCallbackContext).toEqual(callbackContext);
});
}));
});
it('does NOT call flowsDataService.setSessionState if autoUserInfo is false isRenewProcess is false, refreshToken has value', waitForAsync(() => {
it('does NOT call flowsDataService.setSessionState if autoUserInfo is false isRenewProcess is false, refreshToken has value', async () => {
const svr = new StateValidationResult(
'accesstoken',
'idtoken',
@@ -138,17 +139,17 @@ describe('UserCallbackHandlerService', () => {
autoUserInfo: false,
},
];
const spy = spyOn(flowsDataService, 'setSessionState');
const spy = vi.spyOn(flowsDataService, 'setSessionState');
service
.callbackUser(callbackContext, allConfigs[0], allConfigs)
.callbackUser(callbackContext, allConfigs[0]!, allConfigs)
.subscribe((resultCallbackContext) => {
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', waitForAsync(() => {
it('does NOT call flowsDataService.setSessionState if autoUserInfo is false isRenewProcess is false, refreshToken has value, id_token is false', async () => {
const svr = new StateValidationResult('accesstoken', '', true, '');
const callbackContext = {
code: '',
@@ -168,17 +169,17 @@ describe('UserCallbackHandlerService', () => {
},
];
const spy = spyOn(flowsDataService, 'setSessionState');
const spy = vi.spyOn(flowsDataService, 'setSessionState');
service
.callbackUser(callbackContext, allConfigs[0], allConfigs)
.callbackUser(callbackContext, allConfigs[0]!, allConfigs)
.subscribe((resultCallbackContext) => {
expect(spy).not.toHaveBeenCalled();
expect(resultCallbackContext).toEqual(callbackContext);
});
}));
});
it('calls authStateService.updateAndPublishAuthState with correct params if autoUserInfo is false', waitForAsync(() => {
it('calls authStateService.updateAndPublishAuthState with correct params if autoUserInfo is false', async () => {
const svr = new StateValidationResult(
'accesstoken',
'idtoken',
@@ -204,24 +205,24 @@ describe('UserCallbackHandlerService', () => {
},
];
const updateAndPublishAuthStateSpy = spyOn(
const updateAndPublishAuthStateSpy = vi.spyOn(
authStateService,
'updateAndPublishAuthState'
);
service
.callbackUser(callbackContext, allConfigs[0], allConfigs)
.callbackUser(callbackContext, allConfigs[0]!, allConfigs)
.subscribe((resultCallbackContext) => {
expect(updateAndPublishAuthStateSpy).toHaveBeenCalledOnceWith({
expect(updateAndPublishAuthStateSpy).toHaveBeenCalledExactlyOnceWith({
isAuthenticated: true,
validationResult: ValidationResult.NotSet,
isRenewProcess: false,
});
expect(resultCallbackContext).toEqual(callbackContext);
});
}));
});
it('calls userService.getAndPersistUserDataInStore with correct params if autoUserInfo is true', waitForAsync(() => {
it('calls userService.getAndPersistUserDataInStore with correct params if autoUserInfo is true', async () => {
const svr = new StateValidationResult(
'accesstoken',
'idtoken',
@@ -247,16 +248,17 @@ describe('UserCallbackHandlerService', () => {
},
];
const getAndPersistUserDataInStoreSpy = spyOn(
userService,
'getAndPersistUserDataInStore'
).and.returnValue(of({ user: 'some_data' }));
const getAndPersistUserDataInStoreSpy = vi
.spyOn(userService, 'getAndPersistUserDataInStore')
.mockReturnValue(of({ user: 'some_data' }));
service
.callbackUser(callbackContext, allConfigs[0], allConfigs)
.callbackUser(callbackContext, allConfigs[0]!, allConfigs)
.subscribe((resultCallbackContext) => {
expect(getAndPersistUserDataInStoreSpy).toHaveBeenCalledOnceWith(
allConfigs[0],
expect(
getAndPersistUserDataInStoreSpy
).toHaveBeenCalledExactlyOnceWith(
allConfigs[0]!,
allConfigs,
false,
'idtoken',
@@ -264,9 +266,9 @@ describe('UserCallbackHandlerService', () => {
);
expect(resultCallbackContext).toEqual(callbackContext);
});
}));
});
it('calls authStateService.updateAndPublishAuthState with correct params if autoUserInfo is true', waitForAsync(() => {
it('calls authStateService.updateAndPublishAuthState with correct params if autoUserInfo is true', async () => {
const svr = new StateValidationResult(
'accesstoken',
'idtoken',
@@ -293,27 +295,27 @@ describe('UserCallbackHandlerService', () => {
},
];
spyOn(userService, 'getAndPersistUserDataInStore').and.returnValue(
vi.spyOn(userService, 'getAndPersistUserDataInStore').mockReturnValue(
of({ user: 'some_data' })
);
const updateAndPublishAuthStateSpy = spyOn(
const updateAndPublishAuthStateSpy = vi.spyOn(
authStateService,
'updateAndPublishAuthState'
);
service
.callbackUser(callbackContext, allConfigs[0], allConfigs)
.callbackUser(callbackContext, allConfigs[0]!, allConfigs)
.subscribe((resultCallbackContext) => {
expect(updateAndPublishAuthStateSpy).toHaveBeenCalledOnceWith({
expect(updateAndPublishAuthStateSpy).toHaveBeenCalledExactlyOnceWith({
isAuthenticated: true,
validationResult: ValidationResult.MaxOffsetExpired,
isRenewProcess: false,
});
expect(resultCallbackContext).toEqual(callbackContext);
});
}));
});
it('calls flowsDataService.setSessionState with correct params if user data is present and NOT refresh token', waitForAsync(() => {
it('calls flowsDataService.setSessionState with correct params if user data is present and NOT refresh token', async () => {
const svr = new StateValidationResult(
'accesstoken',
'idtoken',
@@ -340,23 +342,23 @@ describe('UserCallbackHandlerService', () => {
},
];
spyOn(userService, 'getAndPersistUserDataInStore').and.returnValue(
vi.spyOn(userService, 'getAndPersistUserDataInStore').mockReturnValue(
of({ user: 'some_data' })
);
const setSessionStateSpy = spyOn(flowsDataService, 'setSessionState');
const setSessionStateSpy = vi.spyOn(flowsDataService, 'setSessionState');
service
.callbackUser(callbackContext, allConfigs[0], allConfigs)
.callbackUser(callbackContext, allConfigs[0]!, allConfigs)
.subscribe((resultCallbackContext) => {
expect(setSessionStateSpy).toHaveBeenCalledOnceWith(
expect(setSessionStateSpy).toHaveBeenCalledExactlyOnceWith(
'mystate',
allConfigs[0]
);
expect(resultCallbackContext).toEqual(callbackContext);
});
}));
});
it('calls authStateService.publishUnauthorizedState with correct params if user info which are coming back are null', waitForAsync(() => {
it('calls authStateService.publishUnauthorizedState with correct params if user info which are coming back are null', async () => {
const svr = new StateValidationResult(
'accesstoken',
'idtoken',
@@ -383,19 +385,21 @@ describe('UserCallbackHandlerService', () => {
},
];
spyOn(userService, 'getAndPersistUserDataInStore').and.returnValue(
vi.spyOn(userService, 'getAndPersistUserDataInStore').mockReturnValue(
of(null)
);
const updateAndPublishAuthStateSpy = spyOn(
const updateAndPublishAuthStateSpy = vi.spyOn(
authStateService,
'updateAndPublishAuthState'
);
service
.callbackUser(callbackContext, allConfigs[0], allConfigs)
.callbackUser(callbackContext, allConfigs[0]!, allConfigs)
.subscribe({
error: (err) => {
expect(updateAndPublishAuthStateSpy).toHaveBeenCalledOnceWith({
expect(
updateAndPublishAuthStateSpy
).toHaveBeenCalledExactlyOnceWith({
isAuthenticated: false,
validationResult: ValidationResult.MaxOffsetExpired,
isRenewProcess: false,
@@ -405,9 +409,9 @@ describe('UserCallbackHandlerService', () => {
);
},
});
}));
});
it('calls resetAuthDataService.resetAuthorizationData if user info which are coming back are null', waitForAsync(() => {
it('calls resetAuthDataService.resetAuthorizationData if user info which are coming back are null', async () => {
const svr = new StateValidationResult(
'accesstoken',
'idtoken',
@@ -434,16 +438,16 @@ describe('UserCallbackHandlerService', () => {
},
];
spyOn(userService, 'getAndPersistUserDataInStore').and.returnValue(
vi.spyOn(userService, 'getAndPersistUserDataInStore').mockReturnValue(
of(null)
);
const resetAuthorizationDataSpy = spyOn(
const resetAuthorizationDataSpy = vi.spyOn(
resetAuthDataService,
'resetAuthorizationData'
);
service
.callbackUser(callbackContext, allConfigs[0], allConfigs)
.callbackUser(callbackContext, allConfigs[0]!, allConfigs)
.subscribe({
error: (err) => {
expect(resetAuthorizationDataSpy).toHaveBeenCalledTimes(1);
@@ -452,6 +456,6 @@ describe('UserCallbackHandlerService', () => {
);
},
});
}));
});
});
});

View File

@@ -1,12 +1,12 @@
import { inject, Injectable } from 'injection-js';
import { Observable, of, throwError } from 'rxjs';
import { Injectable, inject } from 'injection-js';
import { type Observable, of, throwError } from 'rxjs';
import { catchError, switchMap } from 'rxjs/operators';
import { AuthStateService } from '../../auth-state/auth-state.service';
import { OpenIdConfiguration } from '../../config/openid-configuration';
import type { OpenIdConfiguration } from '../../config/openid-configuration';
import { LoggerService } from '../../logging/logger.service';
import { UserService } from '../../user-data/user.service';
import { StateValidationResult } from '../../validation/state-validation-result';
import { CallbackContext } from '../callback-context';
import type { StateValidationResult } from '../../validation/state-validation-result';
import type { CallbackContext } from '../callback-context';
import { FlowsDataService } from '../flows-data.service';
import { ResetAuthDataService } from '../reset-auth-data.service';

View File

@@ -1,7 +1,8 @@
import { TestBed } from '@angular/core/testing';
import { mockProvider } from '../../test/auto-mock';
import { TestBed } from '@/testing';
import { vi } from 'vitest';
import { LoggerService } from '../logging/logger.service';
import { StoragePersistenceService } from '../storage/storage-persistence.service';
import { mockProvider } from '../testing/mock';
import { CryptoService } from '../utils/crypto/crypto.service';
import { FlowsDataService } from './flows-data.service';
import { RandomService } from './random/random.service';
@@ -37,12 +38,12 @@ describe('Flows Data Service', () => {
describe('createNonce', () => {
it('createNonce returns nonce and stores it', () => {
const spy = spyOn(storagePersistenceService, 'write');
const spy = vi.spyOn(storagePersistenceService, 'write');
const result = service.createNonce({ configId: 'configId1' });
expect(result).toBeTruthy();
expect(spy).toHaveBeenCalledOnceWith('authNonce', result, {
expect(spy).toHaveBeenCalledExactlyOnceWith('authNonce', result, {
configId: 'configId1',
});
});
@@ -50,32 +51,38 @@ describe('Flows Data Service', () => {
describe('AuthStateControl', () => {
it('getAuthStateControl returns property from store', () => {
const spy = spyOn(storagePersistenceService, 'read');
const spy = vi.spyOn(storagePersistenceService, 'read');
service.getAuthStateControl({ configId: 'configId1' });
expect(spy).toHaveBeenCalledOnceWith('authStateControl', {
expect(spy).toHaveBeenCalledExactlyOnceWith('authStateControl', {
configId: 'configId1',
});
});
it('setAuthStateControl saves property in store', () => {
const spy = spyOn(storagePersistenceService, 'write');
const spy = vi.spyOn(storagePersistenceService, 'write');
service.setAuthStateControl('ToSave', { configId: 'configId1' });
expect(spy).toHaveBeenCalledOnceWith('authStateControl', 'ToSave', {
configId: 'configId1',
});
expect(spy).toHaveBeenCalledExactlyOnceWith(
'authStateControl',
'ToSave',
{
configId: 'configId1',
}
);
});
});
describe('getExistingOrCreateAuthStateControl', () => {
it('if nothing stored it creates a 40 char one and saves the authStateControl', () => {
spyOn(storagePersistenceService, 'read')
.withArgs('authStateControl', { configId: 'configId1' })
.and.returnValue(null);
const setSpy = spyOn(storagePersistenceService, 'write');
mockImplementationWhenArgsEqual(
vi.spyOn(storagePersistenceService, 'read'),
['authStateControl', { configId: 'configId1' }],
() => null
);
const setSpy = vi.spyOn(storagePersistenceService, 'write');
const result = service.getExistingOrCreateAuthStateControl({
configId: 'configId1',
@@ -83,16 +90,22 @@ describe('Flows Data Service', () => {
expect(result).toBeTruthy();
expect(result.length).toBe(41);
expect(setSpy).toHaveBeenCalledOnceWith('authStateControl', result, {
configId: 'configId1',
});
expect(setSpy).toHaveBeenCalledExactlyOnceWith(
'authStateControl',
result,
{
configId: 'configId1',
}
);
});
it('if stored it returns the value and does NOT Store the value again', () => {
spyOn(storagePersistenceService, 'read')
.withArgs('authStateControl', { configId: 'configId1' })
.and.returnValue('someAuthStateControl');
const setSpy = spyOn(storagePersistenceService, 'write');
mockImplementationWhenArgsEqual(
vi.spyOn(storagePersistenceService, 'read'),
['authStateControl', { configId: 'configId1' }],
() => 'someAuthStateControl'
);
const setSpy = vi.spyOn(storagePersistenceService, 'write');
const result = service.getExistingOrCreateAuthStateControl({
configId: 'configId1',
@@ -106,11 +119,11 @@ describe('Flows Data Service', () => {
describe('setSessionState', () => {
it('setSessionState saves the value in the storage', () => {
const spy = spyOn(storagePersistenceService, 'write');
const spy = vi.spyOn(storagePersistenceService, 'write');
service.setSessionState('Genesis', { configId: 'configId1' });
expect(spy).toHaveBeenCalledOnceWith('session_state', 'Genesis', {
expect(spy).toHaveBeenCalledExactlyOnceWith('session_state', 'Genesis', {
configId: 'configId1',
});
});
@@ -118,7 +131,7 @@ describe('Flows Data Service', () => {
describe('resetStorageFlowData', () => {
it('resetStorageFlowData calls correct method on storagePersistenceService', () => {
const spy = spyOn(storagePersistenceService, 'resetStorageFlowData');
const spy = vi.spyOn(storagePersistenceService, 'resetStorageFlowData');
service.resetStorageFlowData({ configId: 'configId1' });
@@ -128,26 +141,27 @@ describe('Flows Data Service', () => {
describe('codeVerifier', () => {
it('getCodeVerifier returns value from the store', () => {
const spy = spyOn(storagePersistenceService, 'read')
const spy = vi
.spyOn(storagePersistenceService, 'read')
.withArgs('codeVerifier', { configId: 'configId1' })
.and.returnValue('Genesis');
.mockReturnValue('Genesis');
const result = service.getCodeVerifier({ configId: 'configId1' });
expect(result).toBe('Genesis');
expect(spy).toHaveBeenCalledOnceWith('codeVerifier', {
expect(spy).toHaveBeenCalledExactlyOnceWith('codeVerifier', {
configId: 'configId1',
});
});
it('createCodeVerifier returns random createCodeVerifier and stores it', () => {
const setSpy = spyOn(storagePersistenceService, 'write');
const setSpy = vi.spyOn(storagePersistenceService, 'write');
const result = service.createCodeVerifier({ configId: 'configId1' });
expect(result).toBeTruthy();
expect(result.length).toBe(67);
expect(setSpy).toHaveBeenCalledOnceWith('codeVerifier', result, {
expect(setSpy).toHaveBeenCalledExactlyOnceWith('codeVerifier', result, {
configId: 'configId1',
});
});
@@ -165,22 +179,26 @@ describe('Flows Data Service', () => {
jasmine.clock().mockDate(baseTime);
spyOn(storagePersistenceService, 'read')
.withArgs('storageCodeFlowInProgress', config)
.and.returnValue(true);
const spyWrite = spyOn(storagePersistenceService, 'write');
mockImplementationWhenArgsEqual(
vi.spyOn(storagePersistenceService, 'read'),
['storageCodeFlowInProgress', config],
() => true
);
const spyWrite = vi.spyOn(storagePersistenceService, 'write');
const isCodeFlowInProgressResult = service.isCodeFlowInProgress(config);
expect(spyWrite).not.toHaveBeenCalled();
expect(isCodeFlowInProgressResult).toBeTrue();
expect(isCodeFlowInProgressResult).toBeTruthy();
});
it('state object does not exist returns false result', () => {
// arrange
spyOn(storagePersistenceService, 'read')
.withArgs('storageCodeFlowInProgress', { configId: 'configId1' })
.and.returnValue(null);
mockImplementationWhenArgsEqual(
vi.spyOn(storagePersistenceService, 'read'),
['storageCodeFlowInProgress', { configId: 'configId1' }],
() => null
);
// act
const isCodeFlowInProgressResult = service.isCodeFlowInProgress({
@@ -188,7 +206,7 @@ describe('Flows Data Service', () => {
});
// assert
expect(isCodeFlowInProgressResult).toBeFalse();
expect(isCodeFlowInProgressResult).toBeFalsy();
});
});
@@ -200,23 +218,31 @@ describe('Flows Data Service', () => {
jasmine.clock().mockDate(baseTime);
const spy = spyOn(storagePersistenceService, 'write');
const spy = vi.spyOn(storagePersistenceService, 'write');
service.setCodeFlowInProgress({ configId: 'configId1' });
expect(spy).toHaveBeenCalledOnceWith('storageCodeFlowInProgress', true, {
configId: 'configId1',
});
expect(spy).toHaveBeenCalledExactlyOnceWith(
'storageCodeFlowInProgress',
true,
{
configId: 'configId1',
}
);
});
});
describe('resetCodeFlowInProgress', () => {
it('set resetCodeFlowInProgress to false when called', () => {
const spy = spyOn(storagePersistenceService, 'write');
const spy = vi.spyOn(storagePersistenceService, 'write');
service.resetCodeFlowInProgress({ configId: 'configId1' });
expect(spy).toHaveBeenCalledOnceWith('storageCodeFlowInProgress', false, {
configId: 'configId1',
});
expect(spy).toHaveBeenCalledExactlyOnceWith(
'storageCodeFlowInProgress',
false,
{
configId: 'configId1',
}
);
});
});
@@ -238,21 +264,21 @@ describe('Flows Data Service', () => {
dateOfLaunchedProcessUtc: baseTime.toISOString(),
};
spyOn(storagePersistenceService, 'read')
vi.spyOn(storagePersistenceService, 'read')
.withArgs('storageSilentRenewRunning', config)
.and.returnValue(JSON.stringify(storageObject));
const spyWrite = spyOn(storagePersistenceService, 'write');
.mockReturnValue(JSON.stringify(storageObject));
const spyWrite = vi.spyOn(storagePersistenceService, 'write');
jasmine.clock().tick((config.silentRenewTimeoutInSeconds + 1) * 1000);
const isSilentRenewRunningResult = service.isSilentRenewRunning(config);
expect(spyWrite).toHaveBeenCalledOnceWith(
expect(spyWrite).toHaveBeenCalledExactlyOnceWith(
'storageSilentRenewRunning',
'',
config
);
expect(isSilentRenewRunningResult).toBeFalse();
expect(isSilentRenewRunningResult).toBeFalsy();
});
it('checks silent renew process and returns result', () => {
@@ -272,27 +298,29 @@ describe('Flows Data Service', () => {
dateOfLaunchedProcessUtc: baseTime.toISOString(),
};
spyOn(storagePersistenceService, 'read')
vi.spyOn(storagePersistenceService, 'read')
.withArgs('storageSilentRenewRunning', config)
.and.returnValue(JSON.stringify(storageObject));
const spyWrite = spyOn(storagePersistenceService, 'write');
.mockReturnValue(JSON.stringify(storageObject));
const spyWrite = vi.spyOn(storagePersistenceService, 'write');
const isSilentRenewRunningResult = service.isSilentRenewRunning(config);
expect(spyWrite).not.toHaveBeenCalled();
expect(isSilentRenewRunningResult).toBeTrue();
expect(isSilentRenewRunningResult).toBeTruthy();
});
it('state object does not exist returns false result', () => {
spyOn(storagePersistenceService, 'read')
.withArgs('storageSilentRenewRunning', { configId: 'configId1' })
.and.returnValue(null);
mockImplementationWhenArgsEqual(
vi.spyOn(storagePersistenceService, 'read'),
['storageSilentRenewRunning', { configId: 'configId1' }],
() => null
);
const isSilentRenewRunningResult = service.isSilentRenewRunning({
configId: 'configId1',
});
expect(isSilentRenewRunningResult).toBeFalse();
expect(isSilentRenewRunningResult).toBeFalsy();
});
});
@@ -309,10 +337,10 @@ describe('Flows Data Service', () => {
dateOfLaunchedProcessUtc: baseTime.toISOString(),
};
const spy = spyOn(storagePersistenceService, 'write');
const spy = vi.spyOn(storagePersistenceService, 'write');
service.setSilentRenewRunning({ configId: 'configId1' });
expect(spy).toHaveBeenCalledOnceWith(
expect(spy).toHaveBeenCalledExactlyOnceWith(
'storageSilentRenewRunning',
JSON.stringify(storageObject),
{ configId: 'configId1' }
@@ -322,12 +350,16 @@ describe('Flows Data Service', () => {
describe('resetSilentRenewRunning', () => {
it('set resetSilentRenewRunning to empty string when called', () => {
const spy = spyOn(storagePersistenceService, 'write');
const spy = vi.spyOn(storagePersistenceService, 'write');
service.resetSilentRenewRunning({ configId: 'configId1' });
expect(spy).toHaveBeenCalledOnceWith('storageSilentRenewRunning', '', {
configId: 'configId1',
});
expect(spy).toHaveBeenCalledExactlyOnceWith(
'storageSilentRenewRunning',
'',
{
configId: 'configId1',
}
);
});
});
});

View File

@@ -1,8 +1,8 @@
import { inject, Injectable } from 'injection-js';
import { OpenIdConfiguration } from '../config/openid-configuration';
import { Injectable, inject } from 'injection-js';
import type { OpenIdConfiguration } from '../config/openid-configuration';
import { LoggerService } from '../logging/logger.service';
import { StoragePersistenceService } from '../storage/storage-persistence.service';
import { SilentRenewRunning } from './flows.models';
import type { SilentRenewRunning } from './flows.models';
import { RandomService } from './random/random.service';
@Injectable()
@@ -18,7 +18,7 @@ export class FlowsDataService {
createNonce(configuration: OpenIdConfiguration): string {
const nonce = this.randomService.createRandom(40, configuration);
this.loggerService.logDebug(configuration, 'Nonce created. nonce:' + nonce);
this.loggerService.logDebug(configuration, `Nonce created. nonce:${nonce}`);
this.setNonce(nonce, configuration);
return nonce;

View File

@@ -1,7 +1,8 @@
import { TestBed, waitForAsync } from '@angular/core/testing';
import { TestBed } from '@/testing';
import { of } from 'rxjs';
import { mockProvider } from '../../test/auto-mock';
import { CallbackContext } from './callback-context';
import { vi } from 'vitest';
import { mockProvider } from '../testing/mock';
import type { CallbackContext } from './callback-context';
import { CodeFlowCallbackHandlerService } from './callback-handling/code-flow-callback-handler.service';
import { HistoryJwtKeysCallbackHandlerService } from './callback-handling/history-jwt-keys-callback-handler.service';
import { ImplicitFlowCallbackHandlerService } from './callback-handling/implicit-flow-callback-handler.service';
@@ -64,27 +65,25 @@ describe('Flows Service', () => {
});
describe('processCodeFlowCallback', () => {
it('calls all methods correctly', waitForAsync(() => {
const codeFlowCallbackSpy = spyOn(
codeFlowCallbackHandlerService,
'codeFlowCallback'
).and.returnValue(of({} as CallbackContext));
const codeFlowCodeRequestSpy = spyOn(
codeFlowCallbackHandlerService,
'codeFlowCodeRequest'
).and.returnValue(of({} as CallbackContext));
const callbackHistoryAndResetJwtKeysSpy = spyOn(
historyJwtKeysCallbackHandlerService,
'callbackHistoryAndResetJwtKeys'
).and.returnValue(of({} as CallbackContext));
const callbackStateValidationSpy = spyOn(
stateValidationCallbackHandlerService,
'callbackStateValidation'
).and.returnValue(of({} as CallbackContext));
const callbackUserSpy = spyOn(
userCallbackHandlerService,
'callbackUser'
).and.returnValue(of({} as CallbackContext));
it('calls all methods correctly', async () => {
const codeFlowCallbackSpy = vi
.spyOn(codeFlowCallbackHandlerService, 'codeFlowCallback')
.mockReturnValue(of({} as CallbackContext));
const codeFlowCodeRequestSpy = vi
.spyOn(codeFlowCallbackHandlerService, 'codeFlowCodeRequest')
.mockReturnValue(of({} as CallbackContext));
const callbackHistoryAndResetJwtKeysSpy = vi
.spyOn(
historyJwtKeysCallbackHandlerService,
'callbackHistoryAndResetJwtKeys'
)
.mockReturnValue(of({} as CallbackContext));
const callbackStateValidationSpy = vi
.spyOn(stateValidationCallbackHandlerService, 'callbackStateValidation')
.mockReturnValue(of({} as CallbackContext));
const callbackUserSpy = vi
.spyOn(userCallbackHandlerService, 'callbackUser')
.mockReturnValue(of({} as CallbackContext));
const allConfigs = [
{
configId: 'configId1',
@@ -92,10 +91,10 @@ describe('Flows Service', () => {
];
service
.processCodeFlowCallback('some-url1234', allConfigs[0], allConfigs)
.processCodeFlowCallback('some-url1234', allConfigs[0]!, allConfigs)
.subscribe((value) => {
expect(value).toEqual({} as CallbackContext);
expect(codeFlowCallbackSpy).toHaveBeenCalledOnceWith(
expect(codeFlowCallbackSpy).toHaveBeenCalledExactlyOnceWith(
'some-url1234',
allConfigs[0]
);
@@ -104,27 +103,26 @@ describe('Flows Service', () => {
expect(callbackStateValidationSpy).toHaveBeenCalledTimes(1);
expect(callbackUserSpy).toHaveBeenCalledTimes(1);
});
}));
});
});
describe('processSilentRenewCodeFlowCallback', () => {
it('calls all methods correctly', waitForAsync(() => {
const codeFlowCodeRequestSpy = spyOn(
codeFlowCallbackHandlerService,
'codeFlowCodeRequest'
).and.returnValue(of({} as CallbackContext));
const callbackHistoryAndResetJwtKeysSpy = spyOn(
historyJwtKeysCallbackHandlerService,
'callbackHistoryAndResetJwtKeys'
).and.returnValue(of({} as CallbackContext));
const callbackStateValidationSpy = spyOn(
stateValidationCallbackHandlerService,
'callbackStateValidation'
).and.returnValue(of({} as CallbackContext));
const callbackUserSpy = spyOn(
userCallbackHandlerService,
'callbackUser'
).and.returnValue(of({} as CallbackContext));
it('calls all methods correctly', async () => {
const codeFlowCodeRequestSpy = vi
.spyOn(codeFlowCallbackHandlerService, 'codeFlowCodeRequest')
.mockReturnValue(of({} as CallbackContext));
const callbackHistoryAndResetJwtKeysSpy = vi
.spyOn(
historyJwtKeysCallbackHandlerService,
'callbackHistoryAndResetJwtKeys'
)
.mockReturnValue(of({} as CallbackContext));
const callbackStateValidationSpy = vi
.spyOn(stateValidationCallbackHandlerService, 'callbackStateValidation')
.mockReturnValue(of({} as CallbackContext));
const callbackUserSpy = vi
.spyOn(userCallbackHandlerService, 'callbackUser')
.mockReturnValue(of({} as CallbackContext));
const allConfigs = [
{
configId: 'configId1',
@@ -134,7 +132,7 @@ describe('Flows Service', () => {
service
.processSilentRenewCodeFlowCallback(
{} as CallbackContext,
allConfigs[0],
allConfigs[0]!,
allConfigs
)
.subscribe((value) => {
@@ -144,27 +142,26 @@ describe('Flows Service', () => {
expect(callbackStateValidationSpy).toHaveBeenCalled();
expect(callbackUserSpy).toHaveBeenCalled();
});
}));
});
});
describe('processImplicitFlowCallback', () => {
it('calls all methods correctly', waitForAsync(() => {
const implicitFlowCallbackSpy = spyOn(
implicitFlowCallbackHandlerService,
'implicitFlowCallback'
).and.returnValue(of({} as CallbackContext));
const callbackHistoryAndResetJwtKeysSpy = spyOn(
historyJwtKeysCallbackHandlerService,
'callbackHistoryAndResetJwtKeys'
).and.returnValue(of({} as CallbackContext));
const callbackStateValidationSpy = spyOn(
stateValidationCallbackHandlerService,
'callbackStateValidation'
).and.returnValue(of({} as CallbackContext));
const callbackUserSpy = spyOn(
userCallbackHandlerService,
'callbackUser'
).and.returnValue(of({} as CallbackContext));
it('calls all methods correctly', async () => {
const implicitFlowCallbackSpy = vi
.spyOn(implicitFlowCallbackHandlerService, 'implicitFlowCallback')
.mockReturnValue(of({} as CallbackContext));
const callbackHistoryAndResetJwtKeysSpy = vi
.spyOn(
historyJwtKeysCallbackHandlerService,
'callbackHistoryAndResetJwtKeys'
)
.mockReturnValue(of({} as CallbackContext));
const callbackStateValidationSpy = vi
.spyOn(stateValidationCallbackHandlerService, 'callbackStateValidation')
.mockReturnValue(of({} as CallbackContext));
const callbackUserSpy = vi
.spyOn(userCallbackHandlerService, 'callbackUser')
.mockReturnValue(of({} as CallbackContext));
const allConfigs = [
{
configId: 'configId1',
@@ -172,7 +169,7 @@ describe('Flows Service', () => {
];
service
.processImplicitFlowCallback(allConfigs[0], allConfigs, 'any-hash')
.processImplicitFlowCallback(allConfigs[0]!, allConfigs, 'any-hash')
.subscribe((value) => {
expect(value).toEqual({} as CallbackContext);
expect(implicitFlowCallbackSpy).toHaveBeenCalled();
@@ -180,31 +177,32 @@ describe('Flows Service', () => {
expect(callbackStateValidationSpy).toHaveBeenCalled();
expect(callbackUserSpy).toHaveBeenCalled();
});
}));
});
});
describe('processRefreshToken', () => {
it('calls all methods correctly', waitForAsync(() => {
const refreshSessionWithRefreshTokensSpy = spyOn(
refreshSessionCallbackHandlerService,
'refreshSessionWithRefreshTokens'
).and.returnValue(of({} as CallbackContext));
const refreshTokensRequestTokensSpy = spyOn(
refreshTokenCallbackHandlerService,
'refreshTokensRequestTokens'
).and.returnValue(of({} as CallbackContext));
const callbackHistoryAndResetJwtKeysSpy = spyOn(
historyJwtKeysCallbackHandlerService,
'callbackHistoryAndResetJwtKeys'
).and.returnValue(of({} as CallbackContext));
const callbackStateValidationSpy = spyOn(
stateValidationCallbackHandlerService,
'callbackStateValidation'
).and.returnValue(of({} as CallbackContext));
const callbackUserSpy = spyOn(
userCallbackHandlerService,
'callbackUser'
).and.returnValue(of({} as CallbackContext));
it('calls all methods correctly', async () => {
const refreshSessionWithRefreshTokensSpy = vi
.spyOn(
refreshSessionCallbackHandlerService,
'refreshSessionWithRefreshTokens'
)
.mockReturnValue(of({} as CallbackContext));
const refreshTokensRequestTokensSpy = vi
.spyOn(refreshTokenCallbackHandlerService, 'refreshTokensRequestTokens')
.mockReturnValue(of({} as CallbackContext));
const callbackHistoryAndResetJwtKeysSpy = vi
.spyOn(
historyJwtKeysCallbackHandlerService,
'callbackHistoryAndResetJwtKeys'
)
.mockReturnValue(of({} as CallbackContext));
const callbackStateValidationSpy = vi
.spyOn(stateValidationCallbackHandlerService, 'callbackStateValidation')
.mockReturnValue(of({} as CallbackContext));
const callbackUserSpy = vi
.spyOn(userCallbackHandlerService, 'callbackUser')
.mockReturnValue(of({} as CallbackContext));
const allConfigs = [
{
configId: 'configId1',
@@ -212,7 +210,7 @@ describe('Flows Service', () => {
];
service
.processRefreshToken(allConfigs[0], allConfigs)
.processRefreshToken(allConfigs[0]!, allConfigs)
.subscribe((value) => {
expect(value).toEqual({} as CallbackContext);
expect(refreshSessionWithRefreshTokensSpy).toHaveBeenCalled();
@@ -221,6 +219,6 @@ describe('Flows Service', () => {
expect(callbackStateValidationSpy).toHaveBeenCalled();
expect(callbackUserSpy).toHaveBeenCalled();
});
}));
});
});
});

View File

@@ -1,8 +1,8 @@
import { inject, Injectable } from 'injection-js';
import { Observable } from 'rxjs';
import { Injectable, inject } from 'injection-js';
import type { Observable } from 'rxjs';
import { concatMap } from 'rxjs/operators';
import { OpenIdConfiguration } from '../config/openid-configuration';
import { CallbackContext } from './callback-context';
import type { OpenIdConfiguration } from '../config/openid-configuration';
import type { CallbackContext } from './callback-context';
import { CodeFlowCallbackHandlerService } from './callback-handling/code-flow-callback-handler.service';
import { HistoryJwtKeysCallbackHandlerService } from './callback-handling/history-jwt-keys-callback-handler.service';
import { ImplicitFlowCallbackHandlerService } from './callback-handling/implicit-flow-callback-handler.service';

View File

@@ -1,6 +1,7 @@
import { TestBed } from '@angular/core/testing';
import { mockProvider } from '../../../test/auto-mock';
import { TestBed } from '@/testing';
import { vi } from 'vitest';
import { LoggerService } from '../../logging/logger.service';
import { mockProvider } from '../../testing/mock';
import { CryptoService } from '../../utils/crypto/crypto.service';
import { RandomService } from './random.service';

View File

@@ -1,7 +1,8 @@
import { TestBed } from '@angular/core/testing';
import { mockProvider } from '../../test/auto-mock';
import { TestBed } from '@/testing';
import { vi } from 'vitest';
import { AuthStateService } from '../auth-state/auth-state.service';
import { LoggerService } from '../logging/logger.service';
import { mockProvider } from '../testing/mock';
import { UserService } from '../user-data/user.service';
import { FlowsDataService } from './flows-data.service';
import { ResetAuthDataService } from './reset-auth-data.service';
@@ -37,7 +38,7 @@ describe('ResetAuthDataService', () => {
describe('resetAuthorizationData', () => {
it('calls resetUserDataInStore when autoUserInfo is true', () => {
const resetUserDataInStoreSpy = spyOn(
const resetUserDataInStoreSpy = vi.spyOn(
userService,
'resetUserDataInStore'
);
@@ -47,16 +48,16 @@ describe('ResetAuthDataService', () => {
},
];
service.resetAuthorizationData(allConfigs[0], allConfigs);
service.resetAuthorizationData(allConfigs[0]!, allConfigs);
expect(resetUserDataInStoreSpy).toHaveBeenCalled();
});
it('calls correct methods', () => {
const resetStorageFlowDataSpy = spyOn(
const resetStorageFlowDataSpy = vi.spyOn(
flowsDataService,
'resetStorageFlowData'
);
const setUnauthorizedAndFireEventSpy = spyOn(
const setUnauthorizedAndFireEventSpy = vi.spyOn(
authStateService,
'setUnauthenticatedAndFireEvent'
);
@@ -66,7 +67,7 @@ describe('ResetAuthDataService', () => {
},
];
service.resetAuthorizationData(allConfigs[0], allConfigs);
service.resetAuthorizationData(allConfigs[0]!, allConfigs);
expect(resetStorageFlowDataSpy).toHaveBeenCalled();
expect(setUnauthorizedAndFireEventSpy).toHaveBeenCalled();

View File

@@ -1,6 +1,6 @@
import { inject, Injectable } from 'injection-js';
import { Injectable, inject } from 'injection-js';
import { AuthStateService } from '../auth-state/auth-state.service';
import { OpenIdConfiguration } from '../config/openid-configuration';
import type { OpenIdConfiguration } from '../config/openid-configuration';
import { LoggerService } from '../logging/logger.service';
import { UserService } from '../user-data/user.service';
import { FlowsDataService } from './flows-data.service';

View File

@@ -1,11 +1,12 @@
import { HttpResponse } from '@angular/common/http';
import { TestBed, waitForAsync } from '@angular/core/testing';
import { TestBed, mockImplementationWhenArgsEqual } from '@/testing';
import { HttpResponse } from '@ngify/http';
import { isObservable, of, throwError } from 'rxjs';
import { mockProvider } from '../../test/auto-mock';
import { createRetriableStream } from '../../test/create-retriable-stream.helper';
import { vi } from 'vitest';
import { DataService } from '../api/data.service';
import { LoggerService } from '../logging/logger.service';
import { StoragePersistenceService } from '../storage/storage-persistence.service';
import { createRetriableStream } from '../testing/create-retriable-stream.helper';
import { mockProvider } from '../testing/mock';
import { SigninKeyDataService } from './signin-key-data.service';
const DUMMY_JWKS = {
@@ -53,10 +54,12 @@ describe('Signin Key Data Service', () => {
});
describe('getSigningKeys', () => {
it('throws error when no wellKnownEndpoints given', waitForAsync(() => {
spyOn(storagePersistenceService, 'read')
.withArgs('authWellKnownEndPoints', { configId: 'configId1' })
.and.returnValue(null);
it('throws error when no wellKnownEndpoints given', async () => {
mockImplementationWhenArgsEqual(
vi.spyOn(storagePersistenceService, 'read'),
['authWellKnownEndPoints', { configId: 'configId1' }],
() => null
);
const result = service.getSigningKeys({ configId: 'configId1' });
result.subscribe({
@@ -64,12 +67,14 @@ describe('Signin Key Data Service', () => {
expect(err).toBeTruthy();
},
});
}));
});
it('throws error when no jwksUri given', waitForAsync(() => {
spyOn(storagePersistenceService, 'read')
.withArgs('authWellKnownEndPoints', { configId: 'configId1' })
.and.returnValue({ jwksUri: null });
it('throws error when no jwksUri given', async () => {
mockImplementationWhenArgsEqual(
vi.spyOn(storagePersistenceService, 'read'),
['authWellKnownEndPoints', { configId: 'configId1' }],
() => ({ jwksUri: null })
);
const result = service.getSigningKeys({ configId: 'configId1' });
result.subscribe({
@@ -77,30 +82,34 @@ describe('Signin Key Data Service', () => {
expect(err).toBeTruthy();
},
});
}));
});
it('calls dataservice if jwksurl is given', waitForAsync(() => {
spyOn(storagePersistenceService, 'read')
.withArgs('authWellKnownEndPoints', { configId: 'configId1' })
.and.returnValue({ jwksUri: 'someUrl' });
const spy = spyOn(dataService, 'get').and.callFake(() => of());
it('calls dataservice if jwksurl is given', async () => {
mockImplementationWhenArgsEqual(
vi.spyOn(storagePersistenceService, 'read'),
['authWellKnownEndPoints', { configId: 'configId1' }],
() => ({ jwksUri: 'someUrl' })
);
const spy = vi.spyOn(dataService, 'get').mockImplementation(() => of());
const result = service.getSigningKeys({ configId: 'configId1' });
result.subscribe({
complete: () => {
expect(spy).toHaveBeenCalledOnceWith('someUrl', {
expect(spy).toHaveBeenCalledExactlyOnceWith('someUrl', {
configId: 'configId1',
});
},
});
}));
});
it('should retry once', waitForAsync(() => {
spyOn(storagePersistenceService, 'read')
.withArgs('authWellKnownEndPoints', { configId: 'configId1' })
.and.returnValue({ jwksUri: 'someUrl' });
spyOn(dataService, 'get').and.returnValue(
it('should retry once', async () => {
mockImplementationWhenArgsEqual(
vi.spyOn(storagePersistenceService, 'read'),
['authWellKnownEndPoints', { configId: 'configId1' }],
() => ({ jwksUri: 'someUrl' })
);
vi.spyOn(dataService, 'get').mockReturnValue(
createRetriableStream(
throwError(() => new Error('Error')),
of(DUMMY_JWKS)
@@ -113,13 +122,15 @@ describe('Signin Key Data Service', () => {
expect(res).toEqual(DUMMY_JWKS);
},
});
}));
});
it('should retry twice', waitForAsync(() => {
spyOn(storagePersistenceService, 'read')
.withArgs('authWellKnownEndPoints', { configId: 'configId1' })
.and.returnValue({ jwksUri: 'someUrl' });
spyOn(dataService, 'get').and.returnValue(
it('should retry twice', async () => {
mockImplementationWhenArgsEqual(
vi.spyOn(storagePersistenceService, 'read'),
['authWellKnownEndPoints', { configId: 'configId1' }],
() => ({ jwksUri: 'someUrl' })
);
vi.spyOn(dataService, 'get').mockReturnValue(
createRetriableStream(
throwError(() => new Error('Error')),
throwError(() => new Error('Error')),
@@ -133,13 +144,15 @@ describe('Signin Key Data Service', () => {
expect(res).toEqual(DUMMY_JWKS);
},
});
}));
});
it('should fail after three tries', waitForAsync(() => {
spyOn(storagePersistenceService, 'read')
.withArgs('authWellKnownEndPoints', { configId: 'configId1' })
.and.returnValue({ jwksUri: 'someUrl' });
spyOn(dataService, 'get').and.returnValue(
it('should fail after three tries', async () => {
mockImplementationWhenArgsEqual(
vi.spyOn(storagePersistenceService, 'read'),
['authWellKnownEndPoints', { configId: 'configId1' }],
() => ({ jwksUri: 'someUrl' })
);
vi.spyOn(dataService, 'get').mockReturnValue(
createRetriableStream(
throwError(() => new Error('Error')),
throwError(() => new Error('Error')),
@@ -153,21 +166,21 @@ describe('Signin Key Data Service', () => {
expect(err).toBeTruthy();
},
});
}));
});
});
describe('handleErrorGetSigningKeys', () => {
it('keeps observable if error is catched', waitForAsync(() => {
it('keeps observable if error is catched', async () => {
const result = (service as any).handleErrorGetSigningKeys(
new HttpResponse()
);
const hasTypeObservable = isObservable(result);
expect(hasTypeObservable).toBeTrue();
}));
expect(hasTypeObservable).toBeTruthy();
});
it('logs error if error is response', waitForAsync(() => {
const logSpy = spyOn(loggerService, 'logError');
it('logs error if error is response', async () => {
const logSpy = vi.spyOn(loggerService, 'logError');
(service as any)
.handleErrorGetSigningKeys(
@@ -176,31 +189,31 @@ describe('Signin Key Data Service', () => {
)
.subscribe({
error: () => {
expect(logSpy).toHaveBeenCalledOnceWith(
expect(logSpy).toHaveBeenCalledExactlyOnceWith(
{ configId: 'configId1' },
'400 - nono {}'
);
},
});
}));
});
it('logs error if error is not a response', waitForAsync(() => {
const logSpy = spyOn(loggerService, 'logError');
it('logs error if error is not a response', async () => {
const logSpy = vi.spyOn(loggerService, 'logError');
(service as any)
.handleErrorGetSigningKeys('Just some Error', { configId: 'configId1' })
.subscribe({
error: () => {
expect(logSpy).toHaveBeenCalledOnceWith(
expect(logSpy).toHaveBeenCalledExactlyOnceWith(
{ configId: 'configId1' },
'Just some Error'
);
},
});
}));
});
it('logs error if error with message property is not a response', waitForAsync(() => {
const logSpy = spyOn(loggerService, 'logError');
it('logs error if error with message property is not a response', async () => {
const logSpy = vi.spyOn(loggerService, 'logError');
(service as any)
.handleErrorGetSigningKeys(
@@ -209,12 +222,12 @@ describe('Signin Key Data Service', () => {
)
.subscribe({
error: () => {
expect(logSpy).toHaveBeenCalledOnceWith(
expect(logSpy).toHaveBeenCalledExactlyOnceWith(
{ configId: 'configId1' },
'Just some Error'
);
},
});
}));
});
});
});