如何用 Jest 测试 Web 组件(lit-element) [英] How to test Web Component (lit-element) with jest

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

问题描述

有没有人有一个很好的设置来测试带有 jest、jsdom 或类似内容的自定义元素?我一直在使用 Puppeteer 和 Selenium,但它们使测试运行速度减慢太多.jsdom 的任何其他替代方案或修复程序可以使以下测试运行吗?

Anyone has a good setup for testing custom elements with jest, jsdom or similar? I have been using Puppeteer and Selenium, but they slow down the test runs too much. Any other alternatives or fixes for jsdom that makes the below test runnable?

import {LitElement} from 'lit-element';
import {html} from 'lit-html';

export class Counter extends LitElement {
  static get properties() {
    return Object.assign({}, super.properties, {
      count: {type: Number}
    });
  }

  render() {
    return html`Count is ${this.count}`;
  }
}

customElements.define('c-counter', Counter);

与测试文件:

import './counter';

describe('c-counter', () => {
  it('should be registered', () => {
    expect(customElements.get('c-counter')).toBeDefined();
  });

  it('render', async () => {
    const element = window.document.createElement('c-counter');
    window.document.body.appendChild(element);

    await element.updateComplete;
    expect(element.innerHTML).toContain('Count is undefined');

    element.count = 3;
    await element.updateComplete;

    expect(element.innerHTML).toContain('Count is 3');
  });
});

最后这是当前的 jest 环境设置:

And finally this is the current jest environment setup:

const {installCommonGlobals} = require('jest-util');
const {JSDOM, VirtualConsole} = require('jsdom');
const JSDOMEnvironment = require('jest-environment-jsdom');
const installCE = require('document-register-element/pony');

class JSDOMCustomElementsEnvironment extends JSDOMEnvironment {
  constructor(config, context) {
    super(config, context);

    this.dom = new JSDOM('<!DOCTYPE html>', {
      runScripts: 'dangerously',
      pretendToBeVisual: true,
      VirtualConsole: new VirtualConsole().sendTo(context.console || console),
      url: 'http://jsdom'
    });

    /* eslint-disable no-multi-assign */
    const global = (this.global = this.dom.window.document.defaultView);

    installCommonGlobals(global, config.globals);

    installCE(global.window, {
      type: 'force',
      noBuiltIn: false
    });
  }

  teardown() {
    this.global = null;
    this.dom = null;

    return Promise.resolve();
  }
}

module.exports = JSDOMCustomElementsEnvironment;

推荐答案

可以通过一些额外的设置来实现.

It is possible with a bit of additional setup.

如果您查看 open wc 文档,他们建议在浏览器中测试您的 Web 组件,他们已经使用 Karma 和 Headless Chrome 进行了测试.正如您已经指出的,Puppeteer 和 Selenium 对此来说太慢了,唯一可行的浏览器替代方案是 ElectronJS.有一个可供 Jest 使用的跑步者.

If you look at open wc docs, they recommend testing your web components in the browser which they already do with Karma and Headless Chrome. As you already pointed out Puppeteer and Selenium are too slow for this and the only viable browser alternative is ElectronJS. There is a runner available for Jest.

https://github.com/hustcc/jest-electron

这将允许您在能够访问 Shadow DOM 的真实浏览器中渲染您的 Web 组件,并且您的测试仍然会很快.像这样,我使用 Webpack 来处理我的代码.

This will allow you to render your web components in a real browser with access to Shadow DOM and your tests will still be fast. Something like this, I use Webpack for processing my code.

// button.ts
import {html, customElement, LitElement, property} from "lit-element";

@customElement('awesome-button')
export class Button extends LitElement {

    @property()
    buttonText = '';

    render() {
        return html`<button id="custom-button"
            @click="${() => {}}">${this.buttonText}</button>`;
    }
}

Webpack 配置

const path = require('path');
const {CleanWebpackPlugin} = require('clean-webpack-plugin');

module.exports = {
    mode: 'development',
    entry: './index.ts',
    module: {
        rules: [
            {
                test: /.ts?$/,
                use: 'ts-loader',
                exclude: /node_modules/,
            },
        ],
    },
    resolve: {
        extensions: ['.tsx', '.ts', '.js'],
    },
    plugins: [
        new CleanWebpackPlugin()
    ],
    output: {
        filename: 'main.js',
        path: path.resolve(__dirname, 'dist'),
    },
};

Jest 配置

module.exports = {
    preset: 'ts-jest',
    runner: 'jest-electron/runner',
    testEnvironment: 'jest-electron/environment',
    setupFiles: ['./dist/main.js'],
};

最后是我们的测试.

import {LitElement} from 'lit-element';

describe('awesome-button', () => {

    const AWESOME_BUTTON_TAG = 'awesome-button';
    const ELEMENT_ID = 'custom-button';
    let buttonElement: LitElement;

    const getShadowRoot = (tagName: string): ShadowRoot => {
        return document.body.getElementsByTagName(tagName)[0].shadowRoot;
    }

    beforeEach(() => {
        buttonElement = window.document.createElement(AWESOME_BUTTON_TAG) as LitElement;
        document.body.appendChild(buttonElement);
    });

    afterEach(() => {
       document.body.getElementsByTagName(AWESOME_BUTTON_TAG)[0].remove();
    });

    it('displays button text', async () => {
        const dummyText = 'Web components & Jest with Electron';
        buttonElement.setAttribute('buttonText', dummyText);
        await buttonElement.updateComplete;

        const renderedText = getShadowRoot(AWESOME_BUTTON_TAG).getElementById(ELEMENT_ID).innerText;

        expect(renderedText).toEqual(dummyText);
    });
    it('handles clicks', async () => {
        const mockClickFunction = jest.fn();
        buttonElement.addEventListener('click', () => {mockClickFunction()});

        getShadowRoot(AWESOME_BUTTON_TAG).getElementById(ELEMENT_ID).click();
        getShadowRoot(AWESOME_BUTTON_TAG).getElementById(ELEMENT_ID).click();

        expect(mockClickFunction).toHaveBeenCalledTimes(2);
    });
});

我什至写了一篇关于这个的博客文章,你可以在那里找到完整设置等的存储库.

I even wrote a blog post about this and there you can find repos with the full setup etc.

https://www.ninkovic.dev/blog/2020/testing-web-components-with-jest-and-lit-element

这篇关于如何用 Jest 测试 Web 组件(lit-element)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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