mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-01-23 02:36:05 +00:00
fix(e2e): add robust overlay cleanup to prevent blocked clicks
Angular Material overlay backdrops were not being properly cleared between tag operations, causing subsequent clicks to timeout when overlays blocked element interactions. Added waitForOverlaysToClose() helper with multiple fallback strategies (natural close, Escape key, retry) to ensure clean state. Fixes 4 failing tests: - Tag CRUD: remove tag via context menu - Tag CRUD: delete tag and update tasks - Tag CRUD: navigate to tag view - Menu: toggle tags via submenu
This commit is contained in:
parent
7f4e5381d0
commit
5b1a843196
2 changed files with 56 additions and 18 deletions
|
|
@ -27,6 +27,48 @@ export abstract class BasePage {
|
|||
return `${this.testPrefix}-${value}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for all overlay backdrops to be removed from the DOM.
|
||||
* This is critical before interacting with elements that might be blocked by overlays.
|
||||
*/
|
||||
async waitForOverlaysToClose(): Promise<void> {
|
||||
// Try waiting for overlays to close naturally first
|
||||
const overlaysClosed = await this.page
|
||||
.waitForFunction(
|
||||
() => {
|
||||
const backdrops = document.querySelectorAll('.cdk-overlay-backdrop');
|
||||
return backdrops.length === 0;
|
||||
},
|
||||
{ timeout: 3000 },
|
||||
)
|
||||
.then(() => true)
|
||||
.catch(() => false);
|
||||
|
||||
// If overlays didn't close, press Escape and wait again
|
||||
if (!overlaysClosed) {
|
||||
await this.page.keyboard.press('Escape');
|
||||
await this.page.waitForTimeout(300);
|
||||
|
||||
// Wait again after pressing Escape
|
||||
await this.page
|
||||
.waitForFunction(
|
||||
() => {
|
||||
const backdrops = document.querySelectorAll('.cdk-overlay-backdrop');
|
||||
return backdrops.length === 0;
|
||||
},
|
||||
{ timeout: 3000 },
|
||||
)
|
||||
.catch(async () => {
|
||||
// If still not closed, press Escape again and force wait
|
||||
await this.page.keyboard.press('Escape');
|
||||
await this.page.waitForTimeout(500);
|
||||
});
|
||||
}
|
||||
|
||||
// Additional wait for any animations to complete
|
||||
await this.page.waitForTimeout(200);
|
||||
}
|
||||
|
||||
async addTask(taskName: string, skipClose = false): Promise<void> {
|
||||
// Add test prefix to task name for isolation
|
||||
const prefixedTaskName = this.applyPrefix(taskName);
|
||||
|
|
|
|||
|
|
@ -67,6 +67,9 @@ export class TagPage extends BasePage {
|
|||
* Assigns a tag to a task via context menu
|
||||
*/
|
||||
async assignTagToTask(task: Locator, tagName: string): Promise<void> {
|
||||
// Ensure no overlays are blocking before we start
|
||||
await this.waitForOverlaysToClose();
|
||||
|
||||
// Exit any edit mode by pressing Escape first
|
||||
await this.page.keyboard.press('Escape');
|
||||
await this.page.waitForTimeout(300);
|
||||
|
|
@ -113,19 +116,17 @@ export class TagPage extends BasePage {
|
|||
await tagNameInput.waitFor({ state: 'hidden', timeout: 3000 });
|
||||
}
|
||||
|
||||
// Wait for menu to close and overlay to disappear
|
||||
// The stopPropagation wrapper can prevent proper menu closing, so explicitly wait for overlay removal
|
||||
await this.page
|
||||
.locator('.cdk-overlay-backdrop')
|
||||
.waitFor({ state: 'detached', timeout: 3000 })
|
||||
.catch(() => {});
|
||||
await this.page.waitForTimeout(300);
|
||||
// Wait for all overlays to close before returning
|
||||
await this.waitForOverlaysToClose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a tag from a task via context menu
|
||||
*/
|
||||
async removeTagFromTask(task: Locator, tagName: string): Promise<void> {
|
||||
// Ensure no overlays are blocking before we start
|
||||
await this.waitForOverlaysToClose();
|
||||
|
||||
// Exit any edit mode by pressing Escape first
|
||||
await this.page.keyboard.press('Escape');
|
||||
await this.page.waitForTimeout(300);
|
||||
|
|
@ -150,13 +151,8 @@ export class TagPage extends BasePage {
|
|||
await tagOption.waitFor({ state: 'visible', timeout: 3000 });
|
||||
await tagOption.click();
|
||||
|
||||
// Wait for menu to close and overlay to disappear
|
||||
// The stopPropagation wrapper can prevent proper menu closing, so explicitly wait for overlay removal
|
||||
await this.page
|
||||
.locator('.cdk-overlay-backdrop')
|
||||
.waitFor({ state: 'detached', timeout: 3000 })
|
||||
.catch(() => {});
|
||||
await this.page.waitForTimeout(300);
|
||||
// Wait for all overlays to close before returning
|
||||
await this.waitForOverlaysToClose();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -225,10 +221,7 @@ export class TagPage extends BasePage {
|
|||
*/
|
||||
async deleteTag(tagName: string): Promise<void> {
|
||||
// Ensure any open menus/overlays are closed before starting
|
||||
await this.page
|
||||
.locator('.cdk-overlay-backdrop')
|
||||
.waitFor({ state: 'detached', timeout: 3000 })
|
||||
.catch(() => {});
|
||||
await this.waitForOverlaysToClose();
|
||||
|
||||
// Ensure Tags section is expanded
|
||||
const tagsGroupBtn = this.tagsGroup
|
||||
|
|
@ -270,5 +263,8 @@ export class TagPage extends BasePage {
|
|||
|
||||
// Wait for tag to be removed from sidebar
|
||||
await tagTreeItem.waitFor({ state: 'hidden', timeout: 5000 });
|
||||
|
||||
// Wait for all overlays to close before returning
|
||||
await this.waitForOverlaysToClose();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue