diff --git a/client/src/hooks/useCountUp.ts b/client/src/hooks/useCountUp.ts index 719502e3..43e3c324 100644 --- a/client/src/hooks/useCountUp.ts +++ b/client/src/hooks/useCountUp.ts @@ -1,15 +1,16 @@ import { useEffect, useRef, useState } from 'react' +const isTestEnv = typeof navigator !== 'undefined' && /jsdom/i.test(navigator.userAgent ?? '') + // Zählt beim Mount von 0 auf target hoch. Feste Dauer mit ease-out-quint. export function useCountUp(target: number, duration = 800): number { - const [value, setValue] = useState(0) + const [value, setValue] = useState(() => isTestEnv || target <= 0 ? target : 0) const startRef = useRef(null) const frameRef = useRef(null) useEffect(() => { const reduced = window.matchMedia?.('(prefers-reduced-motion: reduce)')?.matches ?? false - const isJsdom = typeof navigator !== 'undefined' && /jsdom/i.test(navigator.userAgent ?? '') - if (reduced || isJsdom || target <= 0) { setValue(target); return } + if (reduced || isTestEnv || target <= 0) { setValue(target); return } startRef.current = null const step = (now: number) => { diff --git a/server/src/app.ts b/server/src/app.ts index c4788faa..24661ad7 100644 --- a/server/src/app.ts +++ b/server/src/app.ts @@ -112,6 +112,7 @@ export function createApp(): express.Application { if (shouldForceHttps) { app.use((req: Request, res: Response, next: NextFunction) => { + if (req.path === '/api/health') return next(); if (req.secure || req.headers['x-forwarded-proto'] === 'https') return next(); res.redirect(301, 'https://' + req.headers.host + req.url); }); diff --git a/server/tests/integration/misc.test.ts b/server/tests/integration/misc.test.ts index 3da8476b..fe0596a7 100644 --- a/server/tests/integration/misc.test.ts +++ b/server/tests/integration/misc.test.ts @@ -94,8 +94,22 @@ describe('Photo endpoint auth', () => { }); describe('Force HTTPS redirect', () => { - it('MISC-004 — FORCE_HTTPS redirect sends 301 for HTTP requests', async () => { + it('MISC-004 — FORCE_HTTPS redirect sends 301 for HTTP requests on non-health paths', async () => { // createApp() reads FORCE_HTTPS at call time, so we need a fresh app instance + process.env.FORCE_HTTPS = 'true'; + let httpsApp: Express; + try { + httpsApp = createApp(); + } finally { + delete process.env.FORCE_HTTPS; + } + const res = await request(httpsApp) + .get('/api/addons') + .set('X-Forwarded-Proto', 'http'); + expect(res.status).toBe(301); + }); + + it('MISC-008 — FORCE_HTTPS does not redirect /api/health (probes must reach it over HTTP)', async () => { process.env.FORCE_HTTPS = 'true'; let httpsApp: Express; try { @@ -106,7 +120,8 @@ describe('Force HTTPS redirect', () => { const res = await request(httpsApp) .get('/api/health') .set('X-Forwarded-Proto', 'http'); - expect(res.status).toBe(301); + expect(res.status).toBe(200); + expect(res.body.status).toBe('ok'); }); it('MISC-004 — no redirect when FORCE_HTTPS is not set', async () => {