refactor(e2e): extract ensureGlobalAddTaskBarOpen helper to reduce code duplication

Extract ensureGlobalAddTaskBarOpen() to e2e/utils/element-helpers.ts to avoid
duplicating the logic for opening the global add task bar across multiple tests.

This helper properly waits for the add button and input to be visible,
preventing race conditions in tests.
This commit is contained in:
Johannes Millan 2026-01-16 13:35:59 +01:00
parent cb1640bca3
commit 13d7afc458
3 changed files with 33 additions and 29 deletions

View file

@ -1,5 +1,6 @@
import { type Locator, type Page } from '@playwright/test';
import { expect, test } from '../../fixtures/test.fixture';
import { ensureGlobalAddTaskBarOpen } from '../../utils/element-helpers';
const ADD_TASK_BAR = 'add-task-bar.global';
const ADD_TASK_INPUT = `${ADD_TASK_BAR} input`;
@ -8,20 +9,6 @@ const CLEAR_DUE_BUTTON = `${ADD_TASK_BAR} [data-test="add-task-bar-clear-due-btn
const SCHEDULE_DIALOG = 'dialog-schedule-task';
const QUICK_ACCESS_BTN = '.quick-access button';
const ensureGlobalAddTaskBarOpen = async (page: Page): Promise<Locator> => {
const addTaskInput = page.locator(ADD_TASK_INPUT).first();
const isVisible = await addTaskInput.isVisible().catch(() => false);
if (!isVisible) {
const addBtn = page.locator('.tour-addBtn').first();
await addBtn.waitFor({ state: 'visible', timeout: 10000 });
await addBtn.click();
}
await addTaskInput.waitFor({ state: 'visible', timeout: 10000 });
return addTaskInput;
};
const openScheduleDialogFromBar = async (
page: Page,
): Promise<{ dialog: Locator; dueButton: Locator }> => {

View file

@ -1,4 +1,5 @@
import { expect, test } from '../../fixtures/test.fixture';
import { ensureGlobalAddTaskBarOpen } from '../../utils/element-helpers';
/**
* Global Search E2E Tests
@ -77,22 +78,15 @@ test.describe('Global Search', () => {
await workViewPage.addTask(taskName);
await expect(page.locator('task').filter({ hasText: taskName })).toBeVisible();
// Try to focus on add task input if visible
const addTaskInput = page.locator('add-task-bar.global input');
const isInputVisible = await addTaskInput
.isVisible({ timeout: 3000 })
.catch(() => false);
// Ensure the add task bar is open and get the input
const addTaskInput = await ensureGlobalAddTaskBarOpen(page);
if (isInputVisible) {
await addTaskInput.click();
// Type part of the task name
await addTaskInput.fill(testPrefix);
await page.waitForTimeout(500);
// Type part of the task name
await addTaskInput.fill(testPrefix);
await page.waitForTimeout(500);
// Clear the input
await addTaskInput.clear();
}
// Clear the input
await addTaskInput.clear();
await page.keyboard.press('Escape');

View file

@ -1,4 +1,4 @@
import type { Locator } from '@playwright/test';
import type { Locator, Page } from '@playwright/test';
/**
* Safely checks if an element is visible, returning false on any error.
@ -33,3 +33,26 @@ export const safeIsEnabled = async (locator: Locator): Promise<boolean> => {
return false;
}
};
/**
* Ensures the global add task bar is open and returns the input locator.
* If the bar is closed, it will click the add button to open it.
* Uses proper condition-based waiting to avoid race conditions.
*
* @param page - Playwright page object
* @returns Promise<Locator> - The add task input locator, ready for interaction
*/
export const ensureGlobalAddTaskBarOpen = async (page: Page): Promise<Locator> => {
const ADD_TASK_INPUT = 'add-task-bar.global input';
const addTaskInput = page.locator(ADD_TASK_INPUT).first();
const isVisible = await addTaskInput.isVisible().catch(() => false);
if (!isVisible) {
const addBtn = page.locator('.tour-addBtn').first();
await addBtn.waitFor({ state: 'visible', timeout: 10000 });
await addBtn.click();
}
await addTaskInput.waitFor({ state: 'visible', timeout: 10000 });
return addTaskInput;
};