feat(sprint-6): Phase 6 — Notifications (WebSocket) + PWA
- 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
This commit is contained in:
@@ -59,9 +59,9 @@ test.describe("Group 1: Login Form Interactions", () => {
|
||||
expect(page.url()).toContain("/login")
|
||||
|
||||
// The email input should fail native HTML5 validation
|
||||
const isInvalid = await page.locator('input[id="email"]').evaluate(
|
||||
(el: HTMLInputElement) => !el.checkValidity()
|
||||
)
|
||||
const isInvalid = await page
|
||||
.locator('input[id="email"]')
|
||||
.evaluate((el: HTMLInputElement) => !el.checkValidity())
|
||||
expect(isInvalid).toBe(true)
|
||||
})
|
||||
|
||||
@@ -192,7 +192,9 @@ test.describe("Group 3: Navigation & Layout", () => {
|
||||
const url = page.url()
|
||||
// If redirected to login — that's also acceptable behavior for protected routes
|
||||
const is404OrLogin = url.includes("/login") || url.includes("not-found")
|
||||
expect(is404OrLogin || (await page.locator("body").textContent()) !== "").toBe(true)
|
||||
expect(
|
||||
is404OrLogin || (await page.locator("body").textContent()) !== ""
|
||||
).toBe(true)
|
||||
})
|
||||
|
||||
test("3.3 - Responsive: mobile viewport (375px)", async ({ page }) => {
|
||||
@@ -611,9 +613,7 @@ test.describe("Group 11: Accessibility Basics", () => {
|
||||
await expect(emailInput).toHaveAttribute("autoComplete", "email")
|
||||
})
|
||||
|
||||
test("11.5 - Form submit button is keyboard-accessible", async ({
|
||||
page,
|
||||
}) => {
|
||||
test("11.5 - Form submit button is keyboard-accessible", async ({ page }) => {
|
||||
await page.goto("/login", { waitUntil: "domcontentloaded" })
|
||||
await page.waitForSelector('input[id="email"]', { timeout: 15000 })
|
||||
|
||||
@@ -683,7 +683,8 @@ test.describe("Group 12: Error States & Edge Cases", () => {
|
||||
|
||||
// Page should not crash — wait and verify it's still functional
|
||||
await page.waitForTimeout(3000)
|
||||
const isStillOnLogin = page.url().includes("/login") || page.url().includes("/dashboard")
|
||||
const isStillOnLogin =
|
||||
page.url().includes("/login") || page.url().includes("/dashboard")
|
||||
expect(isStillOnLogin).toBe(true)
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user