Merge pull request 'f090_magic_strings_refactoring' (#35) from f090_magic_strings_refactoring into development
All checks were successful
InnoHub Processor/tatort/pipeline/head This commit looks good
All checks were successful
InnoHub Processor/tatort/pipeline/head This commit looks good
Reviewed-on: #35
This commit was merged in pull request #35.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import { decryptToken } from '$lib/auth';
|
||||
import type { Handle } from '@sveltejs/kit';
|
||||
import { ROUTE_NAMES } from './routes';
|
||||
|
||||
|
||||
export const handle: Handle = async ({ event, resolve }) => {
|
||||
const jwt = event.cookies.get('session');
|
||||
@@ -9,7 +11,7 @@ export const handle: Handle = async ({ event, resolve }) => {
|
||||
return resolve(event);
|
||||
}
|
||||
} catch (_) {
|
||||
event.cookies.delete('session', {path: '/'});
|
||||
event.cookies.delete('session', {path: ROUTE_NAMES.ROOT});
|
||||
event.locals.user = null;
|
||||
}
|
||||
return await resolve(event);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<script>
|
||||
import Profile from "$lib/icons/Profile.svelte";
|
||||
|
||||
import { ROUTE_NAMES } from "../../routes";
|
||||
|
||||
export let data;
|
||||
</script>
|
||||
|
||||
@@ -10,19 +12,19 @@
|
||||
<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">
|
||||
<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"
|
||||
>
|
||||
© 2023 Innovation Hub Niedersachen
|
||||
</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"
|
||||
>
|
||||
back
|
||||
</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"
|
||||
>
|
||||
<!--icon-->
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<script lang="ts">
|
||||
import Chevron from '$lib/icons/Chevron-right.svelte';
|
||||
|
||||
import { ROUTE_NAMES } from '../../routes';
|
||||
|
||||
export let data;
|
||||
</script>
|
||||
|
||||
@@ -11,7 +13,7 @@
|
||||
aria-label="Global"
|
||||
>
|
||||
<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>
|
||||
<img class="h-8 w-auto" src="/Landeswappen_NI.svg" alt="Landeswappen Niedersachsen" />
|
||||
</a>
|
||||
@@ -19,7 +21,7 @@
|
||||
<h1 class="text-3xl text-slate-400 font-bold">Tatort</h1>
|
||||
<div class="lg:flex lg:justify-end w-48">
|
||||
{#if data.user}
|
||||
<form method="POST" action="/anmeldung?/logout">
|
||||
<form method="POST" action="{ROUTE_NAMES.ANMELDUNG_LOGOUT}">
|
||||
<input type="hidden" />
|
||||
<button type="submit" class="text-sm font-semibold leading-6 text-gray-900"
|
||||
><span
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<svg
|
||||
data-testid="profile-component"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
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 { fail, redirect, type Cookies, type RequestEvent } from '@sveltejs/kit';
|
||||
import { authenticate } from '$lib/auth';
|
||||
import { ROUTE_NAMES } from '../../routes';
|
||||
|
||||
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 });
|
||||
|
||||
cookies.set(COOKIE_NAME, token, {
|
||||
path: '/',
|
||||
path: ROUTE_NAMES.ROOT,
|
||||
httpOnly: true,
|
||||
sameSite: 'strict',
|
||||
secure: !dev
|
||||
});
|
||||
return redirect(303, '/');
|
||||
return redirect(303, ROUTE_NAMES.ROOT);
|
||||
};
|
||||
|
||||
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;
|
||||
return { success: true };
|
||||
};
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { redirect, type ServerLoadEvent } from '@sveltejs/kit';
|
||||
import type { PageServerLoad } from '../anmeldung/$types';
|
||||
|
||||
import { ROUTE_NAMES } from '..';
|
||||
|
||||
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 {
|
||||
user: event.locals.user
|
||||
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
import FileRect from '$lib/icons/File-rect.svelte';
|
||||
import ListIcon from '$lib/icons/List-icon.svelte';
|
||||
|
||||
import { ROUTE_NAMES } from '../index.js';
|
||||
|
||||
export let data;
|
||||
export let outline = true;
|
||||
</script>
|
||||
@@ -18,7 +20,7 @@
|
||||
>
|
||||
<ListIcon class=" group-hover:text-indigo-600" />
|
||||
</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
|
||||
<span class="absolute inset-0"></span>
|
||||
</a>
|
||||
@@ -34,7 +36,7 @@
|
||||
>
|
||||
<AddProcess class=" group-hover:text-indigo-600" />
|
||||
</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
|
||||
<span class="absolute inset-0"></span>
|
||||
</a>
|
||||
@@ -47,7 +49,7 @@
|
||||
>
|
||||
<FileRect class=" group-hover:text-indigo-600" {outline} />
|
||||
</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
|
||||
<span class="absolute inset-0"></span>
|
||||
</a>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import Trash from '$lib/icons/Trash.svelte';
|
||||
import Folder from '$lib/icons/Folder.svelte';
|
||||
import EmptyList from '$lib/components/EmptyList.svelte';
|
||||
import { API_ROUTES, ROUTE_NAMES } from '../../index.js';
|
||||
|
||||
let { data } = $props();
|
||||
|
||||
@@ -17,7 +18,7 @@
|
||||
if (!target) return;
|
||||
let filename = target.id.split('del__')[1];
|
||||
|
||||
let url = `/api/list/${filename}`;
|
||||
let url = API_ROUTES.VORGANG(filename);
|
||||
|
||||
try {
|
||||
const response = await fetch(url, { method: 'DELETE' });
|
||||
@@ -49,7 +50,7 @@
|
||||
{#each vorgangList as vorgangItem}
|
||||
<li data-testid="test-list-item">
|
||||
<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"
|
||||
>
|
||||
<div class="flex gap-x-4">
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import shortenFileSize from '$lib/helper/shortenFileSize.js';
|
||||
import Exclamation from '$lib/icons/Exclamation.svelte';
|
||||
import FileRect from '$lib/icons/File-rect.svelte';
|
||||
import { API_ROUTES, ROUTE_NAMES } from '../../index.js';
|
||||
|
||||
export let form;
|
||||
|
||||
@@ -43,7 +44,7 @@
|
||||
data.append('vorgang', vorgang);
|
||||
data.append('name', name);
|
||||
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} */
|
||||
const result = deserialize(await response.text());
|
||||
|
||||
@@ -76,7 +77,7 @@
|
||||
data.append('type', files[0].type);
|
||||
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} */
|
||||
const result = deserialize(await response.text());
|
||||
if (result.type === 'success') return result.data?.url;
|
||||
@@ -151,7 +152,6 @@
|
||||
return true;
|
||||
}
|
||||
|
||||
// `/(angemeldet)/view` return true or false
|
||||
async function checkVorgangExists(vorgangName: string) {
|
||||
if (vorgangName == '') {
|
||||
vorgangPIN = vorgangPINOld;
|
||||
@@ -159,7 +159,8 @@
|
||||
}
|
||||
|
||||
try {
|
||||
const url = `/api/list/${vorgangName}`;
|
||||
// `HEAD` method
|
||||
const url = API_ROUTES.VORGANG_NAME_EXIST(vorgangName);
|
||||
const response = await fetch(url, { method: 'HEAD' });
|
||||
|
||||
if (response.status === 200) {
|
||||
@@ -185,7 +186,7 @@
|
||||
async function getVorgangPIN(vorgangName: string) {
|
||||
if (vorgangName == '') return;
|
||||
|
||||
let url = `/api/vorgang/${vorgangName}/vorgangPIN`;
|
||||
let url = API_ROUTES.VORGANG_PIN(vorgangName);
|
||||
const response = await fetch(url);
|
||||
|
||||
if (response.status == 200) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import Button from '$lib/components/Button.svelte';
|
||||
import { API_ROUTES } from '../../index.js';
|
||||
|
||||
const { data } = $props();
|
||||
|
||||
@@ -20,7 +21,7 @@
|
||||
});
|
||||
|
||||
async function getUsers() {
|
||||
const URL = '/api/users';
|
||||
const URL = API_ROUTES.USERS;
|
||||
|
||||
try {
|
||||
const response = await fetch(URL);
|
||||
@@ -42,7 +43,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
const URL = '/api/users';
|
||||
const URL = API_ROUTES.USERS;
|
||||
const userData = { userName: userName, userPassword: userPassword };
|
||||
|
||||
try {
|
||||
@@ -78,7 +79,7 @@
|
||||
}
|
||||
|
||||
async function deleteUser(userId: string) {
|
||||
const URL = `/api/users/${userId}`;
|
||||
const URL = API_ROUTES.USER(userId);
|
||||
|
||||
try {
|
||||
const response = await fetch(URL, {
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
} from '$lib/server/vorgangService';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import type { PageServerLoad } from './list/[vorgang]/$types';
|
||||
import { ROUTE_NAMES } from '..';
|
||||
|
||||
export const load: PageServerLoad = async ({ params, url, locals }) => {
|
||||
if (locals.user) {
|
||||
@@ -18,5 +19,5 @@ export const load: PageServerLoad = async ({ params, url, locals }) => {
|
||||
const isVorgangValid = vorgangExists(vorgangToken);
|
||||
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 NameItemEditor from '$lib/components/NameItemEditor.svelte';
|
||||
import EmptyList from '$lib/components/EmptyList.svelte';
|
||||
import { API_ROUTES, ROUTE_NAMES } from '../../../index.js';
|
||||
|
||||
//Seite für die Tatort-Liste
|
||||
let { data } = $props();
|
||||
@@ -44,7 +45,7 @@
|
||||
inProgress = true;
|
||||
isError = false;
|
||||
try {
|
||||
const res = await fetch(`/api/list/${vorgangToken}/${oldName}`, {
|
||||
const res = await fetch(API_ROUTES.CRIME(vorgangToken, oldName), {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
@@ -70,11 +71,10 @@
|
||||
open = true;
|
||||
inProgress = true;
|
||||
isError = false;
|
||||
let path = new URL(data.url).pathname;
|
||||
path += `/${tatort}`;
|
||||
let path = API_ROUTES.CRIME(vorgangToken, tatort)
|
||||
|
||||
try {
|
||||
const res = await fetch(`/api${path}`, {
|
||||
const res = await fetch(path, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
@@ -144,9 +144,9 @@ Mit freundlichen Grüßen,
|
||||
<div class=" flex gap-x-4">
|
||||
<a
|
||||
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"
|
||||
aria-label="/view/{vorgangToken}/{item.name}?pin={vorgangPIN}"
|
||||
aria-label="{ROUTE_NAMES.CRIME(vorgangToken, item.name, vorgangPIN)}"
|
||||
title={item.name}
|
||||
>
|
||||
<Cube />
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { API_ROUTES } from '../../../index.js';
|
||||
|
||||
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 vorgangToken = params.vorgang;
|
||||
const crimesListResponse = await fetch(`/api/list/${vorgangToken}`)
|
||||
const crimesListResponse = await fetch(API_ROUTES.VORGANG(vorgangToken))
|
||||
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
|
||||
if(!vorgang || !crimesList){
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { loginUser, logoutUser } from '$lib/server/authService';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import { ROUTE_NAMES } from '../index.js';
|
||||
|
||||
export const actions = {
|
||||
login: ({ request, cookies }) => loginUser({ request, cookies }),
|
||||
@@ -11,6 +12,6 @@ export const actions = {
|
||||
|
||||
if (!vorgangToken || !vorgangPIN) return;
|
||||
|
||||
throw redirect(303, `/list/${vorgangToken}?pin=${vorgangPIN}`);
|
||||
throw redirect(303, ROUTE_NAMES.VORGANG(vorgangToken, vorgangPIN));
|
||||
}
|
||||
} as const;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
export let open = false;
|
||||
|
||||
import { page } from '$app/state';
|
||||
import { ROUTE_NAMES } from '../index.js';
|
||||
const vorgangToken = page.url.searchParams.get('vorgang');
|
||||
</script>
|
||||
|
||||
@@ -27,7 +28,7 @@
|
||||
<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="mt-10">
|
||||
<form action="?/getVorgangByToken" method="POST">
|
||||
<form action="{ROUTE_NAMES.ANMELDUNG_GET_VORGANG_BY_TOKEN}" method="POST">
|
||||
<BaseInputField
|
||||
id="vorgang-token"
|
||||
name="vorgang-token"
|
||||
@@ -59,7 +60,7 @@
|
||||
<Modal {open}>
|
||||
<ModalTitle>Anmelden</ModalTitle>
|
||||
<ModalContent class="flex justify-center">
|
||||
<form action="?/login" method="POST">
|
||||
<form action="{ROUTE_NAMES.ANMELDUNG_LOGIN}" method="POST">
|
||||
<div>
|
||||
<label for="user" class="text-sm font-medium leading-6 text-gray-900">Kennung</label>
|
||||
<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 { GET } from '../src/routes/api/list/+server';
|
||||
import { GET } from '$root/routes/api/list/+server';
|
||||
import { getVorgaenge } from '$lib/server/vorgangService';
|
||||
|
||||
// Mocks
|
||||
@@ -1,5 +1,5 @@
|
||||
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 {
|
||||
getCrimesListByToken,
|
||||
vorgangNameExists,
|
||||
@@ -1,5 +1,5 @@
|
||||
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';
|
||||
|
||||
// Mock data and methods
|
||||
@@ -1,5 +1,5 @@
|
||||
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';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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 { addUser, getUsers } from '$lib/server/userService';
|
||||
@@ -1,5 +1,5 @@
|
||||
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';
|
||||
|
||||
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 { describe, expect, it, test, vi } from 'vitest';
|
||||
import NameItemEditor from '$lib/components/NameItemEditor.svelte';
|
||||
import { baseData } from './fixtures';
|
||||
import { baseData } from '../fixtures';
|
||||
|
||||
const testCrimesListIndex = 0;
|
||||
const testItem = baseData.crimesList[testCrimesListIndex];
|
||||
@@ -41,6 +41,13 @@ export const baseData = {
|
||||
vorgang: testVorgangsList[0],
|
||||
vorgangList: testVorgangsList,
|
||||
crimesList: testCrimesList,
|
||||
url: `https://example.com/${testVorgangsList[0].vorgangToken}`,
|
||||
url: `https://example.com/list/${testVorgangsList[0].vorgangToken}`,
|
||||
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 { describe, it, expect, vi, test } from 'vitest';
|
||||
import * as nav from '$app/navigation';
|
||||
import TatortListPage from '../src/routes/(token-based)/list/[vorgang]/+page.svelte';
|
||||
import { baseData } from './fixtures';
|
||||
import TatortListPage from '$root/routes/(token-based)/list/[vorgang]/+page.svelte';
|
||||
import { baseData } from '../fixtures';
|
||||
import { tick } from 'svelte';
|
||||
import { API_ROUTES } from '../../src/routes';
|
||||
|
||||
vi.spyOn(nav, 'invalidateAll').mockResolvedValue();
|
||||
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 () => {
|
||||
const testData = structuredClone(baseData);
|
||||
const oldName = testData.crimesList[0].name;
|
||||
const vorgang = testData.vorgang;
|
||||
|
||||
render(TatortListPage, { props: { data: testData } });
|
||||
const initialItems = screen.getAllByTestId('test-list-item');
|
||||
@@ -62,10 +64,9 @@ describe('Seite: Vorgangsansicht', () => {
|
||||
await fireEvent.click(within(listItem).getByTestId('delete-button'));
|
||||
await tick();
|
||||
|
||||
let expectedPath = new URL(testData.url).pathname;
|
||||
expectedPath += `/${oldName}`
|
||||
let expectedPath = API_ROUTES.CRIME(vorgang.vorgangToken, oldName)
|
||||
expect(global.fetch).toHaveBeenCalledWith(
|
||||
`/api${expectedPath}`,
|
||||
expectedPath,
|
||||
expect.objectContaining({
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
@@ -1,7 +1,8 @@
|
||||
import { render, screen, within } from '@testing-library/svelte';
|
||||
import { describe, expect, it, test } from 'vitest';
|
||||
import TatortListPage from '../src/routes/(token-based)/list/[vorgang]/+page.svelte';
|
||||
import { baseData } from './fixtures';
|
||||
import TatortListPage from '$root/routes/(token-based)/list/[vorgang]/+page.svelte';
|
||||
import { baseData } from '../fixtures';
|
||||
import { ROUTE_NAMES } from '../../src/routes';
|
||||
|
||||
describe('Seite: Vorgangsansicht', () => {
|
||||
test.todo('zeigt PIN und Share-Link, wenn Admin');
|
||||
@@ -46,7 +47,7 @@ describe('Seite: Vorgangsansicht', () => {
|
||||
|
||||
items.forEach((item, i) => {
|
||||
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).toHaveAttribute('href', expectedHref);
|
||||
@@ -84,4 +85,19 @@ describe('Seite: Vorgangsansicht', () => {
|
||||
|
||||
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 { sveltekit } from '@sveltejs/kit/vite';
|
||||
import path from 'path';
|
||||
import { defineConfig } from 'vite';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [sveltekit()],
|
||||
resolve: {
|
||||
alias: {
|
||||
$lib: path.resolve('./src/lib'),
|
||||
$root: path.resolve(__dirname, 'src')
|
||||
}
|
||||
},
|
||||
test: {
|
||||
projects: [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user