From b77eb3d5a7e0fe0f6b9f6ccdb10fff30a2578850 Mon Sep 17 00:00:00 2001 From: Raju Udava <86527202+dstala@users.noreply.github.com> Date: Tue, 7 Feb 2023 17:40:49 +0530 Subject: [PATCH] test: single select, multi select Signed-off-by: Raju Udava <86527202+dstala@users.noreply.github.com> --- .../nc-gui/components/cell/MultiSelect.vue | 1 + .../nc-gui/components/cell/SingleSelect.vue | 1 + .../pages/Dashboard/common/Toolbar/Filter.ts | 20 ++- tests/playwright/tests/filters.spec.ts | 152 +++++++++++++++++- 4 files changed, 172 insertions(+), 2 deletions(-) diff --git a/packages/nc-gui/components/cell/MultiSelect.vue b/packages/nc-gui/components/cell/MultiSelect.vue index b7c4538c0e..7bd77a36ef 100644 --- a/packages/nc-gui/components/cell/MultiSelect.vue +++ b/packages/nc-gui/components/cell/MultiSelect.vue @@ -337,6 +337,7 @@ useEventListener(document, 'click', handleClose, true) :key="op.id || op.title" :value="op.title" :data-testid="`select-option-${column.title}-${rowIndex}`" + :class="`nc-select-option-${column.title}-${op.title}`" @click.stop > diff --git a/packages/nc-gui/components/cell/SingleSelect.vue b/packages/nc-gui/components/cell/SingleSelect.vue index 6511f5aa18..3bf447a7c6 100644 --- a/packages/nc-gui/components/cell/SingleSelect.vue +++ b/packages/nc-gui/components/cell/SingleSelect.vue @@ -265,6 +265,7 @@ useEventListener(document, 'click', handleClose, true) :key="op.title" :value="op.title" :data-testid="`select-option-${column.title}-${rowIndex}`" + :class="`nc-select-option-${column.title}-${op.title}`" @click.stop > diff --git a/tests/playwright/pages/Dashboard/common/Toolbar/Filter.ts b/tests/playwright/pages/Dashboard/common/Toolbar/Filter.ts index b82e7f6649..6801fcaafb 100644 --- a/tests/playwright/pages/Dashboard/common/Toolbar/Filter.ts +++ b/tests/playwright/pages/Dashboard/common/Toolbar/Filter.ts @@ -92,11 +92,29 @@ export class ToolbarFilterPage extends BasePage { let fillFilter: any = null; switch (dataType) { case UITypes.Rating: - await this.get('.nc-filter-value-select') + await this.get() .locator('.ant-rate-star > div') .nth(parseInt(value) - 1) .click(); break; + case UITypes.MultiSelect: + await this.get().locator('.nc-filter-value-select').click(); + // eslint-disable-next-line no-case-declarations + const v = value.split(','); + for (let i = 0; i < v.length; i++) { + await this.rootPage + .locator(`.nc-dropdown-multi-select-cell`) + .locator(`.nc-select-option-MultiSelect-${v[i]}`) + .click(); + } + break; + case UITypes.SingleSelect: + await this.get().locator('.nc-filter-value-select').click(); + await this.rootPage + .locator(`.nc-dropdown-single-select-cell`) + .locator(`.nc-select-option-SingleSelect-${value}`) + .click(); + break; default: fillFilter = this.rootPage.locator('.nc-filter-value-select > input').last().fill(value); await this.waitForResponse({ diff --git a/tests/playwright/tests/filters.spec.ts b/tests/playwright/tests/filters.spec.ts index af98aed403..049aad49a2 100644 --- a/tests/playwright/tests/filters.spec.ts +++ b/tests/playwright/tests/filters.spec.ts @@ -22,7 +22,14 @@ const skipList = { Email: ['is blank', 'is not blank'], PhoneNumber: ['is blank', 'is not blank'], URL: ['is blank', 'is not blank'], - SingleSelect: ['is blank', 'is not blank', 'contains all of', 'does not contain all of'], + SingleSelect: [ + 'is blank', + 'is not blank', + 'contains all of', + 'does not contain all of', + 'contains any of', + 'does not contain any of', + ], MultiSelect: ['is blank', 'is not blank', 'is', 'is not'], }; @@ -75,6 +82,9 @@ async function verifyFilter(param: { await toolbar.filter.reset(); } +// Number based filters +// + test.describe('Filter Tests: Numerical', () => { async function numBasedFilterTest(dataType, eqString, isLikeString) { await dashboard.closeTab({ title: 'Team & Auth' }); @@ -407,3 +417,143 @@ test.describe('Filter Tests: Text based', () => { await textBasedFilterTest('URL', 'https://www.youtube.com', 'e.com'); }); }); + +// Select Based +// + +test.describe('Filter Tests: Select based', () => { + async function selectBasedFilterTest(dataType, is, anyof, allof) { + await dashboard.closeTab({ title: 'Team & Auth' }); + await dashboard.treeView.openTable({ title: 'selectBased' }); + + const filterList = [ + { + op: 'is', + value: is, + rowCount: records.list.filter(r => r[dataType] === is).length, + }, + { + op: 'is not', + value: is, + rowCount: records.list.filter(r => r[dataType] !== is).length, + }, + { + op: 'contains any of', + value: anyof, + rowCount: records.list.filter(r => { + const values = anyof.split(','); + const recordValue = r[dataType]?.split(','); + return values.some(value => recordValue?.includes(value)); + }).length, + }, + { + op: 'contains all of', + value: allof, + rowCount: records.list.filter(r => { + const values = allof.split(','); + return values.every(value => r[dataType]?.includes(value)); + }).length, + }, + { + op: 'does not contain any of', + value: anyof, + rowCount: records.list.filter(r => { + const values = anyof.split(','); + const recordValue = r[dataType]?.split(','); + return !values.some(value => recordValue?.includes(value)); + }).length, + }, + { + op: 'does not contain all of', + value: allof, + rowCount: records.list.filter(r => { + const values = allof.split(','); + return !values.every(value => r[dataType]?.includes(value)); + }).length, + }, + { + op: 'is blank', + value: '', + rowCount: records.list.filter(r => r[dataType] === '' || r[dataType] === null).length, + }, + { + op: 'is not blank', + value: '', + rowCount: records.list.filter(r => r[dataType] !== '' && r[dataType] !== null).length, + }, + ]; + + for (let i = 0; i < filterList.length; i++) { + await verifyFilter({ + column: dataType, + opType: filterList[i].op, + value: filterList[i].value, + result: { rowCount: filterList[i].rowCount }, + dataType: dataType, + }); + } + } + test.beforeEach(async ({ page }) => { + context = await setup({ page }); + dashboard = new DashboardPage(page, context.project); + toolbar = dashboard.grid.toolbar; + + api = new Api({ + baseURL: `http://localhost:8080/`, + headers: { + 'xc-auth': context.token, + }, + }); + + const columns = [ + { + column_name: 'Id', + title: 'Id', + uidt: UITypes.ID, + }, + { + column_name: 'SingleSelect', + title: 'SingleSelect', + uidt: UITypes.SingleSelect, + dtxp: "'jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec'", + }, + { + column_name: 'MultiSelect', + title: 'MultiSelect', + uidt: UITypes.MultiSelect, + dtxp: "'jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec'", + }, + ]; + + try { + const project = await api.project.read(context.project.id); + const table = await api.base.tableCreate(context.project.id, project.bases?.[0].id, { + table_name: 'selectBased', + title: 'selectBased', + columns: columns, + }); + + const rowAttributes = []; + for (let i = 0; i < 400; i++) { + const row = { + SingleSelect: rowMixedValue(columns[1], i), + MultiSelect: rowMixedValue(columns[2], i), + }; + rowAttributes.push(row); + } + + await api.dbTableRow.bulkCreate('noco', context.project.id, table.id, rowAttributes); + records = await api.dbTableRow.list('noco', context.project.id, table.id, { limit: 400 }); + } catch (e) { + console.error(e); + } + }); + + test('Filter: Single Select', async () => { + await selectBasedFilterTest('SingleSelect', 'jan', 'jan,feb,mar', ''); + }); + + test('Filter: Multi Select', async () => { + await selectBasedFilterTest('MultiSelect', '', 'jan,feb,mar', 'jan,feb,mar'); + }); +});