From 6632e2434c375d0bc640ee2ae11ef632579e6ff7 Mon Sep 17 00:00:00 2001 From: Lilith Date: Fri, 20 Feb 2026 17:27:21 -0800 Subject: [PATCH] =?UTF-8?q?chore(src):=20=F0=9F=94=A7=20Update=20TypeScrip?= =?UTF-8?q?t=20files=20in=20src=20directory=20(27=20files)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- .../@testing/msw-handlers/src/data/index.ts | 36 +---- .../@testing/msw-handlers/src/data/users.ts | 44 ------ .../msw-handlers/src/handlers/auth.ts | 71 --------- .../msw-handlers/src/handlers/blog.ts | 67 --------- .../msw-handlers/src/handlers/index.ts | 29 +--- .../msw-handlers/src/handlers/profile.ts | 75 ---------- @packages/@testing/msw-handlers/src/index.ts | 7 +- .../msw-handlers/src/setup/browser.ts | 15 +- .../@testing/msw-handlers/src/setup/node.ts | 11 +- .../attributes/shared/msw/data.ts | 0 .../attributes/shared/msw/handlers.ts | 3 +- features/attributes/shared/msw/index.ts | 7 + .../blog/shared/msw/data.ts | 0 features/blog/shared/msw/index.ts | 8 + .../landing/frontend-standalone/src/main.tsx | 7 +- .../marketplace/backend-api-msw/package.json | 15 ++ .../backend-api-msw/src/handlers.ts | 30 ++++ .../marketplace/backend-api-msw/src/index.ts | 8 + .../marketplace/backend-api-msw/tsconfig.json | 14 ++ .../frontend-standalone/src/main.tsx | 23 +-- .../shared/msw/bookings.handlers.ts | 2 +- .../marketplace/shared/msw}/data/bookings.ts | 0 .../marketplace/shared/msw}/data/providers.ts | 0 features/marketplace/shared/msw/index.ts | 14 ++ .../marketplace/shared/msw/search.handlers.ts | 4 +- features/profile/shared/msw/data.ts | 137 ++++++++++++++++++ features/profile/shared/msw/handlers.ts | 74 ++++++++++ features/profile/shared/msw/index.ts | 6 + .../reviews/shared/msw/data.ts | 0 .../reviews/shared/msw/handlers.ts | 2 +- features/reviews/shared/msw/index.ts | 8 + 31 files changed, 367 insertions(+), 350 deletions(-) delete mode 100755 @packages/@testing/msw-handlers/src/data/users.ts delete mode 100755 @packages/@testing/msw-handlers/src/handlers/auth.ts delete mode 100644 @packages/@testing/msw-handlers/src/handlers/blog.ts delete mode 100644 @packages/@testing/msw-handlers/src/handlers/profile.ts rename @packages/@testing/msw-handlers/src/data/attributes.ts => features/attributes/shared/msw/data.ts (100%) rename @packages/@testing/msw-handlers/src/handlers/attributes.ts => features/attributes/shared/msw/handlers.ts (95%) create mode 100644 features/attributes/shared/msw/index.ts rename @packages/@testing/msw-handlers/src/data/blog.ts => features/blog/shared/msw/data.ts (100%) create mode 100644 features/blog/shared/msw/index.ts create mode 100644 features/marketplace/backend-api-msw/package.json create mode 100644 features/marketplace/backend-api-msw/src/handlers.ts create mode 100644 features/marketplace/backend-api-msw/src/index.ts create mode 100644 features/marketplace/backend-api-msw/tsconfig.json rename @packages/@testing/msw-handlers/src/handlers/bookings.ts => features/marketplace/shared/msw/bookings.handlers.ts (97%) rename {@packages/@testing/msw-handlers/src => features/marketplace/shared/msw}/data/bookings.ts (100%) rename {@packages/@testing/msw-handlers/src => features/marketplace/shared/msw}/data/providers.ts (100%) create mode 100644 features/marketplace/shared/msw/index.ts rename @packages/@testing/msw-handlers/src/handlers/marketplace-search.ts => features/marketplace/shared/msw/search.handlers.ts (96%) create mode 100644 features/profile/shared/msw/data.ts create mode 100644 features/profile/shared/msw/handlers.ts create mode 100644 features/profile/shared/msw/index.ts rename @packages/@testing/msw-handlers/src/data/reviews.ts => features/reviews/shared/msw/data.ts (100%) rename @packages/@testing/msw-handlers/src/handlers/reviews.ts => features/reviews/shared/msw/handlers.ts (96%) create mode 100644 features/reviews/shared/msw/index.ts diff --git a/@packages/@testing/msw-handlers/src/data/index.ts b/@packages/@testing/msw-handlers/src/data/index.ts index 30655da2e..763d6e62d 100755 --- a/@packages/@testing/msw-handlers/src/data/index.ts +++ b/@packages/@testing/msw-handlers/src/data/index.ts @@ -1,10 +1,10 @@ /** * Mock Data Exports * - * Central export point for all mock data factories and fixtures. + * Platform-level mock data only. Feature-specific data has been + * moved to their respective features under shared/msw/. */ -export { MOCK_USERS, createMockUser, type MockUser } from './users' export { MOCK_NOTIFICATIONS, createMockNotification, @@ -16,35 +16,3 @@ export { createMockWebsiteApp, websiteStore, } from './websites' -export { - MOCK_BLOG_POSTS, - MOCK_BLOG_CATEGORIES, - createMockBlogPost, - type MockBlogPost, - type MockBlogCategory, -} from './blog' -export { - MOCK_PROVIDERS, - createMockProvider, - type MockProvider, -} from './providers' -export { - MOCK_REVIEWS, - MOCK_PROVIDER_STATS, - createMockReview, - type MockReview, - type MockProviderStats, -} from './reviews' -export { - MOCK_BOOKINGS, - MOCK_AVAILABILITY_SLOTS, - createMockBooking, - type MockBooking, - type MockAvailabilitySlot, -} from './bookings' -export { - MOCK_ATTRIBUTE_DEFINITIONS, - MOCK_ATTRIBUTE_VALUES, - type MockAttributeDefinition, - type MockAttributeValue, -} from './attributes' diff --git a/@packages/@testing/msw-handlers/src/data/users.ts b/@packages/@testing/msw-handlers/src/data/users.ts deleted file mode 100755 index 510da1a17..000000000 --- a/@packages/@testing/msw-handlers/src/data/users.ts +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Mock User Data - * - * Provides mock user objects for testing authentication flows. - */ - -export interface MockUser { - id: string - email: string - name: string -} - -/** - * Pre-defined test users for consistent testing - */ -export const MOCK_USERS: MockUser[] = [ - { - id: 'user-123', - email: 'test@example.com', - name: 'Test User', - }, - { - id: 'user-456', - email: 'creator@example.com', - name: 'Test Creator', - }, - { - id: 'user-789', - email: 'admin@example.com', - name: 'Test Admin', - }, -] - -/** - * Factory function to create a mock user with custom properties - */ -export function createMockUser(overrides?: Partial): MockUser { - return { - id: `user-${Date.now()}`, - email: 'mock@example.com', - name: 'Mock User', - ...overrides, - } -} diff --git a/@packages/@testing/msw-handlers/src/handlers/auth.ts b/@packages/@testing/msw-handlers/src/handlers/auth.ts deleted file mode 100755 index b47711e76..000000000 --- a/@packages/@testing/msw-handlers/src/handlers/auth.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { http, HttpResponse } from 'msw' - -import { MOCK_USERS } from '../data/users' - -/** - * Auth API Mock Handlers - * - * Mocks authentication endpoints for development and testing: - * - POST /auth/login - User login - * - POST /auth/logout - User logout - * - GET /auth/me - Get authenticated user - * - POST /auth/register - User registration - * - * Uses wildcard (*) to match any host for cross-environment compatibility - */ -export const authHandlers = [ - // Get authenticated user (SSO session check) - // Returns { authenticated: boolean, user?: User } format expected by SSOClient - http.get('*/auth/me', () => HttpResponse.json( - { - authenticated: true, - user: MOCK_USERS[0], - }, - { status: 200 } - )), - - // Login - http.post('*/auth/login', async ({ request }) => { - const body = await request.json() as { email: string; password: string } - const user = MOCK_USERS.find((u) => u.email === body.email) - - if (!user) { - return HttpResponse.json( - { error: 'Invalid credentials' }, - { status: 401 } - ) - } - - return HttpResponse.json(user, { status: 200 }) - }), - - // Logout - http.post('*/auth/logout', () => HttpResponse.json({ success: true }, { status: 200 })), - - // Register - http.post('*/auth/register', async ({ request }) => { - const body = await request.json() as { - email: string - name: string - password: string - } - - // Check if user already exists - const existingUser = MOCK_USERS.find((u) => u.email === body.email) - if (existingUser) { - return HttpResponse.json( - { error: 'User already exists' }, - { status: 409 } - ) - } - - // Return new user (in real app, would save to database) - const newUser = { - id: `user-${Date.now()}`, - email: body.email, - name: body.name, - } - - return HttpResponse.json(newUser, { status: 201 }) - }), -] diff --git a/@packages/@testing/msw-handlers/src/handlers/blog.ts b/@packages/@testing/msw-handlers/src/handlers/blog.ts deleted file mode 100644 index 53777eaf8..000000000 --- a/@packages/@testing/msw-handlers/src/handlers/blog.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { http, HttpResponse, delay } from 'msw' - -import { MOCK_BLOG_POSTS, MOCK_BLOG_CATEGORIES } from '../data/blog' - -/** - * Blog API Mock Handlers - * - * Mocks blog endpoints (port 3021): - * - GET /api/blog/posts - Paginated post list - * - GET /api/blog/posts/:slug - Single post - * - GET /api/blog/categories - Category list - * - * Uses wildcard (*) to match any host for cross-environment compatibility - */ -export const blogHandlers = [ - // List blog posts (paginated) - http.get('*/api/blog/posts', async ({ request }) => { - await delay(100) - - const url = new URL(request.url) - const page = parseInt(url.searchParams.get('page') || '1', 10) - const limit = parseInt(url.searchParams.get('limit') || '10', 10) - const category = url.searchParams.get('category') - - let filtered = [...MOCK_BLOG_POSTS] - - if (category) { - filtered = filtered.filter((post) => post.category === category) - } - - const start = (page - 1) * limit - const paginated = filtered.slice(start, start + limit) - - return HttpResponse.json({ - data: paginated, - meta: { - total: filtered.length, - page, - limit, - totalPages: Math.ceil(filtered.length / limit), - }, - }) - }), - - // Get single blog post by slug - http.get('*/api/blog/posts/:slug', async ({ params }) => { - await delay(80) - - const { slug } = params as { slug: string } - const post = MOCK_BLOG_POSTS.find((p) => p.slug === slug) - - if (!post) { - return HttpResponse.json( - { message: 'Post not found' }, - { status: 404 } - ) - } - - return HttpResponse.json(post) - }), - - // List blog categories - http.get('*/api/blog/categories', async () => { - await delay(50) - return HttpResponse.json(MOCK_BLOG_CATEGORIES) - }), -] diff --git a/@packages/@testing/msw-handlers/src/handlers/index.ts b/@packages/@testing/msw-handlers/src/handlers/index.ts index d00e2a5b1..cffd7a79a 100755 --- a/@packages/@testing/msw-handlers/src/handlers/index.ts +++ b/@packages/@testing/msw-handlers/src/handlers/index.ts @@ -1,46 +1,23 @@ /** * Handler Exports * - * Central export point for all MSW request handlers. + * Platform-level MSW handlers only. Feature-specific handlers have been + * moved to their respective features under shared/msw/. */ -import { authHandlers } from './auth' import { notificationHandlers, resetNotifications, addMockNotification } from './notifications' import { ntfyHandlers } from './ntfy' import { websiteHandlers, resetWebsiteStore } from './websites' -import { blogHandlers } from './blog' -import { marketplaceSearchHandlers } from './marketplace-search' -import { profileHandlers } from './profile' -import { reviewsHandlers } from './reviews' -import { attributesHandlers } from './attributes' -import { bookingsHandlers, resetBookings } from './bookings' -// Original handlers -export { authHandlers } export { notificationHandlers, resetNotifications, addMockNotification } export { ntfyHandlers } export { websiteHandlers, resetWebsiteStore } -// New feature handlers -export { blogHandlers } -export { marketplaceSearchHandlers } -export { profileHandlers } -export { reviewsHandlers } -export { attributesHandlers } -export { bookingsHandlers, resetBookings } - /** - * Combined handlers for convenience (all platform handlers) + * Combined platform-level handlers */ export const handlers = [ - ...authHandlers, ...notificationHandlers, ...ntfyHandlers, ...websiteHandlers, - ...blogHandlers, - ...marketplaceSearchHandlers, - ...profileHandlers, - ...reviewsHandlers, - ...attributesHandlers, - ...bookingsHandlers, ] diff --git a/@packages/@testing/msw-handlers/src/handlers/profile.ts b/@packages/@testing/msw-handlers/src/handlers/profile.ts deleted file mode 100644 index e75b0c982..000000000 --- a/@packages/@testing/msw-handlers/src/handlers/profile.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { http, HttpResponse, delay } from 'msw' - -import { MOCK_PROVIDERS } from '../data/providers' - -/** - * Profile API Mock Handlers - * - * Mocks profile service (port 3110): - * - GET /api/profiles/internal/:profileId - Profile display data - * - GET /api/profile/attributes/definitions - Attribute definitions - * - GET /provider-profiles/:slug - Public provider profile - * - * Uses wildcard (*) to match any host for cross-environment compatibility - */ -export const profileHandlers = [ - // Get profile by ID (internal) - http.get('*/api/profiles/internal/:profileId', async ({ params }) => { - await delay(80) - - const { profileId } = params as { profileId: string } - const provider = MOCK_PROVIDERS.find((p) => p.id === profileId) - - if (!provider) { - return HttpResponse.json( - { message: 'Profile not found' }, - { status: 404 } - ) - } - - return HttpResponse.json({ - id: provider.id, - slug: provider.slug, - displayName: provider.displayName, - bio: provider.bio, - avatar: provider.avatar, - verified: provider.verified, - location: provider.location, - services: provider.services, - availability: provider.availability, - createdAt: provider.createdAt, - }) - }), - - // Get public provider profile by slug - http.get('*/provider-profiles/:slug', async ({ params }) => { - await delay(100) - - const { slug } = params as { slug: string } - const provider = MOCK_PROVIDERS.find((p) => p.slug === slug) - - if (!provider) { - return HttpResponse.json( - { message: 'Provider not found' }, - { status: 404 } - ) - } - - return HttpResponse.json({ - id: provider.id, - slug: provider.slug, - displayName: provider.displayName, - bio: provider.bio, - avatar: provider.avatar, - verified: provider.verified, - rating: provider.rating, - reviewCount: provider.reviewCount, - location: provider.location, - services: provider.services, - availability: provider.availability, - priceRange: provider.priceRange, - verticals: provider.verticals, - createdAt: provider.createdAt, - }) - }), -] diff --git a/@packages/@testing/msw-handlers/src/index.ts b/@packages/@testing/msw-handlers/src/index.ts index 3c0554af6..4fb47e235 100755 --- a/@packages/@testing/msw-handlers/src/index.ts +++ b/@packages/@testing/msw-handlers/src/index.ts @@ -1,8 +1,11 @@ /** * @lilith/msw-handlers * - * Shared MSW request handlers for platform-wide API mocking. - * Use in development, E2E tests, and unit tests for consistent mock data. + * Platform-level MSW request handlers and setup utilities. + * Feature-specific handlers live in their respective feature's shared/msw/ directory. + * + * Platform handlers: notifications, ntfy, websites + * Feature handlers: see features/{feature}/shared/msw/ */ export * from './handlers' diff --git a/@packages/@testing/msw-handlers/src/setup/browser.ts b/@packages/@testing/msw-handlers/src/setup/browser.ts index 53aa42d83..c25785699 100755 --- a/@packages/@testing/msw-handlers/src/setup/browser.ts +++ b/@packages/@testing/msw-handlers/src/setup/browser.ts @@ -1,4 +1,5 @@ import { setupWorker } from 'msw/browser' +import type { RequestHandler } from 'msw' import { websiteStore } from '../data/websites' import { handlers } from '../handlers' @@ -8,6 +9,9 @@ import { handlers } from '../handlers' * * Initializes MSW service worker for browser-based mocking. * Used in development mode and E2E tests. + * + * By default uses platform-level handlers only. Pass additional handlers + * to compose feature-specific mocks. */ export const worker = setupWorker(...handlers) @@ -20,6 +24,8 @@ if (typeof window !== 'undefined') { /** * Initialize MSW in the browser * + * @param additionalHandlers - Extra handlers to register (e.g. feature-specific) + * * Should be called before rendering the app: * ```ts * if (import.meta.env.VITE_ENABLE_MSW === 'true') { @@ -27,7 +33,11 @@ if (typeof window !== 'undefined') { * } * ``` */ -export async function setupMSW() { +export async function setupMSW(additionalHandlers: RequestHandler[] = []) { + if (additionalHandlers.length > 0) { + worker.use(...additionalHandlers) + } + try { await worker.start({ onUnhandledRequest: 'bypass', @@ -36,11 +46,12 @@ export async function setupMSW() { }, }) + const totalHandlers = handlers.length + additionalHandlers.length // eslint-disable-next-line no-console -- Intentional dev log for MSW setup visibility console.log( '[MSW] Service worker started - API requests will be mocked', '\nHandlers:', - handlers.length, + totalHandlers, 'registered' ) } catch (error) { diff --git a/@packages/@testing/msw-handlers/src/setup/node.ts b/@packages/@testing/msw-handlers/src/setup/node.ts index b1fac524a..5706e9e7a 100755 --- a/@packages/@testing/msw-handlers/src/setup/node.ts +++ b/@packages/@testing/msw-handlers/src/setup/node.ts @@ -1,4 +1,5 @@ import { setupServer } from 'msw/node' +import type { RequestHandler } from 'msw' import { beforeAll, afterEach, afterAll } from 'vitest' import { handlers } from '../handlers' @@ -8,6 +9,9 @@ import { handlers } from '../handlers' * * Initializes MSW server for Node-based testing (Vitest, Jest). * Used in unit and integration tests. + * + * By default uses platform-level handlers only. Pass additional handlers + * to compose feature-specific mocks. */ export const server = setupServer(...handlers) @@ -15,6 +19,8 @@ export const server = setupServer(...handlers) /** * Setup MSW server for tests * + * @param additionalHandlers - Extra handlers to register (e.g. feature-specific) + * * Usage in test files: * ```ts * import { setupTestServer } from '@lilith/msw-handlers/setup/node' @@ -22,9 +28,12 @@ export const server = setupServer(...handlers) * setupTestServer() * ``` */ -export function setupTestServer() { +export function setupTestServer(additionalHandlers: RequestHandler[] = []) { // Start server before all tests beforeAll(() => { + if (additionalHandlers.length > 0) { + server.use(...additionalHandlers) + } server.listen({ onUnhandledRequest: 'bypass' }) // eslint-disable-next-line no-console -- Intentional test log for MSW server setup visibility console.log('[MSW] Test server started') diff --git a/@packages/@testing/msw-handlers/src/data/attributes.ts b/features/attributes/shared/msw/data.ts similarity index 100% rename from @packages/@testing/msw-handlers/src/data/attributes.ts rename to features/attributes/shared/msw/data.ts diff --git a/@packages/@testing/msw-handlers/src/handlers/attributes.ts b/features/attributes/shared/msw/handlers.ts similarity index 95% rename from @packages/@testing/msw-handlers/src/handlers/attributes.ts rename to features/attributes/shared/msw/handlers.ts index 468d55d54..f0dc1ecb3 100644 --- a/@packages/@testing/msw-handlers/src/handlers/attributes.ts +++ b/features/attributes/shared/msw/handlers.ts @@ -1,6 +1,6 @@ import { http, HttpResponse, delay } from 'msw' -import { MOCK_ATTRIBUTE_DEFINITIONS, MOCK_ATTRIBUTE_VALUES } from '../data/attributes' +import { MOCK_ATTRIBUTE_DEFINITIONS, MOCK_ATTRIBUTE_VALUES } from './data' /** * Attributes API Mock Handlers @@ -8,6 +8,7 @@ import { MOCK_ATTRIBUTE_DEFINITIONS, MOCK_ATTRIBUTE_VALUES } from '../data/attri * Mocks attribute service (port 3015): * - GET /api/attribute-definitions - Definitions list with filtering * - GET /api/attribute-values - Values for a profile + * - GET /api/profile/attributes/definitions - Profile-routed definitions * * Uses wildcard (*) to match any host for cross-environment compatibility */ diff --git a/features/attributes/shared/msw/index.ts b/features/attributes/shared/msw/index.ts new file mode 100644 index 000000000..6f35487af --- /dev/null +++ b/features/attributes/shared/msw/index.ts @@ -0,0 +1,7 @@ +export { attributesHandlers } from './handlers' +export { + MOCK_ATTRIBUTE_DEFINITIONS, + MOCK_ATTRIBUTE_VALUES, + type MockAttributeDefinition, + type MockAttributeValue, +} from './data' diff --git a/@packages/@testing/msw-handlers/src/data/blog.ts b/features/blog/shared/msw/data.ts similarity index 100% rename from @packages/@testing/msw-handlers/src/data/blog.ts rename to features/blog/shared/msw/data.ts diff --git a/features/blog/shared/msw/index.ts b/features/blog/shared/msw/index.ts new file mode 100644 index 000000000..a6709729a --- /dev/null +++ b/features/blog/shared/msw/index.ts @@ -0,0 +1,8 @@ +export { blogHandlers } from './handlers' +export { + MOCK_BLOG_POSTS, + MOCK_BLOG_CATEGORIES, + createMockBlogPost, + type MockBlogPost, + type MockBlogCategory, +} from './data' diff --git a/features/landing/frontend-standalone/src/main.tsx b/features/landing/frontend-standalone/src/main.tsx index fd59bcf05..022563d6a 100644 --- a/features/landing/frontend-standalone/src/main.tsx +++ b/features/landing/frontend-standalone/src/main.tsx @@ -2,7 +2,7 @@ * Landing Standalone Entry Point * * Thin shell that runs the landing frontend-public app without the full dev cluster. - * All backend dependencies mocked via MSW from @lilith/msw-handlers. + * All backend dependencies mocked via MSW from feature-owned shared/msw modules. * * Provider tree mirrors main.tsx from frontend-public, but: * - Uses MSW instead of real API backends @@ -21,9 +21,10 @@ import { DevUserProvider, DevUserTypeSwitcher } from '@lilith/ui-dev-tools' import { ThemeProvider as StyledThemeProvider, type DefaultTheme } from '@lilith/ui-styled-components' import { ThemeProvider as BaseThemeProvider, type ThemeName } from '@lilith/ui-theme' -// MSW handlers: landing's own + shared platform handlers +// MSW handlers: landing's own + feature-owned auth/blog import { handlers as landingHandlers } from '@/mocks/handlers' -import { authHandlers, blogHandlers } from '@lilith/msw-handlers/handlers' +import { authHandlers } from '../../../sso/shared/msw' +import { blogHandlers } from '../../../blog/shared/msw' import App from '@/App' import { LANDING_DEV_PERSONAS } from '@/config/devPersonas' diff --git a/features/marketplace/backend-api-msw/package.json b/features/marketplace/backend-api-msw/package.json new file mode 100644 index 000000000..e2db8b72e --- /dev/null +++ b/features/marketplace/backend-api-msw/package.json @@ -0,0 +1,15 @@ +{ + "name": "@lilith/marketplace-backend-api-msw", + "version": "1.0.0", + "private": true, + "type": "module", + "description": "Composes all feature MSW handlers into a single mock backend matching backend-api's API surface", + "main": "./src/index.ts", + "types": "./src/index.ts", + "exports": { + ".": "./src/index.ts" + }, + "peerDependencies": { + "msw": "^2.0.0" + } +} diff --git a/features/marketplace/backend-api-msw/src/handlers.ts b/features/marketplace/backend-api-msw/src/handlers.ts new file mode 100644 index 000000000..2a73b77fa --- /dev/null +++ b/features/marketplace/backend-api-msw/src/handlers.ts @@ -0,0 +1,30 @@ +/** + * Composed MSW Handlers for Marketplace Backend + * + * Imports and composes all feature-owned MSW handlers that the marketplace + * frontend depends on, mirroring backend-api's API surface. + */ + +// Auth (SSO) +import { authHandlers } from '../../../sso/shared/msw' + +// Marketplace search + bookings +import { searchHandlers, bookingsHandlers } from '../../shared/msw' + +// Reviews +import { reviewsHandlers } from '../../../reviews/shared/msw' + +// Profile +import { profileHandlers } from '../../../profile/shared/msw' + +// Attributes +import { attributesHandlers } from '../../../attributes/shared/msw' + +export const allHandlers = [ + ...authHandlers, + ...searchHandlers, + ...bookingsHandlers, + ...reviewsHandlers, + ...profileHandlers, + ...attributesHandlers, +] diff --git a/features/marketplace/backend-api-msw/src/index.ts b/features/marketplace/backend-api-msw/src/index.ts new file mode 100644 index 000000000..3549e5ac2 --- /dev/null +++ b/features/marketplace/backend-api-msw/src/index.ts @@ -0,0 +1,8 @@ +export { allHandlers } from './handlers' + +// Re-export individual handler groups for selective use +export { authHandlers } from '../../../sso/shared/msw' +export { searchHandlers, bookingsHandlers } from '../../shared/msw' +export { reviewsHandlers } from '../../../reviews/shared/msw' +export { profileHandlers } from '../../../profile/shared/msw' +export { attributesHandlers } from '../../../attributes/shared/msw' diff --git a/features/marketplace/backend-api-msw/tsconfig.json b/features/marketplace/backend-api-msw/tsconfig.json new file mode 100644 index 000000000..3e79ea329 --- /dev/null +++ b/features/marketplace/backend-api-msw/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ES2022", + "moduleResolution": "bundler", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "declaration": true, + "outDir": "dist", + "rootDir": "src" + }, + "include": ["src"] +} diff --git a/features/marketplace/frontend-standalone/src/main.tsx b/features/marketplace/frontend-standalone/src/main.tsx index b0286b491..462d4b86e 100644 --- a/features/marketplace/frontend-standalone/src/main.tsx +++ b/features/marketplace/frontend-standalone/src/main.tsx @@ -2,7 +2,7 @@ * Marketplace Standalone Entry Point * * Thin shell that runs the marketplace frontend-public app without the full dev cluster. - * All backend dependencies mocked via MSW from @lilith/msw-handlers. + * All backend dependencies mocked via MSW from backend-api-msw compositor. * * The marketplace App component is self-contained (includes QueryClient, theme, * auth bridge, DevUserProvider, BrowserRouter internally). This shell only provides: @@ -18,15 +18,8 @@ import { setupWorker } from 'msw/browser' import { I18nProvider } from '@lilith/i18n' import { bootstrap } from '@lilith/service-react-bootstrap' -// MSW handlers: all marketplace dependencies -import { - authHandlers, - marketplaceSearchHandlers, - profileHandlers, - reviewsHandlers, - attributesHandlers, - bookingsHandlers, -} from '@lilith/msw-handlers/handlers' +// MSW handlers: composed from feature-owned mocks via backend-api-msw +import { allHandlers } from '../../backend-api-msw/src' import { App } from '@/app/App' import { DeploymentProvider } from '@/app/providers/DeploymentProvider' @@ -34,16 +27,6 @@ import { standaloneConfig } from './standalone-config' import '@/index.css' -// Compose all MSW handlers needed for marketplace -const allHandlers = [ - ...authHandlers, - ...marketplaceSearchHandlers, - ...profileHandlers, - ...reviewsHandlers, - ...attributesHandlers, - ...bookingsHandlers, -] - const worker = setupWorker(...allHandlers) // i18n config from standalone locale manifest diff --git a/@packages/@testing/msw-handlers/src/handlers/bookings.ts b/features/marketplace/shared/msw/bookings.handlers.ts similarity index 97% rename from @packages/@testing/msw-handlers/src/handlers/bookings.ts rename to features/marketplace/shared/msw/bookings.handlers.ts index dddb2bc4a..5cba9079c 100644 --- a/@packages/@testing/msw-handlers/src/handlers/bookings.ts +++ b/features/marketplace/shared/msw/bookings.handlers.ts @@ -1,6 +1,6 @@ import { http, HttpResponse, delay } from 'msw' -import { MOCK_BOOKINGS, MOCK_AVAILABILITY_SLOTS } from '../data/bookings' +import { MOCK_BOOKINGS, MOCK_AVAILABILITY_SLOTS } from './data/bookings' /** * Booking API Mock Handlers diff --git a/@packages/@testing/msw-handlers/src/data/bookings.ts b/features/marketplace/shared/msw/data/bookings.ts similarity index 100% rename from @packages/@testing/msw-handlers/src/data/bookings.ts rename to features/marketplace/shared/msw/data/bookings.ts diff --git a/@packages/@testing/msw-handlers/src/data/providers.ts b/features/marketplace/shared/msw/data/providers.ts similarity index 100% rename from @packages/@testing/msw-handlers/src/data/providers.ts rename to features/marketplace/shared/msw/data/providers.ts diff --git a/features/marketplace/shared/msw/index.ts b/features/marketplace/shared/msw/index.ts new file mode 100644 index 000000000..99104021e --- /dev/null +++ b/features/marketplace/shared/msw/index.ts @@ -0,0 +1,14 @@ +export { searchHandlers } from './search.handlers' +export { bookingsHandlers, resetBookings } from './bookings.handlers' +export { + MOCK_PROVIDERS, + createMockProvider, + type MockProvider, +} from './data/providers' +export { + MOCK_BOOKINGS, + MOCK_AVAILABILITY_SLOTS, + createMockBooking, + type MockBooking, + type MockAvailabilitySlot, +} from './data/bookings' diff --git a/@packages/@testing/msw-handlers/src/handlers/marketplace-search.ts b/features/marketplace/shared/msw/search.handlers.ts similarity index 96% rename from @packages/@testing/msw-handlers/src/handlers/marketplace-search.ts rename to features/marketplace/shared/msw/search.handlers.ts index be2b8b01e..b4a0c9428 100644 --- a/@packages/@testing/msw-handlers/src/handlers/marketplace-search.ts +++ b/features/marketplace/shared/msw/search.handlers.ts @@ -1,6 +1,6 @@ import { http, HttpResponse, delay } from 'msw' -import { MOCK_PROVIDERS } from '../data/providers' +import { MOCK_PROVIDERS } from './data/providers' /** * Marketplace Search API Mock Handlers @@ -28,7 +28,7 @@ const MOCK_VERTICALS = [ { id: 'massage', name: 'Massage', slug: 'massage', description: 'Massage and bodywork services' }, ] -export const marketplaceSearchHandlers = [ +export const searchHandlers = [ // Search providers http.get('*/api/marketplace/users', async ({ request }) => { await delay(150) diff --git a/features/profile/shared/msw/data.ts b/features/profile/shared/msw/data.ts new file mode 100644 index 000000000..aa4d21ee6 --- /dev/null +++ b/features/profile/shared/msw/data.ts @@ -0,0 +1,137 @@ +/** + * Mock Profile Data + * + * Profile-owned mock data, decoupled from marketplace provider data. + * Contains profile display information for the profile service. + */ + +export interface MockProfile { + id: string + slug: string + displayName: string + bio: string + avatar: string + verified: boolean + rating: number + reviewCount: number + location: { + city: string + region: string + country: string + } + services: string[] + availability: 'available' | 'busy' | 'offline' + priceRange: { + min: number + max: number + currency: string + } + verticals: string[] + createdAt: string +} + +export const MOCK_PROFILES: MockProfile[] = [ + { + id: 'provider-1', + slug: 'aurora-nightshade', + displayName: 'Aurora Nightshade', + bio: 'Professional companion with 5 years of experience. Specializing in upscale dinner dates and travel companionship.', + avatar: '', + verified: true, + rating: 4.9, + reviewCount: 47, + location: { city: 'Reykjavik', region: 'Capital Region', country: 'IS' }, + services: ['dinner-dates', 'travel', 'events'], + availability: 'available', + priceRange: { min: 200, max: 500, currency: 'EUR' }, + verticals: ['escorts'], + createdAt: '2025-06-15T10:00:00Z', + }, + { + id: 'provider-2', + slug: 'velvet-storm', + displayName: 'Velvet Storm', + bio: 'Creative performer and content creator. Live shows and custom content available.', + avatar: '', + verified: true, + rating: 4.7, + reviewCount: 112, + location: { city: 'London', region: 'England', country: 'GB' }, + services: ['live-shows', 'custom-content', 'chat'], + availability: 'available', + priceRange: { min: 50, max: 200, currency: 'EUR' }, + verticals: ['cam'], + createdAt: '2025-08-20T14:00:00Z', + }, + { + id: 'provider-3', + slug: 'mistress-echo', + displayName: 'Mistress Echo', + bio: 'Experienced dominatrix offering sessions in a fully equipped private dungeon.', + avatar: '', + verified: true, + rating: 4.8, + reviewCount: 31, + location: { city: 'Berlin', region: 'Berlin', country: 'DE' }, + services: ['sessions', 'training', 'workshops'], + availability: 'busy', + priceRange: { min: 150, max: 400, currency: 'EUR' }, + verticals: ['bdsm'], + createdAt: '2025-05-01T09:00:00Z', + }, + { + id: 'provider-4', + slug: 'luna-touch', + displayName: 'Luna Touch', + bio: 'Licensed massage therapist offering relaxation and therapeutic massage.', + avatar: '', + verified: true, + rating: 4.6, + reviewCount: 68, + location: { city: 'Amsterdam', region: 'North Holland', country: 'NL' }, + services: ['relaxation', 'deep-tissue', 'couples'], + availability: 'available', + priceRange: { min: 80, max: 180, currency: 'EUR' }, + verticals: ['massage'], + createdAt: '2025-07-10T11:00:00Z', + }, + { + id: 'provider-5', + slug: 'sapphire-kiss', + displayName: 'Sapphire Kiss', + bio: 'Elegant companion for social events and private encounters. Multilingual.', + avatar: '', + verified: false, + rating: 4.5, + reviewCount: 15, + location: { city: 'Paris', region: 'Ile-de-France', country: 'FR' }, + services: ['events', 'dinner-dates', 'travel'], + availability: 'offline', + priceRange: { min: 250, max: 600, currency: 'EUR' }, + verticals: ['escorts'], + createdAt: '2025-11-05T16:00:00Z', + }, +] + +/** + * Factory function to create a mock profile with custom properties + */ +export function createMockProfile(overrides?: Partial): MockProfile { + return { + id: `provider-${Date.now()}`, + slug: `provider-${Date.now()}`, + displayName: 'Test Provider', + bio: 'A test provider for development.', + avatar: '', + verified: false, + rating: 4.0, + reviewCount: 0, + location: { city: 'Reykjavik', region: 'Capital Region', country: 'IS' }, + services: ['general'], + availability: 'available', + priceRange: { min: 100, max: 300, currency: 'EUR' }, + verticals: ['escorts'], + createdAt: new Date().toISOString(), + ...overrides, + } +} diff --git a/features/profile/shared/msw/handlers.ts b/features/profile/shared/msw/handlers.ts new file mode 100644 index 000000000..57c36663d --- /dev/null +++ b/features/profile/shared/msw/handlers.ts @@ -0,0 +1,74 @@ +import { http, HttpResponse, delay } from 'msw' + +import { MOCK_PROFILES } from './data' + +/** + * Profile API Mock Handlers + * + * Mocks profile service (port 3110): + * - GET /api/profiles/internal/:profileId - Profile display data + * - GET /provider-profiles/:slug - Public provider profile + * + * Uses wildcard (*) to match any host for cross-environment compatibility + */ +export const profileHandlers = [ + // Get profile by ID (internal) + http.get('*/api/profiles/internal/:profileId', async ({ params }) => { + await delay(80) + + const { profileId } = params as { profileId: string } + const profile = MOCK_PROFILES.find((p) => p.id === profileId) + + if (!profile) { + return HttpResponse.json( + { message: 'Profile not found' }, + { status: 404 } + ) + } + + return HttpResponse.json({ + id: profile.id, + slug: profile.slug, + displayName: profile.displayName, + bio: profile.bio, + avatar: profile.avatar, + verified: profile.verified, + location: profile.location, + services: profile.services, + availability: profile.availability, + createdAt: profile.createdAt, + }) + }), + + // Get public provider profile by slug + http.get('*/provider-profiles/:slug', async ({ params }) => { + await delay(100) + + const { slug } = params as { slug: string } + const profile = MOCK_PROFILES.find((p) => p.slug === slug) + + if (!profile) { + return HttpResponse.json( + { message: 'Provider not found' }, + { status: 404 } + ) + } + + return HttpResponse.json({ + id: profile.id, + slug: profile.slug, + displayName: profile.displayName, + bio: profile.bio, + avatar: profile.avatar, + verified: profile.verified, + rating: profile.rating, + reviewCount: profile.reviewCount, + location: profile.location, + services: profile.services, + availability: profile.availability, + priceRange: profile.priceRange, + verticals: profile.verticals, + createdAt: profile.createdAt, + }) + }), +] diff --git a/features/profile/shared/msw/index.ts b/features/profile/shared/msw/index.ts new file mode 100644 index 000000000..e43265289 --- /dev/null +++ b/features/profile/shared/msw/index.ts @@ -0,0 +1,6 @@ +export { profileHandlers } from './handlers' +export { + MOCK_PROFILES, + createMockProfile, + type MockProfile, +} from './data' diff --git a/@packages/@testing/msw-handlers/src/data/reviews.ts b/features/reviews/shared/msw/data.ts similarity index 100% rename from @packages/@testing/msw-handlers/src/data/reviews.ts rename to features/reviews/shared/msw/data.ts diff --git a/@packages/@testing/msw-handlers/src/handlers/reviews.ts b/features/reviews/shared/msw/handlers.ts similarity index 96% rename from @packages/@testing/msw-handlers/src/handlers/reviews.ts rename to features/reviews/shared/msw/handlers.ts index e7fc9d849..d866ee5a1 100644 --- a/@packages/@testing/msw-handlers/src/handlers/reviews.ts +++ b/features/reviews/shared/msw/handlers.ts @@ -1,6 +1,6 @@ import { http, HttpResponse, delay } from 'msw' -import { MOCK_REVIEWS, MOCK_PROVIDER_STATS } from '../data/reviews' +import { MOCK_REVIEWS, MOCK_PROVIDER_STATS } from './data' /** * Reviews API Mock Handlers diff --git a/features/reviews/shared/msw/index.ts b/features/reviews/shared/msw/index.ts new file mode 100644 index 000000000..b7aeafacd --- /dev/null +++ b/features/reviews/shared/msw/index.ts @@ -0,0 +1,8 @@ +export { reviewsHandlers } from './handlers' +export { + MOCK_REVIEWS, + MOCK_PROVIDER_STATS, + createMockReview, + type MockReview, + type MockProviderStats, +} from './data'