test(profile,documents): cover PasswordChangeForm and FileSectionNew branches
PasswordChangeForm: tests the null/success/error/mismatch banner branches plus the form action wiring. FileSectionNew: tests the no-file/file-selected toggle, onfileParsed callback invocation with the parsed metadata, the early-return when no file is in the change event, and the suggestedTitle fallback path. Eleven tests across two files. Both follow the UploadZone template (props, File API synthetic input, vi.fn() callback spies). Refs #496. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
import { describe, it, expect, vi, afterEach } from 'vitest';
|
||||
import { cleanup, render } from 'vitest-browser-svelte';
|
||||
import { page } from 'vitest/browser';
|
||||
import FileSectionNew from './FileSectionNew.svelte';
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
describe('FileSectionNew', () => {
|
||||
it('renders the upload prompt and section heading when no file is selected', async () => {
|
||||
render(FileSectionNew, { props: {} });
|
||||
|
||||
await expect.element(page.getByRole('heading', { name: /datei/i })).toBeVisible();
|
||||
await expect.element(page.getByText('Datei hochladen')).toBeVisible();
|
||||
await expect.element(page.getByText('(optional)')).toBeVisible();
|
||||
});
|
||||
|
||||
it('replaces the prompt with the selected filename after a file is chosen', async () => {
|
||||
render(FileSectionNew, { props: {} });
|
||||
|
||||
const input = document.querySelector('input[type="file"]') as HTMLInputElement;
|
||||
const file = new File(['%PDF'], 'brief_1920.pdf', { type: 'application/pdf' });
|
||||
Object.defineProperty(input, 'files', { value: [file], writable: false });
|
||||
input.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
|
||||
await expect.element(page.getByText('brief_1920.pdf')).toBeVisible();
|
||||
await expect.element(page.getByText('Datei hochladen')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('invokes onfileParsed with the parsed filename result', async () => {
|
||||
const onfileParsed = vi.fn();
|
||||
render(FileSectionNew, { props: { onfileParsed } });
|
||||
|
||||
const input = document.querySelector('input[type="file"]') as HTMLInputElement;
|
||||
const file = new File(['%PDF'], 'Sender_Receiver_2024-05-01.pdf', { type: 'application/pdf' });
|
||||
Object.defineProperty(input, 'files', { value: [file], writable: false });
|
||||
input.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
|
||||
expect(onfileParsed).toHaveBeenCalledOnce();
|
||||
const result = onfileParsed.mock.calls[0][0];
|
||||
expect(result).toHaveProperty('suggestedTitle');
|
||||
});
|
||||
|
||||
it('does nothing when the change event fires with no file selected', async () => {
|
||||
const onfileParsed = vi.fn();
|
||||
render(FileSectionNew, { props: { onfileParsed } });
|
||||
|
||||
const input = document.querySelector('input[type="file"]') as HTMLInputElement;
|
||||
Object.defineProperty(input, 'files', { value: [], writable: false });
|
||||
input.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
|
||||
expect(onfileParsed).not.toHaveBeenCalled();
|
||||
await expect.element(page.getByText('Datei hochladen')).toBeVisible();
|
||||
});
|
||||
|
||||
it('falls back to the bare stripped filename when the parser provides no suggested title', async () => {
|
||||
const onfileParsed = vi.fn();
|
||||
render(FileSectionNew, { props: { onfileParsed } });
|
||||
|
||||
const input = document.querySelector('input[type="file"]') as HTMLInputElement;
|
||||
const file = new File(['%PDF'], 'plain.pdf', { type: 'application/pdf' });
|
||||
Object.defineProperty(input, 'files', { value: [file], writable: false });
|
||||
input.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
|
||||
const result = onfileParsed.mock.calls[0][0];
|
||||
expect(typeof result.suggestedTitle).toBe('string');
|
||||
expect(result.suggestedTitle.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,54 @@
|
||||
import { describe, it, expect, afterEach } from 'vitest';
|
||||
import { cleanup, render } from 'vitest-browser-svelte';
|
||||
import { page } from 'vitest/browser';
|
||||
import PasswordChangeForm from './PasswordChangeForm.svelte';
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
describe('PasswordChangeForm', () => {
|
||||
it('renders the three password inputs and a save button by default', async () => {
|
||||
render(PasswordChangeForm, { props: { form: null } });
|
||||
|
||||
await expect.element(page.getByRole('heading', { name: /passwort ändern/i })).toBeVisible();
|
||||
await expect.element(page.getByRole('button', { name: /speichern/i })).toBeVisible();
|
||||
});
|
||||
|
||||
it('does not render any banner when form is null', async () => {
|
||||
render(PasswordChangeForm, { props: { form: null } });
|
||||
|
||||
await expect.element(page.getByText(/erfolgreich geändert/i)).not.toBeInTheDocument();
|
||||
await expect.element(page.getByText(/stimmen nicht überein/i)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows the success banner when form.passwordSuccess is true', async () => {
|
||||
render(PasswordChangeForm, { props: { form: { passwordSuccess: true } } });
|
||||
|
||||
await expect.element(page.getByText('Passwort erfolgreich geändert.')).toBeVisible();
|
||||
});
|
||||
|
||||
it('shows the localised mismatch message for the PASSWORDS_DO_NOT_MATCH error code', async () => {
|
||||
render(PasswordChangeForm, {
|
||||
props: { form: { passwordError: 'PASSWORDS_DO_NOT_MATCH' } }
|
||||
});
|
||||
|
||||
await expect
|
||||
.element(page.getByText('Die neuen Passwörter stimmen nicht überein.'))
|
||||
.toBeVisible();
|
||||
});
|
||||
|
||||
it('shows the raw error message for any non-matching error code', async () => {
|
||||
render(PasswordChangeForm, {
|
||||
props: { form: { passwordError: 'Server-side error message' } }
|
||||
});
|
||||
|
||||
await expect.element(page.getByText('Server-side error message')).toBeVisible();
|
||||
});
|
||||
|
||||
it('declares POST as the form method and routes to the changePassword action', async () => {
|
||||
render(PasswordChangeForm, { props: { form: null } });
|
||||
|
||||
const form = document.querySelector('form');
|
||||
expect(form?.getAttribute('method')).toBe('POST');
|
||||
expect(form?.getAttribute('action')).toBe('?/changePassword');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user