mardi 4 juillet 2017

How to test features depending on Observable variables in Angular components?

While developing Angular component I've challenged situation where I have to test feature which depending on Observable variable.

In my component I've got selectedLanguage$ private property.

private readonly selectedLanguage$: Observable<string>;

In a constructor I'm binding its value to Redux store.

this.selectedLanguage$ = ngRedux.select<string>('language');

On initialization I'm setting default value

this.changeLanguage('en');

changeLanguage(language: string): void {
    this.ngRedux.dispatch(this.actions.setLanguage(language));
}

In my test suit I've mocked NgRedux with NgReduxTestingModule.

Now I want to assert that after initialization component has corresponding flag in template marked. It depends on returned value from function which uses subscribe method of this variable.

isLanguageSelected(lang: string): boolean {
    let currentlySelected;
    this.subscription.add(this.selectedLanguage$.subscribe(selected => 
        currentlySelected = selected));
    return currentlySelected == lang;
}

Template:

<div class="lang-flag en-flag" [ngClass]="{ 'lang-flag-selected': isLanguageSelected('en') }"></div>

In my test suite I'm using ComponentFixtureAutoDetect - that's why I wonder why change detection process is not firing automatically.

Here is my test suite:

it('should select english flag after initializing', fakeAsync(() => {
    fixture.detectChanges();
    let flagElement = debugElement.query(By.css('.en-flag'));
    expect(flagElement.nativeElement.classList).toContain('.lang-flag-selected');
}));

Any advise?

EDIT:

One solution I've found is to set variable manually in a test body as follow:

component.selectedLanguage$ = Observable.of("en");

But it breaks encapsulation - to do so I have to erase readonly and private modifiers. What I'd like to achieve is to get selector with specified class as a result of initialization of component.

EDIT 2:

Because it's fakeAsync, I also tried tick() and second changeDetection, but it still does not work as expected.

it('should select english as default language after initializing', fakeAsync(() => {
    //component.selectedLanguage$ = Observable.of("en");
    fixture.detectChanges();
    tick();
    fixture.detectChanges();
    let flagElement = debugElement.query(By.css('.en-flag'));
    expect(flagElement.nativeElement.classList).toContain('lang-flag-selected');
}));

Aucun commentaire:

Enregistrer un commentaire