diff --git a/tests/playwright/pages/Dashboard/common/Toolbar/Filter.ts b/tests/playwright/pages/Dashboard/common/Toolbar/Filter.ts index 50b8835f11..f9ed740107 100644 --- a/tests/playwright/pages/Dashboard/common/Toolbar/Filter.ts +++ b/tests/playwright/pages/Dashboard/common/Toolbar/Filter.ts @@ -37,6 +37,75 @@ export class ToolbarFilterPage extends BasePage { await this.get().locator(`button:has-text("Add Filter")`).first().click(); } + // can reuse code for addFilterGroup and addFilter + // support for subOperation & datatype specific filter operations not supported yet + async addFilterGroup({ + title, + operation, + _subOperation: _subOperation, + value, + _locallySaved: _locallySaved = false, + _dataType: _dataType, + _openModal: _openModal = false, + _skipWaitingResponse: _skipWaitingResponse = false, // used for undo (single request, less stable) + filterGroupIndex = 0, + filterLogicalOperator = 'AND', + }: { + title: string; + operation: string; + _subOperation?: string; // for date datatype + value?: string; + _locallySaved?: boolean; + _dataType?: string; + _openModal?: boolean; + _skipWaitingResponse?: boolean; + filterGroupIndex?: number; + filterLogicalOperator?: string; + }) { + await this.get().locator(`button:has-text("Add Filter Group")`).last().click(); + const filterDropdown = await this.get().locator('.menu-filter-dropdown').nth(filterGroupIndex); + await filterDropdown.waitFor({ state: 'visible' }); + await filterDropdown.locator(`button:has-text("Add Filter")`).first().click(); + const selectField = await filterDropdown.locator('.nc-filter-field-select').last(); + const selectOperation = await filterDropdown.locator('.nc-filter-operation-select').last(); + const selectValue = await filterDropdown.locator('.nc-filter-value-select > input').last(); + + await selectField.waitFor({ state: 'visible' }); + await selectField.click(); + const fieldDropdown = await this.rootPage + .locator('div.ant-select-dropdown.nc-dropdown-toolbar-field-list') + .last() + .locator(`div[label="${title}"]:visible`); + await fieldDropdown.waitFor({ state: 'visible' }); + await fieldDropdown.click(); + + await selectOperation.waitFor({ state: 'visible' }); + await selectOperation.click(); + const operationDropdown = await this.rootPage + .locator('div.ant-select-dropdown.nc-dropdown-filter-comp-op') + .last() + .locator(`.ant-select-item:has-text("${operation}")`); + await operationDropdown.waitFor({ state: 'visible' }); + await operationDropdown.click(); + + await selectValue.waitFor({ state: 'visible' }); + await selectValue.fill(value); + + if (filterGroupIndex) { + if (filterLogicalOperator === 'OR') { + const logicalButton = await this.rootPage.locator('div.flex.bob').nth(filterGroupIndex - 1); + await logicalButton.waitFor({ state: 'visible' }); + await logicalButton.click(); + + const logicalDropdown = await this.rootPage.locator( + 'div.ant-select-dropdown.nc-dropdown-filter-logical-op-group' + ); + await logicalDropdown.waitFor({ state: 'visible' }); + await logicalDropdown.locator(`.ant-select-item:has-text("${filterLogicalOperator}")`).click(); + } + } + } + async add({ title, operation, @@ -65,7 +134,7 @@ export class ToolbarFilterPage extends BasePage { await this.rootPage.locator('.nc-filter-field-select').last().click(); if (skipWaitingResponse) { - this.rootPage + await this.rootPage .locator('div.ant-select-dropdown.nc-dropdown-toolbar-field-list') .locator(`div[label="${title}"]:visible`) .click(); @@ -88,7 +157,7 @@ export class ToolbarFilterPage extends BasePage { // first() : filter list has >, >= if (skipWaitingResponse) { - this.rootPage + await this.rootPage .locator('.nc-dropdown-filter-comp-op') .locator(`.ant-select-item:has-text("${operation}")`) .first() @@ -117,7 +186,7 @@ export class ToolbarFilterPage extends BasePage { // first() : filter list has >, >= if (skipWaitingResponse) { - this.rootPage + await this.rootPage .locator('.nc-dropdown-filter-comp-sub-op') .locator(`.ant-select-item:has-text("${subOperation}")`) .first() @@ -167,7 +236,7 @@ export class ToolbarFilterPage extends BasePage { await this.rootPage.locator(`.ant-picker-dropdown:visible`); if (skipWaitingResponse) { - this.rootPage.locator(`.ant-picker-cell-inner:has-text("${value}")`).click(); + await this.rootPage.locator(`.ant-picker-cell-inner:has-text("${value}")`).click(); } else { await this.waitForResponse({ uiAction: () => this.rootPage.locator(`.ant-picker-cell-inner:has-text("${value}")`).click(), @@ -188,7 +257,7 @@ export class ToolbarFilterPage extends BasePage { break; case UITypes.Duration: if (skipWaitingResponse) { - this.get().locator('.nc-filter-value-select').locator('input').fill(value); + await this.get().locator('.nc-filter-value-select').locator('input').fill(value); } else { await this.waitForResponse({ uiAction: () => this.get().locator('.nc-filter-value-select').locator('input').fill(value), @@ -298,4 +367,4 @@ export class ToolbarFilterPage extends BasePage { return opListText; } -} \ No newline at end of file +} diff --git a/tests/playwright/tests/db/filters.spec.ts b/tests/playwright/tests/db/filters.spec.ts index 247eaa9210..528fdffd5b 100644 --- a/tests/playwright/tests/db/filters.spec.ts +++ b/tests/playwright/tests/db/filters.spec.ts @@ -1339,3 +1339,52 @@ test.describe('Filter Tests: Toggle button', () => { await dashboard.settings.toggleNullEmptyFilters(); }); }); + +test.describe('Filter Tests: Filter groups', () => { + /** + * Steps + * + * 1. Open table + * 2. Verify filter options : should not include NULL & EMPTY options + * 3. Enable `Show NULL & EMPTY in Filter` in Project Settings + * 4. Verify filter options : should include NULL & EMPTY options + * 5. Add NULL & EMPTY filters + * 6. Disable `Show NULL & EMPTY in Filter` in Project Settings : should not be allowed + * 7. Remove the NULL & EMPTY filters + * 8. Disable `Show NULL & EMPTY in Filter` in Project Settings again : should be allowed + * + */ + + test.beforeEach(async ({ page }) => { + context = await setup({ page, isEmptyProject: false }); + dashboard = new DashboardPage(page, context.project); + toolbar = dashboard.grid.toolbar; + }); + + test('Filter: Empty filters', async () => { + await dashboard.closeTab({ title: 'Team & Auth' }); + await dashboard.treeView.openTable({ title: 'Country', networkResponse: false }); + + await toolbar.clickFilter({ networkValidation: false }); + await toolbar.filter.addFilterGroup({ + title: 'Country', + operation: 'is equal', + value: 'Argentina', + }); + await toolbar.clickFilter({ networkValidation: false }); + + await toolbar.clickFilter({ networkValidation: false }); + await toolbar.filter.addFilterGroup({ + title: 'Country', + operation: 'is equal', + value: 'Indonesia', + filterGroupIndex: 1, + filterLogicalOperator: 'OR', + }); + await toolbar.clickFilter({ networkValidation: false }); + + await validateRowArray({ + rowCount: 2, + }); + }); +});