Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test custom web component with jest?

I would like to test some custom web components and use jest.js as test runner (due to its support for ES6).

Chromium supports commands like

window.customElements.define('my-custom-element', MyCustomElementClass);

to register a custom web component.

However, window.customElements does not seem to be known in the context of jest tests.

As a work around I tried to use jest in combination with puppeteer and express to run the customElements part in Chromium.

However, I have difficulties to inject the custom element class TreezElement in the evaluated code:

treezElement.js:

class TreezElement extends HTMLElement {
    connectedCallback () {
      this.innerHTML = 'Hello, World!';
    }
}

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

});

Maybe TreezElement is not serializable and therefore undefined is passed to the function.

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

=> What is the recommended way to test custom web components with jest?

Some related stuff:

  • Web Component / HtmlElement : unit testing

  • https://itnext.io/testing-your-javascript-in-a-browser-with-jest-puppeteer-express-and-webpack-c998a37ef887

  • How to mock dependencies for ES6 unit tests?

  • Can't get test coverage with jest + puppeteer

  • https://jestjs.io/docs/en/puppeteer

like image 728
Stefan Avatar asked Aug 13 '19 13:08

Stefan


People also ask

Can we test Web components using Jest?

TLDR It is possible to test web components with Jest. Don't use JSDOM but run your tests in a browser environment instead.

How do you test a Web component?

The Web Component Test Execution Environment As of writing this, the only viable way of running tests for Web Components is through Karma which executes them through a target browser. People coming from current technologies, such as React, Angular or Vue, might be disappointed with the current state of matters.


3 Answers

JSDOM 16.2 includes basic support for custom elements and is available in Jest 26.5 and above. Here's a simple Jest test that shows it working:

customElements.define('test-component', class extends HTMLElement {
    constructor() {
        super();
        const p = document.createElement('p')
        p.textContent = 'It works!'
        this.appendChild(p)
    }
})

test('custom elements in JSDOM', () => {
    document.body.innerHTML = `<h1>Custom element test</h1> <test-component></test-component>`
    expect(document.body.innerHTML).toContain('It works!')
})

Output:

$ jest

PASS  ./test.js
✓ custom elements in JSDOM (11 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.409 s
Ran all test suites.

Note not all features are supported yet, notably shadow DOM does not work.

like image 81
Tamlyn Avatar answered Oct 11 '22 07:10

Tamlyn


I have created a DOM that supports server side rendering of web components. It also supports testing web components with Jest.

DOM:

https://www.npmjs.com/package/happy-dom

Jest environment:

https://www.npmjs.com/package/jest-environment-happy-dom

To install it

npm install jest-environment-happy-dom --save-dev

To use it:

Edit your package.json to include the Jest environment:

{
    "scripts": {
        "test": "jest --env=jest-environment-happy-dom"
    }
}
like image 33
David Ortner Avatar answered Oct 11 '22 06:10

David Ortner


use electron runner can include all node and chrome env, use this to replace jsdom

https://github.com/facebook-atom/jest-electron-runner

like image 2
superwf Avatar answered Oct 11 '22 05:10

superwf