Project-Image-Uploader/backend/tests/api/telegram-upload.test.js
matthias.lotz 62be18ecaa feat: Add upload notifications to Telegram Bot (Phase 3)
- Integrate TelegramNotificationService into batchUpload route
- Send notification on successful upload with group details
- Add metadata parsing for year/title/name from form fields
- Create integration tests for upload notifications
- Fix getAdminUrl() to use INTERNAL_HOST with dev port
- Update jest.config.js to transform uuid ESM module
- Non-blocking async notification (won't fail upload on error)

Phase 3 complete: Upload notifications working in Docker dev environment
Tested successfully with real Telegram bot in test group
2025-11-29 23:47:01 +01:00

184 lines
7.4 KiB
JavaScript

/**
* Integration Tests für Telegram Upload-Benachrichtigungen
*
* Phase 3: Upload-Benachrichtigungen
*
* Diese Tests prüfen die Integration zwischen Upload-Route und Telegram-Service
*/
const path = require('path');
const fs = require('fs');
const { getRequest } = require('../testServer');
describe('Telegram Upload Notifications (Integration)', () => {
let TelegramNotificationService;
let sendUploadNotificationSpy;
beforeAll(() => {
// Spy auf TelegramNotificationService
TelegramNotificationService = require('../../src/services/TelegramNotificationService');
});
beforeEach(() => {
// Spy auf sendUploadNotification erstellen
sendUploadNotificationSpy = jest.spyOn(TelegramNotificationService.prototype, 'sendUploadNotification')
.mockResolvedValue({ message_id: 42 });
// isAvailable() immer true zurückgeben für Tests
jest.spyOn(TelegramNotificationService.prototype, 'isAvailable')
.mockReturnValue(true);
});
afterEach(() => {
// Restore alle Spys
jest.restoreAllMocks();
});
describe('POST /api/upload/batch', () => {
const testImagePath = path.join(__dirname, '../utils/test-image.jpg');
// Erstelle Test-Bild falls nicht vorhanden
beforeAll(() => {
if (!fs.existsSync(testImagePath)) {
// Erstelle 1x1 px JPEG
const buffer = Buffer.from([
0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46,
0x49, 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01,
0x00, 0x01, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0x43,
0x00, 0x08, 0x06, 0x06, 0x07, 0x06, 0x05, 0x08,
0x07, 0x07, 0x07, 0x09, 0x09, 0x08, 0x0A, 0x0C,
0x14, 0x0D, 0x0C, 0x0B, 0x0B, 0x0C, 0x19, 0x12,
0x13, 0x0F, 0x14, 0x1D, 0x1A, 0x1F, 0x1E, 0x1D,
0x1A, 0x1C, 0x1C, 0x20, 0x24, 0x2E, 0x27, 0x20,
0x22, 0x2C, 0x23, 0x1C, 0x1C, 0x28, 0x37, 0x29,
0x2C, 0x30, 0x31, 0x34, 0x34, 0x34, 0x1F, 0x27,
0x39, 0x3D, 0x38, 0x32, 0x3C, 0x2E, 0x33, 0x34,
0x32, 0xFF, 0xC0, 0x00, 0x0B, 0x08, 0x00, 0x01,
0x00, 0x01, 0x01, 0x01, 0x11, 0x00, 0xFF, 0xC4,
0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0xFF, 0xC4, 0x00, 0x14,
0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xDA, 0x00, 0x08, 0x01, 0x01,
0x00, 0x00, 0x3F, 0x00, 0x37, 0xFF, 0xD9
]);
fs.writeFileSync(testImagePath, buffer);
}
});
it('sollte Telegram-Benachrichtigung bei erfolgreichem Upload senden', async () => {
const response = await getRequest()
.post('/api/upload/batch')
.field('year', '2024')
.field('title', 'Test Upload')
.field('name', 'Test User')
.field('consents', JSON.stringify({
workshopConsent: true,
socialMediaConsents: ['instagram', 'tiktok']
}))
.attach('images', testImagePath);
// Upload sollte erfolgreich sein
expect(response.status).toBe(200);
expect(response.body.message).toBe('Batch upload successful');
// Warte kurz auf async Telegram-Call
await new Promise(resolve => setTimeout(resolve, 150));
// Telegram-Service sollte aufgerufen worden sein
expect(sendUploadNotificationSpy).toHaveBeenCalledWith(
expect.objectContaining({
name: 'Test User',
year: 2024,
title: 'Test Upload',
imageCount: 1,
workshopConsent: true,
socialMediaConsents: ['instagram', 'tiktok']
})
);
});
it('sollte Upload nicht fehlschlagen wenn Telegram-Service nicht verfügbar', async () => {
// Restore mock und setze isAvailable auf false
jest.restoreAllMocks();
jest.spyOn(TelegramNotificationService.prototype, 'isAvailable')
.mockReturnValue(false);
sendUploadNotificationSpy = jest.spyOn(TelegramNotificationService.prototype, 'sendUploadNotification');
const response = await getRequest()
.post('/api/upload/batch')
.field('year', '2024')
.field('title', 'Test Upload')
.field('name', 'Test User')
.field('consents', JSON.stringify({
workshopConsent: false,
socialMediaConsents: []
}))
.attach('images', testImagePath);
// Upload sollte trotzdem erfolgreich sein
expect(response.status).toBe(200);
expect(response.body.message).toBe('Batch upload successful');
// Telegram sollte nicht aufgerufen worden sein
expect(sendUploadNotificationSpy).not.toHaveBeenCalled();
});
it('sollte Upload nicht fehlschlagen wenn Telegram-Benachrichtigung fehlschlägt', async () => {
sendUploadNotificationSpy.mockRejectedValueOnce(
new Error('Telegram API Error')
);
const response = await getRequest()
.post('/api/upload/batch')
.field('year', '2024')
.field('title', 'Test Upload')
.field('name', 'Test User')
.field('consents', JSON.stringify({
workshopConsent: true,
socialMediaConsents: []
}))
.attach('images', testImagePath);
// Upload sollte trotzdem erfolgreich sein
expect(response.status).toBe(200);
expect(response.body.message).toBe('Batch upload successful');
// Warte auf async error handling
await new Promise(resolve => setTimeout(resolve, 150));
// Telegram wurde versucht aufzurufen
expect(sendUploadNotificationSpy).toHaveBeenCalled();
});
it('sollte korrekte Daten an Telegram-Service übergeben', async () => {
const response = await getRequest()
.post('/api/upload/batch')
.field('year', '2025')
.field('title', 'Schweißkurs November')
.field('name', 'Max Mustermann')
.field('consents', JSON.stringify({
workshopConsent: true,
socialMediaConsents: ['facebook', 'instagram']
}))
.attach('images', testImagePath)
.attach('images', testImagePath);
expect(response.status).toBe(200);
await new Promise(resolve => setTimeout(resolve, 150));
expect(sendUploadNotificationSpy).toHaveBeenCalledWith({
name: 'Max Mustermann',
year: 2025,
title: 'Schweißkurs November',
imageCount: 2,
workshopConsent: true,
socialMediaConsents: ['facebook', 'instagram'],
token: expect.any(String)
});
});
});
});