599514c0db
- WebSocket: Spring STOMP + SockJS, NotificationService, persistent notifications table - NotificationController: GET/PUT endpoints for notification management - Frontend: notification bell with unread badge, dropdown panel, real-time via STOMP - PWA: manifest.json, service worker (manual sw.js), offline page, install prompt - PWA icons (192+512), dark theme colors, standalone display - Full i18n (de/en) for notifications and PWA - Flyway V10 migration for notifications table - spring-boot-starter-websocket dependency added
85 lines
2.5 KiB
JavaScript
85 lines
2.5 KiB
JavaScript
/**
|
|
* Smart mock backend for authenticated E2E tours.
|
|
* Handles auth endpoints so NextAuth can create valid sessions.
|
|
* Run: node e2e/mock-backend.mjs
|
|
*/
|
|
import http from "node:http"
|
|
|
|
const MOCK_USER = {
|
|
id: "user-001",
|
|
email: "admin@gruener-daumen.de",
|
|
role: "ADMIN",
|
|
clubId: "club-001",
|
|
clubName: "Grüner Daumen e.V.",
|
|
}
|
|
|
|
const server = http.createServer((req, res) => {
|
|
// CORS headers
|
|
res.setHeader("Access-Control-Allow-Origin", "*")
|
|
res.setHeader(
|
|
"Access-Control-Allow-Methods",
|
|
"GET, POST, PUT, DELETE, OPTIONS"
|
|
)
|
|
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization")
|
|
|
|
if (req.method === "OPTIONS") {
|
|
res.writeHead(204)
|
|
res.end()
|
|
return
|
|
}
|
|
|
|
const url = req.url?.split("?")[0] // strip query params
|
|
|
|
// Login endpoint
|
|
if (url === "/api/v1/auth/login" && req.method === "POST") {
|
|
let body = ""
|
|
req.on("data", (chunk) => (body += chunk))
|
|
req.on("end", () => {
|
|
console.log(` ✓ POST /api/v1/auth/login — 200 OK`)
|
|
res.writeHead(200, { "Content-Type": "application/json" })
|
|
res.end(
|
|
JSON.stringify({
|
|
accessToken: "mock-jwt-token-for-e2e-testing-" + Date.now(),
|
|
refreshToken: "mock-refresh-token-" + Date.now(),
|
|
tokenType: "Bearer",
|
|
expiresIn: 3600,
|
|
member: MOCK_USER,
|
|
})
|
|
)
|
|
})
|
|
return
|
|
}
|
|
|
|
// Refresh endpoint
|
|
if (url === "/api/v1/auth/refresh" && req.method === "POST") {
|
|
let body = ""
|
|
req.on("data", (chunk) => (body += chunk))
|
|
req.on("end", () => {
|
|
console.log(` ✓ POST /api/v1/auth/refresh — 200 OK`)
|
|
res.writeHead(200, { "Content-Type": "application/json" })
|
|
res.end(
|
|
JSON.stringify({
|
|
accessToken: "mock-refreshed-token-" + Date.now(),
|
|
refreshToken: "mock-refresh-token-new-" + Date.now(),
|
|
tokenType: "Bearer",
|
|
expiresIn: 3600,
|
|
})
|
|
)
|
|
})
|
|
return
|
|
}
|
|
|
|
// Catch-all — return 200 with empty success (frontend uses local mock data)
|
|
console.log(` → ${req.method} ${req.url} — 200 (catch-all)`)
|
|
res.writeHead(200, { "Content-Type": "application/json" })
|
|
res.end(JSON.stringify({ status: "ok", message: "mock backend catch-all" }))
|
|
})
|
|
|
|
server.listen(8080, () => {
|
|
console.log("🟢 Smart mock backend running on http://localhost:8080")
|
|
console.log(" Endpoints:")
|
|
console.log(" • POST /api/v1/auth/login → valid auth response")
|
|
console.log(" • POST /api/v1/auth/refresh → refreshed token")
|
|
console.log(" • * → 200 catch-all")
|
|
})
|