Run ngrx/effect outside of Angular's zone to prevent timeout in Protractor

后端 未结 2 458
盖世英雄少女心
盖世英雄少女心 2021-02-01 09:53

I just started to write e2e tests for my app and am running into timeout problems with Protractor and ngrx/effects.

I have the following effect dispatching an action ev

2条回答
  •  生来不讨喜
    2021-02-01 10:34

    The solution is to schedule the timer observable to run outside of NgZone and then re-enter the zone when something interesting occurs.

    First you are going to need two utility functions that wrap any scheduler and cause the effect to enter or leave the zone:

    import { Subscription } from 'rxjs/Subscription';
    import { Scheduler } from 'rxjs/Scheduler';
    import { NgZone } from '@angular/core';
    
    
    class LeaveZoneSchduler {
      constructor(private zone: NgZone, private scheduler: Scheduler) { }
    
      schedule(...args: any[]): Subscription {
        return this.zone.runOutsideAngular(() => 
            this.scheduler.schedule.apply(this.scheduler, args)
        );
      }
    }
    
    class EnterZoneScheduler {
      constructor(private zone: NgZone, private scheduler: Scheduler) { }
    
      schedule(...args: any[]): Subscription {
        return this.zone.run(() => 
            this.scheduler.schedule.apply(this.scheduler, args)
        );
      }
    }
    
    export function leaveZone(zone: NgZone, scheduler: Scheduler): Scheduler {
      return new LeaveZoneSchduler(zone, scheduler) as any;
    }
    
    export function enterZone(zone: NgZone, scheduler: Scheduler): Scheduler {
      return new EnterZoneScheduler(zone, scheduler) as any;
    }
    

    Then using a scheduler (like asap or async) you can cause a stream to enter or leave the zone:

    import { async } from 'rxjs/scheduler/async';
    import { enterZone, leaveZone } from './util';
    
    actions$.ofType('[Light] Turn On')
        .bufferTime(300, leaveZone(this.ngZone, async))
        .filter(messages => messages.length > 0)
        .observeOn(enterZone(this.ngZone, async))
    

    Note that most of the time-based operators (like bufferTime, debounceTime, Observable.timer, etc) already accept an alternative scheduler. You only need observeOn to re-enter the zone when something interesting happens.

提交回复
热议问题