Тестирование пользовательских труб RXJS - PullRequest
0 голосов
/ 25 июня 2019

У меня есть пользовательский канал, который представляет собой набор из нескольких каналов. Я, однако, хотел бы проверить код.

export type AnnotatedResponse<T> = T & {
    awaitingNewValues: boolean;
    failed: boolean;
};

function merge<T>(
    original: T,
    awaitingNewValues: boolean,
    failed: boolean,
): AnnotatedResponse<T> {
    return Object.assign({},
        original,
        { awaitingNewValues, failed },
    );
}

export function annotateAwaiting<I, T extends {}>(
    initialValue: T,
    toAnnotate: (input: I) => Observable<T>,
): (source: Observable<I>) => Observable<AnnotatedResponse<T>> {
    return (source: Observable<I>) => {
        let lastValue: T = initialValue;
        return source.pipe(
            switchMap(input => concat(
                of(merge(lastValue, true, false)),
                toAnnotate(input).pipe(
                    take(1),
                    map(result => {
                        lastValue = result;
                        return merge(result, false, false);
                    }),
                    catchError(() => {
                        return of(merge(lastValue, false, true));
                    }),
                ),
            )),
            finalize(() => {
                //  Free reference to prevent memory leaks
                lastValue = undefined as any;
            }),
        );
    };
}

Тест

fdescribe('annotateAwaiting$', () => {
    let subject: Subject<string>;
    let annotated: Observable<AnnotatedResponse<{ letter: string }>>;
    let response: Subject<Error | { letter: string }>;

    beforeEach(() => {
        subject = new Subject<string>();
        response = new Subject();
        annotated = subject.pipe(
            annotateAwaiting(
                { letter: '' },
                letter => response.pipe(
                    take(1),
                    map(val => {
                        if (val instanceof Error) {
                            throw val;
                        } else {
                            return val;
                        }
                    }),
                ),
            ),
            shareReplay(1),
        );
    });

    afterEach(() => {
        subject.complete();
        response.complete();
    });

    it('should emit immediately', () => {
        let i = 0;
        subject.next('a');
        annotated.pipe(
            take(1),
        ).subscribe(obj => {    //  Runs
            expect(obj.awaitingNewValues).toBe(true);
            expect(obj.failed).toBe(false);
            expect(obj.letter).toBe('');
            i++;
        });

        expect(i).toBe(1);

        response.next({ letter: 'a'});
        annotated.pipe(
            take(1),
        ).subscribe(obj => {    //  Doesn't run (neither async)
            expect(obj.awaitingNewValues).toBe(false);
            expect(obj.failed).toBe(false);
            expect(obj.letter).toBe('a');
            i++;
        });

        expect(i).toBe(2);
    });
});

Чего мне не хватает? Почему он вообще не работает?

1 Ответ

0 голосов
/ 26 июня 2019

В этот раз это было не так сложно, просто случай с ошибочной логикой.

it('should emit immediately', () => {
    let i = 0;

    annotated.pipe(
        // Adding this skip makes sure that it does not subscribes early
        skipWhile(r => !r.awaitingNewValues),
        take(1),
    ).subscribe(obj => {  // Runs
        expect(obj.awaitingNewValues).toBe(true);
        expect(obj.failed).toBe(false);
        expect(obj.letter).toBe('');

        i++;
    });
    subject.next('a');
    expect(i).toBe(1);

    annotated.pipe(
        // Same here...
        skipWhile(r => r.awaitingNewValues),
        take(1),
    ).subscribe(obj => {
        expect(obj.awaitingNewValues).toBe(false);
        expect(obj.failed).toBe(false);
        expect(obj.letter).toBe('a');

        i++;
    });
    response.next({ letter: 'a'});
    expect(i).toBe(2);
});
...