angular - 在 Angular 区域之外运行 ngrx/effect 以防止 Protractor 超时

标签 angular protractor ngrx ngrx-effects zone.js

我刚开始为我的应用程序编写端到端测试,但遇到了 Protractor 和 ngrx/effects 的超时问题。

我每两分钟调度一个 Action 有以下效果:

@Effect() setSessionTimer$ = this.actions$
        .ofType(Auth.ActionTypes.SET_SECONDS_LEFT)
        .map(toPayload)
        .switchMap(secondsLeft => Observable.concat(
            Observable.timer((secondsLeft - 60) * 1000).map(_ => new Auth.SessionExpiringAction(60)),
            Observable.timer(60 * 1000).map(_ => new Auth.SessionExpiredAction())
        ));

尝试运行 Protractor 测试会导致测试超时并出现以下错误,因为 Angular 不稳定。

Failed: Timed out waiting for asynchronous Angular tasks to finish after 11 seconds. This may be because the current page is not an Angular application. Please see the FAQ for more details: https://github.com/angular/protractor/blob/master/docs/timeouts.md#waiting-for-angular While waiting for element with locator - Locator: By(css selector, .toolbar-title)

根据这个问题(https://github.com/angular/protractor/issues/3349),我需要使用 NgZone 在 Angular 之外运行一个间隔 Observable。我尝试了 this.ngZone.runOutsideAngular() 的不同组合,但没有任何效果,而且测试一直超时。

例如这不起作用:

@Effect() setSessionTimer$ = this.actions$
        .ofType(Auth.ActionTypes.SET_SECONDS_LEFT)
        .map(toPayload)
        .switchMap(secondsLeft => this.ngZone.runOutsideAngular(() => Observable.concat(
            Observable.timer((secondsLeft - 60) * 1000).map(_ => new Auth.SessionExpiringAction(60)),
            Observable.timer(60 * 1000).map(_ => new Auth.SessionExpiredAction())
        )));

我不知道如何在 Angular 之外运行效果。 有人成功地进行了 e2e 测试他们的 ngrx 应用程序吗?

最佳答案

解决方案是安排计时器可观察到在 NgZone 之外运行,然后在发生有趣的事情时重新进入该区域。

首先,您需要两个实用函数来包装任何调度程序并使效果进入或离开区域:

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;
}

然后使用调度程序(如 asapasync),您可以使流进入或离开区域:

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))

请注意,大多数基于时间的运算符(如 bufferTimedebounceTimeObservable.timer 等)已经接受了替代调度程序.当发生有趣的事情时,您只需要 observeOn 重新进入该区域。

关于angular - 在 Angular 区域之外运行 ngrx/effect 以防止 Protractor 超时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43121400/

相关文章:

javascript - 在 ionic 2/3 中获取相同模态的多个实例

node.js - Electron 命令失败: npm prune --production

Angular 4 - 如何在按下后退按钮时路由到特定组件?

node.js - 调试proctor(带/不带webstorm)

Material 表单元格中的 Angular 显示图像

javascript - Protractor - 如何打开 x 数量的网站并发送 key

javascript - 如何创建一维和二维数组以及如何在 Protractor 中初始化具有特定数组大小的数组?

angular - 将 max 与选择器一起使用

angular - 当 URL 的查询参数发生更改时,如何调度 NGRX 操作?

angular - 升级@ngrx/Store 时,类型 'payload' 上不存在属性 'Action'