Files
metabuilder/pastebin/tests/unit/components/CodeEditorSection.test.tsx
johndoe6345789 73c8e3d4dc feat: Add snippet-pastebin application
Full-featured pastebin application with:
- Next.js frontend with TypeScript
- Express backend with SQLite/PostgreSQL
- Syntax highlighting for 100+ languages
- Code quality validation system
- Comprehensive accessibility (WCAG compliance)
- Docker deployment configuration
- Playwright E2E tests
- Jest unit tests

This provides a standalone web application that can be
integrated as a capability module in the Universal Platform.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 16:54:54 +00:00

388 lines
13 KiB
TypeScript

import React from 'react'
import { render, screen, fireEvent } from '@/test-utils'
import userEvent from '@testing-library/user-event'
import { CodeEditorSection } from '@/components/features/snippet-editor/CodeEditorSection'
import { InputParameter } from '@/lib/types'
// Mock the editor components
jest.mock('@/components/features/snippet-editor/MonacoEditor', () => ({
MonacoEditor: ({ value, onChange }: any) => (
<textarea
data-testid="monaco-editor"
value={value}
onChange={(e) => onChange(e.target.value)}
placeholder="Code editor"
/>
),
}))
jest.mock('@/components/features/snippet-editor/SplitScreenEditor', () => ({
SplitScreenEditor: ({ value, onChange }: any) => (
<textarea
data-testid="split-screen-editor"
value={value}
onChange={(e) => onChange(e.target.value)}
placeholder="Split screen editor"
/>
),
}))
describe('CodeEditorSection Component', () => {
const mockOnCodeChange = jest.fn()
const mockOnPreviewChange = jest.fn()
const defaultProps = {
code: 'const test = () => {}',
language: 'TSX',
hasPreview: false,
functionName: 'TestComponent',
inputParameters: [],
errors: {},
onCodeChange: mockOnCodeChange,
onPreviewChange: mockOnPreviewChange,
}
beforeEach(() => {
jest.clearAllMocks()
})
describe('Rendering', () => {
it('should render without crashing', () => {
render(<CodeEditorSection {...defaultProps} />)
expect(screen.getByTestId('code-editor-container')).toBeInTheDocument()
})
it('should display Code label', () => {
render(<CodeEditorSection {...defaultProps} />)
expect(screen.getByText('Code *')).toBeInTheDocument()
})
it('should render code editor', () => {
render(<CodeEditorSection {...defaultProps} />)
expect(screen.getByTestId('monaco-editor')).toBeInTheDocument()
})
})
describe('Preview Checkbox - Supported Languages', () => {
it('should render preview checkbox for TSX language', () => {
render(<CodeEditorSection {...defaultProps} language="TSX" />)
expect(screen.getByTestId('enable-preview-checkbox')).toBeInTheDocument()
})
it('should render preview checkbox for JSX language', () => {
render(<CodeEditorSection {...defaultProps} language="JSX" />)
expect(screen.getByTestId('enable-preview-checkbox')).toBeInTheDocument()
})
it('should render preview checkbox for JavaScript language', () => {
render(<CodeEditorSection {...defaultProps} language="JavaScript" />)
expect(screen.getByTestId('enable-preview-checkbox')).toBeInTheDocument()
})
it('should render preview checkbox for TypeScript language', () => {
render(<CodeEditorSection {...defaultProps} language="TypeScript" />)
expect(screen.getByTestId('enable-preview-checkbox')).toBeInTheDocument()
})
it('should display preview label', () => {
render(<CodeEditorSection {...defaultProps} language="TSX" />)
expect(screen.getByTestId('enable-preview-label')).toBeInTheDocument()
})
it('should have correct label text for preview', () => {
render(<CodeEditorSection {...defaultProps} language="TSX" />)
expect(screen.getByText('Enable live preview')).toBeInTheDocument()
})
})
describe('Preview Checkbox - Unsupported Languages', () => {
it('should render preview checkbox for Python (supported)', () => {
render(<CodeEditorSection {...defaultProps} language="Python" />)
expect(screen.getByTestId('enable-preview-checkbox')).toBeInTheDocument()
})
it('should not render preview checkbox for HTML (unsupported)', () => {
render(<CodeEditorSection {...defaultProps} language="HTML" />)
expect(screen.queryByTestId('enable-preview-checkbox')).not.toBeInTheDocument()
})
})
describe('Preview Checkbox Interaction', () => {
it('should call onPreviewChange when checkbox is clicked', async () => {
const user = userEvent.setup()
render(<CodeEditorSection {...defaultProps} language="TSX" />)
const checkbox = screen.getByTestId('enable-preview-checkbox')
await user.click(checkbox)
expect(mockOnPreviewChange).toHaveBeenCalledWith(true)
})
it('should toggle preview checkbox state', async () => {
const user = userEvent.setup()
const { rerender } = render(
<CodeEditorSection {...defaultProps} language="TSX" hasPreview={false} />
)
const checkbox = screen.getByTestId('enable-preview-checkbox') as HTMLInputElement
expect(checkbox.checked).toBe(false)
await user.click(checkbox)
expect(mockOnPreviewChange).toHaveBeenCalledWith(true)
rerender(
<CodeEditorSection {...defaultProps} language="TSX" hasPreview={true} />
)
expect(checkbox.checked).toBe(true)
})
})
describe('Editor Selection Based on Preview', () => {
it('should render MonacoEditor when preview is disabled', () => {
render(
<CodeEditorSection
{...defaultProps}
language="TSX"
hasPreview={false}
/>
)
expect(screen.getByTestId('code-editor-container')).toBeInTheDocument()
expect(screen.getByTestId('monaco-editor')).toBeInTheDocument()
})
it('should render SplitScreenEditor when preview is enabled', () => {
render(
<CodeEditorSection
{...defaultProps}
language="TSX"
hasPreview={true}
/>
)
expect(screen.getByTestId('split-screen-editor-container')).toBeInTheDocument()
expect(screen.getByTestId('split-screen-editor')).toBeInTheDocument()
})
it('should render MonacoEditor if language is not supported even with hasPreview true', () => {
render(
<CodeEditorSection
{...defaultProps}
language="HTML"
hasPreview={true}
/>
)
// Should show Monaco editor for unsupported language, not split screen
expect(screen.getByTestId('code-editor-container')).toBeInTheDocument()
expect(screen.queryByTestId('split-screen-editor')).not.toBeInTheDocument()
})
})
describe('Code Input Handling', () => {
it('should call onCodeChange when code is modified in MonacoEditor', async () => {
render(<CodeEditorSection {...defaultProps} />)
const editor = screen.getByTestId('monaco-editor') as HTMLTextAreaElement
fireEvent.change(editor, { target: { value: 'new code' } })
expect(mockOnCodeChange).toHaveBeenCalledWith('new code')
})
it('should pass code prop to editor', () => {
const customCode = 'console.log("test")'
render(
<CodeEditorSection
{...defaultProps}
code={customCode}
/>
)
const editor = screen.getByTestId('monaco-editor') as HTMLTextAreaElement
expect(editor.value).toBe(customCode)
})
})
describe('Error Handling', () => {
it('should display error message when code has error', () => {
render(
<CodeEditorSection
{...defaultProps}
errors={{ code: 'Syntax error on line 5' }}
/>
)
expect(screen.getByTestId('code-error-message')).toBeInTheDocument()
expect(screen.getByText('Syntax error on line 5')).toBeInTheDocument()
})
it('should not display error message when there is no error', () => {
render(
<CodeEditorSection
{...defaultProps}
errors={{}}
/>
)
expect(screen.queryByTestId('code-error-message')).not.toBeInTheDocument()
})
it('should apply error styling when error exists', () => {
const { container } = render(
<CodeEditorSection
{...defaultProps}
errors={{ code: 'Error' }}
/>
)
const errorContainer = container.querySelector('[data-testid="code-editor-container"]')
expect(errorContainer?.className).toContain('destructive')
})
it('should apply error styling to split screen editor', () => {
const { container } = render(
<CodeEditorSection
{...defaultProps}
language="TSX"
hasPreview={true}
errors={{ code: 'Error' }}
/>
)
const splitScreenContainer = container.querySelector('[data-testid="split-screen-editor-container"]')
expect(splitScreenContainer?.className).toContain('ring-destructive')
})
})
describe('Props Validation', () => {
it('should accept all required props', () => {
expect(() => {
render(<CodeEditorSection {...defaultProps} />)
}).not.toThrow()
})
it('should handle empty code string', () => {
render(
<CodeEditorSection
{...defaultProps}
code=""
/>
)
const editor = screen.getByTestId('monaco-editor') as HTMLTextAreaElement
expect(editor.value).toBe('')
})
it('should handle empty input parameters', () => {
render(
<CodeEditorSection
{...defaultProps}
inputParameters={[]}
/>
)
expect(screen.getByTestId('code-editor-container')).toBeInTheDocument()
})
it('should handle input parameters', () => {
const params: InputParameter[] = [
{ name: 'count', type: 'number', defaultValue: '0', description: '' },
]
render(
<CodeEditorSection
{...defaultProps}
language="TSX"
hasPreview={true}
inputParameters={params}
/>
)
expect(screen.getByTestId('split-screen-editor-container')).toBeInTheDocument()
})
})
describe('Editor Container Styling', () => {
it('should render code editor container with proper classes', () => {
const { container } = render(<CodeEditorSection {...defaultProps} />)
const editorContainer = container.querySelector('[data-testid="code-editor-container"]')
expect(editorContainer?.className).toContain('rounded-md')
expect(editorContainer?.className).toContain('border')
})
it('should render code editor container with border styling', () => {
const { container } = render(<CodeEditorSection {...defaultProps} />)
const editorContainer = container.querySelector('[data-testid="code-editor-container"]')
expect(editorContainer?.className).toContain('border-border')
})
})
describe('Component Integration', () => {
it('should integrate with MonacoEditor component', () => {
render(<CodeEditorSection {...defaultProps} />)
expect(screen.getByTestId('monaco-editor')).toBeInTheDocument()
})
it('should integrate with SplitScreenEditor component', () => {
render(
<CodeEditorSection
{...defaultProps}
language="TSX"
hasPreview={true}
/>
)
expect(screen.getByTestId('split-screen-editor')).toBeInTheDocument()
})
it('should pass correct props to SplitScreenEditor', () => {
render(
<CodeEditorSection
{...defaultProps}
language="TSX"
hasPreview={true}
functionName="MyComponent"
/>
)
const splitScreenEditor = screen.getByTestId('split-screen-editor')
expect(splitScreenEditor).toBeInTheDocument()
})
})
describe('Accessibility', () => {
it('should have accessible label for preview checkbox', () => {
render(<CodeEditorSection {...defaultProps} language="TSX" />)
expect(screen.getByLabelText('Enable live preview')).toBeInTheDocument()
})
it('should have accessible label for code input', () => {
render(<CodeEditorSection {...defaultProps} />)
expect(screen.getByText('Code *')).toBeInTheDocument()
})
it('should have error message with proper id attribute', () => {
render(
<CodeEditorSection
{...defaultProps}
errors={{ code: 'Error' }}
/>
)
const errorMsg = screen.getByTestId('code-error-message')
expect(errorMsg.id).toBe('code-error')
})
})
describe('Language Support Verification', () => {
it('should verify supported languages show preview checkbox', () => {
const supportedLanguages = ['JSX', 'TSX', 'JavaScript', 'TypeScript']
supportedLanguages.forEach(lang => {
const { unmount } = render(
<CodeEditorSection {...defaultProps} language={lang} />
)
expect(screen.queryByTestId('enable-preview-checkbox')).toBeInTheDocument()
unmount()
})
})
it('should verify unsupported languages hide preview checkbox', () => {
// Use languages that are NOT in previewEnabledLanguages
const unsupportedLanguages = ['HTML', 'CSS', 'SQL', 'Go']
unsupportedLanguages.forEach(lang => {
const { unmount } = render(
<CodeEditorSection {...defaultProps} language={lang} />
)
expect(screen.queryByTestId('enable-preview-checkbox')).not.toBeInTheDocument()
unmount()
})
})
})
})