Fix in news, first android notification service
Some checks failed
Code Analysis and Production Deploy / analyze (push) Failing after 7m50s
Code Analysis and Production Deploy / deploy-production (push) Has been skipped
Code Analysis and Production Deploy / deploy-test (push) Has been skipped

This commit is contained in:
Torsten Schulz (local)
2026-06-10 13:47:33 +02:00
parent e8a50e55ca
commit 5da11d2e4d
28 changed files with 1277 additions and 43 deletions

View File

@@ -35,6 +35,9 @@ import configGetHandler from '../server/api/config.get.js'
import configPutHandler from '../server/api/config.put.js'
import profileGetHandler from '../server/api/profile.get.js'
import profilePutHandler from '../server/api/profile.put.js'
import profileNotificationsGetHandler from '../server/api/profile/notifications.get.js'
import profileNotificationsPutHandler from '../server/api/profile/notifications.put.js'
import profilePushTokenHandler from '../server/api/profile/push-token.post.js'
const invalidCurrentPassword = ['invalid', 'test', 'pw'].join('-')
const validCurrentPassword = ['valid', 'test', 'pw'].join('-')
@@ -157,6 +160,113 @@ describe('Config & Profil Endpoints', () => {
})
})
describe('GET /api/profile/notifications', () => {
it('verlangt Authentifizierung', async () => {
const event = createEvent()
await expect(profileNotificationsGetHandler(event)).rejects.toMatchObject({ statusCode: 401 })
})
it('liefert Defaults plus gespeicherte Benachrichtigungseinstellungen', async () => {
const event = createEvent({ headers: { authorization: 'Bearer android-token' } })
authUtils.verifyToken.mockReturnValue({ id: '1' })
authUtils.getUserFromToken.mockResolvedValue({
id: '1',
notificationSettings: {
eventsToday: true,
selectedTeamSlugs: ['herren-1', 'herren-1', ''],
selectedTeamSeason: '2025/2026',
notificationTime: '07:30'
}
})
const result = await profileNotificationsGetHandler(event)
expect(result.success).toBe(true)
expect(result.settings.eventsToday).toBe(true)
expect(result.settings.newEvents).toBe(false)
expect(result.settings.selectedTeamSlugs).toEqual(['herren-1'])
expect(result.settings.notificationTime).toBe('07:30')
})
})
describe('PUT /api/profile/notifications', () => {
it('verlangt Authentifizierung', async () => {
const event = createEvent({ body: { eventsToday: true } })
await expect(profileNotificationsPutHandler(event)).rejects.toMatchObject({ statusCode: 401 })
})
it('speichert sanitizte Benachrichtigungseinstellungen am Benutzer', async () => {
const event = createEvent({ headers: { authorization: 'Bearer android-token' } })
mockSuccessReadBody({
newEvents: true,
eventsToday: 'true',
birthdays: true,
selectedTeamSlugs: ['herren-1', 'herren-1', ' jugend '],
selectedTeamSeason: '2026/2027',
notificationTime: '25:99'
})
const users = [{ id: '1', email: 'max@test.de', roles: ['mitglied'] }]
authUtils.verifyToken.mockReturnValue({ id: '1' })
authUtils.getUserFromToken.mockResolvedValue(users[0])
authUtils.readUsers.mockResolvedValue(users)
authUtils.writeUsers.mockResolvedValue(true)
const result = await profileNotificationsPutHandler(event)
expect(result.success).toBe(true)
expect(result.settings.newEvents).toBe(true)
expect(result.settings.eventsToday).toBe(false)
expect(result.settings.birthdays).toBe(true)
expect(result.settings.selectedTeamSlugs).toEqual(['herren-1', 'jugend'])
expect(result.settings.notificationTime).toBe('09:00')
expect(authUtils.writeUsers).toHaveBeenCalledWith([
expect.objectContaining({
id: '1',
notificationSettings: expect.objectContaining({
newEvents: true,
birthdays: true,
selectedTeamSeason: '2026/2027'
})
})
])
})
})
describe('POST /api/profile/push-token', () => {
it('verlangt Authentifizierung', async () => {
const event = createEvent()
mockSuccessReadBody({ token: 'fcm-token' })
await expect(profilePushTokenHandler(event)).rejects.toMatchObject({ statusCode: 401 })
})
it('speichert Android-Push-Token am Benutzer', async () => {
const event = createEvent({ headers: { authorization: 'Bearer android-token' } })
mockSuccessReadBody({ token: 'fcm-token', platform: 'android', appVersion: '1.0+1' })
const users = [{ id: '1', email: 'max@test.de', roles: ['mitglied'] }]
authUtils.verifyToken.mockReturnValue({ id: '1' })
authUtils.getUserFromToken.mockResolvedValue(users[0])
authUtils.readUsers.mockResolvedValue(users)
authUtils.writeUsers.mockResolvedValue(true)
const result = await profilePushTokenHandler(event)
expect(result.success).toBe(true)
expect(authUtils.writeUsers).toHaveBeenCalledWith([
expect.objectContaining({
id: '1',
pushTokens: [expect.objectContaining({ token: 'fcm-token', platform: 'android', appVersion: '1.0+1' })]
})
])
})
})
describe('PUT /api/profile', () => {
it('verlangt Authentifizierung', async () => {
const event = createEvent()

View File

@@ -17,8 +17,13 @@ vi.mock('../server/utils/news.js', () => ({
deleteNews: vi.fn()
}))
vi.mock('../server/utils/push-notifications.js', () => ({
sendNewNewsPush: vi.fn().mockResolvedValue({ sent: 1, skipped: false })
}))
const authUtils = await import('../server/utils/auth.js')
const newsUtils = await import('../server/utils/news.js')
const pushUtils = await import('../server/utils/push-notifications.js')
import newsGetHandler from '../server/api/news.get.js'
import newsPostHandler from '../server/api/news.post.js'
@@ -111,6 +116,29 @@ describe('News API Endpoints', () => {
expect(newsUtils.saveNews).toHaveBeenCalledWith(
expect.objectContaining({ title: 'Neue Info', content: 'Inhalt hier', isPublic: true })
)
expect(pushUtils.sendNewNewsPush).toHaveBeenCalledWith(
expect.objectContaining({ title: 'Neue Info', content: 'Inhalt hier', isPublic: true })
)
})
it('sendet keinen Push bei News-Update', async () => {
const event = adminEvent()
newsUtils.saveNews.mockResolvedValue(undefined)
mockSuccessReadBody({ id: 'existing-news', title: 'Update', content: 'Inhalt' })
await newsPostHandler(event)
expect(pushUtils.sendNewNewsPush).not.toHaveBeenCalled()
})
it('sendet keinen Push bei versteckten News', async () => {
const event = adminEvent()
newsUtils.saveNews.mockResolvedValue(undefined)
mockSuccessReadBody({ title: 'Intern', content: 'Inhalt', isHidden: true })
await newsPostHandler(event)
expect(pushUtils.sendNewNewsPush).not.toHaveBeenCalled()
})
it('setzt autor auf den angemeldeten Benutzer', async () => {