mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-07-19 01:17:31 +00:00
Two root causes for failing E2E tests in CI:
1. Encryption button not visible after provider selection: The async
provider change listener loads config from IndexedDB and updates the
Formly model, but the 1000ms waitForTimeout was insufficient in CI.
Replace with polling (200ms intervals, 10s timeout) that waits for
either enable or disable encryption button to become visible.
Also removes ~130 lines of leftover debug logging from disableEncryption().
2. Drag-handle strict mode violation on parent tasks with subtasks:
task.locator('.drag-handle') matched both the parent's drag handle
and nested subtask drag handles. Add .first() to all drag-handle
locator usages to target only the parent task's own handle.
142 lines
5.1 KiB
TypeScript
142 lines
5.1 KiB
TypeScript
import { test, expect } from '../../fixtures/test.fixture';
|
|
|
|
/**
|
|
* Tests for Issue #5942: Prevent Unintended Task Deletions via Backspace
|
|
* Tests the confirmation dialog when deleting tasks
|
|
*/
|
|
test.describe('Task Delete Confirmation', () => {
|
|
test('should show confirmation dialog when deleting task via context menu (default setting)', async ({
|
|
page,
|
|
workViewPage,
|
|
}) => {
|
|
// Setup: Create a task
|
|
await workViewPage.waitForTaskList();
|
|
await workViewPage.addTask('Task to delete');
|
|
await expect(page.locator('task')).toHaveCount(1);
|
|
|
|
// Act: Right-click and select delete
|
|
await page.locator('task').first().click({ button: 'right' });
|
|
await page.locator('.mat-mdc-menu-content button.color-warn').click();
|
|
|
|
// Assert: Confirmation dialog should appear (isConfirmBeforeTaskDelete defaults to true)
|
|
const dialog = page.locator('mat-dialog-container');
|
|
await expect(dialog).toBeVisible({ timeout: 3000 });
|
|
|
|
// Verify dialog content mentions the task title
|
|
await expect(dialog).toContainText('Task to delete');
|
|
|
|
// Verify confirm button exists
|
|
const confirmBtn = page.locator('[e2e="confirmBtn"]');
|
|
await expect(confirmBtn).toBeVisible();
|
|
});
|
|
|
|
test('should delete task when confirmation is accepted', async ({
|
|
page,
|
|
workViewPage,
|
|
}) => {
|
|
// Setup: Create a task
|
|
await workViewPage.waitForTaskList();
|
|
await workViewPage.addTask('Task to delete');
|
|
await expect(page.locator('task')).toHaveCount(1);
|
|
|
|
// Act: Right-click, select delete, and confirm
|
|
await page.locator('task').first().click({ button: 'right' });
|
|
await page.locator('.mat-mdc-menu-content button.color-warn').click();
|
|
|
|
// Wait for dialog and confirm
|
|
const confirmBtn = page.locator('[e2e="confirmBtn"]');
|
|
await confirmBtn.waitFor({ state: 'visible', timeout: 3000 });
|
|
await confirmBtn.click();
|
|
|
|
// Assert: Task should be deleted
|
|
await expect(page.locator('task')).toHaveCount(0, { timeout: 5000 });
|
|
});
|
|
|
|
test('should NOT delete task when confirmation is cancelled', async ({
|
|
page,
|
|
workViewPage,
|
|
}) => {
|
|
// Setup: Create a task
|
|
await workViewPage.waitForTaskList();
|
|
await workViewPage.addTask('Task to keep');
|
|
await expect(page.locator('task')).toHaveCount(1);
|
|
|
|
// Act: Right-click, select delete, but cancel
|
|
await page.locator('task').first().click({ button: 'right' });
|
|
await page.locator('.mat-mdc-menu-content button.color-warn').click();
|
|
|
|
// Wait for dialog and cancel
|
|
const dialog = page.locator('mat-dialog-container');
|
|
await dialog.waitFor({ state: 'visible', timeout: 3000 });
|
|
|
|
// Click cancel button (first button in dialog actions)
|
|
const cancelBtn = dialog.locator('button').first();
|
|
await cancelBtn.click();
|
|
|
|
// Assert: Task should NOT be deleted
|
|
await expect(page.locator('task')).toHaveCount(1);
|
|
await expect(page.locator('task')).toContainText('Task to keep');
|
|
});
|
|
|
|
test('should delete task via keyboard shortcut with confirmation', async ({
|
|
page,
|
|
workViewPage,
|
|
}) => {
|
|
// Setup: Create a task
|
|
await workViewPage.waitForTaskList();
|
|
await workViewPage.addTask('Task to delete with keyboard');
|
|
await expect(page.locator('task')).toHaveCount(1);
|
|
|
|
// Focus the task by clicking on drag-handle (not task-title which would open edit mode)
|
|
const task = page.locator('task').first();
|
|
const dragHandle = task.locator('.drag-handle').first();
|
|
await dragHandle.waitFor({ state: 'visible', timeout: 5000 });
|
|
await dragHandle.click();
|
|
// Wait for focus to settle - the task component needs time to process the click
|
|
await page.waitForTimeout(200);
|
|
// If task isn't focused, try clicking again
|
|
const isFocused = await task.evaluate(
|
|
(el) => el === document.activeElement || el.contains(document.activeElement),
|
|
);
|
|
if (!isFocused) {
|
|
await task.focus();
|
|
await page.waitForTimeout(200);
|
|
}
|
|
|
|
// Act: Press Backspace (default delete shortcut)
|
|
await page.keyboard.press('Backspace');
|
|
|
|
// Assert: Confirmation dialog should appear
|
|
const dialog = page.locator('mat-dialog-container');
|
|
await expect(dialog).toBeVisible({ timeout: 3000 });
|
|
|
|
// Confirm deletion
|
|
const confirmBtn = page.locator('[e2e="confirmBtn"]');
|
|
await confirmBtn.click();
|
|
|
|
// Task should be deleted
|
|
await expect(page.locator('task')).toHaveCount(0, { timeout: 5000 });
|
|
});
|
|
|
|
test('should show undo snackbar after confirmed deletion', async ({
|
|
page,
|
|
workViewPage,
|
|
}) => {
|
|
// Setup: Create a task
|
|
await workViewPage.waitForTaskList();
|
|
await workViewPage.addTask('Task with undo');
|
|
await expect(page.locator('task')).toHaveCount(1);
|
|
|
|
// Act: Delete with confirmation
|
|
await page.locator('task').first().click({ button: 'right' });
|
|
await page.locator('.mat-mdc-menu-content button.color-warn').click();
|
|
|
|
const confirmBtn = page.locator('[e2e="confirmBtn"]');
|
|
await confirmBtn.waitFor({ state: 'visible', timeout: 3000 });
|
|
await confirmBtn.click();
|
|
|
|
// Assert: Undo snackbar should appear
|
|
const snackbar = page.locator('mat-snack-bar-container');
|
|
await expect(snackbar).toBeVisible({ timeout: 3000 });
|
|
});
|
|
});
|