13
votes

Using observable data services using the async pipe to update data directly in the view which is proving difficult to test (works fine normally).

I want to be able to update the view, fire click events and then test that the model has been updated (as a result of the click) correctly, but in the test the async pipe doesn't render anything when its bound observable triggers an event. So I can't interact with the DOM in the test and test the results of the interaction.

Can't find any examples of anyone doing unit tests with components specifically using async pipes so i'm at a loss. Any feedback appreciated.

Test:

it('Updates the availability model correctly after UI interaction.', done => {

    this.instance.morning$
        .subscribe(data => {

            let checkboxes = this.fixture.nativeElement.querySelectorAll('ion-checkbox');
            TestUtils.trigger(checkboxes[0], 'click');

            let morningModel = this.instance.model.morning;
            expect(morningModel[0].v).toEqual(true);

            done();

        });         

});

Template:

<td *ngFor="let day of morning$ | async">
    <ion-checkbox [(ngModel)]="day.v"></ion-checkbox>
</td>

Component:

@Component({
    templateUrl: 'build/modules/availability/availability.view.html',
    selector: 'availability',
    providers: [AvailabilitySvc],
    directives: [Checkbox]
})
export class AvailabilityCom {

    @Input() userId: string;
    public morning$: any;

    constructor(private svc: AvailabilitySvc) {     
        this.morning$ = svc.morning$;
        this.setEvents();
    }

    ngOnInit(){
        this.getAvailability();
    }

    getAvailability(){
        return this.svc.get(this.userId);
    }

};

Mock service. get() usually contains a call to the http provider, but in the mock I'm just calling next with the mock model on the mock subject and returning the observable.

let subjectMock = new BehaviorSubject(model);
let observableMock$ = subjectMock.asObservable();

export class ServiceMock{

    get(id:string):any {
        subjectMock.next(model)
        return observableMock$;
    }

    get morning$(){
        return observableMock$.map((model:any) => model.morning);
    }

}
1
Do you still need help with this question?AngularChef
@AngularFrance Hey man, no, the problem in the end was with ion-checkbox - it had nothing to do with the async pipe. ion-checkbox will not render within a unit test scenario - if i replace ion-checkbox with an input, everything works fine, but with ion-checkbox i just see the ng-bindings comment.user3388195

1 Answers

1
votes

Try to get the morningModel in the instance.morning$ subscribe .subscribe((morningModel: DoneFn) => like so :

it('Updates the availability model correctly after UI interaction.', done => {

    this.instance.morning$
        .subscribe((morningModel: DoneFn) => {

            let checkboxes = this.fixture.nativeElement.querySelectorAll('ion-checkbox');
            TestUtils.trigger(checkboxes[0], 'click');

            let morningModel = this.instance.model.morning;
            expect(morningModel[0].v).toEqual(true);

            done();

        });         

});