Модульный тест ember-cli — контроллер открывает модальный бутстрап

Пытаюсь написать модульный тест для моего контроллера Ember. Он просто изменяет свойство, а затем открывает модальное окно начальной загрузки. Возникли трудности с выяснением того, как проверить, что модальное окно действительно открывается. Не уверен, что это вообще относится к модульному тесту или интеграционному тесту. Если его нет в моем модульном тесте, кажется, что позже будет сложно определить покрытие кода. Версия начальной загрузки: 3.3.1, версия ember-cli 0.1.5, узел 0.10.33. Вот что я пробовал безрезультатно:

1.

test('loginClick() opens modal', function(){
  var controller = this.subject();
  $('#login-modal').on('show.bs.modal', function(){
    equal(true, true, "the show.bs.modal event fired");
  });

  controller.send('loginClick', 'anything');
});

нет ошибки утверждения

2.

test('loginClick() opens modal', function(){
  var controller = this.subject();
  andThen(function(){
    controller.send('loginClick', 'anything');
    stop();

    Ember.run.later(function(){
        start();
        equal($('#login-modal').hasClass('in'), true, "has the 'in' class");
    }, 500);
  });
});

andThen не определено

Вот контроллер:

loginClick: function(param){
  this.set('provider', param);//facebook or google

  $('#login-modal')
    .modal();
}

Любые другие предложения или лучшие практики о том, как тестировать такие вещи, будут оценены.

p.s. Также попытался добавить это перед щелчком:

$.support.transition = false;

по чьему-то предложению, но это не отключает модальный переход.


person carter    schedule 15.01.2015    source источник
comment
Какую версию бутстрапа вы используете?   -  person slindberg    schedule 16.01.2015
comment
С каким тестом вы пробовали $.support.transition = false? При первоначальной проверке он должен работать с первым. Я бы просто установил его в вашем файле tests/test-helper.js, чтобы отключить его для всех виджетов начальной загрузки. Кроме того, andThen определяется только после вызова app.injectTestHelpers(), что обычно делается в помощнике startApp (что делается при написании интеграционных/приемочных тестов).   -  person slindberg    schedule 16.01.2015


Ответы (2)


У меня такая же проблема. Я не уверен, что это лучшее решение, но я решил его, зарегистрировав асинхронный тестовый помощник перед вызовом App.injectTestHelpers():

Ember.Test.registerAsyncHelper 'waitForModalOpen', (app, modal) ->
  # If using QUnit < 1.16, you need to add stop().
  #stop()
  Ember.Test.promise (resolve, reject) ->
    modal.on 'shown.bs.modal', ->
      resolve()
      # If using QUnit < 1.16, you need to add start().
      #start()

Затем я вызываю его после нажатия кнопки и перед утверждениями:

modal = find '#testModal'
click '#openModal'
waitForModalOpen modal
andThen ->
  strictEqual modal.attr('aria-hidden'), 'false', 'modal should be visible'
  strictEqual modal.hasClass('in'), true, 'modal should have .in class'

Вот тестовый пример JS Bin. QUnit 1.16 поддерживает возврат промисов из тестов, поэтому в этой версии вызовы stop() и start() больше не нужны: QUnit будет ждать разрешения промиса andThen().

Изменить: использовать в ember-cli

В документации ember-cli есть раздел о написании собственных тестовых помощников.

Создайте помощника как /tests/helpers/wait-for-modal-open.js:

import Ember from "ember";

export default Ember.Test.registerAsyncHelper('waitForModalOpen', function(app, modal) {
  return Ember.Test.promise(function(resolve, reject) {
    return modal.on('shown.bs.modal', function() {
      return resolve();
    });
  });
});

Затем добавьте эту строку в /tests/helpers/start-app.js:

import waitForModalOpen from './wait-for-modal-open';

Вы также должны добавить "waitForModalOpen" в массив "predef" в /tests/.jshintrc, чтобы избежать ошибок JSHint.

Наконец, создайте тест в виде файла в /tests/integration:

import Ember from "ember";
import { test } from 'ember-qunit';
import startApp from '../helpers/start-app';
var App;

module('Bootstrap Modal Open', {
  setup: function() {
    App = startApp();
    return visit('/');
  },
  teardown: function() {
    Ember.run(App, App.destroy);
  }
});

test('clicking the button should open a modal', function() {
  var modal;
  modal = find('#testModal');
  click('#openModal');
  waitForModalOpen(modal);
  return andThen(function() {
    strictEqual(modal.attr('aria-hidden'), 'false', 'modal should be visible');
    return strictEqual(modal.hasClass('in'), true, 'modal should have .in class');
  });
});
person Hugues De Keyzer    schedule 02.02.2015
comment
Спасибо. После того, как я конвертирую его в javascript, я посмотрю, работает ли он. Я полагаю, что смогу найти решение js, посмотрев на решение coffeescript. - person carter; 02.02.2015
comment
Я нашел конвертер сценария кофе в js, но не могу понять, как получить помощника, доступного в моем тесте. Отстойно, что вся документация НЕ относится к ember-cli. - person carter; 03.02.2015
comment
К вашему сведению: в файле start-app.js при добавлении комментария непосредственно в конец оператора импорта без пробела возникает ошибка. например import waitForModalOpen from './wait-for-modal-open';//my comment вызовет ошибку, а import waitForModalOpen from './wait-for-modal-open'; //my comment в порядке. - person carter; 03.02.2015
comment
Единственная проблема, которую я вижу, заключается в том, что после этого вы ничего не можете запустить. например Теперь заполните форму входа и отправьте ее, чтобы увидеть, правильно ли перенаправляется страница. - person carter; 03.02.2015
comment
Вы, вероятно, захотите, чтобы тест дождался закрытия модального окна (при условии, что вы закроете его при отправке формы). Для этого вам нужен еще один асинхронный помощник. Это то же самое, что и waitForModalOpen(), но вместо этого используется событие hidden.bs.modal. - person Hugues De Keyzer; 05.02.2015
comment
Что касается документации, Эрик Брин говорит в своем выступлении о Ember 1.10, что вся документация будет скоро будет обновлен для Ember CLI. - person Hugues De Keyzer; 06.02.2015
comment
У меня странная ошибка, Uncaught Error: Called stop() outside of a test context есть подсказка? - person Fed03; 06.02.2015
comment
@ Fed03: Вероятно, это связано с тем, что выполнение тестовой функции уже завершено, и какой-то код вызывает stop(). Какую версию QUnit вы используете? Только QUnit ›= 1.16 поддерживает возврат промисов из тестов. Код должен работать с более ранними версиями путем добавления вызовов stop() и start(). Кроме того, обязательно используйте Ember.Test.promise(), а не new Ember.RSVP.Promise() или new Promise(), так как они не будут должным образом связаны с click() и andThen(). - person Hugues De Keyzer; 07.02.2015
comment
@HuguesDeKeyzer У меня последняя версия ember-cli, поэтому я использую qunit ›= 1.* - person Fed03; 08.02.2015
comment
@ Fed03: Вы вручную добавили вызов stop ()? Не могли бы вы предоставить JSBin, воспроизводящий эту ошибку? Пожалуйста, опубликуйте новый вопрос об этом, чтобы другим пользователям с такой же проблемой было легче его найти. - person Hugues De Keyzer; 09.02.2015
comment
@HuguesDeKeyzer уверен, что это gist.github.com/Fed03/38a3d75d9549a8c0f64b - person Fed03; 09.02.2015
comment
@ Fed03: я не смог воспроизвести ту же ошибку с вашим кодом, но у меня это не получается с ошибкой Expected 3 assertions, but 1 were run. Чтобы это работало, мне нужно было либо добавить вызовы stop() и start() в помощнике, либо добавить return перед вызовом andThen() (чтобы вернуть возвращаемое значение andThen()). - person Hugues De Keyzer; 12.02.2015
comment
@HuguesDeKeyzer Я думаю, что мы что-то упускаем .... Если я найду решение, я дам вам знать - person Fed03; 12.02.2015
comment
@HuguesDeKeyzer, у меня это решение не работает с 1.10. Поэтому вместо этого необходимо использовать registerWaiter. В моем случае помощник andThen не остановился на разрешении промиса asyncHelper. - person ppcano; 31.03.2015

Другим общим решением является создание асинхронного помощника waitUntil, который ожидает появления html-выбора.

Ember.Test.registerAsyncHelper('waitUntil', function(app, selector, callback) {

  var waiter = function() {
    return $(selector).length > 0;
  };

  Ember.Test.registerWaiter(waiter);
  var promise = app.testHelpers.wait();

  promise.then(function() {
    Ember.Test.unregisterWaiter(waiter);
  });

  // it will be resolved when the pending events have been processed
  // (routing loads, ajax requests, run loops and waiters)
  return promise;
});

Затем waitUntil можно использовать с другими асинхронными помощниками, например:

waitUntil('#my-button');
click('#my-button');

или перед любым помощником синхронизации как:

waitUntil('#my-modal.modal').then(function() {
  var el = find('#my-modal.modal');
  assert.ok(el.length > 0, 'modal was open');

  ....
});

Как показано в этом примере, registerWaiter и registerAsyncHelper можно использовать вместе для решения аналогичных задач.

person ppcano    schedule 18.01.2016