@@ -11,7 +11,8 @@ import {
11
11
getTableMissingMatchingRowDefError ,
12
12
getTableMissingRowDefsError ,
13
13
getTableMultipleDefaultRowDefsError ,
14
- getTableUnknownColumnError
14
+ getTableUnknownColumnError ,
15
+ getTableUnknownDataSourceError
15
16
} from './table-errors' ;
16
17
import { CdkHeaderRowDef , CdkRowDef } from './row' ;
17
18
import { CdkColumnDef } from './cell' ;
@@ -45,6 +46,7 @@ describe('CdkTable', () => {
45
46
BooleanRowCdkTableApp ,
46
47
WrapperCdkTableApp ,
47
48
OuterTableApp ,
49
+ CdkTableWithDifferentDataInputsApp ,
48
50
] ,
49
51
} ) . compileComponents ( ) ;
50
52
} ) ) ;
@@ -113,6 +115,111 @@ describe('CdkTable', () => {
113
115
} ) ;
114
116
} ) ;
115
117
118
+ describe ( 'with different data inputs other than data source' , ( ) => {
119
+ let dataInputFixture : ComponentFixture < CdkTableWithDifferentDataInputsApp > ;
120
+ let dataInputComponent : CdkTableWithDifferentDataInputsApp ;
121
+ let dataInputTableElement : HTMLElement ;
122
+
123
+ let baseData : TestData [ ] = [
124
+ { a : 'a_1' , b : 'b_1' , c : 'c_1' } ,
125
+ { a : 'a_2' , b : 'b_2' , c : 'c_2' } ,
126
+ { a : 'a_3' , b : 'b_3' , c : 'c_3' } ,
127
+ ] ;
128
+
129
+ beforeEach ( ( ) => {
130
+ dataInputFixture = TestBed . createComponent ( CdkTableWithDifferentDataInputsApp ) ;
131
+ dataInputComponent = dataInputFixture . componentInstance ;
132
+ dataInputFixture . detectChanges ( ) ;
133
+
134
+ dataInputTableElement = dataInputFixture . nativeElement . querySelector ( 'cdk-table' ) ;
135
+ } ) ;
136
+
137
+ it ( 'should render with data array input' , ( ) => {
138
+ const data = baseData . slice ( ) ;
139
+ dataInputComponent . dataSource = data ;
140
+ dataInputFixture . detectChanges ( ) ;
141
+
142
+ const expectedRender = [
143
+ [ 'Column A' , 'Column B' , 'Column C' ] ,
144
+ [ 'a_1' , 'b_1' , 'c_1' ] ,
145
+ [ 'a_2' , 'b_2' , 'c_2' ] ,
146
+ [ 'a_3' , 'b_3' , 'c_3' ] ,
147
+ ] ;
148
+ expectTableToMatchContent ( dataInputTableElement , expectedRender ) ;
149
+
150
+ // Push data to the array but neglect to tell the table, should be no change
151
+ data . push ( { a : 'a_4' , b : 'b_4' , c : 'c_4' } ) ;
152
+ expectTableToMatchContent ( dataInputTableElement , expectedRender ) ;
153
+
154
+ // Notify table of the change, expect another row
155
+ dataInputComponent . table . renderRows ( ) ;
156
+ dataInputFixture . detectChanges ( ) ;
157
+ expectedRender . push ( [ 'a_4' , 'b_4' , 'c_4' ] ) ;
158
+ expectTableToMatchContent ( dataInputTableElement , expectedRender ) ;
159
+
160
+ // Remove a row and expect the change in rows
161
+ data . pop ( ) ;
162
+ expectedRender . pop ( ) ;
163
+ dataInputComponent . table . renderRows ( ) ;
164
+ expectTableToMatchContent ( dataInputTableElement , expectedRender ) ;
165
+
166
+ // Remove the data input entirely and expect no rows - just header.
167
+ dataInputComponent . dataSource = null ;
168
+ dataInputFixture . detectChanges ( ) ;
169
+ expectTableToMatchContent ( dataInputTableElement , [ expectedRender [ 0 ] ] ) ;
170
+
171
+ // Add back the data to verify that it renders rows
172
+ dataInputComponent . dataSource = data ;
173
+ dataInputFixture . detectChanges ( ) ;
174
+ expectTableToMatchContent ( dataInputTableElement , expectedRender ) ;
175
+ } ) ;
176
+
177
+ it ( 'should render with data stream input' , ( ) => {
178
+ const data = baseData . slice ( ) ;
179
+ const stream = new BehaviorSubject < TestData [ ] > ( data ) ;
180
+ dataInputComponent . dataSource = stream ;
181
+ dataInputFixture . detectChanges ( ) ;
182
+
183
+ const expectedRender = [
184
+ [ 'Column A' , 'Column B' , 'Column C' ] ,
185
+ [ 'a_1' , 'b_1' , 'c_1' ] ,
186
+ [ 'a_2' , 'b_2' , 'c_2' ] ,
187
+ [ 'a_3' , 'b_3' , 'c_3' ] ,
188
+ ] ;
189
+ expectTableToMatchContent ( dataInputTableElement , expectedRender ) ;
190
+
191
+ // Push data to the array
192
+ data . push ( { a : 'a_4' , b : 'b_4' , c : 'c_4' } ) ;
193
+ expectedRender . push ( [ 'a_4' , 'b_4' , 'c_4' ] ) ;
194
+ stream . next ( data ) ;
195
+ dataInputFixture . detectChanges ( ) ;
196
+ expectTableToMatchContent ( dataInputTableElement , expectedRender ) ;
197
+
198
+ // Remove a row and expect the change in rows
199
+ data . pop ( ) ;
200
+ expectedRender . pop ( ) ;
201
+ stream . next ( data ) ;
202
+ expectTableToMatchContent ( dataInputTableElement , expectedRender ) ;
203
+
204
+ // Remove the data input entirely and expect no rows - just header.
205
+ dataInputComponent . dataSource = null ;
206
+ dataInputFixture . detectChanges ( ) ;
207
+ expectTableToMatchContent ( dataInputTableElement , [ expectedRender [ 0 ] ] ) ;
208
+
209
+ // Add back the data to verify that it renders rows
210
+ dataInputComponent . dataSource = stream ;
211
+ dataInputFixture . detectChanges ( ) ;
212
+ expectTableToMatchContent ( dataInputTableElement , expectedRender ) ;
213
+ } ) ;
214
+
215
+ it ( 'should throw an error if the data source is not valid' , ( ) => {
216
+ dataInputComponent . dataSource = { invalid : 'dataSource' } ;
217
+
218
+ expect ( ( ) => dataInputFixture . detectChanges ( ) )
219
+ . toThrowError ( getTableUnknownDataSourceError ( ) . message ) ;
220
+ } ) ;
221
+ } ) ;
222
+
116
223
it ( 'should render cells even if row data is falsy' , ( ) => {
117
224
const booleanRowCdkTableAppFixture = TestBed . createComponent ( BooleanRowCdkTableApp ) ;
118
225
const booleanRowCdkTableElement =
@@ -720,6 +827,36 @@ class SimpleCdkTableApp {
720
827
@ViewChild ( CdkTable ) table : CdkTable < TestData > ;
721
828
}
722
829
830
+ @Component ( {
831
+ template : `
832
+ <cdk-table [dataSource]="dataSource">
833
+ <ng-container cdkColumnDef="column_a">
834
+ <cdk-header-cell *cdkHeaderCellDef> Column A</cdk-header-cell>
835
+ <cdk-cell *cdkCellDef="let row"> {{row.a}}</cdk-cell>
836
+ </ng-container>
837
+
838
+ <ng-container cdkColumnDef="column_b">
839
+ <cdk-header-cell *cdkHeaderCellDef> Column B</cdk-header-cell>
840
+ <cdk-cell *cdkCellDef="let row"> {{row.b}}</cdk-cell>
841
+ </ng-container>
842
+
843
+ <ng-container cdkColumnDef="column_c">
844
+ <cdk-header-cell *cdkHeaderCellDef> Column C</cdk-header-cell>
845
+ <cdk-cell *cdkCellDef="let row"> {{row.c}}</cdk-cell>
846
+ </ng-container>
847
+
848
+ <cdk-header-row *cdkHeaderRowDef="columnsToRender"></cdk-header-row>
849
+ <cdk-row *cdkRowDef="let row; columns: columnsToRender"></cdk-row>
850
+ </cdk-table>
851
+ `
852
+ } )
853
+ class CdkTableWithDifferentDataInputsApp {
854
+ dataSource : DataSource < TestData > | Observable < TestData [ ] > | TestData [ ] | any = null ;
855
+ columnsToRender = [ 'column_a' , 'column_b' , 'column_c' ] ;
856
+
857
+ @ViewChild ( CdkTable ) table : CdkTable < TestData > ;
858
+ }
859
+
723
860
@Component ( {
724
861
template : `
725
862
<cdk-table [dataSource]="dataSource">
@@ -1186,6 +1323,9 @@ function expectTableToMatchContent(tableElement: Element, expectedTableContent:
1186
1323
}
1187
1324
}
1188
1325
1326
+ // Copy the expected data array to avoid mutating the test's array
1327
+ expectedTableContent = expectedTableContent . slice ( ) ;
1328
+
1189
1329
// Check header cells
1190
1330
const expectedHeaderContent = expectedTableContent . shift ( ) ;
1191
1331
getHeaderCells ( tableElement ) . forEach ( ( cell , index ) => {
@@ -1196,7 +1336,13 @@ function expectTableToMatchContent(tableElement: Element, expectedTableContent:
1196
1336
} ) ;
1197
1337
1198
1338
// Check data row cells
1199
- getRows ( tableElement ) . forEach ( ( row , rowIndex ) => {
1339
+ const rows = getRows ( tableElement ) ;
1340
+ if ( rows . length !== expectedTableContent . length ) {
1341
+ missedExpectations . push (
1342
+ `Expected ${ expectedTableContent . length } rows but found ${ rows . length } ` ) ;
1343
+ fail ( missedExpectations . join ( '\n' ) ) ;
1344
+ }
1345
+ rows . forEach ( ( row , rowIndex ) => {
1200
1346
getCells ( row ) . forEach ( ( cell , cellIndex ) => {
1201
1347
const expected = expectedTableContent . length ?
1202
1348
expectedTableContent [ rowIndex ] [ cellIndex ] :
0 commit comments