f090_magic_strings_refactoring #35
@@ -1,5 +1,7 @@
|
|||||||
import { decryptToken } from '$lib/auth';
|
import { decryptToken } from '$lib/auth';
|
||||||
import type { Handle } from '@sveltejs/kit';
|
import type { Handle } from '@sveltejs/kit';
|
||||||
|
import { ROUTE_NAMES } from './routes';
|
||||||
|
|
||||||
|
|
||||||
export const handle: Handle = async ({ event, resolve }) => {
|
export const handle: Handle = async ({ event, resolve }) => {
|
||||||
const jwt = event.cookies.get('session');
|
const jwt = event.cookies.get('session');
|
||||||
@@ -9,7 +11,7 @@ export const handle: Handle = async ({ event, resolve }) => {
|
|||||||
return resolve(event);
|
return resolve(event);
|
||||||
}
|
}
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
event.cookies.delete('session', {path: '/'});
|
event.cookies.delete('session', {path: ROUTE_NAMES.ROOT});
|
||||||
event.locals.user = null;
|
event.locals.user = null;
|
||||||
}
|
}
|
||||||
return await resolve(event);
|
return await resolve(event);
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
<script>
|
<script>
|
||||||
import Profile from "$lib/icons/Profile.svelte";
|
import Profile from "$lib/icons/Profile.svelte";
|
||||||
|
|
||||||
|
import { ROUTE_NAMES } from "../../routes";
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -10,19 +12,19 @@
|
|||||||
<div class="mx-auto max-w-7xl px-6 lg:px-8">
|
<div class="mx-auto max-w-7xl px-6 lg:px-8">
|
||||||
<div class="flex justify-between divide-x divide-gray-900/5 border-x border-gray-900/5">
|
<div class="flex justify-between divide-x divide-gray-900/5 border-x border-gray-900/5">
|
||||||
<a
|
<a
|
||||||
href="/list"
|
href="{ROUTE_NAMES.LIST}"
|
||||||
class="px-4 py-1 -ml-4 flex items-center justify-center gap-x-2.5 text-sm font-semibold leading-6 text-gray-500 hover:bg-gray-200 hover:text-gray-700"
|
class="px-4 py-1 -ml-4 flex items-center justify-center gap-x-2.5 text-sm font-semibold leading-6 text-gray-500 hover:bg-gray-200 hover:text-gray-700"
|
||||||
>
|
>
|
||||||
© 2023 Innovation Hub Niedersachen
|
© 2023 Innovation Hub Niedersachen
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
href="/"
|
href="{ROUTE_NAMES.ROOT}"
|
||||||
class="px-4 py-1 flex items-center justify-center gap-x-2.5 text-sm font-semibold leading-6 text-gray-500 hover:bg-gray-200 hover:text-gray-700"
|
class="px-4 py-1 flex items-center justify-center gap-x-2.5 text-sm font-semibold leading-6 text-gray-500 hover:bg-gray-200 hover:text-gray-700"
|
||||||
>
|
>
|
||||||
back
|
back
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
href="/"
|
href="{ROUTE_NAMES.ROOT}"
|
||||||
class="px-4 py-1 -mr-4 flex items-center justify-center gap-x-2.5 text-sm font-semibold leading-6 text-gray-500 hover:bg-gray-200 hover:text-gray-700"
|
class="px-4 py-1 -mr-4 flex items-center justify-center gap-x-2.5 text-sm font-semibold leading-6 text-gray-500 hover:bg-gray-200 hover:text-gray-700"
|
||||||
>
|
>
|
||||||
<!--icon-->
|
<!--icon-->
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Chevron from '$lib/icons/Chevron-right.svelte';
|
import Chevron from '$lib/icons/Chevron-right.svelte';
|
||||||
|
|
||||||
|
import { ROUTE_NAMES } from '../../routes';
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -11,7 +13,7 @@
|
|||||||
aria-label="Global"
|
aria-label="Global"
|
||||||
>
|
>
|
||||||
<div class="flex w-48">
|
<div class="flex w-48">
|
||||||
<a href="/" class="-m-1.5 p-1.5 w-10">
|
<a href="{ROUTE_NAMES.ROOT}" class="-m-1.5 p-1.5 w-10">
|
||||||
<span class="sr-only">Tatort Niedersachen</span>
|
<span class="sr-only">Tatort Niedersachen</span>
|
||||||
<img class="h-8 w-auto" src="/Landeswappen_NI.svg" alt="Landeswappen Niedersachsen" />
|
<img class="h-8 w-auto" src="/Landeswappen_NI.svg" alt="Landeswappen Niedersachsen" />
|
||||||
</a>
|
</a>
|
||||||
@@ -19,7 +21,7 @@
|
|||||||
<h1 class="text-3xl text-slate-400 font-bold">Tatort</h1>
|
<h1 class="text-3xl text-slate-400 font-bold">Tatort</h1>
|
||||||
<div class="lg:flex lg:justify-end w-48">
|
<div class="lg:flex lg:justify-end w-48">
|
||||||
{#if data.user}
|
{#if data.user}
|
||||||
<form method="POST" action="/anmeldung?/logout">
|
<form method="POST" action="{ROUTE_NAMES.ANMELDUNG_LOGOUT}">
|
||||||
<input type="hidden" />
|
<input type="hidden" />
|
||||||
<button type="submit" class="text-sm font-semibold leading-6 text-gray-900"
|
<button type="submit" class="text-sm font-semibold leading-6 text-gray-900"
|
||||||
><span
|
><span
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<svg
|
<svg
|
||||||
|
data-testid="profile-component"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
fill="none"
|
fill="none"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 402 B After Width: | Height: | Size: 435 B |
@@ -1,6 +1,7 @@
|
|||||||
import { dev } from '$app/environment';
|
import { dev } from '$app/environment';
|
||||||
import { fail, redirect, type Cookies, type RequestEvent } from '@sveltejs/kit';
|
import { fail, redirect, type Cookies, type RequestEvent } from '@sveltejs/kit';
|
||||||
import { authenticate } from '$lib/auth';
|
import { authenticate } from '$lib/auth';
|
||||||
|
import { ROUTE_NAMES } from '../../routes';
|
||||||
|
|
||||||
const COOKIE_NAME = 'session';
|
const COOKIE_NAME = 'session';
|
||||||
|
|
||||||
@@ -14,16 +15,16 @@ export const loginUser = async ({ request, cookies }: { request: Request; cookie
|
|||||||
if (!token) return fail(400, { user, incorrect: true });
|
if (!token) return fail(400, { user, incorrect: true });
|
||||||
|
|
||||||
cookies.set(COOKIE_NAME, token, {
|
cookies.set(COOKIE_NAME, token, {
|
||||||
path: '/',
|
path: ROUTE_NAMES.ROOT,
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
sameSite: 'strict',
|
sameSite: 'strict',
|
||||||
secure: !dev
|
secure: !dev
|
||||||
});
|
});
|
||||||
return redirect(303, '/');
|
return redirect(303, ROUTE_NAMES.ROOT);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const logoutUser = async (event: RequestEvent) => {
|
export const logoutUser = async (event: RequestEvent) => {
|
||||||
event.cookies.delete(COOKIE_NAME, { path: '/' });
|
event.cookies.delete(COOKIE_NAME, { path: ROUTE_NAMES.ROOT });
|
||||||
event.locals.user = null;
|
event.locals.user = null;
|
||||||
return { success: true };
|
return { success: true };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import { redirect, type ServerLoadEvent } from '@sveltejs/kit';
|
import { redirect, type ServerLoadEvent } from '@sveltejs/kit';
|
||||||
import type { PageServerLoad } from '../anmeldung/$types';
|
import type { PageServerLoad } from '../anmeldung/$types';
|
||||||
|
|
||||||
|
import { ROUTE_NAMES } from '..';
|
||||||
|
|
||||||
export const load: PageServerLoad = (event: ServerLoadEvent) => {
|
export const load: PageServerLoad = (event: ServerLoadEvent) => {
|
||||||
if (!event.locals.user && event.url.pathname !== '/anmeldung') throw redirect(303, '/anmeldung');
|
if (!event.locals.user && event.url.pathname !== ROUTE_NAMES.ANMELDUNG)
|
||||||
|
throw redirect(303, ROUTE_NAMES.ANMELDUNG);
|
||||||
return {
|
return {
|
||||||
user: event.locals.user
|
user: event.locals.user
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
import FileRect from '$lib/icons/File-rect.svelte';
|
import FileRect from '$lib/icons/File-rect.svelte';
|
||||||
import ListIcon from '$lib/icons/List-icon.svelte';
|
import ListIcon from '$lib/icons/List-icon.svelte';
|
||||||
|
|
||||||
|
import { ROUTE_NAMES } from '../index.js';
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
export let outline = true;
|
export let outline = true;
|
||||||
</script>
|
</script>
|
||||||
@@ -18,7 +20,7 @@
|
|||||||
>
|
>
|
||||||
<ListIcon class=" group-hover:text-indigo-600" />
|
<ListIcon class=" group-hover:text-indigo-600" />
|
||||||
</div>
|
</div>
|
||||||
<a href="/list" class="mt-6 block font-semibold text-gray-900">
|
<a href="{ROUTE_NAMES.LIST}" class="mt-6 block font-semibold text-gray-900">
|
||||||
Vorgänge
|
Vorgänge
|
||||||
<span class="absolute inset-0"></span>
|
<span class="absolute inset-0"></span>
|
||||||
</a>
|
</a>
|
||||||
@@ -34,7 +36,7 @@
|
|||||||
>
|
>
|
||||||
<AddProcess class=" group-hover:text-indigo-600" />
|
<AddProcess class=" group-hover:text-indigo-600" />
|
||||||
</div>
|
</div>
|
||||||
<a href="/upload" class="mt-6 block font-semibold text-gray-900">
|
<a href="{ROUTE_NAMES.UPLOAD}" class="mt-6 block font-semibold text-gray-900">
|
||||||
Hinzufügen
|
Hinzufügen
|
||||||
<span class="absolute inset-0"></span>
|
<span class="absolute inset-0"></span>
|
||||||
</a>
|
</a>
|
||||||
@@ -47,7 +49,7 @@
|
|||||||
>
|
>
|
||||||
<FileRect class=" group-hover:text-indigo-600" {outline} />
|
<FileRect class=" group-hover:text-indigo-600" {outline} />
|
||||||
</div>
|
</div>
|
||||||
<a href="/user-management" class="mt-6 block font-semibold text-gray-900">
|
<a href="{ROUTE_NAMES.USERMGMT}" class="mt-6 block font-semibold text-gray-900">
|
||||||
Benutzerverwaltung
|
Benutzerverwaltung
|
||||||
<span class="absolute inset-0"></span>
|
<span class="absolute inset-0"></span>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import Trash from '$lib/icons/Trash.svelte';
|
import Trash from '$lib/icons/Trash.svelte';
|
||||||
import Folder from '$lib/icons/Folder.svelte';
|
import Folder from '$lib/icons/Folder.svelte';
|
||||||
import EmptyList from '$lib/components/EmptyList.svelte';
|
import EmptyList from '$lib/components/EmptyList.svelte';
|
||||||
|
import { API_ROUTES, ROUTE_NAMES } from '../../index.js';
|
||||||
|
|
||||||
let { data } = $props();
|
let { data } = $props();
|
||||||
|
|
||||||
@@ -17,7 +18,7 @@
|
|||||||
if (!target) return;
|
if (!target) return;
|
||||||
let filename = target.id.split('del__')[1];
|
let filename = target.id.split('del__')[1];
|
||||||
|
|
||||||
let url = `/api/list/${filename}`;
|
let url = API_ROUTES.VORGANG(filename);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(url, { method: 'DELETE' });
|
const response = await fetch(url, { method: 'DELETE' });
|
||||||
@@ -49,7 +50,7 @@
|
|||||||
{#each vorgangList as vorgangItem}
|
{#each vorgangList as vorgangItem}
|
||||||
<li data-testid="test-list-item">
|
<li data-testid="test-list-item">
|
||||||
<a
|
<a
|
||||||
href="/list/{vorgangItem.vorgangToken}?pin={vorgangItem.vorgangPIN}"
|
href="{ROUTE_NAMES.VORGANG(vorgangItem.vorgangToken, vorgangItem.vorgangPIN)}"
|
||||||
class="flex justify-between gap-x-6 py-5"
|
class="flex justify-between gap-x-6 py-5"
|
||||||
>
|
>
|
||||||
<div class="flex gap-x-4">
|
<div class="flex gap-x-4">
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
import shortenFileSize from '$lib/helper/shortenFileSize.js';
|
import shortenFileSize from '$lib/helper/shortenFileSize.js';
|
||||||
import Exclamation from '$lib/icons/Exclamation.svelte';
|
import Exclamation from '$lib/icons/Exclamation.svelte';
|
||||||
import FileRect from '$lib/icons/File-rect.svelte';
|
import FileRect from '$lib/icons/File-rect.svelte';
|
||||||
|
import { API_ROUTES, ROUTE_NAMES } from '../../index.js';
|
||||||
|
|
||||||
export let form;
|
export let form;
|
||||||
|
|
||||||
@@ -43,7 +44,7 @@
|
|||||||
data.append('vorgang', vorgang);
|
data.append('vorgang', vorgang);
|
||||||
data.append('name', name);
|
data.append('name', name);
|
||||||
data.append('vorgangPIN', vorgangPIN);
|
data.append('vorgangPIN', vorgangPIN);
|
||||||
const response = await fetch('?/validate', { method: 'POST', body: data });
|
const response = await fetch(ROUTE_NAMES.UPLOAD_VALIDATE, { method: 'POST', body: data });
|
||||||
/** @type {import('@sveltejs/kit').ActionResult} */
|
/** @type {import('@sveltejs/kit').ActionResult} */
|
||||||
const result = deserialize(await response.text());
|
const result = deserialize(await response.text());
|
||||||
|
|
||||||
@@ -76,7 +77,7 @@
|
|||||||
data.append('type', files[0].type);
|
data.append('type', files[0].type);
|
||||||
data.append('fileName', files[0].name);
|
data.append('fileName', files[0].name);
|
||||||
}
|
}
|
||||||
const response = await fetch('?/url', { method: 'POST', body: data });
|
const response = await fetch(ROUTE_NAMES.UPLOAD_URL, { method: 'POST', body: data });
|
||||||
/** @type {import('@sveltejs/kit').ActionResult} */
|
/** @type {import('@sveltejs/kit').ActionResult} */
|
||||||
const result = deserialize(await response.text());
|
const result = deserialize(await response.text());
|
||||||
if (result.type === 'success') return result.data?.url;
|
if (result.type === 'success') return result.data?.url;
|
||||||
@@ -151,7 +152,6 @@
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// `/(angemeldet)/view` return true or false
|
|
||||||
async function checkVorgangExists(vorgangName: string) {
|
async function checkVorgangExists(vorgangName: string) {
|
||||||
if (vorgangName == '') {
|
if (vorgangName == '') {
|
||||||
vorgangPIN = vorgangPINOld;
|
vorgangPIN = vorgangPINOld;
|
||||||
@@ -159,7 +159,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const url = `/api/list/${vorgangName}`;
|
// `HEAD` method
|
||||||
|
const url = API_ROUTES.VORGANG_NAME_EXIST(vorgangName);
|
||||||
const response = await fetch(url, { method: 'HEAD' });
|
const response = await fetch(url, { method: 'HEAD' });
|
||||||
|
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
@@ -185,7 +186,7 @@
|
|||||||
async function getVorgangPIN(vorgangName: string) {
|
async function getVorgangPIN(vorgangName: string) {
|
||||||
if (vorgangName == '') return;
|
if (vorgangName == '') return;
|
||||||
|
|
||||||
let url = `/api/vorgang/${vorgangName}/vorgangPIN`;
|
let url = API_ROUTES.VORGANG_PIN(vorgangName);
|
||||||
const response = await fetch(url);
|
const response = await fetch(url);
|
||||||
|
|
||||||
if (response.status == 200) {
|
if (response.status == 200) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import Button from '$lib/components/Button.svelte';
|
import Button from '$lib/components/Button.svelte';
|
||||||
|
import { API_ROUTES } from '../../index.js';
|
||||||
|
|
||||||
const { data } = $props();
|
const { data } = $props();
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
async function getUsers() {
|
async function getUsers() {
|
||||||
const URL = '/api/users';
|
const URL = API_ROUTES.USERS;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(URL);
|
const response = await fetch(URL);
|
||||||
@@ -42,7 +43,7 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const URL = '/api/users';
|
const URL = API_ROUTES.USERS;
|
||||||
const userData = { userName: userName, userPassword: userPassword };
|
const userData = { userName: userName, userPassword: userPassword };
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -78,7 +79,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function deleteUser(userId: string) {
|
async function deleteUser(userId: string) {
|
||||||
const URL = `/api/users/${userId}`;
|
const URL = API_ROUTES.USER(userId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(URL, {
|
const response = await fetch(URL, {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import {
|
|||||||
} from '$lib/server/vorgangService';
|
} from '$lib/server/vorgangService';
|
||||||
import { redirect } from '@sveltejs/kit';
|
import { redirect } from '@sveltejs/kit';
|
||||||
import type { PageServerLoad } from './list/[vorgang]/$types';
|
import type { PageServerLoad } from './list/[vorgang]/$types';
|
||||||
|
import { ROUTE_NAMES } from '..';
|
||||||
|
|
||||||
export const load: PageServerLoad = async ({ params, url, locals }) => {
|
export const load: PageServerLoad = async ({ params, url, locals }) => {
|
||||||
if (locals.user) {
|
if (locals.user) {
|
||||||
@@ -18,5 +19,5 @@ export const load: PageServerLoad = async ({ params, url, locals }) => {
|
|||||||
const isVorgangValid = vorgangExists(vorgangToken);
|
const isVorgangValid = vorgangExists(vorgangToken);
|
||||||
const isVorgangPINValid = vorgangPINValidation(vorgangToken, vorgangPIN);
|
const isVorgangPINValid = vorgangPINValidation(vorgangToken, vorgangPIN);
|
||||||
|
|
||||||
if (!isVorgangValid || !isVorgangPINValid) throw redirect(303, `/anmeldung?vorgang=${vorgangToken}`);
|
if (!isVorgangValid || !isVorgangPINValid) throw redirect(303, ROUTE_NAMES.ANMELDUNG_VORGANG_PARAM(vorgangToken));
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
import { invalidateAll } from '$app/navigation';
|
import { invalidateAll } from '$app/navigation';
|
||||||
import NameItemEditor from '$lib/components/NameItemEditor.svelte';
|
import NameItemEditor from '$lib/components/NameItemEditor.svelte';
|
||||||
import EmptyList from '$lib/components/EmptyList.svelte';
|
import EmptyList from '$lib/components/EmptyList.svelte';
|
||||||
|
import { API_ROUTES, ROUTE_NAMES } from '../../../index.js';
|
||||||
|
|
||||||
//Seite für die Tatort-Liste
|
//Seite für die Tatort-Liste
|
||||||
let { data } = $props();
|
let { data } = $props();
|
||||||
@@ -44,7 +45,7 @@
|
|||||||
inProgress = true;
|
inProgress = true;
|
||||||
isError = false;
|
isError = false;
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`/api/list/${vorgangToken}/${oldName}`, {
|
const res = await fetch(API_ROUTES.CRIME(vorgangToken, oldName), {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
@@ -70,11 +71,10 @@
|
|||||||
open = true;
|
open = true;
|
||||||
inProgress = true;
|
inProgress = true;
|
||||||
isError = false;
|
isError = false;
|
||||||
let path = new URL(data.url).pathname;
|
let path = API_ROUTES.CRIME(vorgangToken, tatort)
|
||||||
path += `/${tatort}`;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`/api${path}`, {
|
const res = await fetch(path, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
@@ -144,9 +144,9 @@ Mit freundlichen Grüßen,
|
|||||||
<div class=" flex gap-x-4">
|
<div class=" flex gap-x-4">
|
||||||
<a
|
<a
|
||||||
data-testid="crime-link"
|
data-testid="crime-link"
|
||||||
href="/view/{vorgangToken}/{item.name}?pin={vorgangPIN}"
|
href="{ROUTE_NAMES.CRIME(vorgangToken, item.name, vorgangPIN)}"
|
||||||
class=" flex justify-between gap-x-6 py-5"
|
class=" flex justify-between gap-x-6 py-5"
|
||||||
aria-label="/view/{vorgangToken}/{item.name}?pin={vorgangPIN}"
|
aria-label="{ROUTE_NAMES.CRIME(vorgangToken, item.name, vorgangPIN)}"
|
||||||
title={item.name}
|
title={item.name}
|
||||||
>
|
>
|
||||||
<Cube />
|
<Cube />
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
|
import { API_ROUTES } from '../../../index.js';
|
||||||
|
|
||||||
export async function load({fetch, params, url}){
|
export async function load({fetch, params, url}){
|
||||||
const vorgangResponse = await fetch(`/api/list`);
|
const vorgangResponse = await fetch(API_ROUTES.LIST);
|
||||||
const vorgangList = await vorgangResponse.json()
|
const vorgangList = await vorgangResponse.json()
|
||||||
const vorgangToken = params.vorgang;
|
const vorgangToken = params.vorgang;
|
||||||
const crimesListResponse = await fetch(`/api/list/${vorgangToken}`)
|
const crimesListResponse = await fetch(API_ROUTES.VORGANG(vorgangToken))
|
||||||
const crimesList = await crimesListResponse.json();
|
const crimesList = await crimesListResponse.json();
|
||||||
const vorgang = vorgangList.find(v => v.vorgangToken === vorgangToken); //vorgang sollte ein eigener Typ werden, und dann kann man es hier vernünftig typisieren
|
const vorgang = vorgangList.find(v => v.vorgangToken === vorgangToken); //vorgang sollte ein eigener Typ werden, und dann kann man es hier vernünftig typisieren
|
||||||
if(!vorgang || !crimesList){
|
if(!vorgang || !crimesList){
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { loginUser, logoutUser } from '$lib/server/authService';
|
import { loginUser, logoutUser } from '$lib/server/authService';
|
||||||
import { redirect } from '@sveltejs/kit';
|
import { redirect } from '@sveltejs/kit';
|
||||||
|
import { ROUTE_NAMES } from '../index.js';
|
||||||
|
|
||||||
export const actions = {
|
export const actions = {
|
||||||
login: ({ request, cookies }) => loginUser({ request, cookies }),
|
login: ({ request, cookies }) => loginUser({ request, cookies }),
|
||||||
@@ -11,6 +12,6 @@ export const actions = {
|
|||||||
|
|
||||||
if (!vorgangToken || !vorgangPIN) return;
|
if (!vorgangToken || !vorgangPIN) return;
|
||||||
|
|
||||||
throw redirect(303, `/list/${vorgangToken}?pin=${vorgangPIN}`);
|
throw redirect(303, ROUTE_NAMES.VORGANG(vorgangToken, vorgangPIN));
|
||||||
}
|
}
|
||||||
} as const;
|
} as const;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
export let open = false;
|
export let open = false;
|
||||||
|
|
||||||
import { page } from '$app/state';
|
import { page } from '$app/state';
|
||||||
|
import { ROUTE_NAMES } from '../index.js';
|
||||||
const vorgangToken = page.url.searchParams.get('vorgang');
|
const vorgangToken = page.url.searchParams.get('vorgang');
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@
|
|||||||
<div class="w-full max-w-sm mx-auto">
|
<div class="w-full max-w-sm mx-auto">
|
||||||
<div class="relative mt-5 bg-gray-50 rounded-xl shadow-xl p-3 pt-1">
|
<div class="relative mt-5 bg-gray-50 rounded-xl shadow-xl p-3 pt-1">
|
||||||
<div class="mt-10">
|
<div class="mt-10">
|
||||||
<form action="?/getVorgangByToken" method="POST">
|
<form action="{ROUTE_NAMES.ANMELDUNG_GET_VORGANG_BY_TOKEN}" method="POST">
|
||||||
<BaseInputField
|
<BaseInputField
|
||||||
id="vorgang-token"
|
id="vorgang-token"
|
||||||
name="vorgang-token"
|
name="vorgang-token"
|
||||||
@@ -59,7 +60,7 @@
|
|||||||
<Modal {open}>
|
<Modal {open}>
|
||||||
<ModalTitle>Anmelden</ModalTitle>
|
<ModalTitle>Anmelden</ModalTitle>
|
||||||
<ModalContent class="flex justify-center">
|
<ModalContent class="flex justify-center">
|
||||||
<form action="?/login" method="POST">
|
<form action="{ROUTE_NAMES.ANMELDUNG_LOGIN}" method="POST">
|
||||||
<div>
|
<div>
|
||||||
<label for="user" class="text-sm font-medium leading-6 text-gray-900">Kennung</label>
|
<label for="user" class="text-sm font-medium leading-6 text-gray-900">Kennung</label>
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
|
|||||||
44
src/routes/index.ts
Normal file
44
src/routes/index.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
export const ROUTE_NAMES = {
|
||||||
|
ROOT: '/',
|
||||||
|
|
||||||
|
// (angemeldet)
|
||||||
|
LIST: '/list',
|
||||||
|
UPLOAD: '/upload',
|
||||||
|
// UPLOAD actions
|
||||||
|
UPLOAD_URL: '/upload?/url',
|
||||||
|
UPLOAD_VALIDATE: '/upload?/validate',
|
||||||
|
|
||||||
|
USERMGMT: '/user-management',
|
||||||
|
|
||||||
|
// (token-based)
|
||||||
|
// `pin` param is optional
|
||||||
|
VORGANG: (vorgangToken: string, vorgangPIN: string) =>
|
||||||
|
vorgangPIN ? `/list/${vorgangToken}?pin=${vorgangPIN}` : `/list/${vorgangToken}`,
|
||||||
|
|
||||||
|
CRIME: (vorgangToken: string, tatort: string, vorgangPIN: string) =>
|
||||||
|
vorgangPIN
|
||||||
|
? `/view/${vorgangToken}/${tatort}?pin=${vorgangPIN}`
|
||||||
|
: `/view/${vorgangToken}/${tatort}`,
|
||||||
|
|
||||||
|
// Anmeldung: actions
|
||||||
|
ANMELDUNG: '/anmeldung',
|
||||||
|
ANMELDUNG_LOGIN: '/anmeldung?/login',
|
||||||
|
ANMELDUNG_LOGOUT: '/anmeldung?/logout',
|
||||||
|
ANMELDUNG_GET_VORGANG_BY_TOKEN: '/anmeldung?/getVorgangByToken',
|
||||||
|
ANMELDUNG_VORGANG_PARAM: (vorgangToken: string) => `/anmeldung?vorgang=${vorgangToken}`
|
||||||
|
};
|
||||||
|
|
||||||
|
export const API_ROUTES = {
|
||||||
|
LIST: '/api/list',
|
||||||
|
VORGANG: (vorgangToken: string) => `/api/list/${vorgangToken}`,
|
||||||
|
// via `HEAD` method
|
||||||
|
VORGANG_NAME_EXIST: (vorgangName: string) => `/api/list/${vorgangName}`,
|
||||||
|
VORGANG_PIN: (vorgangName: string) => `/api/vorgang/${vorgangName}/vorgangPIN`,
|
||||||
|
|
||||||
|
// Tatort
|
||||||
|
CRIME: (vorgangToken: string, crimeName: string) => `/api/list/${vorgangToken}/${crimeName}`,
|
||||||
|
|
||||||
|
// Users
|
||||||
|
USERS: '/api/users',
|
||||||
|
USER: (userId: string) => `/api/users/${userId}`
|
||||||
|
};
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import { render } from '@testing-library/svelte';
|
|
||||||
import { describe, expect, it } from 'vitest';
|
|
||||||
import VorgangListPage from '../src/routes/(angemeldet)/list/+page.svelte';
|
|
||||||
import { baseData } from './fixtures';
|
|
||||||
|
|
||||||
describe('Vorgänge Liste Page EmptyList-Komponente View', () => {
|
|
||||||
it('zeigt EmptyList-Komponente an, wenn Liste leer ist', () => {
|
|
||||||
const testData = { ...baseData, vorgangList: [] };
|
|
||||||
const { getByTestId } = render(VorgangListPage, { props: { data: testData } });
|
|
||||||
|
|
||||||
expect(getByTestId('empty-list')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('zeigt Liste(mockData 2 Elemente) an, wenn Liste vorhanden ist', () => {
|
|
||||||
const testData = { ...baseData };
|
|
||||||
const { getAllByTestId } = render(VorgangListPage, { props: { data: testData } });
|
|
||||||
const items = getAllByTestId('test-list-item');
|
|
||||||
|
|
||||||
expect(items.length).toBeGreaterThan(0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, test, expect, vi } from 'vitest';
|
import { describe, test, expect, vi } from 'vitest';
|
||||||
import { GET } from '../src/routes/api/list/+server';
|
import { GET } from '$root/routes/api/list/+server';
|
||||||
import { getVorgaenge } from '$lib/server/vorgangService';
|
import { getVorgaenge } from '$lib/server/vorgangService';
|
||||||
|
|
||||||
// Mocks
|
// Mocks
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, test, expect, vi } from 'vitest';
|
import { describe, test, expect, vi } from 'vitest';
|
||||||
import { DELETE, GET, HEAD } from '../src/routes/api/list/[vorgang]/+server';
|
import { DELETE, GET, HEAD } from '$root/routes/api/list/[vorgang]/+server';
|
||||||
import {
|
import {
|
||||||
getCrimesListByToken,
|
getCrimesListByToken,
|
||||||
vorgangNameExists,
|
vorgangNameExists,
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, test, expect, vi } from 'vitest';
|
import { describe, test, expect, vi } from 'vitest';
|
||||||
import { DELETE, PUT } from '../src/routes/api/list/[vorgang]/[tatort]/+server';
|
import { DELETE, PUT } from '$root/routes/api/list/[vorgang]/[tatort]/+server';
|
||||||
import { BUCKET, client } from '$lib/minio';
|
import { BUCKET, client } from '$lib/minio';
|
||||||
|
|
||||||
// Mock data and methods
|
// Mock data and methods
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, test, expect } from 'vitest';
|
import { describe, test, expect } from 'vitest';
|
||||||
import { GET } from '../src/routes/api/user/+server';
|
import { GET } from '$root/routes/api/user/+server';
|
||||||
|
|
||||||
const id = 'admin';
|
const id = 'admin';
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, test, expect, vi, beforeEach } from 'vitest';
|
import { describe, test, expect, vi, beforeEach } from 'vitest';
|
||||||
import { GET, POST } from '../src/routes/api/users/+server';
|
import { GET, POST } from '$root/routes/api/users/+server';
|
||||||
import bcrypt from 'bcrypt';
|
import bcrypt from 'bcrypt';
|
||||||
|
|
||||||
import { addUser, getUsers } from '$lib/server/userService';
|
import { addUser, getUsers } from '$lib/server/userService';
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, test, expect, vi } from 'vitest';
|
import { describe, test, expect, vi } from 'vitest';
|
||||||
import { GET } from '../src/routes/api/vorgang/[vorgang]/vorgangPIN/+server';
|
import { GET } from '$root/routes/api/vorgang/[vorgang]/vorgangPIN/+server';
|
||||||
import { db } from '$lib/server/dbService';
|
import { db } from '$lib/server/dbService';
|
||||||
|
|
||||||
const mockEvent = {
|
const mockEvent = {
|
||||||
47
tests/components/Footer.test.ts
Normal file
47
tests/components/Footer.test.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import { render, screen } from '@testing-library/svelte';
|
||||||
|
import { describe, test, expect } from 'vitest';
|
||||||
|
|
||||||
|
import { ROUTE_NAMES } from '../../src/routes';
|
||||||
|
import { baseData } from '../fixtures';
|
||||||
|
|
||||||
|
import Footer from '$lib/components/Footer.svelte';
|
||||||
|
|
||||||
|
describe('Footer component', () => {
|
||||||
|
test('Enthält Behörden-Name und entsprechenden Link', () => {
|
||||||
|
render(Footer);
|
||||||
|
const linkElement = screen.getByText('Innovation Hub', { exact: false });
|
||||||
|
expect(linkElement).toBeInTheDocument();
|
||||||
|
expect(linkElement).toHaveAttribute('href', ROUTE_NAMES.LIST);
|
||||||
|
});
|
||||||
|
test('Enthält Zurück-Button und entsprechenden Link', () => {
|
||||||
|
render(Footer);
|
||||||
|
const linkElement = screen.getByText('back');
|
||||||
|
expect(linkElement).toBeInTheDocument();
|
||||||
|
expect(linkElement).toHaveAttribute('href', ROUTE_NAMES.ROOT);
|
||||||
|
});
|
||||||
|
test('Enthält Profil-Icon und entsprechenden Link: angemeldet', () => {
|
||||||
|
render(Footer, { props: { data: baseData } });
|
||||||
|
const linkElement = screen.getByText('admin');
|
||||||
|
expect(linkElement).toBeInTheDocument();
|
||||||
|
expect(linkElement).toHaveAttribute('href', ROUTE_NAMES.ROOT);
|
||||||
|
|
||||||
|
// Check for presence of `Profile` component
|
||||||
|
const svg = screen.getByTestId('profile-component');
|
||||||
|
expect(svg).toBeTruthy();
|
||||||
|
});
|
||||||
|
test('Enthält Profil-Icon und entsprechenden Link: nicht angemeldet', () => {
|
||||||
|
const { container } = render(Footer, { props: { data: null } });
|
||||||
|
|
||||||
|
const links = container.querySelectorAll('a');
|
||||||
|
const linkElement = links[2]; // Index starts at 0
|
||||||
|
expect(linkElement).toHaveAttribute('href', ROUTE_NAMES.ROOT);
|
||||||
|
|
||||||
|
// User/View does not have any ID
|
||||||
|
const ID_displayElement = screen.queryByText('admin');
|
||||||
|
expect(ID_displayElement).not.toBeInTheDocument();
|
||||||
|
|
||||||
|
// Check for presence of `Profile` component
|
||||||
|
const svg = screen.getByTestId('profile-component');
|
||||||
|
expect(svg).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
22
tests/components/Header.test.ts
Normal file
22
tests/components/Header.test.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { render, screen } from '@testing-library/svelte';
|
||||||
|
import { describe, test, expect } from 'vitest';
|
||||||
|
|
||||||
|
import { ROUTE_NAMES } from '../../src/routes';
|
||||||
|
import { baseData } from '../fixtures';
|
||||||
|
|
||||||
|
import Header from '$lib/components/Header.svelte';
|
||||||
|
|
||||||
|
describe('Header component', () => {
|
||||||
|
test('Enthält Landeswappen von NDS und entsprechenden Link', () => {
|
||||||
|
render(Header, { props: { data: baseData } });
|
||||||
|
const linkElement = screen.getByText('Tatort Niedersachen').closest('a');
|
||||||
|
expect(linkElement).toBeInTheDocument();
|
||||||
|
expect(linkElement).toHaveAttribute('href', ROUTE_NAMES.ROOT);
|
||||||
|
});
|
||||||
|
test('Form enthält korrekten Link', () => {
|
||||||
|
const { container } = render(Header, { props: { data: baseData } });
|
||||||
|
const formElement = container.querySelector('form');
|
||||||
|
expect(formElement).toBeInTheDocument();
|
||||||
|
expect(formElement).toHaveAttribute('action', ROUTE_NAMES.ANMELDUNG_LOGOUT);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { fireEvent, render, screen } from '@testing-library/svelte';
|
import { fireEvent, render, screen } from '@testing-library/svelte';
|
||||||
import { describe, expect, it, test, vi } from 'vitest';
|
import { describe, expect, it, test, vi } from 'vitest';
|
||||||
import NameItemEditor from '$lib/components/NameItemEditor.svelte';
|
import NameItemEditor from '$lib/components/NameItemEditor.svelte';
|
||||||
import { baseData } from './fixtures';
|
import { baseData } from '../fixtures';
|
||||||
|
|
||||||
const testCrimesListIndex = 0;
|
const testCrimesListIndex = 0;
|
||||||
const testItem = baseData.crimesList[testCrimesListIndex];
|
const testItem = baseData.crimesList[testCrimesListIndex];
|
||||||
@@ -41,6 +41,13 @@ export const baseData = {
|
|||||||
vorgang: testVorgangsList[0],
|
vorgang: testVorgangsList[0],
|
||||||
vorgangList: testVorgangsList,
|
vorgangList: testVorgangsList,
|
||||||
crimesList: testCrimesList,
|
crimesList: testCrimesList,
|
||||||
url: `https://example.com/${testVorgangsList[0].vorgangToken}`,
|
url: `https://example.com/list/${testVorgangsList[0].vorgangToken}`,
|
||||||
crimeNames: ['modell-A', 'Fall-A']
|
crimeNames: ['modell-A', 'Fall-A']
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const mockEvent = {
|
||||||
|
locals: {
|
||||||
|
user: baseData.user
|
||||||
|
},
|
||||||
|
url: new URL(`https://example.com/anmeldung`)
|
||||||
|
};
|
||||||
|
|||||||
24
tests/views/Home.view.test.ts
Normal file
24
tests/views/Home.view.test.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { render, screen } from '@testing-library/svelte';
|
||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
|
import HomePage from '$root/routes/(angemeldet)/+page.svelte';
|
||||||
|
|
||||||
|
import { ROUTE_NAMES } from '../../src/routes';
|
||||||
|
import { baseData } from '../fixtures';
|
||||||
|
|
||||||
|
describe('Home-Page View', () => {
|
||||||
|
it('Überprüfe Links', () => {
|
||||||
|
render(HomePage, { props: { data: baseData } });
|
||||||
|
let linkElement = screen.getByText('Vorgänge');
|
||||||
|
expect(linkElement).toBeInTheDocument();
|
||||||
|
expect(linkElement).toHaveAttribute('href', ROUTE_NAMES.LIST);
|
||||||
|
|
||||||
|
linkElement = screen.getByText('Hinzufügen');
|
||||||
|
expect(linkElement).toBeInTheDocument();
|
||||||
|
expect(linkElement).toHaveAttribute('href', ROUTE_NAMES.UPLOAD);
|
||||||
|
|
||||||
|
linkElement = screen.getByText('Benutzerverwaltung');
|
||||||
|
expect(linkElement).toBeInTheDocument();
|
||||||
|
expect(linkElement).toHaveAttribute('href', ROUTE_NAMES.USERMGMT);
|
||||||
|
});
|
||||||
|
});
|
||||||
29
tests/views/Layout.test.ts
Normal file
29
tests/views/Layout.test.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { describe, test, expect } from 'vitest';
|
||||||
|
import { load } from '$root/routes/(angemeldet)/+layout.server';
|
||||||
|
import { ROUTE_NAMES } from '../../src/routes';
|
||||||
|
import { baseData, mockEvent } from '../fixtures';
|
||||||
|
|
||||||
|
describe('+layout.server load(): Teste korrekte URL', () => {
|
||||||
|
test('Werfe redirect zu /anmeldung wenn User nicht eingeloggt', async () => {
|
||||||
|
const mockEvent = {
|
||||||
|
locals: {
|
||||||
|
user: null
|
||||||
|
},
|
||||||
|
url: new URL(`https://example.com/not-anmeldung`)
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
load(mockEvent);
|
||||||
|
throw new Error('Expected load() to throw');
|
||||||
|
} catch (err) {
|
||||||
|
expect(err.status).toBe(303);
|
||||||
|
expect(err.location).toBe(ROUTE_NAMES.ANMELDUNG);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('+layout.server load(): Teste erfolgreichen Pfad', () => {
|
||||||
|
test('Werfe kein Fehler', async () => {
|
||||||
|
const result = load(mockEvent);
|
||||||
|
expect(result).toEqual({ user: baseData.user });
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
import { render, fireEvent, screen, within } from '@testing-library/svelte';
|
import { render, fireEvent, screen, within } from '@testing-library/svelte';
|
||||||
import { describe, it, expect, vi, test } from 'vitest';
|
import { describe, it, expect, vi, test } from 'vitest';
|
||||||
import * as nav from '$app/navigation';
|
import * as nav from '$app/navigation';
|
||||||
import TatortListPage from '../src/routes/(token-based)/list/[vorgang]/+page.svelte';
|
import TatortListPage from '$root/routes/(token-based)/list/[vorgang]/+page.svelte';
|
||||||
import { baseData } from './fixtures';
|
import { baseData } from '../fixtures';
|
||||||
import { tick } from 'svelte';
|
import { tick } from 'svelte';
|
||||||
|
import { API_ROUTES } from '../../src/routes';
|
||||||
|
|
||||||
vi.spyOn(nav, 'invalidateAll').mockResolvedValue();
|
vi.spyOn(nav, 'invalidateAll').mockResolvedValue();
|
||||||
global.fetch = vi.fn().mockResolvedValue({ ok: true });
|
global.fetch = vi.fn().mockResolvedValue({ ok: true });
|
||||||
@@ -50,6 +51,7 @@ describe('Seite: Vorgangsansicht', () => {
|
|||||||
it('führt DELETE-Request aus und entfernt Element aus UI', async () => {
|
it('führt DELETE-Request aus und entfernt Element aus UI', async () => {
|
||||||
const testData = structuredClone(baseData);
|
const testData = structuredClone(baseData);
|
||||||
const oldName = testData.crimesList[0].name;
|
const oldName = testData.crimesList[0].name;
|
||||||
|
const vorgang = testData.vorgang;
|
||||||
|
|
||||||
render(TatortListPage, { props: { data: testData } });
|
render(TatortListPage, { props: { data: testData } });
|
||||||
const initialItems = screen.getAllByTestId('test-list-item');
|
const initialItems = screen.getAllByTestId('test-list-item');
|
||||||
@@ -62,10 +64,9 @@ describe('Seite: Vorgangsansicht', () => {
|
|||||||
await fireEvent.click(within(listItem).getByTestId('delete-button'));
|
await fireEvent.click(within(listItem).getByTestId('delete-button'));
|
||||||
await tick();
|
await tick();
|
||||||
|
|
||||||
let expectedPath = new URL(testData.url).pathname;
|
let expectedPath = API_ROUTES.CRIME(vorgang.vorgangToken, oldName)
|
||||||
expectedPath += `/${oldName}`
|
|
||||||
expect(global.fetch).toHaveBeenCalledWith(
|
expect(global.fetch).toHaveBeenCalledWith(
|
||||||
`/api${expectedPath}`,
|
expectedPath,
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
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 '$root/routes/(token-based)/list/[vorgang]/+page.svelte';
|
||||||
import { baseData } from './fixtures';
|
import { baseData } from '../fixtures';
|
||||||
|
import { ROUTE_NAMES } from '../../src/routes';
|
||||||
|
|
||||||
describe('Seite: Vorgangsansicht', () => {
|
describe('Seite: Vorgangsansicht', () => {
|
||||||
test.todo('zeigt PIN und Share-Link, wenn Admin');
|
test.todo('zeigt PIN und Share-Link, wenn Admin');
|
||||||
@@ -46,7 +47,7 @@ describe('Seite: Vorgangsansicht', () => {
|
|||||||
|
|
||||||
items.forEach((item, i) => {
|
items.forEach((item, i) => {
|
||||||
const link = within(item).getByRole('link');
|
const link = within(item).getByRole('link');
|
||||||
const expectedHref = `/view/${testData.vorgang.vorgangToken}/${testData.crimesList[i].name}?pin=${testData.vorgang.vorgangPIN}`;
|
const expectedHref = ROUTE_NAMES.CRIME(testData.vorgang.vorgangToken, testData.crimesList[i].name, testData.vorgang.vorgangPIN);
|
||||||
|
|
||||||
expect(link).toBeInTheDocument();
|
expect(link).toBeInTheDocument();
|
||||||
expect(link).toHaveAttribute('href', expectedHref);
|
expect(link).toHaveAttribute('href', expectedHref);
|
||||||
@@ -84,4 +85,19 @@ describe('Seite: Vorgangsansicht', () => {
|
|||||||
|
|
||||||
test.todo('zeigt keinen Share-Link oder PIN');
|
test.todo('zeigt keinen Share-Link oder PIN');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Teste Links auf Korrektheit', () => {
|
||||||
|
it('Überprüfe Links', () => {
|
||||||
|
const crimesListOneItem = baseData.crimesList.slice(0, 1);
|
||||||
|
const crimeObj = crimesListOneItem[0];
|
||||||
|
const vorgObj = baseData.vorgangList[0]
|
||||||
|
const expectedURL = ROUTE_NAMES.CRIME(vorgObj.vorgangToken, crimeObj.name, vorgObj.vorgangPIN)
|
||||||
|
|
||||||
|
render(TatortListPage, { props: { data: { ...baseData, crimesList: crimesListOneItem } } });
|
||||||
|
const listItem = screen.getByTestId("test-list-item");
|
||||||
|
const linkElement = within(listItem).getByRole('link');
|
||||||
|
expect(linkElement).toBeInTheDocument();
|
||||||
|
expect(linkElement).toHaveAttribute('href', expectedURL);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
36
tests/views/VorgangList.view.test.ts
Normal file
36
tests/views/VorgangList.view.test.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { render, screen, within } from '@testing-library/svelte';
|
||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
import VorgangListPage from '$root/routes/(angemeldet)/list/+page.svelte';
|
||||||
|
import { baseData } from '../fixtures';
|
||||||
|
import { ROUTE_NAMES } from '../../src/routes';
|
||||||
|
|
||||||
|
describe('Vorgänge Liste Page EmptyList-Komponente View', () => {
|
||||||
|
it('zeigt EmptyList-Komponente an, wenn Liste leer ist', () => {
|
||||||
|
const testData = { ...baseData, vorgangList: [] };
|
||||||
|
const { getByTestId } = render(VorgangListPage, { props: { data: testData } });
|
||||||
|
|
||||||
|
expect(getByTestId('empty-list')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('zeigt Liste(mockData 2 Elemente) an, wenn Liste vorhanden ist', () => {
|
||||||
|
const testData = { ...baseData };
|
||||||
|
const { getAllByTestId } = render(VorgangListPage, { props: { data: testData } });
|
||||||
|
const items = getAllByTestId('test-list-item');
|
||||||
|
|
||||||
|
expect(items.length).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Teste Links auf Korrektheit', () => {
|
||||||
|
it('Überprüfe Links', () => {
|
||||||
|
const vorgListOneItem = baseData.vorgangList.slice(0, 1);
|
||||||
|
const vorgObj = vorgListOneItem[0];
|
||||||
|
const expectedURL = ROUTE_NAMES.VORGANG(vorgObj.vorgangToken, vorgObj.vorgangPIN)
|
||||||
|
|
||||||
|
render(VorgangListPage, { props: { data: { ...baseData, vorgangList: vorgListOneItem } } });
|
||||||
|
const listItem = screen.getByTestId("test-list-item");
|
||||||
|
const linkElement = within(listItem).getByRole('link');
|
||||||
|
expect(linkElement).toBeInTheDocument();
|
||||||
|
expect(linkElement).toHaveAttribute('href', expectedURL);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,9 +1,16 @@
|
|||||||
import { svelteTesting } from '@testing-library/svelte/vite';
|
import { svelteTesting } from '@testing-library/svelte/vite';
|
||||||
import { sveltekit } from '@sveltejs/kit/vite';
|
import { sveltekit } from '@sveltejs/kit/vite';
|
||||||
|
import path from 'path';
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [sveltekit()],
|
plugins: [sveltekit()],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
$lib: path.resolve('./src/lib'),
|
||||||
|
$root: path.resolve(__dirname, 'src')
|
||||||
|
}
|
||||||
|
},
|
||||||
test: {
|
test: {
|
||||||
projects: [
|
projects: [
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user