Skip to content

Commit 883081b

Browse files
committed
add tests
1 parent de68a19 commit 883081b

File tree

5 files changed

+164
-115
lines changed

5 files changed

+164
-115
lines changed

src/cdk/table/table.spec.ts

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {combineLatest} from 'rxjs/observable/combineLatest';
88
import {CdkTableModule} from './index';
99
import {map} from 'rxjs/operator/map';
1010

11-
fdescribe('CdkTable', () => {
11+
describe('CdkTable', () => {
1212
let fixture: ComponentFixture<SimpleCdkTableApp>;
1313

1414
let component: SimpleCdkTableApp;
@@ -109,14 +109,45 @@ fdescribe('CdkTable', () => {
109109
expect(fixture.nativeElement.querySelector('cdk-table').getAttribute('role')).toBe('treegrid');
110110
});
111111

112-
fit('should be able to dynamically add/remove column definitions', () => {
112+
it('should be able to dynamically add/remove column definitions', () => {
113113
const dynamicColumnDefFixture = TestBed.createComponent(DynamicColumnDefinitionsCdkTableApp);
114114
dynamicColumnDefFixture.detectChanges();
115+
dynamicColumnDefFixture.detectChanges();
115116

117+
const dynamicColumnDefTableEl = dynamicColumnDefFixture.nativeElement.querySelector('cdk-table');
116118
const dynamicColumnDefComp = dynamicColumnDefFixture.componentInstance;
117-
expect(dynamicColumnDefComp.dynamicColumns.push('columnA'));
118119

120+
// Add a new column and expect it to show up in the table
121+
let columnA = 'columnA';
122+
dynamicColumnDefComp.dynamicColumns.push(columnA);
123+
dynamicColumnDefFixture.detectChanges();
124+
expectTableToMatchContent(dynamicColumnDefTableEl, [
125+
[columnA], // Header row
126+
[columnA], // Data rows
127+
[columnA],
128+
[columnA],
129+
]);
130+
131+
// Add another new column and expect it to show up in the table
132+
let columnB = 'columnB';
133+
dynamicColumnDefComp.dynamicColumns.push(columnB);
119134
dynamicColumnDefFixture.detectChanges();
135+
expectTableToMatchContent(dynamicColumnDefTableEl, [
136+
[columnA, columnB], // Header row
137+
[columnA, columnB], // Data rows
138+
[columnA, columnB],
139+
[columnA, columnB],
140+
]);
141+
142+
// Remove column A expect only column B to be rendered
143+
dynamicColumnDefComp.dynamicColumns.shift();
144+
dynamicColumnDefFixture.detectChanges();
145+
expectTableToMatchContent(dynamicColumnDefTableEl, [
146+
[columnB], // Header row
147+
[columnB], // Data rows
148+
[columnB],
149+
[columnB],
150+
]);
120151
});
121152

122153
it('should re-render the rows when the data changes', () => {
@@ -586,8 +617,8 @@ class TrackByCdkTableApp {
586617
template: `
587618
<cdk-table [dataSource]="dataSource">
588619
<ng-container [cdkColumnDef]="column" *ngFor="let column of dynamicColumns">
589-
<cdk-header-cell *cdkHeaderCellDef> {{column}}</cdk-header-cell>
590-
<cdk-cell *cdkCellDef="let row"> {{column}}</cdk-cell>
620+
<cdk-header-cell *cdkHeaderCellDef> {{column}} </cdk-header-cell>
621+
<cdk-cell *cdkCellDef="let row"> {{column}} </cdk-cell>
591622
</ng-container>
592623
593624
<cdk-header-row *cdkHeaderRowDef="dynamicColumns"></cdk-header-row>
@@ -597,14 +628,9 @@ class TrackByCdkTableApp {
597628
})
598629
class DynamicColumnDefinitionsCdkTableApp {
599630
dynamicColumns: any[] = [];
600-
601631
dataSource: FakeDataSource = new FakeDataSource();
602632

603633
@ViewChild(CdkTable) table: CdkTable<TestData>;
604-
605-
addDynamicColumnDef() {
606-
this.dynamicColumns.push(this.dynamicColumns.length);
607-
}
608634
}
609635

610636
@Component({
@@ -704,7 +730,7 @@ function expectTableToMatchContent(tableElement: Element, expectedTableContent:
704730
// Check data row cells
705731
getRows(tableElement).forEach((row, rowIndex) => {
706732
getCells(row).forEach((cell, cellIndex) => {
707-
const expected = expectedHeaderContent ?
733+
const expected = expectedTableContent.length ?
708734
expectedTableContent[rowIndex][cellIndex] :
709735
null;
710736
checkCellContent(cell, expected);

src/cdk/table/table.ts

Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,8 @@ export class CdkTable<T> implements CollectionViewer {
107107
/** Subscription that listens for the data provided by the data source. */
108108
private _renderChangeSubscription: Subscription;
109109

110-
/**
111-
* Map of all the user's defined columns identified by name.
112-
* Contains the header and data-cell templates.
113-
*/
114-
private _columnDefinitionsByName = new Map<string, CdkColumnDef>();
110+
/** Map of all the user's defined columns (header and data cell template) identified by name. */
111+
private _columnDefinitionsMap = new Map<string, CdkColumnDef>();
115112

116113
/** Differ used to find the changes in the data provided by the data source. */
117114
private _dataDiffer: IterableDiffer<T>;
@@ -134,15 +131,6 @@ export class CdkTable<T> implements CollectionViewer {
134131
get trackBy(): TrackByFunction<T> { return this._trackByFn; }
135132
private _trackByFn: TrackByFunction<T>;
136133

137-
// TODO(andrewseguin): Remove max value as the end index
138-
// and instead calculate the view on init and scroll.
139-
/**
140-
* Stream containing the latest information on what rows are being displayed on screen.
141-
* Can be used by the data source to as a heuristic of what data should be provided.
142-
*/
143-
viewChange =
144-
new BehaviorSubject<{start: number, end: number}>({start: 0, end: Number.MAX_VALUE});
145-
146134
/**
147135
* Provides a stream containing the latest data array to render. Influenced by the table's
148136
* stream of view window (what rows are currently on screen).
@@ -156,6 +144,15 @@ export class CdkTable<T> implements CollectionViewer {
156144
}
157145
private _dataSource: DataSource<T>;
158146

147+
// TODO(andrewseguin): Remove max value as the end index
148+
// and instead calculate the view on init and scroll.
149+
/**
150+
* Stream containing the latest information on what rows are being displayed on screen.
151+
* Can be used by the data source to as a heuristic of what data should be provided.
152+
*/
153+
viewChange =
154+
new BehaviorSubject<{start: number, end: number}>({start: 0, end: Number.MAX_VALUE});
155+
159156
// Placeholders within the table's template where the header and data rows will be inserted.
160157
@ViewChild(RowPlaceholder) _rowPlaceholder: RowPlaceholder;
161158
@ViewChild(HeaderRowPlaceholder) _headerRowPlaceholder: HeaderRowPlaceholder;
@@ -188,14 +185,12 @@ export class CdkTable<T> implements CollectionViewer {
188185
}
189186

190187
ngAfterContentInit() {
191-
// Update the content's column definitions when they are changed. Start with initial null value
192-
// to initialize the map.
193-
startWith.call(this._columnDefinitions.changes, null)
194-
.subscribe(() => this._updateColumnDefinitions());
188+
// Initialize the column definitions map for easy lookup. Update the map when changed.
189+
this._refreshColumnDefinitionsMap();
190+
this._columnDefinitions.changes.subscribe(() => this._refreshColumnDefinitionsMap());
195191
}
196192

197193
ngAfterContentChecked() {
198-
console.log('Content checked');
199194
this._checkColumnsChange();
200195
}
201196

@@ -218,14 +213,13 @@ export class CdkTable<T> implements CollectionViewer {
218213
}
219214

220215
/** Update the map containing the content's column definitions. */
221-
private _updateColumnDefinitions() {
222-
console.log('Updating columns');
223-
this._columnDefinitionsByName.clear();
216+
private _refreshColumnDefinitionsMap() {
217+
this._columnDefinitionsMap.clear();
224218
this._columnDefinitions.forEach(columnDef => {
225-
if (this._columnDefinitionsByName.has(columnDef.name)) {
219+
if (this._columnDefinitionsMap.has(columnDef.name)) {
226220
throw getTableDuplicateColumnNameError(columnDef.name);
227221
}
228-
this._columnDefinitionsByName.set(columnDef.name, columnDef);
222+
this._columnDefinitionsMap.set(columnDef.name, columnDef);
229223
});
230224
}
231225

@@ -380,7 +374,7 @@ export class CdkTable<T> implements CollectionViewer {
380374
private _getHeaderCellTemplatesForRow(headerDef: CdkHeaderRowDef): CdkHeaderCellDef[] {
381375
if (!headerDef.columns) { return []; }
382376
return headerDef.columns.map(columnId => {
383-
const column = this._columnDefinitionsByName.get(columnId);
377+
const column = this._columnDefinitionsMap.get(columnId);
384378

385379
if (!column) {
386380
throw getTableUnknownColumnError(columnId);
@@ -397,7 +391,7 @@ export class CdkTable<T> implements CollectionViewer {
397391
private _getCellTemplatesForRow(rowDef: CdkRowDef): CdkCellDef[] {
398392
if (!rowDef.columns) { return []; }
399393
return rowDef.columns.map(columnId => {
400-
const column = this._columnDefinitionsByName.get(columnId);
394+
const column = this._columnDefinitionsMap.get(columnId);
401395

402396
if (!column) {
403397
throw getTableUnknownColumnError(columnId);

src/demo-app/table/table-demo.html

Lines changed: 90 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,38 @@
1717
<md-radio-button [value]="'index'">Index</md-radio-button>
1818
</md-radio-group>
1919
</div>
20+
</div>
21+
22+
<md-card>
23+
<h3>
24+
CdkTable With Dynamic Column Def
25+
<div>
26+
<button md-raised-button
27+
(click)="addDynamicColumnDef()"
28+
[disabled]="dynamicColumnIds.length >= 4">
29+
Add Column Def
30+
</button>
31+
<button md-raised-button
32+
(click)="removeDynamicColumnDef()"
33+
[disabled]="dynamicColumnIds.length == 0">
34+
Remove Column Def
35+
</button>
36+
</div>
37+
</h3>
38+
39+
<cdk-table [dataSource]="dataSource">
40+
<ng-container [cdkColumnDef]="column.id" *ngFor="let column of dynamicColumnDefs">
41+
<cdk-header-cell *cdkHeaderCellDef> {{column.headerText}} </cdk-header-cell>
42+
<cdk-cell *cdkCellDef="let row"> {{row[column.property]}} </cdk-cell>
43+
</ng-container>
44+
45+
<cdk-header-row *cdkHeaderRowDef="dynamicColumnIds"></cdk-header-row>
46+
<cdk-row *cdkRowDef="let row; columns: dynamicColumnIds;"></cdk-row>
47+
</cdk-table>
48+
</md-card>
49+
50+
<md-card>
51+
<h3>CdkTable Example</h3>
2052

2153
<div class="demo-highlighter">
2254
Highlight:
@@ -26,85 +58,65 @@
2658
<md-checkbox (change)="toggleHighlight('odd', $event.checked)">Odd Rows</md-checkbox>
2759
</div>
2860

29-
<div>
30-
<button md-raised-button (click)="addDynamicColumnDef()" [disabled]="dynamicColumnIds.length >= 4">
31-
Add Dynamic Column Def
32-
</button>
33-
</div>
34-
</div>
61+
<cdk-table #table mdSort
62+
[dataSource]="dataSource"
63+
[trackBy]="userTrackBy">
64+
65+
<!-- Column Definition: ID -->
66+
<ng-container cdkColumnDef="userId">
67+
<cdk-header-cell *cdkHeaderCellDef
68+
md-sort-header arrowPosition="before">
69+
ID
70+
</cdk-header-cell>
71+
<cdk-cell *cdkCellDef="let row"> {{row.id}} </cdk-cell>
72+
</ng-container>
73+
74+
<!-- Column Definition: Progress -->
75+
<ng-container cdkColumnDef="progress">
76+
<cdk-header-cell *cdkHeaderCellDef
77+
md-sort-header start="desc">
78+
Progress
79+
</cdk-header-cell>
80+
<cdk-cell *cdkCellDef="let row">
81+
<div class="demo-progress-stat">{{row.progress}}%</div>
82+
<div class="demo-progress-indicator-container">
83+
<div class="demo-progress-indicator"
84+
[style.background]="row.progress > 50 ? 'green' : 'red'"
85+
[style.opacity]="getOpacity(row.progress)"
86+
[style.width.%]="row.progress"></div>
87+
</div>
88+
</cdk-cell>
89+
</ng-container>
90+
91+
<!-- Column Definition: Name -->
92+
<ng-container cdkColumnDef="userName">
93+
<cdk-header-cell *cdkHeaderCellDef md-sort-header>
94+
Name
95+
</cdk-header-cell>
96+
<cdk-cell *cdkCellDef="let row"> {{row.name}} </cdk-cell>
97+
</ng-container>
98+
99+
<!-- Column Definition: Color -->
100+
<ng-container cdkColumnDef="color">
101+
<cdk-header-cell *cdkHeaderCellDef
102+
md-sort-header disableClear>
103+
Color
104+
</cdk-header-cell>
105+
<cdk-cell *cdkCellDef="let row" [style.color]="row.color"> {{row.color}} </cdk-cell>
106+
</ng-container>
35107

36-
<h3>CdkTable With Dynamic Column Def</h3>
37-
38-
<cdk-table [dataSource]="dataSource">
39-
<ng-container [cdkColumnDef]="column.id" *ngFor="let column of dynamicColumns">
40-
<cdk-header-cell *cdkHeaderCellDef> {{column.headerText}} </cdk-header-cell>
41-
<cdk-cell *cdkCellDef="let row"> {{row[column.property]}} </cdk-cell>
42-
</ng-container>
43-
44-
<cdk-header-row *cdkHeaderRowDef="dynamicColumnIds"></cdk-header-row>
45-
<cdk-row *cdkRowDef="let row; columns: dynamicColumnIds;"></cdk-row>
46-
</cdk-table>
47-
48-
<h3>CdkTable Example</h3>
49-
50-
<cdk-table #table mdSort
51-
[dataSource]="dataSource"
52-
[trackBy]="userTrackBy">
53-
54-
<!-- Column Definition: ID -->
55-
<ng-container cdkColumnDef="userId">
56-
<cdk-header-cell *cdkHeaderCellDef
57-
md-sort-header arrowPosition="before">
58-
ID
59-
</cdk-header-cell>
60-
<cdk-cell *cdkCellDef="let row"> {{row.id}} </cdk-cell>
61-
</ng-container>
62-
63-
<!-- Column Definition: Progress -->
64-
<ng-container cdkColumnDef="progress">
65-
<cdk-header-cell *cdkHeaderCellDef
66-
md-sort-header start="desc">
67-
Progress
68-
</cdk-header-cell>
69-
<cdk-cell *cdkCellDef="let row">
70-
<div class="demo-progress-stat">{{row.progress}}%</div>
71-
<div class="demo-progress-indicator-container">
72-
<div class="demo-progress-indicator"
73-
[style.background]="row.progress > 50 ? 'green' : 'red'"
74-
[style.opacity]="getOpacity(row.progress)"
75-
[style.width.%]="row.progress"></div>
76-
</div>
77-
</cdk-cell>
78-
</ng-container>
79-
80-
<!-- Column Definition: Name -->
81-
<ng-container cdkColumnDef="userName">
82-
<cdk-header-cell *cdkHeaderCellDef md-sort-header>
83-
Name
84-
</cdk-header-cell>
85-
<cdk-cell *cdkCellDef="let row"> {{row.name}} </cdk-cell>
86-
</ng-container>
87-
88-
<!-- Column Definition: Color -->
89-
<ng-container cdkColumnDef="color">
90-
<cdk-header-cell *cdkHeaderCellDef
91-
md-sort-header disableClear>
92-
Color
93-
</cdk-header-cell>
94-
<cdk-cell *cdkCellDef="let row" [style.color]="row.color"> {{row.color}} </cdk-cell>
95-
</ng-container>
96-
97-
<cdk-header-row *cdkHeaderRowDef="displayedColumns"></cdk-header-row>
98-
<cdk-row *cdkRowDef="let row; columns: displayedColumns;
99-
let first = first; let last = last; let even = even; let odd = odd"
100-
[ngClass]="{
101-
'demo-row-highlight-first': highlights.has('first') && first,
102-
'demo-row-highlight-last': highlights.has('last') && last,
103-
'demo-row-highlight-even': highlights.has('even') && even,
104-
'demo-row-highlight-odd': highlights.has('odd') && odd
105-
}">
106-
</cdk-row>
107-
</cdk-table>
108+
<cdk-header-row *cdkHeaderRowDef="displayedColumns"></cdk-header-row>
109+
<cdk-row *cdkRowDef="let row; columns: displayedColumns;
110+
let first = first; let last = last; let even = even; let odd = odd"
111+
[ngClass]="{
112+
'demo-row-highlight-first': highlights.has('first') && first,
113+
'demo-row-highlight-last': highlights.has('last') && last,
114+
'demo-row-highlight-even': highlights.has('even') && even,
115+
'demo-row-highlight-odd': highlights.has('odd') && odd
116+
}">
117+
</cdk-row>
118+
</cdk-table>
119+
</md-card>
108120

109121
<h3>MdTable Example</h3>
110122

src/demo-app/table/table-demo.scss

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,18 @@
2222
.demo-row-highlight-even { background: #ff0099; }
2323
.demo-row-highlight-odd { background: #83f52c; }
2424

25+
.mat-card {
26+
margin: 24px 0;
27+
max-height: 200px;
28+
overflow: auto;
29+
30+
h3 {
31+
display: flex;
32+
justify-content: space-between;
33+
align-items: center;
34+
}
35+
}
36+
2537
/** Styles so that the CDK Table columns have width and font size. */
2638
.cdk-table {
2739
font-size: 12px;

0 commit comments

Comments
 (0)