diff --git a/fe/e2e/auth.spec.ts b/fe/e2e/auth.spec.ts new file mode 100644 index 0000000..4ed3f8f --- /dev/null +++ b/fe/e2e/auth.spec.ts @@ -0,0 +1,150 @@ +import { test, expect, Page } from '@playwright/test'; + +const BASE_URL = 'http://localhost:5173'; // Assuming Vite's default dev server URL + +// Function to generate a unique email for signup +const generateUniqueEmail = () => `testuser_${Date.now()}@example.com`; + +let userEmail = ''; // Will be set by signup test and used by login test +const userPassword = 'Password123!'; + +test.describe.configure({ mode: 'serial' }); // Run tests in this file serially + +test.beforeAll(async () => { + userEmail = generateUniqueEmail(); // Generate unique email once for the suite +}); + +test('1. Successful User Signup', async ({ page }) => { + await page.goto(`${BASE_URL}/auth/signup`); + + // Fill out the signup form + await page.locator('input#name').fill('Test User'); + await page.locator('input#email').fill(userEmail); + await page.locator('input#password').fill(userPassword); + await page.locator('input#confirmPassword').fill(userPassword); + + // Submit the form + await page.locator('form button[type="submit"]:has-text("Sign Up")').click(); + + // Verify redirection to the login page + await page.waitForURL(`${BASE_URL}/auth/login`); + await expect(page).toHaveURL(`${BASE_URL}/auth/login`); + + // Optionally, verify a success message if one exists on the login page after signup + // For example, if a query param or a notification store message is used. + // This example assumes direct redirection without a specific persistent message on login page itself. + // A common pattern is a toast notification, which might be harder to assert reliably here without more specific selectors. + // For now, redirection is the primary assertion. + // We can also check if the email field on login page is pre-filled if that's a feature. + // await expect(page.locator('input#email')).toHaveValue(userEmail); // Uncomment if this is expected +}); + +test('2. Successful Login', async ({ page }) => { + await page.goto(`${BASE_URL}/auth/login`); + + // Fill out the login form with credentials from the signup test + await page.locator('input#email').fill(userEmail); + await page.locator('input#password').fill(userPassword); + + // Submit the form + await page.locator('form button[type="submit"]:has-text("Login")').click(); + + // Verify redirection to a main application page (e.g., /chores or /groups or /) + // Using a regex to be flexible about the exact landing page after login. + await page.waitForURL(new RegExp(`${BASE_URL}/(chores|groups|dashboard)?/?$`)); + // More specific check if you know the exact page: + // await page.waitForURL(`${BASE_URL}/chores`); + // await expect(page).toHaveURL(`${BASE_URL}/chores`); + + // Assert the presence of an element indicating successful login. + // This could be a logout button, user's name, etc. + // I need to find what the actual "logged in" indicator is. + // Let's assume there's a layout component for authenticated routes that includes a common header or nav. + // For now, let's look for a button that might be "Logout" or "Account" or "Profile". + // Or a common page title on the dashboard/chores page. + // Example: Check for a common header/title on a likely landing page. + // If the /chores page has an H1 "All Chores", we can check for that. + const mainHeading = page.locator('h1'); // A general h1 + await expect(mainHeading.first()).toBeVisible({ timeout: 10000 }); // Wait for page to load + // If it's /chores, the heading is "All Chores" + // If it's /groups, the heading is "Groups" + // If it's /dashboard, it might be "Dashboard" + // This assertion needs to be tailored to the actual application. + // For now, just ensuring some H1 is visible on the new page is a basic check. + + // A more reliable check would be a specific logout button, if its selector is known. + // await expect(page.locator('nav button:has-text("Logout")')).toBeVisible(); +}); + +test('3. Successful Logout', async ({ page }) => { + // First, ensure the user is logged in (or perform login steps) + // This test depends on the previous login test having set cookies correctly. + // If running this test standalone, you'd need to programmatically log in first. + await page.goto(`${BASE_URL}/auth/login`); + await page.locator('input#email').fill(userEmail); + await page.locator('input#password').fill(userPassword); + await page.locator('form button[type="submit"]:has-text("Login")').click(); + + // Wait for navigation to a logged-in page (e.g., /chores) + await page.waitForURL(new RegExp(`${BASE_URL}/(chores|groups|dashboard)?/?$`)); + await expect(page.locator('h1').first()).toBeVisible({ timeout: 10000 }); + + + // Find and click the logout button. + // The logout button's selector needs to be determined by inspecting the actual application. + // Common places: Navbar, User dropdown, Account page. + // Let's try to find it on the AccountPage as a common location. + // First navigate to account page, then logout. + // This assumes a link/button to the account page is available. + // Let's assume a common pattern for a navbar link to Account page. + // If no global nav, we might need a more specific way to trigger logout. + // For now, let's assume there is an Account page link and then a logout button there. + // This is a placeholder and likely needs adjustment. + + // Attempt to find a logout button. This selector is a guess. + // A better approach is to have a data-testid for logout button. + // Let's first try to navigate to the account page assuming there's a link. + // This part is highly dependent on the app's structure. + // For now, I'll assume the ChoresPage might have a direct logout or an account link. + // If AccountPage has a logout button: + // await page.goto(`${BASE_URL}/account`); + // const logoutButton = page.locator('button:has-text("Logout")'); // Generic + + // Given the current app structure, a logout button is not globally visible. + // Let's assume the "Account Settings" page (AccountPage.vue) should have it. + // However, AccountPage.vue itself doesn't show a logout button in its template. + // The authStore.logout() method does router.push('/auth/login'). + // This implies that whatever button calls authStore.logout() would be the logout trigger. + + // Let's assume there is a navigation element that becomes visible after login, + // which contains a link to the account page or a direct logout button. + // This is a common pattern missing from the current file analysis. + // For the E2E test to proceed, I'll need to make an assumption or the app needs a clear logout path. + + // Click the user menu button to reveal the dropdown + await page.locator('.user-menu-button').click(); + + // Wait for the dropdown menu to be visible (optional, but good practice if animations are present) + await page.locator('.dropdown-menu').waitFor({ state: 'visible' }); + + // Click the "Logout" link within the dropdown menu + await page.locator('.dropdown-menu a:has-text("Logout")').click(); + + + // Verify redirection to the login page + await page.waitForURL(`${BASE_URL}/auth/login`); + await expect(page).toHaveURL(`${BASE_URL}/auth/login`); + + // Optionally, verify that elements indicating a logged-in state are gone. + // For example, if a user menu was present, it should now be gone. + // await expect(page.locator('#user-menu')).not.toBeVisible(); +}); + +// To make login/logout tests more robust if run independently or if state between tests is an issue: +// - Consider using Playwright's global setup to create a user. +// - Or, use page.context().addCookies() and page.context().addInitScript() to set auth state programmatically +// before tests that require a logged-in user, bypassing UI login for speed and reliability. +// However, the task asks for testing the UI login flow. +// - The `test.describe.configure({ mode: 'serial' });` makes the tests run in order, +// allowing the login test to use credentials from signup, and logout to use the session from login. +// This is acceptable for a small suite like this. diff --git a/fe/e2e/groups.spec.ts b/fe/e2e/groups.spec.ts new file mode 100644 index 0000000..52ada57 --- /dev/null +++ b/fe/e2e/groups.spec.ts @@ -0,0 +1,123 @@ +import { test, expect, Page } from '@playwright/test'; + +const BASE_URL = 'http://localhost:5173'; // Assuming Vite's default dev server URL + +// Credentials - These should ideally come from a shared config or be set by a global setup. +// For this example, we'll assume the user from auth.spec.ts exists or we use a known test user. +// If auth.spec.ts is guaranteed to run first and set a global userEmail, that could be used. +// For robustness, let's define specific credentials for this test suite, assuming this user exists. +// Or, better, use a dynamic user from auth.spec.ts if possible or a global setup. +// For now, hardcoding for clarity, but this implies this user MUST exist. +const userEmailForGroupTests = `testuser_${process.env.PLAYWRIGHT_WORKER_INDEX || 0}@example.com`; // Make it somewhat unique per worker if run in parallel +const userPasswordForGroupTests = 'Password123!'; + +// Helper to generate unique group names +const generateUniqueGroupName = () => `Test Group ${Date.now()}`; +let currentGroupName = ''; // To store the name of the group created in the test + +test.describe.configure({ mode: 'serial' }); // Run group tests serially + +// --- Login before all tests in this suite --- +test.beforeAll(async ({ browser }) => { + // Create a new page context for login to avoid interference with test-specific contexts + const page = await browser.newPage(); + await page.goto(`${BASE_URL}/auth/login`); + await page.locator('input#email').fill(userEmailForGroupTests); + await page.locator('input#password').fill(userPasswordForGroupTests); + await page.locator('form button[type="submit"]:has-text("Login")').click(); + // Wait for navigation to a main page, indicating successful login + await page.waitForURL(new RegExp(`${BASE_URL}/(chores|groups|dashboard)?/?$`)); + // Save storage state (cookies, localStorage) after login + // This state will be used by subsequent tests in this file. + await page.context().storageState({ path: `e2e/.auth/user-${process.env.PLAYWRIGHT_WORKER_INDEX || 0}.json` }); + await page.close(); +}); + +// Use the saved authentication state for all tests in this file +test.use({ storageState: `e2e/.auth/user-${process.env.PLAYWRIGHT_WORKER_INDEX || 0}.json` }); + + +test('1. Create a New Group', async ({ page }) => { + currentGroupName = generateUniqueGroupName(); + await page.goto(`${BASE_URL}/groups`); // Assuming /groups is the main groups page + + // Updated "Create New Group" button selector + const createGroupButton = page.getByRole('button', { name: 'Create New Group' }) + .or(page.locator('.neo-create-group-card:has-text("+ Group")')); // This part remains the same as it's an OR condition + await createGroupButton.click(); + + // Updated modal input for group name selector + await page.locator('input#newGroupNameInput').fill(currentGroupName); + // Optionally fill description if available and required/tested + // await page.locator('textarea#group-description').fill('This is a test group description.'); + + // Updated modal submit button selector + await page.locator('.modal-footer').getByRole('button', { name: 'Create' }).click(); + + // Verify success notification (adjust selector for your notification component) + const successNotification = page.locator('.notification.success, .alert.alert-success, [data-testid="success-notification"]'); + await expect(successNotification).toBeVisible({ timeout: 10000 }); + await expect(successNotification).toContainText(/Group created successfully|Group saved successfully/i); + + + // Verify that the new group appears in the list of groups on the page + // Adjust selector for group items and how group name is displayed + await expect(page.locator(`:text("${currentGroupName}")`).first()).toBeVisible(); + // More specific: await expect(page.locator(`.group-list-item:has-text("${currentGroupName}")`)).toBeVisible(); +}); + +test('2. View Group Details', async ({ page }) => { + await page.goto(`${BASE_URL}/groups`); + + // Click on the group created in the previous test to navigate to its detail page + // Updated group card selector (using :has-text for specificity) and group name header (h1.neo-group-header) + const groupCard = page.locator(`.neo-group-card:has-text("${currentGroupName}")`); + // The h1.neo-group-header is inside the card, so this is for verification if needed, not for clicking the card. + // For clicking, the groupCard selector itself is usually sufficient if the card is clickable. + await groupCard.click(); + + // Verify redirection to the group detail page (URL might be like /groups/some-id) + await page.waitForURL(new RegExp(`${BASE_URL}/groups/\\d+`)); // \d+ matches one or more digits for ID + + // Verify that the group name is displayed on the detail page + // Updated group name display selector on GroupDetailPage.vue + const groupNameDisplay = page.locator('main h1'); // This was already good and specific enough + await expect(groupNameDisplay.first()).toContainText(currentGroupName); + + // (Optional) Verify other elements like member list or chore list if applicable + // await expect(page.locator('.member-list')).toBeVisible(); +}); + +// No changes needed for these skipped tests as per the analysis that UI doesn't exist. +// The existing console.warn messages are appropriate. +test.skip('3. Update Group Name', async ({ page }) => { // Intentionally skipped + // Reason: UI elements for editing group name/description (e.g., an "Edit Group" button + // or editable fields) are not present on the GroupDetailPage.vue based on prior file inspection. + // If these features are added, this test should be implemented. + console.warn('Skipping test "3. Update Group Name": UI for editing group details not found on GroupDetailPage.vue.'); + // Placeholder for future implementation: + // await page.goto(`${BASE_URL}/groups`); + // await page.locator(`.neo-group-card:has-text("${currentGroupName}")`).click(); + // await page.waitForURL(new RegExp(`${BASE_URL}/groups/\\d+`)); + // await page.locator('button:has-text("Edit Group")').click(); // Assuming an edit button + // const updatedGroupName = `${currentGroupName} - Updated`; + // await page.locator('input#groupNameModalInput').fill(updatedGroupName); // Assuming modal input + // await page.locator('button:has-text("Save Changes")').click(); // Assuming save button + // await expect(page.locator('main h1').first()).toContainText(updatedGroupName); + // currentGroupName = updatedGroupName; +}); + +test.skip('4. Delete a Group', async ({ page }) => { // Intentionally skipped + // Reason: UI element for deleting an entire group (e.g., a "Delete Group" button) + // is not present on the GroupDetailPage.vue based on prior file inspection. + // If this feature is added, this test should be implemented. + console.warn('Skipping test "4. Delete a Group": UI for deleting group not found on GroupDetailPage.vue.'); + // Placeholder for future implementation: + // await page.goto(`${BASE_URL}/groups`); + // await page.locator(`.neo-group-card:has-text("${currentGroupName}")`).click(); + // await page.waitForURL(new RegExp(`${BASE_URL}/groups/\\d+`)); + // page.on('dialog', dialog => dialog.accept()); // Handle confirmation dialog + // await page.locator('button:has-text("Delete Group")').click(); // Assuming a delete button + // await page.waitForURL(`${BASE_URL}/groups`); + // await expect(page.locator(`.neo-group-card:has-text("${currentGroupName}")`)).not.toBeVisible(); +}); diff --git a/fe/e2e/lists.spec.ts b/fe/e2e/lists.spec.ts new file mode 100644 index 0000000..b05b4a8 --- /dev/null +++ b/fe/e2e/lists.spec.ts @@ -0,0 +1,231 @@ +import { test, expect, Page } from '@playwright/test'; + +const BASE_URL = 'http://localhost:5173'; + +// Credentials & Group Info - These should align with what groups.spec.ts uses/creates +// or be from a dedicated test setup. For serial execution, we can assume groups.spec.ts ran. +// However, for robustness, especially if these files can run independently or in different orders, +// this shared state is problematic. +// A better approach: +// 1. Global setup that creates a user and a group, storing their IDs/names. +// 2. This file fetches that info or uses fixed, known test data. +// For this task, we'll assume groups.spec.ts has run and created a group. +// We'll need to know the name of that group. +// Let's define them here, assuming this user and group exist. +const userEmailForListTests = `testuser_${process.env.PLAYWRIGHT_WORKER_INDEX || 0}@example.com`; // Must match user from groups.spec.ts's login +const userPasswordForListTests = 'Password123!'; // Must match +let groupNameForListTests = `Test Group ${process.env.PLAYWRIGHT_GROUP_TIMESTAMP || Date.now()}`; // This needs to be the group name from groups.spec.ts +let createdListId = ''; // To store the ID of the list created +let createdListName = ''; + +// Helper to generate unique list/item names +const generateUniqueName = (prefix: string) => `${prefix} ${Date.now()}`; + +test.describe.configure({ mode: 'serial' }); + +// --- Login before all tests in this suite --- +// This re-uses the login logic from groups.spec.ts. +// It's better to have a shared login function or rely on global setup. +test.beforeAll(async ({ browser }) => { + const page = await browser.newPage(); + await page.goto(`${BASE_URL}/auth/login`); + await page.locator('input#email').fill(userEmailForListTests); + await page.locator('input#password').fill(userPasswordForListTests); + await page.locator('form button[type="submit"]:has-text("Login")').click(); + await page.waitForURL(new RegExp(`${BASE_URL}/(chores|groups|dashboard)?/?$`)); + await page.context().storageState({ path: `e2e/.auth/list-user-${process.env.PLAYWRIGHT_WORKER_INDEX || 0}.json` }); + + // After login, ensure the target group exists or create it. + // For simplicity, we'll assume groups.spec.ts created a group. + // We need its name. A robust way is to query the API or have a fixed test group. + // For now, we'll try to use a dynamically set groupName during the first test if possible, + // or rely on a known naming pattern if groups.spec.ts uses Date.now() in a predictable way. + // This is a known limitation of inter-file dependencies without a proper global setup. + // The `groupNameForListTests` will be updated by the first list test if it creates a new group for lists. + // Alternatively, fetch the first group name from the page. + await page.goto(`${BASE_URL}/groups`); + const firstGroupCard = page.locator('.neo-group-card h1.neo-group-header').first(); + if (await firstGroupCard.isVisible()) { + const name = await firstGroupCard.textContent(); + if (name) groupNameForListTests = name.trim(); + else console.warn("Could not determine group name for list tests, using default or generated."); + } else { + console.warn("No groups found for list tests, creating a new one might be needed or tests will fail."); + // If no groups, these tests might not be able to proceed correctly. + // For now, we'll assume `groupNameForListTests` is somewhat valid or will be set. + } + console.log(`Using group: "${groupNameForListTests}" for list tests.`); + await page.close(); +}); + +test.use({ storageState: `e2e/.auth/list-user-${process.env.PLAYWRIGHT_WORKER_INDEX || 0}.json` }); + +test('1. Create a New List within a Group', async ({ page }) => { + createdListName = generateUniqueName('My Test List'); + await page.goto(`${BASE_URL}/groups`); + + // Find the specific group card + const groupCard = page.locator(`.neo-group-card:has-text("${groupNameForListTests}")`); + if (!(await groupCard.isVisible())) { + throw new Error(`Group card for "${groupNameForListTests}" not found. Ensure this group exists and was created by groups.spec.ts or a setup step.`); + } + + // Click the "List" button on that group card to open CreateListModal + await groupCard.getByRole('button', { name: 'List' }).click(); + + // CreateListModal.vue interaction + await expect(page.locator('input#listName')).toBeVisible(); + await page.locator('input#listName').fill(createdListName); + // Group should be pre-selected if modal is opened from group context. + // We can verify this if the select#selectedGroup is disabled or has the correct value. + // For now, assume it's correctly handled by the component. + + await page.locator('.modal-footer button[type="submit"]:has-text("Create")').click(); + + // Verify success notification + const successNotification = page.locator('.notification.success, .alert.alert-success, [data-testid="success-notification"]'); + await expect(successNotification).toBeVisible({ timeout: 10000 }); + await expect(successNotification).toContainText(/List created successfully/i); + + // Verify the new list appears on the GroupDetailPage.vue (within the embedded ListsPage.vue section) + // After list creation, user is usually redirected to the group detail page or the list page itself. + // Let's assume redirection to Group Detail Page, then find the list. + // The URL should be /groups/:id + await page.waitForURL(new RegExp(`${BASE_URL}/groups/\\d+`)); + + // ListsPage.vue is embedded. We need to find the list name. + // Assuming ListsPage renders list names within elements having a class like '.list-name' or similar. + // Or, if ListsPage uses cards similar to GroupsPage: + const newListInGroupPage = page.locator(`.list-card-link:has-text("${createdListName}"), .list-group-item:has-text("${createdListName}")`).first(); + await expect(newListInGroupPage).toBeVisible(); + + // Store list ID for next tests by capturing it from URL or an element attribute + // For example, if clicking the list navigates to /groups/:gid/lists/:listId + await newListInGroupPage.click(); + await page.waitForURL(new RegExp(`${BASE_URL}/groups/\\d+/lists/\\d+`)); + const url = page.url(); + const match = url.match(/lists\/(\d+)/); + if (match && match[1]) { + createdListId = match[1]; + } else { + throw new Error('Could not extract list ID from URL after creation.'); + } + expect(createdListId).toBeTruthy(); +}); + +test('2. View a List and its (empty) items', async ({ page }) => { + expect(createdListId, "List ID must be set from previous test").toBeTruthy(); + expect(createdListName, "List Name must be set from previous test").toBeTruthy(); + + // Navigate directly to the list page (or click through from group detail if preferred) + await page.goto(`${BASE_URL}/groups/some-group-id/lists/${createdListId}`); // some-group-id needs to be the actual group ID + // Since group ID isn't easily passed from previous test, we'll navigate from groups page: + await page.goto(`${BASE_URL}/groups`); + const groupCard = page.locator(`.neo-group-card:has-text("${groupNameForListTests}")`); + await groupCard.click(); + await page.waitForURL(new RegExp(`${BASE_URL}/groups/\\d+`)); + + const listLink = page.locator(`.list-card-link:has-text("${createdListName}"), .list-group-item:has-text("${createdListName}")`).first(); + await listLink.click(); + await page.waitForURL(new RegExp(`${BASE_URL}/groups/\\d+/lists/${createdListId}`)); + + // Verify the list name is displayed (from ListDetailPage.vue) + const listNameDisplay = page.locator('h1.neo-title'); + await expect(listNameDisplay).toContainText(createdListName); + + // Verify items within the list are displayed (should be empty initially) + // From ListDetailPage.vue: "No Items Yet!" message + await expect(page.locator('.neo-empty-state:has-text("No Items Yet!")')).toBeVisible(); +}); + +test('3. Add an Item to a List', async ({ page }) => { + expect(createdListId).toBeTruthy(); + expect(createdListName).toBeTruthy(); + + // Navigate to the list detail page + await page.goto(`${BASE_URL}/groups/some-group-id/lists/${createdListId}`); // Replace some-group-id + // Simplified navigation: + await page.goto(`${BASE_URL}/groups`); + await page.locator(`.neo-group-card:has-text("${groupNameForListTests}")`).click(); + await page.waitForURL(new RegExp(`${BASE_URL}/groups/\\d+`)); + await page.locator(`.list-card-link:has-text("${createdListName}"), .list-group-item:has-text("${createdListName}")`).first().click(); + await page.waitForURL(new RegExp(`${BASE_URL}/groups/\\d+/lists/${createdListId}`)); + + const newItemName = generateUniqueName('Test Item'); + // Add item using the form (from ListDetailPage.vue) + await page.locator('input.neo-new-item-input[placeholder="Add a new item"]').fill(newItemName); + await page.locator('button.neo-add-button:has-text("Add")').click(); + + // Verify success notification (if any - ListDetailPage adds item directly to list.value.items) + // The component doesn't seem to show a notification for item add, but for other actions. + // We'll verify the item appears. + + // Verify the item appears in the list + const newItemInList = page.locator(`.neo-item .neo-item-name:has-text("${newItemName}")`); + await expect(newItemInList).toBeVisible(); +}); + +test('4. Mark an Item as Completed', async ({ page }) => { + expect(createdListId).toBeTruthy(); + expect(createdListName).toBeTruthy(); + + // Navigate to the list detail page + await page.goto(`${BASE_URL}/groups`); + await page.locator(`.neo-group-card:has-text("${groupNameForListTests}")`).click(); + await page.waitForURL(new RegExp(`${BASE_URL}/groups/\\d+`)); + await page.locator(`.list-card-link:has-text("${createdListName}"), .list-group-item:has-text("${createdListName}")`).first().click(); + await page.waitForURL(new RegExp(`${BASE_URL}/groups/\\d+/lists/${createdListId}`)); + + // Assuming the item added in the previous test is the first one. + const firstItem = page.locator('.neo-item').first(); + const itemNameElement = firstItem.locator('.neo-item-name'); + const itemName = await itemNameElement.textContent(); // Get name for confirmation dialog + + const checkbox = firstItem.locator('input[type="checkbox"]'); + await checkbox.check(); // This will trigger @change which calls confirmUpdateItem + + // Handle confirmation dialog (from ListDetailPage.vue) + await expect(page.locator('.modal-container.confirm-modal')).toBeVisible(); + await expect(page.locator('.modal-body')).toContainText(`Mark "${itemName}" as complete?`); + await page.locator('.modal-footer button:has-text("Confirm")').click(); + + // Verify the item's appearance changes (e.g., strikethrough, class 'neo-item-complete') + await expect(firstItem).toHaveClass(/neo-item-complete/); + // Also check if checkbox is now checked (it should be due to optimistic update + confirmation) + await expect(checkbox).toBeChecked(); + + // Optionally, verify success notification if one is shown for item update. + // The component's updateItem doesn't show a notification on success currently. +}); + +test('5. Delete a List', async ({ page }) => { + // Based on ListDetailPage.vue analysis, there is no "Delete List" button. + // This test needs to be skipped unless the UI for deleting a list is found elsewhere + // or added to ListDetailPage.vue. + test.skip(true, "UI for deleting a list is not present on ListDetailPage.vue or ListsPage.vue based on current analysis."); + + console.warn('Skipping test "5. Delete a List": UI for deleting a list not found.'); + // Placeholder for future implementation: + // expect(createdListId).toBeTruthy(); + // expect(createdListName).toBeTruthy(); + + // Navigate to where delete button would be (e.g., group detail page or list detail page) + // await page.goto(`${BASE_URL}/groups`); // Or directly to list page if delete is there + // ... click through to the list or group page ... + + // const deleteButton = page.locator('button:has-text("Delete List")'); // Selector for delete list button + // await deleteButton.click(); + + // Handle confirmation dialog + // page.on('dialog', dialog => dialog.accept()); // For browser confirm + // Or: await page.locator('.confirm-delete-modal button:has-text("Confirm")').click(); // For custom modal + + // Verify success notification + // const successNotification = page.locator('.notification.success, .alert.alert-success, [data-testid="success-notification"]'); + // await expect(successNotification).toBeVisible({ timeout: 10000 }); + // await expect(successNotification).toContainText(/List deleted successfully/i); + + // Verify the list is removed (e.g., from GroupDetailPage or main lists page) + // await page.waitForURL(new RegExp(`${BASE_URL}/groups/\\d+`)); // Assuming redirect to group detail + // await expect(page.locator(`.list-card-link:has-text("${createdListName}")`)).not.toBeVisible(); +});