Newer
Older
import { Mock, mock } from '@alfa-client/test-utils';
import { TestBed, fakeAsync, tick } from '@angular/core/testing';
import KcAdminClient, { NetworkError } from '@keycloak/keycloak-admin-client';
import { TokenProvider } from '@keycloak/keycloak-admin-client/lib/client';
import GroupRepresentation from '@keycloak/keycloak-admin-client/lib/defs/groupRepresentation';
import { Groups } from '@keycloak/keycloak-admin-client/lib/resources/groups';
import { OAuthService } from 'angular-oauth2-oidc';
import { Observable, OperatorFunction, catchError, firstValueFrom, of, throwError } from 'rxjs';
import {
createGroupRepresentation,
createNetworkError,
createOrganisationseinheit,
} from '../../../test/user/user';
import {
Organisationseinheit,
OrganisationseinheitError,
OrganisationseinheitErrorType,
} from './user.model';
import { UserRepository } from './user.repository.service';
const accessToken: string = faker.random.alphaNumeric(40);
const error: OrganisationseinheitError = createOrganisationseinheitError();
const networkError: NetworkError = createNetworkError(400, '');
let repository: UserRepository;
let kcAdminClient: Mock<KcAdminClient>;
let oAuthService: Mock<OAuthService>;
const mockGroupsFunc = (groupsKey: keyof Groups, implementation: jest.Mock) => {
kcAdminClient.groups = <any>{
[groupsKey]: implementation,
};
};
kcAdminClient = mock(KcAdminClient);
oAuthService = mock(OAuthService);
TestBed.configureTestingModule({
providers: [
{ provide: OAuthService, useValue: oAuthService },
{ provide: KcAdminClient, useValue: kcAdminClient },
oAuthService.getAccessToken.mockReturnValue(accessToken);
repository = TestBed.inject(UserRepository);
});
it('should be created', () => {
expect(repository).toBeTruthy();
});
describe('registerTokenProvider', () => {
it('should register token provider from oauth service', async () => {
const tokenProvider: TokenProvider = kcAdminClient.registerTokenProvider.mock.calls[0][0];
const token: string = await tokenProvider.getAccessToken();
expect(token).toEqual(accessToken);
});
describe('map organisationseinheit representation', () => {
let expectedOrganisationseinheit: Organisationseinheit = createOrganisationseinheit();
const organisationseinheit: Organisationseinheit =
repository.mapGroupRepresentationToOrganisationseinheit({
id: expectedOrganisationseinheit.id,
});
expect(organisationseinheit.id).toEqual(expectedOrganisationseinheit.id);
});
it('should map field "name"', () => {
const organisationseinheit: Organisationseinheit =
repository.mapGroupRepresentationToOrganisationseinheit({
name: expectedOrganisationseinheit.name,
expect(organisationseinheit.name).toEqual(expectedOrganisationseinheit.name);
});
it('should map field "organisationseinheitIds"', () => {
const organisationseinheit: Organisationseinheit =
repository.mapGroupRepresentationToOrganisationseinheit({
attributes: {
organisationseinheitId: expectedOrganisationseinheit.organisationseinheitIds,
},
expect(organisationseinheit.organisationseinheitIds).toEqual(
expectedOrganisationseinheit.organisationseinheitIds,
it('should map missing organisationseinheitIds to empty list', () => {
const organisationseinheit: Organisationseinheit =
repository.mapGroupRepresentationToOrganisationseinheit({});
expect(organisationseinheit.organisationseinheitIds).toEqual([]);
describe('find organisationseinheitItems', () => {
const organisationseinheitItems: Organisationseinheit[] = [
createOrganisationseinheit(),
createOrganisationseinheit(),
createOrganisationseinheit(),
const groupReps: GroupRepresentation[] =
organisationseinheitItems.map(createGroupRepresentation);
it('should return mapped organisationseinheit search result', async () => {
const findMock: jest.Mock = jest.fn().mockReturnValue(Promise.resolve(groupReps));
mockGroupsFunc('find', findMock);
const groupsResult: Organisationseinheit[] = await firstValueFrom(
repository.findOrganisationseinheitItems(),
);
expect(groupsResult).toEqual(groupsResult);
it('should call with brief representation', fakeAsync(() => {
const findMock: jest.Mock = jest.fn().mockReturnValue(Promise.resolve(groupReps));
mockGroupsFunc('find', findMock);
repository.findOrganisationseinheitItems().subscribe();
expect(findMock).toHaveBeenCalledWith({ briefRepresentation: false });
}));
describe('save organisationseinheit', () => {
const saveGroup: Organisationseinheit = createOrganisationseinheit();
it('should call kcAdminClient.groups.save', async () => {
const updateMock: jest.Mock = jest.fn(() => of(null));
mockGroupsFunc('update', updateMock);
await firstValueFrom(repository.saveOrganisationseinheit(saveGroup));
expect(updateMock).toHaveBeenCalledWith(
{ id: saveGroup.id },
{
name: saveGroup.name,
attributes: {
organisationseinheitId: saveGroup.organisationseinheitIds,
},
);
});
it('should return organisationseinheit save observable', async () => {
const updateMock: jest.Mock = jest.fn(() => Promise.resolve(null));
mockGroupsFunc('update', updateMock);
const voidResult = await firstValueFrom(repository.saveOrganisationseinheit(saveGroup));
expect(voidResult).toBe(null);
it('should pipe rethrowMappedGroupsError', (done) => {
const updateMock: jest.Mock = jest.fn(() => Promise.reject(networkError));
mockGroupsFunc('update', updateMock);
repository.rethrowMappedGroupsError = jest
.fn()
.mockReturnValue(catchError(() => throwError(() => error)));
repository.saveOrganisationseinheit(saveGroup).subscribe({
error: (err) => {
expect(err).toBe(error);
done();
},
});
});
describe('create organisationseinheit', () => {
const newOrganisationseinheit: Organisationseinheit = createOrganisationseinheit();
it('should call kcAdminClient.groups.create', async () => {
const createMock: jest.Mock = jest.fn(() => of({ id: newOrganisationseinheit.id }));
mockGroupsFunc('create', createMock);
await firstValueFrom(
repository.createOrganisationseinheit(
newOrganisationseinheit.name,
newOrganisationseinheit.organisationseinheitIds,
),
);
expect(createMock).toHaveBeenCalledWith({
name: newOrganisationseinheit.name,
organisationseinheitId: newOrganisationseinheit.organisationseinheitIds,
it('should return mapped organisationseinheit result', async () => {
const createMock: jest.Mock = jest.fn(() =>
Promise.resolve({ id: newOrganisationseinheit.id }),
);
mockGroupsFunc('create', createMock);
const newGroupResult: Organisationseinheit = await firstValueFrom(
repository.createOrganisationseinheit(
newOrganisationseinheit.name,
newOrganisationseinheit.organisationseinheitIds,
),
expect(newGroupResult).toEqual(newOrganisationseinheit);
it('should pipe rethrowMappedGroupsError', (done) => {
const createMock: jest.Mock = jest.fn(() => Promise.reject(networkError));
mockGroupsFunc('create', createMock);
repository.rethrowMappedGroupsError = jest
.fn()
.mockReturnValue(catchError(() => throwError(() => error)));
repository
.createOrganisationseinheit(
newOrganisationseinheit.name,
newOrganisationseinheit.organisationseinheitIds,
)
.subscribe({
error: (err) => {
expect(err).toBe(error);
done();
},
});
});
});
describe('rethrow mapped groups error', () => {
let networkErrorObservable: Observable<never>;
beforeEach(() => {
repository.mapCreateGroupsNetworkError = jest.fn().mockReturnValue(error);
networkErrorObservable = throwError(() => networkError);
});
it('should throw mapped error', (done) => {
const rethrowOperator: OperatorFunction<never, never> = repository.rethrowMappedGroupsError();
networkErrorObservable.pipe(rethrowOperator).subscribe({
error: (err) => {
expect(err).toBe(error);
done();
},
it('should call mapCreateGroupsNetworkError', (done) => {
const rethrowOperator: OperatorFunction<never, never> = repository.rethrowMappedGroupsError();
networkErrorObservable.pipe(rethrowOperator).subscribe({
error: () => {
expect(repository.mapCreateGroupsNetworkError).toHaveBeenCalledWith(networkError);
done();
},
});
});
describe('map create groups network error', () => {
it('should interpret 409 status as name conflict', () => {
const keycloakError: OrganisationseinheitError = createOrganisationseinheitError(
OrganisationseinheitErrorType.NAME_CONFLICT,
const networkError: NetworkError = createNetworkError(409, keycloakError.detail);
const error: OrganisationseinheitError = repository.mapCreateGroupsNetworkError(networkError);
expect(error).toEqual(keycloakError);
});
it('should interpret 400 status as name missing', () => {
const keycloakError: OrganisationseinheitError = createOrganisationseinheitError(
OrganisationseinheitErrorType.NAME_MISSING,
const networkError: NetworkError = createNetworkError(400, keycloakError.detail);
const error: OrganisationseinheitError = repository.mapCreateGroupsNetworkError(networkError);
expect(error).toEqual(keycloakError);
});
it('should map missing errorMessage to empty string', () => {
const networkError: NetworkError = createNetworkError(500, undefined);
const error: OrganisationseinheitError = repository.mapCreateGroupsNetworkError(networkError);
expect(error.detail).toEqual('');
describe('delete organisationseinheit', () => {
const deleteOrganisationseinheit: Organisationseinheit = createOrganisationseinheit();
it('should call kcAdminClient.groups.del', async () => {
const delMock: jest.Mock = jest.fn(() =>
Promise.resolve({ id: deleteOrganisationseinheit.id }),
);
mockGroupsFunc('del', delMock);
await firstValueFrom(repository.deleteOrganisationseinheit(deleteOrganisationseinheit.id));
expect(delMock).toHaveBeenCalledWith({
id: deleteOrganisationseinheit.id,
it('should return void', async () => {
mockGroupsFunc(
'del',
jest.fn(() => Promise.resolve(null)),
);
const voidResult = await firstValueFrom(
repository.deleteOrganisationseinheit(deleteOrganisationseinheit.id),
);
expect(voidResult).toBeNull();