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.