- Reorganize into apps/, packages/, docs/, e2e/, pocketbase/ directories - Add Dockerfiles for web, worker, and PocketBase services - Add docker-compose.yml for local orchestration - Add turbo.json for monorepo task management - Add Playwright e2e test infrastructure - Add PocketBase backend with migrations - Remove Vite/Next.js/ESLint/PostCSS config files - Update package.json with workspace dependencies - Add .env.example and .dockerignore
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/);
|
||
});
|
||
});
|
||
});
|