Непонятная ошибка эффектов модульного тестирования с использованием Jest - PullRequest
3 голосов
/ 19 июня 2019

Я работаю над двумя почти идентичными тестовыми случаями, где я должен утверждать, что два эффекта NgRx возвращают поток логических значений.В первом тестовом примере все работает, как и ожидалось, и, хотя для второго тестового примера то же самое, я не могу заставить его работать так, как ожидалось.Что бы я ни делал, полученное значение всегда является пустым массивом:

expect(received).toEqual(expected) // deep equality
    - Expected
    + Received

    - Array [
    -   Object {
    -     "frame": 10,
    -     "notification": Notification {
    -       "error": undefined,
    -       "hasValue": true,
    -       "kind": "N",
    -       "value": true,
    -     },
    -   },
    - ]
    + Array []

Рабочий тест

logger.effects.spec.ts:

describe('LoggerEffects', () => {
    let actions$: Observable<ApiFailure>;
    let effects: LoggerEffects;
    const serviceMock = <AppLoggerServiceI>{ failure: ({ body, title }) => of(true) };
    beforeEach(() => {
        TestBed.configureTestingModule({
            imports: [StoreModule.forRoot({})],
            providers: [
                LoggerEffects,
                provideMockActions(() => actions$),
                {
                    provide: 'appLoggerService',
                    useValue: serviceMock
                }
            ]
        });
        effects = TestBed.get(LoggerEffects);
    });
    const failure = new HttpErrorResponse({ error: 'HttpErrorResponse' });
    describe('logApiFailure$', () => {
        it('should return a stream of boolean if the dispatched action is ApiActions.searchFailure', () => {
            const action = ApiActions.searchFailure({ failure });
            actions$ = hot('-a--', { a: action });
            const expected = cold('-b--', { b: true });
            expect(effects.logApiFailure$).toBeObservable(expected);
        });
    });
});

logger.effects.ts:

logApiFailure$ = createEffect(
        () =>
            this.actions$.pipe(
                ofType(ApiActions.searchFailure),
                exhaustMap(({ failure: { body, title } }) =>
                    this.appLoggerService.failure({
                        body,
                        title
                    })
                )
            ),
        { dispatch: false }
    );

Неудачный тест

router.effects.spec.ts:

describe('RouterEffects', () => {
    let actions$: Observable<boolean>;
    let effects: RouterEffects;

    const routerMock = <Partial<Router>>{ navigate: (commands: any[]) => Promise.resolve(true) };

    let router: Router;
    beforeEach(() => {
        TestBed.configureTestingModule({
            imports: [StoreModule.forRoot({})],
            providers: [
                RouterEffects,
                provideMockActions(() => actions$),
                {
                    provide: Router,
                    useValue: routerMock
                }
            ]
        });
        effects = TestBed.get(RouterEffects);
    });
    describe('navigateTo$', () => {
        it('should return a stream of boolean if the dispatched action is RouterActions.navigateTo', () => {
            const action = RouterActions.navigateTo();
            actions$ = hot('-a--', { a: action });
            const expected = cold('-b--', { b: true });
            console.log('toto', effects.navigateTo$);
            expect(effects.navigateTo$).toBeObservable(expected);
        });
    });
});

router.effects.ts:

navigateTo$ = createEffect(
    () =>
        this.actions$.pipe(
            ofType(RouterActions.navigateTo),
            exhaustMap(() => this.router.navigate(['my-route', {}]))
        ),
    { dispatch: false }
);

На данный момент, я предполагаю, что что-то не так с Hot Observable в router.effects.spec.ts, которыйпредотвращает эффект отправки действия navigateTo.Есть ли у вас мысли по этому поводу?

Зависимости проекта

{
    "dependencies": {
        "@angular/animations": "^8.0.0",
        "@angular/cdk": "^8.0.0",
        "@angular/common": "^8.0.0",
        "@angular/compiler": "^8.0.0",
        "@angular/core": "^8.0.0",
        "@angular/forms": "^8.0.0",
        "@angular/material": "^8.0.0",
        "@angular/material-moment-adapter": "^8.0.0",
        "@angular/platform-browser": "^8.0.0",
        "@angular/platform-browser-dynamic": "^8.0.0",
        "@angular/router": "^8.0.0",
        "@ngrx/effects": "^8.0.0",
        "@ngrx/router-store": "^8.0.0",
        "@ngrx/store": "^8.0.0",
        "core-js": "^2.5.4",
        "hammerjs": "^2.0.8",
        "moment": "^2.24.0",
        "rxjs": "^6.5.0",
        "tslib": "^1.9.0",
        "zone.js": "^0.9.1"
    },
    "devDependencies": {
        "jest-preset-angular": "7.0.0",
        "@angular-devkit/build-angular": "^0.800.0",
        "@angular-devkit/build-ng-packagr": "~0.800.0",
        "@angular-devkit/core": "^8.0.2",
        "@angular-devkit/schematics": "^8.0.2",
        "@angular/cli": "8.0.0",
        "@angular/compiler-cli": "^8.0.0",
        "@angular/language-service": "^8.0.0",
        "@ngrx/schematics": "^8.0.0",
        "@ngrx/store-devtools": "^8.0.0",
        "@nrwl/cypress": "8.1.0",
        "@nrwl/jest": "8.1.0",
        "@nrwl/workspace": "8.1.0",
        "@nrwl/schematics": "8.1.0",
        "@types/jest": "24.0.9",
        "@types/node": "^12.0.7",
        "codelyzer": "~5.0.1",
        "cypress": "~3.3.1",
        "dotenv": "6.2.0",
        "jest": "24.1.0",
        "ng-packagr": "^5.1.0",
        "prettier": "1.16.4",
        "ts-jest": "24.0.0",
        "ts-node": "^8.2.0",
        "tsickle": "^0.35.0",
        "tslib": "^1.9.0",
        "tslint": "~5.11.0",
        "typescript": "~3.4.5"
    }
}

1 Ответ

0 голосов
/ 10 июля 2019

Я просто потратил некоторое время на отслеживание аналогичной проблемы (пустой ожидаемый массив), и проблема оказалась связана с асинхронным кодом, который не управлялся TestScheduler.В моем случае я использовал from([Promise]).Чтобы устранить проблему, я высмеял функцию, возвращающую обещание вернуть наблюдаемое of().

. Эта проблема мне очень помогла и ясно объясняет проблему: https://github.com/cartant/rxjs-marbles/issues/11

Вв вашем случае, я полагаю, что проблема вызвана this.router.navigate(['my-route', {}]), который возвращает обещание, а не наблюдаемое.

Попробуйте издеваться router.navigate, чтобы вернуть of(true).

...