DevExtreme Angular - Components Testing

Projects created with Angular CLI have built-in testing support with the Jasmine test framework.

View on GitHub

Unit Testing

Unit testing allows you to test single features (units of the code). A unit can be a function or class.

The example below illustrates how to create a unit test for the DataGrid UI component.

To get started, create an Angular application and add DevExtreme. Then, add the following imports:

app.component.spec.ts
app.modules.ts
// Import dependencies
import { TestBed } from '@angular/core/testing';
import { DxDataGridModule } from 'devextreme-angular';
// Import the component
import { AppComponent } from './app.component';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { DxDataGridModule } from 'devextreme-angular';

import { AppComponent } from './app.component';

@NgModule({
declarations: [
    AppComponent
],
imports: [
    BrowserModule,
    DxDataGridModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

Reference DevExtreme style file in the karma.conf.js:

karma.conf.js
files: [
    "node_modules/devextreme/dist/css/dx.light.css"
]

Add the following script to test the DataGrid configuration and the number of loaded records:

app.component.spec.ts
app.component.html
app.component.ts
describe('AppComponent', () => {
beforeEach(async () => {
    jasmine.clock().install();
    await TestBed.configureTestingModule({
    declarations: [
        AppComponent
    ],
    imports: [
        DxDataGridModule
    ]
    }).compileComponents();
});
afterEach( () => {
    jasmine.clock().uninstall();
});

it('renders DataGrid rows',  () => {
    const fixture = TestBed.createComponent(AppComponent);
    fixture.detectChanges();
    const compiled = fixture.nativeElement;
    jasmine.clock().tick(500); // use jasmine clock since DataGrid rendering is async
    expect(compiled.querySelectorAll('.dx-data-row').length).toEqual(4);
});
});
<dx-data-grid
    id="gridContainer"
    [dataSource]="dataSource"
>
</dx-data-grid>
import { Component } from '@angular/core';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent {
    title = 'my-app';
    dataSource: any = [{ id: 1, text: 'test' }, { id: 2, text: 'test' }, { id: 3, text: 'test' }, { id: 4, text: 'test' }];
}

Run ng test command to see the test report.

Integration Testing

Integration testing helps test a component across multiple units. Integration testing does not test unit by unit, but tests all the units as an entity.

The example below illustrates how to test the DataGrid's functionality. The test code adds a new row, saves it, and checks the results.

To get started, create an Angular application and import modules as described in the Unit Testing article.

Add the test code. This code creates the DataGrid and calls the addRow and saveEditData methods to create a new row. Timers allow you to call methods continually since all the processes are asynchronous. The final step is to check whether the DataGrid has two visible rows — an initial row and a newly created row.

app.component.spec.ts
app.component.html
app.component.ts
import { TestBed } from '@angular/core/testing';
import { AppComponent } from './app.component';
import {DxDataGridComponent, DxDataGridModule} from 'devextreme-angular';

describe('AppComponent', () => {
beforeEach(async () => {
    jasmine.clock().install();
    await TestBed.configureTestingModule({
    declarations: [
        AppComponent, DxDataGridComponent
    ],
    imports: [
        DxDataGridModule
    ]
    }).compileComponents();
});
afterEach( () => {
    jasmine.clock().uninstall();
});

it('renders five DataGrid rows and is not able to edit data',  () => {
    const fixture = TestBed.createComponent(AppComponent);
    fixture.detectChanges();
    const compiled = fixture.nativeElement;
    jasmine.clock().tick(500);
    const comp = fixture.componentInstance;
    comp.dataGrid.instance.addRow();
    jasmine.clock().tick(500);
    comp.dataGrid.instance.saveEditData();
    jasmine.clock().tick(500);
    expect(comp.dataGrid.instance.getVisibleRows().length).toEqual(5);
    expect(comp.dataGrid.instance.hasEditData()).toBe(false);
});
});
<dx-data-grid
    id="gridContainer"
    [dataSource]="dataSource"
>
    <dxo-editing mode="batch"></dxo-editing>
</dx-data-grid>
import { Component, ViewChild } from '@angular/core';
import { DxDataGridComponent } from 'devextreme-angular';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent {
    @ViewChild(DxDataGridComponent, { static: false }) dataGrid: DxDataGridComponent;
    title = 'my-app';
    dataSource = {key: 'id', store: [{ id: 1, text: 'test' }, { id: 2, text: 'test' }, { id: 3, text: 'test' }, { id: 4, text: 'test' }]};
}

Run ng test command to see the test report.

End-to-End Testing

End-to-End (Functional) testing ignores the component's internal structure and allows you to verify how DevExtreme components work from a user's point of view.

The example below illustrates how to create an End-to-End test for the DataGrid's functionality. The test code emulates a click on the pager.

To get started, create an Angular application and import modules as described in the Unit Testing article.

Add the following script to your test file. This code finds the specified link on the pager and clicks it. A click on the pager triggers the dxclick event. The test checks whether the result page index is the same as the expected page index.

app.component.spec.ts
app.component.html
app.component.ts
import { TestBed } from '@angular/core/testing';
import { AppComponent } from './app.component';
import {DxDataGridComponent, DxDataGridModule} from 'devextreme-angular';

describe('AppComponent', () => {
beforeEach(async () => {
    jasmine.clock().install();
    await TestBed.configureTestingModule({
    declarations: [
        AppComponent, DxDataGridComponent
    ],
    imports: [
        DxDataGridModule
    ]
    }).compileComponents();
});
afterEach( () => {
    jasmine.clock().uninstall();
});

it('renders DataGrid and switches its page',  () => {
    const fixture = TestBed.createComponent(AppComponent);
    fixture.detectChanges();
    const compiled = fixture.nativeElement;
    jasmine.clock().tick(500);
    const comp = fixture.componentInstance;
    comp.dataGrid.instance.addRow();
    const event = new MouseEvent('click', {
        bubbles: true,
        cancelable: true,
        view: window
    });
    (compiled.querySelectorAll('.dx-page')[5]).dispatchEvent(event);
    jasmine.clock().tick(500);
    expect(comp.dataGrid.instance.pageIndex()).toBe(5);
});
});
<dx-data-grid
    id="gridContainer"
    [dataSource]="dataSource"
>
    <dxo-pager [visible]="true" [allowedPageSizes]="[5, 10]" [showPageSizeSelector]="true"></dxo-pager>
    <dxo-paging [enabled]="true" [pageSize]="10"></dxo-paging>
</dx-data-grid>
import { Component, ViewChild } from '@angular/core';
import { DxDataGridComponent } from 'devextreme-angular';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent {
    @ViewChild(DxDataGridComponent, { static: false }) dataGrid: DxDataGridComponent;
    title = 'my-app';
    array = [];
    dataSource;
    constructor() {
        for (let i = 0; i < 100; i++) {
            this.array.push({id: i, text: 'test ' + i});
        }
        this.dataSource = {key: 'id', store: this.array};
    }
}

Run ng test command to see the test report.