diff --git a/packages/nc-gui/components/virtual-cell/components/ItemChip.vue b/packages/nc-gui/components/virtual-cell/components/ItemChip.vue index 1202bd19a3..ebe49c6b16 100644 --- a/packages/nc-gui/components/virtual-cell/components/ItemChip.vue +++ b/packages/nc-gui/components/virtual-cell/components/ItemChip.vue @@ -65,7 +65,7 @@ export default {
diff --git a/tests/playwright/pages/Account/Users.ts b/tests/playwright/pages/Account/Users.ts index 1618c98b6e..9b6bbdd854 100644 --- a/tests/playwright/pages/Account/Users.ts +++ b/tests/playwright/pages/Account/Users.ts @@ -36,7 +36,8 @@ export class AccountUsersPage extends BasePage { await this.inviteUserModal.locator(`button:has-text("Invite")`).click(); await this.verifyToast({ message: 'Successfully added user' }); - return await this.inviteUserModal.locator(`.ant-alert-message`).innerText(); + // http://localhost:3000/#/signup/a5e7bf3a-cbb0-46bc-87f7-c2ae21796707 + return (await this.inviteUserModal.locator(`.ant-alert-message`).innerText()).slice(0, 67); } prefixEmail(email: string) { diff --git a/tests/playwright/pages/Dashboard/Grid/Column/SelectOptionColumn.ts b/tests/playwright/pages/Dashboard/Grid/Column/SelectOptionColumn.ts index a05fcd166b..5d1d63e995 100644 --- a/tests/playwright/pages/Dashboard/Grid/Column/SelectOptionColumn.ts +++ b/tests/playwright/pages/Dashboard/Grid/Column/SelectOptionColumn.ts @@ -60,7 +60,7 @@ export class SelectOptionColumnPageObject extends BasePage { async deleteOption({ columnTitle, index }: { index: number; columnTitle: string }) { await this.column.openEdit({ title: columnTitle }); - await this.column.get().locator(`svg[data-testid="select-column-option-remove-${index}"]`).click(); + await this.column.get().locator(`[data-testid="select-column-option-remove-${index}"]`).click(); await expect(this.column.get().getByTestId(`select-column-option-${index}`)).toHaveClass(/removed/); @@ -70,11 +70,11 @@ export class SelectOptionColumnPageObject extends BasePage { async deleteOptionWithUndo({ columnTitle, index }: { index: number; columnTitle: string }) { await this.column.openEdit({ title: columnTitle }); - await this.column.get().locator(`svg[data-testid="select-column-option-remove-${index}"]`).click(); + await this.column.get().locator(`[data-testid="select-column-option-remove-${index}"]`).click(); await expect(this.column.get().getByTestId(`select-column-option-${index}`)).toHaveClass(/removed/); - await this.column.get().locator(`svg[data-testid="select-column-option-remove-undo-${index}"]`).click(); + await this.column.get().locator(`[data-testid="select-column-option-remove-undo-${index}"]`).click(); await expect(this.column.get().getByTestId(`select-column-option-${index}`)).not.toHaveClass(/removed/); @@ -95,8 +95,8 @@ export class SelectOptionColumnPageObject extends BasePage { await this.column.rootPage.waitForTimeout(150); await this.column.rootPage.dragAndDrop( - `svg[data-testid="select-option-column-handle-icon-${sourceOption}"]`, - `svg[data-testid="select-option-column-handle-icon-${destinationOption}"]`, + `[data-testid="select-option-column-handle-icon-${sourceOption}"]`, + `[data-testid="select-option-column-handle-icon-${destinationOption}"]`, { force: true, } diff --git a/tests/playwright/pages/Dashboard/Grid/Column/index.ts b/tests/playwright/pages/Dashboard/Grid/Column/index.ts index 9c902566bc..3ca90f1f5d 100644 --- a/tests/playwright/pages/Dashboard/Grid/Column/index.ts +++ b/tests/playwright/pages/Dashboard/Grid/Column/index.ts @@ -3,6 +3,7 @@ import { GridPage } from '..'; import BasePage from '../../../Base'; import { SelectOptionColumnPageObject } from './SelectOptionColumn'; import { AttachmentColumnPageObject } from './Attachment'; +import { getTextExcludeIconText } from '../../../../tests/utils/general'; export class ColumnPageObject extends BasePage { readonly grid: GridPage; @@ -181,28 +182,23 @@ export class ColumnPageObject extends BasePage { await this.save(); + const headersText = []; + const locator = this.grid.get().locator(`th`); + const count = await locator.count(); + for (let i = 0; i < count; i++) { + const header = locator.nth(i); + const text = await getTextExcludeIconText(header); + headersText.push(text); + } + // verify column inserted after the target column if (insertAfterColumnTitle) { - const headersText = await this.grid.get().locator(`th`).allTextContents(); - - await expect( - this.grid - .get() - .locator(`th`) - .nth(headersText.findIndex(title => title.startsWith(insertAfterColumnTitle)) + 1) - ).toHaveText(title); + expect(headersText[headersText.findIndex(title => title.startsWith(insertAfterColumnTitle)) + 1]).toBe(title); } // verify column inserted before the target column if (insertBeforeColumnTitle) { - const headersText = await this.grid.get().locator(`th`).allTextContents(); - - await expect( - this.grid - .get() - .locator(`th`) - .nth(headersText.findIndex(title => title.startsWith(insertBeforeColumnTitle)) - 1) - ).toHaveText(title); + expect(headersText[headersText.findIndex(title => title.startsWith(insertBeforeColumnTitle)) - 1]).toBe(title); } } @@ -254,7 +250,7 @@ export class ColumnPageObject extends BasePage { } async delete({ title }: { title: string }) { - await this.getColumnHeader(title).locator('svg.ant-dropdown-trigger').click(); + await this.getColumnHeader(title).locator('div.ant-dropdown-trigger').locator('.nc-ui-dt-dropdown').click(); // await this.rootPage.locator('li[role="menuitem"]:has-text("Delete")').waitFor(); await this.rootPage.locator('li[role="menuitem"]:has-text("Delete")').click(); diff --git a/tests/playwright/pages/Dashboard/Import/ImportTemplate.ts b/tests/playwright/pages/Dashboard/Import/ImportTemplate.ts index 9db97b3318..bc9afbfb4f 100644 --- a/tests/playwright/pages/Dashboard/Import/ImportTemplate.ts +++ b/tests/playwright/pages/Dashboard/Import/ImportTemplate.ts @@ -1,6 +1,7 @@ import { expect, Locator } from '@playwright/test'; import BasePage from '../../Base'; import { DashboardPage } from '..'; +import { getTextExcludeIconText } from '../../../tests/utils/general'; export class ImportTemplatePage extends BasePage { readonly dashboard: DashboardPage; @@ -22,7 +23,7 @@ export class ImportTemplatePage extends BasePage { const rowCount = await tr.count(); const tableList: string[] = []; for (let i = 0; i < rowCount; i++) { - const tableName = await tr.nth(i).innerText(); + const tableName = await getTextExcludeIconText(tr.nth(i)); tableList.push(tableName); } return tableList; @@ -35,10 +36,7 @@ export class ImportTemplatePage extends BasePage { const rowCount = await tr.count(); for (let i = 0; i < rowCount; i++) { // replace \n and \t from innerText - const columnType = await tr - .nth(i) - .innerText() - .then(text => text.replace(/\n|\t/g, '')); + const columnType = (await getTextExcludeIconText(tr.nth(i))).replace(/\n|\t/g, ''); const columnName = await tr.nth(i).locator(`input[type="text"]`).inputValue(); columnList.push({ type: columnType, name: columnName }); } diff --git a/tests/playwright/pages/Dashboard/Settings/Metadata.ts b/tests/playwright/pages/Dashboard/Settings/Metadata.ts index 803e6dfb65..b93c629a1d 100644 --- a/tests/playwright/pages/Dashboard/Settings/Metadata.ts +++ b/tests/playwright/pages/Dashboard/Settings/Metadata.ts @@ -1,6 +1,7 @@ import { expect } from '@playwright/test'; import BasePage from '../../Base'; import { DataSourcesPage } from './DataSources'; +import { getTextExcludeIconText } from '../../../tests/utils/general'; export class MetaDataPage extends BasePage { private readonly dataSources: DataSourcesPage; @@ -31,12 +32,10 @@ export class MetaDataPage extends BasePage { } async verifyRow({ index, model, state }: { index: number; model: string; state: string }) { - await expect(this.get().locator(`tr.ant-table-row`).nth(index).locator(`td.ant-table-cell`).nth(0)).toHaveText( - model, - { - ignoreCase: true, - } - ); + const fieldLocator = await this.get().locator(`tr.ant-table-row`).nth(index).locator(`td.ant-table-cell`).nth(0); + const fieldText = await getTextExcludeIconText(fieldLocator); + await expect(fieldText).toBe(model); + await expect(this.get().locator(`tr.ant-table-row`).nth(index).locator(`td.ant-table-cell`).nth(1)).toHaveText( state, { diff --git a/tests/playwright/pages/Dashboard/Settings/Teams.ts b/tests/playwright/pages/Dashboard/Settings/Teams.ts index 0bc59edaef..34bf61a5c3 100644 --- a/tests/playwright/pages/Dashboard/Settings/Teams.ts +++ b/tests/playwright/pages/Dashboard/Settings/Teams.ts @@ -44,7 +44,8 @@ export class TeamsPage extends BasePage { await this.inviteTeamModal.locator(`button:has-text("Invite")`).click(); await this.verifyToast({ message: 'Successfully updated the user details' }); - return await this.inviteTeamModal.locator(`.ant-alert-message`).innerText(); + // http://localhost:3000/#/signup/a5e7bf3a-cbb0-46bc-87f7-c2ae21796707 + return (await this.inviteTeamModal.locator(`.ant-alert-message`).innerText()).slice(0, 67); } async closeInvite() { diff --git a/tests/playwright/pages/Dashboard/SurveyForm/index.ts b/tests/playwright/pages/Dashboard/SurveyForm/index.ts index 5e1067ecf2..87d3b8d789 100644 --- a/tests/playwright/pages/Dashboard/SurveyForm/index.ts +++ b/tests/playwright/pages/Dashboard/SurveyForm/index.ts @@ -1,5 +1,6 @@ import { expect, Locator, Page } from '@playwright/test'; import BasePage from '../../Base'; +import { getTextExcludeIconText } from '../../../tests/utils/general'; export class SurveyFormPage extends BasePage { readonly formHeading: Locator; @@ -42,7 +43,15 @@ export class SurveyFormPage extends BasePage { await expect(this.formHeading).toHaveText(heading); await expect(this.formSubHeading).toHaveText(subHeading); await expect(this.formFooter).toHaveText(footer); - await expect(this.get().locator(`[data-testid="nc-form-column-label"]`)).toHaveText(fieldLabel); + + const locator = this.get().locator(`[data-testid="nc-form-column-label"]`); + let fieldText = await getTextExcludeIconText(locator); + + // replace whitespace with ' ' for fieldLabel & fieldText + fieldLabel = fieldLabel.replace(/\u00A0/g, ' '); + fieldText = fieldText.replace(/\u00A0/g, ' '); + + await expect(fieldText).toBe(fieldLabel); // parse footer text ("1 / 3") to identify if last slide let isLastSlide = false; @@ -73,6 +82,9 @@ export class SurveyFormPage extends BasePage { await modal.locator('.ant-picker-ok').click(); await this.nextButton.click(); } + + // post next button click, allow transitions to complete + await this.rootPage.waitForTimeout(100); } async validateSuccessMessage(param: { message: string; showAnotherForm?: boolean }) { diff --git a/tests/playwright/pages/Dashboard/TreeView.ts b/tests/playwright/pages/Dashboard/TreeView.ts index 7caa2d0f3d..9cc622b461 100644 --- a/tests/playwright/pages/Dashboard/TreeView.ts +++ b/tests/playwright/pages/Dashboard/TreeView.ts @@ -39,7 +39,7 @@ export class TreeViewPage extends BasePage { async openTable({ title, mode = 'standard', - networkResponse = true, + networkResponse = false, mobileMode = false, }: { title: string; diff --git a/tests/playwright/pages/Dashboard/ViewSidebar/index.ts b/tests/playwright/pages/Dashboard/ViewSidebar/index.ts index 0823c8763d..4cc1f9e445 100644 --- a/tests/playwright/pages/Dashboard/ViewSidebar/index.ts +++ b/tests/playwright/pages/Dashboard/ViewSidebar/index.ts @@ -86,6 +86,13 @@ export class ViewSidebarPage extends BasePage { // Todo: Make selection better async verifyView({ title, index }: { title: string; index: number }) { + // flicker while page loading + await this.get() + .locator('[data-testid="view-item"]') + .nth(index) + .locator('[data-testid="truncate-label"]') + .waitFor({ state: 'visible' }); + await expect( this.get().locator('[data-testid="view-item"]').nth(index).locator('[data-testid="truncate-label"]') ).toHaveText(title, { ignoreCase: true }); diff --git a/tests/playwright/pages/Dashboard/WebhookForm/index.ts b/tests/playwright/pages/Dashboard/WebhookForm/index.ts index 2a1aea22fa..3a203fe1b6 100644 --- a/tests/playwright/pages/Dashboard/WebhookForm/index.ts +++ b/tests/playwright/pages/Dashboard/WebhookForm/index.ts @@ -2,6 +2,7 @@ import { expect, Locator } from '@playwright/test'; import BasePage from '../../Base'; import { DashboardPage } from '..'; import { ToolbarPage } from '../common/Toolbar'; +import { getTextExcludeIconText } from '../../../tests/utils/general'; export class WebhookFormPage extends BasePage { readonly dashboard: DashboardPage; @@ -181,9 +182,11 @@ export class WebhookFormPage extends BasePage { }) { await expect.poll(async () => await this.get().locator('input.nc-text-field-hook-title').inputValue()).toBe(title); await expect(this.get().locator('.nc-text-field-hook-event >> .ant-select-selection-item')).toHaveText(hookEvent); - await expect(this.get().locator('.nc-select-hook-notification-type >> .ant-select-selection-item')).toHaveText( - notificationType - ); + + const locator = this.get().locator('.nc-select-hook-notification-type >> .ant-select-selection-item'); + const text = await getTextExcludeIconText(locator); + await expect(text).toBe(notificationType); + await expect(this.get().locator('.nc-select-hook-url-method >> .ant-select-selection-item')).toHaveText(urlMethod); await expect.poll(async () => await this.get().locator('input.nc-text-field-hook-url-path').inputValue()).toBe(url); diff --git a/tests/playwright/pages/Dashboard/common/Cell/index.ts b/tests/playwright/pages/Dashboard/common/Cell/index.ts index 23f9b0d0b1..0f95fc607b 100644 --- a/tests/playwright/pages/Dashboard/common/Cell/index.ts +++ b/tests/playwright/pages/Dashboard/common/Cell/index.ts @@ -273,7 +273,7 @@ export class CellPageObject extends BasePage { // verify only the elements that are passed in for (let i = 0; i < value.length; ++i) { - await expect(await chips.nth(i)).toHaveText(value[i]); + await expect(await chips.nth(i).locator('.name')).toHaveText(value[i]); } } @@ -292,6 +292,7 @@ export class CellPageObject extends BasePage { // press escape to close the input await cell.press('Escape'); + await cell.press('Escape'); await cell.click({ button: 'right', clickCount: 1 }); await expect(await this.rootPage.locator(`.nc-dropdown-grid-context-menu:visible`)).toHaveCount( diff --git a/tests/playwright/pages/Dashboard/common/Toolbar/Actions/index.ts b/tests/playwright/pages/Dashboard/common/Toolbar/Actions/index.ts index 86b093cdef..a9286d0d65 100644 --- a/tests/playwright/pages/Dashboard/common/Toolbar/Actions/index.ts +++ b/tests/playwright/pages/Dashboard/common/Toolbar/Actions/index.ts @@ -18,10 +18,10 @@ export class ToolbarActionsPage extends BasePage { // todo: use enum async click(label: string) { - await this.get().locator(`span:has-text("${label}")`).click(); + await this.get().locator(`span:has-text("${label}")`).first().click(); } async clickDownloadSubmenu(label: string) { - await this.rootPage.locator(`div[class="nc-project-menu-item"]:has-text("${label}")`).click(); + await this.rootPage.locator(`div[class="nc-project-menu-item"]:has-text("${label}")`).first().click(); } } diff --git a/tests/playwright/pages/Dashboard/common/Toolbar/Filter.ts b/tests/playwright/pages/Dashboard/common/Toolbar/Filter.ts index ee69da6728..285898a0e5 100644 --- a/tests/playwright/pages/Dashboard/common/Toolbar/Filter.ts +++ b/tests/playwright/pages/Dashboard/common/Toolbar/Filter.ts @@ -2,6 +2,7 @@ import { expect } from '@playwright/test'; import BasePage from '../../../Base'; import { ToolbarPage } from './index'; import { UITypes } from 'nocodb-sdk'; +import { getTextExcludeIconText } from '../../../../tests/utils/general'; export class ToolbarFilterPage extends BasePage { readonly toolbar: ToolbarPage; @@ -16,7 +17,10 @@ export class ToolbarFilterPage extends BasePage { } async verify({ index, column, operator, value }: { index: number; column: string; operator: string; value: string }) { - await expect(this.get().locator('.nc-filter-field-select').nth(index)).toHaveText(column); + const fieldLocator = await this.get().locator('.nc-filter-field-select').nth(index); + const fieldText = await getTextExcludeIconText(fieldLocator); + await expect(fieldText).toBe(column); + await expect(this.get().locator('.nc-filter-operation-select').nth(index)).toHaveText(operator); await expect .poll(async () => await this.get().locator('.nc-filter-value-select > input').nth(index).inputValue()) diff --git a/tests/playwright/pages/Dashboard/common/Toolbar/ShareView.ts b/tests/playwright/pages/Dashboard/common/Toolbar/ShareView.ts index d28de9a9c3..816d0e6538 100644 --- a/tests/playwright/pages/Dashboard/common/Toolbar/ShareView.ts +++ b/tests/playwright/pages/Dashboard/common/Toolbar/ShareView.ts @@ -1,5 +1,6 @@ import BasePage from '../../../Base'; import { ToolbarPage } from './index'; +import { getTextExcludeIconText } from '../../../../tests/utils/general'; export class ToolbarShareViewPage extends BasePage { readonly toolbar: ToolbarPage; @@ -29,7 +30,9 @@ export class ToolbarShareViewPage extends BasePage { } async getShareLink() { - return await this.get().locator(`[data-testid="nc-modal-share-view__link"]`).innerText(); + const locator = this.get().locator(`[data-testid="nc-modal-share-view__link"]`); + const linkText = getTextExcludeIconText(locator); + return linkText; } async close() { diff --git a/tests/playwright/pages/Dashboard/common/Toolbar/Sort.ts b/tests/playwright/pages/Dashboard/common/Toolbar/Sort.ts index 7da27ba7fe..d006d46818 100644 --- a/tests/playwright/pages/Dashboard/common/Toolbar/Sort.ts +++ b/tests/playwright/pages/Dashboard/common/Toolbar/Sort.ts @@ -1,6 +1,7 @@ import { expect } from '@playwright/test'; import BasePage from '../../../Base'; import { ToolbarPage } from './index'; +import { getTextExcludeIconText } from '../../../../tests/utils/general'; export class ToolbarSortPage extends BasePage { readonly toolbar: ToolbarPage; @@ -15,7 +16,10 @@ export class ToolbarSortPage extends BasePage { } async verify({ index, column, direction }: { index: number; column: string; direction: string }) { - await expect(this.get().locator('.nc-sort-field-select').nth(index)).toHaveText(column); + const fieldLocator = await this.get().locator('.nc-sort-field-select').nth(index); + const fieldText = await getTextExcludeIconText(fieldLocator); + await expect(fieldText).toBe(column); + await expect( await this.get().locator('.nc-sort-dir-select >> span.ant-select-selection-item').nth(index) ).toHaveText(direction); diff --git a/tests/playwright/pages/Dashboard/common/Toolbar/ViewMenu.ts b/tests/playwright/pages/Dashboard/common/Toolbar/ViewMenu.ts index 508e958be9..071685c6fe 100644 --- a/tests/playwright/pages/Dashboard/common/Toolbar/ViewMenu.ts +++ b/tests/playwright/pages/Dashboard/common/Toolbar/ViewMenu.ts @@ -141,7 +141,7 @@ export class ToolbarViewMenuPage extends BasePage { await expect(await this.toolbar.get().locator(`.nc-filter-menu-btn.nc-toolbar-btn`)).toBeDisabled(); await expect(await this.toolbar.get().locator(`.nc-sort-menu-btn.nc-toolbar-btn`)).toBeDisabled(); await expect( - await this.toolbar.get().locator(`.nc-add-new-row-btn.nc-toolbar-btn > .nc-icon.disabled`) + await this.toolbar.get().locator(`.nc-add-new-row-btn.nc-toolbar-btn > .material-symbols-outlined.disabled`) ).toBeVisible(); await (this.toolbar.parent as GridPage).verifyEditDisabled({ @@ -153,7 +153,9 @@ export class ToolbarViewMenuPage extends BasePage { await expect(await this.toolbar.get().locator(`.nc-fields-menu-btn.nc-toolbar-btn`)).toBeEnabled(); await expect(await this.toolbar.get().locator(`.nc-filter-menu-btn.nc-toolbar-btn`)).toBeEnabled(); await expect(await this.toolbar.get().locator(`.nc-sort-menu-btn.nc-toolbar-btn`)).toBeEnabled(); - await expect(await this.toolbar.get().locator(`.nc-add-new-row-btn.nc-toolbar-btn > .nc-icon`)).toBeVisible(); + await expect( + await this.toolbar.get().locator(`.nc-add-new-row-btn.nc-toolbar-btn > .material-symbols-outlined`) + ).toBeVisible(); await (this.toolbar.parent as GridPage).verifyEditEnabled({ columnHeader: 'Country', diff --git a/tests/playwright/pages/Dashboard/common/Toolbar/index.ts b/tests/playwright/pages/Dashboard/common/Toolbar/index.ts index 99f79e4364..6f756f21f1 100644 --- a/tests/playwright/pages/Dashboard/common/Toolbar/index.ts +++ b/tests/playwright/pages/Dashboard/common/Toolbar/index.ts @@ -16,6 +16,7 @@ import { ToolbarAddEditStackPage } from './AddEditKanbanStack'; import { ToolbarSearchDataPage } from './SearchData'; import { RowHeight } from './RowHeight'; import { MapPage } from '../../Map'; +import { getTextExcludeIconText } from '../../../../tests/utils/general'; export class ToolbarPage extends BasePage { readonly parent: GridPage | GalleryPage | FormPage | KanbanPage | MapPage; @@ -82,14 +83,26 @@ export class ToolbarPage extends BasePage { async verifyFieldsButtonIsVisibleWithTextAndIcon() { await expect(this.get().locator(`button.nc-fields-menu-btn`)).toBeVisible(); - await expect(this.get().locator(`button.nc-fields-menu-btn`)).toHaveText('Fields'); - expect(await this.get().locator(`button.nc-fields-menu-btn`).locator(`svg`).count()).toBe(2); + + // menu text + const fieldLocator = await this.get().locator(`button.nc-fields-menu-btn`); + const fieldText = await getTextExcludeIconText(fieldLocator); + await expect(fieldText).toBe('Fields'); + + // icons count within fields menu button + expect(await this.get().locator(`button.nc-fields-menu-btn`).locator(`.material-symbols-outlined`).count()).toBe(2); } async verifyFieldsButtonIsVisibleWithoutTextButIcon() { await expect(this.get().locator(`button.nc-fields-menu-btn`)).toBeVisible(); - await expect(this.get().locator(`button.nc-fields-menu-btn`)).not.toHaveText('Fields'); - expect(await this.get().locator(`button.nc-fields-menu-btn`).locator(`svg`).count()).toBe(2); + + // menu text + const fieldLocator = await this.get().locator(`button.nc-fields-menu-btn`); + const fieldText = await getTextExcludeIconText(fieldLocator); + await expect(fieldText).not.toBe('Fields'); + + // icons count within fields menu button + expect(await this.get().locator(`button.nc-fields-menu-btn`).locator(`.material-symbols-outlined`).count()).toBe(2); } async clickFilter({ diff --git a/tests/playwright/tests/columnLinkToAnotherRecord.spec.ts b/tests/playwright/tests/columnLinkToAnotherRecord.spec.ts index 1b7f53c999..dd74bf0fd4 100644 --- a/tests/playwright/tests/columnLinkToAnotherRecord.spec.ts +++ b/tests/playwright/tests/columnLinkToAnotherRecord.spec.ts @@ -43,7 +43,7 @@ test.describe('LTAR create & update', () => { }); await dashboard.closeTab({ title: 'Sheet1' }); - await dashboard.treeView.openTable({ title: 'Sheet2' }); + await dashboard.treeView.openTable({ title: 'Sheet2', networkResponse: false }); await dashboard.grid.column.create({ title: 'Link2-1hm', type: 'LinkToAnotherRecord', @@ -116,6 +116,9 @@ test.describe('LTAR create & update', () => { value: '2c', type: 'text', }); + + await dashboard.rootPage.waitForTimeout(1000); + await dashboard.expandedForm.save(); const expected = [ diff --git a/tests/playwright/tests/columnMenuOperations.spec.ts b/tests/playwright/tests/columnMenuOperations.spec.ts index 01a4e016bf..429d9cf5d7 100644 --- a/tests/playwright/tests/columnMenuOperations.spec.ts +++ b/tests/playwright/tests/columnMenuOperations.spec.ts @@ -66,6 +66,7 @@ test.describe('Column menu operations', () => { } await dashboard.closeTab({ title: 'Film' }); }); + test('Insert after', async () => { await dashboard.treeView.openTable({ title: 'Film' }); diff --git a/tests/playwright/tests/filters.spec.ts b/tests/playwright/tests/filters.spec.ts index 2bc6b30f64..95d29c5e4b 100644 --- a/tests/playwright/tests/filters.spec.ts +++ b/tests/playwright/tests/filters.spec.ts @@ -668,7 +668,7 @@ test.describe('Filter Tests: Date based', () => { const oneYearAgo = new Date(new Date().setFullYear(new Date().getFullYear() - 1)).setHours(0, 0, 0, 0); const oneYearFromNow = new Date(new Date().setFullYear(new Date().getFullYear() + 1)).setHours(0, 0, 0, 0); - async function dateTimeBasedFilterTest(dataType) { + async function dateTimeBasedFilterTest(dataType, setCount) { await dashboard.closeTab({ title: 'Team & Auth' }); await dashboard.treeView.openTable({ title: 'dateTimeBased' }); @@ -829,100 +829,102 @@ test.describe('Filter Tests: Date based', () => { await toolbar.clickFilter(); await toolbar.filter.clickAddFilter(); - // "is" filter list - for (let i = 0; i < isFilterList.length; i++) { - await verifyFilter_withFixedModal({ - column: dataType, - opType: 'is', - opSubType: isFilterList[i].opSub, - value: isFilterList[i]?.value?.toString() || '', - result: { rowCount: isFilterList[i].rowCount }, - dataType: dataType, - }); - } - - // mutually exclusive of "is" filter list - for (let i = 0; i < isFilterList.length; i++) { - await verifyFilter_withFixedModal({ - column: dataType, - opType: 'is not', - opSubType: isFilterList[i].opSub, - value: isFilterList[i]?.value?.toString() || '', - result: { rowCount: 800 - isFilterList[i].rowCount }, - dataType: dataType, - }); - } + if (setCount === 0) { + // "is" filter list + for (let i = 0; i < isFilterList.length; i++) { + await verifyFilter_withFixedModal({ + column: dataType, + opType: 'is', + opSubType: isFilterList[i].opSub, + value: isFilterList[i]?.value?.toString() || '', + result: { rowCount: isFilterList[i].rowCount }, + dataType: dataType, + }); + } - // "is before" filter list - for (let i = 0; i < isAfterFilterList.length; i++) { - await verifyFilter_withFixedModal({ - column: dataType, - opType: 'is before', - opSubType: isAfterFilterList[i].opSub, - value: isAfterFilterList[i]?.value?.toString() || '', - result: { rowCount: 800 - isAfterFilterList[i].rowCount - 1 }, - dataType: dataType, - }); - } + // mutually exclusive of "is" filter list + for (let i = 0; i < isFilterList.length; i++) { + await verifyFilter_withFixedModal({ + column: dataType, + opType: 'is not', + opSubType: isFilterList[i].opSub, + value: isFilterList[i]?.value?.toString() || '', + result: { rowCount: 800 - isFilterList[i].rowCount }, + dataType: dataType, + }); + } - // "is on or before" filter list - for (let i = 0; i < isAfterFilterList.length; i++) { - await verifyFilter_withFixedModal({ - column: dataType, - opType: 'is on or before', - opSubType: isAfterFilterList[i].opSub, - value: isAfterFilterList[i]?.value?.toString() || '', - result: { rowCount: 800 - isAfterFilterList[i].rowCount }, - dataType: dataType, - }); - } + // "is before" filter list + for (let i = 0; i < isAfterFilterList.length; i++) { + await verifyFilter_withFixedModal({ + column: dataType, + opType: 'is before', + opSubType: isAfterFilterList[i].opSub, + value: isAfterFilterList[i]?.value?.toString() || '', + result: { rowCount: 800 - isAfterFilterList[i].rowCount - 1 }, + dataType: dataType, + }); + } + } else { + // "is on or before" filter list + for (let i = 0; i < isAfterFilterList.length; i++) { + await verifyFilter_withFixedModal({ + column: dataType, + opType: 'is on or before', + opSubType: isAfterFilterList[i].opSub, + value: isAfterFilterList[i]?.value?.toString() || '', + result: { rowCount: 800 - isAfterFilterList[i].rowCount }, + dataType: dataType, + }); + } - // "is after" filter list - for (let i = 0; i < isAfterFilterList.length; i++) { - await verifyFilter_withFixedModal({ - column: dataType, - opType: 'is after', - opSubType: isAfterFilterList[i].opSub, - value: isAfterFilterList[i]?.value?.toString() || '', - result: { rowCount: isAfterFilterList[i].rowCount }, - dataType: dataType, - }); - } + // "is after" filter list + for (let i = 0; i < isAfterFilterList.length; i++) { + await verifyFilter_withFixedModal({ + column: dataType, + opType: 'is after', + opSubType: isAfterFilterList[i].opSub, + value: isAfterFilterList[i]?.value?.toString() || '', + result: { rowCount: isAfterFilterList[i].rowCount }, + dataType: dataType, + }); + } - // "is on or after" filter list - for (let i = 0; i < isAfterFilterList.length; i++) { - await verifyFilter_withFixedModal({ - column: dataType, - opType: 'is on or after', - opSubType: isAfterFilterList[i].opSub, - value: isAfterFilterList[i]?.value?.toString() || '', - result: { rowCount: 1 + isAfterFilterList[i].rowCount }, - dataType: dataType, - }); - } + // "is on or after" filter list + for (let i = 0; i < isAfterFilterList.length; i++) { + await verifyFilter_withFixedModal({ + column: dataType, + opType: 'is on or after', + opSubType: isAfterFilterList[i].opSub, + value: isAfterFilterList[i]?.value?.toString() || '', + result: { rowCount: 1 + isAfterFilterList[i].rowCount }, + dataType: dataType, + }); + } - // "is within" filter list - for (let i = 0; i < isWithinFilterList.length; i++) { - await verifyFilter_withFixedModal({ - column: dataType, - opType: 'is within', - opSubType: isWithinFilterList[i].opSub, - value: isWithinFilterList[i]?.value?.toString() || '', - result: { rowCount: isWithinFilterList[i].rowCount }, - dataType: dataType, - }); - } + // "is within" filter list + for (let i = 0; i < isWithinFilterList.length; i++) { + await verifyFilter_withFixedModal({ + column: dataType, + opType: 'is within', + opSubType: isWithinFilterList[i].opSub, + value: isWithinFilterList[i]?.value?.toString() || '', + result: { rowCount: isWithinFilterList[i].rowCount }, + dataType: dataType, + }); + } - // "is blank" and "is not blank" filter list - for (let i = 0; i < filterList.length; i++) { - await verifyFilter_withFixedModal({ - column: dataType, - opType: filterList[i].opType, - opSubType: null, - value: null, - result: { rowCount: filterList[i].rowCount }, - dataType: dataType, - }); + // "is blank" and "is not blank" filter list + for (let i = 0; i < filterList.length; i++) { + await verifyFilter_withFixedModal({ + column: dataType, + opType: filterList[i].opType, + opSubType: null, + value: null, + result: { rowCount: filterList[i].rowCount }, + dataType: dataType, + }); + } } } @@ -974,8 +976,12 @@ test.describe('Filter Tests: Date based', () => { } }); - test('Date : filters', async () => { - await dateTimeBasedFilterTest('Date'); + test('Date : filters-1', async () => { + await dateTimeBasedFilterTest('Date', 1); + }); + + test('Date : filters-2', async () => { + await dateTimeBasedFilterTest('Date', 2); }); }); diff --git a/tests/playwright/tests/metaSync.spec.ts b/tests/playwright/tests/metaSync.spec.ts index f845c384d3..f97c690e99 100644 --- a/tests/playwright/tests/metaSync.spec.ts +++ b/tests/playwright/tests/metaSync.spec.ts @@ -39,6 +39,8 @@ test.describe('Meta sync', () => { await dbExec(`CREATE TABLE table2 (id INT NOT NULL, col1 INT NULL, PRIMARY KEY (id))`); await settings.dataSources.metaData.clickReload(); + await dashboard.rootPage.waitForTimeout(1000); + await settings.dataSources.metaData.verifyRow({ index: isPg(context) ? 21 : 16, model: `table1`, diff --git a/tests/playwright/tests/rolesPreview.spec.ts b/tests/playwright/tests/rolesPreview.spec.ts index 0ecea16c31..eaca9f9fea 100644 --- a/tests/playwright/tests/rolesPreview.spec.ts +++ b/tests/playwright/tests/rolesPreview.spec.ts @@ -66,7 +66,7 @@ test.describe('Preview Mode', () => { await dashboard.rootPage.waitForTimeout(1500); - await dashboard.treeView.openTable({ title: 'Country' }); + await dashboard.treeView.openTable({ title: 'Country', networkResponse: false }); await dashboard.viewSidebar.validateRoleAccess({ role: role.toLowerCase(), diff --git a/tests/playwright/tests/utils/general.ts b/tests/playwright/tests/utils/general.ts new file mode 100644 index 0000000000..1571666b1a --- /dev/null +++ b/tests/playwright/tests/utils/general.ts @@ -0,0 +1,22 @@ +// Selector objects include the text of any icons in the textContent property. +// This function removes the text of any icons from the textContent property. +async function getTextExcludeIconText(selector) { + // Get the text of the selector + let text = await selector.textContent(); + + // List of icons + const icons = await selector.locator('.material-symbols-outlined'); + const iconCount = await icons.count(); + + // Remove the text of each icon from the text + for (let i = 0; i < iconCount; i++) { + await icons.nth(i).waitFor(); + const iconText = await icons.nth(i).textContent(); + text = text.replace(iconText, ''); + } + + // trim text for any spaces + return text.trim(); +} + +export { getTextExcludeIconText };