open-wc测试中使用sinon的存根照明元素方法

问题描述 投票:0回答:1

我正在使用open-wc对用lit-element编写的自定义元素进行单元测试。我们正在使用Karma,Mocha,Sinn和Chai。我正在尝试测试元素的构造函数:

constructor() {
  super();
  window.addEventListener(
    'click',
     this._handleClickOutside
  );
}

供参考,测试中使用的功能是:

 _handleClickOutside = () => {
    console.log('calling real')
    this.active = false;
  };

disconnectedCallback() {
    window.removeEventListener('click', this._handleClickOutside);
  }

为了测试这一点,我需要对this._handleClickOutside进行存根,并检查在调度click事件时是否调用了this._handleClickOutside。这是我尝试进行的测试,其中el是已用open-wc初始化的自定义元素:

    it('should add event listener to window for click', () => {
      const clickEvent = new Event('click');
      el.disconnectedCallback();
      const spy = sinon.stub(el, '_handleClickOutside').callsFake( () => {console.log('calling fake')});
      el._handleClickOutside = spy;
      el.constructor();
      window.dispatchEvent(clickEvent);
      expect(spy.callCount).to.equal(1);
     });

我知道,当我使用open-wc创建元素时,构造函数将在存根到位之前被调用,因此我尝试使用el.disconnectedCallback()删除事件监听器,对函数进行存根,然后调用构造函数再次使用存根添加事件侦听器。但是,这仍在调用实函数。

我已经能够通过在调用this._handleClickOutside的构造函数中使用匿名函数来使测试工作,但是如果我这样做,我看不到在断开的回调中删除事件监听器的方法。想知道为什么在存根就位时再次调用构造函数无法对函数进行存根。

javascript unit-testing sinon lit-element
1个回答
0
投票

您需要进行一些重构。您需要将_handleClickOutside类属性方法更改为类原型方法。这样您就可以在元素实例化之前将其存根。

例如

element.ts

class MyElement {
  active = true;
  constructor() {
    this._handleClickOutside = this._handleClickOutside.bind(this);
    window.addEventListener("click", this._handleClickOutside);
  }
  _handleClickOutside() {
    console.log("calling real");
    this.active = false;
  }
}

export default MyElement;

element.test.ts

import MyElement from "./element";
import sinon from "sinon";
import { expect } from "chai";

// You don't need to setup jsdom in browser test environment
// jsdom start
import jsdom from "jsdom";
const html = '<!doctype html><html><head><meta charset="utf-8">' + "</head><body></body></html>";
const url = "http://localhost";
const document = new jsdom.JSDOM(html, { url });
const window = document.window;
(global as any).document = window.document;
(global as any).window = window;
// jsdom end

describe("MyElement", () => {
  afterEach(() => {
    sinon.restore();
  });
  describe("#construtor", () => {
    it("should pass", () => {
      const addEventListenerStub = sinon.stub(window, "addEventListener");
      const handleClickOutsideStub = sinon.stub(MyElement.prototype, "_handleClickOutside").callsFake(() => {
        console.log("calling fake");
      });
      new MyElement();
      addEventListenerStub.yield();
      sinon.assert.calledWithExactly(addEventListenerStub, "click", sinon.match.func);
      sinon.assert.calledOnce(handleClickOutsideStub);
    });
  });

  describe("#_handleClickOutside", () => {
    it("should pass", () => {
      const el = new MyElement();
      el._handleClickOutside();
      expect(el.active).to.be.false;
    });
  });
});

单元测试结果覆盖率100%:

  MyElement
    #construtor
calling fake
      ✓ should pass
    #_handleClickOutside
calling real
      ✓ should pass


  2 passing (11ms)

-----------------|----------|----------|----------|----------|-------------------|
File             |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-----------------|----------|----------|----------|----------|-------------------|
All files        |      100 |      100 |      100 |      100 |                   |
 element.test.ts |      100 |      100 |      100 |      100 |                   |
 element.ts      |      100 |      100 |      100 |      100 |                   |
-----------------|----------|----------|----------|----------|-------------------|

源代码:https://github.com/mrdulin/mocha-chai-sinon-codelab/tree/master/src/stackoverflow/59567755

© www.soinside.com 2019 - 2024. All rights reserved.