test(coverage): drive browser tests to 80% on all metrics (#496) #505
@@ -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