0

I have two components which are related to charts. Component 1 holds number-cards information and Component 2 holds line-graph information.

After clicking on any card in number-card-component we will show line-graph by enabling line-graph-component.

Test Case: Need to click on a button in line-graph-component using jasmine test case.

Issue Facing: As line-graph-component is enabled only after clicking a card in number-card-component I am unable to click the button in line-graph-component.

number-card-component.ts

import { Component, OnDestroy, OnInit } from '@angular/core';
import { ScaleType } from '@swimlane/ngx-charts';
import { BehaviorSubject, Subscription } from 'rxjs';

@Component({
  selector: 'app-number-card',
  templateUrl: './number-card.component.html',
  styleUrls: ['./number-card.component.scss']
})
export class NumberCardComponent implements OnInit {

  cardsData: any[] = [];
  displayChart = false;
  constructor(private service: MyService) { }

  ngOnInit(): void {
    this.getMetricsSubscription = this.service.getNumbers()
      .subscribe((data: any) => {
        this.cardsData = data;
      })
  }

  onSelect(event: any) {
    this.displayChart = true;
  }

}

line-chart-component

import { Component, OnInit } from '@angular/core';
import { ScaleType } from '@swimlane/ngx-charts';

@Component({
  selector: 'app-line-chart',
  templateUrl: './line-chart.component.html',
  styleUrls: ['./line-chart.component.scss']
})
export class LineChartComponent implements OnInit {

  chartContent: any[] = [];
 
  constructor(private service: MyService) {
  }

  ngOnInit(): void {
    this.service.chartInfo.subscribe((chartData) => {
      this.chartContent = chartData;
    });
  }

  closeChart() {
    console.log('chart is closed');
  }
}

number-card-html

<ngx-charts-number-card
  [results]="cardsData"
  (select)="onSelect($event)">
</ngx-charts-number-card>
<app-line-chart *ngIf=displayChart></app-line-chart>

line-chart-html

<ngx-charts-line-chart  [results]="chartContent">
</ngx-charts-line-chart>
<button (click)="closeChart()">Close</button>

jasmine-test-case

import { HttpClientTestingModule } from '@angular/common/http/testing';
import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from '@angular/core';
import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing';
import { of } from 'rxjs';

import { LineChartComponent } from './line-chart.component';
import { NumberCardComponent } from '../summary-card/summary-card.component'

describe('LineChartComponent', () => {
  let component: LineChartComponent;
  let fixture: ComponentFixture<LineChartComponent>;
  let service: Service;
  let cardComponent: ComponentFixture<NumberCardComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      declarations: [LineChartComponent],
      providers: [MyService],
      schemas: [CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA]
    })
      .compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(LineChartComponent);
    cardComponent = TestBed.createComponent(NumberCardComponent);
    service = TestBed.inject(MyService);
    component = fixture.componentInstance;
    fixture.detectChanges();

    spyOn(service, 'getNumbers').and.returnValue(of(
        [
          { name: "Metric 1", value: 877 },
          { name: "Metric 2", value: 111 }
        ]
    ));

  });


  it('on closeChart method ChartData information needs to be reset', fakeAsync(() => {

    fixture.debugElement.nativeElement.querySelectorAll('button')[1].click();
    // component.closeChart();

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

});
Vineel Pellella
  • 332
  • 2
  • 4
  • 20

1 Answers1

0

You're showing a test for LineChartComponent but I think you need a test for NumberCardComponent.

Set up a test for it as well and do the following:

it('should display chart on select', () => {
  const card = fixture.debugElement.query(By.css('ngx-charts-number-card'));
  // first argument is event name, 2nd argument is the $event object mocked
  card.triggerEventHandler('select', {});
  // call detect changes so the HTML updates
  fixture.detectChanges();
  const chart = fixture.debugElement.query(By.css('app-line-chart'));
  expect(chart).toBeTruthy();
});

Check out triggerEventHandler here: https://netbasal.com/simulating-events-in-angular-unit-tests-5482618cd6c6, it is a very well written article.

AliF50
  • 16,947
  • 1
  • 21
  • 37
  • I am having multiple cards under ngx-charts-number-card which when I tried to get unique by using By.css from angular/platform. I am getting null, Can you help me in finding a unique card using By.css Also, I am trying to click a button in the app-line-chart which only visible after the above action, how can I test this in app-line-chart – Vineel Pellella May 11 '22 at 04:38
  • I assume it is written in an `*ngFor` loop for the many cards, you can assign a class related to the index for each element: https://stackoverflow.com/questions/35405618/ngfor-with-index-as-value-in-attribute. To click on a button in `app-line-chart` after the above action, you have to declare `AppLineChartComponent` in the `declarations` array of `TestBed.configureTestingModule({})` so Angular knows how to render/paint it. – AliF50 May 11 '22 at 12:59
  • No, I didn't use ngFor as a number-card from ngx-charts itself creates as many cards as needed based on the data that we provided to it. Reference link: https://swimlane.github.io/ngx-charts/#/ngx-charts/number-card – Vineel Pellella May 11 '22 at 14:01
  • Ok, then add it to the `declarations` array and it should hopefully work or maybe you need to add `NgxChartsModule` to the `imports` array. – AliF50 May 11 '22 at 16:38
  • We are getting weird issues adding NgxChartsModule to imports. Can you suggest an alternative approach? Also fixture.debugElement.query(By.css('ngx-charts-number-card')); how to get unique value from this – Vineel Pellella May 12 '22 at 06:44
  • Sorry, I am not sure about an alternative approach. `query` gets the first element, you can use `.queryAll` to get an array of elements. – AliF50 May 12 '22 at 12:53