Тест Qunit чередуется между pass и fail при обновлении страницы
У меня есть два теста, которые вызывают побочные эффекты друг с другом. Я понимаю, почему, поскольку я заменяю встроенную функцию jQuery, которая внутренне вызывается во втором тесте. Однако я не понимаю, почему тест поочередно проходит и терпит неудачу.
Этот вопрос аналогичен Однако я ничего не делаю непосредственно на div qunit-fixture.
Вот мои тесты
test('always passing test', function() { // Always passes
var panelId = '#PanelMyTab';
var event = {};
var ui = {
tab: {
name: 'MyTab',
},
panel: panelId,
};
$('<div id="' + panelId + '">')
.append('<a href="#" class="export">Test</a>')
.append('<a href="#" class="showForm">Show Form</a>')
.appendTo('#qunit-fixture');
jQuery.fn.on = function(event, callback) {
ok(this.selector == panelId + ' .export', 'Setting export click event');
equal(callback, tickets.search.getReport, 'Callback being set');
};
loadTab(event, ui);
});
test('alternately passing and failing', function() { // Alternates between passing and failing on page refresh
expect(5);
var testUrl = 'test';
$('<div class="ui-tabs-panel">')
.append('<a href="'+ testUrl + '" id="getReport">Get Report</a>')
.append('<form action="notest" target="" class="ticketSearch"></form>')
.appendTo('#qunit-fixture');
// Setup form mocking
$('form.ticketSearch').submit(function() {
var urlPattern = new RegExp(testUrl + '$');
ok(urlPattern.test($(this).prop('action')), 'Form action set to link href');
equal($(this).prop('target'), '_blank', 'Open form on a new page');
});
var event = {
target: 'a#getReport',
};
var result = getReport(event);
var form = $('form.ticketSearch');
ok(/notest$/.test($(form).prop('action')), 'Making sure action is not replaced');
equal($(form).prop('target'), '', 'Making sure that target is not replaced');
ok(false === result, 'click event returns false to not refresh page');
});
Тесты начнутся, но при обновлении они будут чередоваться между прохождением и провалом.
Почему это происходит? Даже добавление параметров GET к URL-адресу приводит к тому же поведению на странице.
В случае сбоя тест не работает, потому что внутренний jQuery вызывает .on()
, когда установлен обработчик submit()
. Но почему в этом случае тест всегда не срабатывает? Что браузер делает, что состояние сохраняется во время обновления страницы?
Update:
Вот код, который тестируется:
var tickets = function() {
var self = {
loadTab: function(event, ui) {
$(panel).find('.export').button().on('click', this.getReport);
},
search: {
getReport: function(event) {
var button = event.target;
var form = $(button).closest('div.ui-tabs-panel').find('form.ticketSearch').clone(true);
$(form).prop('action', $(button).prop('href'));
$(form).prop('target', '_blank');
$(form).submit();
return false;
}
}
};
return self;
}();
Ответы
Ответ 1
Я изменил @Ben fiddle, чтобы включить ваш код в оба теста. Я изменил некоторые из вашего кода, чтобы он работал правильно. Когда вы нажмете кнопку запуска, все тесты пройдут. Когда вы снова нажмете кнопку "Пробег", второй тест ( "чередование и провал" ) потерпит неудачу - это в основном имитирует вашу исходную проблему.
Проблема - ваш первый тест ( "всегда проходящий тест" ) изменяет глобальное состояние, заменив функцию jQuery.fn.on
на переопределенную. Из-за этого, когда тесты выполняются по порядку, второй тест ( "поочередно передающий и неудачный" ) использует неправильную переопределенную функцию jQuery.fn.on
и не работает. Каждый unit test должен вернуть глобальное состояние обратно в свое состояние перед тестированием, чтобы другие тесты могли выполняться на основе тех же предположений.
Причина, по которой он чередуется между pass и fail, заключается в том, что под капотом QUnit всегда сначала запускает неудачные тесты (он как-то помнит об этом через cookie или локальное хранилище, я не совсем уверен). Когда он сначала запускает неудачные тесты, второй тест выполняется до первого; в результате второй тест получает функцию jQuery native on
и работает. Когда вы запустите его в третий раз, тесты будут выполняться в их "оригинальном" порядке, а во втором тесте будет использоваться переопределенная функция on
и сбой.
Здесь работает fiddle. Я добавлю исправление к "un-override" функции on
после теста путем кэширования исходной функции var jQueryOn = jQuery.fn.on;
и сброса ее в конце теста с помощью: jQuery.fn.on = jQueryOn;
. Вы, вероятно, лучше реализуете это, используя метод QUnit module teardown()
.
Вы можете проверить https://github.com/jquery/qunit/issues/74 для получения дополнительной информации.
Ответ 2
Я не уверен, что смогу решить эту проблему без дополнительной информации, но я могу указать на некоторые возможные проблемы.
Первый тест, похоже, имеет неверный синтаксис в строке 2
var panelId = '#PanelMyTab');
Но это, вероятно, ошибка типа, видя, что вы говорите, что первое всегда проходит.
Я предполагаю, что для того, чтобы первый тест прошел (и был действителен), loadTab (event, ui) должен запустить jQuery.fn.on(), без которого не было никаких утверждений. Что делает некоторое тестирование с вкладками пользовательского интерфейса jQuery, похоже, это так (просто не уверен, что это было ваше намерение).
Я не уверен, что это целесообразно помещать эти утверждения в эту функцию, и вы должны понимать, что вы перезаписали функцию jquery с помощью функции, которая ничего не делает, поэтому она может вызвать проблемы.
Кажется, что вы делаете что-то подобное во втором тесте, вы ожидаете 5 утверждений, но я могу видеть только, как можно запустить последний 3
ok(/notest$/.test($(form).prop('action')), 'Making sure action is not replaced');
equal($(form).prop('target'), '', 'Making sure that target is not replaced');
ok(false === result, 'click event returns false to not refresh page');
Другие 2 находятся в функции отправки, которая не выглядит так, как она вызывается как часть теста.
Помните, что эти тесты являются синхронными, поэтому он не будет ждать, пока вы нажмете submit перед запуском теста и сбоя.
Вот пример
test('asynchronous test', function() {
setTimeout(function() {
ok(true);
}, 100)
})
Не удалось, так как ok запускается через 100 мс после теста.
test('asynchronous test', function() {
// Pause the test first
stop();
setTimeout(function() {
ok(true);
// After the assertion has been called,
// continue the test
start();
}, 100)
})
Стоп() сообщает qunit ждать, а start() - идти!
Существует также ayncTest(), подробно описанный в api здесь
Наконец, кажется, что вы пытаетесь отлаживать свой код с помощью этих тестов. Было бы намного проще использовать инструменты разработчика Chrome или firebug в firefox, чтобы установить точки останова на вашем коде, а также использовать console.log() и console.dir() для вывода информации.
Сказав это, я понятия не имею, как это работает для вас вообще, поэтому я мог бы что-то упустить:) Если вы все еще застряли, посмотрите, можете ли вы добавить еще какой-то окружающий код и что вы пытаетесь достичь, Надеюсь, это поможет.
PS: в конце есть также };
, который недопустим в коде, который вы нам дали, вероятно, актуальным в самом приложении;)