frontend/apps/quantgrid/playwright/components/Grid.ts (307 lines of code) (raw):

import { expect, Page } from '@playwright/test'; import { FieldMenuItem } from '../enums/FieldMenuItem'; import { GridMenuItem } from '../enums/GridMenuItem'; import { MoveDirection } from '../enums/MoveDirection'; import { Table } from '../logic-entities/Table'; import { BaseComponent } from './BaseComponent'; import { Editor } from './Editor'; export class Grid extends BaseComponent { private gridHorizontalCellsHeaders = 'div.grid-header-cell__content'; private gridHorizontalCellHeaderPlaceholder = 'div.grid-cell--header-placeholder'; private gridVerticalCellsHeaders = 'div.grid-row-number'; private gridHorizontalHeaders = 'div.grid-header'; private gridData = 'div.grid-data-container'; private gridScroller = 'div.grid-data-scroller'; private gridSelection = 'div.grid-selection'; private selectedColumn = 'div.grid-header-cell--selected'; private selectedRow = 'div.grid-row-number--selected'; private tableHeader = '[class*="tableRenderer_header"]>div.tableRenderer_headerTitle'; private tableFieldValue = '[class*="tableRenderer_content_"]'; private keyField = '[class*="keyField"]'; private fieldHeader = '[class*="tableRenderer_field"]'; private removeDim = '.remove-dim-button'; private gridCellEditor: Editor; //='.grid-cell-editor'; private gridCellEditorRootLocator = '[data-mode-id="cell-editor"]'; private moveSelection = '.grid-selection__move'; private moveSelectionTooltip = '.grid-selection-move-tooltip'; private contextMenu = '.grid-context-menu'; constructor(page: Page) { super(page); this.gridCellEditor = new Editor( page, page.locator(this.gridCellEditorRootLocator) ); } private keyGridLocator(row: number, column: number) { return `[data-row='${row}'][data-col='${column}']`; } private gridCell(row: number, column: number) { return `div${this.keyGridLocator(row, column)}`; } public gridCellRoot(row: number, column: number) { return `div.grid-cell:has(>${this.gridCell(row, column)})`; } private gridCellTableContent(row: number, column: number) { return `${this.gridCell(row, column)}${this.tableFieldValue}`; } private gridKeyFieldCell(row: number, column: number) { return `${this.gridCell(row, column)}${this.keyField}`; } private gridFieldHeaderCell(row: number, column: number) { return `${this.gridCell(row, column)}${this.fieldHeader}`; } private gridCellDimension(row: number, column: number) { return `${this.removeDim}${this.keyGridLocator(row, column)}`; } private collapsedDimension(row: number, column: number) { return `${this.gridCell(row, column)}>button.show-dim-table`; } private gridCellTableHeader(row: number, column: number) { return `${this.gridCell(row, column)}${this.tableHeader}`; } private gridCellTableMenu(row: number, column: number) { return `button.context-menu-button${this.keyGridLocator(row, column)}`; } public getCellTableText(row: number, column: number) { return this.innerPage.locator(this.gridCellTableContent(row, column)); } public getCellEditor() { return this.gridCellEditor; } public async clickOnCell(row: number, column: number) { await this.innerPage.locator(this.gridCell(row, column)).first().click(); } public async dbClickOnCell(row: number, column: number) { await this.innerPage.locator(this.gridCell(row, column)).first().dblclick(); } public async dragFromCellToCell( rowStart: number, columnStrart: number, rowEnd: number, columnEnd: number ) { await this.innerPage .locator(this.gridCell(rowStart, columnStrart)) .first() .dragTo(this.innerPage.locator(this.gridCell(rowEnd, columnEnd)).first()); } public async expectSelectedRowToBe(row: number) { await expect(this.innerPage.locator(this.selectedRow).first()).toHaveText( row.toString() ); } public async expectFieldToBeKey(row: number, column: number) { await expect( this.innerPage.locator(this.gridKeyFieldCell(row, column)) ).toBeVisible(); } public async expectFieldNotBeKey(row: number, column: number) { await expect( this.innerPage.locator(this.gridKeyFieldCell(row, column)) ).toBeHidden(); } public async expectFieldIsDimension(row: number, column: number) { await this.innerPage .locator(this.gridCellTableContent(row, column)) .click({ button: 'right' }); await expect( this.innerPage.getByText(FieldMenuItem.RemoveDimension, { exact: true }) ).toBeVisible(); } public async expectFieldIsNotDimension(row: number, column: number) { await this.innerPage .locator(this.gridCellTableContent(row, column)) .click({ button: 'right' }); await expect( this.innerPage.getByText(FieldMenuItem.MakeDimension, { exact: true }) ).toBeVisible(); } public async expectSelectedColumnToBe(column: number) { await expect( this.innerPage.locator(this.selectedColumn).first() ).toHaveText(column.toString()); } public async scrollDown() { await this.innerPage .locator(this.gridScroller) .evaluate((e) => (e.scrollTop = e.scrollHeight)); } public async verifyGridDimensionsEqualsTo( expectedRows: number, expectedColumns: number ) { await expect( this.innerPage.locator(this.gridHorizontalCellHeaderPlaceholder) ).toHaveCount(expectedColumns); await this.clickOnCell(1, 1); await this.innerPage.keyboard.press('Control+ArrowDown'); await expect( this.innerPage.locator(this.gridVerticalCellsHeaders).last() ).toContainText((expectedRows + 1).toString()); } public async performMenuAction( row: number, column: number, actionText: string ) { await this.innerPage.locator(this.gridCellTableHeader(row, column)).hover(); await this.innerPage.locator(this.gridCellTableMenu(row, column)).click(); await this.innerPage.getByText(actionText, { exact: true }).click(); } public async waitGridVisible() { await expect( this.innerPage.locator(this.gridHorizontalHeaders) ).toBeVisible(); await expect(this.innerPage.locator(this.gridData)).toBeVisible(); } public async expectCellBecameEditable(cellText: string | undefined) { await this.gridCellEditor.shouldBeVisible(); if (cellText) await expect(this.gridCellEditor.getValueLocator()).toHaveText(cellText); } public async performCellAction( row: number, column: number, actionText: string ) { await this.innerPage .locator(this.gridCellTableContent(row, column)) .click({ button: 'right' }); await this.innerPage.getByText(actionText, { exact: true }).click(); } public async performCellSubAction( row: number, column: number, groupText: string, actionText: string ) { await this.innerPage .locator(this.gridCellTableContent(row, column)) .click({ button: 'right' }); await this.innerPage.getByText(groupText, { exact: true }).hover(); await this.innerPage.getByText(actionText, { exact: true }).click(); } public async expectCellTextChange( row: number, column: number, newCellText: string ) { await expect( this.innerPage.locator(this.gridCellTableContent(row, column)) ).toHaveText(newCellText); } public async setCellValue(newValue: string) { const oldLength = (await this.gridCellEditor.getValueLocator().textContent())?.length || 0; await this.gridCellEditor.setValue(newValue, oldLength, false); await new Promise((resolve) => setTimeout(resolve, 500)); await this.innerPage.keyboard.press('Enter'); } public async setCellValueAndCancel(newValue: string) { await this.gridCellEditor.setValueAndCancel(newValue, false); } public async expectTableToDissapear(row: number, column: number) { await expect( this.innerPage.locator(this.gridCellTableContent(row, column)) ).toBeHidden(); } public async expectTableToAppear(row: number, column: number) { await expect( this.innerPage.locator(this.gridCellTableContent(row, column)) ).toBeVisible(); } public async expectTableHeaderToDissapear(row: number, column: number) { await expect( this.innerPage.locator(this.gridCellTableHeader(row, column)) ).toBeHidden(); } public async expectCellToBeDim(row: number, column: number) { await expect( this.innerPage.locator(this.gridCellTableContent(row, column)) ).toBeVisible(); await expect( this.innerPage.locator(this.collapsedDimension(row, column)) ).toBeVisible(); } public async expectCellToNotBeDim(row: number, column: number) { await expect( this.innerPage.locator(this.collapsedDimension(row, column)) ).toBeHidden(); } public async expectTableHeaderToAppear(row: number, column: number) { await expect( this.innerPage.locator(this.gridCellTableHeader(row, column)) ).toBeVisible(); } public async expectFieldHeaderToAppear(row: number, column: number) { await expect( this.innerPage.locator(this.gridFieldHeaderCell(row, column)) ).toBeVisible(); } public async expectMoveSelectionToBeVisible() { await expect(this.innerPage.locator(this.moveSelection)).toBeVisible(); } public async moveTable(table: Table, direction: MoveDirection) { await this.performMenuAction( table.getTop(), table.getLeft(), GridMenuItem.Move ); await this.expectMoveSelectionToBeVisible(); await this.moveCurrentTable(direction); } public async moveCurrentTable(direction: MoveDirection) { await new Promise((resolve) => setTimeout(resolve, 300)); switch (direction) { case MoveDirection.UP: await this.innerPage.keyboard.press('ArrowUp'); break; case MoveDirection.DOWN: await this.innerPage.keyboard.press('ArrowDown'); break; case MoveDirection.LEFT: await this.innerPage.keyboard.press('ArrowLeft'); break; case MoveDirection.RIGHT: await this.innerPage.keyboard.press('ArrowRight'); break; } await this.innerPage.keyboard.press('Enter'); } public async verifyTableMove( initialRow: number, initialColumn: number, text: string, direction: MoveDirection ) { await expect( this.innerPage.locator( this.gridCellTableHeader(initialRow, initialColumn) ) ).toBeHidden(); let newRow = initialRow, newColumn = initialColumn; switch (direction) { case MoveDirection.UP: newRow--; break; case MoveDirection.DOWN: newRow++; break; case MoveDirection.LEFT: newColumn--; break; case MoveDirection.RIGHT: newColumn++; break; } await expect( this.innerPage.locator(this.gridCellTableHeader(newRow, newColumn)) ).toHaveText(text); } public async expectContextMenuVisible() { await expect(this.innerPage.locator(this.contextMenu)).toBeVisible(); } }