Renders LoginPage with form.rateLimited=true and asserts that the role="alert" div (clock icon + error message) is visible in the browser. Previously only the form action's rateLimited=true return value was tested; now the rendered UI is also verified. Addresses Sara Concern 4 / Elicit open question from PR #617 review. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
86 lines
3.2 KiB
TypeScript
86 lines
3.2 KiB
TypeScript
import { describe, it, expect, afterEach } from 'vitest';
|
|
import { cleanup, render } from 'vitest-browser-svelte';
|
|
import { page } from 'vitest/browser';
|
|
import LoginPage from './+page.svelte';
|
|
|
|
afterEach(cleanup);
|
|
|
|
describe('login page', () => {
|
|
it('renders the login form by default', async () => {
|
|
render(LoginPage, { props: { data: { registered: false }, form: undefined } });
|
|
|
|
await expect.element(page.getByRole('heading', { name: /^anmelden$/i })).toBeVisible();
|
|
await expect.element(page.getByLabelText(/e-mail-adresse/i)).toBeVisible();
|
|
await expect.element(page.getByLabelText(/passwort/i)).toBeVisible();
|
|
await expect.element(page.getByRole('button', { name: /^anmelden$/i })).toBeVisible();
|
|
});
|
|
|
|
it('shows the registered-success banner when data.registered is true', async () => {
|
|
render(LoginPage, { props: { data: { registered: true }, form: undefined } });
|
|
|
|
await expect
|
|
.element(page.getByText('Dein Konto wurde erfolgreich erstellt. Melde dich jetzt an.'))
|
|
.toBeVisible();
|
|
});
|
|
|
|
it('hides the registered-success banner when data.registered is false', async () => {
|
|
render(LoginPage, { props: { data: { registered: false }, form: undefined } });
|
|
|
|
await expect.element(page.getByRole('status')).not.toBeInTheDocument();
|
|
});
|
|
|
|
it('shows the form error when form.error is set', async () => {
|
|
render(LoginPage, {
|
|
props: { data: { registered: false }, form: { error: 'Ungültige Anmeldedaten' } }
|
|
});
|
|
|
|
await expect.element(page.getByText('Ungültige Anmeldedaten')).toBeVisible();
|
|
});
|
|
|
|
it('declares POST as the form method and routes to ?/login', async () => {
|
|
render(LoginPage, { props: { data: { registered: false }, form: undefined } });
|
|
|
|
const form = document.querySelector('form');
|
|
expect(form?.getAttribute('method')).toBe('POST');
|
|
expect(form?.getAttribute('action')).toBe('?/login');
|
|
});
|
|
|
|
it('exposes the email input as type=email and required', async () => {
|
|
render(LoginPage, { props: { data: { registered: false }, form: undefined } });
|
|
|
|
const email = document.querySelector('input[name="email"]') as HTMLInputElement;
|
|
expect(email.type).toBe('email');
|
|
expect(email.required).toBe(true);
|
|
expect(email.autocomplete).toBe('email');
|
|
});
|
|
|
|
it('exposes the password input as type=password and required', async () => {
|
|
render(LoginPage, { props: { data: { registered: false }, form: undefined } });
|
|
|
|
const pwd = document.querySelector('input[name="password"]') as HTMLInputElement;
|
|
expect(pwd.type).toBe('password');
|
|
expect(pwd.required).toBe(true);
|
|
expect(pwd.autocomplete).toBe('current-password');
|
|
});
|
|
|
|
it('renders the forgot-password link', async () => {
|
|
render(LoginPage, { props: { data: { registered: false }, form: undefined } });
|
|
|
|
await expect
|
|
.element(page.getByRole('link', { name: /passwort vergessen/i }))
|
|
.toHaveAttribute('href', '/forgot-password');
|
|
});
|
|
|
|
it('shows rate-limit alert with clock icon when rateLimited is true', async () => {
|
|
render(LoginPage, {
|
|
props: {
|
|
data: { registered: false },
|
|
form: { error: 'Zu viele Anmeldeversuche.', rateLimited: true }
|
|
}
|
|
});
|
|
|
|
await expect.element(page.getByRole('alert')).toBeVisible();
|
|
await expect.element(page.getByText('Zu viele Anmeldeversuche.')).toBeVisible();
|
|
});
|
|
});
|