|
| 1 | +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; |
| 2 | +import { Component, viewChild } from '@angular/core'; |
| 3 | +import { By } from '@angular/platform-browser'; |
| 4 | +import { IgxGridLiteComponent, IgxGridLiteFilteringExpression, IgxGridLiteSortingExpression } from './grid-lite.component'; |
| 5 | +import { IgxGridLiteColumnComponent, IgxGridLiteCellTemplateDirective, IgxGridLiteHeaderTemplateDirective, IgxGridLiteColumnConfiguration } from './grid-lite-column.component'; |
| 6 | + |
| 7 | +describe('IgxGridLiteComponent', () => { |
| 8 | + beforeEach(waitForAsync(() => { |
| 9 | + TestBed.configureTestingModule({ |
| 10 | + imports: [ |
| 11 | + IgxGridLiteComponent, |
| 12 | + IgxGridLiteColumnComponent |
| 13 | + ] |
| 14 | + }).compileComponents(); |
| 15 | + })); |
| 16 | + |
| 17 | + describe('Basic', () => { |
| 18 | + it('should initialize grid with data and columns', async () => { |
| 19 | + const fixture = TestBed.createComponent(BasicGridComponent); |
| 20 | + fixture.detectChanges(); |
| 21 | + await setUp(fixture); |
| 22 | + fixture.detectChanges(); |
| 23 | + |
| 24 | + const gridElement = fixture.debugElement.query(By.directive(IgxGridLiteComponent)); |
| 25 | + expect(gridElement).toBeTruthy(); |
| 26 | + |
| 27 | + const columnElements = fixture.debugElement.queryAll(By.directive(IgxGridLiteColumnComponent)); |
| 28 | + expect(columnElements.length).toBe(3); |
| 29 | + }); |
| 30 | + |
| 31 | + it('should render grid with auto-generate enabled', async () => { |
| 32 | + const fixture = TestBed.createComponent(GridComponentAutogenerate); |
| 33 | + fixture.detectChanges(); |
| 34 | + await setUp(fixture); |
| 35 | + fixture.detectChanges(); |
| 36 | + |
| 37 | + const gridElement = fixture.nativeElement.querySelector('igc-grid-lite'); |
| 38 | + expect(gridElement).toBeTruthy(); |
| 39 | + expect(gridElement.autoGenerate).toBeTrue(); |
| 40 | + expect(gridElement.columns.length).toBe(5); |
| 41 | + }); |
| 42 | + |
| 43 | + it('should update grid data when data input changes', async () => { |
| 44 | + const fixture = TestBed.createComponent(BasicGridComponent); |
| 45 | + fixture.detectChanges(); |
| 46 | + await setUp(fixture); |
| 47 | + |
| 48 | + const gridComponent = fixture.componentInstance.grid(); |
| 49 | + const newData: TestData[] = [ |
| 50 | + { id: 99, name: 'Z', active: true, importance: 'high', address: { city: 'Boston', code: 2101 } } |
| 51 | + ]; |
| 52 | + fixture.componentInstance.data = newData; |
| 53 | + fixture.detectChanges(); |
| 54 | + await fixture.whenStable(); |
| 55 | + |
| 56 | + expect(gridComponent.dataView.length).toBe(1); |
| 57 | + expect(gridComponent.rows.length).toBe(1); |
| 58 | + }); |
| 59 | + |
| 60 | + it('should update sortingExpressions through setter', async () => { |
| 61 | + const fixture = TestBed.createComponent(BasicGridComponent); |
| 62 | + fixture.detectChanges(); |
| 63 | + await setUp(fixture); |
| 64 | + |
| 65 | + const gridComponent = fixture.componentInstance.grid(); |
| 66 | + const expressions: IgxGridLiteSortingExpression<TestData>[] = [ |
| 67 | + { key: 'name', direction: 'ascending' } |
| 68 | + ]; |
| 69 | + |
| 70 | + let secondRow = gridComponent.rows[1]; |
| 71 | + expect(secondRow.cells[1].value).toBe('B'); |
| 72 | + |
| 73 | + gridComponent.sortingExpressions = expressions; |
| 74 | + fixture.detectChanges(); |
| 75 | + await fixture.whenStable(); |
| 76 | + |
| 77 | + secondRow = gridComponent.rows[1]; |
| 78 | + expect(secondRow.cells[1].value).toBe('a'); |
| 79 | + }); |
| 80 | + |
| 81 | + it('should update filteringExpressions through setter', async () => { |
| 82 | + const fixture = TestBed.createComponent(BasicGridComponent); |
| 83 | + fixture.detectChanges(); |
| 84 | + await setUp(fixture); |
| 85 | + |
| 86 | + const gridComponent = fixture.componentInstance.grid(); |
| 87 | + |
| 88 | + expect(gridComponent.dataView.length).toBe(8); |
| 89 | + expect(gridComponent.dataView.some(item => !item.active)).toBeTrue(); |
| 90 | + const expressions: IgxGridLiteFilteringExpression<TestData>[] = [ |
| 91 | + { key: 'active', condition: 'true', searchTerm: true } |
| 92 | + ]; |
| 93 | + |
| 94 | + gridComponent.filteringExpressions = expressions; |
| 95 | + fixture.detectChanges(); |
| 96 | + await fixture.whenStable(); |
| 97 | + |
| 98 | + expect(gridComponent.dataView.length).toBe(4); |
| 99 | + expect(gridComponent.dataView.every(item => item.active)).toBeTrue(); |
| 100 | + }); |
| 101 | + }); |
| 102 | + |
| 103 | + describe('Templates', () => { |
| 104 | + |
| 105 | + function get(element: any, selector: string) { |
| 106 | + return element.renderRoot.querySelector(selector); |
| 107 | + } |
| 108 | + |
| 109 | + it('should render custom header and cell templates when set as inputs', async () => { |
| 110 | + const fixture = TestBed.createComponent(GridComponentTemplate); |
| 111 | + fixture.detectChanges(); |
| 112 | + |
| 113 | + await setUp(fixture); |
| 114 | + fixture.detectChanges(); |
| 115 | + const gridComponent: IgxGridLiteComponent<TestData> = fixture.componentInstance.grid(); |
| 116 | + |
| 117 | + |
| 118 | + // Check header template |
| 119 | + const gridElement = fixture.nativeElement.querySelector('igc-grid-lite'); |
| 120 | + const headerRow = get(gridElement, 'igc-grid-lite-header-row'); |
| 121 | + const headerCell = headerRow.headers.at(0); |
| 122 | + const headerText = get(headerCell, '[part~="title"]').innerText; |
| 123 | + expect(headerText).toEqual('Name (Custom)'); |
| 124 | + |
| 125 | + // check cell template |
| 126 | + const cell = gridComponent.rows[0].cells[1]; |
| 127 | + const content = get(cell, 'span').innerText; |
| 128 | + expect(content).toEqual('No'); |
| 129 | + }); |
| 130 | + |
| 131 | + it('should render custom header and cell templates when set as a column child', async () => { |
| 132 | + const fixture = TestBed.createComponent(GridComponentTemplate); |
| 133 | + fixture.detectChanges(); |
| 134 | + await setUp(fixture); |
| 135 | + fixture.detectChanges(); |
| 136 | + const gridComponent: IgxGridLiteComponent<TestData> = fixture.componentInstance.grid(); |
| 137 | + |
| 138 | + |
| 139 | + // Check header template |
| 140 | + const gridElement = fixture.nativeElement.querySelector('igc-grid-lite'); |
| 141 | + const headerRow = get(gridElement, 'igc-grid-lite-header-row'); |
| 142 | + const headerCell = headerRow.headers.at(2); |
| 143 | + const headerText = get(headerCell, '[part~="title"]').innerText; |
| 144 | + expect(headerText).toEqual('Importance (Custom Inline)'); |
| 145 | + |
| 146 | + // check cell template |
| 147 | + const cell = gridComponent.rows[0].cells[3]; |
| 148 | + const content = get(cell, 'span').innerText; |
| 149 | + expect(content).toEqual('New York, 10001'); |
| 150 | + }); |
| 151 | + |
| 152 | + }); |
| 153 | +}); |
| 154 | + |
| 155 | + |
| 156 | +type Importance = 'low' | 'medium' | 'high'; |
| 157 | +interface TestData { |
| 158 | + id: number; |
| 159 | + name: string; |
| 160 | + active: boolean; |
| 161 | + importance: Importance; |
| 162 | + address: { |
| 163 | + city: string; |
| 164 | + code: number; |
| 165 | + }; |
| 166 | +} |
| 167 | + |
| 168 | +@Component({ |
| 169 | + template: ` |
| 170 | + <igx-grid-lite [data]="data" #grid [autoGenerate]="shouldAutoGenerate"> |
| 171 | + @for(column of columns; track column.field) { |
| 172 | + <igx-grid-lite-column |
| 173 | + [field]="column.field" |
| 174 | + [header]="column.header" |
| 175 | + [dataType]="column.dataType" |
| 176 | + > |
| 177 | + </igx-grid-lite-column> |
| 178 | + } |
| 179 | + </igx-grid-lite> |
| 180 | + `, |
| 181 | + standalone: true, |
| 182 | + imports: [IgxGridLiteComponent, IgxGridLiteColumnComponent] |
| 183 | +}) |
| 184 | +class BasicGridComponent { |
| 185 | + public grid = viewChild<IgxGridLiteComponent<TestData>>('grid'); |
| 186 | + public data: TestData[] = [ |
| 187 | + { |
| 188 | + id: 1, |
| 189 | + name: 'A', |
| 190 | + active: false, |
| 191 | + importance: 'medium', |
| 192 | + address: { city: 'New York', code: 10001 }, |
| 193 | + }, |
| 194 | + { |
| 195 | + id: 2, |
| 196 | + name: 'B', |
| 197 | + active: false, |
| 198 | + importance: 'low', |
| 199 | + address: { city: 'Los Angeles', code: 90001 }, |
| 200 | + }, |
| 201 | + { |
| 202 | + id: 3, |
| 203 | + name: 'C', |
| 204 | + active: true, |
| 205 | + importance: 'medium', |
| 206 | + address: { city: 'Chicago', code: 60601 }, |
| 207 | + }, |
| 208 | + { |
| 209 | + id: 4, |
| 210 | + name: 'D', |
| 211 | + active: false, |
| 212 | + importance: 'low', |
| 213 | + address: { city: 'New York', code: 10002 }, |
| 214 | + }, |
| 215 | + { id: 5, name: 'a', active: true, importance: 'high', address: { city: 'Chicago', code: 60602 } }, |
| 216 | + { |
| 217 | + id: 6, |
| 218 | + name: 'b', |
| 219 | + active: false, |
| 220 | + importance: 'medium', |
| 221 | + address: { city: 'Los Angeles', code: 90002 }, |
| 222 | + }, |
| 223 | + { id: 7, name: 'c', active: true, importance: 'low', address: { city: 'New York', code: 10003 } }, |
| 224 | + { id: 8, name: 'd', active: true, importance: 'high', address: { city: 'Chicago', code: 60603 } }, |
| 225 | + ]; |
| 226 | + public columns: IgxGridLiteColumnConfiguration<TestData>[] = [ |
| 227 | + { field: 'id', header: 'ID', dataType: 'number' }, |
| 228 | + { field: 'name', header: 'Name', dataType: 'string' }, |
| 229 | + { field: 'active', header: 'Active', dataType: 'boolean' } |
| 230 | + ] |
| 231 | + public shouldAutoGenerate = true; |
| 232 | +} |
| 233 | + |
| 234 | +@Component({ |
| 235 | + template: ` |
| 236 | + <igx-grid-lite [data]="data" #grid [autoGenerate]="shouldAutoGenerate"> |
| 237 | + </igx-grid-lite> |
| 238 | + `, |
| 239 | + standalone: true, |
| 240 | + imports: [IgxGridLiteComponent, IgxGridLiteColumnComponent] |
| 241 | +}) |
| 242 | +class GridComponentAutogenerate extends BasicGridComponent { |
| 243 | + public override shouldAutoGenerate = true; |
| 244 | + public override columns = []; |
| 245 | +} |
| 246 | + |
| 247 | + |
| 248 | +@Component({ |
| 249 | + template: ` |
| 250 | + <igx-grid-lite [data]="data" #grid [autoGenerate]="shouldAutoGenerate"> |
| 251 | + <igx-grid-lite-column [field]="'name'" [header]="'Name'" [headerTemplate]="headerTemplate"></igx-grid-lite-column> |
| 252 | + <igx-grid-lite-column [field]="'active'" [header]="'Active'" [cellTemplate]="bodyTemplate"></igx-grid-lite-column> |
| 253 | + <igx-grid-lite-column [field]="'importance'" [header]="'Importance'" [headerTemplate]="headerTemplate"> |
| 254 | + <ng-template igxGridLiteHeaderTemplate let-column> |
| 255 | + <div>{{column.header}} (Custom Inline)</div> |
| 256 | + </ng-template> |
| 257 | + </igx-grid-lite-column> |
| 258 | + <igx-grid-lite-column [field]="'address'" [header]="'Full address'" [cellTemplate]="bodyTemplate"> |
| 259 | + <ng-template igxGridLiteCellTemplate let-value> |
| 260 | + <span>{{value.city}}, {{value.code}}</span> |
| 261 | + </ng-template> |
| 262 | + </igx-grid-lite-column> |
| 263 | +
|
| 264 | + <ng-template igxGridLiteHeaderTemplate let-column #headerTemplate> |
| 265 | + <div>{{column.header}} (Custom)</div> |
| 266 | + </ng-template> |
| 267 | +
|
| 268 | + <ng-template igxGridLiteCellTemplate let-value let-column="column" #bodyTemplate> |
| 269 | + @if (value === true) { |
| 270 | + <span>Yes</span> |
| 271 | + } @else { |
| 272 | + <span>No</span> |
| 273 | + } |
| 274 | + </ng-template> |
| 275 | + </igx-grid-lite> |
| 276 | + `, |
| 277 | + standalone: true, |
| 278 | + imports: [IgxGridLiteComponent, IgxGridLiteColumnComponent, IgxGridLiteCellTemplateDirective, IgxGridLiteHeaderTemplateDirective] |
| 279 | +}) |
| 280 | +class GridComponentTemplate extends BasicGridComponent { |
| 281 | +} |
| 282 | + |
| 283 | +async function setUp(fixture: ComponentFixture<any>) { |
| 284 | + await customElements.whenDefined('igc-grid-lite'); |
| 285 | + |
| 286 | + const gridElement = fixture.nativeElement.querySelector('igc-grid-lite'); |
| 287 | + const gridBody = gridElement?.renderRoot.querySelector('igc-virtualizer'); |
| 288 | + if (gridBody?.updateComplete) { |
| 289 | + await gridBody.updateComplete; |
| 290 | + } |
| 291 | +} |
0 commit comments