mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-01-23 02:36:05 +00:00
The selector 'button:last-child' caused a Playwright strict mode violation by matching multiple buttons (Schedule and Cancel). Changed to 'button[color="primary"]' to specifically target the primary action button. Fixes 5 failing reminder tests that were unable to schedule tasks.
117 lines
4 KiB
TypeScript
117 lines
4 KiB
TypeScript
import type { Locator, Page } from '@playwright/test';
|
|
import type { WorkViewPage } from '../pages/work-view.page';
|
|
import { fillTimeInput } from './time-input-helper';
|
|
|
|
// Selectors for scheduling
|
|
const DETAIL_PANEL_BTN = '.show-additional-info-btn';
|
|
const DETAIL_PANEL_SELECTOR = 'dialog-task-detail-panel, task-detail-panel';
|
|
const DETAIL_PANEL_SCHEDULE_ITEM =
|
|
'task-detail-item:has(mat-icon:text("alarm")), ' +
|
|
'task-detail-item:has(mat-icon:text("today")), ' +
|
|
'task-detail-item:has(mat-icon:text("schedule"))';
|
|
const RIGHT_PANEL = '.right-panel';
|
|
const DIALOG_CONTAINER = 'mat-dialog-container';
|
|
const DIALOG_SUBMIT = 'mat-dialog-actions button[color="primary"]';
|
|
|
|
/**
|
|
* Closes the task detail panel if it's currently open.
|
|
*/
|
|
export const closeDetailPanelIfOpen = async (page: Page): Promise<void> => {
|
|
const detailPanel = page.locator(DETAIL_PANEL_SELECTOR).first();
|
|
const isVisible = await detailPanel.isVisible().catch(() => false);
|
|
if (isVisible) {
|
|
await page.keyboard.press('Escape');
|
|
await detailPanel.waitFor({ state: 'hidden', timeout: 5000 }).catch(() => {});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Opens the detail panel for a task by hovering and clicking the detail button.
|
|
*
|
|
* @param page - Playwright page object
|
|
* @param task - Locator for the task element
|
|
*/
|
|
export const openTaskDetailPanel = async (page: Page, task: Locator): Promise<void> => {
|
|
await task.waitFor({ state: 'visible' });
|
|
await task.scrollIntoViewIfNeeded();
|
|
await task.hover();
|
|
|
|
const detailBtn = task.locator(DETAIL_PANEL_BTN).first();
|
|
await detailBtn.waitFor({ state: 'visible', timeout: 5000 });
|
|
await detailBtn.click();
|
|
|
|
// Wait for detail panel to be visible
|
|
await page
|
|
.locator(RIGHT_PANEL)
|
|
.or(page.locator(DETAIL_PANEL_SELECTOR))
|
|
.first()
|
|
.waitFor({ state: 'visible', timeout: 10000 });
|
|
};
|
|
|
|
/**
|
|
* Schedules a task via the detail panel.
|
|
*
|
|
* @param page - Playwright page object
|
|
* @param task - Locator for the task element
|
|
* @param scheduleTime - Date object or timestamp for when to schedule
|
|
*/
|
|
export const scheduleTaskViaDetailPanel = async (
|
|
page: Page,
|
|
task: Locator,
|
|
scheduleTime: Date | number,
|
|
): Promise<void> => {
|
|
await openTaskDetailPanel(page, task);
|
|
|
|
// Click the schedule item
|
|
const scheduleItem = page.locator(DETAIL_PANEL_SCHEDULE_ITEM).first();
|
|
await scheduleItem.waitFor({ state: 'visible', timeout: 5000 });
|
|
await scheduleItem.click();
|
|
|
|
// Wait for schedule dialog
|
|
const dialogContainer = page.locator(DIALOG_CONTAINER);
|
|
await dialogContainer.waitFor({ state: 'visible', timeout: 10000 });
|
|
|
|
// Fill time input
|
|
await fillTimeInput(page, scheduleTime);
|
|
|
|
// Submit dialog - click the primary action button (Schedule button)
|
|
const submitBtn = page.locator(DIALOG_SUBMIT);
|
|
await submitBtn.waitFor({ state: 'visible', timeout: 5000 });
|
|
await submitBtn.click();
|
|
|
|
// Wait for dialog to close
|
|
await dialogContainer.waitFor({ state: 'hidden', timeout: 10000 });
|
|
|
|
// Close detail panel if open
|
|
await closeDetailPanelIfOpen(page);
|
|
};
|
|
|
|
// Default schedule delta: 5 seconds from now
|
|
const DEFAULT_SCHEDULE_DELTA = 5000;
|
|
|
|
/**
|
|
* Adds a task and schedules it with a reminder.
|
|
* This is a convenience function combining task creation and scheduling.
|
|
*
|
|
* @param page - Playwright page object
|
|
* @param workViewPage - WorkViewPage instance
|
|
* @param taskTitle - Title for the new task
|
|
* @param scheduleTime - Date object or timestamp for when to schedule (defaults to 5s from now)
|
|
*/
|
|
export const addTaskWithReminder = async (
|
|
page: Page,
|
|
workViewPage: WorkViewPage,
|
|
taskTitle: string,
|
|
scheduleTime: Date | number = Date.now() + DEFAULT_SCHEDULE_DELTA,
|
|
): Promise<void> => {
|
|
// Add the task
|
|
await workViewPage.addTask(taskTitle);
|
|
|
|
// Find the task by title
|
|
const escapedTitle = taskTitle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
const task = page.locator(`task:has-text("${escapedTitle}")`).first();
|
|
await task.waitFor({ state: 'visible', timeout: 10000 });
|
|
|
|
// Schedule it
|
|
await scheduleTaskViaDetailPanel(page, task, scheduleTime);
|
|
};
|