test(e2e): fix flaky project creation and context switching tests

Replace broken getByRole selector for project name input with a
direct DOM selector, replace hardcoded waitForTimeout calls with
proper element-based waits (waitForTaskList, waitFor visible, toBeEnabled).
This commit is contained in:
Johannes Millan 2026-03-10 21:56:40 +01:00
parent b69cd8a068
commit 66d051ec28
2 changed files with 20 additions and 17 deletions

View file

@ -21,7 +21,9 @@ export class ProjectPage extends BasePage {
'button[aria-label="Create New Project"], button:has-text("Create Project")',
);
this.projectAccordion = page.locator('nav-item button:has-text("Projects")');
this.projectNameInput = page.getByRole('textbox', { name: 'Project Name' });
this.projectNameInput = page
.locator('dialog-create-project input[type="text"]')
.first();
this.submitBtn = page.locator('dialog-create-project button[type=submit]');
this.workCtxMenu = page.locator('work-context-menu');
// Use more specific selector to avoid matching titles in other areas
@ -109,11 +111,13 @@ export class ProjectPage extends BasePage {
// Wait for the dialog to appear and be fully initialized
await this.projectNameInput.waitFor({ state: 'visible', timeout: 10000 });
// Fill has built-in waiting for element to be editable, but Angular forms
// need a moment to wire up. Add a small delay for form initialization.
await this.page.waitForTimeout(500);
// Wait for Angular form to wire up by checking the submit button is present
await this.submitBtn.waitFor({ state: 'visible', timeout: 5000 });
await this.projectNameInput.fill(prefixedProjectName);
// Wait for the submit button to be enabled (Angular form validation completes)
await expect(this.submitBtn).toBeEnabled({ timeout: 5000 });
await this.submitBtn.click();
// Wait for dialog to close by waiting for input to be hidden
@ -132,8 +136,11 @@ export class ProjectPage extends BasePage {
async navigateToProjectByName(projectName: string): Promise<void> {
const fullProjectName = this.applyPrefix(projectName);
// Wait for Angular to fully render after any navigation
await this.page.waitForTimeout(2000);
// Wait for the route wrapper to be visible (Angular navigation complete)
await this.page
.locator('.route-wrapper, main, [role="main"]')
.first()
.waitFor({ state: 'visible', timeout: 10000 });
// Helper function to check if we're already on the project
const isAlreadyOnProject = async (): Promise<boolean> => {

View file

@ -37,7 +37,7 @@ test.describe('Context Switching', () => {
// Switch to second project
await projectPage.navigateToProjectByName(project2);
await page.waitForTimeout(500);
await workViewPage.waitForTaskList();
// Task from project 1 should not be visible
await expect(task1).not.toBeVisible();
@ -49,7 +49,7 @@ test.describe('Context Switching', () => {
// Switch back to project 1
await projectPage.navigateToProjectByName(project1);
await page.waitForTimeout(500);
await workViewPage.waitForTaskList();
// Task from project 1 should be visible again
await expect(task1).toBeVisible();
@ -92,19 +92,17 @@ test.describe('Context Switching', () => {
const isExpanded = await tagsGroupBtn.getAttribute('aria-expanded');
if (isExpanded !== 'true') {
await tagsGroupBtn.click();
await page.waitForTimeout(500);
}
// Click on the tag
// Click on the tag - wait for it to appear after expansion
const tagTreeItem = tagPage.tagsGroup
.locator('[role="treeitem"]')
.filter({ hasText: tagName })
.first();
await tagTreeItem.waitFor({ state: 'visible', timeout: 5000 });
await tagTreeItem.click();
await page.waitForTimeout(500);
// Verify URL changed to tag view
await expect(page).toHaveURL(/tag/);
await workViewPage.waitForTaskList();
// Project task should not be visible (unless also assigned to this tag)
await expect(projectTask).not.toBeVisible();
@ -131,18 +129,16 @@ test.describe('Context Switching', () => {
const isExpanded = await tagsGroupBtn.getAttribute('aria-expanded');
if (isExpanded !== 'true') {
await tagsGroupBtn.click();
await page.waitForTimeout(500);
}
const tagTreeItem = tagPage.tagsGroup
.locator('[role="treeitem"]')
.filter({ hasText: tagName })
.first();
await tagTreeItem.waitFor({ state: 'visible', timeout: 5000 });
await tagTreeItem.click();
await page.waitForTimeout(500);
// Verify on tag view
await expect(page).toHaveURL(/tag/);
await workViewPage.waitForTaskList();
// Navigate back to TODAY tag by clicking "Today" in sidebar
const todayNavItem = page.locator(