test(frontend): update mock data for displayName and nullable firstName
Add displayName and personType to all Person mock objects in component and page tests. Update assertions from reversed "lastName, firstName" format to forward-order displayName. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,10 +5,10 @@ import DocumentMetadataDrawer from './DocumentMetadataDrawer.svelte';
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
const sender = { id: 's1', firstName: 'Karl', lastName: 'Müller' };
|
||||
const sender = { id: 's1', firstName: 'Karl', lastName: 'Müller', displayName: 'Karl Müller' };
|
||||
const receivers = [
|
||||
{ id: 'r1', firstName: 'Anna', lastName: 'Schmidt' },
|
||||
{ id: 'r2', firstName: 'Hans', lastName: 'Weber' }
|
||||
{ id: 'r1', firstName: 'Anna', lastName: 'Schmidt', displayName: 'Anna Schmidt' },
|
||||
{ id: 'r2', firstName: 'Hans', lastName: 'Weber', displayName: 'Hans Weber' }
|
||||
];
|
||||
const tags = [
|
||||
{ id: 't1', name: 'Familienbrief' },
|
||||
|
||||
@@ -7,9 +7,21 @@ const waitForDebounce = () => new Promise((r) => setTimeout(r, 350));
|
||||
const tick = () => new Promise((r) => setTimeout(r, 0));
|
||||
|
||||
const PERSONS = [
|
||||
{ id: '1', firstName: 'Max', lastName: 'Mustermann' },
|
||||
{ id: '2', firstName: 'Anna', lastName: 'Musterfrau' },
|
||||
{ id: '3', firstName: 'Karl', lastName: 'König' }
|
||||
{
|
||||
id: '1',
|
||||
firstName: 'Max',
|
||||
lastName: 'Mustermann',
|
||||
displayName: 'Max Mustermann',
|
||||
personType: 'PERSON'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
firstName: 'Anna',
|
||||
lastName: 'Musterfrau',
|
||||
displayName: 'Anna Musterfrau',
|
||||
personType: 'PERSON'
|
||||
},
|
||||
{ id: '3', firstName: 'Karl', lastName: 'König', displayName: 'Karl König', personType: 'PERSON' }
|
||||
];
|
||||
|
||||
function mockFetch(persons = PERSONS) {
|
||||
@@ -45,8 +57,20 @@ describe('PersonMultiSelect – rendering', () => {
|
||||
it('renders pre-selected persons as chips', async () => {
|
||||
render(PersonMultiSelect, {
|
||||
selectedPersons: [
|
||||
{ id: '1', firstName: 'Max', lastName: 'Mustermann' },
|
||||
{ id: '2', firstName: 'Anna', lastName: 'Musterfrau' }
|
||||
{
|
||||
id: '1',
|
||||
firstName: 'Max',
|
||||
lastName: 'Mustermann',
|
||||
displayName: 'Max Mustermann',
|
||||
personType: 'PERSON'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
firstName: 'Anna',
|
||||
lastName: 'Musterfrau',
|
||||
displayName: 'Anna Musterfrau',
|
||||
personType: 'PERSON'
|
||||
}
|
||||
]
|
||||
});
|
||||
await expect.element(page.getByText('Max Mustermann')).toBeInTheDocument();
|
||||
@@ -57,8 +81,20 @@ describe('PersonMultiSelect – rendering', () => {
|
||||
it('renders hidden inputs for each selected person', async () => {
|
||||
render(PersonMultiSelect, {
|
||||
selectedPersons: [
|
||||
{ id: '1', firstName: 'Max', lastName: 'Mustermann' },
|
||||
{ id: '2', firstName: 'Anna', lastName: 'Musterfrau' }
|
||||
{
|
||||
id: '1',
|
||||
firstName: 'Max',
|
||||
lastName: 'Mustermann',
|
||||
displayName: 'Max Mustermann',
|
||||
personType: 'PERSON'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
firstName: 'Anna',
|
||||
lastName: 'Musterfrau',
|
||||
displayName: 'Anna Musterfrau',
|
||||
personType: 'PERSON'
|
||||
}
|
||||
]
|
||||
});
|
||||
await tick();
|
||||
@@ -70,7 +106,15 @@ describe('PersonMultiSelect – rendering', () => {
|
||||
|
||||
it('hides the placeholder when persons are selected', async () => {
|
||||
render(PersonMultiSelect, {
|
||||
selectedPersons: [{ id: '1', firstName: 'Max', lastName: 'Mustermann' }]
|
||||
selectedPersons: [
|
||||
{
|
||||
id: '1',
|
||||
firstName: 'Max',
|
||||
lastName: 'Mustermann',
|
||||
displayName: 'Max Mustermann',
|
||||
personType: 'PERSON'
|
||||
}
|
||||
]
|
||||
});
|
||||
await expect.element(page.getByPlaceholder('Namen tippen...')).not.toBeInTheDocument();
|
||||
});
|
||||
@@ -85,7 +129,7 @@ describe('PersonMultiSelect – selecting persons', () => {
|
||||
const input = page.getByRole('textbox');
|
||||
await input.fill('Mu');
|
||||
await waitForDebounce();
|
||||
await page.getByText('Mustermann, Max').click();
|
||||
await page.getByText('Max Mustermann').click();
|
||||
await expect.element(page.getByText('Max Mustermann')).toBeInTheDocument();
|
||||
await expect.element(input).toHaveValue('');
|
||||
await page.screenshot({
|
||||
@@ -100,11 +144,11 @@ describe('PersonMultiSelect – selecting persons', () => {
|
||||
|
||||
await input.fill('Mu');
|
||||
await waitForDebounce();
|
||||
await page.getByText('Mustermann, Max').click();
|
||||
await page.getByText('Max Mustermann').click();
|
||||
|
||||
await input.fill('Mu');
|
||||
await waitForDebounce();
|
||||
await page.getByText('Musterfrau, Anna').click();
|
||||
await page.getByText('Anna Musterfrau').click();
|
||||
|
||||
await expect.element(page.getByText('Max Mustermann')).toBeInTheDocument();
|
||||
await expect.element(page.getByText('Anna Musterfrau')).toBeInTheDocument();
|
||||
@@ -116,22 +160,41 @@ describe('PersonMultiSelect – selecting persons', () => {
|
||||
it('filters already-selected persons from search results', async () => {
|
||||
mockFetch();
|
||||
render(PersonMultiSelect, {
|
||||
selectedPersons: [{ id: '1', firstName: 'Max', lastName: 'Mustermann' }]
|
||||
selectedPersons: [
|
||||
{
|
||||
id: '1',
|
||||
firstName: 'Max',
|
||||
lastName: 'Mustermann',
|
||||
displayName: 'Max Mustermann',
|
||||
personType: 'PERSON'
|
||||
}
|
||||
]
|
||||
});
|
||||
const input = page.getByRole('textbox');
|
||||
await input.fill('Mu');
|
||||
await waitForDebounce();
|
||||
await expect.element(page.getByText('Mustermann, Max')).not.toBeInTheDocument();
|
||||
await expect.element(page.getByText('Musterfrau, Anna')).toBeInTheDocument();
|
||||
// Chip still shows "Max Mustermann" but the dropdown item (role=button) must be filtered out
|
||||
await expect
|
||||
.element(page.getByRole('button', { name: 'Max Mustermann' }))
|
||||
.not.toBeInTheDocument();
|
||||
await expect.element(page.getByRole('button', { name: 'Anna Musterfrau' })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('selects a result with Enter key', async () => {
|
||||
mockFetch([{ id: '1', firstName: 'Max', lastName: 'Mustermann' }]);
|
||||
mockFetch([
|
||||
{
|
||||
id: '1',
|
||||
firstName: 'Max',
|
||||
lastName: 'Mustermann',
|
||||
displayName: 'Max Mustermann',
|
||||
personType: 'PERSON'
|
||||
}
|
||||
]);
|
||||
render(PersonMultiSelect, { selectedPersons: [] });
|
||||
const input = page.getByRole('textbox');
|
||||
await input.fill('Ma');
|
||||
await waitForDebounce();
|
||||
await page.getByText('Mustermann, Max').click();
|
||||
await page.getByText('Max Mustermann').click();
|
||||
await expect.element(page.getByText('Max Mustermann')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -142,8 +205,20 @@ describe('PersonMultiSelect – removing persons', () => {
|
||||
it('removes a chip when its × button is clicked', async () => {
|
||||
render(PersonMultiSelect, {
|
||||
selectedPersons: [
|
||||
{ id: '1', firstName: 'Max', lastName: 'Mustermann' },
|
||||
{ id: '2', firstName: 'Anna', lastName: 'Musterfrau' }
|
||||
{
|
||||
id: '1',
|
||||
firstName: 'Max',
|
||||
lastName: 'Mustermann',
|
||||
displayName: 'Max Mustermann',
|
||||
personType: 'PERSON'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
firstName: 'Anna',
|
||||
lastName: 'Musterfrau',
|
||||
displayName: 'Anna Musterfrau',
|
||||
personType: 'PERSON'
|
||||
}
|
||||
]
|
||||
});
|
||||
// Buttons have aria-label="Entfernen"
|
||||
@@ -156,8 +231,20 @@ describe('PersonMultiSelect – removing persons', () => {
|
||||
it('removes the corresponding hidden input when a chip is removed', async () => {
|
||||
render(PersonMultiSelect, {
|
||||
selectedPersons: [
|
||||
{ id: '1', firstName: 'Max', lastName: 'Mustermann' },
|
||||
{ id: '2', firstName: 'Anna', lastName: 'Musterfrau' }
|
||||
{
|
||||
id: '1',
|
||||
firstName: 'Max',
|
||||
lastName: 'Mustermann',
|
||||
displayName: 'Max Mustermann',
|
||||
personType: 'PERSON'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
firstName: 'Anna',
|
||||
lastName: 'Musterfrau',
|
||||
displayName: 'Anna Musterfrau',
|
||||
personType: 'PERSON'
|
||||
}
|
||||
]
|
||||
});
|
||||
await page.getByRole('button', { name: 'Entfernen' }).first().click();
|
||||
@@ -177,9 +264,9 @@ describe('PersonMultiSelect – click outside', () => {
|
||||
const input = page.getByRole('textbox');
|
||||
await input.fill('Mu');
|
||||
await waitForDebounce();
|
||||
await expect.element(page.getByText('Mustermann, Max')).toBeInTheDocument();
|
||||
await expect.element(page.getByText('Max Mustermann')).toBeInTheDocument();
|
||||
document.body.click();
|
||||
await tick();
|
||||
await expect.element(page.getByText('Mustermann, Max')).not.toBeInTheDocument();
|
||||
await expect.element(page.getByText('Max Mustermann')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,8 +7,20 @@ const waitForDebounce = () => new Promise((r) => setTimeout(r, 350));
|
||||
const tick = () => new Promise((r) => setTimeout(r, 0));
|
||||
|
||||
const PERSONS = [
|
||||
{ id: '1', firstName: 'Max', lastName: 'Mustermann' },
|
||||
{ id: '2', firstName: 'Anna', lastName: 'Musterfrau' }
|
||||
{
|
||||
id: '1',
|
||||
firstName: 'Max',
|
||||
lastName: 'Mustermann',
|
||||
displayName: 'Max Mustermann',
|
||||
personType: 'PERSON'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
firstName: 'Anna',
|
||||
lastName: 'Musterfrau',
|
||||
displayName: 'Anna Musterfrau',
|
||||
personType: 'PERSON'
|
||||
}
|
||||
];
|
||||
|
||||
function mockFetchWithPersons(persons = PERSONS) {
|
||||
@@ -76,8 +88,8 @@ describe('PersonTypeahead – search', () => {
|
||||
const input = page.getByPlaceholder('Namen tippen...');
|
||||
await input.fill('Mu');
|
||||
await waitForDebounce();
|
||||
await expect.element(page.getByText('Mustermann, Max')).toBeInTheDocument();
|
||||
await expect.element(page.getByText('Musterfrau, Anna')).toBeInTheDocument();
|
||||
await expect.element(page.getByText('Max Mustermann')).toBeInTheDocument();
|
||||
await expect.element(page.getByText('Anna Musterfrau')).toBeInTheDocument();
|
||||
await page.screenshot({ path: 'test-results/screenshots/person-typeahead-open.png' });
|
||||
});
|
||||
|
||||
@@ -105,7 +117,7 @@ describe('PersonTypeahead – search', () => {
|
||||
const input = page.getByPlaceholder('Namen tippen...');
|
||||
await input.fill('Ma');
|
||||
await waitForDebounce();
|
||||
await expect.element(page.getByText('Mustermann, Max')).not.toBeInTheDocument();
|
||||
await expect.element(page.getByText('Max Mustermann')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -122,7 +134,7 @@ describe('PersonTypeahead – selection', () => {
|
||||
await tick();
|
||||
await expect.element(input).toHaveValue('Max Mustermann');
|
||||
await expect
|
||||
.element(page.getByRole('button', { name: 'Mustermann, Max' }))
|
||||
.element(page.getByRole('button', { name: 'Max Mustermann' }))
|
||||
.not.toBeInTheDocument();
|
||||
await page.screenshot({ path: 'test-results/screenshots/person-typeahead-selected.png' });
|
||||
});
|
||||
@@ -152,7 +164,15 @@ describe('PersonTypeahead – selection', () => {
|
||||
});
|
||||
|
||||
it('selects a result with Enter key', async () => {
|
||||
mockFetchWithPersons([{ id: '1', firstName: 'Max', lastName: 'Mustermann' }]);
|
||||
mockFetchWithPersons([
|
||||
{
|
||||
id: '1',
|
||||
firstName: 'Max',
|
||||
lastName: 'Mustermann',
|
||||
displayName: 'Max Mustermann',
|
||||
personType: 'PERSON'
|
||||
}
|
||||
]);
|
||||
render(PersonTypeahead, { name: 'senderId', label: 'Absender' });
|
||||
const input = page.getByPlaceholder('Namen tippen...');
|
||||
await input.fill('Ma');
|
||||
@@ -218,7 +238,7 @@ describe('PersonTypeahead – correspondent mode', () => {
|
||||
(document.querySelector('input[placeholder="Namen tippen..."]') as HTMLInputElement).focus();
|
||||
await waitForDebounce();
|
||||
|
||||
await expect.element(page.getByText('Mustermann, Max')).toBeInTheDocument();
|
||||
await expect.element(page.getByText('Max Mustermann')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('uses correspondents endpoint with q param when typing', async () => {
|
||||
@@ -259,9 +279,9 @@ describe('PersonTypeahead – click outside', () => {
|
||||
const input = page.getByPlaceholder('Namen tippen...');
|
||||
await input.fill('Mu');
|
||||
await waitForDebounce();
|
||||
await expect.element(page.getByText('Mustermann, Max')).toBeInTheDocument();
|
||||
await expect.element(page.getByText('Max Mustermann')).toBeInTheDocument();
|
||||
document.body.click();
|
||||
await tick();
|
||||
await expect.element(page.getByText('Mustermann, Max')).not.toBeInTheDocument();
|
||||
await expect.element(page.getByText('Max Mustermann')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -54,7 +54,15 @@ describe('korrespondenz load — senderId set, no receiverId', () => {
|
||||
const docs = [{ id: 'd1', title: 'Testbrief' }];
|
||||
const GET = mockApi([
|
||||
{ ok: true, data: docs },
|
||||
{ ok: true, data: { firstName: 'Hans', lastName: 'Müller' } }
|
||||
{
|
||||
ok: true,
|
||||
data: {
|
||||
firstName: 'Hans',
|
||||
lastName: 'Müller',
|
||||
displayName: 'Hans Müller',
|
||||
personType: 'PERSON'
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
const result = await load({
|
||||
@@ -76,8 +84,24 @@ describe('korrespondenz load — senderId and receiverId set', () => {
|
||||
it('calls conversation, sender person, and receiver person endpoints', async () => {
|
||||
const GET = mockApi([
|
||||
{ ok: true, data: [] },
|
||||
{ ok: true, data: { firstName: 'Hans', lastName: 'Müller' } },
|
||||
{ ok: true, data: { firstName: 'Anna', lastName: 'Schmidt' } }
|
||||
{
|
||||
ok: true,
|
||||
data: {
|
||||
firstName: 'Hans',
|
||||
lastName: 'Müller',
|
||||
displayName: 'Hans Müller',
|
||||
personType: 'PERSON'
|
||||
}
|
||||
},
|
||||
{
|
||||
ok: true,
|
||||
data: {
|
||||
firstName: 'Anna',
|
||||
lastName: 'Schmidt',
|
||||
displayName: 'Anna Schmidt',
|
||||
personType: 'PERSON'
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
const result = await load({
|
||||
@@ -98,7 +122,15 @@ describe('korrespondenz load — canWrite', () => {
|
||||
it('derives canWrite true from WRITE_ALL permission', async () => {
|
||||
mockApi([
|
||||
{ ok: true, data: [] },
|
||||
{ ok: true, data: { firstName: 'Hans', lastName: 'Müller' } }
|
||||
{
|
||||
ok: true,
|
||||
data: {
|
||||
firstName: 'Hans',
|
||||
lastName: 'Müller',
|
||||
displayName: 'Hans Müller',
|
||||
personType: 'PERSON'
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
const result = await load({
|
||||
@@ -113,7 +145,15 @@ describe('korrespondenz load — canWrite', () => {
|
||||
it('derives canWrite false when user lacks WRITE_ALL', async () => {
|
||||
mockApi([
|
||||
{ ok: true, data: [] },
|
||||
{ ok: true, data: { firstName: 'Hans', lastName: 'Müller' } }
|
||||
{
|
||||
ok: true,
|
||||
data: {
|
||||
firstName: 'Hans',
|
||||
lastName: 'Müller',
|
||||
displayName: 'Hans Müller',
|
||||
personType: 'PERSON'
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
const result = await load({
|
||||
@@ -132,7 +172,15 @@ describe('korrespondenz load — backend error', () => {
|
||||
it('throws when the conversation endpoint returns non-ok', async () => {
|
||||
mockApi([
|
||||
{ ok: false, status: 500 },
|
||||
{ ok: true, data: { firstName: 'Hans', lastName: 'Müller' } }
|
||||
{
|
||||
ok: true,
|
||||
data: {
|
||||
firstName: 'Hans',
|
||||
lastName: 'Müller',
|
||||
displayName: 'Hans Müller',
|
||||
personType: 'PERSON'
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
await expect(
|
||||
|
||||
@@ -58,7 +58,9 @@ describe('New document page – receiver prefill', () => {
|
||||
it('shows a receiver chip when initialReceivers has a person', async () => {
|
||||
const data = {
|
||||
...baseData,
|
||||
initialReceivers: [{ id: 'p2', firstName: 'Anna', lastName: 'Schmidt' }]
|
||||
initialReceivers: [
|
||||
{ id: 'p2', firstName: 'Anna', lastName: 'Schmidt', displayName: 'Anna Schmidt' }
|
||||
]
|
||||
};
|
||||
render(Page, { data, form: null });
|
||||
await expect.element(page.getByText('Anna Schmidt')).toBeInTheDocument();
|
||||
@@ -67,7 +69,9 @@ describe('New document page – receiver prefill', () => {
|
||||
it('renders a hidden receiverIds input for the prefilled receiver', async () => {
|
||||
const data = {
|
||||
...baseData,
|
||||
initialReceivers: [{ id: 'p2', firstName: 'Anna', lastName: 'Schmidt' }]
|
||||
initialReceivers: [
|
||||
{ id: 'p2', firstName: 'Anna', lastName: 'Schmidt', displayName: 'Anna Schmidt' }
|
||||
]
|
||||
};
|
||||
render(Page, { data, form: null });
|
||||
const hidden = document.querySelector<HTMLInputElement>('input[name="receiverIds"]');
|
||||
|
||||
@@ -39,8 +39,22 @@ const makeDoc = (overrides = {}) => ({
|
||||
status: 'UPLOADED' as const,
|
||||
documentDate: '2024-03-15',
|
||||
location: 'Berlin',
|
||||
sender: { id: 'p1', firstName: 'Max', lastName: 'Mustermann' },
|
||||
receivers: [{ id: 'p2', firstName: 'Anna', lastName: 'Musterfrau' }],
|
||||
sender: {
|
||||
id: 'p1',
|
||||
firstName: 'Max',
|
||||
lastName: 'Mustermann',
|
||||
displayName: 'Max Mustermann',
|
||||
personType: 'PERSON' as const
|
||||
},
|
||||
receivers: [
|
||||
{
|
||||
id: 'p2',
|
||||
firstName: 'Anna',
|
||||
lastName: 'Musterfrau',
|
||||
displayName: 'Anna Musterfrau',
|
||||
personType: 'PERSON' as const
|
||||
}
|
||||
],
|
||||
tags: [{ id: 't1', name: 'Familie' }],
|
||||
filePath: '/files/testbrief.pdf',
|
||||
createdAt: '2024-03-15T10:00:00Z',
|
||||
|
||||
@@ -11,6 +11,7 @@ const makePerson = (overrides = {}) => ({
|
||||
id: '1',
|
||||
firstName: 'Max',
|
||||
lastName: 'Mustermann',
|
||||
displayName: 'Max Mustermann',
|
||||
documentCount: 0,
|
||||
...overrides
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user