obs-ss-plugin-webui/lib/__tests__/apiHelpers.test.ts
Decobus c259f0d943
Some checks failed
Lint and Build / build (20) (pull_request) Failing after 36s
Lint and Build / build (22) (pull_request) Failing after 50s
Add comprehensive performance monitoring and testing infrastructure
- Implement performance dashboard with real-time metrics tracking
- Add React hooks for smart polling, debouncing, and active source lookup
- Create Jest testing framework with comprehensive test suites for components, API endpoints, and utilities
- Enhance UI components with optimized rendering and memoization
- Improve polling efficiency with visibility detection and adaptive intervals

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-19 06:20:19 -04:00

252 lines
No EOL
7 KiB
TypeScript

import { NextResponse } from 'next/server';
import {
createErrorResponse,
createSuccessResponse,
createValidationError,
createDatabaseError,
createOBSError,
parseRequestBody,
} from '../apiHelpers';
// Mock NextResponse
jest.mock('next/server', () => ({
NextResponse: {
json: jest.fn((data, options) => ({
data,
status: options?.status || 200,
})),
},
}));
// Mock console.error to silence expected error logs
const mockConsoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
describe('apiHelpers', () => {
beforeEach(() => {
jest.clearAllMocks();
});
afterAll(() => {
mockConsoleError.mockRestore();
});
describe('createErrorResponse', () => {
it('creates error response with default status 500', () => {
const response = createErrorResponse('Test Error');
expect(NextResponse.json).toHaveBeenCalledWith(
expect.objectContaining({
error: 'Test Error',
timestamp: expect.any(String),
}),
{ status: 500 }
);
});
it('creates error response with custom status and message', () => {
const response = createErrorResponse('Test Error', 400, 'Custom message', { detail: 'extra' });
expect(NextResponse.json).toHaveBeenCalledWith(
expect.objectContaining({
error: 'Test Error',
message: 'Custom message',
details: { detail: 'extra' },
timestamp: expect.any(String),
}),
{ status: 400 }
);
});
it('logs error to console', () => {
// Temporarily restore the mock to capture calls
mockConsoleError.mockRestore();
const tempMock = jest.spyOn(console, 'error').mockImplementation(() => {});
createErrorResponse('Test Error', 400);
expect(tempMock).toHaveBeenCalledWith(
'API Error [400]:',
expect.objectContaining({
error: 'Test Error',
timestamp: expect.any(String),
})
);
// Restore the original mock
tempMock.mockRestore();
jest.spyOn(console, 'error').mockImplementation(() => {});
});
});
describe('createSuccessResponse', () => {
it('creates success response with default status 200', () => {
const data = { test: 'data' };
const response = createSuccessResponse(data);
expect(NextResponse.json).toHaveBeenCalledWith(
expect.objectContaining({
success: true,
data: { test: 'data' },
timestamp: expect.any(String),
}),
{ status: 200 }
);
});
it('creates success response with custom status', () => {
const data = { id: 1, name: 'test' };
const response = createSuccessResponse(data, 201);
expect(NextResponse.json).toHaveBeenCalledWith(
expect.objectContaining({
success: true,
data: { id: 1, name: 'test' },
timestamp: expect.any(String),
}),
{ status: 201 }
);
});
});
describe('specialized error responses', () => {
it('createValidationError creates 400 response', () => {
const details = { field: 'error message' };
createValidationError('Validation failed', details);
expect(NextResponse.json).toHaveBeenCalledWith(
expect.objectContaining({
error: 'Validation Error',
message: 'Validation failed',
details,
}),
{ status: 400 }
);
});
it('createDatabaseError creates 500 response', () => {
const originalError = new Error('DB connection failed');
createDatabaseError('fetch users', originalError);
expect(NextResponse.json).toHaveBeenCalledWith(
expect.objectContaining({
error: 'Database Error',
message: 'Database operation failed: fetch users',
}),
{ status: 500 }
);
});
it('createOBSError creates 502 response', () => {
const originalError = new Error('WebSocket failed');
createOBSError('connect to OBS', originalError);
expect(NextResponse.json).toHaveBeenCalledWith(
expect.objectContaining({
error: 'OBS Error',
message: 'OBS operation failed: connect to OBS',
}),
{ status: 502 }
);
});
});
describe('parseRequestBody', () => {
const mockRequest = (body: any): Request => ({
json: jest.fn().mockResolvedValue(body),
} as any);
it('parses valid JSON body without validator', async () => {
const body = { name: 'test', value: 123 };
const request = mockRequest(body);
const result = await parseRequestBody(request);
expect(result.success).toBe(true);
if (result.success) {
expect(result.data).toEqual(body);
}
});
it('handles invalid JSON', async () => {
const request = {
json: jest.fn().mockRejectedValue(new Error('Invalid JSON')),
} as any;
const result = await parseRequestBody(request);
expect(result.success).toBe(false);
if (!result.success) {
expect(result.response).toBeDefined();
}
});
it('validates body with custom validator', async () => {
const body = { name: 'test' };
const request = mockRequest(body);
const validator = jest.fn().mockReturnValue({
valid: true,
data: { name: 'test' },
});
const result = await parseRequestBody(request, validator);
expect(result.success).toBe(true);
expect(validator).toHaveBeenCalledWith(body);
if (result.success) {
expect(result.data).toEqual({ name: 'test' });
}
});
it('handles validation failure', async () => {
const body = { name: '' };
const request = mockRequest(body);
const validator = jest.fn().mockReturnValue({
valid: false,
errors: { name: 'Name is required' },
});
const result = await parseRequestBody(request, validator);
expect(result.success).toBe(false);
expect(validator).toHaveBeenCalledWith(body);
});
});
describe('environment-specific behavior', () => {
const originalEnv = process.env.NODE_ENV;
afterAll(() => {
process.env.NODE_ENV = originalEnv;
});
it('includes error details in development', () => {
process.env.NODE_ENV = 'development';
const originalError = new Error('Test error');
createDatabaseError('test operation', originalError);
expect(NextResponse.json).toHaveBeenCalledWith(
expect.objectContaining({
details: originalError,
}),
{ status: 500 }
);
});
it('excludes error details in production', () => {
process.env.NODE_ENV = 'production';
const originalError = new Error('Test error');
createDatabaseError('test operation', originalError);
expect(NextResponse.json).toHaveBeenCalledWith(
expect.objectContaining({
details: undefined,
}),
{ status: 500 }
);
});
});
});