-
Notifications
You must be signed in to change notification settings - Fork 160
Test implementation guidelines for Ignite UI for Angular
Version | User | Date | Notes |
---|---|---|---|
0.1 | Zdravko Kolev | June 10, 2019 | Initial version |
0.2 | Nikolay Alipiev | January 17, 2020 | Angular component unit testing |
0.3 | Nikolay Alipiev / Plamena Miteva | March 30, 2020 | Define new Guidelines |
- Radoslav Karaivanov | Date:
- Konstantin Dinev | Date:
- Angular Testing Guide
- Jasmine
- Run tests locally with
ng test igniteui-angular
Note: those guidelines should be applied only if reasonable
- Define constants, when using a class name as a selector, at the top of the tests:
const CSS_CLASS_DRAG_ROW = 'igx-grid__tr--drag';
- Define types for all variables and parameters:
let grid: IgxGridComponent;
- For better performance, use
NoopAnimationsModule
to disable animatoions in tests where they are not the subject of tests:
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
- Describes should be organized according to features
- Create one testbed for each describe, e.g.
IgxComboSampleComponent
- Testbed component to be also declared for the specific describe
describe('Initialization and rendering tests: ', () => { configureTestSuite(); beforeAll(async(() => { TestBed.configureTestingModule({ declarations: [ IgxComboSampleComponent ], imports: [ IgxComboModule, NoopAnimationsModule, IgxToggleModule, ReactiveFormsModule, FormsModule ] }).compileComponents(); })); ...
- When writing tests for a new control/functionality the method
configureTestSuite()
must be called.
describe('Initialization and rendering tests: ', () => {
configureTestSuite();
- Define variables, acting for all tests, in the scope of the describe:
describe('Custom ghost template tests', () => { let grid: IgxGridComponent; let rows: IgxGridRowComponent[]; let dragRows: DebugElement[]; configureTestSuite(); beforeAll(async(() => { ...
- Define types for all variables that you define.
- Following Angular tutorials for component unit testing, what they suggest is to directly instantiate the component instead of creating a test fixture. Here is an example of such an approach:
select = new IgxSelectComponent(null, mockCdr, mockSelection, null, mockInjector);
Note: for such cases, you will need to mock the everything that you don't need including component features. If there are exceptions, in most of cases this will mean that a part of the component is not being mocked.
const mockInjector = jasmine.createSpyObj('Injector', {
'get': mockNgControl
});
Note: In addition to all the unit tests, there is a single test that is responsible for testing if the bandings are properly called. Once this is tested, all other related tests can be unit tests using API.
Note: If there are several unit tests with direct component initialization, then you can specify separate describe for unit tests, but not necessary.
- Tests should be excluded with pending() function; Do not use
x
. Example:
it('my it block', () => {
pending('my pending comment');
...
});
- Use separate
describes
. When multiple tests are using the sametestBed
, it should be initialized in abeforeEach
. Example:
describe('IgxGrid - Multi Cell selection', () => {
configureTestSuite();
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
SelectionWithScrollsComponent,
SelectionWithTransactionsComponent
],
imports: [NoopAnimationsModule, IgxGridModule]
}).compileComponents();
}));
describe('Base', () => {
...
beforeEach(fakeAsync(/** height/width setter rAF */() => {
fixture = TestBed.createComponent(TestComponentX);
...
}));
it('Should be able to select a range with mouse dragging', () => {
...
-
The helper functions for the tests are in HelperUtils. Review and reuse them in tests instead of rewriting them. For example,
verifyCheckbox()
,clearOverlay()
etc. -
When adding tests for the Grids (
igxGrid
,igxTreeGrid
,igxHieraticalGrid
) the test beds from the filesgrid-base-components.spec
,grid-samples.spec
andtree-grid-components.spec.ts
should be used or extended /Most probably one of the test components already defined in them would be suitable for your scenario/. When a new test component is necessary, add it to one of these files so it can be easily reused later. -
Avoid defining test components in the test files. Define them in a separate file instead (for example,
grid-samples.spec.ts
) so they can be easily reused in other test files. -
Implement different tests for each scenario, based on the
Test plan
. -
Common logic should be exposed in separate functions. Example:
// tests column and column group header rendering
function testColumnGroupHeaderRendering(column: DebugElement, width: number, height: number,
title: string, descendentColumnCssClass?: string, descendentColumnCount?: number) {}
-
When keyboard or mouse events are needed, the functions from the UIInteractions (ui-interactions.spec) should be used. For example
UIInteractions.triggerKeyDownEvtUponElem('tab', cell.nativeElement, true)
,UIInteractions.simulateClickAndSelectCellEvent()
,UIInteractions. simulateTouchMoveEvent()
etc. New event functions should also be added here. -
Use
fakeAsync
when there are async operations (animations, rAF, timeouts). Most grid testbeds setups need to befakeAsync
(orasync
). -
Use
native
async (whenfakeAsync
is not an option) - Example.
- When there are delays in the execution. For example, when testing
Grid's scrolling
orResizing
- this is because thescrolling
is happening out of thezone
. - When using
await wait
withfixture.detectChanges()
.
- Consider Jasmine
async
andcallback
when using promises - whenStable, rendering done, etc. - Avoid using
done()
callback, withtimeout()
andfixture.whenStable
when possible. - Use
Spies
to:
- check for different calls. Example:
it('should not trigger onRemove event when ..', () => {
...
const firstChipComp = fix.componentInstance.chips.toArray()[0];
spyOn(firstChipComp.onRemove, 'emit');
- prevent a certain function from execution. For example:
// Spy the saveBlobToFile method so the files are not really created
spyOn(ExportUtilities as any, 'saveBlobToFile');