Add accident and activity routes to the Express application
Enhanced the backend by integrating new routes for accident and activity management. This addition improves the API's functionality, allowing for better organization and access to related resources.
This commit is contained in:
65
backend/tests/accidentRoutes.test.js
Normal file
65
backend/tests/accidentRoutes.test.js
Normal file
@@ -0,0 +1,65 @@
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import request from 'supertest';
|
||||
|
||||
vi.mock('../services/emailService.js', () => ({
|
||||
sendActivationEmail: vi.fn().mockResolvedValue(),
|
||||
}));
|
||||
|
||||
import app from './testApp.js';
|
||||
import sequelize from '../database.js';
|
||||
import User from '../models/User.js';
|
||||
import Club from '../models/Club.js';
|
||||
import UserClub from '../models/UserClub.js';
|
||||
import Member from '../models/Member.js';
|
||||
import DiaryDate from '../models/DiaryDates.js';
|
||||
|
||||
const registerAndActivate = async (email) => {
|
||||
const password = 'Test123!';
|
||||
await request(app).post('/api/auth/register').send({ email, password });
|
||||
const user = await User.findOne({ where: { email } });
|
||||
await user.update({ isActive: true });
|
||||
return { user, credentials: { email, password } };
|
||||
};
|
||||
|
||||
const loginAndGetToken = async (credentials) => {
|
||||
const response = await request(app).post('/api/auth/login').send(credentials);
|
||||
return response.body.token;
|
||||
};
|
||||
|
||||
describe('Accident Routes', () => {
|
||||
beforeEach(async () => {
|
||||
await sequelize.sync({ force: true });
|
||||
});
|
||||
|
||||
it('legt einen Unfall an und gibt ihn zurück', async () => {
|
||||
const { user, credentials } = await registerAndActivate('accident@example.com');
|
||||
const token = await loginAndGetToken(credentials);
|
||||
const club = await Club.create({ name: 'Accident Club' });
|
||||
await UserClub.create({ userId: user.id, clubId: club.id, role: 'admin', approved: true, isOwner: true });
|
||||
const member = await Member.create({ firstName: 'Anna', lastName: 'Accident', clubId: club.id });
|
||||
const diaryDate = await DiaryDate.create({ clubId: club.id, date: new Date(), description: 'Training' });
|
||||
|
||||
const createResponse = await request(app)
|
||||
.post('/api/accident/add')
|
||||
.set('Authorization', `Bearer ${token}`)
|
||||
.send({ clubId: club.id, memberId: member.id, diaryDateId: diaryDate.id, accident: 'Verletzung' });
|
||||
|
||||
expect(createResponse.status).toBe(201);
|
||||
|
||||
const listResponse = await request(app)
|
||||
.get(`/api/accident/${club.id}/${diaryDate.id}`)
|
||||
.set('Authorization', `Bearer ${token}`);
|
||||
|
||||
expect(listResponse.status).toBe(200);
|
||||
expect(listResponse.body).toHaveLength(1);
|
||||
expect(listResponse.body[0]).toMatchObject({ firstName: 'Anna' });
|
||||
});
|
||||
|
||||
it('verhindert Anlage eines Unfalls ohne Authentifizierung', async () => {
|
||||
const response = await request(app)
|
||||
.post('/api/accident/add')
|
||||
.send({ clubId: 1, memberId: 1, diaryDateId: 1, accident: 'Test' });
|
||||
|
||||
expect(response.status).toBe(401);
|
||||
});
|
||||
});
|
||||
63
backend/tests/accidentService.test.js
Normal file
63
backend/tests/accidentService.test.js
Normal file
@@ -0,0 +1,63 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
|
||||
import sequelize from '../database.js';
|
||||
import Accident from '../models/Accident.js';
|
||||
import DiaryDate from '../models/DiaryDates.js';
|
||||
import Member from '../models/Member.js';
|
||||
import User from '../models/User.js';
|
||||
import Club from '../models/Club.js';
|
||||
import UserClub from '../models/UserClub.js';
|
||||
import accidentService from '../services/accidentService.js';
|
||||
|
||||
vi.mock('../utils/userUtils.js', async () => {
|
||||
const actual = await vi.importActual('../utils/userUtils.js');
|
||||
return {
|
||||
...actual,
|
||||
checkAccess: vi.fn().mockResolvedValue(true),
|
||||
getUserByToken: vi.fn().mockResolvedValue({ id: 1 }),
|
||||
};
|
||||
});
|
||||
|
||||
describe('accidentService', () => {
|
||||
const token = 'test-token';
|
||||
|
||||
beforeEach(async () => {
|
||||
await sequelize.sync({ force: true });
|
||||
});
|
||||
|
||||
it('legt einen Unfall-Eintrag an, wenn alle Referenzen vorhanden sind', async () => {
|
||||
const club = await Club.create({ name: 'Accident Club' });
|
||||
const member = await Member.create({ firstName: 'Alice', lastName: 'Accident', clubId: club.id });
|
||||
const diaryDate = await DiaryDate.create({ clubId: club.id, date: new Date(), description: 'Training' });
|
||||
|
||||
const result = await accidentService.createAccident(token, club.id, member.id, diaryDate.id, 'Verstauchung');
|
||||
|
||||
expect(result).toBeTruthy();
|
||||
const stored = await Accident.findOne({ where: { diaryDateId: diaryDate.id } });
|
||||
expect(stored).not.toBeNull();
|
||||
expect(stored.accident).toBe('Verstauchung');
|
||||
});
|
||||
|
||||
it('wirft Fehler, wenn Member nicht im selben Club ist', async () => {
|
||||
const club = await Club.create({ name: 'Club A' });
|
||||
const otherClub = await Club.create({ name: 'Club B' });
|
||||
const member = await Member.create({ firstName: 'Bob', lastName: 'B', clubId: otherClub.id });
|
||||
const diaryDate = await DiaryDate.create({ clubId: club.id, date: new Date(), description: 'Training' });
|
||||
|
||||
await expect(
|
||||
accidentService.createAccident(token, club.id, member.id, diaryDate.id, 'Sturz')
|
||||
).rejects.toThrow('Member not found');
|
||||
});
|
||||
|
||||
it('liefert Unfälle samt Mitgliedern zurück', async () => {
|
||||
const club = await Club.create({ name: 'Club A' });
|
||||
const member = await Member.create({ firstName: 'Clara', lastName: 'Club', clubId: club.id });
|
||||
const diaryDate = await DiaryDate.create({ clubId: club.id, date: new Date(), description: 'Training' });
|
||||
await Accident.create({ memberId: member.id, diaryDateId: diaryDate.id, accident: 'Verstauchung' });
|
||||
|
||||
const accidents = await accidentService.getAccidents(token, club.id, diaryDate.id);
|
||||
|
||||
expect(accidents).toHaveLength(1);
|
||||
expect(accidents[0]).toMatchObject({ firstName: 'Clara', accident: 'Verstauchung' });
|
||||
});
|
||||
});
|
||||
63
backend/tests/activityController.test.js
Normal file
63
backend/tests/activityController.test.js
Normal file
@@ -0,0 +1,63 @@
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import request from 'supertest';
|
||||
|
||||
vi.mock('../services/emailService.js', () => ({
|
||||
sendActivationEmail: vi.fn().mockResolvedValue(),
|
||||
}));
|
||||
|
||||
import app from './testApp.js';
|
||||
import sequelize from '../database.js';
|
||||
import User from '../models/User.js';
|
||||
import Club from '../models/Club.js';
|
||||
import UserClub from '../models/UserClub.js';
|
||||
import DiaryDate from '../models/DiaryDates.js';
|
||||
|
||||
const registerAndActivate = async (email) => {
|
||||
const password = 'Test123!';
|
||||
await request(app).post('/api/auth/register').send({ email, password });
|
||||
const user = await User.findOne({ where: { email } });
|
||||
await user.update({ isActive: true });
|
||||
return { user, credentials: { email, password } };
|
||||
};
|
||||
|
||||
const loginAndGetToken = async (credentials) => {
|
||||
const response = await request(app).post('/api/auth/login').send(credentials);
|
||||
return response.body.token;
|
||||
};
|
||||
|
||||
describe('Activity Routes', () => {
|
||||
beforeEach(async () => {
|
||||
await sequelize.sync({ force: true });
|
||||
});
|
||||
|
||||
it('erstellt und liest Aktivitäten', async () => {
|
||||
const { user, credentials } = await registerAndActivate('activity@example.com');
|
||||
const token = await loginAndGetToken(credentials);
|
||||
const club = await Club.create({ name: 'Activity Club' });
|
||||
await UserClub.create({ userId: user.id, clubId: club.id, role: 'admin', approved: true, isOwner: true });
|
||||
const diaryDate = await DiaryDate.create({ clubId: club.id, date: new Date(), description: 'Training' });
|
||||
|
||||
const createResponse = await request(app)
|
||||
.post('/api/activities/add')
|
||||
.set('Authorization', `Bearer ${token}`)
|
||||
.send({ diaryDateId: diaryDate.id, description: 'Koordinationsübungen' });
|
||||
|
||||
expect(createResponse.status).toBe(201);
|
||||
|
||||
const listResponse = await request(app)
|
||||
.get(`/api/activities/${diaryDate.id}`)
|
||||
.set('Authorization', `Bearer ${token}`);
|
||||
|
||||
expect(listResponse.status).toBe(200);
|
||||
expect(listResponse.body).toHaveLength(1);
|
||||
expect(listResponse.body[0]).toMatchObject({ description: 'Koordinationsübungen' });
|
||||
});
|
||||
|
||||
it('verweigert Anlage einer Aktivität ohne Token', async () => {
|
||||
const response = await request(app)
|
||||
.post('/api/activities/add')
|
||||
.send({ diaryDateId: 1, description: 'Test' });
|
||||
|
||||
expect(response.status).toBe(401);
|
||||
});
|
||||
});
|
||||
39
backend/tests/activityService.test.js
Normal file
39
backend/tests/activityService.test.js
Normal file
@@ -0,0 +1,39 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
|
||||
import sequelize from '../database.js';
|
||||
import Activity from '../models/Activity.js';
|
||||
import DiaryDate from '../models/DiaryDates.js';
|
||||
import activityController from '../controllers/activityController.js';
|
||||
|
||||
import { buildMockRequest, buildMockResponse } from './testUtils.js';
|
||||
|
||||
describe('activityController', () => {
|
||||
beforeEach(async () => {
|
||||
await sequelize.sync({ force: true });
|
||||
});
|
||||
|
||||
it('fügt eine Aktivität hinzu', async () => {
|
||||
const diaryDate = await DiaryDate.create({ clubId: 1, date: new Date(), description: 'Training' });
|
||||
const req = buildMockRequest({ body: { diaryDateId: diaryDate.id, description: 'Koordination' } });
|
||||
const res = buildMockResponse();
|
||||
|
||||
await activityController.addActivity(req, res);
|
||||
|
||||
expect(res.status).toHaveBeenCalledWith(201);
|
||||
const stored = await Activity.findOne({ where: { diaryDateId: diaryDate.id } });
|
||||
expect(stored.description).toBe('Koordination');
|
||||
});
|
||||
|
||||
it('liefert Aktivitäten für einen Trainingstag', async () => {
|
||||
const diaryDate = await DiaryDate.create({ clubId: 1, date: new Date(), description: 'Training' });
|
||||
await Activity.create({ diaryDateId: diaryDate.id, description: 'Aufwärmen' });
|
||||
|
||||
const req = buildMockRequest({ params: { diaryDateId: diaryDate.id } });
|
||||
const res = buildMockResponse();
|
||||
|
||||
await activityController.getActivities(req, res);
|
||||
|
||||
expect(res.status).toHaveBeenCalledWith(200);
|
||||
expect(res.json.mock.calls[0][0]).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
@@ -1,12 +1,16 @@
|
||||
import express from 'express';
|
||||
import authRoutes from '../routes/authRoutes.js';
|
||||
import permissionRoutes from '../routes/permissionRoutes.js';
|
||||
import accidentRoutes from '../routes/accidentRoutes.js';
|
||||
import activityRoutes from '../routes/activityRoutes.js';
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(express.json());
|
||||
app.use('/api/auth', authRoutes);
|
||||
app.use('/api/permissions', permissionRoutes);
|
||||
app.use('/api/accident', accidentRoutes);
|
||||
app.use('/api/activities', activityRoutes);
|
||||
|
||||
app.use((err, req, res, next) => {
|
||||
const status = err?.status || err?.statusCode || 500;
|
||||
|
||||
16
backend/tests/testUtils.js
Normal file
16
backend/tests/testUtils.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import { vi } from 'vitest';
|
||||
|
||||
export function buildMockRequest({ body = {}, params = {}, headers = {} } = {}) {
|
||||
return {
|
||||
body,
|
||||
params,
|
||||
headers,
|
||||
};
|
||||
}
|
||||
|
||||
export function buildMockResponse() {
|
||||
const res = {};
|
||||
res.status = vi.fn().mockReturnValue(res);
|
||||
res.json = vi.fn().mockReturnValue(res);
|
||||
return res;
|
||||
}
|
||||
Reference in New Issue
Block a user