JQuery проверка на видимость элементов в шутливых тестах - PullRequest
2 голосов
/ 09 апреля 2019

Я пытаюсь проверить в модульном тесте, что состояние видимости элемента было изменено. Я использую .is(":visible"), чтобы сделать это, и в модульном тесте он всегда сообщает, что элемент скрыт, но он отлично работает в браузерах.

Код так же прост (см. Полностью рабочий пример ):

HTML

<form>
      <div id="field">hi</div>
      <input type='checkbox' id="toggle">toggle</input>
      <input type='checkbox' id="show">show</input>
      <input type='checkbox' id="hide">hide</input>
</form>

1011 * Javascript * $('form').on('change', 'input#toggle[type="checkbox"]', function() { target_row = $('#field'); if (target_row.length) { target_row.toggle("fast"); } }); Как я уже писал, это прекрасно работает в браузерах, но не работает в следующем тесте: jest.dontMock('jquery'); jest.dontMock('../toggle.js'); $ = jQuery = require('jquery'); describe('toggle.js', function() { var sut = require('../toggle.js'); function givenFields(formFields) { document.documentElement.innerHTML = ` <html><body><form> <div id="field">hi</div> ${formFields} </form></body></html> `; sut.initialize(); } it('toggles the field', function() { givenFields(`<input type='checkbox' id="toggle">toggle</input>`); var initiallyVisible = $("#field").is(":visible"); $('#toggle').click(); // Checking that this is not jsdom rendering issue expect(document.hidden).toEqual(false); expect($("#field").is(":visible")).toEqual(!initiallyVisible); }); it('shows the field', function() { givenFields(`<input type='checkbox' id="show">show</input>`); $('#show').click(); expect($("#field").is(":visible")).toEqual(true); }); }); Результат: ● toggle.js › toggles the field expect(received).toEqual(expected) Expected: true Received: false 26 | expect(document.hidden).toEqual(false); 27 | > 28 | expect($("#field").is(":visible")).toEqual(!initiallyVisible); | ^ 29 | }); 30 | 31 | it('shows the field', function() { at Object.toEqual (src/__test__/toggle.spec.js:28:40) ● toggle.js › shows the field expect(received).toEqual(expected) Expected: true Received: false 34 | $('#show').click(); 35 | > 36 | expect($("#field").is(":visible")).toEqual(true); | ^ 37 | }); 38 | }); 39 | at Object.toEqual (src/__test__/toggle.spec.js:36:40) package.json: { "name": "toggle", "devDependencies": { "jasmine": "3.2.0", "jest-cli": "24.1.0", "jquery": "3.3.1" }, "scripts": { "test": "jest" } } Есть идеи, что может быть не так и как я могу подойти к этой проблеме? Один вариант, который мне не очень нравится, так как это не решение, а обходной путь, заключается в том, что я могу проверять взаимодействия с DOM, а не с его состоянием. Под этим я подразумеваю, что могу проверять вызовы функций toggle, show и hide. У этого подхода есть недостаток, а именно, он увеличивает сложность, так как это потребует от меня поддержания состояния элементов DOM в тестах и ​​введения предположений о начальном состоянии.

1 Ответ

1 голос
/ 09 апреля 2019

Я думаю, что первая проблема заключается в том, что с длительностью (в данном случае «быстрой»), toggle and show functions don't just change the visibility:

When a duration, a plain object, or a single "complete" function is provided, .toggle() becomes an animation method. The .toggle() method animates the width, height, and opacity of the matched elements simultaneously. When these properties reach 0 after a hiding animation, the display style property is set to none to ensure that the element no longer affects the layout of the page.

So you actually want to be checking for the display of the element.

The next issue is that it takes 200ms before jquery sets the display to none, so we need to account for that, meaning we could write something like this:

  it('toggles the field', function(done) {
    givenFields(`
       kuku переключатель  `);var initialDisplay = $ ("# field"). css ('display');$ ( '# Тумблер') нажмите ().// Проверка того, что это не проблема рендеринга jsdom ожидаем (document.hidden) .toEqual (false);var ожидаетсяDisplay = initialDisplay === 'блок'?'none': 'block' setTimeout (function () {Ожидайте ($ ("# поле"). css ('display')). toEqual (Ожидаемый вывод); done ()}, 200)});

Также может быть способ ввести jest timer-mocks into jquery so that you can avoid the 200ms wait. Would be cool but not sure if it's possible.

EDIT: jQuery.fx.off = true; This works great, leaving us with:

jest.dontMock('jquery');
jest.dontMock('./toggle.js');

$ = jQuery = require('jquery');
jQuery.fx.off = true;

describe('toggle.js', function() {
  var sut = require('./toggle.js');
  function givenFields(formFields) {
    document.documentElement.innerHTML = `
      ${formFields}
    `;
    sut.initialize();
  }

  it('toggles the field', function() {
    givenFields(`
       Куку переключатель  `);var initialDisplay = $ ("# field"). css ('display');$ ( '# Тумблер') нажмите ().// Проверка того, что это не проблема рендеринга jsdom ожидаем (document.hidden) .toEqual (false);var ожидаетсяDisplay = initialDisplay === 'блок'?'none': 'block' Ожидается ($ ("# field"). css ('display')). toEqual (Ожидаемый вывод);});it ('показывает поле', function () {GivenFields (`Куку show  `);$ ( '# Шоу') нажмите ().ожидать ($ ( "# поле") есть ( ": видимые").) toEqual (истина);.});});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...