如何用玩笑来测试自定义Web组件? [英] How to test custom web component with jest?

查看:174
本文介绍了如何用玩笑来测试自定义Web组件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想测试一些自定义的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组件的推荐方法是什么?

一些相关的东西:

如何为ES6单元测试模拟依赖项? /a>

How to mock dependencies for ES6 unit tests?

无法获得jest + puppeteer的测试报道

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆