使用NGRX存储测试异步Angular验证器

时间:2019-06-26 00:25:31

标签: javascript angular rxjs ngrx

我有一个用于反应形式的异步验证器,该反应器在模糊时调度一个动作。此操作将触发一个效果,该效果将按摩来自服务的某些数据。

在验证器中,我使用选择器来监听商店,并使用rxjs运算符以所需的形式获取数据。这运作良好。但是,我一直在此功能的测试范围内。为什么我的测试不能涵盖整个操作?

用户名验证器

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}),
      )
    }
}

用户名验证器规范

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 个答案:

答案 0 :(得分:1)

您将返回一个在测试中从未订阅的可观察对象。订阅

中的逻辑是订阅返回的observable的行为。
.pipe(
    take(2),
    tap((val) => console.log(val)),
    filter(isUnique => isUnique !== undefined),
    map(isUnique => isUnique ? null : {usernameIsNotUnique: true}),
 )

您需要测试返回的observable的发射值。

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运算符一样。 / p>