Test the HTML element using ngIf async call in Angular 2 with Jasmine unit testing

As I work on writing unit tests for an HTML div with a condition using *ngIf, I come across a specific scenario.

<div *ngIf="clientSearchResults$ | async  as searchResults" class = 'fgf'  #datalist id="mydata" >
  <app-client-list id="clientDataTable1" class="clientDataTable dataTable" [clients]='searchResults'></app-client-list>
</div>

The *ngIf condition becomes true when data is received from the ngrx store, as explained in the component code snippet below.

searchData(client: Client) {
      //// some conditions
      this._clientService.getClientList()
     .subscribe(data => {
      const filteredData = this.filterData(data, client);
      this.isDataFound = filteredData !== null && filteredData.length > 0;
      this.testbool = true;
      /// The div element is filled with data using the async condition here.
      this.store.dispatch(new SetClientSearchResultsAction(filteredData));

    });
}

When writing the unit test case for this scenario, I encountered an issue.

it('should search the data with valid client passed from UI', async(() => {
    let debugFixture: DebugElement = fixture.debugElement;
    let htmlElement: HTMLElement = debugFixture.nativeElement;
    let clientListGrid = htmlElement.getElementsByClassName('fgf');
    let testbool= htmlElement.getElementsByClassName('testbool');

    spyOn(component, 'searchData').and.callThrough();
    spyOn(component, 'filterData').and.returnValue(CLIENT_OBJECT);
    spyOn(clientService, 'getClientList').and.callThrough();

    console.log("=========before======="+ clientListGrid.length);

    component.searchData(validClient);
    component.clientSearchResults$ = store.select('searchResults');
    fixture.detectChanges();
    debugFixture = fixture.debugElement;
    htmlElement = debugFixture.nativeElement;
    clientListGrid = htmlElement.getElementsByClassName('fgf');

    console.log("=========after ======="+ clientListGrid.length);

    expect(component.searchData).toHaveBeenCalled();
  }));

The issue lies in the fact that the console logs a length of 0 both before and after calling the function, when it should be 1 after receiving data from the store. This discrepancy is attributed to the *ngIf condition,

*ngIf="clientSearchResults$ | async  as searchResults"
.

Even though data loads into the div, I struggle with testing this aspect in the unit test. Any suggestions on how to tackle this?

Answer №1

Although I may be a little late in responding, there is still a chance that someone will come across this in the future.

I faced a similar issue due to a bug in Angular testing. The problem arose because the change detection was not being triggered when a new value was passed to an input in components with the ChangeDetectionStrategy set to OnPush.

To resolve this issue, you will need to override it in the Testing module:

TestBed.configureTestingModule({
  ... include your declarations and providers here
})
.overrideComponent(ComponentYoureTesting, {
  set: { changeDetection: ChangeDetectionStrategy.Default }
})
.compileComponents();

By making these changes, the issue should be resolved.

Answer №2

Here is a possible solution:

it('tests data search functionality with valid user input from the UI', fakeAsync(() => {
  // ---
  tick();
  fixture.detectChanges();
  // --- 
  expect(component.searchData).toHaveBeenCalled();
}));

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

Modifying an onClick handler function within a react element located in a node module, which points to a function in a prop declared in the main Component file

I have successfully implemented the coreui CDataTable to display a table. return ( <CDataTable items={data} fields={fields} ... /> ) Everything is working smoothly, but I wanted to add an extra button in the header of the C ...

Using an object-key value array with *ngFor in Angular 7

I am trying to populate an array of objects in a table, but the changes are not being displayed as expected. <ng-container *ngFor="let file of err_data "> <tr> <td>{{file.details.commodity_name}}</td> <t ...

Function exported as default in Typescript

My current version of TypeScript is 1.6.2 and we compile it to ECMA 5. I am a beginner in TypeScript, so please bear with me. These are the imported library typings. The contents of redux-thunk.d.ts: declare module "redux-thunk" { import { Middle ...

Angular's Reactive forms: The power of bidirectional binding

Struggling with Reactive forms? I've encountered an issue where updating the model class when a User changes the input is easy, but what about programmatically changing the model and reflecting those changes in the HTML form? In simplified terms: th ...

Get the latest B2B department for the client within Spartacus

How can I display the current B2B Unit name in the header for the customer? I have been exploring ways to retrieve the B2B Unit for the current customer and found that there is a payload available for the /current? endpoint that loads on the initial page ...

Navigating between routes in Angular can lead to multiple subscriptions being created

One issue I've encountered is receiving multiple subscriptions as I switch between routes in my Angular application. Within my parent component, I have defined the following routes: <li routerLink="route1" [routerLinkActive]="[&apos ...

Angular 2: Changing the name of a component

Looking for guidance on renaming a component in my Angular2 application. I've already updated all the necessary files - changed the file names and folder name, as well as made adjustments to specific files such as y.component.ts, app.routing.ts, and a ...

Retrieving the attribute key from a dynamically typed object

Having this specific interface structure: interface test { [key: string]: string } along with an object defined as follows: const obj: test ={ name: 'mda', telephone: '1234' } Attempting to utilize this object in a variab ...

The angular framework is unable to assign a value to the property 'xxxx' because it is currently undefined

I am currently working on a simple application using Ionic (angular) and I am facing an issue with the error message: Cannot set property 'origin' of undefined Below is the interface for Product.ts: export interface Products{ id: number ...

Is it necessary to wait for the resolve function when using hooks in SvelteKit?

i have implemented this handle function for SvelteKit hooks and since it returns a promise of response, the resolve function does not necessarily need to be awaited. This is because it is a function that either directly returns a value or returns a promise ...

Setting limits to disable or remove specific times from the time picker input box in Angular

I'm having trouble with a time input box. <input type="time" min="09:00" max="18:00" \> Even though I have set the min and max attributes to values of 09:00 and 18:00 respectively, it doesn't seem to be working properly. I want to ...

How can I bypass additional ngIf checks in the Angular template if a variable is null?

I have this code snippet in my template: <div class="icon-action" *ngIf="node == null ? false : node.data && node.data.name && !node.parent.data.virtual" (click)="delete(node)"> ...

Type returned by a React component

I am currently using a basic context provider export function CustomStepsProvider ({ children, ...props }: React.PropsWithChildren<CustomStepsProps>) => { return <Steps.Provider value={props}> {typeof children === 'function&ap ...

Experiencing difficulty in triggering a NextUI Modal by clicking on a NextUI Table Row

In the process of developing my web portfolio, I am utilizing NextJS, TypeScript, and TailwindCSS. A key feature on my site involves displaying a list of books I have read along with my ratings using a NextUI table. To visualize this functionality, you can ...

How can I identify the nearest ancestor based on a specific class in Angular 8?

In order to achieve a specific goal, let's imagine this scenario: Object A Object B Object C Object D Object D represents my angular component. It is important for me to adjust its height based on the heights of Object A and Object B. Regardle ...

Fetching data from one component to load an Angular component

Essentially, I have a grid within Ionic that dynamically populates its rows using ngFor. Each row contains an ionic button labeled "View details" which, when clicked, should display all the data associated with that specific object. Imagine it as a preview ...

In Angular 2, if one HTTP call is dependent on another, ensure to retry all calls if one fails for seamless operation

I have a situation with this Angular 2 code where it first makes an http call to './customer.json' and then uses the returned URL to make another call. I want to implement retry functionality for both calls using the rxjs retry method. Currently, ...

Obtaining an instance of the CKEditor Editor in TypeScript with CKEditor 4: what's the best way?

Can someone explain how to utilize the CKEDITOR 4 plugin in TypeScript for an Angular 9 application? I am looking to set the configuration through TypeScript (specifically for autogrow) and also implement an INSERT HTML function. I have already imported ...

What is the syntax for calling a Component located in a sub-folder in Angular/Ionic?

I have a custom component located in /app/components/my-component When the component is in the app/ directory, I can easily reference it like this: <app-my-component></app-my-component> and it functions properly. However, when I move the comp ...

Angular Error: Unable to access the 'title' property of an undefined value

Error Message Showing on Console for post-create.component.html ERROR Message: TypeError: Cannot read property 'title' of undefined at PostCreateComponent_Template (template.html:13) I suspect the issue is related to this line - console.log(for ...