tududi/e2e/tests/discard-changes.spec.ts
Chris b8c46e1d0d
Set verification modal on escape (#470) (#473)
* fixup! Fix priority auto (#470)

* Add translations
2025-11-03 16:27:13 +02:00

369 lines
12 KiB
TypeScript

import { test, expect } from '@playwright/test';
import {
login,
navigateAndWait,
waitForElement,
hoverAndWaitForVisible,
createUniqueEntity,
waitForNetworkIdle,
} from '../helpers/testHelpers';
// Helper to create a task
async function createTask(page, taskName) {
const taskInput = page.locator('[data-testid="new-task-input"]');
await taskInput.fill(taskName);
await taskInput.press('Enter');
await waitForNetworkIdle(page);
}
// Helper to open task edit modal
async function openTaskEditModal(page, taskName) {
const taskContainer = page
.locator('[data-testid*="task-item"]')
.filter({ hasText: taskName });
await expect(taskContainer).toBeVisible({ timeout: 15000 });
const editButton = taskContainer.locator('[data-testid*="task-edit"]');
await hoverAndWaitForVisible(taskContainer, editButton);
await editButton.click();
const taskNameInput = page.locator('[data-testid="task-name-input"]');
await waitForElement(taskNameInput, { timeout: 15000 });
return taskNameInput;
}
test.describe('Discard Changes Dialog', () => {
test('shows discard dialog when closing task modal with unsaved changes', async ({
page,
baseURL,
}) => {
const appUrl = await login(page, baseURL);
await navigateAndWait(page, appUrl + '/tasks');
// Create a task
const taskName = createUniqueEntity('Test Task for Discard');
await createTask(page, taskName);
// Open the task edit modal
await openTaskEditModal(page, taskName);
// Wait for modal to be in idle state
await expect(
page.locator('[data-testid="task-modal"][data-state="idle"]')
).toBeVisible();
// Make a change to the task name
const taskNameInput = page.locator('[data-testid="task-name-input"]');
await taskNameInput.fill(taskName + ' Modified');
// Press Escape key
await page.keyboard.press('Escape');
// Verify discard dialog appears
const discardDialog = page.locator(
'[data-testid="discard-dialog-cancel"]'
);
await expect(discardDialog).toBeVisible({ timeout: 5000 });
// Verify the "No, keep editing" button is focused
await expect(discardDialog).toBeFocused();
// Verify both buttons are visible
await expect(
page.locator('[data-testid="discard-dialog-confirm"]')
).toBeVisible();
});
test('keeps editing when clicking "No, keep editing" button', async ({
page,
baseURL,
}) => {
const appUrl = await login(page, baseURL);
await navigateAndWait(page, appUrl + '/tasks');
// Create a task
const taskName = createUniqueEntity('Test Task Keep Editing');
await createTask(page, taskName);
// Open the task edit modal
await openTaskEditModal(page, taskName);
// Wait for modal to be in idle state
await expect(
page.locator('[data-testid="task-modal"][data-state="idle"]')
).toBeVisible();
// Make a change
const taskNameInput = page.locator('[data-testid="task-name-input"]');
const modifiedName = taskName + ' Modified';
await taskNameInput.fill(modifiedName);
// Press Escape
await page.keyboard.press('Escape');
// Wait for discard dialog
const cancelButton = page.locator(
'[data-testid="discard-dialog-cancel"]'
);
await expect(cancelButton).toBeVisible({ timeout: 5000 });
// Click "No, keep editing"
await cancelButton.click();
// Verify modal is still open and changes are preserved
await expect(
page.locator('[data-testid="task-modal"]')
).toBeVisible();
await expect(taskNameInput).toHaveValue(modifiedName);
});
test('discards changes when clicking "Yes, discard" button', async ({
page,
baseURL,
}) => {
const appUrl = await login(page, baseURL);
await navigateAndWait(page, appUrl + '/tasks');
// Create a task
const taskName = createUniqueEntity('Test Task Discard');
await createTask(page, taskName);
// Open the task edit modal
await openTaskEditModal(page, taskName);
// Wait for modal to be in idle state
await expect(
page.locator('[data-testid="task-modal"][data-state="idle"]')
).toBeVisible();
// Make a change
const taskNameInput = page.locator('[data-testid="task-name-input"]');
await taskNameInput.fill(taskName + ' Modified');
// Press Escape
await page.keyboard.press('Escape');
// Wait for discard dialog
const confirmButton = page.locator(
'[data-testid="discard-dialog-confirm"]'
);
await expect(confirmButton).toBeVisible({ timeout: 5000 });
// Click "Yes, discard"
await confirmButton.click();
// Verify modal is closed
await expect(
page.locator('[data-testid="task-modal"]')
).not.toBeVisible({ timeout: 5000 });
});
test('closes modal directly when pressing Escape with no changes', async ({
page,
baseURL,
}) => {
const appUrl = await login(page, baseURL);
await navigateAndWait(page, appUrl + '/tasks');
// Create a task
const taskName = createUniqueEntity('Test Task No Changes');
await createTask(page, taskName);
// Open the task edit modal
await openTaskEditModal(page, taskName);
// Wait for modal to be in idle state
await expect(
page.locator('[data-testid="task-modal"][data-state="idle"]')
).toBeVisible();
// Don't make any changes, just press Escape
await page.keyboard.press('Escape');
// Verify modal closes immediately without showing discard dialog
await expect(
page.locator('[data-testid="task-modal"]')
).not.toBeVisible({ timeout: 5000 });
// Verify discard dialog never appeared
await expect(
page.locator('[data-testid="discard-dialog-cancel"]')
).not.toBeVisible();
});
test('closes discard dialog when pressing Escape in the dialog', async ({
page,
baseURL,
}) => {
const appUrl = await login(page, baseURL);
await navigateAndWait(page, appUrl + '/tasks');
// Create a task
const taskName = createUniqueEntity('Test Task Escape Dialog');
await createTask(page, taskName);
// Open the task edit modal
await openTaskEditModal(page, taskName);
// Wait for modal to be in idle state
await expect(
page.locator('[data-testid="task-modal"][data-state="idle"]')
).toBeVisible();
// Make a change
const taskNameInput = page.locator('[data-testid="task-name-input"]');
const modifiedName = taskName + ' Modified';
await taskNameInput.fill(modifiedName);
// Press Escape to show discard dialog
await page.keyboard.press('Escape');
// Wait for discard dialog
const cancelButton = page.locator(
'[data-testid="discard-dialog-cancel"]'
);
await expect(cancelButton).toBeVisible({ timeout: 5000 });
// Press Escape again to close the discard dialog
await page.keyboard.press('Escape');
// Verify discard dialog is closed
await expect(cancelButton).not.toBeVisible({ timeout: 5000 });
// Verify task modal is still open with changes preserved
await expect(
page.locator('[data-testid="task-modal"]')
).toBeVisible();
await expect(taskNameInput).toHaveValue(modifiedName);
});
test('shows discard dialog when closing project modal with unsaved changes', async ({
page,
baseURL,
}) => {
const appUrl = await login(page, baseURL);
await navigateAndWait(page, appUrl + '/projects');
// Click "Add Project" button
const addProjectButton = page.locator(
'button[aria-label="Add Project"]'
);
await expect(addProjectButton).toBeVisible();
await addProjectButton.click();
// Wait for modal to open
await expect(page.locator('input[name="name"]')).toBeVisible({
timeout: 10000,
});
// Type a project name
const projectName = createUniqueEntity('Test Project');
const nameInput = page.locator('[data-testid="project-name-input"]');
await nameInput.fill(projectName);
// Press Escape
await page.keyboard.press('Escape');
// Verify discard dialog appears
const discardDialog = page.locator(
'[data-testid="discard-dialog-cancel"]'
);
await expect(discardDialog).toBeVisible({ timeout: 5000 });
// Click "Yes, discard"
await page
.locator('[data-testid="discard-dialog-confirm"]')
.click();
// Verify modal is closed
await expect(
page.locator('[data-testid="project-modal"]')
).not.toBeVisible({ timeout: 5000 });
});
test('detects changes in task note field', async ({ page, baseURL }) => {
const appUrl = await login(page, baseURL);
await navigateAndWait(page, appUrl + '/tasks');
// Create a task
const taskName = createUniqueEntity('Test Task Note Change');
await createTask(page, taskName);
// Open the task edit modal
await openTaskEditModal(page, taskName);
// Wait for modal to be in idle state
await expect(
page.locator('[data-testid="task-modal"][data-state="idle"]')
).toBeVisible();
// Add content to the note field
const noteTextarea = page.locator('textarea[name="note"]');
await noteTextarea.fill('This is a test note');
// Press Escape
await page.keyboard.press('Escape');
// Verify discard dialog appears
const discardDialog = page.locator(
'[data-testid="discard-dialog-cancel"]'
);
await expect(discardDialog).toBeVisible({ timeout: 5000 });
});
test('detects changes when adding tags to task', async ({
page,
baseURL,
}) => {
const appUrl = await login(page, baseURL);
await navigateAndWait(page, appUrl + '/tasks');
// Create a task
const taskName = createUniqueEntity('Test Task Tag Change');
await createTask(page, taskName);
// Open the task edit modal
await openTaskEditModal(page, taskName);
// Wait for modal to be in idle state
await expect(
page.locator('[data-testid="task-modal"][data-state="idle"]')
).toBeVisible();
// Open tags section
const tagsSectionButton = page
.locator('button[title*="Tags"]')
.filter({ has: page.locator('svg') });
await tagsSectionButton.click();
// Wait for tag input to become visible
const tagInput = page.locator('input[placeholder*="tag"]');
await expect(tagInput).toBeVisible({ timeout: 5000 });
// Add a tag
await tagInput.fill('test-tag');
await tagInput.press('Enter');
// Wait a moment for tag to be added
await page.waitForTimeout(500);
// Press Escape
await page.keyboard.press('Escape');
// Verify discard dialog appears
const discardDialog = page.locator(
'[data-testid="discard-dialog-cancel"]'
);
await expect(discardDialog).toBeVisible({ timeout: 5000 });
});
});