From 775b320b425bef6177d4e56dbe92a9949f58dc1a Mon Sep 17 00:00:00 2001 From: senke Date: Mon, 6 Apr 2026 13:35:26 +0200 Subject: [PATCH] feat(e2e): add 303 deep behavioral tests + fix WebSocket + lint-staged 9 deep E2E test files (303 tests total): 41-chat(33) 42-player(31) 43-upload(28) 44-auth(37) 45-playlists(35) 46-search(32) 47-social(30) 48-marketplace(30) 49-settings(37) Fix WebSocket origin bug (Chat never worked): GetAllowedWebSocketOrigins() excluded localhost/127.0.0.1 in dev. Fix lint-staged gofmt: pass files as args not stdin. Co-Authored-By: Claude Opus 4.6 (1M context) --- .lintstagedrc.json | 15 + tests/e2e/41-chat-deep.spec.ts | 723 ++++++++++ tests/e2e/42-player-deep.spec.ts | 1273 +++++++++++++++++ tests/e2e/43-upload-deep.spec.ts | 835 +++++++++++ tests/e2e/44-auth-deep.spec.ts | 1083 ++++++++++++++ tests/e2e/45-playlists-deep.spec.ts | 944 ++++++++++++ tests/e2e/46-search-discover-deep.spec.ts | 940 ++++++++++++ tests/e2e/47-social-deep.spec.ts | 668 +++++++++ tests/e2e/48-marketplace-deep.spec.ts | 654 +++++++++ .../49-notifications-settings-deep.spec.ts | 924 ++++++++++++ veza-backend-api/internal/handlers/common.go | 5 + 11 files changed, 8064 insertions(+) create mode 100644 .lintstagedrc.json create mode 100644 tests/e2e/41-chat-deep.spec.ts create mode 100644 tests/e2e/42-player-deep.spec.ts create mode 100644 tests/e2e/43-upload-deep.spec.ts create mode 100644 tests/e2e/44-auth-deep.spec.ts create mode 100644 tests/e2e/45-playlists-deep.spec.ts create mode 100644 tests/e2e/46-search-discover-deep.spec.ts create mode 100644 tests/e2e/47-social-deep.spec.ts create mode 100644 tests/e2e/48-marketplace-deep.spec.ts create mode 100644 tests/e2e/49-notifications-settings-deep.spec.ts diff --git a/.lintstagedrc.json b/.lintstagedrc.json new file mode 100644 index 000000000..8ff13f577 --- /dev/null +++ b/.lintstagedrc.json @@ -0,0 +1,15 @@ +{ + "apps/web/**/*.{ts,tsx}": [ + "bash -c 'cd apps/web && npx eslint --max-warnings=0 --fix'", + "bash -c 'cd apps/web && npx tsc --noEmit -p tsconfig.json'" + ], + "apps/web/**/*.{js,jsx,json,css,md}": ["prettier --write"], + "veza-backend-api/**/*.go": [ + "bash -c 'cd veza-backend-api && gofmt -l -w \"$@\"' --", + "bash -c 'cd veza-backend-api && go vet ./...'" + ], + "veza-stream-server/**/*.rs": [ + "bash -c 'cd veza-stream-server && cargo fmt --'" + ], + "*.{json,md,yml,yaml}": ["prettier --write"] +} diff --git a/tests/e2e/41-chat-deep.spec.ts b/tests/e2e/41-chat-deep.spec.ts new file mode 100644 index 000000000..c09167dfc --- /dev/null +++ b/tests/e2e/41-chat-deep.spec.ts @@ -0,0 +1,723 @@ +import { test, expect, type Page } from '@playwright/test'; +import { loginViaAPI, CONFIG, navigateTo } from './helpers'; + +/** + * CHAT DEEP — Behavioural E2E tests for the chat feature. + * + * These tests are written BECAUSE Chat has historically been broken. + * They make REAL assertions about the state of the app and will FAIL + * when the feature is broken — that is the whole point. + * + * Components tested (source of truth): + * - apps/web/src/features/chat/pages/ChatPage.tsx + * - apps/web/src/features/chat/components/ChatSidebar.tsx + * - apps/web/src/features/chat/components/ChatRoom.tsx + * - apps/web/src/features/chat/components/ChatInput.tsx + * - apps/web/src/features/chat/components/ChatMessage.tsx + * - apps/web/src/features/chat/hooks/useChat.ts + * - apps/web/src/features/chat/store/chatStore.ts + * + * Selectors derived from the above code: + * - Message input: [aria-label="Type a message"] (placeholder "Broadcast message...") + * - Send button: [aria-label="Send message"] + * - Attach file: [aria-label="Attach file"] + * - Emoji button: [aria-label="Add emoji"] | [aria-label="Close emoji picker"] + * - Voice button: [aria-label="Voice message"] + * - Room name input (dialog): #room-name + * - Channels list heading: "Active Channels" + * - Connection dot: w-2 h-2 rounded-full (bg-success when connected, bg-destructive otherwise) + * - Empty state placeholder: "No conversation selected" | "Pick a channel from the sidebar" + * - Empty message state: "No messages yet" / "Send the first message" + * + * Routes: /chat (protected, redirects to /login when unauthenticated). + */ + +const CHAT_URL = `${CONFIG.baseURL}/chat`; + +// --- Small helpers scoped to this file -------------------------------------- + +/** Wait for the ChatPage to mount and either be connected or show a state. */ +async function waitForChatPageReady(page: Page): Promise { + // The page root renders either: + // - "ESTABLISHING UPLINK..." while loading + // - The main chat layout with "Active Channels" heading + // - The "Access Restricted" card + // - The "Connection Terminated" error card + // We accept any of those as "ready" (mount complete), but prefer the main layout. + await expect( + page.locator( + 'h2:has-text("Active Channels"), h2:has-text("Access Restricted"), h2:has-text("Connection Terminated"), p:has-text("ESTABLISHING UPLINK")', + ).first(), + ).toBeVisible({ timeout: CONFIG.timeouts.navigation }); +} + +/** Get the first conversation row from the sidebar (buttons rendered by ConversationItem). */ +function firstConversationRow(page: Page) { + // ConversationItem renders a