如何用玩笑来测试自定义Web组件? [英] How to test custom web component with jest?
问题描述
我想测试一些自定义的Web组件,并使用jest.js作为测试运行器(由于其对ES6的支持).
I would like to test some custom web components and use jest.js as test runner (due to its support for ES6).
Chromium支持类似的命令
Chromium supports commands like
window.customElements.define('my-custom-element', MyCustomElementClass);
注册自定义Web组件.
to register a custom web component.
但是,在玩笑测试的背景下,window.customElements
似乎并不为人所知.
However, window.customElements
does not seem to be known in the context of jest tests.
作为解决方法,我尝试将玩笑与puppeteer结合使用并表达,以在Chromium中运行customElements
部分.
As a work around I tried to use jest in combination with puppeteer and express to run the customElements
part in Chromium.
但是,我很难将自定义元素类TreezElement
插入评估的代码中:
However, I have difficulties to inject the custom element class TreezElement
in the evaluated code:
treezElement.js:
treezElement.js:
class TreezElement extends HTMLElement {
connectedCallback () {
this.innerHTML = 'Hello, World!';
}
}
treezElement.test.js:
treezElement.test.js:
import TreezElement from '../../src/components/treezElement.js';
import puppeteer from 'puppeteer';
import express from 'express';
describe('Construction', ()=>{
let port = 3000;
let browser;
let page;
let element;
const width = 800;
const height = 800;
beforeAll(async () => {
const app = await express()
.use((req, res) => {
res.send(
`<!DOCTYPE html>
<html>
<body>
<div id="root"></div>
</body>
</html>`
)
})
.listen(port);
browser = await puppeteer.launch({
headless: false,
slowMo: 80,
args: [`--window-size=${width},${height}`]
});
var pages = await browser.pages();
page = pages[0];
await page.setViewport({ width, height });
await page.goto('http://localhost:3000');
element = await page.evaluate(({TreezElement}) => {
console.log('TreezElement:')
console.log(TreezElement);
window.customElements.define('treez-element', TreezElement);
var element = document.create('treez-element');
document.body.appendChild(element);
return element;
}, {TreezElement});
});
it('TreezElement', ()=>{
});
afterAll(() => {
browser.close();
});
});
也许TreezElement
无法序列化,因此undefined
被传递给该函数.
Maybe TreezElement
is not serializable and therefore undefined
is passed to the function.
如果我尝试直接从评估的代码中导入自定义元素类TreezElement
...
If I try to import the custom element class TreezElement
directly from within the evaluated code ...
element = await page.evaluate(() => {
import TreezElement from '../../src/components/treezElement.js';
console.log('TreezElement:')
console.log(TreezElement);
window.customElements.define('treez-element', TreezElement);
var element = document.create('treez-element');
document.body.appendChild(element);
return element;
});
...我收到错误消息
... I get the error
导入"和导出"只能出现在顶层
'import' and 'export' may only appear at the top level
=>用玩笑来测试自定义Web组件的推荐方法是什么?
一些相关的东西:
How to mock dependencies for ES6 unit tests?
https://jestjs.io/docs/en/puppeteer
推荐答案
这是一个丑陋的版本,可以正常工作.关于此的一些进一步说明:
Here is an ugly version that kind of works. Some further notes on this:
-
express.js被配置为用作文件服务器.否则,对于导入的ES6模块,mime类型或跨源检查会存在问题.
express.js is configured to work as file server. Otherwise there would be issues with mime type or cross origin checking for the imported ES6 modules.
类TreezElement
不是直接导入的,而是使用了创建额外脚本标签
The class TreezElement
is not directly imported but using the work around of creating an extra script tag
实例方法与代码覆盖率有关.似乎不可能直接调用TreezElement
的构造函数(继承自HTMLElement,=> illegal constructor
). 元素类的实例只能在操纵p的情况下用document.createElement(...)
创建.因此,不能在Jest中测试所有实例方法,而只能在静态方法中测试.实例方法和属性可以在puppeteer中进行测试.但是,开玩笑的代码覆盖范围并未考虑到伪造者的代码覆盖范围.
There are issues with instance methods regarding the code coverage. It does not seem to be possible to directly call the constructor of TreezElement
(inherits from HTMLElement, => illegal constructor
). An instance of the element class can only be created with document.createElement(...)
in puppeteer. Therefore, all the instance methods cannot be tested in Jest but only static methods. The instance methods and properties can be tested in puppeteer. However, the code coverage of jest does not consider the code coverage of puppeteer.
创建的类型为TreezElement
的元素可以以 ElementHandle . 访问element实例的属性和方法很麻烦(请参见下面的示例).作为处理方法的替代方法,可以应用page.$eval
方法:
The created element of type TreezElement
can be returned in form of an ElementHandle. Accessing the properties and methods of the element instance is quite cumbersome (see example below). As an alternative to the handle approach, the page.$eval
method can be applied:
var id = await page.$eval('#custom-element', element=> element.id);
index.html
index.html
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="root"></div>
</body>
</html>
treezElement.test.js
treezElement.test.js
import TreezElement from '../../src/components/treezElement.js';
import puppeteer from 'puppeteer';
import express from 'express';
describe('Construction', ()=>{
let port = 4444;
const index = Math.max(process.argv.indexOf('--port'), process.argv.indexOf('-p'))
if (index !== -1) {
port = +process.argv[index + 1] || port;
}
var elementHandle;
beforeAll(async () => {
const fileServer = await express()
.use(express.static('.'))
.listen(port);
var browser = await puppeteer.launch({
headless: false,
slowMo: 80,
userDataDir: '.chrome',
args: ['--auto-open-devtools-for-tabs']
});
var pages = await browser.pages();
var page = pages[0];
await page.goto('http://localhost:'+port + '/test/index.html');
await page.evaluate(() => {
var script = document.createElement('script');
script.type='module';
script.innerHTML="import TreezElement from '../src/components/treezElement.js';\n" +
"window.customElements.define('treez-element', TreezElement);\n" +
"var element = document.createElement('treez-element');\n" +
"element.id='custom-element';\n" +
"document.body.appendChild(element);";
document.head.appendChild(script);
});
elementHandle = await page.evaluateHandle(() => {
return document.getElementById('custom-element');
});
});
it('id', async ()=>{
var idHandle = await elementHandle.getProperty('id');
var id = await idHandle.jsonValue();
expect(id).toBe('custom-element');
});
afterAll(() => {
browser.close();
});
});
这篇关于如何用玩笑来测试自定义Web组件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!