// No need to require jest - it's available globally in Jest test files // JEST MOCKS - must be set up before importing any modules that use them // Mock MongoDB - fix MongoClient to work properly const mockAdmin = { ping: jest.fn().mockResolvedValue({ ok: 1 }) } const mockDb = { collection: jest.fn().mockReturnValue({ findOne: jest.fn().mockResolvedValue(null), replaceOne: jest.fn().mockResolvedValue({ acknowledged: true }), find: jest.fn(() => ({ toArray: jest.fn().mockResolvedValue([]) })), insertOne: jest.fn().mockResolvedValue({ acknowledged: true, insertedId: 'test-id' }), insertMany: jest.fn().mockResolvedValue({ acknowledged: true, insertedIds: { 0: 'test-id' } }), updateOne: jest.fn().mockResolvedValue({ acknowledged: true, matchedCount: 1, modifiedCount: 1 }), updateMany: jest.fn().mockResolvedValue({ acknowledged: true, matchedCount: 2, modifiedCount: 2 }), deleteOne: jest.fn().mockResolvedValue({ acknowledged: true, deletedCount: 1 }), deleteMany: jest.fn().mockResolvedValue({ acknowledged: true, deletedCount: 2 }), bulkWrite: jest.fn().mockResolvedValue({ acknowledged: true, insertedCount: 0, matchedCount: 0, modifiedCount: 0, deletedCount: 0, upsertedCount: 0, upsertedIds: {} }) }), admin: jest.fn().mockReturnValue(mockAdmin) } const mockClient = { connect: jest.fn().mockResolvedValue({}), close: jest.fn().mockResolvedValue(undefined), db: jest.fn().mockImplementation((dbName) => mockDb) } jest.mock('mongodb', () => ({ MongoClient: jest.fn().mockImplementation(() => mockClient) })) // Mock environment variables for tests process.env.MONGODB_URI = 'mongodb://localhost:27017/test' process.env.MONGODB_DB = 'test' // Mock Winston logger - simplified for default export jest.mock('winston', () => ({ transports: { Console: jest.fn(), }, createLogger: jest.fn(() => ({ info: jest.fn(), warn: jest.fn(), error: jest.fn(), debug: jest.fn(), log: jest.fn(), child: jest.fn(() => ({ info: jest.fn(), warn: jest.fn(), error: jest.fn(), debug: jest.fn(), log: jest.fn(), isLevelEnabled: jest.fn().mockReturnValue(true), levels: { error: 0, warn: 1, info: 2, debug: 3 } })), isLevelEnabled: jest.fn().mockReturnValue(true), levels: { error: 0, warn: 1, info: 2, debug: 3 } })), format: { timestamp: jest.fn(() => ({})), errors: jest.fn(() => ({})), json: jest.fn(() => ({})), colorize: jest.fn(() => ({})), simple: jest.fn(() => ({})), combine: jest.fn((...args) => args[args.length - 1] || {}), printf: jest.fn(() => ({})) } })) // Mock logger module to use the mocked winston jest.mock('./src/lib/logger', () => { const mockLogger = { info: jest.fn(), warn: jest.fn(), error: jest.fn(), debug: jest.fn(), log: jest.fn(), child: jest.fn(() => ({ info: jest.fn(), warn: jest.fn(), error: jest.fn(), debug: jest.fn(), log: jest.fn() })) } return { __esModule: true, default: mockLogger, logger: mockLogger, createComponentLogger: jest.fn(() => mockLogger.child()), requestLogger: mockLogger.child(), apiLogger: mockLogger.child(), dbLogger: mockLogger.child(), authLogger: mockLogger.child(), errorLogger: mockLogger.child(), generateRequestId: jest.fn(() => 'test-request-id'), withTiming: jest.fn(async (operation, fn) => fn()) } }) // Mock Next.js Response objects global.Response = class Response { constructor(body, init) { this.body = body this.status = init?.status || 200 this.statusText = init?.statusText || '' this.headers = new Map() if (init?.headers) { Object.entries(init.headers).forEach(([key, value]) => { this.headers.set(key.toLowerCase(), value) }) } } json() { return Promise.resolve(JSON.parse(this.body || '{}')) } headers = { get: (key) => this.headers.get(key.toLowerCase()) } } global.NextResponse = { json: (data, init) => { return new Response(JSON.stringify(data), { status: init?.status || 200, headers: init?.headers || {} }) } } // Mock Next.js NextResponse properly jest.mock('next/server', () => ({ NextResponse: { json: jest.fn((data, init) => { return new Response(JSON.stringify(data), { status: init?.status || 200, headers: init?.headers || {} }) }) }, NextRequest: jest.fn() })) // Ensure process.env is available in tests if (!global.process.env) { global.process.env = {} } // Logger will be mocked by the winston mock above // Mock Loki transport jest.mock('winston-loki', () => jest.fn(() => ({ log: jest.fn(), close: jest.fn() }))) // Mock Next.js router jest.mock('next/router', () => ({ useRouter: () => ({ route: '/', pathname: '/', query: {}, asPath: '/', push: jest.fn(), replace: jest.fn(), reload: jest.fn(), back: jest.fn(), prefetch: jest.fn(), beforePopState: jest.fn(), events: { on: jest.fn(), off: jest.fn(), emit: jest.fn(), }, }), })) // Mock Next.js navigation jest.mock('next/navigation', () => ({ useRouter: () => ({ push: jest.fn(), replace: jest.fn(), refresh: jest.fn(), back: jest.fn(), forward: jest.fn(), prefetch: jest.fn(), }), useSearchParams: () => new URLSearchParams(), usePathname: () => '/', })) // Mock Response constructor for Next.js API routes global.Response = class MockResponse { constructor(body, options = {}) { this.body = body this.status = options.status || 200 this.statusText = options.statusText || 'OK' this.headers = new Map([ ['content-type', options.headers?.['content-type'] || 'application/json'], ...Object.entries(options.headers || {}) ]) // Next.js Response.json() method this.json = jest.fn(() => { try { return JSON.parse(body || '{}') } catch { return body } }) this.text = jest.fn(() => Promise.resolve(body || '')) this.arrayBuffer = jest.fn(() => Promise.resolve(new ArrayBuffer(0))) } get(name) { return this.headers.get(name.toLowerCase()) } set(name, value) { this.headers.set(name.toLowerCase(), value) } clone() { return { ...this } } } // Mock Request constructor for Next.js API routes global.Request = class MockRequest { constructor(url, options = {}) { this.url = url this.method = options.method || 'GET' this.headers = new Map([ ['content-type', 'application/json'], ...Object.entries(options.headers || {}) ]) this.body = options.body || null } json() { return Promise.resolve(this.body ? JSON.parse(this.body) : {}) } text() { return Promise.resolve(this.body || '') } get(name) { return this.headers.get(name.toLowerCase()) } } // Mock NextResponse for API routes global.NextResponse = { json: jest.fn((data, options = {}) => { return new global.Response(JSON.stringify(data), { status: options.status || 200, headers: { 'content-type': 'application/json', ...options.headers } }) }), redirect: jest.fn((url, status = 302) => ({ url, status, headers: new Map([['location', url]]) })), rewrite: jest.fn((url) => ({ url, status: 200 })) } // Set up environment variables for tests process.env.MONGODB_URI = 'mongodb://localhost:27017/test' process.env.MONGODB_DB = 'test' process.env.LOKI_HOST = 'http://loki:3100' process.env.NODE_ENV = 'test' process.env.NEXT_PUBLIC_CONTACT_EMAIL = 'info@mozdit.hu' process.env.NEXT_PUBLIC_SITE_URL = 'https://localhost:3000' process.env.npm_package_version = '1.0.0' process.env.PACKAGE_VERSION = '1.0.0' // Set up cleanup for consistent testing afterEach(() => { jest.clearAllMocks() }) // Import React Testing Library DOM (using require for Jest setup files) require('@testing-library/jest-dom')