在使用angular-dynamic-locale
的AngularJS应用程序中,我想在不同语言环境中测试Locale依赖的代码。
我试图在异步设置中更改语言环境。在以前的茉莉版本中,这是通过闩锁功能完成的。这些现在被弃用并用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
的内部表明,该语言环境更改已安排,但从未实际应用:
// This line runs
$rootScope.$applyAsync(function() {
// But this callback doesn't
storage[storagePut](storageKey, localeId);
$rootScope.$broadcast('$localeChangeSuccess', localeId, $locale);
deferred.resolve($locale);
});
我尝试调用 $browser.defer.flush
并消化/应用根范围,但是LOCALE更改回调仍未执行。
我该如何更改此测试套件中的语言环境?
plunker ,添加了 tmhDynamicLocale
中的日志。
似乎没有一种干净的方法,但是我找到了一个黑客的解决方法。
为什么承诺不安定下来
tmhDynamicLocale
通过<script>
元素加载语言环境文件。当此元素的load
事件发射时,它将安排$localeChangeSuccess
事件并承诺解决。
在生产中,这效果很好:
- 我的代码调用
tmhDynamicLocale.set('fr-fr')
- 创建了
<script>
元素 - 位置文件已加载;
load
FIRES - 在
load
事件回调中,安排新的回调是异步应用的 - 完成的重新测量事件也触发了角度消化循环
- 摘要周期运行计划的回调
- 此回调可以解决该语言环境变化承诺
在测试中,浏览器事件做不是触发摘要周期,因此发生了:
- 我的代码调用
tmhDynamicLocale.set('fr-fr')
- 创建了
<script>
元素 - 我的测试代码中的任何
$timeout
S在这里运行,带有空的$$applyAsyncQueue
- 位置文件已加载;
load
fires - 在
load
事件回调中,计划将新回调用于异步 - 我的代码未通知此;它无法触发新的回调,并且承诺永远依据
因此,触发承诺分辨率无法在角度消化周期内完成,或者至少我看不到如何。
解决方案
由于我们无法分辨何时安排回调,请进行轮询直到为止。与$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();
});
但是有很多缺点:
- 访问$$私人角度内部词不是一个好主意,并且很可能在版本之间打破。
- 不断冲洗可能会干扰其他异步设置。
- 如果由于某种原因没有清除间隔,它将在以后的测试中造成各种破坏。
plunker