From 32970250f754f505586dea4cf2e492f5e92de700 Mon Sep 17 00:00:00 2001 From: Diana Broeders Date: Tue, 16 Jul 2024 09:41:54 +0200 Subject: [PATCH 01/29] removed default value, added tests --- packages/components/grid/src/column.spec.ts | 100 ++++++++++++++++++++ packages/components/grid/src/column.ts | 2 +- packages/components/grid/src/grid.scss | 1 + 3 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 packages/components/grid/src/column.spec.ts diff --git a/packages/components/grid/src/column.spec.ts b/packages/components/grid/src/column.spec.ts new file mode 100644 index 0000000000..e67bed7cdf --- /dev/null +++ b/packages/components/grid/src/column.spec.ts @@ -0,0 +1,100 @@ +import { setupIgnoreWindowResizeObserverLoopErrors } from '@lit-labs/virtualizer/support/resize-observer-errors.js'; +import { expect, fixture } from '@open-wc/testing'; +import { Avatar } from '@sl-design-system/avatar'; +import { html } from 'lit'; +import { Person } from 'tools/example-data/index.js'; +import '../register.js'; +import { GridColumnDataRenderer } from './column.js'; +import { type Grid } from './grid.js'; + +setupIgnoreWindowResizeObserverLoopErrors(beforeEach, afterEach); + +describe('sl-grid', () => { + let el: Grid; + let cells: HTMLElement[]; + + describe('defaults', () => { + beforeEach(async () => { + el = await fixture(html` + + + + + + `); + el.items = [ + { firstName: 'John', lastName: 'Doe', age: 20 }, + { firstName: 'Jane', lastName: 'Smith', age: 40 } + ]; + await el.updateComplete; + + // Give grid time to render the table structure + await new Promise(resolve => setTimeout(resolve, 100)); + await el.updateComplete; + + cells = Array.from(el.renderRoot.querySelectorAll('tbody tr:first-of-type td')); + }); + + it('should render column headers', () => { + const columns = Array.from(el.renderRoot.querySelectorAll('th')).map(col => col.textContent); + + expect(columns).to.deep.equal(['First name', 'Last name', 'Age']); + }); + + it('should have the right justify-content value', () => { + expect(cells.map(cell => getComputedStyle(cell).justifyContent)).to.deep.equal(['start', 'start', 'end']); + }); + + it('should have the right grow value', () => { + expect(cells.map(cell => getComputedStyle(cell).flexGrow)).to.deep.equal(['1', '1', '3']); + }); + + it('should have the right parts', () => { + expect(cells.map(cell => cell.getAttribute('part'))).to.deep.equal([ + 'data first-name', + 'data last-name', + 'data age' + ]); + }); + }); + + describe('custom renderer', () => { + beforeEach(async () => { + const avatarRenderer: GridColumnDataRenderer = ({ firstName, lastName }) => { + return html``; + }; + + el = await fixture(html` + + + + + `); + el.items = [ + { firstName: 'John', lastName: 'Doe', age: 20 }, + { firstName: 'Jane', lastName: 'Smith', age: 40 } + ]; + await el.updateComplete; + + // Give grid time to render the table structure + await new Promise(resolve => setTimeout(resolve, 100)); + await el.updateComplete; + + cells = Array.from(el.renderRoot.querySelectorAll('tbody tr:first-of-type td')); + }); + + it('should render the elements set with the custom renderer', () => { + expect(cells[0]).to.contain('sl-avatar'); + }); + + it('should have the right parts, including one set on the column', () => { + expect(cells.map(cell => cell.getAttribute('part'))).to.deep.equal(['data', 'data number age']); + }); + }); +}); diff --git a/packages/components/grid/src/column.ts b/packages/components/grid/src/column.ts index ae4688226f..a69995bcfe 100644 --- a/packages/components/grid/src/column.ts +++ b/packages/components/grid/src/column.ts @@ -43,7 +43,7 @@ export class GridColumn extends LitElement { #width?: number; /** The alignment of the content within the column. */ - @property() align: GridColumnAlignment = 'start'; + @property() align?: GridColumnAlignment; /** * Automatically sets the width of the column based on the column contents when this is set to `true`. diff --git a/packages/components/grid/src/grid.scss b/packages/components/grid/src/grid.scss index aa3c25d4b7..28d5b8bdaf 100644 --- a/packages/components/grid/src/grid.scss +++ b/packages/components/grid/src/grid.scss @@ -172,6 +172,7 @@ th[part~='filter'] { td { border-block-end: var(--_cell-border); + justify-content: start; } td[part~='drag-handle']:not([part~='fixed']) { From 70718bc2351a6abc5307a95a74ddf8ae5b378077 Mon Sep 17 00:00:00 2001 From: Diana Broeders Date: Wed, 17 Jul 2024 15:53:47 +0200 Subject: [PATCH 02/29] added tests for column-group --- .../components/grid/src/column-group.spec.ts | 95 +++++++++++++++++++ packages/components/grid/src/column-group.ts | 3 +- 2 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 packages/components/grid/src/column-group.spec.ts diff --git a/packages/components/grid/src/column-group.spec.ts b/packages/components/grid/src/column-group.spec.ts new file mode 100644 index 0000000000..122153f640 --- /dev/null +++ b/packages/components/grid/src/column-group.spec.ts @@ -0,0 +1,95 @@ +import { setupIgnoreWindowResizeObserverLoopErrors } from '@lit-labs/virtualizer/support/resize-observer-errors.js'; +import { expect, fixture } from '@open-wc/testing'; +import { html } from 'lit'; +import '../register.js'; +import { type Grid } from './grid.js'; + +setupIgnoreWindowResizeObserverLoopErrors(beforeEach, afterEach); + +describe('sl-grid', () => { + let el: Grid; + + describe('defaults', () => { + beforeEach(async () => { + el = await fixture(html` + + + + + + + + + + + + + `); + el.items = [{ firstName: 'John', lastName: 'Doe', grades: { biology: 'A', maths: 'B', english: 'B+' } }]; + await el.updateComplete; + + // Give grid time to render the table structure + await new Promise(resolve => setTimeout(resolve, 100)); + await el.updateComplete; + }); + + it('should render column headers', () => { + const columns = Array.from(el.renderRoot.querySelectorAll('th')).map(col => col.textContent); + + expect(columns).to.deep.equal(['Name', 'Grades', 'First name', 'Last name', 'Biology', 'Maths', 'English']); + }); + + it('should have the correct width', () => { + const cells = Array.from(el.renderRoot.querySelectorAll('th')); + expect(cells.map(cell => Math.floor(parseFloat(getComputedStyle(cell).width)))).to.deep.equal([ + 312, 469, 156, 156, 156, 156, 156 + ]); + }); + + // it('should emit an sl-column-update event after clicking the checkbox', async () => { + // const columnUpdateEvent = spy(); + // const columnGoup = el.querySelector('sl-grid-column-group:first-of-type') as GridColumnGroup; + // columnGoup?.addEventListener('sl-column-update', columnUpdateEvent); + + // const newColumn = document.createElement('sl-grid-column'); + // await new Promise(resolve => setTimeout(resolve, 100)); + + // columnGoup?.appendChild(newColumn); + + // // expect(columnUpdateEvent).to.have.been.called; + // expect(columnGoup?.columns).to.equal(3); + // }); + }); + + describe('explicit width', () => { + beforeEach(async () => { + el = await fixture(html` + + + + + + + + + + + + `); + + el.items = [{ firstName: 'John', lastName: 'Doe', grades: { biology: 'A', maths: 'B', english: 'B+' } }]; + await el.updateComplete; + + // Give grid time to render the table structure + await new Promise(resolve => setTimeout(resolve, 100)); + await el.updateComplete; + }); + + it('should have the correct width when one is set explicitly', () => { + const cells = Array.from(el.renderRoot.querySelectorAll('th')); + expect(cells.map(cell => Math.floor(parseFloat(getComputedStyle(cell).width)))).to.deep.equal([ + 200, 600, 160, 160, 160, 160, 160 + ]); + }); + }); +}); diff --git a/packages/components/grid/src/column-group.ts b/packages/components/grid/src/column-group.ts index acc6170997..587b892168 100644 --- a/packages/components/grid/src/column-group.ts +++ b/packages/components/grid/src/column-group.ts @@ -1,4 +1,3 @@ -import { getNameByPath } from '@sl-design-system/shared'; import { type PropertyValues, type TemplateResult, html } from 'lit'; import { state } from 'lit/decorators.js'; import { GridColumn } from './column.js'; @@ -35,7 +34,7 @@ export class GridColumnGroup extends GridColumn { } override renderHeader(): TemplateResult { - return html`${this.header ?? getNameByPath(this.path)}`; + return html`${this.header}`; } #onSlotchange(event: Event & { target: HTMLSlotElement }): void { From 8f2ec04af468acaf22cfef66af3d7c290b7d81a8 Mon Sep 17 00:00:00 2001 From: Diana Broeders Date: Fri, 19 Jul 2024 10:24:37 +0200 Subject: [PATCH 03/29] fixed column width and made sl-column next to sl-column-group possible --- .../components/grid/src/column-group.spec.ts | 17 +++++++++++++---- packages/components/grid/src/column-group.ts | 2 +- packages/components/grid/src/column.spec.ts | 2 +- packages/components/grid/src/grid.ts | 14 +++++++------- .../grid/src/stories/basics.stories.ts | 1 + packages/components/grid/src/view-model.ts | 16 ++++++++-------- 6 files changed, 31 insertions(+), 21 deletions(-) diff --git a/packages/components/grid/src/column-group.spec.ts b/packages/components/grid/src/column-group.spec.ts index 122153f640..5859ae03ce 100644 --- a/packages/components/grid/src/column-group.spec.ts +++ b/packages/components/grid/src/column-group.spec.ts @@ -6,7 +6,7 @@ import { type Grid } from './grid.js'; setupIgnoreWindowResizeObserverLoopErrors(beforeEach, afterEach); -describe('sl-grid', () => { +describe('sl-column-group', () => { let el: Grid; describe('defaults', () => { @@ -36,13 +36,22 @@ describe('sl-grid', () => { it('should render column headers', () => { const columns = Array.from(el.renderRoot.querySelectorAll('th')).map(col => col.textContent); - expect(columns).to.deep.equal(['Name', 'Grades', 'First name', 'Last name', 'Biology', 'Maths', 'English']); + expect(columns).to.deep.equal([ + 'Name', + 'Grades', + 'First name', + 'Last name', + 'Biology', + 'Maths', + 'English', + 'Age' + ]); }); it('should have the correct width', () => { const cells = Array.from(el.renderRoot.querySelectorAll('th')); expect(cells.map(cell => Math.floor(parseFloat(getComputedStyle(cell).width)))).to.deep.equal([ - 312, 469, 156, 156, 156, 156, 156 + 300, 481, 151, 148, 128, 120, 128, 103 ]); }); @@ -88,7 +97,7 @@ describe('sl-grid', () => { it('should have the correct width when one is set explicitly', () => { const cells = Array.from(el.renderRoot.querySelectorAll('th')); expect(cells.map(cell => Math.floor(parseFloat(getComputedStyle(cell).width)))).to.deep.equal([ - 200, 600, 160, 160, 160, 160, 160 + 209, 600, 177, 175, 155, 147, 155 ]); }); }); diff --git a/packages/components/grid/src/column-group.ts b/packages/components/grid/src/column-group.ts index 587b892168..15a3aefbc2 100644 --- a/packages/components/grid/src/column-group.ts +++ b/packages/components/grid/src/column-group.ts @@ -34,7 +34,7 @@ export class GridColumnGroup extends GridColumn { } override renderHeader(): TemplateResult { - return html`${this.header}`; + return html`${this.header}`; } #onSlotchange(event: Event & { target: HTMLSlotElement }): void { diff --git a/packages/components/grid/src/column.spec.ts b/packages/components/grid/src/column.spec.ts index e67bed7cdf..7c13d41c67 100644 --- a/packages/components/grid/src/column.spec.ts +++ b/packages/components/grid/src/column.spec.ts @@ -9,7 +9,7 @@ import { type Grid } from './grid.js'; setupIgnoreWindowResizeObserverLoopErrors(beforeEach, afterEach); -describe('sl-grid', () => { +describe('sl-column', () => { let el: Grid; let cells: HTMLElement[]; diff --git a/packages/components/grid/src/grid.ts b/packages/components/grid/src/grid.ts index 17cd6a4ea0..db0f03d868 100644 --- a/packages/components/grid/src/grid.ts +++ b/packages/components/grid/src/grid.ts @@ -17,7 +17,7 @@ import { property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { styleMap } from 'lit/directives/style-map.js'; import { type Virtualizer } from 'node_modules/@lit-labs/virtualizer/Virtualizer.js'; -import { type GridColumnGroup } from './column-group.js'; +import { GridColumnGroup } from './column-group.js'; import { GridColumn } from './column.js'; import { GridFilterColumn } from './filter-column.js'; import { type GridFilter, type SlFilterChangeEvent } from './filter.js'; @@ -312,14 +312,16 @@ export class Grid extends ScopedElementsMixin(LitElement) { return html` ${rows.slice(0, -1).map((row, rowIndex) => { return row.map((col, colIndex) => { - return ` + return col instanceof GridColumnGroup + ? ` thead tr:nth-child(${rowIndex + 1}) th:nth-child(${colIndex + 1}) { - flex-grow: ${(col as GridColumnGroup).columns.length}; + flex-grow: ${Math.max((col as GridColumnGroup).columns.length, 1)}; inline-size: ${col.width || '100'}px; justify-content: ${col.align}; ${col.renderStyles()?.toString() ?? ''} } - `; + ` + : nothing; }); })} ${rows[rows.length - 1].map((col, index) => { @@ -350,7 +352,6 @@ export class Grid extends ScopedElementsMixin(LitElement) { selectionColumn && this.selection.size > 0 && (this.selection.areSomeSelected() || this.selection.areAllSelected()); - return html` ${rows.slice(0, -1).map( row => html` @@ -437,9 +438,8 @@ export class Grid extends ScopedElementsMixin(LitElement) { rows[rows.length - 1] .filter(col => !col.hidden && col.autoWidth) .forEach(col => { - const index = this.view.columns.indexOf(col), + const index = this.view.headerRows[this.view.headerRows.length - 1].indexOf(col), cells = this.renderRoot.querySelectorAll(`:where(td, th):nth-child(${index + 1})`); - col.width = Array.from(cells).reduce((acc, cur) => { cur.style.flexGrow = '0'; cur.style.width = 'auto'; diff --git a/packages/components/grid/src/stories/basics.stories.ts b/packages/components/grid/src/stories/basics.stories.ts index 4670102867..0d7b8cf3ad 100644 --- a/packages/components/grid/src/stories/basics.stories.ts +++ b/packages/components/grid/src/stories/basics.stories.ts @@ -68,6 +68,7 @@ export const ColumnGroups: Story = { + ` }; diff --git a/packages/components/grid/src/view-model.ts b/packages/components/grid/src/view-model.ts index 8c62a9d081..c96a5d491a 100644 --- a/packages/components/grid/src/view-model.ts +++ b/packages/components/grid/src/view-model.ts @@ -1,6 +1,6 @@ import { type DataSource, getStringByPath, getValueByPath } from '@sl-design-system/shared'; import { GridColumnGroup } from './column-group.js'; -import { type GridColumn } from './column.js'; +import { GridColumn } from './column.js'; import { GridDragHandleColumn } from './drag-handle-column.js'; import { type Grid } from './grid.js'; @@ -193,12 +193,12 @@ export class GridViewModel { } #getHeaderRows(columns: Array>): Array>> { - const children = columns - .filter((col): col is GridColumnGroup => col instanceof GridColumnGroup) - .reduce((acc: Array>>, cur) => { - return [...acc, ...this.#getHeaderRows(cur.columns)]; - }, []); - - return children.length ? [[...columns], children.flat(2)] : [[...columns]]; + const groups = columns.filter((col): col is GridColumnGroup => col instanceof GridColumnGroup); + const groupsNew = columns.map(col => (col instanceof GridColumnGroup ? col : new GridColumnGroup())); + const columnsOutsideGroups = columns.filter((col): col is GridColumn => !(col instanceof GridColumnGroup)); + const children = groups.reduce((acc: Array>>, cur) => { + return [...acc, ...this.#getHeaderRows(cur.columns)]; + }, []); + return children.length ? [[...groupsNew], [...children.flat(2), ...columnsOutsideGroups]] : [[...columns]]; } } From 4513aed02ea6b40c34986fafe4a047241b737d42 Mon Sep 17 00:00:00 2001 From: Diana Broeders Date: Mon, 22 Jul 2024 15:28:08 +0200 Subject: [PATCH 04/29] changed around the odd and even row colours to better match header --- packages/components/grid/src/column.ts | 1 + packages/components/grid/src/grid.scss | 2 +- .../components/grid/src/sort-column.spec.ts | 101 ++++++++++++++++++ 3 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 packages/components/grid/src/sort-column.spec.ts diff --git a/packages/components/grid/src/column.ts b/packages/components/grid/src/column.ts index a69995bcfe..bc8604cdba 100644 --- a/packages/components/grid/src/column.ts +++ b/packages/components/grid/src/column.ts @@ -160,6 +160,7 @@ export class GridColumn extends LitElement { if (typeof this.parts === 'string') { parts = this.parts.split(' '); } else if (typeof this.parts === 'function' && item) { + // TODO: what does this do? How can parts ever be a function? According to the typing this should not be possible. parts = this.parts(item)?.split(' ') ?? []; } diff --git a/packages/components/grid/src/grid.scss b/packages/components/grid/src/grid.scss index 28d5b8bdaf..c0a6c9ba52 100644 --- a/packages/components/grid/src/grid.scss +++ b/packages/components/grid/src/grid.scss @@ -38,7 +38,7 @@ --_cell-border: none; } -:host([striped]) tr[part~='odd'] { +:host([striped]) tr[part~='even'] { --_cell-background: var(--_striped-background); } diff --git a/packages/components/grid/src/sort-column.spec.ts b/packages/components/grid/src/sort-column.spec.ts new file mode 100644 index 0000000000..e82e27e120 --- /dev/null +++ b/packages/components/grid/src/sort-column.spec.ts @@ -0,0 +1,101 @@ +import { setupIgnoreWindowResizeObserverLoopErrors } from '@lit-labs/virtualizer/support/resize-observer-errors.js'; +import { expect, fixture } from '@open-wc/testing'; +import { html } from 'lit'; +import '../register.js'; +import { Grid } from './grid.js'; +import { GridSortColumn } from './sort-column.js'; +import { GridSorter } from './sorter.js'; + +setupIgnoreWindowResizeObserverLoopErrors(beforeEach, afterEach); + +describe('sl-sort-column', () => { + let el: Grid; + + describe('defaults', () => { + beforeEach(async () => { + el = await fixture(html` + + + + + + `); + el.items = [ + { firstName: 'John', lastName: 'Doe', age: 20 }, + { firstName: 'Jane', lastName: 'Smith', age: 40 }, + { firstName: 'Jimmy', lastName: 'Adams', age: 30 }, + { firstName: 'Jane', lastName: 'Brown', age: 15 } + ]; + await el.updateComplete; + + // Give grid time to render the table structure + await new Promise(resolve => setTimeout(resolve, 100)); + await el.updateComplete; + }); + + it('should render column headers', () => { + const columns = Array.from(el.renderRoot.querySelectorAll('th')); + const sortColumns = Array.from(el.querySelectorAll('sl-grid-sort-column')); + + expect(columns.map(col => col.textContent?.trim())).to.deep.equal(['First name', 'Last name', 'Age']); + expect(columns.map(col => col.getAttribute('part')?.trim())).to.deep.equal([ + 'header sort first-name', + 'header sort last-name', + 'header sort age' + ]); + expect(sortColumns.map(col => col.direction)).to.deep.equal([undefined, undefined, undefined]); + }); + + it('should pass the right information to the sorter element', async () => { + const sortColumns = Array.from(el.querySelectorAll('sl-grid-sort-column')); + await el.updateComplete; + await new Promise(resolve => setTimeout(resolve, 100)); + sortColumns.forEach(col => { + const sorter = el.querySelector(`#${col.id} sl-grid-sorter`); + expect(col.direction).to.equal(sorter?.direction); + expect(col.sorter).to.equal(sorter?.sorter); + + // TODO: checking for these doesn't work? + // expect(col).to.equal(sorter?.column); + // expect(col.path).to.equal(sorter?.path); + }); + }); + + it('should set the directions correctly when the sorting is set for the first time ', async () => { + const gridCols = Array.from(el.querySelectorAll('sl-grid-sort-column')); + el.dataSource?.setSort(gridCols[0].id, 'string', 'asc'); + const allUpdated = gridCols.map(el => { + el.stateChanged(); + return el.updateComplete; + }); + + await el.updateComplete; + await Promise.all(allUpdated); + + expect(gridCols.map(col => col.direction)).to.deep.equal(['asc', undefined, undefined]); + }); + + it('should set the directions correctly when the sorting is set switched from another column ', async () => { + const gridCols = Array.from(el.querySelectorAll('sl-grid-sort-column')); + + el.dataSource?.setSort(gridCols[0].id, 'string', 'asc'); + let allUpdated = gridCols.map(el => { + el.stateChanged(); + return el.updateComplete; + }); + + await Promise.all(allUpdated); + + expect(gridCols.map(col => col.direction)).to.deep.equal(['asc', undefined, undefined]); + + el.dataSource?.setSort(gridCols[1].id, 'string', 'asc'); + allUpdated = gridCols.map(el => { + el.stateChanged(); + return el.updateComplete; + }); + + await Promise.all(allUpdated); + expect(gridCols.map(col => col.direction)).to.deep.equal([undefined, 'asc', undefined]); + }); + }); +}); From 54d2994a25c4a76b29f6f9f576cf850928997213 Mon Sep 17 00:00:00 2001 From: Diana Broeders Date: Tue, 23 Jul 2024 14:13:27 +0200 Subject: [PATCH 05/29] added comments, attempt to improve sorter --- packages/components/grid/register.ts | 2 ++ packages/components/grid/src/sorter.ts | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/components/grid/register.ts b/packages/components/grid/register.ts index d76e4d251d..9f7a66b0bd 100644 --- a/packages/components/grid/register.ts +++ b/packages/components/grid/register.ts @@ -6,6 +6,7 @@ import { Grid } from './src/grid.js'; import { GridSelectColumn } from './src/select-column.js'; import { GridSelectionColumn } from './src/selection-column.js'; import { GridSortColumn } from './src/sort-column.js'; +import { GridSorter } from './src/sorter.js'; import { GridTextFieldColumn } from './src/text-field-column.js'; customElements.define('sl-grid', Grid); @@ -16,4 +17,5 @@ customElements.define('sl-grid-filter-column', GridFilterColumn); customElements.define('sl-grid-select-column', GridSelectColumn); customElements.define('sl-grid-selection-column', GridSelectionColumn); customElements.define('sl-grid-sort-column', GridSortColumn); +customElements.define('sl-grid-sorter', GridSorter); customElements.define('sl-grid-text-field-column', GridTextFieldColumn); diff --git a/packages/components/grid/src/sorter.ts b/packages/components/grid/src/sorter.ts index 725eef2d29..55a289c734 100644 --- a/packages/components/grid/src/sorter.ts +++ b/packages/components/grid/src/sorter.ts @@ -21,7 +21,7 @@ declare global { } interface HTMLElementTagNameMap { - 'sl-sorter': GridSorter; + 'sl-grid-sorter': GridSorter; } } @@ -81,6 +81,7 @@ export class GridSorter extends ScopedElementsMixin(LitElement) { super.updated(changes); if (changes.has('direction')) { + //TODO isn't this a bit dangerous? const header = this.closest('th'); if (!this.direction) { From bbe1c3aa04f8e741693f1f1f701eaa2f0d462a4b Mon Sep 17 00:00:00 2001 From: Diana Broeders Date: Wed, 24 Jul 2024 09:08:36 +0200 Subject: [PATCH 06/29] attempt to write tests for sorter + clean up code --- packages/components/grid/src/grid.spec.ts | 2 +- .../components/grid/src/sort-column.spec.ts | 28 ++++++---- packages/components/grid/src/sort-column.ts | 10 +++- packages/components/grid/src/sorter.spec.ts | 52 +++++++++++++++++++ packages/components/grid/src/sorter.ts | 20 +++---- 5 files changed, 89 insertions(+), 23 deletions(-) create mode 100644 packages/components/grid/src/sorter.spec.ts diff --git a/packages/components/grid/src/grid.spec.ts b/packages/components/grid/src/grid.spec.ts index bf7a5ac384..be022827e2 100644 --- a/packages/components/grid/src/grid.spec.ts +++ b/packages/components/grid/src/grid.spec.ts @@ -43,7 +43,7 @@ describe('sl-grid', () => { ]; // Give grid time to render the rows - await new Promise(resolve => setTimeout(resolve, 50)); + await new Promise(resolve => setTimeout(resolve, 100)); const rows = Array.from(el.renderRoot.querySelectorAll('tbody tr')).map(row => Array.from(row.querySelectorAll('td')).map(cell => cell.textContent?.trim()) diff --git a/packages/components/grid/src/sort-column.spec.ts b/packages/components/grid/src/sort-column.spec.ts index e82e27e120..710b5f8773 100644 --- a/packages/components/grid/src/sort-column.spec.ts +++ b/packages/components/grid/src/sort-column.spec.ts @@ -61,19 +61,25 @@ describe('sl-sort-column', () => { }); }); - it('should set the directions correctly when the sorting is set for the first time ', async () => { - const gridCols = Array.from(el.querySelectorAll('sl-grid-sort-column')); - el.dataSource?.setSort(gridCols[0].id, 'string', 'asc'); - const allUpdated = gridCols.map(el => { - el.stateChanged(); - return el.updateComplete; - }); + // it('should set the directions correctly when the sorting is set for the first time ', async () => { + // const gridCols = Array.from(el.querySelectorAll('sl-grid-sort-column')); + // el.dataSource?.setSort(gridCols[0].id, 'string', 'asc'); + // const allUpdated = gridCols.map(el => { + // el.stateChanged(); + // return el.updateComplete; + // }); - await el.updateComplete; - await Promise.all(allUpdated); + // await el.updateComplete; + // await Promise.all(allUpdated); + // await new Promise(resolve => setTimeout(resolve, 1000)); + // await el.updateComplete; - expect(gridCols.map(col => col.direction)).to.deep.equal(['asc', undefined, undefined]); - }); + // expect(gridCols.map(col => col.direction)).to.deep.equal(['asc', undefined, undefined]); + + // const ths = gridCols.map(col => col.shadowRoot?.querySelector('th')); + + // // expect(ths.map(th => th.getAttribute('aria-sort'))).to.deep.equal(['ascending', undefined, undefined]); + // }); it('should set the directions correctly when the sorting is set switched from another column ', async () => { const gridCols = Array.from(el.querySelectorAll('sl-grid-sort-column')); diff --git a/packages/components/grid/src/sort-column.ts b/packages/components/grid/src/sort-column.ts index eaaa8fde25..4a7c7e3c7b 100644 --- a/packages/components/grid/src/sort-column.ts +++ b/packages/components/grid/src/sort-column.ts @@ -20,6 +20,8 @@ export class GridSortColumn extends GridColumn { /** If you want to provide a custom sort function, you can via this property. */ @property({ attribute: false }) sorter?: DataSourceSortFunction; + @property({ attribute: false }) ariaSorting?: 'ascending' | 'descending'; + override connectedCallback(): void { super.connectedCallback(); @@ -36,13 +38,19 @@ export class GridSortColumn extends GridColumn { } else { this.direction = undefined; } + + if (!this.direction) { + this.ariaSorting = undefined; + } else { + this.ariaSorting = this.direction === 'asc' ? 'ascending' : 'descending'; + } } override renderHeader(): TemplateResult { const parts = ['header', 'sort', ...this.getParts()]; return html` - + ${this.header ?? getNameByPath(this.path)} diff --git a/packages/components/grid/src/sorter.spec.ts b/packages/components/grid/src/sorter.spec.ts new file mode 100644 index 0000000000..b7af68c400 --- /dev/null +++ b/packages/components/grid/src/sorter.spec.ts @@ -0,0 +1,52 @@ +import { setupIgnoreWindowResizeObserverLoopErrors } from '@lit-labs/virtualizer/support/resize-observer-errors.js'; +import { expect, fixture } from '@open-wc/testing'; +import { Icon } from '@sl-design-system/icon'; +import { ArrayDataSource, DataSource } from '@sl-design-system/shared'; +import { html } from 'lit'; +import '../register.js'; +import { GridSortColumn } from './sort-column.js'; +import { GridSorter } from './sorter.js'; + +setupIgnoreWindowResizeObserverLoopErrors(beforeEach, afterEach); + +describe('sl-sort-column', () => { + let wrapper: HTMLElement; + let el: GridSorter; + const items = [{ name: 'John' }, { name: 'Jane' }, { name: 'Jimmy' }, { name: 'Jane' }]; + + const column = new GridSortColumn(); + const dataSource = new ArrayDataSource(items) as DataSource; + dataSource.setSort('', 'name', 'asc'); + + describe('defaults', () => { + beforeEach(async () => { + wrapper = await fixture(html` + + + Name + + + `); + el = wrapper.querySelector('sl-grid-sorter')!; + await el.updateComplete; + + // Give grid time to render the table structure + await new Promise(resolve => setTimeout(resolve, 100)); + await el.updateComplete; + }); + + it('should render the correct icon', async () => { + el.direction = 'asc'; + await el.updateComplete; + expect(el.renderRoot.querySelector('sl-icon')?.getAttribute('name')).to.equal('sort-up'); + + el.direction = 'desc'; + await el.updateComplete; + expect(el.renderRoot.querySelector('sl-icon')?.getAttribute('name')).to.equal('sort-down'); + + el.reset(); + await el.updateComplete; + expect(el.renderRoot.querySelector('sl-icon')?.getAttribute('name')).to.equal('sort'); + }); + }); +}); diff --git a/packages/components/grid/src/sorter.ts b/packages/components/grid/src/sorter.ts index 55a289c734..5d108cd5fd 100644 --- a/packages/components/grid/src/sorter.ts +++ b/packages/components/grid/src/sorter.ts @@ -80,16 +80,16 @@ export class GridSorter extends ScopedElementsMixin(LitElement) { override updated(changes: PropertyValues): void { super.updated(changes); - if (changes.has('direction')) { - //TODO isn't this a bit dangerous? - const header = this.closest('th'); - - if (!this.direction) { - header?.removeAttribute('aria-sort'); - } else { - header?.setAttribute('aria-sort', this.direction === 'asc' ? 'ascending' : 'descending'); - } - } + // if (changes.has('direction')) { + // //TODO isn't this a bit dangerous? setting attributes of elements OUTSIDE of this component. + // const header = this.closest('th'); + + // if (!this.direction) { + // header?.removeAttribute('aria-sort'); + // } else { + // header?.setAttribute('aria-sort', this.direction === 'asc' ? 'ascending' : 'descending'); + // } + // } } override disconnectedCallback(): void { From 63620281eaaf8afda4fc132167eb7580402009ae Mon Sep 17 00:00:00 2001 From: anna-lach Date: Thu, 8 Aug 2024 14:39:10 +0200 Subject: [PATCH 07/29] changeset added --- .../components/grid/src/filter-column.spec.ts | 158 ++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 packages/components/grid/src/filter-column.spec.ts diff --git a/packages/components/grid/src/filter-column.spec.ts b/packages/components/grid/src/filter-column.spec.ts new file mode 100644 index 0000000000..087d755dbc --- /dev/null +++ b/packages/components/grid/src/filter-column.spec.ts @@ -0,0 +1,158 @@ +import { setupIgnoreWindowResizeObserverLoopErrors } from '@lit-labs/virtualizer/support/resize-observer-errors.js'; +import { expect, fixture } from '@open-wc/testing'; +import { html } from 'lit'; +import '../register.js'; +import { type Grid } from './grid.js'; + +setupIgnoreWindowResizeObserverLoopErrors(beforeEach, afterEach); + +describe('sl-column', () => { + let el: Grid; + // let cells: HTMLElement[]; + + describe('defaults', () => { + beforeEach(async () => { + el = await fixture(html` + + + + + + + + `); + el.items = [ + { + firstName: 'John', + lastName: 'Doe', + age: 20, + profession: 'Endocrinologist', + status: 'Available', + membership: 'Regular' + }, + { + firstName: 'Jane', + lastName: 'Smith', + age: 40, + profession: 'Anesthesiologist', + status: 'Busy', + membership: 'Premium' + } + ]; + await el.updateComplete; + + // Give grid time to render the table structure + await new Promise(resolve => setTimeout(resolve, 100)); + await el.updateComplete; + + cells = Array.from(el.renderRoot.querySelectorAll('tbody tr:first-of-type td')); + }); + + it('should render column and filter column headers', () => { + const columns = Array.from(el.renderRoot.querySelectorAll('th')) + .map(col => col.textContent) + .slice(0, 2); + // const filterColumns = el.renderRoot?.querySelectorAll('sl-grid-filter'); + const filterColumns = Array.from(el.renderRoot?.querySelectorAll('sl-grid-filter')).map(col => + col.textContent.trim() + ); + + // console.log('coolumns', columns, el.renderRoot.querySelectorAll('th')); + + // console.log('coolumns--2', columns); + // console.log('filterColumns', filterColumns, Array.from(filterColumns).map(col => col.textContent.trim())); + // console.log('filterColumns trimmed', Array.from(filterColumns).map(col => col.textContent.trim())); + // console.log('filterColumnsTrimmedfilterColumnsTrimmedfilterColumnsTrimmed', filterColumnsTrimmed); + + expect(columns).to.exist; + expect(filterColumns).to.exist; + + expect(columns).to.deep.equal(['First name', 'Last name']); + expect(filterColumns).to.deep.equal(['Profession', 'Status', 'Membership']); + }); + + // TODO: with no filter mode by default + + it('should have no filter mode by default', () => { + const filterColumn = Array.from(el.querySelectorAll('sl-grid-filter-column'))[0]; //[0]; + const filterMode = filterColumn.getAttribute('mode'); + + // console.log('filterColumns for mode', filterColumns, filterColumnsNew, filterMode); + expect(filterMode).not.to.exist; + // expect(columns).to.deep.equal(['First name', 'Last name', 'Age']); + }); + + // TODO: check whether there are right parts added when it's a filter column - also by default and when there is exact mode used + + it('should have a filter column header with a proper mode when it is set', () => { + console.log('el', el); + const columns = Array.from(el.renderRoot.querySelectorAll('th')).map(col => col.textContent); + // const filterColumns = Array.from(el.renderRoot?.querySelectorAll('sl-grid-filter'))[0]; + const filterColumnsNew = Array.from(el.querySelectorAll('sl-grid-filter-column'))[1]; + + console.log('filterColumns for mode default', filterColumnsNew); + + expect(columns).to.deep.equal(['First name', 'Last name', 'Age']); + + // TODO: need to check whether there is a button and popover inside + }); + + // it('should have the right justify-content value', () => { + // expect(cells.map(cell => getComputedStyle(cell).justifyContent)).to.deep.equal(['start', 'start', 'end']); + // }); + // + // it('should have the right grow value', () => { + // expect(cells.map(cell => getComputedStyle(cell).flexGrow)).to.deep.equal(['1', '1', '3']); + // }); + // + // it('should have the right parts', () => { + // expect(cells.map(cell => cell.getAttribute('part'))).to.deep.equal([ + // 'data first-name', + // 'data last-name', + // 'data age' + // ]); + // }); + }); + + // describe('custom renderer', () => { + // beforeEach(async () => { + // const avatarRenderer: GridColumnDataRenderer = ({ firstName, lastName }) => { + // return html``; + // }; + // + // el = await fixture(html` + // + // + // + // + // `); + // el.items = [ + // { firstName: 'John', lastName: 'Doe', age: 20 }, + // { firstName: 'Jane', lastName: 'Smith', age: 40 } + // ]; + // await el.updateComplete; + // + // // Give grid time to render the table structure + // await new Promise(resolve => setTimeout(resolve, 100)); + // await el.updateComplete; + // + // cells = Array.from(el.renderRoot.querySelectorAll('tbody tr:first-of-type td')); + // }); + // + // it('should render the elements set with the custom renderer', () => { + // expect(cells[0]).to.contain('sl-avatar'); + // }); + // + // it('should have the right parts, including one set on the column', () => { + // expect(cells.map(cell => cell.getAttribute('part'))).to.deep.equal(['data', 'data number age']); + // }); + // }); +}); + +// TODO: test mode text and select From 977205423acb78bd6cf84b71b4dc56aa7fd95f15 Mon Sep 17 00:00:00 2001 From: anna-lach Date: Thu, 8 Aug 2024 14:43:59 +0200 Subject: [PATCH 08/29] filter column tests (in progress) --- packages/components/grid/src/filter-column.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/grid/src/filter-column.spec.ts b/packages/components/grid/src/filter-column.spec.ts index 087d755dbc..f7f84d3ac2 100644 --- a/packages/components/grid/src/filter-column.spec.ts +++ b/packages/components/grid/src/filter-column.spec.ts @@ -45,7 +45,7 @@ describe('sl-column', () => { await new Promise(resolve => setTimeout(resolve, 100)); await el.updateComplete; - cells = Array.from(el.renderRoot.querySelectorAll('tbody tr:first-of-type td')); + // cells = Array.from(el.renderRoot.querySelectorAll('tbody tr:first-of-type td')); }); it('should render column and filter column headers', () => { @@ -54,7 +54,7 @@ describe('sl-column', () => { .slice(0, 2); // const filterColumns = el.renderRoot?.querySelectorAll('sl-grid-filter'); const filterColumns = Array.from(el.renderRoot?.querySelectorAll('sl-grid-filter')).map(col => - col.textContent.trim() + col.textContent?.trim() ); // console.log('coolumns', columns, el.renderRoot.querySelectorAll('th')); From 1b7c0630c8dd2da91c66cca3c3310ed2c1f213dc Mon Sep 17 00:00:00 2001 From: anna-lach Date: Fri, 9 Aug 2024 15:02:05 +0200 Subject: [PATCH 09/29] filter column tests changes, initial test for filter --- .../components/grid/src/filter-column.spec.ts | 23 ++- packages/components/grid/src/filter.spec.ts | 174 ++++++++++++++++++ 2 files changed, 188 insertions(+), 9 deletions(-) create mode 100644 packages/components/grid/src/filter.spec.ts diff --git a/packages/components/grid/src/filter-column.spec.ts b/packages/components/grid/src/filter-column.spec.ts index f7f84d3ac2..1842b1246c 100644 --- a/packages/components/grid/src/filter-column.spec.ts +++ b/packages/components/grid/src/filter-column.spec.ts @@ -6,16 +6,15 @@ import { type Grid } from './grid.js'; setupIgnoreWindowResizeObserverLoopErrors(beforeEach, afterEach); -describe('sl-column', () => { +describe('sl-grid-filter-column', () => { let el: Grid; - // let cells: HTMLElement[]; describe('defaults', () => { beforeEach(async () => { el = await fixture(html` - - + @@ -49,15 +48,16 @@ describe('sl-column', () => { }); it('should render column and filter column headers', () => { - const columns = Array.from(el.renderRoot.querySelectorAll('th')) - .map(col => col.textContent) - .slice(0, 2); + const columns = Array.from(el.renderRoot.querySelectorAll('th')); + // .map(col => col.textContent); + // .slice(0, 2); // const filterColumns = el.renderRoot?.querySelectorAll('sl-grid-filter'); const filterColumns = Array.from(el.renderRoot?.querySelectorAll('sl-grid-filter')).map(col => col.textContent?.trim() ); + console.log('el ---grid', el); - // console.log('coolumns', columns, el.renderRoot.querySelectorAll('th')); + console.log('coolumns', columns, el.renderRoot.querySelectorAll('th')); // console.log('coolumns--2', columns); // console.log('filterColumns', filterColumns, Array.from(filterColumns).map(col => col.textContent.trim())); @@ -67,7 +67,12 @@ describe('sl-column', () => { expect(columns).to.exist; expect(filterColumns).to.exist; - expect(columns).to.deep.equal(['First name', 'Last name']); + // expect(columns).to.deep.equal(['First name', 'Last name']); + expect(columns.map(col => col.getAttribute('part')?.trim())).to.deep.equal([ + 'header filter profession', + 'header filter status', + 'header filter membership' + ]); expect(filterColumns).to.deep.equal(['Profession', 'Status', 'Membership']); }); diff --git a/packages/components/grid/src/filter.spec.ts b/packages/components/grid/src/filter.spec.ts new file mode 100644 index 0000000000..39ac5b84e6 --- /dev/null +++ b/packages/components/grid/src/filter.spec.ts @@ -0,0 +1,174 @@ +import { setupIgnoreWindowResizeObserverLoopErrors } from '@lit-labs/virtualizer/support/resize-observer-errors.js'; +import { expect, fixture } from '@open-wc/testing'; +import { html } from 'lit'; +import '../register.js'; +import { type Grid } from './grid.js'; +import {getNameByPath} from "@sl-design-system/shared"; + +setupIgnoreWindowResizeObserverLoopErrors(beforeEach, afterEach); + +describe('sl-grid-filter', () => { + let el: Grid; + // let cells: HTMLElement[]; + + describe('defaults', () => { + beforeEach(async () => { + el = await fixture(html` + + + + + + + `); + el.items = [ + { + firstName: 'John', + lastName: 'Doe', + age: 20, + profession: 'Endocrinologist', + status: 'Available', + membership: 'Regular' + }, + { + firstName: 'Jane', + lastName: 'Smith', + age: 40, + profession: 'Anesthesiologist', + status: 'Busy', + membership: 'Premium' + } + ]; + await el.updateComplete; + + // Give grid time to render the table structure + await new Promise(resolve => setTimeout(resolve, 100)); + await el.updateComplete; + + // cells = Array.from(el.renderRoot.querySelectorAll('tbody tr:first-of-type td')); + }); + + // it('should render column and filter column headers', () => { + // const columns = Array.from(el.renderRoot.querySelectorAll('th')); + // // .map(col => col.textContent); + // // .slice(0, 2); + // // const filterColumns = el.renderRoot?.querySelectorAll('sl-grid-filter'); + // const filterColumns = Array.from(el.renderRoot?.querySelectorAll('sl-grid-filter')).map(col => + // col.textContent?.trim() + // ); + // + // console.log('coolumns', columns, el.renderRoot.querySelectorAll('th')); + // + // // console.log('coolumns--2', columns); + // // console.log('filterColumns', filterColumns, Array.from(filterColumns).map(col => col.textContent.trim())); + // // console.log('filterColumns trimmed', Array.from(filterColumns).map(col => col.textContent.trim())); + // // console.log('filterColumnsTrimmedfilterColumnsTrimmedfilterColumnsTrimmed', filterColumnsTrimmed); + // + // expect(columns).to.exist; + // expect(filterColumns).to.exist; + // + // // expect(columns).to.deep.equal(['First name', 'Last name']); + // expect(columns.map(col => col.getAttribute('part')?.trim())).to.deep.equal([ + // 'header filter profession', + // 'header filter status', + // 'header filter membership' + // ]); + // expect(filterColumns).to.deep.equal(['Profession', 'Status', 'Membership']); + // }); + + // it('should have no filter mode by default', () => { + // const filterColumn = Array.from(el.querySelectorAll('sl-grid-filter-column'))[0]; //[0]; + // const filterMode = filterColumn.getAttribute('mode'); + // + // // console.log('filterColumns for mode', filterColumns, filterColumnsNew, filterMode); + // expect(filterMode).not.to.exist; + // // expect(columns).to.deep.equal(['First name', 'Last name', 'Age']); + // }); + + + // it('should have a filter column header with a proper mode when it is set', () => { + // console.log('el', el); + // const columns = Array.from(el.renderRoot.querySelectorAll('th')).map(col => col.textContent); + // // const filterColumns = Array.from(el.renderRoot?.querySelectorAll('sl-grid-filter'))[0]; + // const filterColumnsNew = Array.from(el.querySelectorAll('sl-grid-filter-column'))[1]; + // + // console.log('filterColumns for mode default', filterColumnsNew); + // + // expect(columns).to.deep.equal(['First name', 'Last name', 'Age']); + // + // // TODO: need to check whether there is a button and popover inside + // }); + + // it('should have the right justify-content value', () => { + // expect(cells.map(cell => getComputedStyle(cell).justifyContent)).to.deep.equal(['start', 'start', 'end']); + // }); + // + // it('should have the right grow value', () => { + // expect(cells.map(cell => getComputedStyle(cell).flexGrow)).to.deep.equal(['1', '1', '3']); + // }); + // + // it('should have the right parts', () => { + // expect(cells.map(cell => cell.getAttribute('part'))).to.deep.equal([ + // 'data first-name', + // 'data last-name', + // 'data age' + // ]); + // }); + }); + + // describe('custom renderer', () => { + // beforeEach(async () => { + // const avatarRenderer: GridColumnDataRenderer = ({ firstName, lastName }) => { + // return html``; + // }; + // + // el = await fixture(html` + // + // + // + // + // `); + // el.items = [ + // { firstName: 'John', lastName: 'Doe', age: 20 }, + // { firstName: 'Jane', lastName: 'Smith', age: 40 } + // ]; + // await el.updateComplete; + // + // // Give grid time to render the table structure + // await new Promise(resolve => setTimeout(resolve, 100)); + // await el.updateComplete; + // + // cells = Array.from(el.renderRoot.querySelectorAll('tbody tr:first-of-type td')); + // }); + // + // it('should render the elements set with the custom renderer', () => { + // expect(cells[0]).to.contain('sl-avatar'); + // }); + // + // it('should have the right parts, including one set on the column', () => { + // expect(cells.map(cell => cell.getAttribute('part'))).to.deep.equal(['data', 'data number age']); + // }); + // }); +}); + +// TODO: events emitting tests + + +// TODO: test this exactly (inside th, similar to sorter.spec.ts?): +/* + +${this.header ?? getNameByPath(this.path)} +*/ From c4c954bb89ea8c6d1ca3e870836f71c340817399 Mon Sep 17 00:00:00 2001 From: anna-lach Date: Mon, 12 Aug 2024 16:08:28 +0200 Subject: [PATCH 10/29] filter and filter column unit tests changes --- .../components/grid/src/filter-column.spec.ts | 58 +++++++--- packages/components/grid/src/filter-column.ts | 2 + packages/components/grid/src/filter.spec.ts | 105 +++++++++++++----- 3 files changed, 120 insertions(+), 45 deletions(-) diff --git a/packages/components/grid/src/filter-column.spec.ts b/packages/components/grid/src/filter-column.spec.ts index 1842b1246c..c643b678d2 100644 --- a/packages/components/grid/src/filter-column.spec.ts +++ b/packages/components/grid/src/filter-column.spec.ts @@ -3,6 +3,7 @@ import { expect, fixture } from '@open-wc/testing'; import { html } from 'lit'; import '../register.js'; import { type Grid } from './grid.js'; +import {GridFilter} from "./filter"; setupIgnoreWindowResizeObserverLoopErrors(beforeEach, afterEach); @@ -13,8 +14,6 @@ describe('sl-grid-filter-column', () => { beforeEach(async () => { el = await fixture(html` - @@ -24,7 +23,6 @@ describe('sl-grid-filter-column', () => { { firstName: 'John', lastName: 'Doe', - age: 20, profession: 'Endocrinologist', status: 'Available', membership: 'Regular' @@ -32,7 +30,6 @@ describe('sl-grid-filter-column', () => { { firstName: 'Jane', lastName: 'Smith', - age: 40, profession: 'Anesthesiologist', status: 'Busy', membership: 'Premium' @@ -41,7 +38,7 @@ describe('sl-grid-filter-column', () => { await el.updateComplete; // Give grid time to render the table structure - await new Promise(resolve => setTimeout(resolve, 100)); + await new Promise(resolve => setTimeout(resolve, 500)); await el.updateComplete; // cells = Array.from(el.renderRoot.querySelectorAll('tbody tr:first-of-type td')); @@ -55,9 +52,9 @@ describe('sl-grid-filter-column', () => { const filterColumns = Array.from(el.renderRoot?.querySelectorAll('sl-grid-filter')).map(col => col.textContent?.trim() ); - console.log('el ---grid', el); + // console.log('el ---grid', el); - console.log('coolumns', columns, el.renderRoot.querySelectorAll('th')); + // console.log('coolumns', columns, el.renderRoot.querySelectorAll('th')); // console.log('coolumns--2', columns); // console.log('filterColumns', filterColumns, Array.from(filterColumns).map(col => col.textContent.trim())); @@ -79,29 +76,53 @@ describe('sl-grid-filter-column', () => { // TODO: with no filter mode by default it('should have no filter mode by default', () => { - const filterColumn = Array.from(el.querySelectorAll('sl-grid-filter-column'))[0]; //[0]; + const filterColumn = Array.from(el.querySelectorAll('sl-grid-filter-column'))[0]; const filterMode = filterColumn.getAttribute('mode'); - // console.log('filterColumns for mode', filterColumns, filterColumnsNew, filterMode); expect(filterMode).not.to.exist; - // expect(columns).to.deep.equal(['First name', 'Last name', 'Age']); }); // TODO: check whether there are right parts added when it's a filter column - also by default and when there is exact mode used - it('should have a filter column header with a proper mode when it is set', () => { - console.log('el', el); - const columns = Array.from(el.renderRoot.querySelectorAll('th')).map(col => col.textContent); + // TODO: should have a header with proper filter options when there is no mode + + it('should have a filter button and popover with filter options', async () => { + // console.log('el', el); + const columnHeaders = Array.from(el.renderRoot.querySelectorAll('th')).map(col => col.textContent); + const columns = el.renderRoot.querySelectorAll('sl-grid-filter'); //Array.from(el.renderRoot.querySelectorAll('sl-grid-filter')); + const button = columns[0]?.renderRoot.querySelector('.toggle'); + const popover = columns[0]?.renderRoot.querySelector('sl-popover'); + console.log('button and popover', button, popover); + console.log('ccccolumns', columns, columns[0]?.renderRoot, 'popoooover', columns[0]?.renderRoot.querySelector('sl-checkbox-group').renderRoot); + + // TODO: why I cannot get renderRoot from sl-grid-filter? + + // TODO check title - 'filter by profession' + + await new Promise(resolve => setTimeout(resolve, 500)); + + // const gridFilters = columns?.querySelectorAll('sl-grid-filter') as GridFilter[]; //el.renderRoor?.querySelectorAll('sl-grid-filter'); // const filterColumns = Array.from(el.renderRoot?.querySelectorAll('sl-grid-filter'))[0]; - const filterColumnsNew = Array.from(el.querySelectorAll('sl-grid-filter-column'))[1]; + //const filterColumnsNew = Array.from(el.querySelectorAll('sl-grid-filter-column'))[1]; - console.log('filterColumns for mode default', filterColumnsNew); + // console.log('gridFilters', gridFilters, 'el.renderRoor', el.renderRoor, 'eeeel', el, el.renderRoot.querySelectorAll('th')); - expect(columns).to.deep.equal(['First name', 'Last name', 'Age']); + // console.log('filterColumns for mode default', filterColumnsNew); + + // expect(columns).to.deep.equal(['First name', 'Last name', 'Age']); + + expect(button).to.exist; + expect(popover).to.exist; // TODO: need to check whether there is a button and popover inside }); + // TODO: check options + + // TODO: no value by default? + + // TODO: check filter icon when filtered and not filtered + // it('should have the right justify-content value', () => { // expect(cells.map(cell => getComputedStyle(cell).justifyContent)).to.deep.equal(['start', 'start', 'end']); // }); @@ -161,3 +182,8 @@ describe('sl-grid-filter-column', () => { }); // TODO: test mode text and select + +// TODO: a list of options based on the column's values + + +// TODO: to have popover diff --git a/packages/components/grid/src/filter-column.ts b/packages/components/grid/src/filter-column.ts index 3490930947..4506774438 100644 --- a/packages/components/grid/src/filter-column.ts +++ b/packages/components/grid/src/filter-column.ts @@ -97,6 +97,8 @@ export class GridFilterColumn extends GridColumn { override renderHeader(): TemplateResult { const parts = ['header', 'filter', ...this.getParts()]; + // console.log(' this.internalOptions', this.internalOptions, this.options, this.path, this, this.value); + return html` { - let el: Grid; + let wrapper: HTMLElement; + let el: GridFilter; + + const items = [{ membership: 'Premium' }, { membership: 'VIP' }, { membership: 'Regular' }]; + + const column = new GridFilterColumn(); + const dataSource = new ArrayDataSource(items) as DataSource; + dataSource.addFilter('', 'membership', 'Premium'); + + // let el: Grid; // let cells: HTMLElement[]; + // TODO: use addFilter?? + + // TODO: test mode -> .mode=${this.mode || 'select'} + // TODO: test options -> .options=${this.options ?? this.internalOptions} + + /* + Name + */ + + // .value=${dataSource.filters.values()} + describe('defaults', () => { beforeEach(async () => { - el = await fixture(html` - - - - - - + wrapper = await fixture(html` + + + Membership + + `); - el.items = [ - { - firstName: 'John', - lastName: 'Doe', - age: 20, - profession: 'Endocrinologist', - status: 'Available', - membership: 'Regular' - }, - { - firstName: 'Jane', - lastName: 'Smith', - age: 40, - profession: 'Anesthesiologist', - status: 'Busy', - membership: 'Premium' - } - ]; + el = wrapper.querySelector('sl-grid-filter')!; await el.updateComplete; // Give grid time to render the table structure - await new Promise(resolve => setTimeout(resolve, 100)); + await new Promise(resolve => setTimeout(resolve, 500)); await el.updateComplete; + console.log('wrapper before', wrapper, wrapper.renderRoot); + console.log('eeeeeel1 before', el, el.renderRoot); + // el = await fixture(html` + // + // + // + // + // + // `); + // el.items = [ + // { + // firstName: 'John', + // lastName: 'Doe', + // age: 20, + // profession: 'Endocrinologist', + // status: 'Available', + // membership: 'Regular' + // }, + // { + // firstName: 'Jane', + // lastName: 'Smith', + // age: 40, + // profession: 'Anesthesiologist', + // status: 'Busy', + // membership: 'Premium' + // } + // ]; + // await el.updateComplete; + // + // // Give grid time to render the table structure + // await new Promise(resolve => setTimeout(resolve, 100)); + // await el.updateComplete; + // cells = Array.from(el.renderRoot.querySelectorAll('tbody tr:first-of-type td')); }); + it('should render correct checkboxes', () => { + console.log('wrapper', wrapper, wrapper.renderRoot); + console.log('eeeeeel1', el, el.renderRoot); + expect(wrapper).to.exist; + }); + // it('should render column and filter column headers', () => { // const columns = Array.from(el.renderRoot.querySelectorAll('th')); // // .map(col => col.textContent); From fc116a1d14410f81d6e81cf30225fef72adcde6b Mon Sep 17 00:00:00 2001 From: anna-lach Date: Tue, 13 Aug 2024 15:54:00 +0200 Subject: [PATCH 11/29] filter tests changes --- .../components/grid/src/filter-column.spec.ts | 88 ++++++++----------- packages/components/grid/src/filter-column.ts | 2 +- packages/components/grid/src/filter.spec.ts | 13 +-- 3 files changed, 48 insertions(+), 55 deletions(-) diff --git a/packages/components/grid/src/filter-column.spec.ts b/packages/components/grid/src/filter-column.spec.ts index c643b678d2..413a6216cf 100644 --- a/packages/components/grid/src/filter-column.spec.ts +++ b/packages/components/grid/src/filter-column.spec.ts @@ -3,7 +3,8 @@ import { expect, fixture } from '@open-wc/testing'; import { html } from 'lit'; import '../register.js'; import { type Grid } from './grid.js'; -import {GridFilter} from "./filter"; +import {type CheckboxGroup} from "@sl-design-system/checkbox"; +import {GridFilterColumn} from "./filter-column"; setupIgnoreWindowResizeObserverLoopErrors(beforeEach, afterEach); @@ -14,7 +15,7 @@ describe('sl-grid-filter-column', () => { beforeEach(async () => { el = await fixture(html` - + @@ -82,18 +83,51 @@ describe('sl-grid-filter-column', () => { expect(filterMode).not.to.exist; }); - // TODO: check whether there are right parts added when it's a filter column - also by default and when there is exact mode used + it('should have no active filter by default', () => { + const columns = Array.from(el.renderRoot.querySelectorAll('sl-grid-filter')).map(filter => filter.hasAttribute('active')); + + expect(columns).to.eql([false, false, false]); + }); // TODO: should have a header with proper filter options when there is no mode + it('should have a header with proper filter options when there is no mode', async () => { + const columns = el.renderRoot.querySelectorAll('sl-grid-filter'); //Array.from(el.renderRoot.querySelectorAll('sl-grid-filter')); + const popover = columns[0]?.renderRoot.querySelector('sl-popover'); + const checkboxGroup = popover.querySelector('sl-checkbox-group') as CheckboxGroup; + const filterColumns = Array.from(popover?.querySelectorAll('sl-checkbox')).map(col => + col.textContent?.trim() + ); + + await el.updateComplete; + await new Promise(resolve => setTimeout(resolve, 500)); + + console.log('checkboxgroup no mode---', checkboxGroup, filterColumns, Array.from(checkboxGroup?.querySelectorAll('sl-checkbox'))); + + expect(checkboxGroup).to.have.trimmed.text('Endocrinologist'); + }); + it('should have a filter button and popover with filter options', async () => { // console.log('el', el); const columnHeaders = Array.from(el.renderRoot.querySelectorAll('th')).map(col => col.textContent); const columns = el.renderRoot.querySelectorAll('sl-grid-filter'); //Array.from(el.renderRoot.querySelectorAll('sl-grid-filter')); const button = columns[0]?.renderRoot.querySelector('.toggle'); const popover = columns[0]?.renderRoot.querySelector('sl-popover'); + const checkbox = columns[0]?.renderRoot.querySelectorAll('sl-checkbox'); + const checkboxGroup = popover.querySelector('sl-checkbox-group') as CheckboxGroup; + const title = popover?.querySelector('#title'); + const dataSource = el?.dataSource as DataSource | undefined; + await new Promise(resolve => setTimeout(resolve, 500)); + console.log('dataSource1', dataSource, dataSource.items, 'eeeeeeel options', el.dataSource?.filters); + console.log('columns1', columns, 'has attribute??', (columns[0] as GridFilterColumn).hasAttribute('active'), (columns[0] as GridFilterColumn).options, (columns[0] as GridFilterColumn).internalOptions, popover?.querySelector('#title')); console.log('button and popover', button, popover); - console.log('ccccolumns', columns, columns[0]?.renderRoot, 'popoooover', columns[0]?.renderRoot.querySelector('sl-checkbox-group').renderRoot); + console.log('cheeeckbox', checkbox, 'pooopover checkbox', popover.querySelectorAll('sl-checkbox'), Array.from(checkboxGroup.querySelectorAll('sl-checkbox')), + 'checkboxGroupcheckboxGroupcheckboxGroupcheckboxGroup', checkboxGroup, checkboxGroup.renderRoot); + // console.log('ccccolumns', columns, columns[0]?.renderRoot, 'popoooover', columns[0]?.renderRoot.querySelector('sl-checkbox-group').renderRoot); + + expect(title).to.have.trimmed.text('Filter by Profession'); + + // expect(checkbox).to.exist; // TODO: why I cannot get renderRoot from sl-grid-filter? @@ -139,51 +173,7 @@ describe('sl-grid-filter-column', () => { // ]); // }); }); - - // describe('custom renderer', () => { - // beforeEach(async () => { - // const avatarRenderer: GridColumnDataRenderer = ({ firstName, lastName }) => { - // return html``; - // }; - // - // el = await fixture(html` - // - // - // - // - // `); - // el.items = [ - // { firstName: 'John', lastName: 'Doe', age: 20 }, - // { firstName: 'Jane', lastName: 'Smith', age: 40 } - // ]; - // await el.updateComplete; - // - // // Give grid time to render the table structure - // await new Promise(resolve => setTimeout(resolve, 100)); - // await el.updateComplete; - // - // cells = Array.from(el.renderRoot.querySelectorAll('tbody tr:first-of-type td')); - // }); - // - // it('should render the elements set with the custom renderer', () => { - // expect(cells[0]).to.contain('sl-avatar'); - // }); - // - // it('should have the right parts, including one set on the column', () => { - // expect(cells.map(cell => cell.getAttribute('part'))).to.deep.equal(['data', 'data number age']); - // }); - // }); }); -// TODO: test mode text and select - -// TODO: a list of options based on the column's values - +// TODO: a list of options based on the column's values - I cannot get checkboxes from checkbox group -// TODO: to have popover diff --git a/packages/components/grid/src/filter-column.ts b/packages/components/grid/src/filter-column.ts index 4506774438..d69b323474 100644 --- a/packages/components/grid/src/filter-column.ts +++ b/packages/components/grid/src/filter-column.ts @@ -97,7 +97,7 @@ export class GridFilterColumn extends GridColumn { override renderHeader(): TemplateResult { const parts = ['header', 'filter', ...this.getParts()]; - // console.log(' this.internalOptions', this.internalOptions, this.options, this.path, this, this.value); + console.log(' this.internalOptions', this.internalOptions, this.options, this.path, this, this.value); return html` diff --git a/packages/components/grid/src/filter.spec.ts b/packages/components/grid/src/filter.spec.ts index b6979495c6..20877f4630 100644 --- a/packages/components/grid/src/filter.spec.ts +++ b/packages/components/grid/src/filter.spec.ts @@ -54,8 +54,8 @@ describe('sl-grid-filter', () => { await new Promise(resolve => setTimeout(resolve, 500)); await el.updateComplete; - console.log('wrapper before', wrapper, wrapper.renderRoot); - console.log('eeeeeel1 before', el, el.renderRoot); + // console.log('wrapper before', wrapper, wrapper.renderRoot); + // console.log('eeeeeel1 before', el, el.renderRoot); // el = await fixture(html` // // @@ -91,9 +91,9 @@ describe('sl-grid-filter', () => { }); it('should render correct checkboxes', () => { - console.log('wrapper', wrapper, wrapper.renderRoot); - console.log('eeeeeel1', el, el.renderRoot); - expect(wrapper).to.exist; + // console.log('wrapper', wrapper, wrapper.renderRoot); + console.log('eeeeeel1', el); + expect(wrapper).not.to.exist; }); // it('should render column and filter column headers', () => { @@ -219,3 +219,6 @@ describe('sl-grid-filter', () => { > ${this.header ?? getNameByPath(this.path)} */ + + +// TODO: test mode text and select From 03e4ad5311fa49bbc64660defc022d90df156245 Mon Sep 17 00:00:00 2001 From: anna-lach Date: Wed, 14 Aug 2024 09:35:56 +0200 Subject: [PATCH 12/29] filter tests updates (not working yet) --- .../components/grid/src/filter-column.spec.ts | 18 ++++++++--------- packages/components/grid/src/filter-column.ts | 1 + packages/components/grid/src/filter.spec.ts | 20 +++++++++++++++++-- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/packages/components/grid/src/filter-column.spec.ts b/packages/components/grid/src/filter-column.spec.ts index 413a6216cf..996028e74e 100644 --- a/packages/components/grid/src/filter-column.spec.ts +++ b/packages/components/grid/src/filter-column.spec.ts @@ -94,10 +94,10 @@ describe('sl-grid-filter-column', () => { it('should have a header with proper filter options when there is no mode', async () => { const columns = el.renderRoot.querySelectorAll('sl-grid-filter'); //Array.from(el.renderRoot.querySelectorAll('sl-grid-filter')); const popover = columns[0]?.renderRoot.querySelector('sl-popover'); - const checkboxGroup = popover.querySelector('sl-checkbox-group') as CheckboxGroup; - const filterColumns = Array.from(popover?.querySelectorAll('sl-checkbox')).map(col => - col.textContent?.trim() - ); + const checkboxGroup = popover?.querySelector('sl-checkbox-group') as CheckboxGroup; + const filterColumns = popover?.querySelectorAll('sl-checkbox'); /*Array.from(popover?.querySelectorAll('sl-checkbox')).map(col => + col.innerHTML + );*/ // col.textContent?.trim() await el.updateComplete; await new Promise(resolve => setTimeout(resolve, 500)); @@ -114,14 +114,14 @@ describe('sl-grid-filter-column', () => { const button = columns[0]?.renderRoot.querySelector('.toggle'); const popover = columns[0]?.renderRoot.querySelector('sl-popover'); const checkbox = columns[0]?.renderRoot.querySelectorAll('sl-checkbox'); - const checkboxGroup = popover.querySelector('sl-checkbox-group') as CheckboxGroup; + const checkboxGroup = popover?.querySelector('sl-checkbox-group') as CheckboxGroup; const title = popover?.querySelector('#title'); - const dataSource = el?.dataSource as DataSource | undefined; + const dataSource = el?.dataSource; await new Promise(resolve => setTimeout(resolve, 500)); - console.log('dataSource1', dataSource, dataSource.items, 'eeeeeeel options', el.dataSource?.filters); - console.log('columns1', columns, 'has attribute??', (columns[0] as GridFilterColumn).hasAttribute('active'), (columns[0] as GridFilterColumn).options, (columns[0] as GridFilterColumn).internalOptions, popover?.querySelector('#title')); + console.log('dataSource1', dataSource, dataSource?.items, 'eeeeeeel options', el.dataSource?.filters); + console.log('columns1', columns, 'has attribute??', (columns[0])?.hasAttribute('active'), (columns[0])?.options, /*(columns[0])?.internalOptions,*/ popover?.querySelector('#title')); console.log('button and popover', button, popover); - console.log('cheeeckbox', checkbox, 'pooopover checkbox', popover.querySelectorAll('sl-checkbox'), Array.from(checkboxGroup.querySelectorAll('sl-checkbox')), + console.log('cheeeckbox', checkbox, 'pooopover checkbox', popover?.querySelectorAll('sl-checkbox'), Array.from(checkboxGroup.querySelectorAll('sl-checkbox')), 'checkboxGroupcheckboxGroupcheckboxGroupcheckboxGroup', checkboxGroup, checkboxGroup.renderRoot); // console.log('ccccolumns', columns, columns[0]?.renderRoot, 'popoooover', columns[0]?.renderRoot.querySelector('sl-checkbox-group').renderRoot); diff --git a/packages/components/grid/src/filter-column.ts b/packages/components/grid/src/filter-column.ts index d69b323474..12fb1cacf1 100644 --- a/packages/components/grid/src/filter-column.ts +++ b/packages/components/grid/src/filter-column.ts @@ -98,6 +98,7 @@ export class GridFilterColumn extends GridColumn { const parts = ['header', 'filter', ...this.getParts()]; console.log(' this.internalOptions', this.internalOptions, this.options, this.path, this, this.value); + console.log('dataSource', this.grid?.dataSource, this.grid); return html` diff --git a/packages/components/grid/src/filter.spec.ts b/packages/components/grid/src/filter.spec.ts index 20877f4630..50d7aa52c4 100644 --- a/packages/components/grid/src/filter.spec.ts +++ b/packages/components/grid/src/filter.spec.ts @@ -19,6 +19,21 @@ describe('sl-grid-filter', () => { const dataSource = new ArrayDataSource(items) as DataSource; dataSource.addFilter('', 'membership', 'Premium'); + const options = [ + { + "label": "Premium", + "value": "Premium" + }, + { + "label": "Regular", + "value": "Regular" + }, + { + "label": "VIP", + "value": "VIP" + } + ]; + // let el: Grid; // let cells: HTMLElement[]; @@ -39,6 +54,7 @@ describe('sl-grid-filter', () => { { await el.updateComplete; // Give grid time to render the table structure - await new Promise(resolve => setTimeout(resolve, 500)); + await new Promise(resolve => setTimeout(resolve, 1500)); await el.updateComplete; - // console.log('wrapper before', wrapper, wrapper.renderRoot); + console.log('wrapper before and el', wrapper, el); // console.log('eeeeeel1 before', el, el.renderRoot); // el = await fixture(html` // From bcf24380e1dc737d4dec050c26deee1906c7c84c Mon Sep 17 00:00:00 2001 From: anna-lach Date: Mon, 19 Aug 2024 16:09:24 +0200 Subject: [PATCH 13/29] trying to fix filter tests --- .../components/grid/src/filter-column.spec.ts | 34 ++++++++++++++----- packages/components/grid/src/filter.spec.ts | 15 ++++---- .../src/data-source/array-data-source.ts | 1 + .../shared/src/data-source/data-source.ts | 2 ++ 4 files changed, 38 insertions(+), 14 deletions(-) diff --git a/packages/components/grid/src/filter-column.spec.ts b/packages/components/grid/src/filter-column.spec.ts index 996028e74e..46441f4503 100644 --- a/packages/components/grid/src/filter-column.spec.ts +++ b/packages/components/grid/src/filter-column.spec.ts @@ -39,7 +39,7 @@ describe('sl-grid-filter-column', () => { await el.updateComplete; // Give grid time to render the table structure - await new Promise(resolve => setTimeout(resolve, 500)); + await new Promise(resolve => setTimeout(resolve, 100)); await el.updateComplete; // cells = Array.from(el.renderRoot.querySelectorAll('tbody tr:first-of-type td')); @@ -93,16 +93,34 @@ describe('sl-grid-filter-column', () => { it('should have a header with proper filter options when there is no mode', async () => { const columns = el.renderRoot.querySelectorAll('sl-grid-filter'); //Array.from(el.renderRoot.querySelectorAll('sl-grid-filter')); + await el.updateComplete; + await new Promise(resolve => setTimeout(resolve, 100)); + // await columns.updateComplete; const popover = columns[0]?.renderRoot.querySelector('sl-popover'); + await popover.updateComplete; + const filterButton = columns[0]?.renderRoot.querySelector('#anchor'); + await new Promise(resolve => setTimeout(resolve, 100)); + console.log('filterButton no mode---', filterButton); + // TODO: filterButton to exist + // filterButton?.click(); + const clickEvent = new Event('click'); + filterButton?.dispatchEvent(clickEvent); + await popover.updateComplete; + await new Promise(resolve => setTimeout(resolve, 100)); const checkboxGroup = popover?.querySelector('sl-checkbox-group') as CheckboxGroup; - const filterColumns = popover?.querySelectorAll('sl-checkbox'); /*Array.from(popover?.querySelectorAll('sl-checkbox')).map(col => - col.innerHTML - );*/ // col.textContent?.trim() + await checkboxGroup.updateComplete; + await new Promise(resolve => setTimeout(resolve, 100)); + const filterColumns = checkboxGroup?.querySelectorAll('sl-checkbox'); + // const filterColumns = popover?.querySelectorAll('sl-checkbox'); /*Array.from(popover?.querySelectorAll('sl-checkbox')).map(col => + // col.innerHTML + //);*/ // col.textContent?.trim() await el.updateComplete; - await new Promise(resolve => setTimeout(resolve, 500)); + await popover.updateComplete; + await new Promise(resolve => setTimeout(resolve, 100)); + console.log('popover in no mode---', popover, 'columns no mode---', columns[0].renderRoot, 'checkboxGroup no mode---', checkboxGroup.renderRoot, checkboxGroup.renderRoot.querySelector('slot')?.assignedNodes()); - console.log('checkboxgroup no mode---', checkboxGroup, filterColumns, Array.from(checkboxGroup?.querySelectorAll('sl-checkbox'))); + console.log('checkboxgroup no mode---', checkboxGroup, filterColumns, Array.from(checkboxGroup?.querySelectorAll('sl-checkbox')), popover?.querySelectorAll('sl-checkbox')); expect(checkboxGroup).to.have.trimmed.text('Endocrinologist'); }); @@ -117,7 +135,7 @@ describe('sl-grid-filter-column', () => { const checkboxGroup = popover?.querySelector('sl-checkbox-group') as CheckboxGroup; const title = popover?.querySelector('#title'); const dataSource = el?.dataSource; - await new Promise(resolve => setTimeout(resolve, 500)); + await new Promise(resolve => setTimeout(resolve, 100)); console.log('dataSource1', dataSource, dataSource?.items, 'eeeeeeel options', el.dataSource?.filters); console.log('columns1', columns, 'has attribute??', (columns[0])?.hasAttribute('active'), (columns[0])?.options, /*(columns[0])?.internalOptions,*/ popover?.querySelector('#title')); console.log('button and popover', button, popover); @@ -133,7 +151,7 @@ describe('sl-grid-filter-column', () => { // TODO check title - 'filter by profession' - await new Promise(resolve => setTimeout(resolve, 500)); + await new Promise(resolve => setTimeout(resolve, 100)); // const gridFilters = columns?.querySelectorAll('sl-grid-filter') as GridFilter[]; //el.renderRoor?.querySelectorAll('sl-grid-filter'); // const filterColumns = Array.from(el.renderRoot?.querySelectorAll('sl-grid-filter'))[0]; diff --git a/packages/components/grid/src/filter.spec.ts b/packages/components/grid/src/filter.spec.ts index 50d7aa52c4..6a15f216d9 100644 --- a/packages/components/grid/src/filter.spec.ts +++ b/packages/components/grid/src/filter.spec.ts @@ -17,7 +17,7 @@ describe('sl-grid-filter', () => { const column = new GridFilterColumn(); const dataSource = new ArrayDataSource(items) as DataSource; - dataSource.addFilter('', 'membership', 'Premium'); + dataSource.addFilter('', 'membership', ['Premium']); const options = [ { @@ -48,16 +48,19 @@ describe('sl-grid-filter', () => { // .value=${dataSource.filters.values()} + // .filter=... + + // path="membership" + // value="Premium" + describe('defaults', () => { beforeEach(async () => { wrapper = await fixture(html` Membership @@ -67,10 +70,10 @@ describe('sl-grid-filter', () => { await el.updateComplete; // Give grid time to render the table structure - await new Promise(resolve => setTimeout(resolve, 1500)); + await new Promise(resolve => setTimeout(resolve, 200)); await el.updateComplete; - console.log('wrapper before and el', wrapper, el); + console.log('wrapper before and el', wrapper, el, dataSource); // console.log('eeeeeel1 before', el, el.renderRoot); // el = await fixture(html` // diff --git a/packages/components/shared/src/data-source/array-data-source.ts b/packages/components/shared/src/data-source/array-data-source.ts index 3073e8c675..4e08f1cff1 100644 --- a/packages/components/shared/src/data-source/array-data-source.ts +++ b/packages/components/shared/src/data-source/array-data-source.ts @@ -25,6 +25,7 @@ export class ArrayDataSource extends DataSource { constructor(items: T[]) { super(); + console.log('items in array data source', items); this.#filteredItems = [...items]; this.#items = [...items]; } diff --git a/packages/components/shared/src/data-source/data-source.ts b/packages/components/shared/src/data-source/data-source.ts index 396e13fa88..0e623f3192 100644 --- a/packages/components/shared/src/data-source/data-source.ts +++ b/packages/components/shared/src/data-source/data-source.ts @@ -44,6 +44,7 @@ export abstract class DataSource extends EventTarget { #sort?: DataSourceSort; get filters(): Map> { + console.log('this.#filters in data source', this.#filters); return this.#filters; } @@ -72,6 +73,7 @@ export abstract class DataSource extends EventTarget { pathOrFilter: U, value?: string | string[] ): void { + console.log('in addFilter', id, pathOrFilter, value); if (typeof pathOrFilter === 'string') { this.#filters.set(id, { path: pathOrFilter, value: value ?? '' }); } else { From c62062f6a2e9ba962175c876205295a3ca432859 Mon Sep 17 00:00:00 2001 From: anna-lach Date: Tue, 20 Aug 2024 16:00:06 +0200 Subject: [PATCH 14/29] filter column tests update, still cannot check options --- .../components/grid/src/filter-column.spec.ts | 111 +++++------------- 1 file changed, 27 insertions(+), 84 deletions(-) diff --git a/packages/components/grid/src/filter-column.spec.ts b/packages/components/grid/src/filter-column.spec.ts index 46441f4503..a7ef5c20f0 100644 --- a/packages/components/grid/src/filter-column.spec.ts +++ b/packages/components/grid/src/filter-column.spec.ts @@ -2,9 +2,9 @@ import { setupIgnoreWindowResizeObserverLoopErrors } from '@lit-labs/virtualizer import { expect, fixture } from '@open-wc/testing'; import { html } from 'lit'; import '../register.js'; +import { Checkbox } from '@sl-design-system/checkbox'; import { type Grid } from './grid.js'; import {type CheckboxGroup} from "@sl-design-system/checkbox"; -import {GridFilterColumn} from "./filter-column"; setupIgnoreWindowResizeObserverLoopErrors(beforeEach, afterEach); @@ -15,7 +15,9 @@ describe('sl-grid-filter-column', () => { beforeEach(async () => { el = await fixture(html` - + @@ -41,31 +43,17 @@ describe('sl-grid-filter-column', () => { // Give grid time to render the table structure await new Promise(resolve => setTimeout(resolve, 100)); await el.updateComplete; - - // cells = Array.from(el.renderRoot.querySelectorAll('tbody tr:first-of-type td')); }); it('should render column and filter column headers', () => { const columns = Array.from(el.renderRoot.querySelectorAll('th')); - // .map(col => col.textContent); - // .slice(0, 2); - // const filterColumns = el.renderRoot?.querySelectorAll('sl-grid-filter'); const filterColumns = Array.from(el.renderRoot?.querySelectorAll('sl-grid-filter')).map(col => col.textContent?.trim() ); - // console.log('el ---grid', el); - - // console.log('coolumns', columns, el.renderRoot.querySelectorAll('th')); - - // console.log('coolumns--2', columns); - // console.log('filterColumns', filterColumns, Array.from(filterColumns).map(col => col.textContent.trim())); - // console.log('filterColumns trimmed', Array.from(filterColumns).map(col => col.textContent.trim())); - // console.log('filterColumnsTrimmedfilterColumnsTrimmedfilterColumnsTrimmed', filterColumnsTrimmed); expect(columns).to.exist; expect(filterColumns).to.exist; - // expect(columns).to.deep.equal(['First name', 'Last name']); expect(columns.map(col => col.getAttribute('part')?.trim())).to.deep.equal([ 'header filter profession', 'header filter status', @@ -74,8 +62,6 @@ describe('sl-grid-filter-column', () => { expect(filterColumns).to.deep.equal(['Profession', 'Status', 'Membership']); }); - // TODO: with no filter mode by default - it('should have no filter mode by default', () => { const filterColumn = Array.from(el.querySelectorAll('sl-grid-filter-column'))[0]; const filterMode = filterColumn.getAttribute('mode'); @@ -89,20 +75,34 @@ describe('sl-grid-filter-column', () => { expect(columns).to.eql([false, false, false]); }); - // TODO: should have a header with proper filter options when there is no mode - it('should have a header with proper filter options when there is no mode', async () => { + it('should have proper filter titles', async () => { + const titles = Array.from(el.renderRoot.querySelectorAll('sl-grid-filter')).map(filter => filter?.renderRoot.querySelector('sl-popover')?.querySelector('#title').textContent?.trim()); + + expect(titles).to.eql(['Filter by Profession', 'Filter by Status', 'Filter by Membership']); + }); + + it('should have filter buttons and popovers with filter options', async () => { + const buttons = Array.from(el.renderRoot.querySelectorAll('sl-grid-filter')).map(filter => filter?.renderRoot.querySelector('.toggle')); + const popovers = Array.from(el.renderRoot.querySelectorAll('sl-grid-filter')).map(filter => filter?.renderRoot.querySelector('sl-popover')); + + expect(buttons).to.exist; + expect(popovers).to.exist; + }); + + // TODO: this one below is not working, I cannot check sl-checkboxes which are rendered options to filter + it('should have proper filter options when there is no mode', async () => { const columns = el.renderRoot.querySelectorAll('sl-grid-filter'); //Array.from(el.renderRoot.querySelectorAll('sl-grid-filter')); - await el.updateComplete; - await new Promise(resolve => setTimeout(resolve, 100)); - // await columns.updateComplete; const popover = columns[0]?.renderRoot.querySelector('sl-popover'); - await popover.updateComplete; + // await popover.updateComplete; const filterButton = columns[0]?.renderRoot.querySelector('#anchor'); await new Promise(resolve => setTimeout(resolve, 100)); console.log('filterButton no mode---', filterButton); // TODO: filterButton to exist // filterButton?.click(); + + expect(filterButton).to.exist; + const clickEvent = new Event('click'); filterButton?.dispatchEvent(clickEvent); await popover.updateComplete; @@ -116,80 +116,23 @@ describe('sl-grid-filter-column', () => { //);*/ // col.textContent?.trim() await el.updateComplete; - await popover.updateComplete; + // await popover.updateComplete; await new Promise(resolve => setTimeout(resolve, 100)); console.log('popover in no mode---', popover, 'columns no mode---', columns[0].renderRoot, 'checkboxGroup no mode---', checkboxGroup.renderRoot, checkboxGroup.renderRoot.querySelector('slot')?.assignedNodes()); console.log('checkboxgroup no mode---', checkboxGroup, filterColumns, Array.from(checkboxGroup?.querySelectorAll('sl-checkbox')), popover?.querySelectorAll('sl-checkbox')); expect(checkboxGroup).to.have.trimmed.text('Endocrinologist'); - }); - - it('should have a filter button and popover with filter options', async () => { - // console.log('el', el); - const columnHeaders = Array.from(el.renderRoot.querySelectorAll('th')).map(col => col.textContent); - const columns = el.renderRoot.querySelectorAll('sl-grid-filter'); //Array.from(el.renderRoot.querySelectorAll('sl-grid-filter')); - const button = columns[0]?.renderRoot.querySelector('.toggle'); - const popover = columns[0]?.renderRoot.querySelector('sl-popover'); - const checkbox = columns[0]?.renderRoot.querySelectorAll('sl-checkbox'); - const checkboxGroup = popover?.querySelector('sl-checkbox-group') as CheckboxGroup; - const title = popover?.querySelector('#title'); - const dataSource = el?.dataSource; - await new Promise(resolve => setTimeout(resolve, 100)); - console.log('dataSource1', dataSource, dataSource?.items, 'eeeeeeel options', el.dataSource?.filters); - console.log('columns1', columns, 'has attribute??', (columns[0])?.hasAttribute('active'), (columns[0])?.options, /*(columns[0])?.internalOptions,*/ popover?.querySelector('#title')); - console.log('button and popover', button, popover); - console.log('cheeeckbox', checkbox, 'pooopover checkbox', popover?.querySelectorAll('sl-checkbox'), Array.from(checkboxGroup.querySelectorAll('sl-checkbox')), - 'checkboxGroupcheckboxGroupcheckboxGroupcheckboxGroup', checkboxGroup, checkboxGroup.renderRoot); - // console.log('ccccolumns', columns, columns[0]?.renderRoot, 'popoooover', columns[0]?.renderRoot.querySelector('sl-checkbox-group').renderRoot); - - expect(title).to.have.trimmed.text('Filter by Profession'); - - // expect(checkbox).to.exist; - - // TODO: why I cannot get renderRoot from sl-grid-filter? - - // TODO check title - 'filter by profession' - - await new Promise(resolve => setTimeout(resolve, 100)); - - // const gridFilters = columns?.querySelectorAll('sl-grid-filter') as GridFilter[]; //el.renderRoor?.querySelectorAll('sl-grid-filter'); - // const filterColumns = Array.from(el.renderRoot?.querySelectorAll('sl-grid-filter'))[0]; - //const filterColumnsNew = Array.from(el.querySelectorAll('sl-grid-filter-column'))[1]; - - // console.log('gridFilters', gridFilters, 'el.renderRoor', el.renderRoor, 'eeeel', el, el.renderRoot.querySelectorAll('th')); - - // console.log('filterColumns for mode default', filterColumnsNew); - - // expect(columns).to.deep.equal(['First name', 'Last name', 'Age']); - - expect(button).to.exist; - expect(popover).to.exist; - // TODO: need to check whether there is a button and popover inside + // TODO: expect options (sl-checkboxes) to exist }); - // TODO: check options + // TODO: check filter options // TODO: no value by default? // TODO: check filter icon when filtered and not filtered - // it('should have the right justify-content value', () => { - // expect(cells.map(cell => getComputedStyle(cell).justifyContent)).to.deep.equal(['start', 'start', 'end']); - // }); - // - // it('should have the right grow value', () => { - // expect(cells.map(cell => getComputedStyle(cell).flexGrow)).to.deep.equal(['1', '1', '3']); - // }); - // - // it('should have the right parts', () => { - // expect(cells.map(cell => cell.getAttribute('part'))).to.deep.equal([ - // 'data first-name', - // 'data last-name', - // 'data age' - // ]); - // }); }); }); From 45580d62eb7f9772a9088b1c8fec69059fa295d3 Mon Sep 17 00:00:00 2001 From: anna-lach Date: Wed, 21 Aug 2024 13:11:52 +0200 Subject: [PATCH 15/29] filter and filter column tests changes --- .../components/grid/src/filter-column.spec.ts | 69 ++++++++++--------- packages/components/grid/src/filter.spec.ts | 51 +++++--------- 2 files changed, 54 insertions(+), 66 deletions(-) diff --git a/packages/components/grid/src/filter-column.spec.ts b/packages/components/grid/src/filter-column.spec.ts index a7ef5c20f0..d1a89cb83d 100644 --- a/packages/components/grid/src/filter-column.spec.ts +++ b/packages/components/grid/src/filter-column.spec.ts @@ -1,10 +1,10 @@ import { setupIgnoreWindowResizeObserverLoopErrors } from '@lit-labs/virtualizer/support/resize-observer-errors.js'; import { expect, fixture } from '@open-wc/testing'; +// import { Checkbox } from '@sl-design-system/checkbox'; +import { type CheckboxGroup } from '@sl-design-system/checkbox'; import { html } from 'lit'; import '../register.js'; -import { Checkbox } from '@sl-design-system/checkbox'; import { type Grid } from './grid.js'; -import {type CheckboxGroup} from "@sl-design-system/checkbox"; setupIgnoreWindowResizeObserverLoopErrors(beforeEach, afterEach); @@ -15,9 +15,7 @@ describe('sl-grid-filter-column', () => { beforeEach(async () => { el = await fixture(html` - + @@ -41,7 +39,7 @@ describe('sl-grid-filter-column', () => { await el.updateComplete; // Give grid time to render the table structure - await new Promise(resolve => setTimeout(resolve, 100)); + await new Promise(resolve => setTimeout(resolve, 200)); await el.updateComplete; }); @@ -70,21 +68,28 @@ describe('sl-grid-filter-column', () => { }); it('should have no active filter by default', () => { - const columns = Array.from(el.renderRoot.querySelectorAll('sl-grid-filter')).map(filter => filter.hasAttribute('active')); + const columns = Array.from(el.renderRoot.querySelectorAll('sl-grid-filter')).map(filter => + filter.hasAttribute('active') + ); expect(columns).to.eql([false, false, false]); }); - - it('should have proper filter titles', async () => { - const titles = Array.from(el.renderRoot.querySelectorAll('sl-grid-filter')).map(filter => filter?.renderRoot.querySelector('sl-popover')?.querySelector('#title').textContent?.trim()); + it('should have proper filter titles', () => { + const titles = Array.from(el.renderRoot.querySelectorAll('sl-grid-filter')).map(filter => + filter?.renderRoot.querySelector('sl-popover')?.querySelector('#title')?.textContent?.trim() + ); expect(titles).to.eql(['Filter by Profession', 'Filter by Status', 'Filter by Membership']); }); - it('should have filter buttons and popovers with filter options', async () => { - const buttons = Array.from(el.renderRoot.querySelectorAll('sl-grid-filter')).map(filter => filter?.renderRoot.querySelector('.toggle')); - const popovers = Array.from(el.renderRoot.querySelectorAll('sl-grid-filter')).map(filter => filter?.renderRoot.querySelector('sl-popover')); + it('should have filter buttons and popovers with filter options', () => { + const buttons = Array.from(el.renderRoot.querySelectorAll('sl-grid-filter')).map(filter => + filter?.renderRoot.querySelector('.toggle') + ); + const popovers = Array.from(el.renderRoot.querySelectorAll('sl-grid-filter')).map(filter => + filter?.renderRoot.querySelector('sl-popover') + ); expect(buttons).to.exist; expect(popovers).to.exist; @@ -92,36 +97,40 @@ describe('sl-grid-filter-column', () => { // TODO: this one below is not working, I cannot check sl-checkboxes which are rendered options to filter it('should have proper filter options when there is no mode', async () => { - const columns = el.renderRoot.querySelectorAll('sl-grid-filter'); //Array.from(el.renderRoot.querySelectorAll('sl-grid-filter')); + const columns = el.renderRoot.querySelectorAll('sl-grid-filter'); const popover = columns[0]?.renderRoot.querySelector('sl-popover'); - // await popover.updateComplete; const filterButton = columns[0]?.renderRoot.querySelector('#anchor'); - await new Promise(resolve => setTimeout(resolve, 100)); - console.log('filterButton no mode---', filterButton); - // TODO: filterButton to exist - // filterButton?.click(); expect(filterButton).to.exist; + // filterButton?.click(); + const clickEvent = new Event('click'); filterButton?.dispatchEvent(clickEvent); - await popover.updateComplete; await new Promise(resolve => setTimeout(resolve, 100)); + const checkboxGroup = popover?.querySelector('sl-checkbox-group') as CheckboxGroup; await checkboxGroup.updateComplete; await new Promise(resolve => setTimeout(resolve, 100)); - const filterColumns = checkboxGroup?.querySelectorAll('sl-checkbox'); - // const filterColumns = popover?.querySelectorAll('sl-checkbox'); /*Array.from(popover?.querySelectorAll('sl-checkbox')).map(col => - // col.innerHTML - //);*/ // col.textContent?.trim() + + const filterOptions = checkboxGroup?.querySelectorAll('sl-checkbox'); await el.updateComplete; - // await popover.updateComplete; await new Promise(resolve => setTimeout(resolve, 100)); - console.log('popover in no mode---', popover, 'columns no mode---', columns[0].renderRoot, 'checkboxGroup no mode---', checkboxGroup.renderRoot, checkboxGroup.renderRoot.querySelector('slot')?.assignedNodes()); - console.log('checkboxgroup no mode---', checkboxGroup, filterColumns, Array.from(checkboxGroup?.querySelectorAll('sl-checkbox')), popover?.querySelectorAll('sl-checkbox')); + console.log('filterOptions', filterOptions); + console.log( + 'popover in no mode---', + popover, + 'columns no mode---', + columns[0].renderRoot, + 'checkboxGroup no mode---', + checkboxGroup.renderRoot, + checkboxGroup.renderRoot.querySelector('slot')?.assignedNodes() + ); + // console.log('checkboxgroup no mode---', checkboxGroup, filterOptions, Array.from(checkboxGroup?.querySelectorAll('sl-checkbox')), popover?.querySelectorAll('sl-checkbox')); + // expect(filterOptions).to.exist; // TODO: and check content of the options (checkboxes) expect(checkboxGroup).to.have.trimmed.text('Endocrinologist'); // TODO: expect options (sl-checkboxes) to exist @@ -129,12 +138,10 @@ describe('sl-grid-filter-column', () => { // TODO: check filter options - // TODO: no value by default? - - // TODO: check filter icon when filtered and not filtered + // TODO: no value by default? when it's not filtered + // TODO: check filter icon when filtered and not filtered - maybe in filter.spec.ts }); }); // TODO: a list of options based on the column's values - I cannot get checkboxes from checkbox group - diff --git a/packages/components/grid/src/filter.spec.ts b/packages/components/grid/src/filter.spec.ts index 6a15f216d9..3d6cc75148 100644 --- a/packages/components/grid/src/filter.spec.ts +++ b/packages/components/grid/src/filter.spec.ts @@ -1,11 +1,10 @@ import { setupIgnoreWindowResizeObserverLoopErrors } from '@lit-labs/virtualizer/support/resize-observer-errors.js'; import { expect, fixture } from '@open-wc/testing'; +import { ArrayDataSource, DataSource } from '@sl-design-system/shared'; import { html } from 'lit'; import '../register.js'; -import { type Grid } from './grid.js'; -import {ArrayDataSource, DataSource, getNameByPath} from "@sl-design-system/shared"; -import {GridFilter} from "./filter.js"; -import {GridFilterColumn} from "./filter-column.js"; +import { GridFilterColumn } from './filter-column.js'; +import { GridFilter } from './filter.js'; setupIgnoreWindowResizeObserverLoopErrors(beforeEach, afterEach); @@ -21,31 +20,22 @@ describe('sl-grid-filter', () => { const options = [ { - "label": "Premium", - "value": "Premium" + label: 'Premium', + value: 'Premium' }, { - "label": "Regular", - "value": "Regular" + label: 'Regular', + value: 'Regular' }, { - "label": "VIP", - "value": "VIP" + label: 'VIP', + value: 'VIP' } ]; - // let el: Grid; - // let cells: HTMLElement[]; - - // TODO: use addFilter?? - // TODO: test mode -> .mode=${this.mode || 'select'} // TODO: test options -> .options=${this.options ?? this.internalOptions} - /* - Name - */ - // .value=${dataSource.filters.values()} // .filter=... @@ -57,13 +47,9 @@ describe('sl-grid-filter', () => { beforeEach(async () => { wrapper = await fixture(html` - - Membership - + + Membership + `); el = wrapper.querySelector('sl-grid-filter')!; @@ -73,8 +59,8 @@ describe('sl-grid-filter', () => { await new Promise(resolve => setTimeout(resolve, 200)); await el.updateComplete; - console.log('wrapper before and el', wrapper, el, dataSource); - // console.log('eeeeeel1 before', el, el.renderRoot); + console.log('wrapper before and el', wrapper, el, dataSource); + // console.log('el before', el, el.renderRoot); // el = await fixture(html` // // @@ -105,12 +91,10 @@ describe('sl-grid-filter', () => { // // Give grid time to render the table structure // await new Promise(resolve => setTimeout(resolve, 100)); // await el.updateComplete; - - // cells = Array.from(el.renderRoot.querySelectorAll('tbody tr:first-of-type td')); }); - it('should render correct checkboxes', () => { - // console.log('wrapper', wrapper, wrapper.renderRoot); + it('should render correct checkboxes', () => { + // console.log('wrapper', wrapper, wrapper.renderRoot); console.log('eeeeeel1', el); expect(wrapper).not.to.exist; }); @@ -152,7 +136,6 @@ describe('sl-grid-filter', () => { // // expect(columns).to.deep.equal(['First name', 'Last name', 'Age']); // }); - // it('should have a filter column header with a proper mode when it is set', () => { // console.log('el', el); // const columns = Array.from(el.renderRoot.querySelectorAll('th')).map(col => col.textContent); @@ -226,7 +209,6 @@ describe('sl-grid-filter', () => { // TODO: events emitting tests - // TODO: test this exactly (inside th, similar to sorter.spec.ts?): /* { ${this.header ?? getNameByPath(this.path)} */ - // TODO: test mode text and select From 7b120ab6ff4d3f61626395b2dbc9f774ed24ddf7 Mon Sep 17 00:00:00 2001 From: Jeroen Zwartepoorte Date: Fri, 23 Aug 2024 09:31:45 +0200 Subject: [PATCH 16/29] =?UTF-8?q?=F0=9F=9A=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/grid/src/filter-column.spec.ts | 94 ++++++++----------- 1 file changed, 40 insertions(+), 54 deletions(-) diff --git a/packages/components/grid/src/filter-column.spec.ts b/packages/components/grid/src/filter-column.spec.ts index d1a89cb83d..1249fc0c4e 100644 --- a/packages/components/grid/src/filter-column.spec.ts +++ b/packages/components/grid/src/filter-column.spec.ts @@ -1,41 +1,41 @@ import { setupIgnoreWindowResizeObserverLoopErrors } from '@lit-labs/virtualizer/support/resize-observer-errors.js'; import { expect, fixture } from '@open-wc/testing'; // import { Checkbox } from '@sl-design-system/checkbox'; -import { type CheckboxGroup } from '@sl-design-system/checkbox'; import { html } from 'lit'; import '../register.js'; import { type Grid } from './grid.js'; setupIgnoreWindowResizeObserverLoopErrors(beforeEach, afterEach); +const ITEMS = [ + { + firstName: 'John', + lastName: 'Doe', + profession: 'Endocrinologist', + status: 'Available', + membership: 'Regular' + }, + { + firstName: 'Jane', + lastName: 'Smith', + profession: 'Anesthesiologist', + status: 'Busy', + membership: 'Premium' + } +]; + describe('sl-grid-filter-column', () => { let el: Grid; describe('defaults', () => { beforeEach(async () => { el = await fixture(html` - + `); - el.items = [ - { - firstName: 'John', - lastName: 'Doe', - profession: 'Endocrinologist', - status: 'Available', - membership: 'Regular' - }, - { - firstName: 'Jane', - lastName: 'Smith', - profession: 'Anesthesiologist', - status: 'Busy', - membership: 'Premium' - } - ]; await el.updateComplete; // Give grid time to render the table structure @@ -61,18 +61,18 @@ describe('sl-grid-filter-column', () => { }); it('should have no filter mode by default', () => { - const filterColumn = Array.from(el.querySelectorAll('sl-grid-filter-column'))[0]; - const filterMode = filterColumn.getAttribute('mode'); + const filterColumn = el.querySelector('sl-grid-filter-column'); - expect(filterMode).not.to.exist; + expect(filterColumn).to.exist; + expect(filterColumn).not.to.have.attribute('mode'); }); it('should have no active filter by default', () => { - const columns = Array.from(el.renderRoot.querySelectorAll('sl-grid-filter')).map(filter => + const active = Array.from(el.renderRoot.querySelectorAll('sl-grid-filter')).map(filter => filter.hasAttribute('active') ); - expect(columns).to.eql([false, false, false]); + expect(active).to.deep.equal([true, false, false]); }); it('should have proper filter titles', () => { @@ -95,45 +95,31 @@ describe('sl-grid-filter-column', () => { expect(popovers).to.exist; }); - // TODO: this one below is not working, I cannot check sl-checkboxes which are rendered options to filter it('should have proper filter options when there is no mode', async () => { - const columns = el.renderRoot.querySelectorAll('sl-grid-filter'); - const popover = columns[0]?.renderRoot.querySelector('sl-popover'); - const filterButton = columns[0]?.renderRoot.querySelector('#anchor'); - - expect(filterButton).to.exist; + const filter = el.renderRoot.querySelector('sl-grid-filter'), + popover = filter?.renderRoot.querySelector('sl-popover'), + button = filter?.renderRoot.querySelector('sl-button'); - // filterButton?.click(); - - const clickEvent = new Event('click'); - filterButton?.dispatchEvent(clickEvent); - await new Promise(resolve => setTimeout(resolve, 100)); + expect(button).to.exist; + expect(button).to.have.attribute('id'); + expect(button!.id).to.equal(popover?.getAttribute('anchor')); - const checkboxGroup = popover?.querySelector('sl-checkbox-group') as CheckboxGroup; - await checkboxGroup.updateComplete; + // Open the popover + button?.click(); await new Promise(resolve => setTimeout(resolve, 100)); - const filterOptions = checkboxGroup?.querySelectorAll('sl-checkbox'); + const checkboxGroup = popover?.querySelector('sl-checkbox-group'); - await el.updateComplete; - await new Promise(resolve => setTimeout(resolve, 100)); - - console.log('filterOptions', filterOptions); - console.log( - 'popover in no mode---', - popover, - 'columns no mode---', - columns[0].renderRoot, - 'checkboxGroup no mode---', - checkboxGroup.renderRoot, - checkboxGroup.renderRoot.querySelector('slot')?.assignedNodes() - ); - // console.log('checkboxgroup no mode---', checkboxGroup, filterOptions, Array.from(checkboxGroup?.querySelectorAll('sl-checkbox')), popover?.querySelectorAll('sl-checkbox')); + expect(checkboxGroup).to.exist; + expect(checkboxGroup).to.have.attribute('aria-labelledby'); + expect(checkboxGroup?.getAttribute('aria-labelledby')).to.equal(popover?.querySelector('h1')?.id); - // expect(filterOptions).to.exist; // TODO: and check content of the options (checkboxes) - expect(checkboxGroup).to.have.trimmed.text('Endocrinologist'); + const options = Array.from(checkboxGroup!.querySelectorAll('sl-checkbox')), + labels = options.map(o => o.querySelector('[slot="label"]')?.textContent?.trim()); - // TODO: expect options (sl-checkboxes) to exist + expect(options).to.have.length(2); + expect(options.map(o => o.checked)).to.deep.equal([false, true]); + expect(labels).to.deep.equal(['Anesthesiologist', 'Endocrinologist']); }); // TODO: check filter options From d2d35a713f214328db442bb7fd110f8bfbcee9c6 Mon Sep 17 00:00:00 2001 From: Jeroen Zwartepoorte Date: Fri, 23 Aug 2024 09:38:35 +0200 Subject: [PATCH 17/29] =?UTF-8?q?=F0=9F=9B=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/components/grid/src/filter.spec.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/components/grid/src/filter.spec.ts b/packages/components/grid/src/filter.spec.ts index 3d6cc75148..5cfdc3940c 100644 --- a/packages/components/grid/src/filter.spec.ts +++ b/packages/components/grid/src/filter.spec.ts @@ -45,14 +45,11 @@ describe('sl-grid-filter', () => { describe('defaults', () => { beforeEach(async () => { - wrapper = await fixture(html` - - - Membership - - + el = await fixture(html` + + Membership + `); - el = wrapper.querySelector('sl-grid-filter')!; await el.updateComplete; // Give grid time to render the table structure From 7a4ef6f6d192687e4797583b6089c30702bb8fa5 Mon Sep 17 00:00:00 2001 From: anna-lach Date: Fri, 23 Aug 2024 14:52:50 +0200 Subject: [PATCH 18/29] filter column tests changes --- .../components/grid/src/filter-column.spec.ts | 120 +++++++++++++++++- packages/components/grid/src/filter.spec.ts | 3 +- 2 files changed, 117 insertions(+), 6 deletions(-) diff --git a/packages/components/grid/src/filter-column.spec.ts b/packages/components/grid/src/filter-column.spec.ts index 1249fc0c4e..889abc1c53 100644 --- a/packages/components/grid/src/filter-column.spec.ts +++ b/packages/components/grid/src/filter-column.spec.ts @@ -21,6 +21,13 @@ const ITEMS = [ profession: 'Anesthesiologist', status: 'Busy', membership: 'Premium' + }, + { + firstName: 'Jimmy', + lastName: 'Adams', + profession: 'Cardiologist', + status: 'Busy', + membership: 'Premium' } ]; @@ -31,7 +38,7 @@ describe('sl-grid-filter-column', () => { beforeEach(async () => { el = await fixture(html` - + @@ -72,7 +79,7 @@ describe('sl-grid-filter-column', () => { filter.hasAttribute('active') ); - expect(active).to.deep.equal([true, false, false]); + expect(active).to.deep.equal([false, false, false]); }); it('should have proper filter titles', () => { @@ -117,9 +124,9 @@ describe('sl-grid-filter-column', () => { const options = Array.from(checkboxGroup!.querySelectorAll('sl-checkbox')), labels = options.map(o => o.querySelector('[slot="label"]')?.textContent?.trim()); - expect(options).to.have.length(2); - expect(options.map(o => o.checked)).to.deep.equal([false, true]); - expect(labels).to.deep.equal(['Anesthesiologist', 'Endocrinologist']); + expect(options).to.have.length(3); + expect(options.map(o => o.checked)).to.deep.equal([false, false, false]); + expect(labels).to.deep.equal(['Anesthesiologist', 'Cardiologist', 'Endocrinologist']); }); // TODO: check filter options @@ -128,6 +135,109 @@ describe('sl-grid-filter-column', () => { // TODO: check filter icon when filtered and not filtered - maybe in filter.spec.ts }); + + describe('active filter', () => { + beforeEach(async () => { + el = await fixture(html` + + + + + + `); + await el.updateComplete; + + // Give grid time to render the table structure + await new Promise(resolve => setTimeout(resolve, 200)); + await el.updateComplete; + }); + + it('should have active filter', () => { + const active = Array.from(el.renderRoot.querySelectorAll('sl-grid-filter')).map(filter => + filter.hasAttribute('active') + ); + + expect(active).to.deep.equal([true, true, false]); + }); + + // TODO: check shown items + }); + + describe('select mode', () => { + beforeEach(async () => { + el = await fixture(html` + + + + + + `); + await el.updateComplete; + + // Give grid time to render the table structure + await new Promise(resolve => setTimeout(resolve, 200)); + await el.updateComplete; + }); + + // it('should render column and filter column headers', () => { + // const columns = Array.from(el.renderRoot.querySelectorAll('th')); + // const filterColumns = Array.from(el.renderRoot?.querySelectorAll('sl-grid-filter')).map(col => + // col.textContent?.trim() + // ); + // + // expect(columns).to.exist; + // expect(filterColumns).to.exist; + // + // expect(columns.map(col => col.getAttribute('part')?.trim())).to.deep.equal([ + // 'header filter profession', + // 'header filter status', + // 'header filter membership' + // ]); + // expect(filterColumns).to.deep.equal(['Profession', 'Status', 'Membership']); + // }); + }); + + describe('text mode', () => { + beforeEach(async () => { + el = await fixture(html` + + + + + + `); + await el.updateComplete; + + // Give grid time to render the table structure + await new Promise(resolve => setTimeout(resolve, 200)); + await el.updateComplete; + }); + + // it('should render column and filter column headers', () => { + // const columns = Array.from(el.renderRoot.querySelectorAll('th')); + // const filterColumns = Array.from(el.renderRoot?.querySelectorAll('sl-grid-filter')).map(col => + // col.textContent?.trim() + // ); + // + // expect(columns).to.exist; + // expect(filterColumns).to.exist; + // + // expect(columns.map(col => col.getAttribute('part')?.trim())).to.deep.equal([ + // 'header filter profession', + // 'header filter status', + // 'header filter membership' + // ]); + // expect(filterColumns).to.deep.equal(['Profession', 'Status', 'Membership']); + // }); + }); }); // TODO: a list of options based on the column's values - I cannot get checkboxes from checkbox group + +/*describe('defaults) + +describe('active filter') + +describe('select mode') + +describe('text mode')*/ diff --git a/packages/components/grid/src/filter.spec.ts b/packages/components/grid/src/filter.spec.ts index 5cfdc3940c..ddfc964775 100644 --- a/packages/components/grid/src/filter.spec.ts +++ b/packages/components/grid/src/filter.spec.ts @@ -93,7 +93,8 @@ describe('sl-grid-filter', () => { it('should render correct checkboxes', () => { // console.log('wrapper', wrapper, wrapper.renderRoot); console.log('eeeeeel1', el); - expect(wrapper).not.to.exist; + // expect(wrapper).not.to.exist; + expect(el).not.to.exist; }); // it('should render column and filter column headers', () => { From 81ac1dbf3c21ed99d81b4eddc1269cb83285e425 Mon Sep 17 00:00:00 2001 From: anna-lach Date: Mon, 26 Aug 2024 16:04:34 +0200 Subject: [PATCH 19/29] filter column tests, filter test change --- .../components/grid/src/filter-column.spec.ts | 156 ++++++++++++------ packages/components/grid/src/filter.spec.ts | 17 +- 2 files changed, 120 insertions(+), 53 deletions(-) diff --git a/packages/components/grid/src/filter-column.spec.ts b/packages/components/grid/src/filter-column.spec.ts index 889abc1c53..cbe9293183 100644 --- a/packages/components/grid/src/filter-column.spec.ts +++ b/packages/components/grid/src/filter-column.spec.ts @@ -82,6 +82,15 @@ describe('sl-grid-filter-column', () => { expect(active).to.deep.equal([false, false, false]); }); + it('should have a button with the right icon when it is not filtered', () => { + const filter = el.renderRoot.querySelector('sl-grid-filter'), + button = filter?.renderRoot.querySelector('sl-button'), + icon = button?.querySelector('sl-icon'); + + expect(icon).to.exist; + expect(icon.getAttribute('name')).to.equal('far-filter'); + }); + it('should have proper filter titles', () => { const titles = Array.from(el.renderRoot.querySelectorAll('sl-grid-filter')).map(filter => filter?.renderRoot.querySelector('sl-popover')?.querySelector('#title')?.textContent?.trim() @@ -128,12 +137,6 @@ describe('sl-grid-filter-column', () => { expect(options.map(o => o.checked)).to.deep.equal([false, false, false]); expect(labels).to.deep.equal(['Anesthesiologist', 'Cardiologist', 'Endocrinologist']); }); - - // TODO: check filter options - - // TODO: no value by default? when it's not filtered - - // TODO: check filter icon when filtered and not filtered - maybe in filter.spec.ts }); describe('active filter', () => { @@ -160,14 +163,42 @@ describe('sl-grid-filter-column', () => { expect(active).to.deep.equal([true, true, false]); }); - // TODO: check shown items + it('should have checked option in the select mode when it is filtered', async () => { + const filter = el.renderRoot.querySelector('sl-grid-filter'), + popover = filter?.renderRoot.querySelector('sl-popover'), + button = filter?.renderRoot.querySelector('sl-button'); + + expect(button).to.exist; + + // Open the popover + button?.click(); + await new Promise(resolve => setTimeout(resolve, 100)); + + const checkboxGroup = popover?.querySelector('sl-checkbox-group'); + + expect(checkboxGroup).to.exist; + + const optionsChecked = Array.from(checkboxGroup!.querySelectorAll('sl-checkbox[checked]')), + labels = optionsChecked.map(o => o.querySelector('[slot="label"]')?.textContent?.trim()); + + expect(labels).to.deep.equal(['Cardiologist', 'Endocrinologist']); + }); + + it('should have a button with the right icon when it is filtered', () => { + const filter = el.renderRoot.querySelector('sl-grid-filter'), + button = filter?.renderRoot.querySelector('sl-button'), + icon = button?.querySelector('sl-icon'); + + expect(icon).to.exist; + expect(icon.getAttribute('name')).to.equal('fas-filter'); + }); }); describe('select mode', () => { beforeEach(async () => { el = await fixture(html` - + @@ -179,31 +210,69 @@ describe('sl-grid-filter-column', () => { await el.updateComplete; }); - // it('should render column and filter column headers', () => { - // const columns = Array.from(el.renderRoot.querySelectorAll('th')); - // const filterColumns = Array.from(el.renderRoot?.querySelectorAll('sl-grid-filter')).map(col => - // col.textContent?.trim() - // ); - // - // expect(columns).to.exist; - // expect(filterColumns).to.exist; - // - // expect(columns.map(col => col.getAttribute('part')?.trim())).to.deep.equal([ - // 'header filter profession', - // 'header filter status', - // 'header filter membership' - // ]); - // expect(filterColumns).to.deep.equal(['Profession', 'Status', 'Membership']); - // }); + it('should have proper options', async () => { + const filters = el.renderRoot.querySelectorAll('sl-grid-filter'), + popoverProfession = filters[0]?.renderRoot.querySelector('sl-popover'), + buttonProfession = filters[0]?.renderRoot.querySelector('sl-button'), + popoverStatus = filters[1]?.renderRoot.querySelector('sl-popover'), + buttonStatus = filters[1]?.renderRoot.querySelector('sl-button'), + popoverMembership = filters[2]?.renderRoot.querySelector('sl-popover'), + buttonMembership = filters[2]?.renderRoot.querySelector('sl-button'); + + expect(buttonProfession).to.exist; + + // Open the popover + buttonProfession?.click(); + await new Promise(resolve => setTimeout(resolve, 100)); + + const checkboxGroupProfession = popoverProfession?.querySelector('sl-checkbox-group'); + + expect(checkboxGroupProfession).to.exist; + + const optionsProfession = Array.from(checkboxGroupProfession!.querySelectorAll('sl-checkbox')), + labelsProfession = optionsProfession.map(o => o.querySelector('[slot="label"]')?.textContent?.trim()); + + expect(labelsProfession).to.deep.equal(['Anesthesiologist', 'Cardiologist', 'Endocrinologist']); + + expect(buttonStatus).to.exist; + + // Open the popover + buttonStatus?.click(); + await new Promise(resolve => setTimeout(resolve, 100)); + + const checkboxGroupStatus = popoverStatus?.querySelector('sl-checkbox-group'); + + expect(checkboxGroupStatus).to.exist; + + const optionsStatus = Array.from(checkboxGroupStatus!.querySelectorAll('sl-checkbox')), + labelsStatus = optionsStatus.map(o => o.querySelector('[slot="label"]')?.textContent?.trim()); + + expect(labelsStatus).to.deep.equal(['Available', 'Busy']); + + expect(buttonMembership).to.exist; + + // Open the popover + buttonMembership?.click(); + await new Promise(resolve => setTimeout(resolve, 100)); + + const checkboxGroupMembership = popoverMembership?.querySelector('sl-checkbox-group'); + + expect(checkboxGroupProfession).to.exist; + + const optionsMembership = Array.from(checkboxGroupMembership!.querySelectorAll('sl-checkbox')), + labelsMembership = optionsMembership.map(o => o.querySelector('[slot="label"]')?.textContent?.trim()); + + expect(labelsMembership).to.deep.equal(['Premium', 'Regular']); + }); }); describe('text mode', () => { beforeEach(async () => { el = await fixture(html` - + - + `); await el.updateComplete; @@ -213,31 +282,16 @@ describe('sl-grid-filter-column', () => { await el.updateComplete; }); - // it('should render column and filter column headers', () => { - // const columns = Array.from(el.renderRoot.querySelectorAll('th')); - // const filterColumns = Array.from(el.renderRoot?.querySelectorAll('sl-grid-filter')).map(col => - // col.textContent?.trim() - // ); - // - // expect(columns).to.exist; - // expect(filterColumns).to.exist; - // - // expect(columns.map(col => col.getAttribute('part')?.trim())).to.deep.equal([ - // 'header filter profession', - // 'header filter status', - // 'header filter membership' - // ]); - // expect(filterColumns).to.deep.equal(['Profession', 'Status', 'Membership']); - // }); - }); -}); - -// TODO: a list of options based on the column's values - I cannot get checkboxes from checkbox group + it('should have text field', () => { + const filters = el.renderRoot.querySelectorAll('sl-grid-filter'), + popovers = Array.from(filters).map(o => o.renderRoot.querySelector('sl-popover')); -/*describe('defaults) - -describe('active filter') + expect(popovers).to.exist; -describe('select mode') + const textFields = Array.from(popovers).map(o => o.querySelector('sl-text-field')); -describe('text mode')*/ + expect(textFields).to.exist; + expect(textFields).to.have.length(3); + }); + }); +}); diff --git a/packages/components/grid/src/filter.spec.ts b/packages/components/grid/src/filter.spec.ts index ddfc964775..08599cb567 100644 --- a/packages/components/grid/src/filter.spec.ts +++ b/packages/components/grid/src/filter.spec.ts @@ -90,11 +90,22 @@ describe('sl-grid-filter', () => { // await el.updateComplete; }); - it('should render correct checkboxes', () => { + it('should render correct icon', () => { + const button = el.renderRoot?.querySelector('sl-button'), + icon = el.querySelector('sl-icon'); + // console.log('wrapper', wrapper, wrapper.renderRoot); + console.log('icon', icon, button, el); + // expect(wrapper).not.to.exist; + expect(button).to.exist; + expect(icon).to.exist; + }); // TODO: check right title? membership + + it('should render correct items', () => { + // TODO: check this one... // console.log('wrapper', wrapper, wrapper.renderRoot); console.log('eeeeeel1', el); // expect(wrapper).not.to.exist; - expect(el).not.to.exist; + expect(el).to.exist; }); // it('should render column and filter column headers', () => { @@ -220,3 +231,5 @@ ${this.header ?? getNameByPath(this.path)} */ // TODO: test mode text and select + +// TODO: check shown items when filtered From 9dbe0bc8a284fef7ca1c1fc0d9dcdcd1c3ed0d72 Mon Sep 17 00:00:00 2001 From: anna-lach Date: Tue, 27 Aug 2024 10:43:48 +0200 Subject: [PATCH 20/29] Trying to change filter test example --- packages/components/grid/src/filter.spec.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/components/grid/src/filter.spec.ts b/packages/components/grid/src/filter.spec.ts index 08599cb567..1aa36db5e6 100644 --- a/packages/components/grid/src/filter.spec.ts +++ b/packages/components/grid/src/filter.spec.ts @@ -9,7 +9,7 @@ import { GridFilter } from './filter.js'; setupIgnoreWindowResizeObserverLoopErrors(beforeEach, afterEach); describe('sl-grid-filter', () => { - let wrapper: HTMLElement; + // let wrapper: HTMLElement; let el: GridFilter; const items = [{ membership: 'Premium' }, { membership: 'VIP' }, { membership: 'Regular' }]; @@ -45,18 +45,19 @@ describe('sl-grid-filter', () => { describe('defaults', () => { beforeEach(async () => { + // TODO: how to connect grid-filter with dataSource? el = await fixture(html` Membership - `); + `); // .filter=${dataSource.filters} await el.updateComplete; // Give grid time to render the table structure - await new Promise(resolve => setTimeout(resolve, 200)); + await new Promise(resolve => setTimeout(resolve, 500)); await el.updateComplete; - console.log('wrapper before and el', wrapper, el, dataSource); + // console.log('wrapper before and el', wrapper, el, dataSource); // console.log('el before', el, el.renderRoot); // el = await fixture(html` // @@ -94,7 +95,7 @@ describe('sl-grid-filter', () => { const button = el.renderRoot?.querySelector('sl-button'), icon = el.querySelector('sl-icon'); // console.log('wrapper', wrapper, wrapper.renderRoot); - console.log('icon', icon, button, el); + console.log('icon', icon, button, el, 'el.renderRoot', el.renderRoot, 'dataSource', dataSource); // expect(wrapper).not.to.exist; expect(button).to.exist; expect(icon).to.exist; @@ -233,3 +234,5 @@ ${this.header ?? getNameByPath(this.path)} // TODO: test mode text and select // TODO: check shown items when filtered + +// TODO: check whether grid filter is active From d7eac3a8597a5a21882e3f03ca02dcf196dc5466 Mon Sep 17 00:00:00 2001 From: anna-lach Date: Tue, 27 Aug 2024 12:50:57 +0200 Subject: [PATCH 21/29] trying to improve the example in filter tests --- packages/components/grid/src/filter-column.ts | 6 +- packages/components/grid/src/filter.spec.ts | 68 ++++++++++++++++--- 2 files changed, 62 insertions(+), 12 deletions(-) diff --git a/packages/components/grid/src/filter-column.ts b/packages/components/grid/src/filter-column.ts index 12fb1cacf1..e5ab76c1b9 100644 --- a/packages/components/grid/src/filter-column.ts +++ b/packages/components/grid/src/filter-column.ts @@ -97,8 +97,8 @@ export class GridFilterColumn extends GridColumn { override renderHeader(): TemplateResult { const parts = ['header', 'filter', ...this.getParts()]; - console.log(' this.internalOptions', this.internalOptions, this.options, this.path, this, this.value); - console.log('dataSource', this.grid?.dataSource, this.grid); + console.log(' this.internalOptions', this.internalOptions, this.options, this.path, this, this.value); + console.log('dataSource', this.grid?.dataSource, this.grid); return html` @@ -112,6 +112,6 @@ export class GridFilterColumn extends GridColumn { ${this.header ?? getNameByPath(this.path)} - `; + `; // .filter=${this.filter} } } diff --git a/packages/components/grid/src/filter.spec.ts b/packages/components/grid/src/filter.spec.ts index 1aa36db5e6..dd0b7f3133 100644 --- a/packages/components/grid/src/filter.spec.ts +++ b/packages/components/grid/src/filter.spec.ts @@ -9,14 +9,18 @@ import { GridFilter } from './filter.js'; setupIgnoreWindowResizeObserverLoopErrors(beforeEach, afterEach); describe('sl-grid-filter', () => { - // let wrapper: HTMLElement; + let wrapper: HTMLElement; let el: GridFilter; const items = [{ membership: 'Premium' }, { membership: 'VIP' }, { membership: 'Regular' }]; const column = new GridFilterColumn(); + // column.path = 'membership'; + // column.value = 'Premium'; + // await column.updateComplete; + const dataSource = new ArrayDataSource(items) as DataSource; - dataSource.addFilter('', 'membership', ['Premium']); + // dataSource.addFilter('', 'membership', ['Premium']); const options = [ { @@ -33,6 +37,8 @@ describe('sl-grid-filter', () => { } ]; + console.log('column before', column); + // TODO: test mode -> .mode=${this.mode || 'select'} // TODO: test options -> .options=${this.options ?? this.internalOptions} @@ -45,19 +51,50 @@ describe('sl-grid-filter', () => { describe('defaults', () => { beforeEach(async () => { + column.path = 'membership'; + column.value = 'Premium'; + await new Promise(resolve => setTimeout(resolve, 200)); + // await column.updateComplete; + + dataSource.addFilter('', 'membership', ['Premium']); + await new Promise(resolve => setTimeout(resolve, 200)); + // TODO: how to connect grid-filter with dataSource? - el = await fixture(html` - - Membership - + wrapper = await fixture(html` + + + Membership + + `); // .filter=${dataSource.filters} + el = wrapper.querySelector('sl-grid-filter')!; + await new Promise(resolve => setTimeout(resolve, 200)); await el.updateComplete; // Give grid time to render the table structure - await new Promise(resolve => setTimeout(resolve, 500)); + await new Promise(resolve => setTimeout(resolve, 200)); await el.updateComplete; - // console.log('wrapper before and el', wrapper, el, dataSource); + console.log( + 'wrapper before and el', + wrapper, + el, + dataSource, + 'column', + column, + dataSource.filters, + 'filteredItems', + dataSource.filteredItems, + 'column', + column + ); // console.log('el before', el, el.renderRoot); // el = await fixture(html` // @@ -95,7 +132,18 @@ describe('sl-grid-filter', () => { const button = el.renderRoot?.querySelector('sl-button'), icon = el.querySelector('sl-icon'); // console.log('wrapper', wrapper, wrapper.renderRoot); - console.log('icon', icon, button, el, 'el.renderRoot', el.renderRoot, 'dataSource', dataSource); + console.log( + 'icon', + icon, + button, + el, + 'el.renderRoot', + el.renderRoot, + 'dataSource', + dataSource, + 'wrapper', + wrapper + ); // expect(wrapper).not.to.exist; expect(button).to.exist; expect(icon).to.exist; @@ -236,3 +284,5 @@ ${this.header ?? getNameByPath(this.path)} // TODO: check shown items when filtered // TODO: check whether grid filter is active + +// TODO: defaults, filtered tests From c43d6cda33bb7d3b0ee650d530579c0fc9fde714 Mon Sep 17 00:00:00 2001 From: anna-lach Date: Wed, 28 Aug 2024 09:47:34 +0200 Subject: [PATCH 22/29] filter test updated --- packages/components/grid/src/filter-column.ts | 4 ++-- packages/components/grid/src/filter.spec.ts | 10 ++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/components/grid/src/filter-column.ts b/packages/components/grid/src/filter-column.ts index e5ab76c1b9..c96d142122 100644 --- a/packages/components/grid/src/filter-column.ts +++ b/packages/components/grid/src/filter-column.ts @@ -97,8 +97,8 @@ export class GridFilterColumn extends GridColumn { override renderHeader(): TemplateResult { const parts = ['header', 'filter', ...this.getParts()]; - console.log(' this.internalOptions', this.internalOptions, this.options, this.path, this, this.value); - console.log('dataSource', this.grid?.dataSource, this.grid); + // console.log(' this.internalOptions', this.internalOptions, this.options, this.path, this, this.value); + // console.log('dataSource', this.grid?.dataSource, this.grid); return html` diff --git a/packages/components/grid/src/filter.spec.ts b/packages/components/grid/src/filter.spec.ts index dd0b7f3133..e8c34bc0db 100644 --- a/packages/components/grid/src/filter.spec.ts +++ b/packages/components/grid/src/filter.spec.ts @@ -51,6 +51,12 @@ describe('sl-grid-filter', () => { describe('defaults', () => { beforeEach(async () => { + try { + customElements.define('sl-grid-filter', GridFilter); + } catch { + // + } + column.path = 'membership'; column.value = 'Premium'; await new Promise(resolve => setTimeout(resolve, 200)); @@ -82,7 +88,7 @@ describe('sl-grid-filter', () => { await new Promise(resolve => setTimeout(resolve, 200)); await el.updateComplete; - console.log( + /* console.log( 'wrapper before and el', wrapper, el, @@ -94,7 +100,7 @@ describe('sl-grid-filter', () => { dataSource.filteredItems, 'column', column - ); + );*/ // console.log('el before', el, el.renderRoot); // el = await fixture(html` // From 1e2986ed098efc1d7b7682c10a398ac86f1c520c Mon Sep 17 00:00:00 2001 From: anna-lach Date: Wed, 28 Aug 2024 15:52:04 +0200 Subject: [PATCH 23/29] new tests, removed unnecessary elements --- packages/components/grid/src/filter-column.ts | 5 +- packages/components/grid/src/filter.spec.ts | 302 ++++++------------ packages/components/grid/src/filter.ts | 2 +- .../src/data-source/array-data-source.ts | 1 - .../shared/src/data-source/data-source.ts | 2 - 5 files changed, 100 insertions(+), 212 deletions(-) diff --git a/packages/components/grid/src/filter-column.ts b/packages/components/grid/src/filter-column.ts index c96d142122..3490930947 100644 --- a/packages/components/grid/src/filter-column.ts +++ b/packages/components/grid/src/filter-column.ts @@ -97,9 +97,6 @@ export class GridFilterColumn extends GridColumn { override renderHeader(): TemplateResult { const parts = ['header', 'filter', ...this.getParts()]; - // console.log(' this.internalOptions', this.internalOptions, this.options, this.path, this, this.value); - // console.log('dataSource', this.grid?.dataSource, this.grid); - return html` extends GridColumn { ${this.header ?? getNameByPath(this.path)} - `; // .filter=${this.filter} + `; } } diff --git a/packages/components/grid/src/filter.spec.ts b/packages/components/grid/src/filter.spec.ts index e8c34bc0db..a6e5fcc3b0 100644 --- a/packages/components/grid/src/filter.spec.ts +++ b/packages/components/grid/src/filter.spec.ts @@ -1,6 +1,5 @@ import { setupIgnoreWindowResizeObserverLoopErrors } from '@lit-labs/virtualizer/support/resize-observer-errors.js'; import { expect, fixture } from '@open-wc/testing'; -import { ArrayDataSource, DataSource } from '@sl-design-system/shared'; import { html } from 'lit'; import '../register.js'; import { GridFilterColumn } from './filter-column.js'; @@ -12,14 +11,14 @@ describe('sl-grid-filter', () => { let wrapper: HTMLElement; let el: GridFilter; - const items = [{ membership: 'Premium' }, { membership: 'VIP' }, { membership: 'Regular' }]; + // const items = [{ membership: 'Premium' }, { membership: 'VIP' }, { membership: 'Regular' }]; const column = new GridFilterColumn(); // column.path = 'membership'; // column.value = 'Premium'; // await column.updateComplete; - const dataSource = new ArrayDataSource(items) as DataSource; + // const dataSource = new ArrayDataSource(items) as DataSource; // dataSource.addFilter('', 'membership', ['Premium']); const options = [ @@ -37,8 +36,6 @@ describe('sl-grid-filter', () => { } ]; - console.log('column before', column); - // TODO: test mode -> .mode=${this.mode || 'select'} // TODO: test options -> .options=${this.options ?? this.internalOptions} @@ -62,20 +59,13 @@ describe('sl-grid-filter', () => { await new Promise(resolve => setTimeout(resolve, 200)); // await column.updateComplete; - dataSource.addFilter('', 'membership', ['Premium']); - await new Promise(resolve => setTimeout(resolve, 200)); + // dataSource.addFilter('', 'membership', ['Premium']); + // await new Promise(resolve => setTimeout(resolve, 200)); // TODO: how to connect grid-filter with dataSource? wrapper = await fixture(html` - + Membership @@ -87,208 +77,112 @@ describe('sl-grid-filter', () => { // Give grid time to render the table structure await new Promise(resolve => setTimeout(resolve, 200)); await el.updateComplete; - - /* console.log( - 'wrapper before and el', - wrapper, - el, - dataSource, - 'column', - column, - dataSource.filters, - 'filteredItems', - dataSource.filteredItems, - 'column', - column - );*/ - // console.log('el before', el, el.renderRoot); - // el = await fixture(html` - // - // - // - // - // - // `); - // el.items = [ - // { - // firstName: 'John', - // lastName: 'Doe', - // age: 20, - // profession: 'Endocrinologist', - // status: 'Available', - // membership: 'Regular' - // }, - // { - // firstName: 'Jane', - // lastName: 'Smith', - // age: 40, - // profession: 'Anesthesiologist', - // status: 'Busy', - // membership: 'Premium' - // } - // ]; - // await el.updateComplete; - // - // // Give grid time to render the table structure - // await new Promise(resolve => setTimeout(resolve, 100)); - // await el.updateComplete; }); it('should render correct icon', () => { const button = el.renderRoot?.querySelector('sl-button'), - icon = el.querySelector('sl-icon'); - // console.log('wrapper', wrapper, wrapper.renderRoot); - console.log( - 'icon', - icon, - button, - el, - 'el.renderRoot', - el.renderRoot, - 'dataSource', - dataSource, - 'wrapper', - wrapper - ); - // expect(wrapper).not.to.exist; + icon = button?.querySelector('sl-icon'); + expect(button).to.exist; expect(icon).to.exist; - }); // TODO: check right title? membership - - it('should render correct items', () => { - // TODO: check this one... - // console.log('wrapper', wrapper, wrapper.renderRoot); - console.log('eeeeeel1', el); - // expect(wrapper).not.to.exist; - expect(el).to.exist; + expect(icon!.getAttribute('name')).to.equal('far-filter'); }); - // it('should render column and filter column headers', () => { - // const columns = Array.from(el.renderRoot.querySelectorAll('th')); - // // .map(col => col.textContent); - // // .slice(0, 2); - // // const filterColumns = el.renderRoot?.querySelectorAll('sl-grid-filter'); - // const filterColumns = Array.from(el.renderRoot?.querySelectorAll('sl-grid-filter')).map(col => - // col.textContent?.trim() - // ); - // - // console.log('coolumns', columns, el.renderRoot.querySelectorAll('th')); - // - // // console.log('coolumns--2', columns); - // // console.log('filterColumns', filterColumns, Array.from(filterColumns).map(col => col.textContent.trim())); - // // console.log('filterColumns trimmed', Array.from(filterColumns).map(col => col.textContent.trim())); - // // console.log('filterColumnsTrimmedfilterColumnsTrimmedfilterColumnsTrimmed', filterColumnsTrimmed); - // - // expect(columns).to.exist; - // expect(filterColumns).to.exist; - // - // // expect(columns).to.deep.equal(['First name', 'Last name']); - // expect(columns.map(col => col.getAttribute('part')?.trim())).to.deep.equal([ - // 'header filter profession', - // 'header filter status', - // 'header filter membership' - // ]); - // expect(filterColumns).to.deep.equal(['Profession', 'Status', 'Membership']); - // }); - - // it('should have no filter mode by default', () => { - // const filterColumn = Array.from(el.querySelectorAll('sl-grid-filter-column'))[0]; //[0]; - // const filterMode = filterColumn.getAttribute('mode'); - // - // // console.log('filterColumns for mode', filterColumns, filterColumnsNew, filterMode); - // expect(filterMode).not.to.exist; - // // expect(columns).to.deep.equal(['First name', 'Last name', 'Age']); - // }); - - // it('should have a filter column header with a proper mode when it is set', () => { - // console.log('el', el); - // const columns = Array.from(el.renderRoot.querySelectorAll('th')).map(col => col.textContent); - // // const filterColumns = Array.from(el.renderRoot?.querySelectorAll('sl-grid-filter'))[0]; - // const filterColumnsNew = Array.from(el.querySelectorAll('sl-grid-filter-column'))[1]; - // - // console.log('filterColumns for mode default', filterColumnsNew); - // - // expect(columns).to.deep.equal(['First name', 'Last name', 'Age']); - // - // // TODO: need to check whether there is a button and popover inside - // }); - - // it('should have the right justify-content value', () => { - // expect(cells.map(cell => getComputedStyle(cell).justifyContent)).to.deep.equal(['start', 'start', 'end']); - // }); - // - // it('should have the right grow value', () => { - // expect(cells.map(cell => getComputedStyle(cell).flexGrow)).to.deep.equal(['1', '1', '3']); - // }); - // - // it('should have the right parts', () => { - // expect(cells.map(cell => cell.getAttribute('part'))).to.deep.equal([ - // 'data first-name', - // 'data last-name', - // 'data age' - // ]); - // }); + it('should have no active filter by default', () => { + const active = el.hasAttribute('active'); + + expect(active).to.equal(false); + }); }); - // describe('custom renderer', () => { - // beforeEach(async () => { - // const avatarRenderer: GridColumnDataRenderer = ({ firstName, lastName }) => { - // return html``; - // }; - // - // el = await fixture(html` - // - // - // - // - // `); - // el.items = [ - // { firstName: 'John', lastName: 'Doe', age: 20 }, - // { firstName: 'Jane', lastName: 'Smith', age: 40 } - // ]; - // await el.updateComplete; - // - // // Give grid time to render the table structure - // await new Promise(resolve => setTimeout(resolve, 100)); - // await el.updateComplete; - // - // cells = Array.from(el.renderRoot.querySelectorAll('tbody tr:first-of-type td')); - // }); - // - // it('should render the elements set with the custom renderer', () => { - // expect(cells[0]).to.contain('sl-avatar'); - // }); - // - // it('should have the right parts, including one set on the column', () => { - // expect(cells.map(cell => cell.getAttribute('part'))).to.deep.equal(['data', 'data number age']); - // }); - // }); -}); + describe('active filter', () => { + beforeEach(async () => { + try { + customElements.define('sl-grid-filter', GridFilter); + } catch { + // + } + + column.path = 'membership'; + column.value = 'Premium'; + await new Promise(resolve => setTimeout(resolve, 200)); + + // dataSource.addFilter('', 'membership', ['Premium']); + // await new Promise(resolve => setTimeout(resolve, 200)); + + // TODO: how to connect grid-filter with dataSource? + wrapper = await fixture(html` + + + Membership + + + `); + el = wrapper.querySelector('sl-grid-filter')!; + await new Promise(resolve => setTimeout(resolve, 200)); + await el.updateComplete; + + // Give grid time to render the table structure + await new Promise(resolve => setTimeout(resolve, 200)); + await el.updateComplete; + }); + + it('should have active attribute when filtered', async () => { + const button = el.renderRoot?.querySelector('sl-button'), + popover = el?.renderRoot.querySelector('sl-popover'); + + // Open the popover + button?.click(); + await new Promise(resolve => setTimeout(resolve, 100)); + + const checkboxGroup = popover?.querySelector('sl-checkbox-group'); -// TODO: events emitting tests + expect(checkboxGroup).to.exist; -// TODO: test this exactly (inside th, similar to sorter.spec.ts?): -/* - -${this.header ?? getNameByPath(this.path)} -*/ + const options = Array.from(checkboxGroup!.querySelectorAll('sl-checkbox')); -// TODO: test mode text and select + expect(options).to.exist; + + options[0].click(); + el.value = 'Premium'; + await new Promise(resolve => setTimeout(resolve, 200)); + await el.updateComplete; + + expect(el.hasAttribute('active')).to.equal(true); + }); + + it('should have a proper icon when filtered', async () => { + const button = el.renderRoot?.querySelector('sl-button'), + popover = el?.renderRoot.querySelector('sl-popover'), + icon = button?.querySelector('sl-icon'); -// TODO: check shown items when filtered + // Open the popover + button?.click(); + await new Promise(resolve => setTimeout(resolve, 100)); -// TODO: check whether grid filter is active + const checkboxGroup = popover?.querySelector('sl-checkbox-group'); + + expect(checkboxGroup).to.exist; + + const options = Array.from(checkboxGroup!.querySelectorAll('sl-checkbox')); + + expect(options).to.exist; + + options[0].click(); + el.value = 'Premium'; + await new Promise(resolve => setTimeout(resolve, 200)); + await el.updateComplete; + + expect(icon).to.exist; + expect(icon!.getAttribute('name')).to.equal('fas-filter'); + }); + + it('should have no active filter by default', () => { + const active = el.hasAttribute('active'); + + expect(active).to.equal(false); + }); + }); +}); -// TODO: defaults, filtered tests +// TODO: remove th!!! diff --git a/packages/components/grid/src/filter.ts b/packages/components/grid/src/filter.ts index d08e9fc96d..80259f6e96 100644 --- a/packages/components/grid/src/filter.ts +++ b/packages/components/grid/src/filter.ts @@ -74,7 +74,7 @@ export class GridFilter extends ScopedElementsMixin(LitElement) { /** @internal Emits when the filter has been added or removed. */ @event({ name: 'sl-filter-change' }) filterChangeEvent!: EventEmitter; - /** @internal Emits when the value of the this filter has changed. */ + /** @internal Emits when the value of the filter has changed. */ @event({ name: 'sl-filter-value-change' }) filterValueChangeEvent!: EventEmitter>; /** The mode of the filter. */ diff --git a/packages/components/shared/src/data-source/array-data-source.ts b/packages/components/shared/src/data-source/array-data-source.ts index 4e08f1cff1..3073e8c675 100644 --- a/packages/components/shared/src/data-source/array-data-source.ts +++ b/packages/components/shared/src/data-source/array-data-source.ts @@ -25,7 +25,6 @@ export class ArrayDataSource extends DataSource { constructor(items: T[]) { super(); - console.log('items in array data source', items); this.#filteredItems = [...items]; this.#items = [...items]; } diff --git a/packages/components/shared/src/data-source/data-source.ts b/packages/components/shared/src/data-source/data-source.ts index 0e623f3192..396e13fa88 100644 --- a/packages/components/shared/src/data-source/data-source.ts +++ b/packages/components/shared/src/data-source/data-source.ts @@ -44,7 +44,6 @@ export abstract class DataSource extends EventTarget { #sort?: DataSourceSort; get filters(): Map> { - console.log('this.#filters in data source', this.#filters); return this.#filters; } @@ -73,7 +72,6 @@ export abstract class DataSource extends EventTarget { pathOrFilter: U, value?: string | string[] ): void { - console.log('in addFilter', id, pathOrFilter, value); if (typeof pathOrFilter === 'string') { this.#filters.set(id, { path: pathOrFilter, value: value ?? '' }); } else { From 9ef8a1466f9e8bebdc7ea563739de065a41be81d Mon Sep 17 00:00:00 2001 From: anna-lach Date: Thu, 29 Aug 2024 08:33:42 +0200 Subject: [PATCH 24/29] cleanup --- packages/components/grid/src/filter.spec.ts | 62 ++++----------------- 1 file changed, 10 insertions(+), 52 deletions(-) diff --git a/packages/components/grid/src/filter.spec.ts b/packages/components/grid/src/filter.spec.ts index a6e5fcc3b0..f42a5665f6 100644 --- a/packages/components/grid/src/filter.spec.ts +++ b/packages/components/grid/src/filter.spec.ts @@ -8,18 +8,9 @@ import { GridFilter } from './filter.js'; setupIgnoreWindowResizeObserverLoopErrors(beforeEach, afterEach); describe('sl-grid-filter', () => { - let wrapper: HTMLElement; let el: GridFilter; - // const items = [{ membership: 'Premium' }, { membership: 'VIP' }, { membership: 'Regular' }]; - const column = new GridFilterColumn(); - // column.path = 'membership'; - // column.value = 'Premium'; - // await column.updateComplete; - - // const dataSource = new ArrayDataSource(items) as DataSource; - // dataSource.addFilter('', 'membership', ['Premium']); const options = [ { @@ -36,16 +27,6 @@ describe('sl-grid-filter', () => { } ]; - // TODO: test mode -> .mode=${this.mode || 'select'} - // TODO: test options -> .options=${this.options ?? this.internalOptions} - - // .value=${dataSource.filters.values()} - - // .filter=... - - // path="membership" - // value="Premium" - describe('defaults', () => { beforeEach(async () => { try { @@ -57,20 +38,12 @@ describe('sl-grid-filter', () => { column.path = 'membership'; column.value = 'Premium'; await new Promise(resolve => setTimeout(resolve, 200)); - // await column.updateComplete; - - // dataSource.addFilter('', 'membership', ['Premium']); - // await new Promise(resolve => setTimeout(resolve, 200)); - - // TODO: how to connect grid-filter with dataSource? - wrapper = await fixture(html` - - - Membership - - - `); // .filter=${dataSource.filters} - el = wrapper.querySelector('sl-grid-filter')!; + + el = await fixture(html` + + Membership + + `); await new Promise(resolve => setTimeout(resolve, 200)); await el.updateComplete; @@ -107,18 +80,11 @@ describe('sl-grid-filter', () => { column.value = 'Premium'; await new Promise(resolve => setTimeout(resolve, 200)); - // dataSource.addFilter('', 'membership', ['Premium']); - // await new Promise(resolve => setTimeout(resolve, 200)); - - // TODO: how to connect grid-filter with dataSource? - wrapper = await fixture(html` - - - Membership - - + el = await fixture(html` + + Membership + `); - el = wrapper.querySelector('sl-grid-filter')!; await new Promise(resolve => setTimeout(resolve, 200)); await el.updateComplete; @@ -176,13 +142,5 @@ describe('sl-grid-filter', () => { expect(icon).to.exist; expect(icon!.getAttribute('name')).to.equal('fas-filter'); }); - - it('should have no active filter by default', () => { - const active = el.hasAttribute('active'); - - expect(active).to.equal(false); - }); }); }); - -// TODO: remove th!!! From 114096c5e5f77da8d31507abf81a3b9a08b38bc2 Mon Sep 17 00:00:00 2001 From: anna-lach Date: Thu, 29 Aug 2024 08:51:21 +0200 Subject: [PATCH 25/29] missing export --- packages/components/grid/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/components/grid/index.ts b/packages/components/grid/index.ts index b4394a5685..e35c856691 100644 --- a/packages/components/grid/index.ts +++ b/packages/components/grid/index.ts @@ -6,4 +6,5 @@ export * from './src/grid.js'; export * from './src/select-column.js'; export * from './src/selection-column.js'; export * from './src/sort-column.js'; +export * from './src/sorter.js'; export * from './src/text-field-column.js'; From 0ae6b24ede16261c90da3337471220631c3ec5b3 Mon Sep 17 00:00:00 2001 From: anna-lach Date: Wed, 11 Sep 2024 08:44:51 +0200 Subject: [PATCH 26/29] filter and filter column changes after review --- .../components/grid/src/filter-column.spec.ts | 1 - packages/components/grid/src/filter.spec.ts | 18 ++++++------------ 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/packages/components/grid/src/filter-column.spec.ts b/packages/components/grid/src/filter-column.spec.ts index fb7940d010..e4d0d34086 100644 --- a/packages/components/grid/src/filter-column.spec.ts +++ b/packages/components/grid/src/filter-column.spec.ts @@ -1,6 +1,5 @@ import { setupIgnoreWindowResizeObserverLoopErrors } from '@lit-labs/virtualizer/support/resize-observer-errors.js'; import { expect, fixture } from '@open-wc/testing'; -// import { Checkbox } from '@sl-design-system/checkbox'; import { html } from 'lit'; import '../register.js'; import { type Grid } from './grid.js'; diff --git a/packages/components/grid/src/filter.spec.ts b/packages/components/grid/src/filter.spec.ts index f42a5665f6..113778d383 100644 --- a/packages/components/grid/src/filter.spec.ts +++ b/packages/components/grid/src/filter.spec.ts @@ -8,6 +8,12 @@ import { GridFilter } from './filter.js'; setupIgnoreWindowResizeObserverLoopErrors(beforeEach, afterEach); describe('sl-grid-filter', () => { + try { + customElements.define('sl-grid-filter', GridFilter); + } catch { + // + } + let el: GridFilter; const column = new GridFilterColumn(); @@ -29,12 +35,6 @@ describe('sl-grid-filter', () => { describe('defaults', () => { beforeEach(async () => { - try { - customElements.define('sl-grid-filter', GridFilter); - } catch { - // - } - column.path = 'membership'; column.value = 'Premium'; await new Promise(resolve => setTimeout(resolve, 200)); @@ -70,12 +70,6 @@ describe('sl-grid-filter', () => { describe('active filter', () => { beforeEach(async () => { - try { - customElements.define('sl-grid-filter', GridFilter); - } catch { - // - } - column.path = 'membership'; column.value = 'Premium'; await new Promise(resolve => setTimeout(resolve, 200)); From b97476a850f98f9e433a5b289f71b4af663a6d7f Mon Sep 17 00:00:00 2001 From: Diana Broeders Date: Thu, 12 Sep 2024 17:08:56 +0200 Subject: [PATCH 27/29] review comments --- packages/components/grid/index.ts | 1 - packages/components/grid/register.ts | 2 -- packages/components/grid/src/column.spec.ts | 10 +++++++--- packages/components/grid/src/sort-column.ts | 4 +++- packages/components/grid/src/sorter.spec.ts | 13 ++++--------- packages/components/grid/src/sorter.ts | 17 +---------------- packages/components/grid/src/view-model.ts | 2 ++ 7 files changed, 17 insertions(+), 32 deletions(-) diff --git a/packages/components/grid/index.ts b/packages/components/grid/index.ts index e35c856691..b4394a5685 100644 --- a/packages/components/grid/index.ts +++ b/packages/components/grid/index.ts @@ -6,5 +6,4 @@ export * from './src/grid.js'; export * from './src/select-column.js'; export * from './src/selection-column.js'; export * from './src/sort-column.js'; -export * from './src/sorter.js'; export * from './src/text-field-column.js'; diff --git a/packages/components/grid/register.ts b/packages/components/grid/register.ts index 9f7a66b0bd..d76e4d251d 100644 --- a/packages/components/grid/register.ts +++ b/packages/components/grid/register.ts @@ -6,7 +6,6 @@ import { Grid } from './src/grid.js'; import { GridSelectColumn } from './src/select-column.js'; import { GridSelectionColumn } from './src/selection-column.js'; import { GridSortColumn } from './src/sort-column.js'; -import { GridSorter } from './src/sorter.js'; import { GridTextFieldColumn } from './src/text-field-column.js'; customElements.define('sl-grid', Grid); @@ -17,5 +16,4 @@ customElements.define('sl-grid-filter-column', GridFilterColumn); customElements.define('sl-grid-select-column', GridSelectColumn); customElements.define('sl-grid-selection-column', GridSelectionColumn); customElements.define('sl-grid-sort-column', GridSortColumn); -customElements.define('sl-grid-sorter', GridSorter); customElements.define('sl-grid-text-field-column', GridTextFieldColumn); diff --git a/packages/components/grid/src/column.spec.ts b/packages/components/grid/src/column.spec.ts index 7c13d41c67..b7bb754f6c 100644 --- a/packages/components/grid/src/column.spec.ts +++ b/packages/components/grid/src/column.spec.ts @@ -1,6 +1,7 @@ import { setupIgnoreWindowResizeObserverLoopErrors } from '@lit-labs/virtualizer/support/resize-observer-errors.js'; import { expect, fixture } from '@open-wc/testing'; import { Avatar } from '@sl-design-system/avatar'; +import '@sl-design-system/avatar/register.js'; import { html } from 'lit'; import { Person } from 'tools/example-data/index.js'; import '../register.js'; @@ -19,7 +20,7 @@ describe('sl-column', () => { - + `); el.items = [ @@ -38,7 +39,7 @@ describe('sl-column', () => { it('should render column headers', () => { const columns = Array.from(el.renderRoot.querySelectorAll('th')).map(col => col.textContent); - expect(columns).to.deep.equal(['First name', 'Last name', 'Age']); + expect(columns).to.deep.equal(['First name', 'Last name', 'Current age']); }); it('should have the right justify-content value', () => { @@ -90,7 +91,10 @@ describe('sl-column', () => { }); it('should render the elements set with the custom renderer', () => { - expect(cells[0]).to.contain('sl-avatar'); + const avatar = cells[0].querySelector('sl-avatar') as Avatar; + + expect(avatar).to.exist; + expect(avatar?.shadowRoot?.querySelector('[part="name"]')?.textContent).to.equal('John Doe'); }); it('should have the right parts, including one set on the column', () => { diff --git a/packages/components/grid/src/sort-column.ts b/packages/components/grid/src/sort-column.ts index 4a7c7e3c7b..b7d6738466 100644 --- a/packages/components/grid/src/sort-column.ts +++ b/packages/components/grid/src/sort-column.ts @@ -1,6 +1,7 @@ import { type DataSourceSortDirection, type DataSourceSortFunction, getNameByPath } from '@sl-design-system/shared'; import { type TemplateResult, html } from 'lit'; import { property } from 'lit/decorators.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; import { GridColumn } from './column.js'; import { GridSorter } from './sorter.js'; @@ -20,6 +21,7 @@ export class GridSortColumn extends GridColumn { /** If you want to provide a custom sort function, you can via this property. */ @property({ attribute: false }) sorter?: DataSourceSortFunction; + /** The direction of the sorting */ @property({ attribute: false }) ariaSorting?: 'ascending' | 'descending'; override connectedCallback(): void { @@ -50,7 +52,7 @@ export class GridSortColumn extends GridColumn { const parts = ['header', 'sort', ...this.getParts()]; return html` - + ${this.header ?? getNameByPath(this.path)} diff --git a/packages/components/grid/src/sorter.spec.ts b/packages/components/grid/src/sorter.spec.ts index b7af68c400..b73737cc2b 100644 --- a/packages/components/grid/src/sorter.spec.ts +++ b/packages/components/grid/src/sorter.spec.ts @@ -8,9 +8,9 @@ import { GridSortColumn } from './sort-column.js'; import { GridSorter } from './sorter.js'; setupIgnoreWindowResizeObserverLoopErrors(beforeEach, afterEach); +customElements.define('sl-grid-sorter', GridSorter); -describe('sl-sort-column', () => { - let wrapper: HTMLElement; +describe('sl-grid-sorter', () => { let el: GridSorter; const items = [{ name: 'John' }, { name: 'Jane' }, { name: 'Jimmy' }, { name: 'Jane' }]; @@ -20,14 +20,9 @@ describe('sl-sort-column', () => { describe('defaults', () => { beforeEach(async () => { - wrapper = await fixture(html` - - - Name - - + el = await fixture(html` + Name `); - el = wrapper.querySelector('sl-grid-sorter')!; await el.updateComplete; // Give grid time to render the table structure diff --git a/packages/components/grid/src/sorter.ts b/packages/components/grid/src/sorter.ts index a3ab04a394..27effd9ed7 100644 --- a/packages/components/grid/src/sorter.ts +++ b/packages/components/grid/src/sorter.ts @@ -7,7 +7,7 @@ import { EventsController, event } from '@sl-design-system/shared'; -import { type CSSResultGroup, LitElement, type PropertyValues, type TemplateResult, html } from 'lit'; +import { type CSSResultGroup, LitElement, type TemplateResult, html } from 'lit'; import { property } from 'lit/decorators.js'; import { choose } from 'lit/directives/choose.js'; import { type GridColumn } from './column.js'; @@ -77,21 +77,6 @@ export class GridSorter extends ScopedElementsMixin(LitElement) { this.sorterChangeEvent.emit('added'); } - override updated(changes: PropertyValues): void { - super.updated(changes); - - // if (changes.has('direction')) { - // //TODO isn't this a bit dangerous? setting attributes of elements OUTSIDE of this component. - // const header = this.closest('th'); - - // if (!this.direction) { - // header?.removeAttribute('aria-sort'); - // } else { - // header?.setAttribute('aria-sort', this.direction === 'asc' ? 'ascending' : 'descending'); - // } - // } - } - override disconnectedCallback(): void { // FIXME: This event is not emitted when the component is removed from the DOM. this.sorterChangeEvent.emit('removed'); diff --git a/packages/components/grid/src/view-model.ts b/packages/components/grid/src/view-model.ts index 83611afc3e..d40747c0e2 100644 --- a/packages/components/grid/src/view-model.ts +++ b/packages/components/grid/src/view-model.ts @@ -199,6 +199,8 @@ export class GridViewModel { const children = groups.reduce((acc: Array>>, cur) => { return [...acc, ...this.#getHeaderRows(cur.columns)]; }, []); + + // when there are columns groups, return the groups and the columns outside groups, otherwise only return the columns return children.length ? [[...groupsNew], [...children.flat(2), ...columnsOutsideGroups]] : [[...columns]]; } } From b6cc3e3545f92d64d8c2a81a0d33008a26630642 Mon Sep 17 00:00:00 2001 From: Diana Broeders Date: Mon, 16 Sep 2024 12:11:58 +0200 Subject: [PATCH 28/29] fixed columns widths in non-grouped columns next to grouped columns --- .../components/grid/src/stories/basics.stories.ts | 2 +- packages/components/grid/src/view-model.ts | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/components/grid/src/stories/basics.stories.ts b/packages/components/grid/src/stories/basics.stories.ts index 611231fd49..f448793e73 100644 --- a/packages/components/grid/src/stories/basics.stories.ts +++ b/packages/components/grid/src/stories/basics.stories.ts @@ -69,7 +69,7 @@ export const ColumnGroups: Story = { - + ` }; diff --git a/packages/components/grid/src/view-model.ts b/packages/components/grid/src/view-model.ts index d40747c0e2..dde338071c 100644 --- a/packages/components/grid/src/view-model.ts +++ b/packages/components/grid/src/view-model.ts @@ -194,8 +194,21 @@ export class GridViewModel { #getHeaderRows(columns: Array>): Array>> { const groups = columns.filter((col): col is GridColumnGroup => col instanceof GridColumnGroup); - const groupsNew = columns.map(col => (col instanceof GridColumnGroup ? col : new GridColumnGroup())); const columnsOutsideGroups = columns.filter((col): col is GridColumn => !(col instanceof GridColumnGroup)); + const groupsNew = columns + .map(col => { + if (col instanceof GridColumnGroup) { + return col; + } + if (!(col.parentElement instanceof GridColumnGroup)) { + const newGroup = new GridColumnGroup(); + // add the column this header group represents to the group in order to calculate the width correctly. + newGroup.columns = [col]; + return newGroup; + } + return null; + }) + .filter(g => !!g); const children = groups.reduce((acc: Array>>, cur) => { return [...acc, ...this.#getHeaderRows(cur.columns)]; }, []); From 4bbe387d336085593592f15eb3ce6475e0732952 Mon Sep 17 00:00:00 2001 From: Diana Broeders Date: Mon, 16 Sep 2024 13:50:14 +0200 Subject: [PATCH 29/29] fix build --- packages/components/grid/src/view-model.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/components/grid/src/view-model.ts b/packages/components/grid/src/view-model.ts index dde338071c..6f1c633452 100644 --- a/packages/components/grid/src/view-model.ts +++ b/packages/components/grid/src/view-model.ts @@ -200,13 +200,12 @@ export class GridViewModel { if (col instanceof GridColumnGroup) { return col; } + const newGroup = new GridColumnGroup(); if (!(col.parentElement instanceof GridColumnGroup)) { - const newGroup = new GridColumnGroup(); // add the column this header group represents to the group in order to calculate the width correctly. - newGroup.columns = [col]; - return newGroup; + newGroup.columns = [col as GridColumnGroup]; } - return null; + return newGroup; }) .filter(g => !!g); const children = groups.reduce((acc: Array>>, cur) => {