ReferenceError: customElements is not defined
Asked Answered
I

4

11

I'm using @[email protected], @ngneat/[email protected] (with Jest), [email protected] in a project and everything works on application when I run ng serve or even ng build, but it fails when I try to run a test suite for a @Pipe that uses Inputmask:

@Pipe:

import { Pipe, PipeTransform } from '@angular/core';

import Inputmask from 'inputmask';

@Pipe({
  name: 'appSomePipe',
})
export class SomePipe implements PipeTransform {
  transform(value: string): string {
    return Inputmask.format(value, {
      jitMasking: true,
      mask: '1111-1',
    });
  }
}

@Spec:

import { createPipeFactory, SpectatorPipe } from '@ngneat/spectator/jest';

import { SomePipe } from './some.pipe';

describe('SomePipe', () => {
  let spectator: SpectatorPipe<SomePipe>;
  const createPipe = createPipeFactory(SomePipe);

  it('test', () => {
    spectator = createPipe(`{{ '11111' | appSome }}`);
    expect(spectator.element).toHaveText('1111-1');
  });
});

When I run ng test, it shows:

ReferenceError: customElements is not defined

  2 | 
> 3 | import Inputmask from 'inputmask';

PS: This error just appears for Angular 9, in Angular 8 all tests were successfully passed.

Its answered 19/3, 2020 at 16:20 Comment(0)
T
11

A quick search into inputmask repository shows that it uses customElements which is a feature implemented by modern browsers in order to create native web components (without a framework).

When looking at Jest documentation we can see that the default testEnvironment is jsdom, which is an implementation of the DOM that runs without a browser. This library implements custom elements since version 16.2.0 and this version is pretty recent, and is not yet used by jest (the last version of jest uses jsdom v15.1.1).

So you just have to wait for jest to update the jsdom dependency, and then update your project to use the latest version of jest.

Another option: you can use jest-browser which runs Jest in a headless browser based on puppeteer.

Update 05-2020:

Upgrade to (at least) Jest 26.0.0 which uses jsdom 16.2.0 (Source)

Traditor answered 21/3, 2020 at 20:31 Comment(3)
Thanks. As I said, the problem started to occur after package updates (Angular [8x -> 9x], Spectator [4x -> 5x], Jest [15x -> 16x] and many others) and, for some reason, I thought automatically that the problem was with the new versions of Angular or Spectator, completely forgetting Jest. Anyway, after downgraded Jest version to 15x everything went back to working as before. I hope they fix it ASAP in 16x.Its
Glad it helped!Traditor
Ah, I almost forgot... after fixing this problem with Jest, I had to change the import from import Inputmask from 'inputmask'; to import { format } from 'inputmask'; to make it work properly on Angular 9.Its
E
4

jsdom does not support customElements until v16.2.0 as Guerric P wrote.

To get jest running with jsdom v 16 you need to do the following

yarn add jest-environment-jsdom-sixteen

Then in you jest.config.js add this

module.exports = {
  testEnvironment: 'jest-environment-jsdom-sixteen',
  ...
}

this will force jest to use a newer implementation. and this should solve your problem.

Edmundson answered 26/3, 2020 at 19:35 Comment(0)
R
0

I remember stumbling upon your question and I stumbled upon something else related to ngx-bootstrap with regards to an import not working in Angular 9.

https://valor-software.com/ngx-bootstrap/#/datepicker

Check out the usage section and its warning about Angular 9.

Try doing import InputMask from 'inputmask/somethingMoreSpecificHere'; or `import { somethingSpecificHere } from 'inputmask';

Recidivate answered 19/3, 2020 at 18:29 Comment(1)
Thanks for your answer, but unfortunately it doesn't work either. I tried import { format } from 'inputmask' and it shows the same error :/. import InputMask from 'inputmask/somethingXXX' isn't possible.Its
O
-2

The problem is that you are not injecting the Inputmask dependency into your test.

This is because you are using a javascript import. There are Angular libraries to do this (ngx-mask).

In Angular we use Dependency Injection with IOC, so for this example I'll use an InputMaskService to create the angular dependency.

Pipe

import { Pipe, PipeTransform } from '@angular/core';

import { InputMaskService } from './inputmask.service';

@Pipe({
  name: 'appSomePipe',
})
export class SomePipe implements PipeTransform {

  constructor(private inputMaskService: InputMaskService){}

  transform(value: string): string {
    return this.inputMaskService.format(value, {
      jitMasking: true,
      mask: '1111-1',
    });
  }
}

Note that I'm injecting the service in the constructor and using that instance in the transform method.

Test

You can create an instance of your pipe passing the service reference

beforeEach(() => {
  const inputMaskService = new InputMaskService();
  const pipe = new SomePipe(inputMaskService);
});
Ogletree answered 26/3, 2020 at 8:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.