mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-01-23 02:36:05 +00:00
243 lines
5.9 KiB
TypeScript
243 lines
5.9 KiB
TypeScript
import { Locator, Page } from '@playwright/test';
|
|
import { BasePage } from './base.page';
|
|
import { cssSelectors } from '../constants/selectors';
|
|
import { waitForAngularStability } from '../utils/waits';
|
|
|
|
const { TASK, FIRST_TASK, TASK_DONE_BTN, TASK_TEXTAREA, SUB_TASK } = cssSelectors;
|
|
|
|
export class TaskPage extends BasePage {
|
|
constructor(page: Page, testPrefix: string = '') {
|
|
super(page, testPrefix);
|
|
}
|
|
|
|
/**
|
|
* Get a task by index (1-based)
|
|
*/
|
|
getTask(index: number = 1): Locator {
|
|
if (index === 1) {
|
|
return this.page.locator(FIRST_TASK);
|
|
}
|
|
return this.page.locator(TASK).nth(index - 1);
|
|
}
|
|
|
|
/**
|
|
* Get a task by text content
|
|
*/
|
|
getTaskByText(text: string): Locator {
|
|
return this.page.locator(TASK).filter({ hasText: text });
|
|
}
|
|
|
|
/**
|
|
* Get all tasks
|
|
*/
|
|
getAllTasks(): Locator {
|
|
return this.page.locator(TASK);
|
|
}
|
|
|
|
/**
|
|
* Get task count
|
|
*/
|
|
async getTaskCount(): Promise<number> {
|
|
return await this.page.locator(TASK).count();
|
|
}
|
|
|
|
/**
|
|
* Get task title element for a specific task
|
|
*/
|
|
getTaskTitle(task: Locator): Locator {
|
|
return task.locator('task-title');
|
|
}
|
|
|
|
/**
|
|
* Mark a task as done
|
|
*/
|
|
async markTaskAsDone(task: Locator): Promise<void> {
|
|
await task.waitFor({ state: 'visible' });
|
|
await task.hover();
|
|
|
|
// Give hover effects time to settle
|
|
await this.page.waitForTimeout(100);
|
|
|
|
const doneBtn = task.locator(TASK_DONE_BTN);
|
|
await doneBtn.waitFor({ state: 'visible', timeout: 5000 });
|
|
await doneBtn.click();
|
|
|
|
await waitForAngularStability(this.page);
|
|
}
|
|
|
|
/**
|
|
* Mark the first task as done
|
|
*/
|
|
async markFirstTaskAsDone(): Promise<void> {
|
|
const firstTask = this.getTask(1);
|
|
await this.markTaskAsDone(firstTask);
|
|
}
|
|
|
|
/**
|
|
* Edit task title
|
|
*/
|
|
async editTaskTitle(task: Locator, newTitle: string): Promise<void> {
|
|
const titleElement = this.getTaskTitle(task);
|
|
await titleElement.waitFor({ state: 'visible' });
|
|
await titleElement.click();
|
|
|
|
const textarea = task.locator(TASK_TEXTAREA);
|
|
await textarea.waitFor({ state: 'visible', timeout: 3000 });
|
|
await textarea.clear();
|
|
await this.page.waitForTimeout(50);
|
|
await textarea.fill(newTitle);
|
|
await this.page.keyboard.press('Tab'); // Blur to save
|
|
await waitForAngularStability(this.page);
|
|
}
|
|
|
|
/**
|
|
* Open task detail panel (additional info)
|
|
*/
|
|
async openTaskDetail(task: Locator): Promise<void> {
|
|
await task.waitFor({ state: 'visible' });
|
|
await task.hover();
|
|
const showDetailBtn = this.page.getByRole('button', {
|
|
name: 'Show/Hide additional info',
|
|
});
|
|
await showDetailBtn.waitFor({ state: 'visible', timeout: 3000 });
|
|
await showDetailBtn.click();
|
|
await this.page.waitForTimeout(300);
|
|
}
|
|
|
|
/**
|
|
* Open detail panel for the first task
|
|
*/
|
|
async openFirstTaskDetail(): Promise<void> {
|
|
const firstTask = this.getTask(1);
|
|
await this.openTaskDetail(firstTask);
|
|
}
|
|
|
|
/**
|
|
* Get subtasks for a task
|
|
*/
|
|
getSubTasks(task: Locator): Locator {
|
|
return task.locator(SUB_TASK);
|
|
}
|
|
|
|
/**
|
|
* Get subtask count for a task
|
|
*/
|
|
async getSubTaskCount(task: Locator): Promise<number> {
|
|
return await this.getSubTasks(task).count();
|
|
}
|
|
|
|
/**
|
|
* Check if a task is marked as done
|
|
*/
|
|
async isTaskDone(task: Locator): Promise<boolean> {
|
|
const classes = await task.getAttribute('class');
|
|
return classes?.includes('isDone') || false;
|
|
}
|
|
|
|
/**
|
|
* Get done tasks
|
|
*/
|
|
getDoneTasks(): Locator {
|
|
return this.page.locator(`${TASK}.isDone`);
|
|
}
|
|
|
|
/**
|
|
* Get undone tasks
|
|
*/
|
|
getUndoneTasks(): Locator {
|
|
return this.page.locator(`${TASK}:not(.isDone)`);
|
|
}
|
|
|
|
/**
|
|
* Get done task count
|
|
*/
|
|
async getDoneTaskCount(): Promise<number> {
|
|
return await this.getDoneTasks().count();
|
|
}
|
|
|
|
/**
|
|
* Get undone task count
|
|
*/
|
|
async getUndoneTaskCount(): Promise<number> {
|
|
return await this.getUndoneTasks().count();
|
|
}
|
|
|
|
/**
|
|
* Wait for a task to appear with specific text
|
|
*/
|
|
async waitForTaskWithText(text: string, timeout: number = 10000): Promise<Locator> {
|
|
const task = this.getTaskByText(text);
|
|
await task.waitFor({ state: 'visible', timeout });
|
|
return task;
|
|
}
|
|
|
|
/**
|
|
* Wait for task count to match expected count
|
|
*/
|
|
async waitForTaskCount(expectedCount: number, timeout: number = 10000): Promise<void> {
|
|
await this.page.waitForFunction(
|
|
(args) => {
|
|
const currentCount = document.querySelectorAll('task').length;
|
|
return currentCount === args.expectedCount;
|
|
},
|
|
{ expectedCount },
|
|
{ timeout },
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get task tags
|
|
*/
|
|
getTaskTags(task: Locator): Locator {
|
|
return task.locator('tag');
|
|
}
|
|
|
|
/**
|
|
* Check if task has a specific tag
|
|
*/
|
|
async taskHasTag(task: Locator, tagName: string): Promise<boolean> {
|
|
const tags = this.getTaskTags(task);
|
|
const tagCount = await tags.count();
|
|
|
|
for (let i = 0; i < tagCount; i++) {
|
|
const tagText = await tags.nth(i).textContent();
|
|
if (tagText?.includes(tagName)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Toggle task detail panel
|
|
*/
|
|
async toggleTaskDetail(task: Locator): Promise<void> {
|
|
await task.hover();
|
|
const toggleBtn = this.page.getByRole('button', {
|
|
name: 'Show/Hide additional info',
|
|
});
|
|
await toggleBtn.click();
|
|
await this.page.waitForTimeout(300);
|
|
}
|
|
|
|
/**
|
|
* Start/Stop task time tracking
|
|
*/
|
|
async toggleTaskTimeTracking(task: Locator): Promise<void> {
|
|
await task.waitFor({ state: 'visible' });
|
|
await task.hover();
|
|
const playBtn = task.locator('.play-btn, .pause-btn').first();
|
|
await playBtn.waitFor({ state: 'visible', timeout: 3000 });
|
|
await playBtn.click();
|
|
await waitForAngularStability(this.page);
|
|
}
|
|
|
|
/**
|
|
* Get the date info element (created/completed) in task detail
|
|
*/
|
|
getDateInfo(infoPrefix: string): Locator {
|
|
return this.page
|
|
.locator('.edit-date-info')
|
|
.filter({ hasText: new RegExp(infoPrefix) });
|
|
}
|
|
}
|