1 JQuery проверка на видимость элементов в шутливых тестах

вопрос создан в Tue, Apr 9, 2019 12:00 AM

Я пытаюсь проверить в модульном тесте, что состояние видимости элемента было изменено. Я использую .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>

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 в тестах и ​​вводить предположения о начальном состоянии.     

2
1 ответ                              1                         

Я думаю, что первая проблема заключается в том, что при длительности (в данном случае «быстрой») переключатель и функции show не просто изменяют видимость:

  

Если указана длительность, простой объект или одна «полная» функция, .toggle () становится методом анимации. Метод .toggle () одновременно анимирует ширину, высоту и непрозрачность сопоставляемых элементов. Когда эти свойства достигают 0 после скрытой анимации, для свойства стиля отображения устанавливается значение none, чтобы гарантировать, что элемент больше не влияет на макет страницы.

То есть вы действительно хотите проверить display элемента.

Следующая проблема заключается в том, что для установки jquery значения none требуется 200 мс, поэтому мы должны учитывать это, то есть мы могли бы написать что-то вроде этого:

  it('toggles the field', function(done) {
    givenFields(`
      <div id="field">kuku</div>
      <input type='checkbox' id="toggle">toggle</input>
    `);

    var initialDisplay = $("#field").css('display');

    $('#toggle').click();

    // Checking that this is not jsdom rendering issue
    expect(document.hidden).toEqual(false);
    var expectedDisplay = initialDisplay === 'block' ? 'none' : 'block'
    setTimeout(function() {
      expect($("#field").css('display')).toEqual(expectedDisplay);
      done()
    }, 200)
  });

Также может быть способ внедрить jest timer-mocks в jquery, чтобы что вы можете избежать ожидания 200 мс. Было бы круто, но не уверен, если это возможно.

EDIT: jQuery.fx.off = true; Это прекрасно работает, оставляя нас с:

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 = `
      <html><body><form>${formFields}</form></body></html>
    `;
    sut.initialize();
  }

  it('toggles the field', function() {
    givenFields(`
      <div id="field">kuku</div>
      <input type='checkbox' id="toggle">toggle</input>
    `);

    var initialDisplay = $("#field").css('display');

    $('#toggle').click();

    // Checking that this is not jsdom rendering issue
    expect(document.hidden).toEqual(false);
    var expectedDisplay = initialDisplay === 'block' ? 'none' : 'block'
    expect($("#field").css('display')).toEqual(expectedDisplay);
  });

  it('shows the field', function() {
    givenFields(`
      <div id="field">kuku</div>
      <input type='checkbox' id="show">show</input>
    `);

    $('#show').click();

    expect($("#field").is(":visible")).toEqual(true);
  });

});
    
1
2019-04-09 12: 34: 17Z
источник размещен Вот