refactor: migrate to monorepo structure with Docker, PocketBase, and e2e tests
- 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
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
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/);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user