Skip to content

Commit cc24766

Browse files
crisbetoandrewseguin
authored andcommitted
refactor(table): improved unit test speed (#10517)
Reduces the runtime of the table tests to about 1/3 of the one from master by not recompiling all the individual test cases for each test.
1 parent 9091b21 commit cc24766

File tree

1 file changed

+98
-78
lines changed

1 file changed

+98
-78
lines changed

src/cdk/table/table.spec.ts

Lines changed: 98 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
1-
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
2-
import {Component, ContentChild, ContentChildren, Input, QueryList, ViewChild} from '@angular/core';
1+
import {ComponentFixture, TestBed} from '@angular/core/testing';
2+
import {
3+
Component,
4+
ContentChild,
5+
ContentChildren,
6+
Input,
7+
QueryList,
8+
ViewChild,
9+
Type,
10+
} from '@angular/core';
311
import {CdkTable} from './table';
412
import {CollectionViewer, DataSource} from '@angular/cdk/collections';
513
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
@@ -18,51 +26,31 @@ import {CdkHeaderRowDef, CdkRowDef} from './row';
1826
import {CdkColumnDef} from './cell';
1927

2028
describe('CdkTable', () => {
21-
let fixture: ComponentFixture<SimpleCdkTableApp>;
22-
23-
let component: SimpleCdkTableApp;
24-
let dataSource: FakeDataSource;
25-
let table: CdkTable<any>;
26-
let tableElement: HTMLElement;
27-
28-
beforeEach(async(() => {
29+
function createComponent<T>(component: Type<T>, declarations: any[] = []): ComponentFixture<T> {
2930
TestBed.configureTestingModule({
3031
imports: [CdkTableModule],
31-
declarations: [
32-
SimpleCdkTableApp,
33-
DynamicDataSourceCdkTableApp,
34-
CustomRoleCdkTableApp,
35-
TrackByCdkTableApp,
36-
DynamicColumnDefinitionsCdkTableApp,
37-
RowContextCdkTableApp,
38-
DuplicateColumnDefNameCdkTableApp,
39-
MissingColumnDefCdkTableApp,
40-
CrazyColumnNameCdkTableApp,
41-
UndefinedColumnsCdkTableApp,
42-
WhenRowCdkTableApp,
43-
WhenRowWithoutDefaultCdkTableApp,
44-
WhenRowMultipleDefaultsCdkTableApp,
45-
MissingRowDefsCdkTableApp,
46-
BooleanRowCdkTableApp,
47-
WrapperCdkTableApp,
48-
OuterTableApp,
49-
CdkTableWithDifferentDataInputsApp,
50-
],
32+
declarations: [component, ...declarations],
5133
}).compileComponents();
52-
}));
5334

54-
beforeEach(() => {
55-
fixture = TestBed.createComponent(SimpleCdkTableApp);
35+
return TestBed.createComponent<T>(component);
36+
}
5637

57-
component = fixture.componentInstance;
58-
dataSource = component.dataSource as FakeDataSource;
59-
table = component.table;
60-
tableElement = fixture.nativeElement.querySelector('cdk-table');
38+
describe('should initialize', () => {
39+
let fixture: ComponentFixture<SimpleCdkTableApp>;
40+
let component: SimpleCdkTableApp;
41+
let dataSource: FakeDataSource;
42+
let table: CdkTable<any>;
43+
let tableElement: HTMLElement;
6144

62-
fixture.detectChanges();
63-
});
45+
beforeEach(() => {
46+
fixture = createComponent(SimpleCdkTableApp);
47+
fixture.detectChanges();
48+
component = fixture.componentInstance;
49+
dataSource = component.dataSource as FakeDataSource;
50+
table = component.table;
51+
tableElement = fixture.nativeElement.querySelector('cdk-table');
52+
});
6453

65-
describe('should initialize', () => {
6654
it('with a connected data source', () => {
6755
expect(table.dataSource).toBe(dataSource);
6856
expect(dataSource.isConnected).toBe(true);
@@ -127,10 +115,9 @@ describe('CdkTable', () => {
127115
];
128116

129117
beforeEach(() => {
130-
dataInputFixture = TestBed.createComponent(CdkTableWithDifferentDataInputsApp);
131-
dataInputComponent = dataInputFixture.componentInstance;
118+
dataInputFixture = createComponent(CdkTableWithDifferentDataInputsApp);
132119
dataInputFixture.detectChanges();
133-
120+
dataInputComponent = dataInputFixture.componentInstance;
134121
dataInputTableElement = dataInputFixture.nativeElement.querySelector('cdk-table');
135122
});
136123

@@ -248,10 +235,11 @@ describe('CdkTable', () => {
248235
});
249236

250237
it('should render cells even if row data is falsy', () => {
251-
const booleanRowCdkTableAppFixture = TestBed.createComponent(BooleanRowCdkTableApp);
238+
const booleanRowCdkTableAppFixture = createComponent(BooleanRowCdkTableApp);
239+
booleanRowCdkTableAppFixture.detectChanges();
240+
252241
const booleanRowCdkTableElement =
253242
booleanRowCdkTableAppFixture.nativeElement.querySelector('cdk-table');
254-
booleanRowCdkTableAppFixture.detectChanges();
255243

256244
expectTableToMatchContent(booleanRowCdkTableElement, [
257245
[''], // Header row
@@ -263,50 +251,55 @@ describe('CdkTable', () => {
263251
});
264252

265253
it('should be able to apply class-friendly css class names for the column cells', () => {
266-
const crazyColumnNameAppFixture = TestBed.createComponent(CrazyColumnNameCdkTableApp);
254+
const crazyColumnNameAppFixture = createComponent(CrazyColumnNameCdkTableApp);
255+
crazyColumnNameAppFixture.detectChanges();
256+
267257
const crazyColumnNameTableElement =
268258
crazyColumnNameAppFixture.nativeElement.querySelector('cdk-table');
269-
crazyColumnNameAppFixture.detectChanges();
270259

271260
// Column was named 'crazy-column-NAME-1!@#$%^-_&*()2'
272261
expect(getHeaderCells(crazyColumnNameTableElement)[0].classList)
273262
.toContain('cdk-column-crazy-column-NAME-1-------_----2');
274263
});
275264

276265
it('should disconnect the data source when table is destroyed', () => {
277-
expect(dataSource.isConnected).toBe(true);
266+
const fixture = createComponent(SimpleCdkTableApp);
267+
fixture.detectChanges();
268+
269+
const dataSource = fixture.componentInstance.dataSource as FakeDataSource;
278270

271+
expect(dataSource.isConnected).toBe(true);
279272
fixture.destroy();
280273
expect(dataSource.isConnected).toBe(false);
281274
});
282275

283276
it('should not clobber an existing table role', () => {
284-
fixture = TestBed.createComponent(CustomRoleCdkTableApp);
277+
const fixture = createComponent(CustomRoleCdkTableApp);
285278
fixture.detectChanges();
286279

287280
expect(fixture.nativeElement.querySelector('cdk-table').getAttribute('role')).toBe('treegrid');
288281
});
289282

290283
it('should throw an error if two column definitions have the same name', () => {
291-
expect(() => TestBed.createComponent(DuplicateColumnDefNameCdkTableApp).detectChanges())
284+
expect(() => createComponent(DuplicateColumnDefNameCdkTableApp).detectChanges())
292285
.toThrowError(getTableDuplicateColumnNameError('column_a').message);
293286
});
294287

295288
it('should throw an error if a column definition is requested but not defined', () => {
296-
expect(() => TestBed.createComponent(MissingColumnDefCdkTableApp).detectChanges())
289+
expect(() => createComponent(MissingColumnDefCdkTableApp).detectChanges())
297290
.toThrowError(getTableUnknownColumnError('column_a').message);
298291
});
299292

300293
it('should throw an error if the row definitions are missing', () => {
301-
expect(() => TestBed.createComponent(MissingRowDefsCdkTableApp).detectChanges())
294+
expect(() => createComponent(MissingRowDefsCdkTableApp).detectChanges())
302295
.toThrowError(getTableMissingRowDefsError().message);
303296
});
304297

305298
it('should not throw an error if columns are undefined on initialization', () => {
306-
const undefinedColumnsFixture = TestBed.createComponent(UndefinedColumnsCdkTableApp);
299+
const undefinedColumnsFixture = createComponent(UndefinedColumnsCdkTableApp);
307300
undefinedColumnsFixture.detectChanges();
308301

309-
tableElement = undefinedColumnsFixture.nativeElement.querySelector('cdk-table');
302+
const tableElement = undefinedColumnsFixture.nativeElement.querySelector('cdk-table');
310303

311304
expect(getHeaderRow(tableElement)).toBeNull('Should be no header without cells');
312305

@@ -318,7 +311,7 @@ describe('CdkTable', () => {
318311
});
319312

320313
it('should be able to dynamically add/remove column definitions', () => {
321-
const dynamicColumnDefFixture = TestBed.createComponent(DynamicColumnDefinitionsCdkTableApp);
314+
const dynamicColumnDefFixture = createComponent(DynamicColumnDefinitionsCdkTableApp);
322315
dynamicColumnDefFixture.detectChanges();
323316

324317
const dynamicColumnDefTable = dynamicColumnDefFixture.nativeElement.querySelector('cdk-table');
@@ -358,6 +351,13 @@ describe('CdkTable', () => {
358351
});
359352

360353
it('should re-render the rows when the data changes', () => {
354+
const fixture = createComponent(SimpleCdkTableApp);
355+
fixture.detectChanges();
356+
357+
const component = fixture.componentInstance;
358+
const dataSource = component.dataSource as FakeDataSource;
359+
const tableElement = fixture.nativeElement.querySelector('cdk-table');
360+
361361
dataSource.addData();
362362
fixture.detectChanges();
363363

@@ -370,7 +370,7 @@ describe('CdkTable', () => {
370370
});
371371

372372
it('should be able to register column, row, and header row definitions outside content', () => {
373-
const outerTableAppFixture = TestBed.createComponent(OuterTableApp);
373+
const outerTableAppFixture = createComponent(OuterTableApp, [WrapperCdkTableApp]);
374374
outerTableAppFixture.detectChanges();
375375

376376
// The first two columns were defined in the wrapped table component as content children,
@@ -387,10 +387,11 @@ describe('CdkTable', () => {
387387

388388
describe('using when predicate', () => {
389389
it('should be able to display different row templates based on the row data', () => {
390-
let whenFixture = TestBed.createComponent(WhenRowCdkTableApp);
390+
const whenFixture = createComponent(WhenRowCdkTableApp);
391391
whenFixture.detectChanges();
392392

393-
let data = whenFixture.componentInstance.dataSource.data;
393+
const data = whenFixture.componentInstance.dataSource.data;
394+
394395
expectTableToMatchContent(whenFixture.nativeElement.querySelector('cdk-table'), [
395396
['Column A', 'Column B', 'Column C'],
396397
[data[0].a, data[0].b, data[0].c],
@@ -401,19 +402,23 @@ describe('CdkTable', () => {
401402
});
402403

403404
it('should error if there is row data that does not have a matching row template', () => {
404-
let whenFixture = TestBed.createComponent(WhenRowWithoutDefaultCdkTableApp);
405-
expect(() => whenFixture.detectChanges())
405+
expect(() => createComponent(WhenRowWithoutDefaultCdkTableApp).detectChanges())
406406
.toThrowError(getTableMissingMatchingRowDefError().message);
407407
});
408408

409409
it('should error if there are multiple rows that do not have a when function', () => {
410-
let whenFixture = TestBed.createComponent(WhenRowMultipleDefaultsCdkTableApp);
411-
expect(() => whenFixture.detectChanges())
410+
expect(() => createComponent(WhenRowMultipleDefaultsCdkTableApp).detectChanges())
412411
.toThrowError(getTableMultipleDefaultRowDefsError().message);
413412
});
414413
});
415414

416415
it('should use differ to add/remove/move rows', () => {
416+
const fixture = createComponent(SimpleCdkTableApp);
417+
fixture.detectChanges();
418+
419+
const component = fixture.componentInstance;
420+
const tableElement = fixture.nativeElement.querySelector('cdk-table');
421+
417422
// Each row receives an attribute 'initialIndex' the element's original place
418423
getRows(tableElement).forEach((row: Element, index: number) => {
419424
row.setAttribute('initialIndex', index.toString());
@@ -447,8 +452,12 @@ describe('CdkTable', () => {
447452
});
448453

449454
it('should clear the row view containers on destroy', () => {
450-
const rowPlaceholder = fixture.componentInstance.table._rowPlaceholder.viewContainer;
451-
const headerPlaceholder = fixture.componentInstance.table._headerRowPlaceholder.viewContainer;
455+
const fixture = createComponent(SimpleCdkTableApp);
456+
fixture.detectChanges();
457+
458+
const component = fixture.componentInstance;
459+
const rowPlaceholder = component.table._rowPlaceholder.viewContainer;
460+
const headerPlaceholder = component.table._headerRowPlaceholder.viewContainer;
452461

453462
spyOn(rowPlaceholder, 'clear').and.callThrough();
454463
spyOn(headerPlaceholder, 'clear').and.callThrough();
@@ -463,15 +472,14 @@ describe('CdkTable', () => {
463472

464473
let trackByComponent: TrackByCdkTableApp;
465474
let trackByFixture: ComponentFixture<TrackByCdkTableApp>;
475+
let tableElement: HTMLElement;
466476

467477
function createTestComponentWithTrackyByTable(trackByStrategy) {
468-
trackByFixture = TestBed.createComponent(TrackByCdkTableApp);
478+
trackByFixture = createComponent(TrackByCdkTableApp);
469479

470480
trackByComponent = trackByFixture.componentInstance;
471481
trackByComponent.trackByStrategy = trackByStrategy;
472482

473-
dataSource = trackByComponent.dataSource as FakeDataSource;
474-
table = trackByComponent.table;
475483
tableElement = trackByFixture.nativeElement.querySelector('cdk-table');
476484
trackByFixture.detectChanges();
477485

@@ -587,7 +595,13 @@ describe('CdkTable', () => {
587595
});
588596

589597
it('should match the right table content with dynamic data', () => {
598+
const fixture = createComponent(SimpleCdkTableApp);
599+
fixture.detectChanges();
600+
601+
const dataSource = fixture.componentInstance.dataSource as FakeDataSource;
602+
const tableElement = fixture.nativeElement.querySelector('cdk-table');
590603
const initialDataLength = dataSource.data.length;
604+
591605
expect(dataSource.data.length).toBe(3);
592606

593607
let data = dataSource.data;
@@ -614,11 +628,12 @@ describe('CdkTable', () => {
614628
});
615629

616630
it('should match the right table content with dynamic data source', () => {
617-
const dynamicDataSourceFixture = TestBed.createComponent(DynamicDataSourceCdkTableApp);
618-
component = dynamicDataSourceFixture.componentInstance;
619-
tableElement = dynamicDataSourceFixture.nativeElement.querySelector('cdk-table');
631+
const dynamicDataSourceFixture = createComponent(DynamicDataSourceCdkTableApp);
620632
dynamicDataSourceFixture.detectChanges();
621633

634+
const component = dynamicDataSourceFixture.componentInstance;
635+
const tableElement = dynamicDataSourceFixture.nativeElement.querySelector('cdk-table');
636+
622637
// Expect that the component has no data source and the table element reflects empty data.
623638
expect(component.dataSource).toBeUndefined();
624639
expectTableToMatchContent(tableElement, [
@@ -640,7 +655,7 @@ describe('CdkTable', () => {
640655
]);
641656

642657
// Remove the data source and check to make sure the table is empty again.
643-
component.dataSource = undefined;
658+
component.dataSource = undefined!;
644659
dynamicDataSourceFixture.detectChanges();
645660

646661
// Expect that the old data source has been disconnected.
@@ -665,12 +680,11 @@ describe('CdkTable', () => {
665680
});
666681

667682
it('should be able to apply classes to rows based on their context', () => {
668-
const contextFixture = TestBed.createComponent(RowContextCdkTableApp);
669-
const contextComponent = contextFixture.componentInstance;
670-
tableElement = contextFixture.nativeElement.querySelector('cdk-table');
683+
const contextFixture = createComponent(RowContextCdkTableApp);
671684
contextFixture.detectChanges();
672685

673-
let rowElements = contextFixture.nativeElement.querySelectorAll('cdk-row');
686+
const contextComponent = contextFixture.componentInstance;
687+
const rowElements = contextFixture.nativeElement.querySelectorAll('cdk-row');
674688

675689
// Rows should not have any context classes
676690
for (let i = 0; i < rowElements.length; i++) {
@@ -701,11 +715,10 @@ describe('CdkTable', () => {
701715
});
702716

703717
it('should be able to apply classes to cells based on their row context', () => {
704-
const contextFixture = TestBed.createComponent(RowContextCdkTableApp);
705-
const contextComponent = contextFixture.componentInstance;
706-
tableElement = contextFixture.nativeElement.querySelector('cdk-table');
718+
const contextFixture = createComponent(RowContextCdkTableApp);
707719
contextFixture.detectChanges();
708720

721+
const contextComponent = contextFixture.componentInstance;
709722
const rowElements = contextFixture.nativeElement.querySelectorAll('cdk-row');
710723

711724
for (let i = 0; i < rowElements.length; i++) {
@@ -743,6 +756,13 @@ describe('CdkTable', () => {
743756
});
744757

745758
it('should be able to dynamically change the columns for header and rows', () => {
759+
const fixture = createComponent(SimpleCdkTableApp);
760+
fixture.detectChanges();
761+
762+
const component = fixture.componentInstance;
763+
const dataSource = component.dataSource as FakeDataSource;
764+
const tableElement = fixture.nativeElement.querySelector('cdk-table');
765+
746766
expect(dataSource.data.length).toBe(3);
747767

748768
let data = dataSource.data;

0 commit comments

Comments
 (0)