Тестирование асинхронных угловых валидаторов с хранилищем NGRX - PullRequest
0 голосов
/ 26 июня 2019

У меня есть асинхронный валидатор для реактивной формы, который при размытии отправляет действие.Это действие вызывает эффект, который массирует некоторые данные, поступающие из службы.

В валидаторе я использую селектор для прослушивания в хранилище и использую операторы rxjs для получения данных в форме Iнеобходимость.Это работает хорошо.Тем не менее, я застрял в покрытии тестирования для этой функции.Почему мой тест не охватывает всю операцию?

Проверка имени пользователя

export const UniqueUsernameValidator = (store) => {
   return (control: any): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
    console.log(store)
    store.dispatch(new CheckUsername(control.value));
      return store.pipe(select(selectUsernameIsUnique)).pipe(
        take(2),
        tap((val) => console.log(val)),
        filter(isUnique => isUnique !== undefined),
        map(isUnique => isUnique ? null : {usernameIsNotUnique: true}),
      )
    }
}

Проверка имени пользователя Spec

describe('UniqueUsernameValidator', () => {
    const storeMock = {
        dispatch() {
            return true
        },
        pipe() {
            return of(true);
        }
      };
    let control = {
        value: 'abc123'
    }
    it('should dispatch an action of CheckUsername', () => {
        UniqueUsernameValidator(storeMock)(control.value)
    })
})

И это текущее покрытие: enter image description here

TLDR: Почему оно пропускает это покрытие, и является ли это правильным подходом для насмешки над магазином?

1 Ответ

1 голос
/ 26 июня 2019

Вы возвращаете наблюдаемое, на которое никогда не подписывается ваш тест. Акт подписки на возвращаемое наблюдаемое запускает логику в

.pipe(
    take(2),
    tap((val) => console.log(val)),
    filter(isUnique => isUnique !== undefined),
    map(isUnique => isUnique ? null : {usernameIsNotUnique: true}),
 )

Вам необходимо проверить выбранное значение из возвращаемой наблюдаемой.

let validationResult;
const sub = UniqueUsernameValidator(storeMock)(control.value).subscribe(result => {
  validationResult = result;
});
sub.unsubscribe();
expect(validationResult.usernameIsNotUnique).toEqual(true);

Если вы знаете, что наблюдаемая была создана из вас, вы можете развернуть ее таким образом, но если наблюдаемая была асинхронной, вам нужно будет выполнить асинхронный тест.

Я использую эту вспомогательную функцию для асинхронного тестирования наблюдаемых.

import { Observable, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

export async function firstEmitted<T>(obs$: Observable<T>): Promise<T> {
    return new Promise<T>(resolve => {
        const finalise = new Subject<void>();
        obs$.pipe(takeUntil(finalise)).subscribe(value => {
            finalise.next();
            resolve(value);
        });
    });
}

и используйте его как

it('should dispatch an action of CheckUsername', async(async () => {
  const validationResult = await firstEmitted(UniqueUsernameValidator(storeMock)(control.value));
  expect(validationResult.usernameIsNotUnique).toEqual(true);
}));

The

async(async () =>

смущает некоторых людей, но первая асинхронная функция - это асинхронная функция из модуля углового тестирования, утверждающая, что тестовая функция является функцией anync, а вторая помечает функцию как асинхронную, поскольку мы используем в ней оператор await.

...