Generate Angular component unit tests that involve manipulating the DOM using TypeScript

Currently, I am in the process of developing a UI library in Angular 16. While creating a component like a textarea in my typescript file, I find that manipulating the DOM element at a logical level works smoothly. However, when attempting to write tests, the code consistently breaks at lines where the DOM is involved.

How can I effectively write tests for this scenario?

ts :


@ViewChild('myTextarea') myTextarea!: ElementRef<HTMLTextAreaElement>;

@Input() placeholderLabel?: string = 'label';
@Input() helperText?: string;
@Input() formGroup?: FormGroup;
@Input() formControlName?: string;
@Input() name: string;
@Input() disabled: boolean = false;
@Input() isWrongInput: boolean = false; // deprecated
@Input() hasError: boolean = false;

showHelperText: boolean = false;
showName: boolean = false;
tempPlaceholder: string = '';

ngOnInit(): void {
    if (this.helperText) {
        this.showHelperText = true;
    }
    this.tempPlaceholder = this.placeholderLabel;
}

onFocus() {
    if (!this.disabled) {
        this.showName = true;
        this.placeholderLabel = '';
    }
}

onBlur(event: any) {
    if (!this.disabled) {
        if (event.target.value == "") {
            this.showName = false;
            this.placeholderLabel = this.tempPlaceholder;
        }
    }
}

autoResizeTextarea() {
    const textarea = this.myTextarea.nativeElement;
    textarea.style.height = 'auto';
    textarea.style.height = `${textarea.scrollHeight}px`;

    if (textarea.style.height !== '44px') {
        textarea.style.lineHeight = '24px';
        this.autoResizeTextarea();
        if (textarea.style.height === '80px') {
            textarea.style.lineHeight = '52px';
        }
    }
    if (textarea.style.height === '44px' || textarea.style.height === undefined) {
        textarea.style.lineHeight = '38px';
    }
}

My Spec Test


describe('CaInputTextComponent', () => {
    let component: CaTextAreaComponent;
    let fixture: ComponentFixture<CaTextAreaComponent>;

    beforeEach(() => {
        TestBed.configureTestingModule({
            imports: [
                CaTextAreaComponent,
            ],
        });

        fixture = TestBed.createComponent(CaTextAreaComponent);
        component = fixture.componentInstance;
    });

    // Test to verify component creation
    it('Should create the component', () => {
        expect(component).toBeTruthy();
    });

    // Test to check if the label is displayed in the template
    it('Should display the label in the template', () => {
        component.placeholderLabel = 'Test';
        fixture.detectChanges();
        const labelElement = fixture.nativeElement.querySelector('.input');
        expect(labelElement.placeholder).toContain('Test');
    });

    // Test for onFocus event click
    it('Should emit click event with the correct value', () => {
        const labelElement = fixture.nativeElement.querySelector('.input');
        component.placeholderLabel = 'Test';
        component.onFocus();
        expect(component.placeholderLabel).toEqual('');
        expect(labelElement.placeholder).toEqual('');
    });

    // Test for onBlur event click
    it('Should emit click event with the correct value', () => {
        const labelElement = fixture.nativeElement.querySelector('.input');
        const event = {
            target: {
                value: ''
            }
        };
        component.onBlur(event);
        fixture.detectChanges();
        expect(component.showName).toEqual(false);
        expect(labelElement.placeholder).toBe(component.tempPlaceholder);
    });

    it('Should display helper text correctly', () => {
        component.helperText = 'test';
        component.ngOnInit();
        fixture.detectChanges();
        expect(component.helperText).toEqual('test');
        expect(component.showHelperText).toEqual(true);
    });

    it('Should resize the textarea properly', () => {
        component.myTextarea.nativeElement.value = 'Sss';
        component.autoResizeTextarea();
        expect(component.myTextarea.nativeElement.style.height).toBe(`${component.myTextarea.nativeElement.scrollHeight}px`);
        // Add other expectations based on your specific requirements
    });
});

My Error:

TypeError: Cannot read properties of undefined (reading 'nativeElement') at UserContext.apply...

Line of Error: component.myTextarea.nativeElement.value = 'Sss';

Answer №1

Try using

fixture.debugElement.query(...).nativeElement
for querying the HTML content, it should resolve the issue.

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

Is the window.location.href of a component not inside a router-outlet updated after a router redirect through a guard?

The navigation component I have is positioned outside of the router. It utilizes a reusable icon component that depends on absolute URLs to point to SVG icons, retrieved through a getter within the component: public get absUrl(): string { return windo ...

What is the method for generating an observable that includes a time delay?

Question In order to conduct testing, I am developing Observable objects that simulate the observable typically returned by an actual http call using Http. This is how my observable is set up: dummyObservable = Observable.create(obs => { obs.next([ ...

Assuming control value accessor - redirecting attention

import { Component, Input, forwardRef, OnChanges } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; @Component({ selector: 'formatted-currency-input', templateUrl: '../v ...

Exploring the method of dynamically adding a row to a table on button click using Angular 2

In the midst of my Angular2 project, I am exploring the possibility of dynamically adding rows to a table when a button is clicked. While I am aware that *ngFor can achieve this, I am curious if it can be implemented only upon the clicking of a button. ...

Error message: Unable to locate module (webpack)/hot/emitter when running ionic serve with Ionic 4

Current Technology Stack: Node v10.15.1 Ionic 4.10.1 Upon running ionic serve, an error is encountered: ERROR in (webpack)/hot/emitter.js [ng] Module not found: Error: Can't resolve 'events' in '/zazou/node_modules/@angular-de ...

Issues with responsiveness and calculated attributes in Vue 3 using the Composition API

Within this menu, there are different items: Item 1 (marked as number 1 in orange) with the path: http://localhost:8080/#/documents Item 2 (marked as number 2 in orange) with the path: http://localhost:8080/#/documents/1 Item 3 (marked as number 3 in or ...

Integrate child component properties within the parent component

Looking to create a wrapper component that selects specific props from an inner component and includes additional custom props. The issue is that using pick will generate a type rather than an interface, limiting the ability to add more keys. How can I wor ...

What prevents ts-morph from retrieving the classes within a TypeScript project?

Utilizing ts-morph, I am examining the inheritance relationships of classes in a project: For testing purposes, I have downloaded an open-source projectantv/x6: import { Project } from "ts-morph"; const project = new Project(); project.addDire ...

The Heart of the Publisher-Subscriber Design Paradigm

After reading various online articles on the Publisher-Subscriber pattern, I have found that many include unnecessary domain-specific components or unreliable information inconsistent with OOP standards. I am seeking the most basic and abstract explanatio ...

Steps to resolve the error message 'Uncaught Error: Unable to find all parameters for AuthService: (?)'

An issue is arising when the application is initiated. No errors are displaying in the terminal, but they appear in the browser console. The last action taken was importing JwtHelperService from '@auth0/angular-jwt'. The project involves Nodejs, ...

Can you explain the significance of using square brackets in the typescript enum declaration?

While reviewing a typescript file within an Angular ngrx project titled collection.ts, I came across the declaration of enum constants. import { Action } from '@ngrx/store'; import { Book } from '../models/book'; export enum Collecti ...

Even with the use of setTimeout, Angular 5 fails to recognize changes during a lengthy operation

Currently, I am facing an issue with displaying a ngx-bootstrap progress bar while my application is loading data from a csv file. The Challenge: The user interface becomes unresponsive until the entire operation is completed To address this problem, I a ...

MongoDB Node.js throws a RangeError when trying to push a message that exceeds the maximum call stack size

I'm currently delving into the world of building a MEAN app and encountering an issue when attempting to append a message to a messages array within my User Model. While I can successfully create a new message and pass the user object, I face an error ...

Is it possible to modify a single value in a React useState holding an object while assigning a new value to the others?

In my current state, I have the following setup: const [clickColumn, setClickColumn] = useState({ name: 0, tasks: 0, partner: 0, riskFactor: 0, legalForm: 0, foundationYear: 0 }) Consider this scenario where I only want to update ...

Emphasize a Row Based on a Certain Criteria

One of the challenges I am facing is how to emphasize a specific row in a table based on certain conditions. Currently, I am utilizing Jqxgrid and have made some modifications in the front-end to achieve the highlighting effect: TypeScript: carsDataAgain ...

Modifying the status of a RadDataForm Switch editor through code

I'm working on a new angular + nativescript project that relies on the RadDataForm plugin to create forms. I have set up a source object to initialize the form editors, which is functioning correctly. One of the editors is a switch element that I want ...

Swapping out a class or method throughout an entire TypeScript project

Currently, I am working on a software project built with TypeScript. This project relies on several third-party libraries that are imported through the package.json file. One such library includes a utility class, utilized by other classes within the same ...

Zod Entry using standard encryption key

I'm attempting to define an object type in zod that looks like this: { default: string, [string]: string, } I've experimented with combining z.object and z.record using z.union, but the validation results are not as expected. const Local ...

Updating the date format of [(ngModel)] with the ngx-datepicker library

One of the challenges I'm facing is dealing with a web form that captures date of birth. To accomplish this, I'm utilizing the ngx-bootstrap version 2.0.2 datepicker module. The issue I encounter lies in the fact that my API only accepts date val ...

What is the best way to organize class usage within other classes to prevent circular dependencies?

The engine class presented below utilizes two renderer classes that extend a base renderer class: import {RendererOne} from "./renderer-one"; import {RendererTwo} from "./renderer-two"; export class Engine { coordinates: number; randomProperty: ...