Web Component / HtmlElement : unit testing

2020-03-27 08:42发布

问题:

I'm trying to test a web component. Here is my project structure :

├── package.json
├── src
│   ├── app.js
│   └── index.html
└── test
    └── hello-world-test.html

Here is my working code :

class HelloWorld extends HTMLElement {
    connectedCallback () {
      this.innerHTML = 'Hello, World!'
    }
}
customElements.define('hello-world', HelloWorld);
<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <script src="app.js"></script>
</head>

<body>
    <hello-world></hello-world>
</body>

</html>

I'm trying to test that web component with web-component-tester. I installed the utility globally :

npm install -g web-component-tester

I declared it in the package.json file :

"devDependencies": {
    "web-component-tester": "^6.9.0"
}

then, I wrote my test in the test folder and saved it to hello-world-test.html:

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <script src="../node_modules/web-component-tester/browser.js"></script>
    <script src="app.js"></script>
</head>
<body>
    <test-fixture id="hello-world-fixture">
            <hello-world></hello-world>
    </test-fixture>
    <script>
        suite('<hello-world>', function(){
            let component = document.querySelector('hello-world');

            test('contains hello world string ?', () => {
                let index = component.innerText.indexOf('Hello');
                assert.isAtLeast(index, 0);
            });
        });
    </script>
</body>
</html>

Finally, I typed :

wct --npm

Then obtained the following error in Chrome :

What am I missing to run the test correctly ? The only decent materials I've found are this one and that one but they are outdated.

回答1:

There are many errors :

  • First, please read the whole documentation as in the last paragraph it's clear that for those who use npm you need an additional dependency through the wctPackageName :

Components which wish to support npm-based installation should include wct-browser-legacy in their devDependencies, which is a package that contains only the client-side javascript necessary for executing WCT tests in an npm-based environment. WCT will attempt to identify which package provides the client-side code by checking for compatible packages in the following order of preference: wct-mocha, wct-browser-legacy and web-component-tester. If you want to specify which package provides WCT client-side code, use the --wct-package-name flag or wctPackageName option in wct.conf.json with the npm package name.

So you will need to add wct-browser-legacy in your devDependencies

  • Giving your project structure, you are including the app.js as if it was at the same level. It should be ../src/app.js.
  • You should add the type="module" to that import
  • You declared a fixture but didn't take profit of it through the function fixture

If I had to correct your code :

  • The command should be wct --npm -wct-package-name=wct-browser-legacy. Or even better create a wct.conf.js file with the following information :

module.exports = {
    npm:true,
    verbose: true,
    plugins: {
        local: {
            browsers: ["chrome"]
        }
    },
    wctPackageName: "wct-browser-legacy"
};

  • Your test should be modified as following :

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <script src="../node_modules/web-component-tester/browser.js"></script>
    <script src="../src/app.js"></script>
</head>
<body>
    <test-fixture id="helloWorldFixture">
        <template>
            <hello-world>
            </hello-world>
        </template>
    </test-fixture>
    <script>
        suite('<hello-world>', () => {
            let component;
            setup(() => {
                component = fixture('helloWorldFixture');
            });

            test('contains hello world string ?', () => {
                let index = component.innerText.indexOf('Hello');
                assert.isAtLeast(index, 0);
            });
        });
    </script>
</body>
</html>

Please, notice that I used the fixture's id and put the component initialisation in the setup function.



回答2:

Zakaria's answer is good, but I suggest ditching wct-browser-legacy in favor of wct-mocha as it is lighter-weight and doesn't have out-of-date dependencies like old version of lodash and sinon etc.

See the README for full details: https://www.npmjs.com/package/wct-mocha

tl;dr version:

$ npm rm --save wct-browser-legacy
$ npm install --save-dev \
  @webcomponents/webcomponentsjs \
  @polymer/test-fixture \
  wct-mocha \
  mocha \
  chai

You shouldn't need to specify it, but if you have wct.conf.js file you should change an existing wctPackageName entry to:

wctPackageName: "wct-mocha"

Your HTML needs to change a little and you need to make sure mocha is a direct dependency, since wct-mocha will not autoload. You'd also need to do that with chai if you're using chai assertions and @polymer/test-fixture if you use those.

<head>
  <meta charset="utf-8">
  <script src="../node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js"></script> 
  <script src="../node_modules/mocha/mocha.js"></script> 
  <script src="../node_modules/chai/chai.js"></script> 
  <script src="../node_modules/@polymer/test-fixture/test-fixture.js"></script> 
  <script src="../node_modules/wct-mocha/wct-mocha.js"></script> 
</head>