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 })
+