super-productivity/e2e/tests/task-basic/task-delete-confirmation.spec.ts
Johannes Millan f3954131ac feat(tasks): add confirmation dialog before task deletion
Add optional setting to show confirmation dialog when deleting tasks
via keyboard shortcut (Backspace) or context menu. This prevents
accidental cascading deletions when users press Backspace expecting
browser-like "go back" behavior.

- Add isConfirmBeforeTaskDelete setting (defaults to true)
- Add confirmation dialog to TaskComponent.deleteTask()
- Add confirmation dialog to context menu deleteTask()
- Add setting checkbox in Settings > Misc
- Add unit and E2E tests for the feature

Closes #5942
2026-01-09 15:01:06 +01:00

129 lines
4.5 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
await page.locator('task').first().click();
// 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 });
});
});