【问题标题】:How to test Web Component (lit-element) with jest如何用 jest 测试 Web 组件(lit-element)
【发布时间】:2021-11-04 19:34:03
【问题描述】:

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

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 环境设置:

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;

【问题讨论】:

  • 如果您分享错误是什么会很有帮助。而且由于很少有人(如果有的话)在 Jest 中运行 Web 组件测试,我可能会尝试在 repo 或 gist 中进行复制以供人们尝试。
  • 在 jsdom 支持自定义元素和 JS 模块之前,我不认为这会很好。鉴于 Web 组件使用大量 DOM API,我认为在真实浏览器中进行测试是更为谨慎的方法。您应该在您支持的所有实际浏览器中进行测试。
  • 我完全同意贾斯汀的观点...如果您在使用真实浏览器设置测试方面需要任何帮助,请查看此处open-wc.org/testing - 这应该很简单,并且可以为您提供大部分您在真实浏览器中从 Jest 中了解的功能
  • @JustinFagnani,我正在寻找一个好的堆栈来测试 vanilla webcomponents(你会在这里找到我关于这个主题的几个问题)。您说“很少有人在 Jest 中运行 Web 组件测试”。你知道赞成/反对使用 Jest 来测试 web 组件吗?不要误会我的意思,只是说“很少有人使用......”并没有多大帮助(你会发现很多人说没有多少人使用 web 组件。我使用 Polymer 取得了相当大的成功,现在我正在尝试香草网络组件)。 “很少/很多/很多/等等并没有增加太多,但如果你能很快指出为什么不呢
  • 我自己也遇到了这个问题

标签: polymer jestjs web-component jsdom lit-element


【解决方案1】:

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

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

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

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

// 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);
    });
});

我什至写了一篇关于这个的博客文章,在那里你可以找到包含完整设置等的 repos。

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

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2019-08-05
  • 2019-11-01
  • 1970-01-01
  • 2021-03-08
  • 2021-01-01
  • 2020-02-02
  • 1970-01-01
  • 2022-07-08
相关资源
最近更新 更多