我正在使用open-wc对使用lit-element编写的自定义元素进行单元测试。我们使用Karma,Mocha,Sinon和Chai。我正在尝试测试元素的构造函数:
constructor() {
super();
window.addEventListener(
'click',
this._handleClickOutside
);
}作为参考,测试中使用的函数如下:
_handleClickOutside = () => {
console.log('calling real')
this.active = false;
};
disconnectedCallback() {
window.removeEventListener('click', this._handleClickOutside);
}为了测试这一点,我需要存根this._handleClickOutside并检查当一个单击事件被分派时,是否调用了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的构造函数中使用匿名函数来使测试工作,但是如果我这样做,我看不到在断开连接的回调中删除事件侦听器的方法。想知道为什么在存根已经就位的情况下再次调用构造函数并不能将函数存根。
发布于 2020-01-03 12:12:20
你需要做一些重构。您需要将_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
https://stackoverflow.com/questions/59567755
复制相似问题