106 lines
3.7 KiB
TypeScript
106 lines
3.7 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
||||
|
|
import { login, logout, goToLogin } from './helpers/auth';
|
|||
|
|
import { TEST_USER, INVALID_USER } from './helpers/fixtures';
|
|||
|
|
|
|||
|
|
test.describe('Authentication Flow', () => {
|
|||
|
|
test.describe('Login', () => {
|
|||
|
|
test('should login with valid credentials and redirect to dashboard', async ({ page }) => {
|
|||
|
|
await goToLogin(page);
|
|||
|
|
|
|||
|
|
// Verify login page loaded
|
|||
|
|
await expect(page.getByRole('heading', { name: /project e/i })).toBeVisible();
|
|||
|
|
await expect(page.getByRole('button', { name: /sign in/i })).toBeVisible();
|
|||
|
|
|
|||
|
|
// Fill in credentials
|
|||
|
|
await page.getByLabel('Email').fill(TEST_USER.email);
|
|||
|
|
await page.getByLabel('Password').fill(TEST_USER.password);
|
|||
|
|
await page.getByRole('button', { name: /sign in/i }).click();
|
|||
|
|
|
|||
|
|
// Should redirect to dashboard
|
|||
|
|
await page.waitForURL('**/dashboard', { timeout: 15_000 });
|
|||
|
|
await expect(page).toHaveURL(/\/dashboard/);
|
|||
|
|
|
|||
|
|
// Dashboard should be visible
|
|||
|
|
await expect(page.getByRole('heading', { name: /dashboard/i })).toBeVisible();
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('should show error with invalid credentials', async ({ page }) => {
|
|||
|
|
await goToLogin(page);
|
|||
|
|
|
|||
|
|
await page.getByLabel('Email').fill(INVALID_USER.email);
|
|||
|
|
await page.getByLabel('Password').fill(INVALID_USER.password);
|
|||
|
|
await page.getByRole('button', { name: /sign in/i }).click();
|
|||
|
|
|
|||
|
|
// Should still be on login page
|
|||
|
|
await expect(page).toHaveURL(/\/login/);
|
|||
|
|
|
|||
|
|
// Should show error message (toast or inline)
|
|||
|
|
// The app uses sonner toasts for errors
|
|||
|
|
await expect(
|
|||
|
|
page.getByText(/login failed|invalid/i),
|
|||
|
|
).toBeVisible({ timeout: 10_000 });
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('should prevent submitting empty form', async ({ page }) => {
|
|||
|
|
await goToLogin(page);
|
|||
|
|
|
|||
|
|
const submitButton = page.getByRole('button', { name: /sign in/i });
|
|||
|
|
await expect(submitButton).toBeVisible();
|
|||
|
|
|
|||
|
|
// HTML5 required attribute should prevent submission
|
|||
|
|
// The email field is required
|
|||
|
|
await page.getByLabel('Password').fill('somepassword');
|
|||
|
|
await submitButton.click();
|
|||
|
|
|
|||
|
|
// Should stay on login page (HTML5 validation prevents submit)
|
|||
|
|
await expect(page).toHaveURL(/\/login/);
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test.describe('Logout', () => {
|
|||
|
|
test('should logout and redirect to login page', async ({ page }) => {
|
|||
|
|
// First login
|
|||
|
|
await login(page);
|
|||
|
|
await expect(page).toHaveURL(/\/dashboard/);
|
|||
|
|
|
|||
|
|
// Clear cookies to simulate logout
|
|||
|
|
await logout(page);
|
|||
|
|
|
|||
|
|
// Navigate to dashboard – should redirect to login
|
|||
|
|
await page.goto('/dashboard');
|
|||
|
|
await page.waitForURL('**/login', { timeout: 10_000 });
|
|||
|
|
await expect(page).toHaveURL(/\/login/);
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test.describe('Session persistence', () => {
|
|||
|
|
test('should stay logged in after page refresh', async ({ page }) => {
|
|||
|
|
await login(page);
|
|||
|
|
await expect(page).toHaveURL(/\/dashboard/);
|
|||
|
|
|
|||
|
|
// Refresh the page
|
|||
|
|
await page.reload();
|
|||
|
|
|
|||
|
|
// Should still be on dashboard
|
|||
|
|
await expect(page).toHaveURL(/\/dashboard/);
|
|||
|
|
await expect(page.getByRole('heading', { name: /dashboard/i })).toBeVisible();
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test.describe('Protected routes', () => {
|
|||
|
|
test('should redirect unauthenticated users from dashboard to login', async ({ page }) => {
|
|||
|
|
await logout(page);
|
|||
|
|
await page.goto('/dashboard');
|
|||
|
|
await page.waitForURL('**/login', { timeout: 10_000 });
|
|||
|
|
await expect(page).toHaveURL(/\/login/);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('should redirect unauthenticated users from tasks to login', async ({ page }) => {
|
|||
|
|
await logout(page);
|
|||
|
|
await page.goto('/tasks');
|
|||
|
|
await page.waitForURL('**/login', { timeout: 10_000 });
|
|||
|
|
await expect(page).toHaveURL(/\/login/);
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
});
|