Is it possible for Angular Jest to mock HTMLElement even though it is not registered as a custom element?

I have been working on unit testing a directive in Angular 11 using Jest 28. In order to simulate a click event on an image, I have written the following code snippet to mock the mouse event:

import { HTMLClickDirective } from "./html-click.directive";

describe('HTMLClickDirective', () => {
  it('should trigger a lightbox for images when clicked', () => {
    const directive = new HTMLClickDirective(null);
    
    const image = new HTMLImageElement;
    image.setAttribute('src','foo');
    let click = {target: image} as unknown as MouseEvent;
    
    directive.onClick(click);
    expect(directive.openLightbox).toHaveBeenCalled();
  });
});

Even though TypeScript does not indicate any errors, Jest throws the following complaint: "TypeError: Invalid constructor, the constructor is not part of the custom element registry".

A similar error occurs when attempting to create an HTMLElement and then casting it to an HTMLImageElement. Moreover, if I try creating a new Element for future type coercion, Jest complains about an "Illegal constructor".

The issue persists even when moving the variable assignment outside the describe block.

Could this be related to JSDOM?

Edit: here is the Directive under test:

import { Directive, HostListener } from "@angular/core"
import { BsModalRef, BsModalService } from "ngx-bootstrap/modal"
import { ModalLightboxComponent } from "../components/shared/modal-lightbox/modal-lightbox.component";

/**
 * This directive handles click events on HTML elements within safe HTML content projections.
 * 
 * @example
 * html
 * <div [innerHTML]="..." HTMLClick></div>
 * 
 */
@Directive({
  selector: "[HTMLClick]",
})
export class HTMLClickDirective {
  modalRef: BsModalRef;
  constructor(
    private modalService: BsModalService,
  ) {}

  /**
   * Listens for click events on any HTMLElement.
   */
  @HostListener("click", ["$event"])
  onClick($event: MouseEvent) {
    const target = $event.target as any

    switch (target.constructor) {
      case HTMLImageElement:
        $event.preventDefault()
        this.handleImageElement(target)
        break;
      case HTMLElement:
        $event.preventDefault()
        this.handleElement(target)
        break;
      default:
        break;
    }
  }

  openLightbox(img: string) {
    this.modalRef = this.modalService.show(ModalLightboxComponent, {
      animated: false,
      class: 'lightbox',
      initialState: {
        modalPath: img,
        closeModal: this.closeModal.bind(this),
      }
    });
  }
  closeModal() {
    this.modalRef?.hide();
  }
  
  private async handleImageElement(target: HTMLImageElement): Promise<void> {
    this.openLightbox(target.getAttribute('src'));
  }
  private async handleElement(target: HTMLElement): Promise<void> {
    console.log(target)
    if(target.nodeName === 'STRONG') document.querySelector('[id="' + target.innerText.toLowerCase() + '"]').scrollIntoView();
  }
}

Answer №1

const picture = document.createElement('img');

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the functionality of react-table v7.7.9 when utilizing global filtering in a TypeScript environment?

My react-table component is functioning smoothly in typescript. const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable( { columns, data } ); I am interested in implementing global filtering. When I incorporate the pl ...

Combining and Filtering Arrays of Objects with Angular

I possess: arrayBefore arrayBefore = [{name:'n1', items: [i1]}, {name:'n2', items: [i2]}, {name:'n1', items: [i3]}] I desire to craft a function: myFunction myFunction(arrayBefore) In order for it to generate: arrayAfte ...

Using React.PureComponent, the list component efficiently renders each item with optimized performance

We've developed a reusable list component in ReactJS. To address performance concerns, we decided to incorporate the shouldComponentUpdate method to dictate when our list component should re-render. public shouldComponentUpdate(nextProps: TreeItemInt ...

Learn how to leverage Angular 4's ngComponentOutlet to dynamically pass values from an array

Check out this Plunker demo: https://plnkr.co/edit/JvXBLOVaeaYO5bmMQa6a?p=preview In the Plunker example, I have created 3 boxes using an ngFor loop from an array. Each box has its own event listener attached to it. The goal is to generate a component whe ...

Struggling to execute the "Protractor test cases on Firefox browser" for an "angular 4 web application"

Having recently started using the Protractor tool, I am facing a challenge running my test script in multiple browsers - it only seems to work in Chrome. Here are the versions I am using: Node: v6.11.3 NPM: 3.10.10 Protractor: 5.1.2 My goal is to autom ...

Error: The function parentSubmit does not exist

Hello, I am currently in the process of converting a redux-forms TypeScript class component into hooks. Here is the original class-based component that will eventually be converted to hooks: import React from 'react'; import { connect } from &ap ...

Displaying maximum number of items in each row using ngFor

Is there a way to automatically create a new row within the 'td' element after the ngFor directive has generated 10 image repeats? Currently, all the images are displayed in a single td and as more images are added, they start to shrink. <td ...

Using the differences of discriminated unions

Consider the scenario where discriminated unions and associated types are defined as follows: type Union = 'a' | 'b'; type Product<A extends Union, B> = { f1: A, f2: B}; type ProductUnion = Product<'a', 0> | Produ ...

Not all Angular Material2 styles are being fully applied

One issue I am encountering is that styles for components such as <mat-chip> or <button mat-raised-button> (the only ones I have found) are not working properly and appear gray by default. However, styles do apply correctly to the <mat-card& ...

Error message "route is not defined" appears during Angular 2 deployment on IIS using Visual Studio 2015

Currently, I have a .Net Core project in Visual Studio 2015 (update 3) that utilizes Angular 2. It runs smoothly within Visual Studio using IIS Express on my Windows 10 professional PC. However, upon attempting to deploy the application to my local IIS ins ...

Is there an equivalent concept to Java's `Class<T>` in TypeScript which allows extracting the type of a class constructor?

I'm in need of a feature similar to the Class functionality in Java, but I've had no luck finding it. Class<T> is exactly what I require. I believe it could be named NewableFunction<T>. However, such an option does not exist. Using M ...

The service method call does not occur synchronously

In my OrderServer class, I am utilizing an OrderService to connect to a database and retrieve data every minute. The communication with the web app is handled through SocketIO. Here is a snippet of the code: export class OrderServer { // some required fie ...

Obtaining the result of an Angular Service method using subscribe and storing it in a

I have a function within a service that subscribes to an event, rather than the component. The data from this event is stored in message.content. Take a look at the code: Service Function: myMethod() { this.socket$.subscribe( (message) => ...

Experiencing constant errors with axios requests in my MERN Stack project using a Typescript Webpack setup

Hey there, I'm in need of some help! I've been working on a MERN Stack project and have set up Webpack and Babel from scratch on the frontend. However, every time I send a request to my Node Server, I keep getting an error message back. Can anyon ...

What is the best way to play AudioBuffer on an iPhone device?

When retrieving audio data from a stream, I encounter an issue with playing audio on iPhone Safari. The sound does not play unless I allow mediaDevice access for audio. Is there a way to play the audio without having to grant this permission? This is the ...

The issue of returning a boolean value in an rxjs function leading to failure

Hey there, I am currently learning about rxjs and I want to create an observable that returns either true or false. This is my attempted code: checkLoggedIn(): Observable<boolean> { // Check with the server if the user is logged in if(this._tok ...

What is the best way to initiate an HTTP POST request in Ionic 2 (typescript) while including parameters in the form of a multipart/form-data

My webservice, which is generated with the Drupal 7 plugin Service, accepts requests on ''. These requests are checked against an 'api-key' variable, acting as a password. When attempting to connect to the service using my Ionic2/Cordo ...

Webpack, TypeScript, and modules are set to "esnext," resulting in a change to undefined

In my setup, I am using webpack with typescript (via ts-loader). To enable code splitting in webpack, it is necessary to adjust the module setting to esnext in the tsconfig file: // tsconfig.json { "compilerOptions": { "module": ...

How to define an object type in Typescript without specifying types for keys in order to access keyof

Is there a way to define the type for object keys without individually defining types for each value? const sizes: Record<string, CSSObject>= { md: { padding: [10, 24], fontSize: 'medium', }, xs: { padding: [6, 12], f ...

conceal a div in Angular when the user is authenticated

One of my tasks involves managing the visibility of a div based on whether the user is logged in. This functionality is achieved by utilizing an authentication service in Angular and tokens from Django. Component.html <a *ngIf="authService.isLoggedIn( ...