测试直接更改 DOM 的库

Posted

技术标签:

【中文标题】测试直接更改 DOM 的库【英文标题】:Testing a library that changes DOM directly 【发布时间】:2018-07-26 14:10:36 【问题描述】:

我编写了一个直接操作 DOM 的小型库,使用 windowdocument 来搜索和更改 DOM。现在我正在尝试弄清楚如何对其进行测试。

到目前为止,我已经尝试了jest + jsdom 的组合:

const jsdom = require('jsdom');
const JSDOM = jsdom;

const dom = new JSDOM('<!DOCTYPE html><p>Hello world</p>');

// these two lines do not seem to do anything useful:
global.window = dom.window;
global.document = dom.window.document;

test('can globally access and search the DOM', () => 
    // this doesn't work
    expect(global.document.querySelectorAll('p').length).toBe(1);
);

我在这里做错了什么,还是我的测试方法完全错了?如果是这样,进行此类测试的正确方法是什么?

我觉得有点迷失在所谓的 e2e 测试和单元测试之间,因为在我的情况下,这似乎是介于两者之间的东西。

理想情况下,我希望最终对这个东西进行针对多个浏览器的测试,并获得某种测试覆盖率。但这更像是下一步。现在我根本无法让它工作。

我知道网络世界的发展速度有多快,所以如果我完全错了,如果你能指出今天的正确方法,我将不胜感激。


更新

这是我的完整代码,经过 @duxfox 的一些建议,因为使用这种方法,我的库现在缺少事件 DOMContentLoaded,它应该触发其 DOM 处理。

const jsdom = require('jsdom');
const JSDOM = jsdom;

const  document  = (new JSDOM('<!DOCTYPE html><p>Hello world</p>')).window;
global.document = document;

global.window = document.defaultView;
window.console = global.console;

Object.keys(document.defaultView).forEach((property) => 
    if (typeof global[property] === 'undefined') 
        global[property] = document.defaultView[property];
    
);

global.navigator = 
    userAgent: 'node.js'
;

// Here I'm trying to follow a suggestion from Luis:
// https://***.com/questions/36803733/jsdom-dispatchevent-addeventlistener-doesnt-seem-to-work
window.addEventListener('DOMContentLoaded', function (ev) 
    console.log('DOMContentLoaded called!'); // this is not called.
    /*
    console.log('window click', ev.target.constructor.name,
        ev.currentTarget.constructor.name);*/
);

// loading my library here:
// const root = require('../src');

test('something', () => 

    // This now works, but my library is missing
    // event DOMContentLoaded to start processing the DOM

    expect(document.querySelectorAll('p').length).toBe(1);
);

【问题讨论】:

手动触发 domContentLoaded 事件会起作用吗? ***.com/questions/9153314/… 等一下,对不起,你已经这样做了 或者这个:gist.github.com/chad3814/5059671 @duxfox——我不明白,使用那段代码我得到错误TypeError: jsdom.env is not a function。我正在使用jsdom 版本11.11.0 @duxfox-- 哈哈,刚刚看到最后一条评论:Would you please redo the example using the new API? jsdom.env is deprecated as of jsdom v10.。所以,这行不通。那么最新的jsdom的正确方法是什么? :) lol idk,我也看到了,只是在查找它 【参考方案1】:

下面是我与mocha/chai/jsdom/enzyme一起使用的jsdom设置脚本

看起来global.window 应该设置为

dom.window.document.defaultView

而不是

dom.window

完整脚本,添加其他全局属性:

var jsdom = require('jsdom');
const  JSDOM  = jsdom;

const  document  = (new JSDOM('')).window;
global.document = document;

global.window = document.defaultView;
window.console = global.console;

Object.keys(document.defaultView).forEach((property) => 
  if (typeof global[property] === 'undefined') 
    global[property] = document.defaultView[property];
  
);

global.navigator = 
  userAgent: 'node.js'
;

【讨论】:

这似乎在表面上起作用。现在它对我来说失败了,因为在库内部它仅在初始化后解析 DOM:document.addEventListener('DOMContentLoaded', function () /* process the DOM */);。任何建议如何解决这个问题? 不确定您的意思 - 您粘贴的 addEventListener 代码的意义是什么?这是一个测试用例还是什么? 看到这个问题:***.com/questions/36803733/… document.addEventListener('DOMContentLoaded', function () 是在文档加载完成后开始处理 DOM。但在我们的案例中,这发生在包含库之前。如果我首先包含该库,那么它将无法工作,因为尚未设置全局变量。所以这就像一场比赛。 我开始感觉到什么应该是正确的方法,但我还没有尝试管理它。我认为,最好的方法可能是使用JSDOM.fromFile 加载一个包含所有库用例的 HTML 文件,但最重要的是 - 从其中包含我的库。然后,理论上,一切都应该正常工作。这就是我现在正在尝试做的事情......

以上是关于测试直接更改 DOM 的库的主要内容,如果未能解决你的问题,请参考以下文章

来测试下 2019 你一共写了多少行代码?

axiosaxios的基本使用

搭建React环境

react虚拟dom与diff算法

使用 DOM 按钮更改选择 HTML 元素中的选定值 单击 select2.js

jQuery:如何更改标签名称?