implement tests TatortList.view, check delete/edit Item
This commit is contained in:
@@ -81,8 +81,9 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div>
|
<div data-testid="test-nameItemEditor">
|
||||||
<input
|
<input
|
||||||
|
data-testid="test-input"
|
||||||
bind:this={inputRef}
|
bind:this={inputRef}
|
||||||
bind:value={localName}
|
bind:value={localName}
|
||||||
onfocus={() => {
|
onfocus={() => {
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
import { readFileSync } from 'fs';
|
import { readFileSync } from 'fs';
|
||||||
|
|
||||||
export default JSON.parse(readFileSync('./config.json').toString());
|
export default JSON.parse(readFileSync('./config_prod.json').toString());
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
prefix?: string;
|
prefix?: string;
|
||||||
// add other properties as needed
|
// add other properties as needed
|
||||||
}
|
}
|
||||||
|
console.log(data.url);
|
||||||
|
|
||||||
let vorgangName: string = data.vorgang.vorgangName;
|
let vorgangName: string = data.vorgang.vorgangName;
|
||||||
let crimesList: ListItem[] = $state(data.crimesList);
|
let crimesList: ListItem[] = $state(data.crimesList);
|
||||||
@@ -53,25 +54,18 @@
|
|||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
inProgress = false;
|
inProgress = false;
|
||||||
|
invalidateAll();
|
||||||
|
crimesList = data.crimesList;
|
||||||
|
open = false;
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
inProgress = false;
|
inProgress = false;
|
||||||
isError = true;
|
isError = true;
|
||||||
console.log('ERROR', err);
|
console.log('ERROR', err);
|
||||||
});
|
});
|
||||||
|
} catch (err) {
|
||||||
if (!res.ok) {
|
|
||||||
const msg = await res.text();
|
|
||||||
console.error('❌ Fehler beim Umbenennen:', msg);
|
|
||||||
isError = true;
|
isError = true;
|
||||||
inProgress = false;
|
inProgress = false;
|
||||||
} else {
|
|
||||||
await invalidateAll();
|
|
||||||
crimesList = data.crimesList;
|
|
||||||
open = false;
|
|
||||||
inProgress = false;
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error('⚠️ Netzwerkfehler:', err);
|
console.error('⚠️ Netzwerkfehler:', err);
|
||||||
inProgress = false;
|
inProgress = false;
|
||||||
}
|
}
|
||||||
@@ -82,7 +76,6 @@
|
|||||||
inProgress = true;
|
inProgress = true;
|
||||||
let url = new URL(data.url);
|
let url = new URL(data.url);
|
||||||
url.pathname += `/${tatort}`;
|
url.pathname += `/${tatort}`;
|
||||||
console.log('Delete tatort: ', `/api${url.pathname}`, url.pathname);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`/api${url.pathname}`, {
|
const res = await fetch(`/api${url.pathname}`, {
|
||||||
@@ -94,21 +87,15 @@
|
|||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
inProgress = false;
|
inProgress = false;
|
||||||
|
console.log('🗑️ Erfolgreich gelöscht:', url.pathname);
|
||||||
|
invalidateAll();
|
||||||
|
crimesList = data.crimesList;
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
isError = true;
|
isError = true;
|
||||||
inProgress = false;
|
inProgress = false;
|
||||||
console.log('ERROR', err);
|
console.log('ERROR', err);
|
||||||
});
|
});
|
||||||
if (!res.ok) {
|
|
||||||
const msg = await res.text();
|
|
||||||
console.error('❌ Fehler beim Löschen:', msg);
|
|
||||||
} else {
|
|
||||||
console.log('🗑️ Erfolgreich gelöscht:', url.pathname);
|
|
||||||
await invalidateAll();
|
|
||||||
|
|
||||||
crimesList = data.crimesList;
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
isError = true;
|
isError = true;
|
||||||
inProgress = false;
|
inProgress = false;
|
||||||
@@ -180,9 +167,12 @@ Mit freundlichen Grüßen,
|
|||||||
onDelete={handleDelete}
|
onDelete={handleDelete}
|
||||||
></NameItemEditor>
|
></NameItemEditor>
|
||||||
{:else}
|
{:else}
|
||||||
<span class="text-sm font-semibold leading-6 text-gray-900 inline-block min-w-1"
|
<p
|
||||||
>{item.name}</span
|
data-testid="test-nameItem-p"
|
||||||
|
class="text-sm font-semibold leading-6 text-gray-900 inline-block min-w-1"
|
||||||
>
|
>
|
||||||
|
{item.name}
|
||||||
|
</p>
|
||||||
{/if}
|
{/if}
|
||||||
{#if item.size}
|
{#if item.size}
|
||||||
<p class="mt-1 truncate text-xs leading-5 text-gray-500">
|
<p class="mt-1 truncate text-xs leading-5 text-gray-500">
|
||||||
|
|||||||
@@ -1,54 +1,9 @@
|
|||||||
import { fireEvent, render } from '@testing-library/svelte';
|
import { fireEvent, render } from '@testing-library/svelte';
|
||||||
import { describe, expect, it, vi } from "vitest";
|
import { describe, expect, it, vi } from "vitest";
|
||||||
import NameItemEditor from '$lib/components/NameItemEditor.svelte';
|
import NameItemEditor from '$lib/components/NameItemEditor.svelte';
|
||||||
|
import { baseData } from './fixtures';
|
||||||
|
|
||||||
const testUser = {
|
|
||||||
admin: true,
|
|
||||||
exp: 1757067123,
|
|
||||||
iat: 1757063523,
|
|
||||||
id: "admin",
|
|
||||||
}
|
|
||||||
const testCrimesList = [
|
|
||||||
{
|
|
||||||
name: 'model-A',
|
|
||||||
lastModified: '2025-08-28T09:44:12.453Z',
|
|
||||||
etag: '558f35716f6af953f9bb5d75f6d77e6a',
|
|
||||||
size: 8947140,
|
|
||||||
prefix: '7596e4d5-c51f-482d-a4aa-ff76434305fc',
|
|
||||||
show_button: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'model-z',
|
|
||||||
lastModified: '2025-08-28T10:37:20.142Z',
|
|
||||||
etag: '43e3989c32c4682bee407baaf83b6fa0',
|
|
||||||
size: 35788560,
|
|
||||||
prefix: '7596e4d5-c51f-482d-a4aa-ff76434305fc',
|
|
||||||
show_button: true
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const testVorgangsList = [
|
|
||||||
{
|
|
||||||
vorgangName: "vorgang-1",
|
|
||||||
vorgangPIN: "pin-123",
|
|
||||||
vorgangToken: "c322f26f-8c5e-4cb9-94b3-b5433bf5109e"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
vorgangName: "vorgang-2",
|
|
||||||
vorgangPIN: "pin-2",
|
|
||||||
vorgangToken: "cb0051bc-5f38-47b8-943c-9352d4d9c984"
|
|
||||||
}
|
|
||||||
|
|
||||||
]
|
|
||||||
|
|
||||||
const baseData = {
|
|
||||||
user: testUser,
|
|
||||||
vorgang: testVorgangsList[0],
|
|
||||||
vorgangList: testVorgangsList,
|
|
||||||
crimesList: testCrimesList,
|
|
||||||
url: URL,
|
|
||||||
crimeNames: [ "modell-A" ],
|
|
||||||
}
|
|
||||||
|
|
||||||
const testCrimesListIndex = 0;
|
const testCrimesListIndex = 0;
|
||||||
const testItem = baseData.crimesList[testCrimesListIndex];
|
const testItem = baseData.crimesList[testCrimesListIndex];
|
||||||
|
|||||||
77
tests/TatortList.test.ts
Normal file
77
tests/TatortList.test.ts
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import { fireEvent, getAllByTestId, queryAllByTestId, render, screen, within } from '@testing-library/svelte';
|
||||||
|
import { describe, expect, it, vi } from "vitest";
|
||||||
|
import TatortListPage from "../src/routes/(token-based)/list/[vorgang]/+page.svelte";
|
||||||
|
import { baseData } from './fixtures';
|
||||||
|
|
||||||
|
|
||||||
|
// Mock für invalidateAll
|
||||||
|
vi.mock('$app/navigation', () => ({
|
||||||
|
invalidateAll: vi.fn()
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Minimaler fetch-Mock
|
||||||
|
global.fetch = vi.fn().mockResolvedValue({ ok: true });
|
||||||
|
|
||||||
|
describe('Seite: Vorgangsansicht', () => {
|
||||||
|
describe('Szenario: Admin + Liste gefüllt', () => {
|
||||||
|
it('ändert den Namen nach Speichern', async () => {
|
||||||
|
const testData = structuredClone(baseData);
|
||||||
|
const oldName = testData.crimesList[0].name;
|
||||||
|
|
||||||
|
render(TatortListPage, { props: { data: testData } });
|
||||||
|
|
||||||
|
const firstItem = screen.getAllByTestId('test-list-item')[0];
|
||||||
|
await fireEvent.click(within(firstItem).getByTestId('edit-button'));
|
||||||
|
|
||||||
|
const input = within(firstItem).getByRole('textbox');
|
||||||
|
await fireEvent.input(input, { target: { value: 'Fall-B' } });
|
||||||
|
|
||||||
|
await fireEvent.click(within(firstItem).getByTestId('commit-button'));
|
||||||
|
|
||||||
|
// Erwartung: fetch wurde aufgerufen
|
||||||
|
expect(global.fetch).toHaveBeenCalledWith(
|
||||||
|
expect.stringContaining(`/api/list/${testData.vorgang.vorgangToken}/${oldName}`),
|
||||||
|
expect.any(Object)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Erwartung: neuer Name ist sofort im DOM sichtbar
|
||||||
|
expect(within(firstItem).getByRole('textbox')).toHaveValue('Fall-B');
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('entfernt das Listenelement nach Löschen', async () => {
|
||||||
|
const testData = structuredClone(baseData);
|
||||||
|
testData.url = new URL('https://example.com/vorgang-1'); // Fix für Invalid URL
|
||||||
|
const toDelete = testData.crimesList[0];
|
||||||
|
|
||||||
|
global.fetch = vi.fn().mockResolvedValue({ ok: true });
|
||||||
|
|
||||||
|
render(TatortListPage, { props: { data: testData } });
|
||||||
|
const deletedFirstItem = screen.getAllByTestId('test-list-item')[0];
|
||||||
|
|
||||||
|
|
||||||
|
const deletedLink = within(deletedFirstItem).getByRole('link');
|
||||||
|
|
||||||
|
const deletedExpectedHref = `/view/${testData.vorgang.vorgangToken}/${toDelete.name}?pin=${testData.vorgang.vorgangPIN}`;
|
||||||
|
|
||||||
|
expect(deletedLink).toBeInTheDocument();
|
||||||
|
|
||||||
|
expect(deletedLink).toHaveAttribute('href', deletedExpectedHref);
|
||||||
|
expect(deletedLink).toHaveAttribute('title', toDelete.name);
|
||||||
|
|
||||||
|
|
||||||
|
await fireEvent.click(within(deletedFirstItem).getByTestId('delete-button'));
|
||||||
|
|
||||||
|
// Erwartung: fetch wurde aufgerufen
|
||||||
|
expect(global.fetch).toHaveBeenCalledWith(
|
||||||
|
expect.stringContaining(`/api/vorgang-1/${toDelete.name}`),
|
||||||
|
expect.any(Object)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Erwartung: Element ist nicht mehr im DOM
|
||||||
|
expect(within(deletedFirstItem).getByRole('textbox')).toHaveValue(toDelete.name);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -1,58 +1,11 @@
|
|||||||
import { render, screen, within } from '@testing-library/svelte';
|
import { render, screen, within } from '@testing-library/svelte';
|
||||||
import { describe, expect, it, test } from "vitest";
|
import { describe, expect, it, test } from "vitest";
|
||||||
import TatortListPage from "../src/routes/(token-based)/list/[vorgang]/+page.svelte";
|
import TatortListPage from "../src/routes/(token-based)/list/[vorgang]/+page.svelte";
|
||||||
|
import { baseData } from './fixtures';
|
||||||
const testUser = {
|
|
||||||
admin: true,
|
|
||||||
exp: 1757067123,
|
|
||||||
iat: 1757063523,
|
|
||||||
id: "admin",
|
|
||||||
}
|
|
||||||
const testCrimesList = [
|
|
||||||
{
|
|
||||||
name: 'model-A',
|
|
||||||
lastModified: '2025-08-28T09:44:12.453Z',
|
|
||||||
etag: '558f35716f6af953f9bb5d75f6d77e6a',
|
|
||||||
size: 8947140,
|
|
||||||
prefix: '7596e4d5-c51f-482d-a4aa-ff76434305fc',
|
|
||||||
show_button: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'model-z',
|
|
||||||
lastModified: '2025-08-28T10:37:20.142Z',
|
|
||||||
etag: '43e3989c32c4682bee407baaf83b6fa0',
|
|
||||||
size: 35788560,
|
|
||||||
prefix: '7596e4d5-c51f-482d-a4aa-ff76434305fc',
|
|
||||||
show_button: true
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const testVorgangsList = [
|
|
||||||
{
|
|
||||||
vorgangName: "vorgang-1",
|
|
||||||
vorgangPIN: "pin-123",
|
|
||||||
vorgangToken: "c322f26f-8c5e-4cb9-94b3-b5433bf5109e"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
vorgangName: "vorgang-2",
|
|
||||||
vorgangPIN: "pin-2",
|
|
||||||
vorgangToken: "cb0051bc-5f38-47b8-943c-9352d4d9c984"
|
|
||||||
}
|
|
||||||
|
|
||||||
]
|
|
||||||
|
|
||||||
const baseData = {
|
|
||||||
user: testUser,
|
|
||||||
vorgang: testVorgangsList[0],
|
|
||||||
vorgangList: testVorgangsList,
|
|
||||||
crimesList: testCrimesList,
|
|
||||||
url: URL,
|
|
||||||
crimeNames: [ "modell-A" ]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
describe('Seite: Vorgangsansicht', () => {
|
describe('Seite: Vorgangsansicht', () => {
|
||||||
test.todo('zeigt PIN und Share-Link, wenn Admin');
|
test.todo('zeigt PIN und Share-Link, wenn Admin');
|
||||||
|
test.todo('zeigt PIN und Share-Link disabeld, wenn Liste leer')
|
||||||
|
|
||||||
describe('Szenario: Liste leer (unabhängig von Rolle)', () => {
|
describe('Szenario: Liste leer (unabhängig von Rolle)', () => {
|
||||||
it('zeigt Hinweistext bei leerer Liste', () => {
|
it('zeigt Hinweistext bei leerer Liste', () => {
|
||||||
@@ -105,17 +58,28 @@ describe('Seite: Vorgangsansicht', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Szenario: Admin + Liste gefüllt', () => {
|
describe('Szenario: Admin + Liste gefüllt', () => {
|
||||||
it('zeigt PIN und Share-Link disabeld, wenn Liste leer', () => { });
|
const testData = { ...baseData, user: { ...baseData.user, admin: true }};
|
||||||
it('zeigt PIN und Share-Link disabeld=false', () => { });
|
it('zeigt Listeneinträge mit Komponente NameItemEditor', () => {
|
||||||
it('zeigt Listeneinträge mit Edit/Delete', () => { });
|
const { getAllByTestId } = render(TatortListPage, {props:{data: testData}});
|
||||||
it('gibt Edit/Delete-Events korrekt weiter', () => { });
|
const items = getAllByTestId('test-nameItemEditor');
|
||||||
|
|
||||||
|
expect(items.length).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('Szenario: Viewer + Liste gefüllt', () => {
|
describe('Szenario: Viewer + Liste gefüllt', () => {
|
||||||
it('zeigt Listeneinträge ohne Edit/Delete', () => { });
|
const testData = { ...baseData, user: { ...baseData.user, admin: false }};
|
||||||
it('zeigt Link und Änderungsdatum', () => { });
|
it('zeigt Listeneinträge mit p', () => {
|
||||||
it('zeigt keinen Share-Link oder PIN', () => { });
|
render(TatortListPage, { props: { data: testData } });
|
||||||
|
const paragraphs = screen.queryAllByTestId('test-nameItem-p');
|
||||||
|
|
||||||
|
expect(paragraphs).toHaveLength(testData.crimesList.length);
|
||||||
|
paragraphs.forEach((p, i) => {
|
||||||
|
expect(p).toHaveTextContent(testData.crimesList[i].name);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test.todo('zeigt keinen Share-Link oder PIN')
|
||||||
test.todo('Modal testen, wenn open')
|
test.todo('Modal testen, wenn open')
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,54 +1,7 @@
|
|||||||
import { render } from '@testing-library/svelte';
|
import { render } from '@testing-library/svelte';
|
||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import VorgangListPage from '../src/routes/(angemeldet)/list/+page.svelte';
|
import VorgangListPage from '../src/routes/(angemeldet)/list/+page.svelte';
|
||||||
const testUser = {
|
import { baseData } from './fixtures';
|
||||||
admin: true,
|
|
||||||
exp: 1757067123,
|
|
||||||
iat: 1757063523,
|
|
||||||
id: "admin",
|
|
||||||
}
|
|
||||||
const testCrimesList = [
|
|
||||||
{
|
|
||||||
name: 'model-A',
|
|
||||||
lastModified: '2025-08-28T09:44:12.453Z',
|
|
||||||
etag: '558f35716f6af953f9bb5d75f6d77e6a',
|
|
||||||
size: 8947140,
|
|
||||||
prefix: '7596e4d5-c51f-482d-a4aa-ff76434305fc',
|
|
||||||
show_button: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'model-z',
|
|
||||||
lastModified: '2025-08-28T10:37:20.142Z',
|
|
||||||
etag: '43e3989c32c4682bee407baaf83b6fa0',
|
|
||||||
size: 35788560,
|
|
||||||
prefix: '7596e4d5-c51f-482d-a4aa-ff76434305fc',
|
|
||||||
show_button: true
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const testVorgangsList = [
|
|
||||||
{
|
|
||||||
vorgangName: "vorgang-1",
|
|
||||||
vorgangPIN: "pin-123",
|
|
||||||
vorgangToken: "c322f26f-8c5e-4cb9-94b3-b5433bf5109e"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
vorgangName: "vorgang-2",
|
|
||||||
vorgangPIN: "pin-2",
|
|
||||||
vorgangToken: "cb0051bc-5f38-47b8-943c-9352d4d9c984"
|
|
||||||
}
|
|
||||||
|
|
||||||
]
|
|
||||||
|
|
||||||
const baseData = {
|
|
||||||
user: testUser,
|
|
||||||
vorgang: testVorgangsList[0],
|
|
||||||
vorgangList: testVorgangsList,
|
|
||||||
crimesList: testCrimesList,
|
|
||||||
url: URL,
|
|
||||||
crimeNames: [ "modell-A" ],
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('Vorgänge Liste Page EmptyList-Komponente View', ()=>{
|
describe('Vorgänge Liste Page EmptyList-Komponente View', ()=>{
|
||||||
it('zeigt EmptyList-Komponente an, wenn Liste leer ist', () => {
|
it('zeigt EmptyList-Komponente an, wenn Liste leer ist', () => {
|
||||||
|
|||||||
47
tests/fixtures.ts
Normal file
47
tests/fixtures.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
const testUser = {
|
||||||
|
admin: true,
|
||||||
|
exp: 1757067123,
|
||||||
|
iat: 1757063523,
|
||||||
|
id: "admin",
|
||||||
|
}
|
||||||
|
const testCrimesList = [
|
||||||
|
{
|
||||||
|
name: 'modell-A',
|
||||||
|
lastModified: '2025-08-28T09:44:12.453Z',
|
||||||
|
etag: '558f35716f6af953f9bb5d75f6d77e6a',
|
||||||
|
size: 8947140,
|
||||||
|
prefix: '7596e4d5-c51f-482d-a4aa-ff76434305fc',
|
||||||
|
show_button: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Fall-A',
|
||||||
|
lastModified: '2025-08-28T10:37:20.142Z',
|
||||||
|
etag: '43e3989c32c4682bee407baaf83b6fa0',
|
||||||
|
size: 35788560,
|
||||||
|
prefix: '7596e4d5-c51f-482d-a4aa-ff76434305fc',
|
||||||
|
show_button: true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const testVorgangsList = [
|
||||||
|
{
|
||||||
|
vorgangName: "vorgang-1",
|
||||||
|
vorgangPIN: "pin-123",
|
||||||
|
vorgangToken: "c322f26f-8c5e-4cb9-94b3-b5433bf5109e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
vorgangName: "vorgang-2",
|
||||||
|
vorgangPIN: "pin-2",
|
||||||
|
vorgangToken: "cb0051bc-5f38-47b8-943c-9352d4d9c984"
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
export const baseData = {
|
||||||
|
user: testUser,
|
||||||
|
vorgang: testVorgangsList[0],
|
||||||
|
vorgangList: testVorgangsList,
|
||||||
|
crimesList: testCrimesList,
|
||||||
|
url: new URL(`https://example.com/${testVorgangsList[0].vorgangToken}`),
|
||||||
|
crimeNames: [ "modell-A", "Fall-A" ],
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user