Encountering the ExpressionChangedAfterItHasBeenCheckedError error during Karma testing

Testing out some functionality in one of my components has led me to face an issue. I have set up an observable that is connected to the paramMap of the ActivatedRoute to retrieve a guid from the URL. This data is then processed using switchMap and assigned to a component variable. The information fetched is displayed on the view, and everything appears to be functioning correctly when running the app via the CLI.

However, when attempting to run tests for the component, I encounter the ExpressionChangedAfterItHasBeenCheckedError in Karma's browser tab.

The error seems to stem from the fact that I am modifying the value of the isBranded variable, which is essential for displaying the appropriate logo in the view.

https://i.sstatic.net/cqk4p.png

This is the code snippet for my component:

@Component({
    selector: 'app-digital-payment',
    templateUrl: './digital-payment.component.html',
    styleUrls: ['./digital-payment.component.scss']
})
export class DigitalPaymentComponent implements OnInit {
    cdnUrl = environment.cdnUrl;
    isBranded = false;

    payment$: any;

    constructor(private service: DigitalPaymentService, private activeRoute: ActivatedRoute) {

    }

    ngOnInit() {
        this.payment$ = this.activeRoute.paramMap.pipe(switchMap((params: any) => {
            let guid = params.get('guid');

            return this.service.checkPaymentStatus(guid).pipe(map((data: any) => {
                this.isBranded = data.isBranded;

                return data;
            }));
        }));
    }
}

Here is how the view is structured:

<header>
    <a class="logo">
        <img src="{{ cdnUrl }}/Image/not-branded-logo.svg" alt="Not Branded Logo" />
    </a>
    <a class="logo pull-right text-right" *ngIf="isBranded">
        <img src="{{ cdnUrl }}/Image/branded-logo.svg" alt="Branded Logo" />
    </a>
</header>

<section>
    <div class="payment-status {{ payment.class }}" *ngIf="payment$ | async as payment; else loading">
        <mat-icon *ngIf="payment.icon">{{ payment.icon }}</mat-icon>
        <h1>{{ payment.heading }}</h1>
        <p>{{ payment.text }}</p>
    </div>

    <ng-template #loading>
        <h1 class="loading-heading">Loading</h1>
        <p>Please wait until your request has been executed.</p>
    </ng-template>
</section>

Now, let's take a look at the Service:

@Injectable({
    providedIn: 'root'
})
export class DigitalPaymentService {
    private apiUrl: string = 'digitalpaymentexternal/';
    private statusBinding = {
        Success: {
            class: 'success',
            icon: 'check_circle_outline',
            heading: 'Successful',
            text: 'Your payment plan has been confirmed.'
        },
        Failed: {
            class: 'fail',
            icon: 'highlight_off',
            heading: 'Transaction failed',
            text: 'Please try a different payment method.'
        },
        Invalid: {
            class: 'fail',
            icon: 'error_outline',
            heading: 'Incorrect link',
            text: 'This link is invalid or it has been expired.'
        }
    };

    constructor(private requester: RequesterService) { }

    checkPaymentStatus(guid): Observable<any> {
        return this.requester.post<void>(this.apiUrl + 'CheckPaymentStatus', guid).pipe(map((data: any) => {
            return { ...this.statusBinding[data.status], isBranded: data.isBranded };
        }));
    }
}

Lastly, here is the test code for the component:

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

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            declarations: [DigitalPaymentComponent],
            providers: [
                {
                    provide: DigitalPaymentService,
                    useValue: {
                        checkPaymentStatus: guid => of({ isBranded: true })
                    }
                },
                {
                    provide: ActivatedRoute,
                    useValue: {
                        paramMap: of(convertToParamMap({ guid: '00000000-0000-0000-0000-000000000000' }))
                    },
                },
            ]
        }).compileComponents();
    }));

    beforeEach(() => {
        fixture = TestBed.createComponent(DigitalPaymentComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
    });

    it('should create', () => {
        expect(component).toBeTruthy();
    });
});

Answer â„–1

One potential solution is to include this.cdr.detectChanges(); within either ngOnInit() or ngAfterViewInit(). The variable cdr stands for ChangeDetectorRef.

constructor(..., private cdr: ChangeDetectorRef) {}

ngOnInit() {
    ...
    // To prevent the ExpressionChangedAfterItHasBeenCheckedError issue during karma testing
    this.cdr.detectChanges();
}

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

Differences between Angular TS Lint onInit and ngOnInit

My TS Lint issue warned me to implement the OnInit interface and included a link to this page: https://angular.io/docs/ts/latest/guide/style-guide.html#!#09-01 I'm curious, what sets apart `onInit` from `ngOnInit`? Both seem to work just fine for me. ...

Tips for centering text inside a div using a separator

During my side project, I decided to use the angular material divider but encountered issues with aligning the text correctly. https://i.stack.imgur.com/zg1mu.png The problem can be seen in the image provided - the text on the right side is not aligned b ...

Generate a custom string to reference a JSON object containing a variable from an Angular HTML document

I am trying to generate a string within my HTML file to access data from a JSON object. HTML File <app-banner></app-banner> <section id="mail-view" class="bg-gray" > <div class="container"> <figure id="state-stats" class= ...

Learn how to selectively hide the header from the root layout on a single page in Next.js version 14

I am currently working on an app using Next.js 14 and TypeScript. In my root layout, I have added a header and footer. However, on one of the pages I created, I need to hide the header and footer. import type { Metadata } from "next"; import { In ...

An error has occurred: Inconsistency found in metadata versions for angular2-flash-messages

I am currently following the Traversy Media MEAN stack front to back playlist on YouTube. However, I encountered an error after importing the flash-messages and I'm having trouble understanding it. I have tried looking at some GitHub issue pages, but ...

Mastering the Implementation of Timetable.js in Angular with TypeScript

I am currently working on integrating an amazing JavaScript plugin called Timetable.js into my Angular6 project. You can find the plugin here and its repository on Github here. While searching for a way to implement this plugin, I stumbled upon a helpful ...

The modal remains closed: Error - Attempting to access property 'open' of undefined

I've been attempting to showcase a pop-up that I implemented as a modal, but I keep getting this error: TypeError: Cannot read property 'open' of undefined The pop-up was created as a component: import { Component, OnInit, ViewChild, Ele ...

Challenge involving Angular for creating multiline innerHtml contentEditable feature

I am currently working on a project using Angular5 to create a unique type of "text-editor" utilizing div elements with the contenteditable property. This setup allows users to input plain text, but also enables them to select specific text and trigger an ...

What's Causing the UNMET PEER DEPENDENCY Error in Angular 8 with @angular/[email protected]?

After updating to the latest version of Angular 8, everything seems to be working fine without any issues. However, I am seeing some strange messages when running npm list after completing npm install: UNMET PEER DEPENDENCY @angular/<a href="/cdn-cgi/ ...

Utilizing Foundation and jQuery in a Next.js web development project

I've been attempting to incorporate Zurb Foundation's scripts into my next js application, but I keep encountering an error message when trying to include the Foundation core. The error I'm seeing is: /Users/alasdair_macrae/Sites/merlin/spa_ ...

Having trouble parsing the ICU expression. Utilizing angular for internationalization

I need to convert an array of left-menu items into another language, and I am encountering an error in my code. Here is the snippet: left-menu.component.html <ng-container *ngFor="let m of menuItems; let last = last"> <a mat-list-it ...

Angular5: At what point does Angular finish loading a page?

Within my angular5 application, I have implemented a table that retrieves data from the backend. After the initial load of the table, I aim to adjust the scroll position inside it. To achieve this, I am utilizing the following code: ngAfterViewInit() { ...

Ionic 4: Facing issues with setting complete background image on ion-card

https://i.stack.imgur.com/3lH6h.png I'm currently attempting to set a background image for an Ion-card in order to completely cover the card's area. However, I'm facing an issue where the background image does not cover the entire area and ...

Retrieve a formatted item from a JSON document

Within my Next.js project, I have implemented a method for loading translations and passing them into the component. Here is an example: import "server-only"; import i18nConfig from "../../i18n-config"; const dictionaries = { en: () ...

Using a custom validator in Angular that accepts an array as input

My special code: <input mdInput [mdAutocomplete]="auto" [(ngModel)]="formData.areaName" (keyup)="updateFilteredAreas(formData.areaName)" class="form-control {{areaName.errors ...

Leveraging Json data in Angular components through parsing

I am currently developing an angular application where I need to retrieve and process data from JSON in two different steps. To start, I have a JSON structure that is alphabetically sorted as follows: { "1": "Andy", "2": &qu ...

Enhancing TypeScript type definitions for the Response.render() method in Express

Struggling with enhancing the type safety of my Express project by extending the Response.render function. import { Response } from "express"; import { Product } from "../models/Product.interface"; export interface ProductListResponse ...

What is the method for extending props from React.HTMLProps<HTMLButtonElement>?

"react": "^17.0.2", "typescript": "^4.2.4" Can someone help me understand how to extend props from React.HTMLProps? import { FC, HTMLProps } from 'react' export interface SliderButtonProps extends HTMLPro ...

Discover the steps to obtain the css class md-inputfield within primeng by referencing the code: <span class="md-inputfield ">

Sorry for the inconvenience, but I am having trouble locating the md-inputfield class in primeng. It is crucial for me to have access to that class attributes in order to properly debug the text field. Is there any chance of resolving this issue and maki ...

Determining if a component is nested within itself in Angular 6 is a crucial task

My goal is to develop a custom Angular component for a nested navigation menu with multiple levels. Below is an example of how the menu structure looks: app.component.html <nav-menu> <nav-menu-item>Section 1</nav-menu-item> <nav- ...