78001: RelationshipEffects test fixes

This commit is contained in:
Kristof De Langhe
2021-04-07 17:07:26 +02:00
parent 9c85328b17
commit 5fca681222
3 changed files with 72 additions and 81 deletions

View File

@@ -1,6 +1,6 @@
import { Router, UrlTree } from '@angular/router';
import { combineLatest as observableCombineLatest, Observable } from 'rxjs';
import { filter, find, map, mergeMap, switchMap, take, takeWhile, tap } from 'rxjs/operators';
import { debounceTime, filter, find, map, mergeMap, switchMap, take, takeWhile, tap } from 'rxjs/operators';
import { hasNoValue, hasValue, hasValueOperator, isNotEmpty } from '../../shared/empty.util';
import { SearchResult } from '../../shared/search/search-result.model';
import { PaginatedList } from '../data/paginated-list.model';
@@ -15,6 +15,12 @@ import { DSpaceObject } from './dspace-object.model';
import { getForbiddenRoute, getPageNotFoundRoute } from '../../app-routing-paths';
import { getEndUserAgreementPath } from '../../info/info-routing-paths';
import { AuthService } from '../auth/auth.service';
import { InjectionToken } from '@angular/core';
export const DEBOUNCE_TIME_OPERATOR = new InjectionToken<<T>(dueTime: number) => (source: Observable<T>) => Observable<T>>('debounceTime', {
providedIn: 'root',
factory: () => debounceTime
});
/**
* This file contains custom RxJS operators that can be used in multiple places

View File

@@ -1,10 +1,7 @@
import { TestBed, waitForAsync } from '@angular/core/testing';
import { BehaviorSubject, Observable, of as observableOf } from 'rxjs';
import { TestScheduler } from 'rxjs/testing';
import { provideMockActions } from '@ngrx/effects/testing';
import { Store } from '@ngrx/store';
import { RelationshipEffects } from './relationship.effects';
import { AddRelationshipAction, RelationshipActionTypes, RemoveRelationshipAction } from './relationship.actions';
import { Item } from '../../../../../core/shared/item.model';
@@ -23,6 +20,9 @@ import { RequestService } from '../../../../../core/data/request.service';
import { NotificationsService } from '../../../../notifications/notifications.service';
import { TranslateService } from '@ngx-translate/core';
import { SelectableListService } from '../../../../object-list/selectable-list/selectable-list.service';
import { cold, hot } from 'jasmine-marbles';
import { DEBOUNCE_TIME_OPERATOR } from '../../../../../core/shared/operators';
import { last } from 'rxjs/operators';
describe('RelationshipEffects', () => {
let relationEffects: RelationshipEffects;
@@ -51,7 +51,6 @@ describe('RelationshipEffects', () => {
let notificationsService;
let translateService;
let selectableListService;
let testScheduler: TestScheduler;
function init() {
testUUID1 = '20e24c2f-a00a-467c-bdee-c929e79bf08d';
@@ -131,6 +130,7 @@ describe('RelationshipEffects', () => {
{ provide: NotificationsService, useValue: notificationsService },
{ provide: TranslateService, useValue: translateService },
{ provide: SelectableListService, useValue: selectableListService },
{ provide: DEBOUNCE_TIME_OPERATOR, useValue: jasmine.createSpy('debounceTime').and.returnValue((v) => v.pipe(last())) },
],
});
}));
@@ -140,9 +140,6 @@ describe('RelationshipEffects', () => {
identifier = (relationEffects as any).createIdentifier(leftItem, rightItem, relationshipType.leftwardType);
spyOn((relationEffects as any), 'addRelationship').and.stub();
spyOn((relationEffects as any), 'removeRelationship').and.stub();
testScheduler = new TestScheduler((actual, expected) => {
expect(actual).toEqual(expected);
});
});
describe('mapLastActions$', () => {
@@ -151,15 +148,13 @@ describe('RelationshipEffects', () => {
let action;
it('should set the current value debounceMap and the value of the initialActionMap to ADD_RELATIONSHIP', () => {
testScheduler.run(({ hot, expectObservable, flush }) => {
action = new AddRelationshipAction(leftItem, rightItem, relationshipType.leftwardType, '1234');
actions = hot('--a-|', { a: action });
expectObservable(relationEffects.mapLastActions$).toBe('--b-|', { b: undefined });
flush();
// TODO check following expectations with the implementation
// expect((relationEffects as any).initialActionMap[identifier]).toBe(action.type);
// expect((relationEffects as any).debounceMap[identifier].value).toBe(action.type);
});
action = new AddRelationshipAction(leftItem, rightItem, relationshipType.leftwardType, '1234');
actions = hot('--a-|', { a: action });
const expected = cold('--b-|', { b: undefined });
expect(relationEffects.mapLastActions$).toBeObservable(expected);
expect((relationEffects as any).initialActionMap[identifier]).toBe(action.type);
expect((relationEffects as any).debounceMap[identifier].value).toBe(action.type);
});
});
@@ -172,14 +167,14 @@ describe('RelationshipEffects', () => {
});
it('should set the current value debounceMap to ADD_RELATIONSHIP but not change the value of the initialActionMap', () => {
testScheduler.run(({ hot, expectObservable, flush }) => {
action = new AddRelationshipAction(leftItem, rightItem, relationshipType.leftwardType, '1234');
actions = hot('--a-|', { a: action });
expectObservable(relationEffects.mapLastActions$).toBe('--b-|', { b: undefined });
flush();
expect((relationEffects as any).initialActionMap[identifier]).toBe(testActionType);
expect((relationEffects as any).debounceMap[identifier].value).toBe(action.type);
});
action = new AddRelationshipAction(leftItem, rightItem, relationshipType.leftwardType, '1234');
actions = hot('--a-|', { a: action });
const expected = cold('--b-|', { b: undefined });
expect(relationEffects.mapLastActions$).toBeObservable(expected);
expect((relationEffects as any).initialActionMap[identifier]).toBe(testActionType);
expect((relationEffects as any).debounceMap[identifier].value).toBe(action.type);
});
});
@@ -188,30 +183,26 @@ describe('RelationshipEffects', () => {
describe('When the last value in the debounceMap is also an ADD_RELATIONSHIP action', () => {
beforeEach(() => {
(relationEffects as any).initialActionMap[identifier] = RelationshipActionTypes.ADD_RELATIONSHIP;
((relationEffects as any).debounceTime as jasmine.Spy).and.returnValue((v) => v);
});
it('should call addRelationship on the effect', () => {
testScheduler.run(({ hot, expectObservable, flush }) => {
action = new AddRelationshipAction(leftItem, rightItem, relationshipType.leftwardType, '1234');
actions = hot('--a-|', { a: action });
expectObservable(relationEffects.mapLastActions$).toBe('--b-|', { b: undefined });
flush();
expect((relationEffects as any).addRelationship).toHaveBeenCalledWith(leftItem, rightItem, relationshipType.leftwardType, '1234', undefined);
});
action = new AddRelationshipAction(leftItem, rightItem, relationshipType.leftwardType, '1234');
actions = hot('--a-|', { a: action });
const expected = cold('--b-|', { b: undefined });
expect(relationEffects.mapLastActions$).toBeObservable(expected);
expect((relationEffects as any).addRelationship).toHaveBeenCalledWith(leftItem, rightItem, relationshipType.leftwardType, '1234', undefined);
});
});
describe('When the last value in the debounceMap is instead a REMOVE_RELATIONSHIP action', () => {
it('should <b>not</b> call removeRelationship or addRelationship on the effect', () => {
testScheduler.run(({ hot, expectObservable, flush }) => {
const actiona = new AddRelationshipAction(leftItem, rightItem, relationshipType.leftwardType, '1234');
const actionb = new RemoveRelationshipAction(leftItem, rightItem, relationshipType.leftwardType, '1234');
actions = hot('--ab-|', { a: actiona, b: actionb });
expectObservable(relationEffects.mapLastActions$).toBe('--bb-|', { b: undefined });
flush();
expect((relationEffects as any).addRelationship).not.toHaveBeenCalled();
expect((relationEffects as any).removeRelationship).not.toHaveBeenCalled();
});
const actiona = new AddRelationshipAction(leftItem, rightItem, relationshipType.leftwardType, '1234');
const actionb = new RemoveRelationshipAction(leftItem, rightItem, relationshipType.leftwardType, '1234');
actions = hot('--ab-|', { a: actiona, b: actionb });
const expected = cold('--bb-|', { b: undefined });
expect(relationEffects.mapLastActions$).toBeObservable(expected);
expect((relationEffects as any).addRelationship).not.toHaveBeenCalled();
expect((relationEffects as any).removeRelationship).not.toHaveBeenCalled();
});
});
});
@@ -222,15 +213,13 @@ describe('RelationshipEffects', () => {
let action;
it('should set the current value debounceMap and the value of the initialActionMap to REMOVE_RELATIONSHIP', () => {
testScheduler.run(({ hot, expectObservable, flush }) => {
action = new RemoveRelationshipAction(leftItem, rightItem, relationshipType.leftwardType, '1234');
actions = hot('--a-|', { a: action });
expectObservable(relationEffects.mapLastActions$).toBe('--b-|', { b: undefined });
flush();
// TODO check following expectations with the implementation
// expect((relationEffects as any).initialActionMap[identifier]).toBe(action.type);
// expect((relationEffects as any).debounceMap[identifier].value).toBe(action.type);
});
action = new RemoveRelationshipAction(leftItem, rightItem, relationshipType.leftwardType, '1234');
actions = hot('--a-|', { a: action });
const expected = cold('--b-|', { b: undefined });
expect(relationEffects.mapLastActions$).toBeObservable(expected);
expect((relationEffects as any).initialActionMap[identifier]).toBe(action.type);
expect((relationEffects as any).debounceMap[identifier].value).toBe(action.type);
});
});
@@ -238,20 +227,19 @@ describe('RelationshipEffects', () => {
let action;
const testActionType = 'TEST_TYPE';
beforeEach(() => {
((relationEffects as any).debounceTime as jasmine.Spy).and.returnValue((v) => v);
(relationEffects as any).initialActionMap[identifier] = testActionType;
(relationEffects as any).debounceMap[identifier] = new BehaviorSubject<string>(testActionType);
});
it('should set the current value debounceMap to REMOVE_RELATIONSHIP but not change the value of the initialActionMap', () => {
testScheduler.run(({ hot, expectObservable, flush }) => {
action = new RemoveRelationshipAction(leftItem, rightItem, relationshipType.leftwardType, '1234');
actions = hot('--a-|', { a: action });
expectObservable(relationEffects.mapLastActions$).toBe('--b-|', { b: undefined });
flush();
// TODO check following expectations with the implementation
// expect((relationEffects as any).initialActionMap[identifier]).toBe(testActionType);
// expect((relationEffects as any).debounceMap[identifier].value).toBe(action.type);
});
action = new RemoveRelationshipAction(leftItem, rightItem, relationshipType.leftwardType, '1234');
actions = hot('--a-|', { a: action });
const expected = cold('--b-|', { b: undefined });
expect(relationEffects.mapLastActions$).toBeObservable(expected);
expect((relationEffects as any).initialActionMap[identifier]).toBe(testActionType);
expect((relationEffects as any).debounceMap[identifier].value).toBe(action.type);
});
});
@@ -259,32 +247,28 @@ describe('RelationshipEffects', () => {
let action;
describe('When the last value in the debounceMap is also an REMOVE_RELATIONSHIP action', () => {
beforeEach(() => {
((relationEffects as any).debounceTime as jasmine.Spy).and.returnValue((v) => v);
(relationEffects as any).initialActionMap[identifier] = RelationshipActionTypes.REMOVE_RELATIONSHIP;
});
it('should call removeRelationship on the effect', () => {
testScheduler.run(({ hot, expectObservable, flush }) => {
action = new RemoveRelationshipAction(leftItem, rightItem, relationshipType.leftwardType, '1234');
actions = hot('a', { a: action });
expectObservable(relationEffects.mapLastActions$).toBe('b', { b: undefined });
flush();
expect((relationEffects as any).removeRelationship).toHaveBeenCalledWith(leftItem, rightItem, relationshipType.leftwardType, '1234',);
});
action = new RemoveRelationshipAction(leftItem, rightItem, relationshipType.leftwardType, '1234');
actions = hot('--a-|', { a: action });
const expected = cold('--b-|', { b: undefined });
expect(relationEffects.mapLastActions$).toBeObservable(expected);
expect((relationEffects as any).removeRelationship).toHaveBeenCalledWith(leftItem, rightItem, relationshipType.leftwardType, '1234',);
});
});
describe('When the last value in the debounceMap is instead a ADD_RELATIONSHIP action', () => {
it('should <b>not</b> call addRelationship or removeRelationship on the effect', () => {
testScheduler.run(({ hot, expectObservable, flush }) => {
const actionb = new RemoveRelationshipAction(leftItem, rightItem, relationshipType.leftwardType, '1234');
const actiona = new AddRelationshipAction(leftItem, rightItem, relationshipType.leftwardType, '1234');
actions = hot('--ab-|', { a: actiona, b: actionb });
expectObservable(relationEffects.mapLastActions$).toBe('--bb-|', { b: undefined });
flush();
expect((relationEffects as any).addRelationship).not.toHaveBeenCalled();
expect((relationEffects as any).removeRelationship).not.toHaveBeenCalled();
});
const actionb = new RemoveRelationshipAction(leftItem, rightItem, relationshipType.leftwardType, '1234');
const actiona = new AddRelationshipAction(leftItem, rightItem, relationshipType.leftwardType, '1234');
actions = hot('--ab-|', { a: actiona, b: actionb });
const expected = cold('--bb-|', { b: undefined });
expect(relationEffects.mapLastActions$).toBeObservable(expected);
expect((relationEffects as any).addRelationship).not.toHaveBeenCalled();
expect((relationEffects as any).removeRelationship).not.toHaveBeenCalled();
});
});
});

View File

@@ -1,11 +1,11 @@
import { Injectable } from '@angular/core';
import { Inject, Injectable } from '@angular/core';
import { Actions, Effect, ofType } from '@ngrx/effects';
import { debounceTime, filter, map, mergeMap, switchMap, take } from 'rxjs/operators';
import { filter, map, mergeMap, switchMap, take } from 'rxjs/operators';
import { BehaviorSubject, Observable } from 'rxjs';
import { RelationshipService } from '../../../../../core/data/relationship.service';
import {
getRemoteDataPayload,
getFirstSucceededRemoteData
getFirstSucceededRemoteData, DEBOUNCE_TIME_OPERATOR
} from '../../../../../core/shared/operators';
import {
AddRelationshipAction,
@@ -71,7 +71,7 @@ export class RelationshipEffects {
this.initialActionMap[identifier] = action.type;
this.debounceMap[identifier] = new BehaviorSubject<string>(action.type);
this.debounceMap[identifier].pipe(
debounceTime(DEBOUNCE_TIME),
this.debounceTime(DEBOUNCE_TIME),
take(1)
).subscribe(
(type) => {
@@ -159,6 +159,7 @@ export class RelationshipEffects {
private notificationsService: NotificationsService,
private translateService: TranslateService,
private selectableListService: SelectableListService,
@Inject(DEBOUNCE_TIME_OPERATOR) private debounceTime: <T>(dueTime: number) => (source: Observable<T>) => Observable<T>,
) {
}