Select Git revision
DocumentManagerApplicationITCase.java
command.effects.spec.ts 17.09 KiB
import {
ApiError,
ApiErrorAction,
EMPTY_STRING,
TypedActionCreatorWithProps,
} from '@alfa-client/tech-shared';
import { Mock, mock } from '@alfa-client/test-utils';
import { SnackBarService } from '@alfa-client/ui';
import { TestBed } from '@angular/core/testing';
import { provideMockActions } from '@ngrx/effects/testing';
import { Action, Store, createAction, props } from '@ngrx/store';
import { TypedAction } from '@ngrx/store/src/models';
import { provideMockStore } from '@ngrx/store/testing';
import { Resource } from '@ngxp/rest';
import { cold, hot } from 'jest-marbles';
import { ColdObservable } from 'jest-marbles/typings/src/rxjs/cold-observable';
import {
createCommandListResource,
createCommandResource,
createCreateCommandProps,
} from 'libs/command-shared/test/command';
import { createApiError } from 'libs/tech-shared/test/error';
import { Observable, of } from 'rxjs';
import { TestScheduler } from 'rxjs/testing';
import { CommandLinkRel } from '../command.linkrel';
import { CREATE_COMMAND_MESSAGE_BY_ORDER, CommandErrorMessage } from '../command.message';
import { CommandListResource, CommandResource, CreateCommandProps } from '../command.model';
import { CommandRepository } from '../command.repository';
import {
CommandProps,
LoadCommandListSuccessProps,
SnackBarProps,
createCommandFailure,
} from './command.actions';
import { CommandEffects } from './command.effects';
import * as CommandActions from './command.actions';
describe('CommandEffects', () => {
let actions: Observable<Action>;
let effects: CommandEffects;
let repository: Mock<CommandRepository>;
let snackBarService: Mock<SnackBarService>;
let store: Mock<Store>;
let testScheduler: TestScheduler;
beforeEach(() => {
repository = mock(CommandRepository);
snackBarService = mock(SnackBarService);
store = mock(Store);
testScheduler = new TestScheduler((actual, expected) => expect(actual).toEqual(expected));
TestBed.configureTestingModule({
providers: [
CommandEffects,
provideMockActions(() => actions),
provideMockStore(),
{
provide: CommandRepository,
useValue: repository,
},
{
provide: SnackBarService,
useValue: snackBarService,
},
{
provide: Store,
useValue: store,
},
],
});
effects = TestBed.inject(CommandEffects);
});
describe('loadCommandList', () => {
const resource: Resource = createCommandResource();
const linkRel: string = 'LinkRelationOfResource';
const loadSuccess: TypedActionCreatorWithProps<LoadCommandListSuccessProps> = createAction(
'[Test Action] Load Success',
props<LoadCommandListSuccessProps>(),
);
const loadFailure: TypedActionCreatorWithProps<ApiErrorAction> = createAction(
'[Test Action] Load Failure',
props<ApiErrorAction>(),
);
const loadCommandList: TypedAction<string> = CommandActions.loadCommandList({
resource,
linkRel,
successAction: (commandList) => loadSuccess({ commandList }),
failureAction: (apiError) => loadFailure({ apiError }),
});
const commandListResource: CommandListResource = createCommandListResource();
beforeEach(() => {
repository.getPendingCommands.mockReturnValue(of(commandListResource));
});
it('should call repository', () => {
actions = of(loadCommandList);
effects.loadCommandList$.subscribe();
expect(repository.getPendingCommands).toHaveBeenCalledWith(resource, linkRel);
});
it('should dispatch success action on no error', () => {
actions = hot('-a', { a: loadCommandList });
const expected: ColdObservable = cold('-b', {
b: loadSuccess({ commandList: commandListResource }),
});
expect(effects.loadCommandList$).toBeObservable(expected);
});
it('should dispatch failure action on error', () => {
const apiError: ApiError = createApiError();
const error = { error: apiError };
const errorResponse = cold('-#', {}, error);
repository.getPendingCommands = jest.fn(() => errorResponse);
actions = hot('-a', { a: loadCommandList });
const expected: ColdObservable = cold('--b', { b: loadFailure({ apiError }) });
expect(effects.loadCommandList$).toBeObservable(expected);
});
});
describe('createCommand', () => {
const createCommandProps: CreateCommandProps = createCreateCommandProps();
const createCommandAction: TypedAction<string> =
CommandActions.createCommand(createCommandProps);
const commandResource: CommandResource = createCommandResource();
beforeEach(() => {
repository.createCommand.mockReturnValue(of(commandResource));
});
it('should call repository', () => {
actions = of(createCommandAction);
effects.createCommand$.subscribe();
expect(repository.createCommand).toHaveBeenCalledWith(
createCommandProps.resource,
createCommandProps.linkRel,
createCommandProps.command,
);
});
it('should handle createdCommand on success', () => {
effects.handleCreatedCommand = jest.fn();
actions = of(createCommandAction);
effects.createCommand$.subscribe();
expect(effects.handleCreatedCommand).toHaveBeenCalledWith(
addCreateCommandActionType(createCommandProps),
commandResource,
);
});
function addCreateCommandActionType(createCommandProps: CreateCommandProps) {
return { ...createCommandProps, type: '[Command] Create command' };
}
it('should dispatch failure action on error', () => {
const error = { error: {} };
const errorResponse = cold('-#', {}, error);
repository.createCommand = jest.fn(() => errorResponse);
actions = hot('-a', { a: createCommandAction });
const expected: ColdObservable = cold('--b', {
b: CommandActions.createCommandFailure({ error, command: createCommandProps.command }),
});
expect(effects.createCommand$).toBeObservable(expected);
});
});
describe('handleCreatedCommand', () => {
const createCommandProps: CreateCommandProps = createCreateCommandProps();
it('should return pollCreatedCommand action on pending command', () => {
const command: CommandResource = createCommandResource([CommandLinkRel.UPDATE]);
const actions: TypedAction<string>[] = effects.handleCreatedCommand(
createCommandProps,
command,
);
expect(actions.length).toBe(1);
expect(actions[0].type).toBe(CommandActions.pollCreatedCommand.type);
const pollCreatedCommandAction: CommandActions.PollCommandProps = <any>actions[0];
expect(pollCreatedCommandAction.command).toBe(command);
expect(pollCreatedCommandAction.createCommandProps).toBe(createCommandProps);
});
it('should call handleCreateCommandSuccess on NOT pending command', () => {
effects.handleCreateCommandSuccess = jest.fn();
const command: CommandResource = createCommandResource();
effects.handleCreatedCommand(createCommandProps, command);
expect(effects.handleCreateCommandSuccess).toHaveBeenCalledWith(createCommandProps, command);
});
});
describe.skip('FIXME: pollCreatedCommand', () => {
const delay: string = CommandEffects.POLL_DELAY + 'ms';
const command: CommandResource = createCommandResource();
const pollCreateCommandAction: TypedAction<string> = CommandActions.pollCreatedCommand({
command,
});
beforeEach(() => {
repository.getCommand.mockReturnValue(of(command));
});
it('should call repository', () => {
actions = hot('-a', { a: pollCreateCommandAction });
effects.pollCreatedCommand$.subscribe(() => {
console.info('Call repo!?');
// expect(repository.getCommand).toHaveBeenCalledWith(command);
fail();
});
});
it('should handle createdCommand on no error and pending command', () => {
// testScheduler.run((helpers) => {
// const { hot, cold } = helpers;
repository.getCommand.mockReturnValue(cold('-b|', { b: command }));
effects.handleCreatedCommand = jest.fn();
actions = hot('-a', { a: pollCreateCommandAction });
effects.createCommand$.subscribe(() => {
console.info('Call handleCreatedCommand!?');
expect(effects.handleCreatedCommand).toHaveBeenCalledWith(command);
});
// });
});
it('should dispatch failure action on error', () => {
testScheduler.run((helpers) => {
const { hot, cold, expectObservable } = helpers;
const error = { error: {} };
const errorResponse = cold('-#', {}, error);
repository.getCommand = jest.fn(() => errorResponse);
actions = hot('-a', { a: pollCreateCommandAction });
expectObservable(effects.pollCreatedCommand$).toBe(delay + ' --c', {
c: createCommandFailure({ command, error }),
});
});
});
});
describe('handleCreateCommandSuccess', () => {
const createCommandProps: CreateCommandProps = createCreateCommandProps();
describe('on non revokeable command without error', () => {
it('should return createCommandSuccess action', () => {
const command: CommandResource = createCommandResource();
const actions: TypedAction<string>[] = effects.handleCreateCommandSuccess(
createCommandProps,
command,
);
expect(actions.length).toBe(2);
const createCommandSuccessAction: CommandActions.CommandProps = <any>actions[0];
expect(createCommandSuccessAction.command).toBe(command);
expect(actions[1].type).toBe(CommandActions.showSnackbar.type);
});
it('should return showSnackbar action', () => {
const command: CommandResource = createCommandResource();
const actions: TypedAction<string>[] = effects.handleCreateCommandSuccess(
createCommandProps,
command,
);
expect(actions.length).toBe(2);
const showSnackbarAction: CommandActions.SnackBarProps = <any>actions[1];
expect(showSnackbarAction.createCommandProps).toBe(createCommandProps);
expect(showSnackbarAction.command).toBe(command);
});
});
describe('on revokeable command', () => {
it('should return createCommandSuccess action', () => {
const command: CommandResource = createCommandResource([CommandLinkRel.REVOKE]);
const actions: TypedAction<string>[] = effects.handleCreateCommandSuccess(
createCommandProps,
command,
);
expect(actions.length).toBe(2);
expect(actions[0].type).toBe(CommandActions.createCommandSuccess.type);
expect((<any>actions[0]).command).toBe(command);
});
it('should return showRevokeSnackbar action', () => {
const command: CommandResource = createCommandResource([CommandLinkRel.REVOKE]);
const actions: TypedAction<string>[] = effects.handleCreateCommandSuccess(
createCommandProps,
command,
);
expect(actions.length).toBe(2);
expect(actions[1].type).toBe(CommandActions.showRevokeSnackbar.type);
expect((<any>actions[1]).command).toBe(command);
});
});
describe('on error command', () => {
it('should show snackbar with error', () => {
const command: CommandResource = {
...createCommandResource(),
errorMessage: CommandErrorMessage.CONCURRENT_MODIFICATION,
};
effects.handleCreateCommandSuccess(createCommandProps, command);
expect(snackBarService.showError).toHaveBeenCalledWith(
'Der Vorgang wurde zwischenzeitlich verändert und wurde neu geladen.',
);
});
it('should return createCommandSuccess and publishConcurrentModificationAction', () => {
const command: CommandResource = {
...createCommandResource(),
errorMessage: CommandErrorMessage.CONCURRENT_MODIFICATION,
};
const actions: TypedAction<string>[] = effects.handleCreateCommandSuccess(
createCommandProps,
command,
);
expect(actions.length).toBe(2);
expect(actions[0].type).toBe(CommandActions.createCommandSuccess.type);
expect((<any>actions[0]).command).toBe(command);
expect(actions[1].type).toBe(CommandActions.publishConcurrentModificationAction.type);
});
});
});
describe('showRevokeSnackbar', () => {
const command: CommandResource = createCommandResource();
const showRevokeSnackbarAction: TypedAction<string> = CommandActions.showRevokeSnackbar({
command,
});
it('should show snackbar', () => {
actions = of(showRevokeSnackbarAction);
effects.showRevokeSnackbar$.subscribe();
expect(snackBarService.show).toHaveBeenCalled();
});
});
describe('showSnackbar', () => {
const createCommandProps: CreateCommandProps = createCreateCommandProps();
const command: CommandResource = createCommandResource();
it('should call handle snackbar by command', () => {
effects.handleSnackbarByCommand = jest.fn();
const showSnackbarAction: TypedAction<string> = CommandActions.showSnackbar({
createCommandProps,
command,
});
actions = of(showSnackbarAction);
effects.showSnackbar$.subscribe();
expect(effects.handleSnackbarByCommand).toHaveBeenCalled();
});
});
describe('handle snackbar by command', () => {
const createCommandProps: CreateCommandProps = createCreateCommandProps();
const command: CommandResource = createCommandResource();
it('should show snackBar on existing snackBarMessage', () => {
const snackBarProps: SnackBarProps = { createCommandProps, command };
effects.handleSnackbarByCommand(snackBarProps);
expect(snackBarService.show).toHaveBeenCalledWith(
command,
createCommandProps.snackBarMessage,
);
});
it('should show snackBar on undefined snackBarMessage', () => {
const snackBarProps: SnackBarProps = {
createCommandProps: { ...createCommandProps, snackBarMessage: undefined },
command,
};
effects.handleSnackbarByCommand(snackBarProps);
expect(snackBarService.show).toHaveBeenCalledWith(
command,
CREATE_COMMAND_MESSAGE_BY_ORDER[command.order],
);
});
it('should NOT show snackBar on empty snackBarMessage', () => {
const snackBarProps: SnackBarProps = {
createCommandProps: { ...createCommandProps, snackBarMessage: EMPTY_STRING },
command,
};
effects.handleSnackbarByCommand(snackBarProps);
expect(snackBarService.show).not.toHaveBeenCalled();
});
it('should NOT show snackBar on existing error message', () => {
const snackBarProps: SnackBarProps = {
createCommandProps,
command: { ...command, errorMessage: 'dummyErrorMessage' },
};
effects.handleSnackbarByCommand(snackBarProps);
expect(snackBarService.show).not.toHaveBeenCalled();
});
});
describe('revokeCommand', () => {
const command: CommandResource = createCommandResource();
const revokeCommandAction: TypedAction<string> = CommandActions.revokeCommand({ command });
const getCommand: CommandResource = createCommandResource();
beforeEach(() => {
repository.revokeCommand.mockReturnValue(of(getCommand));
});
it('should call repository', () => {
actions = of(revokeCommandAction);
effects.revokeCommand$.subscribe();
expect(repository.revokeCommand).toHaveBeenCalledWith(command);
});
it('should handle revokeCommand', () => {
effects.handleRevokeCommand = jest.fn();
actions = of(revokeCommandAction);
effects.revokeCommand$.subscribe();
expect(effects.handleRevokeCommand).toHaveBeenCalledWith(getCommand);
});
it('should dispatch failure action on error', () => {
const error = { error: {} };
const errorResponse = cold('-#', {}, error);
repository.revokeCommand = jest.fn(() => errorResponse);
actions = hot('-a', { a: revokeCommandAction });
const expected: ColdObservable = cold('--b', {
b: CommandActions.revokeCommandFailure({ command, error }),
});
expect(effects.revokeCommand$).toBeObservable(expected);
});
});
describe.skip('pollRevokedCommand', () => {
//TODO Test fuer pollRevokedCommand
});
describe('handleRevokeCommand', () => {
it('should return revokeCommandSuccess action', () => {
const command: CommandResource = createCommandResource();
const actions: (CommandProps & TypedAction<string>)[] = effects.handleRevokeCommand(command);
expect(actions.length).toBe(1);
expect(actions[0].type).toBe(CommandActions.revokeCommandSuccess.type);
expect(actions[0].command).toBe(command);
});
it('should return pollRevokedCommand action on pending command', () => {
const command: CommandResource = createCommandResource([CommandLinkRel.UPDATE]);
const actions: (CommandProps & TypedAction<string>)[] = effects.handleRevokeCommand(command);
expect(actions.length).toBe(1);
expect(actions[0].type).toBe(CommandActions.pollRevokedCommand.type);
expect(actions[0].command).toBe(command);
});
});
});