Кажется, нет чистого способа сделать это, но я нашел хакерский обходной путь.
Почему обещание не улаживается
tmhDynamicLocale
загружает файл локали через элемент <script>
.Когда срабатывает событие load
этого элемента, он планирует событие $localeChangeSuccess
и разрешение обещания.
В производстве это работает хорошо:
- Мой код вызывает
tmhDynamicLocale.set('fr-fr')
- Элемент
<script>
создан - Загружен файл локали;
load
срабатывает - В обратном вызове события
load
запланировано, что новый обратный вызов будет применен асинхронно - Событие завершенного запроса также запускает цикл углового дайджеста
- Цикл дайджеста запускает запланированный обратный вызов
- Этот обратный вызов разрешает обещание изменения локали
В тестах события браузера не запускают циклы дайджеста, поэтому это происходит:
- Мой код вызывает
tmhDynamicLocale.set('fr-fr')
- Создается
<script>
элемент - Любые
$timeout
s в моем тестовом коде выполняются здесь, с пустым $$applyAsyncQueue
- Файл локали загружен;
load
срабатывает - При обратном вызове события
load
планируется, что новый обратный вызов будет применен асинхронно - Мой код не уведомлен об этом;у него нет никакого способа вызвать новый обратный вызов, и обещание ожидает навсегда
Так что запуск разрешения обещания не может быть выполнен в цикле дайджеста Angular, или, по крайней мере, я не понимаю как.
Обходной путь
Поскольку мы не можем сказать, когда запланирован обратный вызов, проводите опрос, пока он не будет.В отличие от $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();
});
Но есть много недостатков:
- Доступ к $$ private внутренним внутренним элементам Angular не является хорошей идеей и, вероятно, приведет кперерыв между версиями.
- Постоянная очистка может помешать другим асинхронным установкам.
- Если по какой-то причине интервал не будет очищен, это повлечет за собой всевозможные разрушения в последующих тестах.
Плункер