如何在AngularJS测试中应用动态语言环境更改?

时间:2019-02-14 22:05:39

标签: javascript angularjs jasmine karma-jasmine

在使用angular-dynamic-locale的AngularJS应用程序中,我想在不同的语言环境中测试与语言环境相关的代码。

我正在尝试在异步设置中更改语言环境。在以前的Jasmine版本中,它是done with a latch function;现在已弃用这些参数,并用done回调代替。

beforeEach(function (done) {
  inject(function ($injector) {
    tmhDynamicLocale = $injector.get('tmhDynamicLocale');

    console.log('setting locale to French...');
    tmhDynamicLocale
      .set('fr-fr')
      .then(function () {
        console.log('locale set.');
        done();
      })
      .catch(function (err) {
        done.fail('failed to set locale:', err);
      });
  });
});

tmhDynamicLocale.set返回的诺言永远待定,并且设置超时。

查看tmhDynamicLocale的{​​{3}},表明已计划区域设置,但从未实际应用过:

// This line runs
$rootScope.$applyAsync(function() {
  // But this callback doesn't
  storage[storagePut](storageKey, localeId);
  $rootScope.$broadcast('$localeChangeSuccess', localeId, $locale);
  deferred.resolve($locale);
});

我已经尝试过innards并消化/应用了根作用域,但是语言环境更改回调仍未执行。

如何在此测试套件中更改语言环境?

calling $browser.defer.flush,并添加了tmhDynamicLocale登录以保持清晰。

1 个答案:

答案 0 :(得分:0)

似乎没有一种干净的方法,但是我发现了一种骇人的解决方法。

为什么诺言没有兑现

tmhDynamicLocale loads the locale file通过<script>元素。当此元素的load事件触发时,它会schedules $localeChangeSuccess事件并承诺解决。

在生产中,这很好用:

  1. 我的代码调用tmhDynamicLocale.set('fr-fr')
  2. <script>元素已创建
  3. 语言环境文件已加载; load起火
  4. load事件回调中,计划以异步方式应用新的回调
  5. completed-request事件还会触发Angular摘要周期
  6. 摘要周期运行计划的回调
  7. 此回调可解决语言环境更改承诺

在测试中,浏览器事件不会触发摘要周期,因此发生这种情况:

  1. 我的代码调用tmhDynamicLocale.set('fr-fr')
  2. <script>元素已创建
  3. 我的测试代码中的任何$timeout都在此处运行,其中有一个空的$$applyAsyncQueue
  4. 语言环境文件已加载; load起火
  5. load事件回调中,计划以异步方式应用新的回调
  6. 我的代码未收到通知;它无法触发新的回调,并且承诺永远存在

因此,无法在Angular摘要周期内完成promise解析的触发,或者至少我不知道如何实现。

解决方法

由于我们无法确定回调的调度时间,因此请轮询直到调度调度。与$interval不同,setInterval在测试中并未被模拟出来,并允许进行真正的轮询。

安排了回调后,$browser.defer.flush将运行该回调并触发承诺解析。如果没有要刷新的延迟任务,则抛出该异常,因此仅当队列为非空时才调用它。

_forceFlushInterval = setInterval(function () {
  if ($rootScope.$$applyAsyncQueue.length > 0) {
    $browser.defer.flush();
  }
});

可以想象,可以安排除语言环境更改之外的其他任务。因此,我们会继续进行轮询,直到兑现诺言为止。

tmhDynamicLocale.set('fr-fr')
  .then(function () {
    clearInterval(_forceFlushInterval);
    done();
  })
  .catch(function () {
    clearInterval(_forceFlushInterval);
    done.fail();
  });

但是有很多缺点:

  1. 访问$$$ private Angular内部结构不是一个好主意,并且可能会在版本之间中断。
  2. 不断刷新可能会干扰其他异步设置。
  3. 如果由于某种原因而无法清除间隔,它将在以后的测试中造成各种破坏。

Plunker