diff --git a/app/api/__tests__/streams.test.ts b/app/api/__tests__/streams.test.ts new file mode 100644 index 0000000..d4ef664 --- /dev/null +++ b/app/api/__tests__/streams.test.ts @@ -0,0 +1,76 @@ +import { GET } from '../streams/route'; + +// Mock the database module +jest.mock('@/lib/database', () => ({ + getDatabase: jest.fn(), +})); + +describe('/api/streams', () => { + let mockDb: any; + + beforeEach(() => { + // Create mock database + mockDb = { + all: jest.fn(), + }; + + const { getDatabase } = require('@/lib/database'); + getDatabase.mockResolvedValue(mockDb); + }); + + describe('GET /api/streams', () => { + it('returns all streams successfully', async () => { + const mockStreams = [ + { id: 1, name: 'Stream 1', url: 'http://example.com/1', obs_source_name: 'Source 1', team_id: 1 }, + { id: 2, name: 'Stream 2', url: 'http://example.com/2', obs_source_name: 'Source 2', team_id: 2 }, + ]; + + mockDb.all.mockResolvedValue(mockStreams); + + const response = await GET(); + + expect(mockDb.all).toHaveBeenCalledWith( + expect.stringContaining('SELECT * FROM') + ); + + const { NextResponse } = require('next/server'); + expect(NextResponse.json).toHaveBeenCalledWith(mockStreams); + }); + + it('returns empty array when no streams exist', async () => { + mockDb.all.mockResolvedValue([]); + + const response = await GET(); + + const { NextResponse } = require('next/server'); + expect(NextResponse.json).toHaveBeenCalledWith([]); + }); + + it('handles database errors gracefully', async () => { + const dbError = new Error('Database connection failed'); + mockDb.all.mockRejectedValue(dbError); + + const response = await GET(); + + const { NextResponse } = require('next/server'); + expect(NextResponse.json).toHaveBeenCalledWith( + { error: 'Failed to fetch streams' }, + { status: 500 } + ); + }); + + it('handles database connection errors', async () => { + const connectionError = new Error('Failed to connect to database'); + const { getDatabase } = require('@/lib/database'); + getDatabase.mockRejectedValue(connectionError); + + const response = await GET(); + + const { NextResponse } = require('next/server'); + expect(NextResponse.json).toHaveBeenCalledWith( + { error: 'Failed to fetch streams' }, + { status: 500 } + ); + }); + }); +}); \ No newline at end of file diff --git a/app/api/__tests__/teams.test.ts b/app/api/__tests__/teams.test.ts new file mode 100644 index 0000000..4f26d27 --- /dev/null +++ b/app/api/__tests__/teams.test.ts @@ -0,0 +1,89 @@ +import { GET } from '../teams/route'; + +// Mock the database module +jest.mock('@/lib/database', () => ({ + getDatabase: jest.fn(), +})); + +// Mock the apiHelpers module +jest.mock('@/lib/apiHelpers', () => ({ + withErrorHandling: jest.fn((handler) => handler), + createSuccessResponse: jest.fn((data, status = 200) => ({ + data, + status, + json: async () => ({ success: true, data }), + })), + createDatabaseError: jest.fn((operation, error) => ({ + error: 'Database Error', + status: 500, + json: async () => ({ + error: 'Database Error', + message: `Database operation failed: ${operation}`, + }), + })), +})); + +describe('/api/teams', () => { + let mockDb: any; + + beforeEach(() => { + // Create mock database + mockDb = { + all: jest.fn(), + }; + + const { getDatabase } = require('@/lib/database'); + getDatabase.mockResolvedValue(mockDb); + }); + + describe('GET /api/teams', () => { + it('returns all teams successfully', async () => { + const mockTeams = [ + { team_id: 1, team_name: 'Team Alpha' }, + { team_id: 2, team_name: 'Team Beta' }, + { team_id: 3, team_name: 'Team Gamma' }, + ]; + + mockDb.all.mockResolvedValue(mockTeams); + + const response = await GET(); + + expect(mockDb.all).toHaveBeenCalledWith( + expect.stringContaining('SELECT * FROM') + ); + + const { createSuccessResponse } = require('@/lib/apiHelpers'); + expect(createSuccessResponse).toHaveBeenCalledWith(mockTeams); + }); + + it('returns empty array when no teams exist', async () => { + mockDb.all.mockResolvedValue([]); + + const response = await GET(); + + const { createSuccessResponse } = require('@/lib/apiHelpers'); + expect(createSuccessResponse).toHaveBeenCalledWith([]); + }); + + it('handles database errors gracefully', async () => { + const dbError = new Error('Table does not exist'); + mockDb.all.mockRejectedValue(dbError); + + const response = await GET(); + + const { createDatabaseError } = require('@/lib/apiHelpers'); + expect(createDatabaseError).toHaveBeenCalledWith('fetch teams', dbError); + }); + + it('handles database connection errors', async () => { + const connectionError = new Error('Failed to connect to database'); + const { getDatabase } = require('@/lib/database'); + getDatabase.mockRejectedValue(connectionError); + + const response = await GET(); + + const { createDatabaseError } = require('@/lib/apiHelpers'); + expect(createDatabaseError).toHaveBeenCalledWith('fetch teams', connectionError); + }); + }); +}); \ No newline at end of file diff --git a/app/layout.tsx b/app/layout.tsx index d81d0a1..7358406 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -2,6 +2,7 @@ import './globals.css'; import Header from '@/components/Header'; import Footer from '@/components/Footer'; import { ErrorBoundary } from '@/components/ErrorBoundary'; +import PerformanceDashboard from '@/components/PerformanceDashboard'; export const metadata = { title: 'OBS Source Switcher', @@ -19,6 +20,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })