feat(admin): 添加用户管理相关文件
添加用户管理视图、API和状态管理文件
This commit is contained in:
@@ -0,0 +1,622 @@
|
||||
import { Page, Locator } from '@playwright/test';
|
||||
import { testLogger } from '../shared/utils/test-logger';
|
||||
|
||||
export interface TableColumn {
|
||||
name: string;
|
||||
selector: string;
|
||||
type: 'text' | 'number' | 'date' | 'boolean' | 'action';
|
||||
sortable?: boolean;
|
||||
filterable?: boolean;
|
||||
}
|
||||
|
||||
export interface TableRow {
|
||||
index: number;
|
||||
data: Record<string, string>;
|
||||
cells: Map<string, Locator>;
|
||||
}
|
||||
|
||||
export interface TableOperation {
|
||||
name: string;
|
||||
selector: string;
|
||||
type: 'edit' | 'delete' | 'view' | 'custom';
|
||||
}
|
||||
|
||||
export class TableHelper {
|
||||
private page: Page;
|
||||
private tableSelector: string;
|
||||
private columns: Map<string, TableColumn> = new Map();
|
||||
private operations: Map<string, TableOperation> = new Map();
|
||||
|
||||
constructor(page: Page, tableSelector: string = 'table') {
|
||||
this.page = page;
|
||||
this.tableSelector = tableSelector;
|
||||
testLogger.info(`TableHelper initialized for table: ${tableSelector}`);
|
||||
}
|
||||
|
||||
setColumn(column: TableColumn): void {
|
||||
this.columns.set(column.name, column);
|
||||
testLogger.debug(`Column added: ${column.name}`);
|
||||
}
|
||||
|
||||
setColumns(columns: TableColumn[]): void {
|
||||
columns.forEach(column => this.setColumn(column));
|
||||
testLogger.debug(`${columns.length} columns added`);
|
||||
}
|
||||
|
||||
setOperation(operation: TableOperation): void {
|
||||
this.operations.set(operation.name, operation);
|
||||
testLogger.debug(`Operation added: ${operation.name}`);
|
||||
}
|
||||
|
||||
setOperations(operations: TableOperation[]): void {
|
||||
operations.forEach(operation => this.setOperation(operation));
|
||||
testLogger.debug(`${operations.length} operations added`);
|
||||
}
|
||||
|
||||
getColumn(name: string): TableColumn | undefined {
|
||||
return this.columns.get(name);
|
||||
}
|
||||
|
||||
getAllColumns(): TableColumn[] {
|
||||
return Array.from(this.columns.values());
|
||||
}
|
||||
|
||||
async getRowCount(): Promise<number> {
|
||||
testLogger.info('Getting row count');
|
||||
|
||||
const rowsLocator = this.page.locator(`${this.tableSelector} tbody tr, ${this.tableSelector} .table-row`);
|
||||
const count = await rowsLocator.count();
|
||||
|
||||
testLogger.debug(`Row count: ${count}`);
|
||||
return count;
|
||||
}
|
||||
|
||||
async getColumnCount(): Promise<number> {
|
||||
testLogger.info('Getting column count');
|
||||
|
||||
const headersLocator = this.page.locator(`${this.tableSelector} thead th, ${this.tableSelector} .table-header th`);
|
||||
const count = await headersLocator.count();
|
||||
|
||||
testLogger.debug(`Column count: ${count}`);
|
||||
return count;
|
||||
}
|
||||
|
||||
async getRow(index: number): Promise<TableRow> {
|
||||
testLogger.info(`Getting row: ${index}`);
|
||||
|
||||
const rowLocator = this.page.locator(`${this.tableSelector} tbody tr, ${this.tableSelector} .table-row`).nth(index);
|
||||
const cells: Map<string, Locator> = new Map();
|
||||
const data: Record<string, string> = {};
|
||||
|
||||
const columnEntries = Array.from(this.columns.entries());
|
||||
for (const [columnName, column] of columnEntries) {
|
||||
const cellSelector = `td:nth-child(${this.getColumnIndex(columnName) + 1}), .table-cell:nth-child(${this.getColumnIndex(columnName) + 1})`;
|
||||
const cellLocator = rowLocator.locator(cellSelector);
|
||||
|
||||
cells.set(columnName, cellLocator);
|
||||
|
||||
let cellValue: string;
|
||||
|
||||
switch (column.type) {
|
||||
case 'text':
|
||||
cellValue = await cellLocator.textContent() || '';
|
||||
break;
|
||||
case 'number':
|
||||
cellValue = await cellLocator.textContent() || '0';
|
||||
break;
|
||||
case 'date':
|
||||
cellValue = await cellLocator.textContent() || '';
|
||||
break;
|
||||
case 'boolean':
|
||||
const checkboxLocator = cellLocator.locator('input[type="checkbox"]');
|
||||
cellValue = String(await checkboxLocator.isChecked());
|
||||
break;
|
||||
case 'action':
|
||||
cellValue = 'action';
|
||||
break;
|
||||
default:
|
||||
cellValue = await cellLocator.textContent() || '';
|
||||
}
|
||||
|
||||
data[columnName] = cellValue.trim();
|
||||
}
|
||||
|
||||
const row: TableRow = {
|
||||
index,
|
||||
data,
|
||||
cells
|
||||
};
|
||||
|
||||
testLogger.debug(`Row retrieved: ${index}`);
|
||||
return row;
|
||||
}
|
||||
|
||||
async getAllRows(): Promise<TableRow[]> {
|
||||
testLogger.info('Getting all rows');
|
||||
|
||||
const rowCount = await this.getRowCount();
|
||||
const rows: TableRow[] = [];
|
||||
|
||||
for (let i = 0; i < rowCount; i++) {
|
||||
rows.push(await this.getRow(i));
|
||||
}
|
||||
|
||||
testLogger.info(`All rows retrieved: ${rows.length}`);
|
||||
return rows;
|
||||
}
|
||||
|
||||
async getTableData(): Promise<Record<string, string>[]> {
|
||||
testLogger.info('Getting table data');
|
||||
|
||||
const rows = await this.getAllRows();
|
||||
const data: Record<string, string>[] = rows.map(row => row.data);
|
||||
|
||||
testLogger.debug(`Table data retrieved: ${JSON.stringify(data)}`);
|
||||
return data;
|
||||
}
|
||||
|
||||
async findRowByColumn(columnName: string, value: string): Promise<TableRow | undefined> {
|
||||
testLogger.info(`Finding row by column: ${columnName} = ${value}`);
|
||||
|
||||
const rows = await this.getAllRows();
|
||||
const foundRow = rows.find(row => row.data[columnName] === value);
|
||||
|
||||
if (foundRow) {
|
||||
testLogger.info(`Row found: ${foundRow.index}`);
|
||||
} else {
|
||||
testLogger.warn(`Row not found: ${columnName} = ${value}`);
|
||||
}
|
||||
|
||||
return foundRow;
|
||||
}
|
||||
|
||||
async findRowsByColumn(columnName: string, value: string): Promise<TableRow[]> {
|
||||
testLogger.info(`Finding rows by column: ${columnName} = ${value}`);
|
||||
|
||||
const rows = await this.getAllRows();
|
||||
const foundRows = rows.filter(row => row.data[columnName] === value);
|
||||
|
||||
testLogger.info(`Rows found: ${foundRows.length}`);
|
||||
return foundRows;
|
||||
}
|
||||
|
||||
async filterByColumn(columnName: string, value: string): Promise<void> {
|
||||
testLogger.info(`Filtering by column: ${columnName} = ${value}`);
|
||||
|
||||
const column = this.columns.get(columnName);
|
||||
|
||||
if (!column) {
|
||||
throw new Error(`Column not found: ${columnName}`);
|
||||
}
|
||||
|
||||
if (!column.filterable) {
|
||||
throw new Error(`Column is not filterable: ${columnName}`);
|
||||
}
|
||||
|
||||
const filterSelector = `${this.tableSelector} thead th:nth-child(${this.getColumnIndex(columnName) + 1}) .filter-input, ${this.tableSelector} .table-header th:nth-child(${this.getColumnIndex(columnName) + 1}) .filter-input`;
|
||||
const filterLocator = this.page.locator(filterSelector);
|
||||
|
||||
await filterLocator.waitFor({ state: 'visible' });
|
||||
await filterLocator.fill(value);
|
||||
|
||||
await this.page.waitForTimeout(500);
|
||||
|
||||
testLogger.info(`Filter applied: ${columnName} = ${value}`);
|
||||
}
|
||||
|
||||
async clearFilter(columnName: string): Promise<void> {
|
||||
testLogger.info(`Clearing filter: ${columnName}`);
|
||||
|
||||
const column = this.columns.get(columnName);
|
||||
|
||||
if (!column) {
|
||||
throw new Error(`Column not found: ${columnName}`);
|
||||
}
|
||||
|
||||
if (!column.filterable) {
|
||||
throw new Error(`Column is not filterable: ${columnName}`);
|
||||
}
|
||||
|
||||
const filterSelector = `${this.tableSelector} thead th:nth-child(${this.getColumnIndex(columnName) + 1}) .filter-input, ${this.tableSelector} .table-header th:nth-child(${this.getColumnIndex(columnName) + 1}) .filter-input`;
|
||||
const filterLocator = this.page.locator(filterSelector);
|
||||
|
||||
await filterLocator.clear();
|
||||
|
||||
await this.page.waitForTimeout(500);
|
||||
|
||||
testLogger.info(`Filter cleared: ${columnName}`);
|
||||
}
|
||||
|
||||
async clearAllFilters(): Promise<void> {
|
||||
testLogger.info('Clearing all filters');
|
||||
|
||||
const columnKeys = Array.from(this.columns.keys());
|
||||
for (const columnName of columnKeys) {
|
||||
const column = this.columns.get(columnName);
|
||||
|
||||
if (column?.filterable) {
|
||||
try {
|
||||
await this.clearFilter(columnName);
|
||||
} catch (error) {
|
||||
const errorObj = error instanceof Error ? error : new Error(String(error));
|
||||
testLogger.warn(`Failed to clear filter: ${columnName}`, { error: errorObj.message });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
testLogger.info('All filters cleared');
|
||||
}
|
||||
|
||||
async sortByColumn(columnName: string, order: 'asc' | 'desc' = 'asc'): Promise<void> {
|
||||
testLogger.info(`Sorting by column: ${columnName} (${order})`);
|
||||
|
||||
const column = this.columns.get(columnName);
|
||||
|
||||
if (!column) {
|
||||
throw new Error(`Column not found: ${columnName}`);
|
||||
}
|
||||
|
||||
if (!column.sortable) {
|
||||
throw new Error(`Column is not sortable: ${columnName}`);
|
||||
}
|
||||
|
||||
const sortSelector = `${this.tableSelector} thead th:nth-child(${this.getColumnIndex(columnName) + 1}) .sort-icon, ${this.tableSelector} .table-header th:nth-child(${this.getColumnIndex(columnName) + 1}) .sort-icon`;
|
||||
const sortLocator = this.page.locator(sortSelector);
|
||||
|
||||
await sortLocator.waitFor({ state: 'visible' });
|
||||
await sortLocator.click();
|
||||
|
||||
await this.page.waitForTimeout(500);
|
||||
|
||||
const currentOrder = await this.getSortOrder(columnName);
|
||||
if (currentOrder !== order) {
|
||||
await sortLocator.click();
|
||||
await this.page.waitForTimeout(500);
|
||||
}
|
||||
|
||||
testLogger.info(`Sorted by: ${columnName} (${order})`);
|
||||
}
|
||||
|
||||
async getSortOrder(columnName: string): Promise<'asc' | 'desc' | null> {
|
||||
const column = this.columns.get(columnName);
|
||||
|
||||
if (!column) {
|
||||
throw new Error(`Column not found: ${columnName}`);
|
||||
}
|
||||
|
||||
const sortSelector = `${this.tableSelector} thead th:nth-child(${this.getColumnIndex(columnName) + 1})`;
|
||||
const sortLocator = this.page.locator(sortSelector);
|
||||
|
||||
const classList = await sortLocator.getAttribute('class') || '';
|
||||
|
||||
if (classList.includes('asc')) {
|
||||
return 'asc';
|
||||
} else if (classList.includes('desc')) {
|
||||
return 'desc';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
async clickRow(index: number): Promise<void> {
|
||||
testLogger.info(`Clicking row: ${index}`);
|
||||
|
||||
const rowLocator = this.page.locator(`${this.tableSelector} tbody tr, ${this.tableSelector} .table-row`).nth(index);
|
||||
|
||||
await rowLocator.waitFor({ state: 'visible' });
|
||||
await rowLocator.click();
|
||||
|
||||
testLogger.info(`Row clicked: ${index}`);
|
||||
}
|
||||
|
||||
async clickRowByColumn(columnName: string, value: string): Promise<void> {
|
||||
testLogger.info(`Clicking row by column: ${columnName} = ${value}`);
|
||||
|
||||
const row = await this.findRowByColumn(columnName, value);
|
||||
|
||||
if (!row) {
|
||||
throw new Error(`Row not found: ${columnName} = ${value}`);
|
||||
}
|
||||
|
||||
const rowLocator = this.page.locator(`${this.tableSelector} tbody tr, ${this.tableSelector} .table-row`).nth(row.index);
|
||||
|
||||
await rowLocator.click();
|
||||
|
||||
testLogger.info(`Row clicked: ${row.index}`);
|
||||
}
|
||||
|
||||
async performOperation(rowIndex: number, operationName: string): Promise<void> {
|
||||
testLogger.info(`Performing operation: ${operationName} on row: ${rowIndex}`);
|
||||
|
||||
const operation = this.operations.get(operationName);
|
||||
|
||||
if (!operation) {
|
||||
throw new Error(`Operation not found: ${operationName}`);
|
||||
}
|
||||
|
||||
const rowLocator = this.page.locator(`${this.tableSelector} tbody tr, ${this.tableSelector} .table-row`).nth(rowIndex);
|
||||
const operationLocator = rowLocator.locator(operation.selector);
|
||||
|
||||
await operationLocator.waitFor({ state: 'visible' });
|
||||
await operationLocator.click();
|
||||
|
||||
testLogger.info(`Operation performed: ${operationName} on row: ${rowIndex}`);
|
||||
}
|
||||
|
||||
async performOperationByColumn(columnName: string, value: string, operationName: string): Promise<void> {
|
||||
testLogger.info(`Performing operation: ${operationName} on row: ${columnName} = ${value}`);
|
||||
|
||||
const row = await this.findRowByColumn(columnName, value);
|
||||
|
||||
if (!row) {
|
||||
throw new Error(`Row not found: ${columnName} = ${value}`);
|
||||
}
|
||||
|
||||
await this.performOperation(row.index, operationName);
|
||||
}
|
||||
|
||||
async editRow(rowIndex: number): Promise<void> {
|
||||
testLogger.info(`Editing row: ${rowIndex}`);
|
||||
|
||||
const editOperation = this.operations.get('edit');
|
||||
|
||||
if (!editOperation) {
|
||||
throw new Error('Edit operation not found');
|
||||
}
|
||||
|
||||
await this.performOperation(rowIndex, 'edit');
|
||||
|
||||
testLogger.info(`Row edited: ${rowIndex}`);
|
||||
}
|
||||
|
||||
async editRowByColumn(columnName: string, value: string): Promise<void> {
|
||||
testLogger.info(`Editing row by column: ${columnName} = ${value}`);
|
||||
|
||||
const row = await this.findRowByColumn(columnName, value);
|
||||
|
||||
if (!row) {
|
||||
throw new Error(`Row not found: ${columnName} = ${value}`);
|
||||
}
|
||||
|
||||
await this.editRow(row.index);
|
||||
}
|
||||
|
||||
async deleteRow(rowIndex: number): Promise<void> {
|
||||
testLogger.info(`Deleting row: ${rowIndex}`);
|
||||
|
||||
const deleteOperation = this.operations.get('delete');
|
||||
|
||||
if (!deleteOperation) {
|
||||
throw new Error('Delete operation not found');
|
||||
}
|
||||
|
||||
await this.performOperation(rowIndex, 'delete');
|
||||
|
||||
testLogger.info(`Row deleted: ${rowIndex}`);
|
||||
}
|
||||
|
||||
async deleteRowByColumn(columnName: string, value: string): Promise<void> {
|
||||
testLogger.info(`Deleting row by column: ${columnName} = ${value}`);
|
||||
|
||||
const row = await this.findRowByColumn(columnName, value);
|
||||
|
||||
if (!row) {
|
||||
throw new Error(`Row not found: ${columnName} = ${value}`);
|
||||
}
|
||||
|
||||
await this.deleteRow(row.index);
|
||||
}
|
||||
|
||||
async viewRow(rowIndex: number): Promise<void> {
|
||||
testLogger.info(`Viewing row: ${rowIndex}`);
|
||||
|
||||
const viewOperation = this.operations.get('view');
|
||||
|
||||
if (!viewOperation) {
|
||||
throw new Error('View operation not found');
|
||||
}
|
||||
|
||||
await this.performOperation(rowIndex, 'view');
|
||||
|
||||
testLogger.info(`Row viewed: ${rowIndex}`);
|
||||
}
|
||||
|
||||
async viewRowByColumn(columnName: string, value: string): Promise<void> {
|
||||
testLogger.info(`Viewing row by column: ${columnName} = ${value}`);
|
||||
|
||||
const row = await this.findRowByColumn(columnName, value);
|
||||
|
||||
if (!row) {
|
||||
throw new Error(`Row not found: ${columnName} = ${value}`);
|
||||
}
|
||||
|
||||
await this.viewRow(row.index);
|
||||
}
|
||||
|
||||
async selectRow(rowIndex: number): Promise<void> {
|
||||
testLogger.info(`Selecting row: ${rowIndex}`);
|
||||
|
||||
const rowLocator = this.page.locator(`${this.tableSelector} tbody tr, ${this.tableSelector} .table-row`).nth(rowIndex);
|
||||
const checkboxLocator = rowLocator.locator('input[type="checkbox"]');
|
||||
|
||||
await checkboxLocator.waitFor({ state: 'visible' });
|
||||
await checkboxLocator.check();
|
||||
|
||||
testLogger.info(`Row selected: ${rowIndex}`);
|
||||
}
|
||||
|
||||
async selectRowByColumn(columnName: string, value: string): Promise<void> {
|
||||
testLogger.info(`Selecting row by column: ${columnName} = ${value}`);
|
||||
|
||||
const row = await this.findRowByColumn(columnName, value);
|
||||
|
||||
if (!row) {
|
||||
throw new Error(`Row not found: ${columnName} = ${value}`);
|
||||
}
|
||||
|
||||
await this.selectRow(row.index);
|
||||
}
|
||||
|
||||
async selectAllRows(): Promise<void> {
|
||||
testLogger.info('Selecting all rows');
|
||||
|
||||
const selectAllLocator = this.page.locator(`${this.tableSelector} thead input[type="checkbox"], ${this.tableSelector} .table-header input[type="checkbox"]`);
|
||||
|
||||
await selectAllLocator.waitFor({ state: 'visible' });
|
||||
await selectAllLocator.check();
|
||||
|
||||
testLogger.info('All rows selected');
|
||||
}
|
||||
|
||||
async deselectRow(rowIndex: number): Promise<void> {
|
||||
testLogger.info(`Deselecting row: ${rowIndex}`);
|
||||
|
||||
const rowLocator = this.page.locator(`${this.tableSelector} tbody tr, ${this.tableSelector} .table-row`).nth(rowIndex);
|
||||
const checkboxLocator = rowLocator.locator('input[type="checkbox"]');
|
||||
|
||||
await checkboxLocator.waitFor({ state: 'visible' });
|
||||
await checkboxLocator.uncheck();
|
||||
|
||||
testLogger.info(`Row deselected: ${rowIndex}`);
|
||||
}
|
||||
|
||||
async deselectAllRows(): Promise<void> {
|
||||
testLogger.info('Deselecting all rows');
|
||||
|
||||
const selectAllLocator = this.page.locator(`${this.tableSelector} thead input[type="checkbox"], ${this.tableSelector} .table-header input[type="checkbox"]`);
|
||||
|
||||
await selectAllLocator.waitFor({ state: 'visible' });
|
||||
await selectAllLocator.uncheck();
|
||||
|
||||
testLogger.info('All rows deselected');
|
||||
}
|
||||
|
||||
async getSelectedRows(): Promise<TableRow[]> {
|
||||
testLogger.info('Getting selected rows');
|
||||
|
||||
const rows = await this.getAllRows();
|
||||
const selectedRows: TableRow[] = [];
|
||||
|
||||
for (const row of rows) {
|
||||
const checkboxLocator = this.page.locator(`${this.tableSelector} tbody tr:nth-child(${row.index + 1}) input[type="checkbox"], ${this.tableSelector} .table-row:nth-child(${row.index + 1}) input[type="checkbox"]`);
|
||||
|
||||
if (await checkboxLocator.isChecked()) {
|
||||
selectedRows.push(row);
|
||||
}
|
||||
}
|
||||
|
||||
testLogger.info(`Selected rows: ${selectedRows.length}`);
|
||||
return selectedRows;
|
||||
}
|
||||
|
||||
async goToPage(pageNumber: number): Promise<void> {
|
||||
testLogger.info(`Going to page: ${pageNumber}`);
|
||||
|
||||
const pageSelector = `${this.tableSelector} .pagination .page-item[data-page="${pageNumber}"], ${this.tableSelector} .pagination button[data-page="${pageNumber}"]`;
|
||||
const pageLocator = this.page.locator(pageSelector);
|
||||
|
||||
await pageLocator.waitFor({ state: 'visible' });
|
||||
await pageLocator.click();
|
||||
|
||||
await this.page.waitForTimeout(500);
|
||||
|
||||
testLogger.info(`Page changed: ${pageNumber}`);
|
||||
}
|
||||
|
||||
async nextPage(): Promise<void> {
|
||||
testLogger.info('Going to next page');
|
||||
|
||||
const nextSelector = `${this.tableSelector} .pagination .next, ${this.tableSelector} .pagination button[aria-label="Next"]`;
|
||||
const nextLocator = this.page.locator(nextSelector);
|
||||
|
||||
await nextLocator.waitFor({ state: 'visible' });
|
||||
await nextLocator.click();
|
||||
|
||||
await this.page.waitForTimeout(500);
|
||||
|
||||
testLogger.info('Next page loaded');
|
||||
}
|
||||
|
||||
async previousPage(): Promise<void> {
|
||||
testLogger.info('Going to previous page');
|
||||
|
||||
const prevSelector = `${this.tableSelector} .pagination .prev, ${this.tableSelector} .pagination button[aria-label="Previous"]`;
|
||||
const prevLocator = this.page.locator(prevSelector);
|
||||
|
||||
await prevLocator.waitFor({ state: 'visible' });
|
||||
await prevLocator.click();
|
||||
|
||||
await this.page.waitForTimeout(500);
|
||||
|
||||
testLogger.info('Previous page loaded');
|
||||
}
|
||||
|
||||
async getCurrentPage(): Promise<number> {
|
||||
testLogger.info('Getting current page');
|
||||
|
||||
const activePageSelector = `${this.tableSelector} .pagination .page-item.active, ${this.tableSelector} .pagination button.active`;
|
||||
const activePageLocator = this.page.locator(activePageSelector);
|
||||
|
||||
const pageNumber = await activePageLocator.getAttribute('data-page');
|
||||
|
||||
testLogger.debug(`Current page: ${pageNumber}`);
|
||||
return parseInt(pageNumber || '1', 10);
|
||||
}
|
||||
|
||||
async getTotalPages(): Promise<number> {
|
||||
testLogger.info('Getting total pages');
|
||||
|
||||
const pagesSelector = `${this.tableSelector} .pagination .page-item, ${this.tableSelector} .pagination button`;
|
||||
const pagesLocator = this.page.locator(pagesSelector);
|
||||
|
||||
const count = await pagesLocator.count();
|
||||
|
||||
testLogger.debug(`Total pages: ${count}`);
|
||||
return count;
|
||||
}
|
||||
|
||||
async waitForData(timeout: number = 5000): Promise<void> {
|
||||
testLogger.info(`Waiting for table data (${timeout}ms)`);
|
||||
|
||||
const rowsLocator = this.page.locator(`${this.tableSelector} tbody tr, ${this.tableSelector} .table-row`).first();
|
||||
|
||||
await rowsLocator.waitFor({ state: 'visible', timeout });
|
||||
|
||||
testLogger.info('Table data loaded');
|
||||
}
|
||||
|
||||
async isEmpty(): Promise<boolean> {
|
||||
testLogger.info('Checking if table is empty');
|
||||
|
||||
const rowCount = await this.getRowCount();
|
||||
const isEmpty = rowCount === 0;
|
||||
|
||||
testLogger.debug(`Table is empty: ${isEmpty}`);
|
||||
return isEmpty;
|
||||
}
|
||||
|
||||
async hasData(): Promise<boolean> {
|
||||
const isEmpty = await this.isEmpty();
|
||||
return !isEmpty;
|
||||
}
|
||||
|
||||
async refresh(): Promise<void> {
|
||||
testLogger.info('Refreshing table');
|
||||
|
||||
const refreshSelector = `${this.tableSelector} .refresh-button, ${this.tableSelector} button[aria-label="Refresh"]`;
|
||||
const refreshLocator = this.page.locator(refreshSelector);
|
||||
|
||||
if (await refreshLocator.isVisible()) {
|
||||
await refreshLocator.click();
|
||||
await this.page.waitForTimeout(500);
|
||||
testLogger.info('Table refreshed');
|
||||
} else {
|
||||
testLogger.warn('Refresh button not found');
|
||||
}
|
||||
}
|
||||
|
||||
private getColumnIndex(columnName: string): number {
|
||||
const columns = Array.from(this.columns.keys());
|
||||
return columns.indexOf(columnName);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user