Files
Kimi Agent 520be53901
CI / Test (Python 3.11) (push) Has been cancelled
CI / Test (Python 3.12) (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Type Check (push) Has been cancelled
CI / Summary (push) Has been cancelled
fix: migrations, auth, providers health check, E2E tests, remove neko-sama
- 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
2026-05-12 11:45:56 +00:00

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);
});
});