codephobia
codephobia

Reputation: 1590

Unit testing - getting TypeError: You provided an invalid object where a stream was expected

I'm trying to do a unit test where an effect uses a service to fetch results from an API, then fires either a success action, or an error action. I keep getting the error TypeError: You provided an invalid object where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.. Not entirely sure what needs to be changed to get this working.

Including the error check test and relevant code.

Angular

Angular CLI: 7.1.4
Node: 10.5.0
OS: win32 x64
Angular: 7.1.4
... animations, cli, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.10.7
@angular-devkit/build-angular     0.10.7
@angular-devkit/build-optimizer   0.10.7
@angular-devkit/build-webpack     0.10.7
@angular-devkit/core              7.0.7
@angular-devkit/schematics        7.1.4
@angular/cdk                      7.2.0
@angular/material                 7.2.0
@ngtools/webpack                  7.0.7
@schematics/angular               7.1.4
@schematics/update                0.11.4
rxjs                              6.3.3
typescript                        3.1.6
webpack                           4.19.1

Test

describe('ResultsEffects', () => {
    let store: jasmine.SpyObj<Store<FeatureState>>;
    let ebs: jasmine.SpyObj<EBSService>;
    let snackbar: jasmine.SpyObj<SnackBarService>;

    beforeEach(() => {
        store = jasmine.createSpyObj('store', ['pipe']);
        ebs = jasmine.createSpyObj('EBSService', ['getPollResults', 'getUserHasVoted', 'getSettings']);
        snackbar = jasmine.createSpyObj('SnackBarService', ['notify']);
    });

    describe('fetchResults', () => {
        it(`should dispatch 'FetchPanelResultsError'`, () => {
            const fetchAction = new FetchPanelResults();
            const error = { statusText: 'ERROR' };
            const errorAction = new FetchPanelResultsError({ error: error.statusText });
            const values = {
                a: fetchAction,
                e: errorAction
            };
            const source = cold('a', values);
            const expected = cold('--e', values);
            const actions = new Actions(source);

            ebs.getPollResults.and.returnValue(throwError(error));

            const effects = new ResultsEffects(
                actions,
                store,
                snackbar,
                ebs
            );

            expect(
                effects.fetchResults$({
                    debounce: 20,
                    scheduler: getTestScheduler()
                })
            ).toBeObservable(expected);
        });
    });
});

Effect

@Effect()
fetchResults$ = ({ debounce = 500, scheduler = asyncScheduler } = {}) => this.actions$.pipe(
    ofType<SetPanelResults>(PanelResultsActionTypes.FETCH_PANEL_RESULTS),
    // need alternate method for this
    // withLatestFrom(this.featureState$),
    // map(([_, state]) => state.twitch.token),
    debounceTime(debounce, scheduler),
    switchMap((token) =>
        this.ebs.getPollResults(token).pipe(
            map(res => new SetPanelResults(res.data.results)),
            catchError(error => of(new FetchPanelResultsError({ error: error.statusText })))
        )
    )
)

Service

getPollResults(token: string): Observable<PollResultsFetchData> {
    const options = {
        headers: ebsHeaders(token)
    };

    return this.http.get<PollResultsFetchData>(`${this.ebsURL}/poll/results`, options);
}

Update: Added debounce to trigger the error with marbles. Still need alternative to withLatestFrom.

Upvotes: 2

Views: 2838

Answers (2)

Ameba Brain
Ameba Brain

Reputation: 343

For me that error started to happen regularly for a couple of months (Angular 7) on Live Reload during development. I was fixing it just by re-opening browser with a few seconds pause.

Today re-opening didn't help and I occasionally figured out, that re-saving one of source file (even without actually changing it) helps out and error dissapears. Re-saving triggers project in-memory build recompilation by webpack and live reload

Upvotes: 0

timdeschryver
timdeschryver

Reputation: 15505

Based on the comments:

The problem is that withLatest from isn't really returning anything because you don't have a feature state. This is because you mock out the store with jasmine.createSpyObj('store', ['pipe']).

To solve this use the "real" ngrx store or use the mock store, which was implemented in NgRx 7.

Upvotes: 1

Related Questions