UNPKG

igniteui-angular-sovn

Version:

Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps

905 lines (800 loc) 62.8 kB
import { TestBed, fakeAsync } from '@angular/core/testing'; import { IgxGridComponent } from './grid.component'; import { Component, ViewChild } from '@angular/core'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { IgxColumnLayoutComponent } from '../columns/column-layout.component'; import { By } from '@angular/platform-browser'; import { SampleTestData } from '../../test-utils/sample-test-data.spec'; import { wait } from '../../test-utils/ui-interactions.spec'; import { DefaultSortingStrategy, SortingDirection } from '../../data-operations/sorting-strategy'; import { configureTestSuite } from '../../test-utils/configure-suite'; import { ICellPosition } from '../common/events'; import { GridFunctions, GRID_MRL_BLOCK } from '../../test-utils/grid-functions.spec'; import { NgFor } from '@angular/common'; import { IgxColumnGroupComponent } from '../columns/column-group.component'; import { IgxColumnComponent } from '../columns/column.component'; const GRID_COL_THEAD_CLASS = '.igx-grid-th'; const GRID_MRL_BLOCK_CLASS = `.${GRID_MRL_BLOCK}`; describe('IgxGrid - multi-row-layout #grid', () => { const DEBOUNCETIME = 60; configureTestSuite((() => { return TestBed.configureTestingModule({ imports: [ NoopAnimationsModule, ColumnLayoutTestComponent, ColumnLayoutAndGroupsTestComponent ] }); })); it('should initialize a grid with 1 column group', fakeAsync(() => { const fixture = TestBed.createComponent(ColumnLayoutTestComponent); fixture.detectChanges(); const grid = fixture.componentInstance.grid; const gridFirstRow = grid.rowList.first; // headers are aligned to cells GridFunctions.verifyLayoutHeadersAreAligned(grid, gridFirstRow); GridFunctions.verifyDOMMatchesLayoutSettings(grid, gridFirstRow, fixture.componentInstance.colGroups); const firstRowCellsArr = gridFirstRow.cells.toArray(); // the last cell is spaned as much as the first 3 cells const firstThreeCellsWidth = firstRowCellsArr[0].nativeElement.offsetWidth + firstRowCellsArr[1].nativeElement.offsetWidth + firstRowCellsArr[2].nativeElement.offsetWidth; const lastCellWidth = firstRowCellsArr[3].nativeElement.offsetWidth; expect(2 * firstRowCellsArr[0].nativeElement.offsetHeight).toEqual(firstRowCellsArr[3].nativeElement.offsetHeight); expect(firstThreeCellsWidth).toEqual(lastCellWidth); })); it('should initialize grid with 2 column groups', fakeAsync(() => { const fixture = TestBed.createComponent(ColumnLayoutTestComponent); fixture.detectChanges(); fixture.componentInstance.colGroups.push({ group: 'group2', columns: [ { field: 'ContactName', rowStart: 2, colStart: 1, colEnd: 4, rowEnd: 4 }, { field: 'CompanyName', rowStart: 1, colStart: 1 }, { field: 'PostalCode', rowStart: 1, colStart: 2 }, { field: 'Fax', rowStart: 1, colStart: 3 } ] }); fixture.detectChanges(); const grid = fixture.componentInstance.grid; const gridFirstRow = grid.rowList.first; // headers are aligned to cells GridFunctions.verifyLayoutHeadersAreAligned(grid, gridFirstRow); GridFunctions.verifyDOMMatchesLayoutSettings(grid, gridFirstRow, fixture.componentInstance.colGroups); })); it('should not throw error when layout is incomplete and should render valid mrl block styles', fakeAsync(() => { const fixture = TestBed.createComponent(ColumnLayoutTestComponent); fixture.detectChanges(); // creating an incomplete layout fixture.componentInstance.colGroups = [{ group: 'group1', columns: [ { field: 'ContactName', rowStart: 2, colStart: 1, colEnd: 4, rowEnd: 3 }, { field: 'CompanyName', rowStart: 1, colStart: 1 }, { field: 'PostalCode', rowStart: 1, colStart: 2 }, // { field: 'Fax', rowStart: 1, colStart: 3}, { field: 'Country', rowStart: 3, colStart: 1 }, // { field: 'Region', rowStart: 3, colStart: 2}, { field: 'Phone', rowStart: 3, colStart: 3 } ] }]; fixture.componentInstance.grid.width = '617px'; fixture.detectChanges(); const grid = fixture.componentInstance.grid; const gridFirstRow = grid.rowList.first; // headers are aligned to cells GridFunctions.verifyLayoutHeadersAreAligned(grid, gridFirstRow); // verify block style expect(grid.columnList.first.getGridTemplate(false)).toBe('200px 200px 200px'); expect(grid.columnList.first.getGridTemplate(true)).toBe('repeat(3,1fr)'); // creating an incomplete layout 2 fixture.componentInstance.colGroups = [{ group: 'group1', columns: [ { field: 'ContactName', rowStart: 1, colStart: 1, colEnd: 4, rowEnd: 3 }, { field: 'CompanyName', rowStart: 3, colStart: 1 }, // { field: 'PostalCode', rowStart: 1, colStart: 2}, { field: 'Fax', rowStart: 3, colStart: 3 } ] }]; fixture.componentInstance.grid.width = '617px'; fixture.detectChanges(); expect(grid.columnList.first.getGridTemplate(false)).toBe('200px 200px 200px'); expect(grid.columnList.first.getGridTemplate(true)).toBe('repeat(3,1fr)'); })); it('should initialize correctly when no column widths are set.', fakeAsync(() => { // test with single group const fixture = TestBed.createComponent(ColumnLayoutTestComponent); fixture.detectChanges(); fixture.componentInstance.grid.width = '617px'; fixture.detectChanges(); const grid = fixture.componentInstance.grid; // col span is 3 => columns should have grid width - scrollbarWitdh/3 width // check columns expect(grid.gridAPI.get_cell_by_index(0, 'ID').nativeElement.offsetWidth).toBe(200); expect(grid.gridAPI.get_cell_by_index(0, 'CompanyName').nativeElement.offsetWidth).toBe(200); expect(grid.gridAPI.get_cell_by_index(0, 'ContactName').nativeElement.offsetWidth).toBe(200); expect(grid.gridAPI.get_cell_by_index(0, 'ContactTitle').nativeElement.offsetWidth).toBe(200 * 3); // check group blocks let groupHeaderBlocks = fixture.debugElement.query(By.css('.igx-grid-thead')).queryAll(By.css(GRID_MRL_BLOCK_CLASS)); expect(groupHeaderBlocks[0].nativeElement.clientWidth).toBe(200 * 3); expect(groupHeaderBlocks[0].nativeElement.clientHeight).toBe(51 * 3); let gridFirstRow = grid.rowList.first; GridFunctions.verifyLayoutHeadersAreAligned(grid, gridFirstRow); GridFunctions.verifyDOMMatchesLayoutSettings(grid, gridFirstRow, fixture.componentInstance.colGroups); // test with 2 groups fixture.componentInstance.colGroups.push({ group: 'group2', columns: [ { field: 'Country', rowStart: 1, colStart: 1, colEnd: 4, rowEnd: 3 }, { field: 'Region', rowStart: 3, colStart: 1 }, { field: 'PostalCode', rowStart: 3, colStart: 2 }, { field: 'Fax', rowStart: 3, colStart: 3 } ] }); fixture.componentInstance.grid.width = '917px'; fixture.detectChanges(); // col span is 6 => columns should have grid width - scrollbarWitdh/6 width expect(grid.gridAPI.get_cell_by_index(0, 'ID').nativeElement.offsetWidth).toBe(150); expect(grid.gridAPI.get_cell_by_index(0, 'CompanyName').nativeElement.offsetWidth).toBe(150); expect(grid.gridAPI.get_cell_by_index(0, 'ContactName').nativeElement.offsetWidth).toBe(150); expect(grid.gridAPI.get_cell_by_index(0, 'ContactTitle').nativeElement.offsetWidth).toBe(150 * 3); expect(grid.gridAPI.get_cell_by_index(0, 'Fax').nativeElement.offsetWidth).toBe(150); expect(grid.gridAPI.get_cell_by_index(0, 'Region').nativeElement.offsetWidth).toBe(150); expect(grid.gridAPI.get_cell_by_index(0, 'PostalCode').nativeElement.offsetWidth).toBe(150); expect(grid.gridAPI.get_cell_by_index(0, 'Country').nativeElement.offsetWidth).toBe(150 * 3); // check group blocks groupHeaderBlocks = fixture.debugElement.query(By.css('.igx-grid-thead')).queryAll(By.css(GRID_MRL_BLOCK_CLASS)); expect(groupHeaderBlocks[0].nativeElement.clientWidth).toBe(150 * 3); expect(groupHeaderBlocks[0].nativeElement.clientHeight).toBe(51 * 3); expect(groupHeaderBlocks[1].nativeElement.clientWidth).toBe(150 * 3); expect(groupHeaderBlocks[1].nativeElement.clientHeight).toBe(51 * 3); gridFirstRow = grid.rowList.first; GridFunctions.verifyLayoutHeadersAreAligned(grid, gridFirstRow); GridFunctions.verifyDOMMatchesLayoutSettings(grid, gridFirstRow, fixture.componentInstance.colGroups); // test with 3 groups fixture.componentInstance.colGroups.push({ group: 'group3', columns: [ { field: 'Phone', rowStart: 1, colStart: 1, colEnd: 3, rowEnd: 4 } ] }); fixture.detectChanges(); // col span is 8 => min-width exceeded should use 136px expect(grid.gridAPI.get_cell_by_index(0, 'ID').nativeElement.offsetWidth).toBe(136); expect(grid.gridAPI.get_cell_by_index(0, 'CompanyName').nativeElement.offsetWidth).toBe(136); expect(grid.gridAPI.get_cell_by_index(0, 'ContactName').nativeElement.offsetWidth).toBe(136); expect(grid.gridAPI.get_cell_by_index(0, 'ContactTitle').nativeElement.offsetWidth).toBe(136 * 3); expect(grid.gridAPI.get_cell_by_index(0, 'Fax').nativeElement.offsetWidth).toBe(136); expect(grid.gridAPI.get_cell_by_index(0, 'Region').nativeElement.offsetWidth).toBe(136); expect(grid.gridAPI.get_cell_by_index(0, 'PostalCode').nativeElement.offsetWidth).toBe(136); expect(grid.gridAPI.get_cell_by_index(0, 'Country').nativeElement.offsetWidth).toBe(136 * 3); expect(grid.gridAPI.get_cell_by_index(0, 'Phone').nativeElement.offsetWidth).toBe(136 * 2); // check group blocks groupHeaderBlocks = fixture.debugElement.query(By.css('.igx-grid-thead')).queryAll(By.css(GRID_MRL_BLOCK_CLASS)); expect(groupHeaderBlocks[0].nativeElement.clientWidth).toBe(136 * 3); expect(groupHeaderBlocks[0].nativeElement.clientHeight).toBe(51 * 3); expect(groupHeaderBlocks[1].nativeElement.clientWidth).toBe(136 * 3); expect(groupHeaderBlocks[1].nativeElement.clientHeight).toBe(51 * 3); expect(groupHeaderBlocks[2].nativeElement.clientWidth).toBe(136 * 2); // the following throws error because last colgroup row span in header does not fill content // expect(groupHeaderBlocks[2].nativeElement.clientHeight).toBe(50 * 3); gridFirstRow = grid.rowList.first; GridFunctions.verifyLayoutHeadersAreAligned(grid, gridFirstRow); GridFunctions.verifyDOMMatchesLayoutSettings(grid, gridFirstRow, fixture.componentInstance.colGroups); })); it('should initialize correctly when widths are set in px.', fakeAsync(() => { // test with single group - all cols with colspan 1 have width const fixture = TestBed.createComponent(ColumnLayoutTestComponent); fixture.detectChanges(); fixture.componentInstance.colGroups = [{ group: 'group1', columns: [ { field: 'ID', rowStart: 1, colStart: 1, width: '100px' }, { field: 'CompanyName', rowStart: 1, colStart: 2, width: '200px' }, { field: 'ContactName', rowStart: 1, colStart: 3, width: '300px' }, { field: 'ContactTitle', rowStart: 2, colStart: 1, rowEnd: 4, colEnd: 4 }, ] }]; fixture.detectChanges(); fixture.detectChanges(); const grid = fixture.componentInstance.grid; // check columns expect(grid.gridAPI.get_cell_by_index(0, 'ID').nativeElement.offsetWidth).toBe(100); expect(grid.gridAPI.get_cell_by_index(0, 'CompanyName').nativeElement.offsetWidth).toBe(200); expect(grid.gridAPI.get_cell_by_index(0, 'ContactName').nativeElement.offsetWidth).toBe(300); expect(grid.gridAPI.get_cell_by_index(0, 'ContactTitle').nativeElement.offsetWidth).toBe(600); // check group blocks let groupHeaderBlocks = fixture.debugElement.query(By.css('.igx-grid-thead')).queryAll(By.css(GRID_MRL_BLOCK_CLASS)); expect(groupHeaderBlocks[0].nativeElement.clientWidth).toBe(600); let gridFirstRow = grid.rowList.first; GridFunctions.verifyLayoutHeadersAreAligned(grid, gridFirstRow); GridFunctions.verifyDOMMatchesLayoutSettings(grid, gridFirstRow, fixture.componentInstance.colGroups); // test with 2 groups - only 2 columns with colspan1 have width fixture.componentInstance.colGroups.push({ group: 'group2', columns: [ { field: 'Country', rowStart: 1, colStart: 1, colEnd: 4, rowEnd: 3 }, { field: 'Region', rowStart: 3, colStart: 1, width: '100px' }, { field: 'PostalCode', rowStart: 3, colStart: 2 }, { field: 'Fax', rowStart: 3, colStart: 3, width: '200px' } ] }); fixture.componentInstance.grid.width = '1117px'; fixture.detectChanges(); fixture.detectChanges(); // first group takes 600px, 500px left for second group // check columns expect(grid.gridAPI.get_cell_by_index(0, 'ID').nativeElement.offsetWidth).toBe(100); expect(grid.gridAPI.get_cell_by_index(0, 'CompanyName').nativeElement.offsetWidth).toBe(200); expect(grid.gridAPI.get_cell_by_index(0, 'ContactName').nativeElement.offsetWidth).toBe(300); expect(grid.gridAPI.get_cell_by_index(0, 'ContactTitle').nativeElement.offsetWidth).toBe(600); // This fails for unknown reasons only in travis with 2px difference // expect(grid.gridAPI.get_cell_by_index(0, 'Country').nativeElement.offsetWidth).toBe(500); // expect(grid.gridAPI.get_cell_by_index(0, 'Region').nativeElement.offsetWidth).toBe(100); // // postal code has no width - auto width should be assigned based on available space. // expect(grid.gridAPI.get_cell_by_index(0, 'PostalCode').nativeElement.offsetWidth).toBe(200); // expect(grid.gridAPI.get_cell_by_index(0, 'Fax').nativeElement.offsetWidth).toBe(200); // // check group blocks // groupHeaderBlocks = fixture.debugElement.query(By.css('.igx-grid-thead')).queryAll(By.css(GRID_MRL_BLOCK_CLASS)); // expect(groupHeaderBlocks[1].nativeElement.clientWidth).toBe(500); gridFirstRow = grid.rowList.first; GridFunctions.verifyLayoutHeadersAreAligned(grid, gridFirstRow); GridFunctions.verifyDOMMatchesLayoutSettings(grid, gridFirstRow, fixture.componentInstance.colGroups); // test with 3 groups - only parent has width fixture.componentInstance.colGroups.push({ group: 'group3', columns: [ { field: 'Phone', rowStart: 1, colStart: 1, colEnd: 3, width: '500px' }, { field: 'Phone1', rowStart: 2, colStart: 1, colEnd: 2, rowSpan: 'span 2' }, { field: 'Phone2', rowStart: 2, colStart: 2, colEnd: 3, rowSpan: 'span 2' } ] }); fixture.componentInstance.grid.width = '1617px'; fixture.detectChanges(); fixture.detectChanges(); // check columns expect(grid.gridAPI.get_cell_by_index(0, 'Phone').nativeElement.offsetWidth).toBe(500); expect(grid.gridAPI.get_cell_by_index(0, 'Phone1').nativeElement.offsetWidth).toBe(250); expect(grid.gridAPI.get_cell_by_index(0, 'Phone2').nativeElement.offsetWidth).toBe(250); groupHeaderBlocks = fixture.debugElement.query(By.css('.igx-grid-thead')).queryAll(By.css(GRID_MRL_BLOCK_CLASS)); expect(groupHeaderBlocks[2].nativeElement.clientWidth).toBe(500); gridFirstRow = grid.rowList.first; // headerCells = grid.theadRow._groups.last.children; GridFunctions.verifyLayoutHeadersAreAligned(grid, gridFirstRow); })); it('should correctly autofit column without width when there are other set with width in pixels', fakeAsync(() => { // In this case it would be for City column and 3rd template column. const fixture = TestBed.createComponent(ColumnLayoutTestComponent); fixture.detectChanges(); // creating an incomplete layout fixture.componentInstance.grid.width = '1200px'; fixture.componentInstance.colGroups = [{ group: 'group1', columns: [ { field: 'ContactName', rowStart: 1, colStart: 1, colEnd: 4 }, { field: 'ContactTitle', rowStart: 1, colStart: 4, colEnd: 6, width: '200px' }, { field: 'Country', rowStart: 1, colStart: 6, colEnd: 7, width: '200px' }, { field: 'Phone', rowStart: 2, colStart: 1, colEnd: 3, width: '200px' }, { field: 'City', rowStart: 2, colStart: 3, colEnd: 5 }, { field: 'Address', rowStart: 2, colStart: 5, colEnd: 7, width: '200px' }, { field: 'CompanyName', rowStart: 3, colStart: 1, colEnd: 2, width: '200px' }, { field: 'PostalCode', rowStart: 3, colStart: 2, colEnd: 3, width: '200px' }, { field: 'Fax', rowStart: 3, colStart: 3, colEnd: 7 }, ] }]; fixture.detectChanges(); const grid = fixture.componentInstance.grid; const gridFirstRow = grid.rowList.first; // headers are aligned to cells GridFunctions.verifyLayoutHeadersAreAligned(grid, gridFirstRow); const autoSizedColumnWidth = 400 - grid.scrollSize; const groupRowBlocks = fixture.debugElement.query(By.css('.igx-grid__tbody')).queryAll(By.css(GRID_MRL_BLOCK_CLASS)); expect(groupRowBlocks[0].nativeElement.style.gridTemplateColumns) .toEqual('200px 200px ' + autoSizedColumnWidth + 'px 100px 100px 200px'); })); it('should correctly size column without width when it overlaps partially with bigger column that has width above it', fakeAsync(() => { // In this case it would be for City column and 3rd template column overlapping width ContactName. const fixture = TestBed.createComponent(ColumnLayoutTestComponent); // creating an incomplete layout fixture.componentInstance.grid.width = '1200px'; fixture.componentInstance.colGroups = [{ group: 'group1', columns: [ { field: 'ContactName', rowStart: 1, colStart: 1, colEnd: 4, width: '300px' }, { field: 'ContactTitle', rowStart: 1, colStart: 4, colEnd: 6, width: '200px' }, { field: 'Country', rowStart: 1, colStart: 6, colEnd: 7, width: '200px' }, { field: 'Phone', rowStart: 2, colStart: 1, colEnd: 3, width: '200px' }, { field: 'City', rowStart: 2, colStart: 3, colEnd: 5 }, { field: 'Address', rowStart: 2, colStart: 5, colEnd: 7, width: '200px' }, { field: 'CompanyName', rowStart: 3, colStart: 1, colEnd: 2, width: '200px' }, { field: 'PostalCode', rowStart: 3, colStart: 2, colEnd: 3, width: '200px' }, { field: 'Fax', rowStart: 3, colStart: 3, colEnd: 7 }, ] }]; fixture.detectChanges(); const grid = fixture.componentInstance.grid; const gridFirstRow = grid.rowList.first; // headers are aligned to cells GridFunctions.verifyLayoutHeadersAreAligned(grid, gridFirstRow); const groupRowBlocks = fixture.debugElement.query(By.css('.igx-grid__tbody')).queryAll(By.css(GRID_MRL_BLOCK_CLASS)); expect(groupRowBlocks[0].nativeElement.style.gridTemplateColumns).toEqual('200px 200px 100px 100px 100px 200px'); })); it('should correctly size column without width when it overlaps partially with bigger column that has width bellow it', fakeAsync(() => { // In this case it would be for City column and 3rd template column overlapping width ContactName. const fixture = TestBed.createComponent(ColumnLayoutTestComponent); // creating an incomplete layout fixture.componentInstance.grid.width = '1200px'; fixture.componentInstance.colGroups = [{ group: 'group1', columns: [ { field: 'ContactName', rowStart: 1, colStart: 1, colEnd: 5, width: '200px' }, { field: 'ContactTitle', rowStart: 1, colStart: 5, colEnd: 6, width: '200px' }, { field: 'Country', rowStart: 1, colStart: 6, colEnd: 7 }, { field: 'Phone', rowStart: 2, colStart: 1, colEnd: 3, width: '200px' }, { field: 'City', rowStart: 2, colStart: 3, colEnd: 5, width: '200px' }, { field: 'Address', rowStart: 2, colStart: 5, colEnd: 7, width: '300px' }, { field: 'CompanyName', rowStart: 3, colStart: 1, colEnd: 2, width: '200px' }, { field: 'PostalCode', rowStart: 3, colStart: 2, colEnd: 3, width: '200px' }, { field: 'Fax', rowStart: 3, colStart: 3, colEnd: 7, width: '200px' }, ] }]; fixture.detectChanges(); const grid = fixture.componentInstance.grid; const gridFirstRow = grid.rowList.first; // headers are aligned to cells GridFunctions.verifyLayoutHeadersAreAligned(grid, gridFirstRow); const groupRowBlocks = fixture.debugElement.query(By.css('.igx-grid__tbody')).queryAll(By.css(GRID_MRL_BLOCK_CLASS)); expect(groupRowBlocks[0].nativeElement.style.gridTemplateColumns).toEqual('200px 200px 100px 100px 200px 150px'); })); it('should correctly set column width when there is bigger column at the bottom where there is not width yet', fakeAsync(() => { // In this case it would be for City column and 3rd template column. const fixture = TestBed.createComponent(ColumnLayoutTestComponent); // creating an incomplete layout fixture.componentInstance.grid.width = '1200px'; fixture.componentInstance.colGroups = [{ group: 'group1', columns: [ { field: 'ContactName', rowStart: 1, colStart: 1, colEnd: 4 }, { field: 'ContactTitle', rowStart: 1, colStart: 4, colEnd: 6, width: '200px' }, { field: 'Country', rowStart: 1, colStart: 6, colEnd: 7, width: '200px' }, { field: 'Phone', rowStart: 2, colStart: 1, colEnd: 3, width: '200px' }, { field: 'City', rowStart: 2, colStart: 3, colEnd: 5 }, { field: 'Address', rowStart: 2, colStart: 5, colEnd: 7, width: '200px' }, { field: 'CompanyName', rowStart: 3, colStart: 1, colEnd: 2, width: '200px' }, { field: 'PostalCode', rowStart: 3, colStart: 2, colEnd: 3, width: '200px' }, { field: 'Fax', rowStart: 3, colStart: 3, colEnd: 7, width: '400px' }, ] }]; fixture.detectChanges(); const grid = fixture.componentInstance.grid; const gridFirstRow = grid.rowList.first; // headers are aligned to cells GridFunctions.verifyLayoutHeadersAreAligned(grid, gridFirstRow); const groupRowBlocks = fixture.debugElement.query(By.css('.igx-grid__tbody')).queryAll(By.css(GRID_MRL_BLOCK_CLASS)); expect(groupRowBlocks[0].nativeElement.style.gridTemplateColumns).toEqual('200px 200px 100px 100px 100px 200px'); })); it('should correctly set column width of column without width when there are two bigger columns that overlap with it', fakeAsync(() => { // In this case it would be for City column and 3rd template column overlapping with ContactName and Fax. const fixture = TestBed.createComponent(ColumnLayoutTestComponent); // creating an incomplete layout fixture.componentInstance.grid.width = '1200px'; fixture.componentInstance.colGroups = [{ group: 'group1', columns: [ { field: 'ContactName', rowStart: 1, colStart: 1, colEnd: 4, width: '360px' }, { field: 'ContactTitle', rowStart: 1, colStart: 4, colEnd: 6, width: '200px' }, { field: 'Country', rowStart: 1, colStart: 6, colEnd: 7, width: '200px' }, { field: 'Phone', rowStart: 2, colStart: 1, colEnd: 3, width: '200px' }, { field: 'City', rowStart: 2, colStart: 3, colEnd: 5 }, { field: 'Address', rowStart: 2, colStart: 5, colEnd: 7, width: '200px' }, { field: 'CompanyName', rowStart: 3, colStart: 1, colEnd: 2, width: '200px' }, { field: 'PostalCode', rowStart: 3, colStart: 2, colEnd: 3, width: '200px' }, { field: 'Fax', rowStart: 3, colStart: 3, colEnd: 7, width: '400px' }, ] }]; fixture.detectChanges(); const grid = fixture.componentInstance.grid; const gridFirstRow = grid.rowList.first; // headers are aligned to cells GridFunctions.verifyLayoutHeadersAreAligned(grid, gridFirstRow); const groupRowBlocks = fixture.debugElement.query(By.css('.igx-grid__tbody')).queryAll(By.css(GRID_MRL_BLOCK_CLASS)); expect(groupRowBlocks[0].nativeElement.style.gridTemplateColumns).toEqual('200px 200px 120px 100px 100px 200px'); })); it('should correctly autofit column without width when grid width is not enough and other cols are set in pixels', fakeAsync(() => { // In this case it would be for City column and 3rd template column. const fixture = TestBed.createComponent(ColumnLayoutTestComponent); // creating an incomplete layout fixture.componentInstance.grid.width = '700px'; fixture.componentInstance.colGroups = [{ group: 'group1', columns: [ { field: 'ContactName', rowStart: 1, colStart: 1, colEnd: 4 }, { field: 'ContactTitle', rowStart: 1, colStart: 4, colEnd: 6, width: '200px' }, { field: 'Country', rowStart: 1, colStart: 6, colEnd: 7, width: '200px' }, { field: 'Phone', rowStart: 2, colStart: 1, colEnd: 3, width: '200px' }, { field: 'City', rowStart: 2, colStart: 3, colEnd: 5 }, { field: 'Address', rowStart: 2, colStart: 5, colEnd: 7, width: '200px' }, { field: 'CompanyName', rowStart: 3, colStart: 1, colEnd: 2, width: '200px' }, { field: 'PostalCode', rowStart: 3, colStart: 2, colEnd: 3, width: '200px' }, { field: 'Fax', rowStart: 3, colStart: 3, colEnd: 7 }, ] }]; fixture.detectChanges(); const grid = fixture.componentInstance.grid; const gridFirstRow = grid.rowList.first; // headers are aligned to cells GridFunctions.verifyLayoutHeadersAreAligned(grid, gridFirstRow); const groupRowBlocks = fixture.debugElement.query(By.css('.igx-grid__tbody')).queryAll(By.css(GRID_MRL_BLOCK_CLASS)); expect(groupRowBlocks[0].nativeElement.style.gridTemplateColumns).toEqual('200px 200px 136px 100px 100px 200px'); })); it('should autofit a column with span 1 that does not have width set and is under a col with span 2 with width set', fakeAsync(() => { // In this case it would be for Phone, CompanyName and PostalCode columns and first 2 template columns. const fixture = TestBed.createComponent(ColumnLayoutTestComponent); // creating an incomplete layout fixture.componentInstance.grid.width = '700px'; fixture.componentInstance.colGroups = [{ group: 'group1', columns: [ { field: 'ContactName', rowStart: 1, colStart: 1, colEnd: 4 }, { field: 'ContactTitle', rowStart: 1, colStart: 4, colEnd: 6, width: '200px' }, { field: 'Country', rowStart: 1, colStart: 6, colEnd: 7, width: '200px' }, { field: 'Phone', rowStart: 2, colStart: 1, colEnd: 3 }, { field: 'City', rowStart: 2, colStart: 3, colEnd: 5 }, { field: 'Address', rowStart: 2, colStart: 5, colEnd: 7, width: '200px' }, { field: 'CompanyName', rowStart: 3, colStart: 1, colEnd: 2, width: '200px' }, { field: 'PostalCode', rowStart: 3, colStart: 2, colEnd: 3 }, { field: 'Fax', rowStart: 3, colStart: 3, colEnd: 7 }, ] }]; fixture.detectChanges(); const grid = fixture.componentInstance.grid; const gridFirstRow = grid.rowList.first; // headers are aligned to cells GridFunctions.verifyLayoutHeadersAreAligned(grid, gridFirstRow); const groupRowBlocks = fixture.debugElement.query(By.css('.igx-grid__tbody')).queryAll(By.css(GRID_MRL_BLOCK_CLASS)); expect(groupRowBlocks[0].nativeElement.style.gridTemplateColumns).toEqual('200px 136px 136px 100px 100px 200px'); })); it('should use column width of a column with span 2 that has width when there are no columns with span 1 to take width from', fakeAsync(() => { // In this case it would be for Phone, CompanyName and PostalCode columns and first 2 template columns. const fixture = TestBed.createComponent(ColumnLayoutTestComponent); // creating an incomplete layout fixture.componentInstance.grid.width = '700px'; fixture.componentInstance.colGroups = [{ group: 'group1', columns: [ { field: 'ContactName', rowStart: 1, colStart: 1, colEnd: 4 }, { field: 'ContactTitle', rowStart: 1, colStart: 4, colEnd: 6, width: '200px' }, { field: 'Country', rowStart: 1, colStart: 6, colEnd: 7, width: '200px' }, { field: 'Phone', rowStart: 2, colStart: 1, colEnd: 3, width: '200px' }, { field: 'City', rowStart: 2, colStart: 3, colEnd: 5 }, { field: 'Address', rowStart: 2, colStart: 5, colEnd: 7, width: '200px' }, { field: 'CompanyName', rowStart: 3, colStart: 1, colEnd: 2 }, { field: 'PostalCode', rowStart: 3, colStart: 2, colEnd: 3 }, { field: 'Fax', rowStart: 3, colStart: 3, colEnd: 7 }, ] }]; fixture.detectChanges(); const grid = fixture.componentInstance.grid; const gridFirstRow = grid.rowList.first; // headers are aligned to cells GridFunctions.verifyLayoutHeadersAreAligned(grid, gridFirstRow); const groupRowBlocks = fixture.debugElement.query(By.css('.igx-grid__tbody')).queryAll(By.css(GRID_MRL_BLOCK_CLASS)); expect(groupRowBlocks[0].nativeElement.style.gridTemplateColumns).toEqual('100px 100px 136px 100px 100px 200px'); })); it('should use divided column width when there is stairway type of defined columns and they have widths set', fakeAsync(() => { // In this case it would be for Country and Address columns and last 3 template columns. const fixture = TestBed.createComponent(ColumnLayoutTestComponent); // creating an incomplete layout fixture.componentInstance.grid.width = '700px'; fixture.componentInstance.colGroups = [{ group: 'group1', columns: [ { field: 'ContactName', rowStart: 1, colStart: 1, colEnd: 4 }, { field: 'ContactTitle', rowStart: 1, colStart: 4, colEnd: 6, width: '200px' }, { field: 'Country', rowStart: 1, colStart: 6, colEnd: 8, width: '200px' }, { field: 'Phone', rowStart: 2, colStart: 1, colEnd: 3, width: '200px' }, { field: 'City', rowStart: 2, colStart: 3, colEnd: 5 }, { field: 'Address', rowStart: 2, colStart: 5, colEnd: 8, width: '150px' }, { field: 'CompanyName', rowStart: 3, colStart: 1, colEnd: 2 }, { field: 'PostalCode', rowStart: 3, colStart: 2, colEnd: 3 }, { field: 'Fax', rowStart: 3, colStart: 3, colEnd: 8 }, ] }]; fixture.detectChanges(); const grid = fixture.componentInstance.grid; const gridFirstRow = grid.rowList.first; // headers are aligned to cells GridFunctions.verifyLayoutHeadersAreAligned(grid, gridFirstRow); const groupRowBlocks = fixture.debugElement.query(By.css('.igx-grid__tbody')).queryAll(By.css(GRID_MRL_BLOCK_CLASS)); expect(groupRowBlocks[0].nativeElement.style.gridTemplateColumns).toEqual('100px 100px 136px 100px 100px 100px 100px'); })); it('should initialize correctly when widths are set in %.', fakeAsync(() => { const fixture = TestBed.createComponent(ColumnLayoutTestComponent); fixture.detectChanges(); const grid = fixture.componentInstance.grid; fixture.componentInstance.colGroups = [{ group: 'group1', columns: [ { field: 'ID', rowStart: 1, colStart: 1, width: '10%' }, { field: 'CompanyName', rowStart: 1, colStart: 2, width: '20%' }, { field: 'ContactName', rowStart: 1, colStart: 3, width: '30%' }, { field: 'ContactTitle', rowStart: 2, colStart: 1, rowEnd: 4, colEnd: 4 }, ] }]; fixture.detectChanges(); fixture.componentInstance.grid.width = (1000 + grid.scrollSize) + 'px'; fixture.detectChanges(); // check columns expect(grid.gridAPI.get_cell_by_index(0, 'ID').nativeElement.offsetWidth).toBe(100); expect(grid.gridAPI.get_cell_by_index(0, 'CompanyName').nativeElement.offsetWidth).toBe(200); expect(grid.gridAPI.get_cell_by_index(0, 'ContactName').nativeElement.offsetWidth).toBe(300); expect(grid.gridAPI.get_cell_by_index(0, 'ContactTitle').nativeElement.offsetWidth).toBe(600); // check group blocks // let groupHeaderBlocks = fixture.debugElement.query(By.css('.igx-grid-thead')).queryAll(By.css(GRID_MRL_BLOCK_CLASS)); let groupHeaderBlocks = grid.theadRow.nativeElement.querySelectorAll(GRID_MRL_BLOCK_CLASS); expect(groupHeaderBlocks[0].clientWidth).toBe(600); let gridFirstRow = grid.rowList.first; GridFunctions.verifyLayoutHeadersAreAligned(grid, gridFirstRow); GridFunctions.verifyDOMMatchesLayoutSettings(grid, gridFirstRow, fixture.componentInstance.colGroups); fixture.componentInstance.colGroups.push({ group: 'group2', columns: [ { field: 'Country', rowStart: 1, colStart: 1, colEnd: 4, rowEnd: 3 }, { field: 'Region', rowStart: 3, colStart: 1, width: '10%' }, { field: 'PostalCode', rowStart: 3, colStart: 2 }, { field: 'Fax', rowStart: 3, colStart: 3, width: '20%' } ] }); fixture.detectChanges(); fixture.detectChanges(); // check columns expect(grid.gridAPI.get_cell_by_index(0, 'Country').nativeElement.offsetWidth).toBe(100 + 200 + 136); expect(grid.gridAPI.get_cell_by_index(0, 'Region').nativeElement.offsetWidth).toBe(100); expect(grid.gridAPI.get_cell_by_index(0, 'PostalCode').nativeElement.offsetWidth).toBe(136); expect(grid.gridAPI.get_cell_by_index(0, 'Fax').nativeElement.offsetWidth).toBe(200); // check group blocks // groupHeaderBlocks = fixture.debugElement.query(By.css('.igx-grid-thead')).queryAll(By.css(GRID_MRL_BLOCK_CLASS)); groupHeaderBlocks = grid.theadRow.nativeElement.querySelectorAll(GRID_MRL_BLOCK_CLASS); expect(groupHeaderBlocks[1].clientWidth).toBe(436); gridFirstRow = grid.rowList.first; // headerCells = grid.theadRow._groups.last.children; GridFunctions.verifyLayoutHeadersAreAligned(grid, gridFirstRow); GridFunctions.verifyDOMMatchesLayoutSettings(grid, gridFirstRow, fixture.componentInstance.colGroups); fixture.componentInstance.colGroups = [{ group: 'group1', columns: [ { field: 'ID', rowStart: 1, colStart: 1 }, { field: 'CompanyName', rowStart: 1, colStart: 2 }, { field: 'ContactName', rowStart: 1, colStart: 3 }, { field: 'Country', rowStart: 2, colStart: 1, colEnd: 3 }, { field: 'Region', rowStart: 2, colStart: 3 }, { field: 'ContactTitle', rowStart: 3, colStart: 1, rowEnd: 5, colEnd: 4, width: '60%' }, ] }]; fixture.detectChanges(); fixture.detectChanges(); // check columns expect(grid.gridAPI.get_cell_by_index(0, 'ID').nativeElement.offsetWidth).toBe(200); expect(grid.gridAPI.get_cell_by_index(0, 'CompanyName').nativeElement.offsetWidth).toBe(200); expect(grid.gridAPI.get_cell_by_index(0, 'ContactName').nativeElement.offsetWidth).toBe(200); expect(grid.gridAPI.get_cell_by_index(0, 'ContactTitle').nativeElement.offsetWidth).toBe(600); expect(grid.gridAPI.get_cell_by_index(0, 'Country').nativeElement.offsetWidth).toBe(400); expect(grid.gridAPI.get_cell_by_index(0, 'Region').nativeElement.offsetWidth).toBe(200); // check group blocks // groupHeaderBlocks = fixture.debugElement.query(By.css('.igx-grid-thead')).queryAll(By.css(GRID_MRL_BLOCK_CLASS)); groupHeaderBlocks = grid.theadRow.nativeElement.querySelectorAll(GRID_MRL_BLOCK_CLASS); expect(groupHeaderBlocks[0].clientWidth).toBe(600); expect((groupHeaderBlocks[0] as HTMLElement).style.gridTemplateColumns).toEqual('200px 200px 200px'); gridFirstRow = grid.rowList.first; GridFunctions.verifyLayoutHeadersAreAligned(grid, gridFirstRow); GridFunctions.verifyDOMMatchesLayoutSettings(grid,gridFirstRow, fixture.componentInstance.colGroups); })); it('should initialize correctly when grid width is in % and no widths are set for columns.', fakeAsync(() => { const fixture = TestBed.createComponent(ColumnLayoutTestComponent); const grid = fixture.componentInstance.grid; fixture.componentInstance.colGroups = [{ group: 'group1', columns: [ { field: 'ID', rowStart: 1, colStart: 1 }, { field: 'CompanyName', rowStart: 1, colStart: 2 }, { field: 'ContactName', rowStart: 1, colStart: 3, colEnd: 5 }, { field: 'ContactTitle', rowStart: 2, colStart: 1, rowEnd: 3, colEnd: 4 }, ] }]; fixture.componentInstance.grid.width = '100%'; fixture.detectChanges(); // check group blocks // const groupHeaderBlocks = fixture.debugElement.query(By.css('.igx-grid-thead')).queryAll(By.css(GRID_MRL_BLOCK_CLASS)); const groupHeaderBlocks = grid.theadRow.nativeElement.querySelectorAll(GRID_MRL_BLOCK_CLASS); expect(groupHeaderBlocks[0].clientWidth).toBe(groupHeaderBlocks[0].parentElement.clientWidth); const gridFirstRow = grid.rowList.first; GridFunctions.verifyLayoutHeadersAreAligned(grid, gridFirstRow); GridFunctions.verifyDOMMatchesLayoutSettings(grid, gridFirstRow, fixture.componentInstance.colGroups); })); it('should use columns with the smallest col spans when determining the column group’s column widths.', fakeAsync(() => { const fixture = TestBed.createComponent(ColumnLayoutTestComponent); const grid = fixture.componentInstance.grid; fixture.componentInstance.colGroups = [{ group: 'group2', columns: [ { field: 'ContactName', rowStart: 2, colStart: 1, colEnd: 4, rowEnd: 4, width: '500px' }, { field: 'CompanyName', rowStart: 1, colStart: 1, width: '100px' }, { field: 'PostalCode', rowStart: 1, colStart: 2, width: '200px' }, { field: 'Fax', rowStart: 1, colStart: 3, width: '100px' } ] }]; fixture.detectChanges(); // check group blocks // let groupHeaderBlocks = fixture.debugElement.query(By.css('.igx-grid-thead')).queryAll(By.css(GRID_MRL_BLOCK_CLASS)); let groupHeaderBlocks = grid.theadRow.nativeElement.querySelectorAll(GRID_MRL_BLOCK_CLASS); expect(groupHeaderBlocks[0].clientWidth).toBe(400); expect((groupHeaderBlocks[0] as HTMLElement).style.gridTemplateColumns).toBe('100px 200px 100px'); fixture.componentInstance.colGroups = [{ group: 'group2', columns: [ { field: 'ContactName', rowStart: 1, colStart: 1, colEnd: 4, rowEnd: 2, width: '500px' }, { field: 'CompanyName', rowStart: 2, colStart: 1, width: '100px' }, { field: 'PostalCode', rowStart: 2, colStart: 2, width: '200px' }, { field: 'Fax', rowStart: 2, colStart: 3, width: '100px' } ] }]; fixture.detectChanges(); // check group blocks groupHeaderBlocks = grid.theadRow.nativeElement.querySelectorAll(GRID_MRL_BLOCK_CLASS); expect(groupHeaderBlocks[0].clientWidth).toBe(400); expect((groupHeaderBlocks[0] as HTMLElement).style.gridTemplateColumns).toBe('100px 200px 100px'); })); it('should disregard column groups if multi-column layouts are also defined.', fakeAsync(() => { const fixture = TestBed.createComponent(ColumnLayoutAndGroupsTestComponent); fixture.detectChanges(); const grid = fixture.componentInstance.grid; // check grid's columns collection // 5 in total expect(grid.columns.length).toBe(5); // 1 column layout expect(grid.columns.filter(x => x.columnLayout).length).toBe(1); // 4 normal columns expect(grid.columns.filter(x => !x.columnLayout && !x.columnGroup).length).toBe(4); // check header expect(document.querySelectorAll('igx-grid-header-group').length).toEqual(5); expect(document.querySelectorAll(GRID_COL_THEAD_CLASS).length).toEqual(4); })); it('should render correct heights when groups have different total row span', fakeAsync(() => { const fixture = TestBed.createComponent(ColumnLayoutAndGroupsTestComponent); const grid = fixture.componentInstance.grid; fixture.componentInstance.colGroups = [ { group: 'group1', // group with total row span 1 columns: [ { field: 'Fax', rowStart: 1, colStart: 1 } ] }, { group: 'group2', // group with total row span 2 columns: [ { field: 'ContactName', rowStart: 1, colStart: 1, colEnd: 4, rowEnd: 2 }, { field: 'CompanyName', rowStart: 2, colStart: 1 }, { field: 'PostalCode', rowStart: 2, colStart: 2 }, { field: 'Fax', rowStart: 2, colStart: 3 } ] }]; fixture.detectChanges(); // check first group has height of 2 row spans in header and rows but the header itself should span 1 row // check group block and column header height const firstLayout = grid.columns[0]; expect(grid.multiRowLayoutRowSize).toEqual(2); expect(firstLayout.getGridTemplate(true)).toEqual('repeat(2,1fr)'); expect(firstLayout.headerGroup.nativeElement.offsetHeight).toBe((grid.rowHeight + 1) * 2); expect(grid.getColumnByName('Fax').headerCell.nativeElement.offsetHeight).toBe(grid.rowHeight + 1); const secondLayout = grid.columns[2]; const contactNameColumn = grid.getColumnByName('ContactName'); expect(contactNameColumn.getGridTemplate(true)).toEqual('repeat(2,1fr)'); expect(secondLayout.headerGroup.nativeElement.offsetHeight).toBe((grid.rowHeight + 1) * 2); // check cell height in row. By default should span 1 row const firstCell = grid.gridAPI.get_cell_by_index(0, 'Fax').nativeElement; expect(firstCell.offsetHeight).toEqual(grid.gridAPI.get_cell_by_index(0, 'ContactName').nativeElement.offsetHeight); })); // Virtualization it('should apply horizontal virtualization based on the group blocks.', async () => { const fixture = TestBed.createComponent(ColumnLayoutTestComponent); const grid = fixture.componentInstance.grid; const uniqueGroups = [ { group: 'group1', // total colspan 3 columns: [ { field: 'Address', rowStart: 1, colStart: 1, colEnd: 4, rowEnd: 3 }, { field: 'County', rowStart: 3, colStart: 1 }, { field: 'Region', rowStart: 3, colStart: 2 }, { field: 'City', rowStart: 3, colStart: 3 } ] }, { group: 'group2', // total colspan 2 columns: [ { field: 'CompanyName', rowStart: 1, colStart: 1 }, { field: 'Address', rowStart: 1, colStart: 2 }, { field: 'ContactName', rowStart: 2, colStart: 1, colEnd: 3, rowEnd: 4 } ] }, { group: 'group3', // total colspan 1 columns: [ { field: 'Phone', rowStart: 1, colStart: 1 }, { field: 'Fax', rowStart: 2, colStart: 1, rowEnd: 4 } ] }, { group: 'group4', // total colspan 4 columns: [ { field: 'CompanyName', rowStart: 1, colStart: 1, colEnd: 3 }, { field: 'Phone', rowStart: 1, colStart: 3, rowEnd: 3 }, { field: 'Address', rowStart: 1, colStart: 4, rowEnd: 4 }, { field: 'Region', rowStart: 2, colStart: 1 }, { field: 'City', rowStart: 2, colStart: 2 }, { field: 'ContactName', rowStart: 3, colStart: 1, colEnd: 4 }, ] } ]; fixture.componentInstance.colGroups = []; for (let i = 0; i < 3; i++) { fixture.componentInstance.colGroups = fixture.componentInstance.colGroups.concat(uniqueGroups); } grid.columnWidth = '200px'; fixture.componentInstance.grid.width = '600px'; fixture.detectChanges(); // 12 groups in total const horizontalVirtualization = grid.rowList.first.virtDirRow; expect(grid.hasHorizontalScroll()).toBeTruthy(); expect(horizontalVirtualization.igxForOf.length).toBe(12); // check chunk size is correct expect(horizontalVirtualization.state.chunkSize).toBe(3); // check passed instances to igxFor are the groups expect(horizontalVirtualization.igxForOf[0] instanceof IgxColumnLayoutComponent).toBeTruthy(); // check their sizes are correct expect(horizontalVirtualization.getSizeAt(0)).toBe(3 * 200); expect(horizontalVirtualization.getSizeAt(1)).toBe(2 * 200); expect(horizontalVirtualization.getSizeAt(2)).toBe(200); expect(horizontalVirtualization.getSizeAt(3)).toBe(4 * 200); // check total widths sum - unique col groups col span 10 in total * 200px default witdth * 3 times repeated const horizonatalScrElem = horizontalVirtualization.getScroll(); const totalExpected = 10 * 200 * 3; expect(parseInt((horizonatalScrElem.children[0] as HTMLElement).style.width, 10)).toBe(totalExpected); // check groups are rendered correctly const gridFirstRow = grid.rowList.first; GridFunctions.verifyLayoutHeadersAreAligned(grid, gridFirstRow); GridFunctions.verifyDOMMatchesLayoutSettings(grid, gridFirstRow, fixture.componentInstance.colGroups.slice(0, horizontalVirtualization.state.chunkSize)); // check last column group can be scrolled in view horizontalVirtualization.scrollTo(11); await wait(100); fixture.detectChanges(); // last 3 blocks should be rendered GridFunctions.verifyDOMMatchesLayoutSettings(grid, grid.rowList.first, fixture.componentInstance.colGroups.slice( horizontalVirtualization.state.startIndex, horizontalVirtualization.state.startIndex + horizontalVirtualization.state.chunkSize)); }); it('should apply horizontal virtualization correctly for widths in px, % and no-width columns.', fakeAsync(() => { const fixture = TestBed.createComponent(ColumnLayoutTestComponent); fixture.detectChanges(); const grid = fixture.componentInstance.grid; // test with px fixture.componentInstance.colGroups = [{ group: 'group1', // total colspan 3 columns: [ { field: 'Address', rowStart: 1, colStart: 1, colEnd: 4, rowEnd: 3 }, { field: 'County', rowStart: 3, colStart: 1, width: '200px' }, { field: 'Region', rowStart: 3, colStart: 2, width: '300px' }, { field: 'City', rowStart: 3, colStart: 3, width: '200px' } ] }]; fixture.componentInstance.grid