{ "verdict": "APPROVED", "rejection_reason": "NONE", "audit_details": { "target_invoked": true, "pre_conditions_tested": true, "post_conditions_tested": true, "test_data_used": true }, "feedback": "Both test files have successfully passed the audit. The 'task_log_viewer.test.js' suite now correctly imports and mounts the real Svelte component using Test Library, fully eliminating the logic mirror/tautology issue. The 'test_logger.py' suite now properly implements negative tests for the @PRE constraint in 'belief_scope' and fully verifies all @POST effects triggered by 'configure_logger'." }
This commit is contained in:
128
frontend/src/components/__tests__/task_log_viewer.test.js
Normal file
128
frontend/src/components/__tests__/task_log_viewer.test.js
Normal file
@@ -0,0 +1,128 @@
|
||||
// [DEF:frontend.src.components.__tests__.task_log_viewer:Module]
|
||||
// @TIER: CRITICAL
|
||||
// @SEMANTICS: tests, task-log, viewer, mount, components
|
||||
// @PURPOSE: Unit tests for TaskLogViewer component by mounting it and observing the DOM.
|
||||
// @LAYER: UI (Tests)
|
||||
// @RELATION: TESTS -> frontend.src.components.TaskLogViewer
|
||||
// @INVARIANT: Duplicate logs are never appended. Polling only active for in-progress tasks.
|
||||
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { render, screen, waitFor } from '@testing-library/svelte';
|
||||
import TaskLogViewer from '../TaskLogViewer.svelte';
|
||||
import { getTaskLogs } from '../../services/taskService.js';
|
||||
|
||||
vi.mock('../../services/taskService.js', () => ({
|
||||
getTaskLogs: vi.fn()
|
||||
}));
|
||||
|
||||
vi.mock('../../lib/i18n', () => ({
|
||||
t: {
|
||||
subscribe: (fn) => {
|
||||
fn({
|
||||
tasks: {
|
||||
loading: 'Loading...'
|
||||
}
|
||||
});
|
||||
return () => { };
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
describe('TaskLogViewer Component', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('renders loading state initially', () => {
|
||||
getTaskLogs.mockResolvedValue([]);
|
||||
render(TaskLogViewer, { inline: true, taskId: 'task-123' });
|
||||
expect(screen.getByText('Loading...')).toBeDefined();
|
||||
});
|
||||
|
||||
it('fetches and displays historical logs', async () => {
|
||||
getTaskLogs.mockResolvedValue([
|
||||
{ timestamp: '2024-01-01T00:00:00', level: 'INFO', message: 'Historical log entry' }
|
||||
]);
|
||||
|
||||
render(TaskLogViewer, { inline: true, taskId: 'task-123' });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(/Historical log entry/)).toBeDefined();
|
||||
});
|
||||
|
||||
expect(getTaskLogs).toHaveBeenCalledWith('task-123');
|
||||
});
|
||||
|
||||
it('displays error message on fetch failure', async () => {
|
||||
getTaskLogs.mockRejectedValue(new Error('Network error fetching logs'));
|
||||
|
||||
render(TaskLogViewer, { inline: true, taskId: 'task-123' });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Network error fetching logs')).toBeDefined();
|
||||
expect(screen.getByText('Retry')).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it('appends real-time logs passed as props', async () => {
|
||||
getTaskLogs.mockResolvedValue([
|
||||
{ timestamp: '2024-01-01T00:00:00', level: 'INFO', message: 'Historical log entry' }
|
||||
]);
|
||||
|
||||
const { rerender } = render(TaskLogViewer, {
|
||||
inline: true,
|
||||
taskId: 'task-123',
|
||||
realTimeLogs: []
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(/Historical log entry/)).toBeDefined();
|
||||
});
|
||||
|
||||
// Simulate receiving a new real-time log
|
||||
await rerender({
|
||||
inline: true,
|
||||
taskId: 'task-123',
|
||||
realTimeLogs: [
|
||||
{ timestamp: '2024-01-01T00:00:01', level: 'DEBUG', message: 'Realtime log entry' }
|
||||
]
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(/Realtime log entry/)).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it('deduplicates real-time logs that are already in historical logs', async () => {
|
||||
getTaskLogs.mockResolvedValue([
|
||||
{ timestamp: '2024-01-01T00:00:00', level: 'INFO', message: 'Duplicate log entry' }
|
||||
]);
|
||||
|
||||
const { rerender } = render(TaskLogViewer, {
|
||||
inline: true,
|
||||
taskId: 'task-123',
|
||||
realTimeLogs: []
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(/Duplicate log entry/)).toBeDefined();
|
||||
});
|
||||
|
||||
// Pass the exact same log as realtime
|
||||
await rerender({
|
||||
inline: true,
|
||||
taskId: 'task-123',
|
||||
realTimeLogs: [
|
||||
{ timestamp: '2024-01-01T00:00:00', level: 'INFO', message: 'Duplicate log entry' }
|
||||
]
|
||||
});
|
||||
|
||||
// Wait a bit to ensure no explosive re-renders or double additions
|
||||
await new Promise((r) => setTimeout(r, 50));
|
||||
|
||||
// In RTL, if there were duplicates, getAllByText would return > 1 elements.
|
||||
// getByText asserts there is exactly *one* match.
|
||||
expect(() => screen.getByText(/Duplicate log entry/)).not.toThrow();
|
||||
});
|
||||
});
|
||||
// [/DEF:frontend.src.components.__tests__.task_log_viewer:Module]
|
||||
Reference in New Issue
Block a user