jQuery在玩笑测试中检查元素可见性

时间:2019-04-09 11:14:18

标签: javascript jquery node.js jestjs

我正在尝试检查单元测试中元素可见性状态是否已更改。我正在使用.is(":visible")进行此操作,在单元测试中,它始终报告该元素是隐藏的,但在浏览器中效果很好。

代码就是这么简单(请参阅完全正常工作的example):

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的交互而不是其状态。我的意思是,我可以验证对函数toggleshowhide的调用。这种方法有一个缺点,那就是它增加了复杂性,因为这将需要我在测试中保持DOM元素的状态并引入有关初始状态的假设。

1 个答案:

答案 0 :(得分:1)

我认为第一个问题是持续时间(在本例中为“快速”),toggle和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中,从而避免了200ms的等待。会很酷,但不确定是否可行。

编辑: 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);
  });

});