520be53901
- Add proper Alembic initial migration (0001_initial_schema.py) - Migrate refresh tokens from JSON file to SQLite (RefreshTokenTable) - Remove Neko-Sama provider entirely (redirects to Gupy, not a host) - Fix provider health check always showing UNKNOWN - Run check_all_health() on startup - Fix POST /providers/health/check background task bug - Add HTMX refresh after manual health check trigger - Fix anime search relevance scoring with MIN_RELEVANCE_THRESHOLD=0.5 - Replace bare 'except:' with 'except Exception:' across codebase - Add Playwright E2E test suite (12 tests, auth setup, helpers) - Fix toast container blocking clicks via pointer-events: none - Remove obsolete Jest/Vite test files and config - Clean up obsolete test_watchlist scripts - Update sonarr model comment for active providers
94 lines
3.2 KiB
TypeScript
94 lines
3.2 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
import { TEST_USER, login } from './helpers';
|
|
|
|
test.describe('Auth Flow', () => {
|
|
test('login success - redirects to home and stores token', async ({ page }) => {
|
|
await login(page, TEST_USER.username, TEST_USER.password);
|
|
|
|
// Verify redirect to /web
|
|
await expect(page).toHaveURL(/\/web/);
|
|
|
|
// Verify token stored
|
|
const token = await page.evaluate(() => localStorage.getItem('auth_token'));
|
|
expect(token).toBeTruthy();
|
|
});
|
|
|
|
test('login with wrong credentials shows error', async ({ page }) => {
|
|
await page.goto('/login');
|
|
await page.fill('#loginUsername', 'nonexistentuser_xyz');
|
|
await page.fill('#loginPassword', 'wrongpassword');
|
|
|
|
const [response] = await Promise.all([
|
|
page.waitForResponse((resp) => resp.url().includes('/api/auth/login')),
|
|
page.click('#loginSubmit'),
|
|
]);
|
|
|
|
expect(response.status()).toBe(401);
|
|
|
|
// Error message should be visible
|
|
const errorLocator = page.locator('#authError');
|
|
await expect(errorLocator).toBeVisible();
|
|
await expect(errorLocator).toContainText(/incorrect|mot de passe|connexion/i);
|
|
});
|
|
|
|
test('register new user shows success', async ({ page }) => {
|
|
await page.goto('/login');
|
|
await page.click('text=Inscription');
|
|
|
|
const uniqueUsername = `testuser_${Date.now()}`;
|
|
await page.fill('#registerUsername', uniqueUsername);
|
|
await page.fill('#registerPassword', 'password123');
|
|
await page.fill('#registerPasswordConfirm', 'password123');
|
|
|
|
const [response] = await Promise.all([
|
|
page.waitForResponse((resp) => resp.url().includes('/api/auth/register')),
|
|
page.click('#registerSubmit'),
|
|
]);
|
|
|
|
expect(response.status()).toBeLessThan(400);
|
|
|
|
await expect(page.locator('#authSuccess')).toBeVisible();
|
|
await expect(page.locator('#authSuccess')).toContainText(/réussie|succès/i);
|
|
});
|
|
|
|
test('password mismatch shows validation error', async ({ page }) => {
|
|
await page.goto('/login');
|
|
await page.click('text=Inscription');
|
|
|
|
await page.fill('#registerUsername', 'testuser');
|
|
await page.fill('#registerPassword', 'password123');
|
|
await page.fill('#registerPasswordConfirm', 'differentpassword');
|
|
await page.click('#registerSubmit');
|
|
|
|
await expect(page.locator('#authError')).toBeVisible();
|
|
await expect(page.locator('#authError')).toContainText(/correspondent|match/i);
|
|
});
|
|
|
|
test('login button shows loading state during request', async ({ page }) => {
|
|
await page.goto('/login');
|
|
const button = page.locator('#loginSubmit');
|
|
const initialText = await button.textContent();
|
|
|
|
await page.fill('#loginUsername', TEST_USER.username);
|
|
await page.fill('#loginPassword', TEST_USER.password);
|
|
|
|
// Start the click but don't await it fully — we want to observe the loading state
|
|
const clickPromise = button.click();
|
|
|
|
// Poll briefly for loading state
|
|
let sawLoading = false;
|
|
for (let i = 0; i < 10; i++) {
|
|
const text = await button.textContent();
|
|
const disabled = await button.isDisabled();
|
|
if (text !== initialText || disabled) {
|
|
sawLoading = true;
|
|
break;
|
|
}
|
|
await page.waitForTimeout(50);
|
|
}
|
|
|
|
await clickPromise;
|
|
expect(sawLoading).toBe(true);
|
|
});
|
|
});
|