import { expect, Locator } from '@playwright/test'; import { DashboardPage } from '.'; import BasePage from '../Base'; export class TreeViewPage extends BasePage { readonly dashboard: DashboardPage; readonly project: any; readonly quickImportButton: Locator; constructor(dashboard: DashboardPage, project: any) { super(dashboard.rootPage); this.dashboard = dashboard; this.project = project; this.quickImportButton = dashboard.get().locator('.nc-import-menu'); } get() { return this.dashboard.get().locator('.nc-treeview-container'); } async isVisible() { return await this.get().isVisible(); } async verifyVisibility({ isVisible }: { isVisible: boolean }) { await this.rootPage.waitForTimeout(1000); const domElement = await this.get(); // get width of treeview dom element const width = (await domElement.boundingBox()).width; // if (isVisible) { // await expect(this.get()).toBeVisible(); // } else { // await expect(this.get()).not.toBeVisible(); // } // border for treeview is 1px // if not-visible, width should be < 5; if (!isVisible) { expect(width).toBeLessThan(5); } else { expect(width).toBeGreaterThan(5); } } async focusTable({ title }: { title: string }) { await this.get().locator(`.nc-project-tree-tbl-${title}`).focus(); } async openBase({ title }: { title: string }) { const nodes = await this.get().locator(`.ant-collapse`); // loop through nodes.count() to find the node with title for (let i = 0; i < (await nodes.count()); i++) { const node = nodes.nth(i); const nodeTitle = await node.innerText(); // check if nodeTitle contains title if (nodeTitle.includes(title)) { // click on node await node.waitFor({ state: 'visible' }); await node.click(); break; } } await this.rootPage.waitForTimeout(2000); } // assumption: first view rendered is always GRID // async openTable({ title, mode = 'standard', networkResponse = false, mobileMode = false, }: { title: string; mode?: string; networkResponse?: boolean; mobileMode?: boolean; }) { if (mobileMode) { await this.rootPage.locator('.h-full > div > .nc-sidebar-left-toggle-icon').click(); } if ((await this.get().locator('.active.nc-project-tree-tbl').count()) > 0) { if ((await this.get().locator('.active.nc-project-tree-tbl').innerText()) === title) { // table already open return; } } await this.get().locator(`.nc-project-tree-tbl-${title}`).waitFor({ state: 'visible' }); if (networkResponse === true) { await this.waitForResponse({ uiAction: async () => await this.get().locator(`.nc-project-tree-tbl-${title}`).click(), httpMethodsToMatch: ['GET'], requestUrlPathToMatch: `/api/v1/db/data/noco/`, responseJsonMatcher: json => json.pageInfo, }); await this.dashboard.waitForTabRender({ title, mode }); } else { await this.get().locator(`.nc-project-tree-tbl-${title}`).click(); await this.rootPage.waitForTimeout(1000); } } async createTable({ title, skipOpeningModal, mode }: { title: string; skipOpeningModal?: boolean; mode?: string }) { if (!skipOpeningModal) await this.get().locator('.nc-add-new-table').click(); await this.dashboard.get().locator('.nc-modal-table-create').locator('.ant-modal-body').waitFor(); await this.dashboard.get().getByPlaceholder('Enter table name').fill(title); await this.waitForResponse({ uiAction: async () => await this.dashboard.get().locator('button:has-text("Submit")').click(), httpMethodsToMatch: ['POST'], requestUrlPathToMatch: `/api/v1/db/meta/projects/`, responseJsonMatcher: json => json.title === title && json.type === 'table', }); // Tab render is slow for playwright await this.dashboard.waitForTabRender({ title, mode }); } async verifyTable({ title, index, exists = true }: { title: string; index?: number; exists?: boolean }) { if (exists) { await expect(this.get().getByTestId(`tree-view-table-${title}`)).toHaveCount(1); if (index) { await expect(this.get().locator('.nc-tbl-title').nth(index)).toHaveText(title); } } else { await expect(this.get().getByTestId(`tree-view-table-${title}`)).toHaveCount(0); } } async deleteTable({ title }: { title: string }) { await this.get().locator(`.nc-project-tree-tbl-${title}`).click({ button: 'right' }); await this.dashboard.get().locator('div.nc-project-menu-item:has-text("Delete")').click(); await this.waitForResponse({ uiAction: async () => await this.dashboard.get().locator('button:has-text("Yes")').click(), httpMethodsToMatch: ['DELETE'], requestUrlPathToMatch: `/api/v1/db/meta/tables/`, }); await expect .poll( async () => await this.dashboard.tabBar .locator('.ant-tabs-tab', { hasText: title, }) .isVisible() ) .toBe(false); (await this.rootPage.locator('.nc-container').last().elementHandle())?.waitForElementState('stable'); } async renameTable({ title, newTitle }: { title: string; newTitle: string }) { await this.get().locator(`.nc-project-tree-tbl-${title}`).click({ button: 'right' }); await this.dashboard.get().locator('div.nc-project-menu-item:has-text("Rename")').click(); await this.dashboard.get().locator('[placeholder="Enter table name"]').fill(newTitle); await this.dashboard.get().locator('button:has-text("Submit")').click(); await this.verifyToast({ message: 'Table renamed successfully' }); } async reorderTables({ sourceTable, destinationTable }: { sourceTable: string; destinationTable: string }) { await this.dashboard .get() .locator(`[data-testid="tree-view-table-draggable-handle-${sourceTable}"]`) .dragTo(this.get().locator(`[data-testid="tree-view-table-${destinationTable}"]`)); } async quickImport({ title }: { title: string }) { await this.get().locator('.nc-add-new-table').hover(); await this.quickImportButton.click(); const importMenu = this.dashboard.get().locator('.nc-dropdown-import-menu'); await importMenu.locator(`.ant-dropdown-menu-title-content:has-text("${title}")`).click(); } async changeTableIcon({ title, icon }: { title: string; icon: string }) { await this.get().locator(`.nc-project-tree-tbl-${title} .nc-table-icon`).click(); await this.rootPage.getByTestId('nc-emoji-filter').type(icon); await this.rootPage.getByTestId('nc-emoji-container').locator(`.nc-emoji-item >> svg`).first().click(); await this.rootPage.getByTestId('nc-emoji-container').isHidden(); await expect( this.get().locator(`.nc-project-tree-tbl-${title} [data-testid="nc-icon-emojione:${icon}"]`) ).toHaveCount(1); } async duplicateTable(title: string, includeData = true, includeViews = true) { await this.get().locator(`.nc-project-tree-tbl-${title}`).click({ button: 'right' }); await this.dashboard.get().locator('div.nc-project-menu-item:has-text("Duplicate")').click(); // Find the checkbox element with the label "Include data" const includeDataCheckbox = await this.dashboard.get().getByText('Include data', { exact: true }); // Check the checkbox if it is not already checked if ((await includeDataCheckbox.isChecked()) && !includeData) { await includeDataCheckbox.click(); // click the checkbox to check it } // Find the checkbox element with the label "Include data" const includeViewsCheckbox = await this.dashboard.get().getByText('Include views', { exact: true }); // Check the checkbox if it is not already checked if ((await includeViewsCheckbox.isChecked()) && !includeViews) { await includeViewsCheckbox.click(); // click the checkbox to check it } await this.waitForResponse({ uiAction: async () => await this.rootPage.getByRole('button', { name: 'Confirm' }).click(), httpMethodsToMatch: ['POST'], requestUrlPathToMatch: `/api/v1/db/meta/duplicate/`, }); await this.get().locator(`[data-testid="tree-view-table-${title} copy"]`).waitFor(); } async verifyTabIcon({ title, icon }: { title: string; icon: string }) { await new Promise(resolve => setTimeout(resolve, 1000)); await expect( this.rootPage.locator( `[data-testid="nc-tab-title"]:has-text("${title}") [data-testid="nc-tab-icon-emojione:${icon}"]` ) ).toBeVisible(); } // todo: Break this into smaller methods async validateRoleAccess(param: { role: string }) { // Add new table button await expect(this.get().locator(`.nc-add-new-table`)).toHaveCount(param.role === 'creator' ? 1 : 0); // Import menu await expect(this.get().locator(`.nc-import-menu`)).toHaveCount(param.role === 'creator' ? 1 : 0); // Team and Settings button await expect(this.get().locator(`.nc-new-base`)).toHaveCount(param.role === 'creator' ? 1 : 0); // Right click context menu await this.get().locator(`.nc-project-tree-tbl-Country`).click({ button: 'right', }); await expect(this.rootPage.locator(`.nc-dropdown-tree-view-context-menu:visible`)).toHaveCount( param.role === 'creator' ? 1 : 0 ); } }