How to perform unit tests for custom elements in Jest using JSDom
Asked Answered
N

1

7

I realise that this question has been asked on a number of occasions, though the environment has changed since those questions where asked: notably, JSDom now supports custom elements.

These other questions revolved around seeking alternatives (such as using Happy Dom) as JSDom did not support custom elements at that time. However, now that JSDom does support custom elements, does anyone have any information that can solve the following error?

TypeError: Class constructor HTMLElement cannot be invoked without 'new'

  1 | export default class Foo extends HTMLElement {
  2 |   constructor() {
> 3 |     super();
    |     ^
  4 | 
  5 |     this._clicker = 2;
  6 |   }

at new Foo (__tests__/fooclass.js:3:5)     
at Object.<anonymous> (__tests__/fooclass.test.js:7:13)

Current setup:

A reference repo is available here (now fixed):

Custom element example

class Foo extends HTMLElement {
  constructor() {
    super();

    this._clicker = 2;
  }

  connectedCallback() {
    this.textContent = 'My Foo Bar Element';
  }

  get testCallback() {
    return 'hello world!';
  }

  set clicker(num) {
    this._clicker = Number(num);
  }

  get clicker() {
    return this._clicker;
  }
}

packages.json

{
  "scripts": {
    "test": "jest --env=jest-environment-jsdom-sixteen"
  },
  "jest": {
    "verbose": true
  },
  "devDependencies": {
    "@babel/preset-env": "^7.8.4",
    "babel-plugin-transform-builtin-classes": "^0.6.1",
    "jest": "^25.1.0",
    "jest-environment-jsdom-sixteen": "^1.0.2"
  }
}

.babelrc

{
  "presets": ["@babel/preset-env"]
}
Necrotomy answered 26/2, 2020 at 13:13 Comment(0)
N
2

NOTE: As of May 2020, Jest supports JSDom 16.* by default, rendering the below no longer necessary or relevant

Solution

Jest runs with JSDom ^15.1.1 by default (as of Feb 17th, 2020) so you will need to update manually to use JSDom 16.2.0 installing jest-environment-jsdom-sixteen.

First, install the latest JSDom environment for Jest

npm i jest-environment-jsdom-sixteen --save-dev

And change your package.json to include:

"scripts": {
  "test": "jest --env=jest-environment-jsdom-sixteen"
},

This will ensure that Jest is running the correct environment.

You will also need to ensure that Babel correctly handles built-in classes (e.g. class HTMLElement {}) by installing babel-plugin-transform-builtin-classes, like so:

npm i babel-plugin-transform-builtin-classes --save-dev

And added to your .babelrc the following

"plugins": [
  ["babel-plugin-transform-builtin-classes", {
    "globals": ["Array", "Error", "HTMLElement"]
  }]
]

Do not install babel-plugin-transform-es2015-classes as this already forms part of the Babel 7 core, as per this issue

Working reduced test case available here.

Necrotomy answered 26/2, 2020 at 13:13 Comment(3)
As of Jest version 26 this is no longer required: github.com/facebook/jest/blob/master/packages/…Mercier
I am running jsdom 16+ and still getting the error reported in the original question.Abrams
@Sam152 it may be worth you asking as a new question with a minimum reproduction, as it could be any number of factors causing the issue. I'd recommend sharing the relevant parts of your package.json and your babel config (as that can cause conflicts with Jest - as per original answer)Necrotomy

© 2022 - 2024 — McMap. All rights reserved.