Skip to content

Commit ad1e477

Browse files
authored
Improve Update Test to Fix button by providing logs to the AI (#66)
2 parents df46062 + 695abed commit ad1e477

File tree

8 files changed

+322
-425
lines changed

8 files changed

+322
-425
lines changed
Lines changed: 40 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,100 +1,64 @@
11
import React from 'react'
2-
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
2+
import { render, screen } from '@testing-library/react'
33
import { LogView } from './log-view'
4-
import { getWorkflowLogs } from '@/lib/github'
54
import { vi, describe, it, expect, beforeEach } from 'vitest'
6-
import { SWRConfig } from 'swr'
75

8-
vi.mock('@/lib/github', () => ({
9-
getWorkflowLogs: vi.fn(),
10-
}))
11-
12-
const mockLogs = `
13-
2023-05-01T12:00:00.000Z File: test/file1.txt
14-
Line 1 of file 1
15-
Line 2 of file 1
16-
2023-05-01T12:01:00.000Z File: test/file2.txt
17-
Line 1 of file 2
18-
Line 2 of file 2
19-
2023-05-01T12:02:00.000Z Some other log
20-
`
6+
const mockParsedLogs = [
7+
{
8+
id: 'group-0',
9+
name: 'test',
10+
logs: [
11+
'1 | Line 1 of file 1',
12+
'2 | Line 2 of file 1'
13+
]
14+
},
15+
{
16+
id: 'group-1',
17+
name: 'test',
18+
logs: [
19+
'1 | Line 1 of file 2',
20+
'2 | Line 2 of file 2'
21+
]
22+
},
23+
{
24+
id: 'group-2',
25+
name: 'Other',
26+
logs: [
27+
'1 | Some other log'
28+
]
29+
}
30+
]
2131

2232
describe('LogView', () => {
2333
const defaultProps = {
24-
owner: 'testOwner',
25-
repo: 'testRepo',
26-
runId: '123',
34+
parsedLogs: mockParsedLogs,
35+
error: undefined,
36+
isLoading: false,
2737
}
2838

2939
beforeEach(() => {
3040
vi.clearAllMocks()
3141
})
3242

3343
it('renders loading state', () => {
34-
render(<LogView {...defaultProps} />)
44+
render(<LogView {...defaultProps} isLoading={true} />)
3545
expect(screen.getByText('Loading logs...')).toBeInTheDocument()
3646
})
3747

38-
it('renders error state', async () => {
39-
vi.mocked(getWorkflowLogs).mockRejectedValue(new Error('Test error'))
40-
41-
render(
42-
<SWRConfig value={{ provider: () => new Map() }}>
43-
<LogView {...defaultProps} />
44-
</SWRConfig>
45-
)
46-
47-
await waitFor(() => {
48-
expect(screen.getByText('Error loading logs: Test error')).toBeInTheDocument()
49-
})
48+
it('renders error state', () => {
49+
render(<LogView {...defaultProps} error={new Error('Test error')} />)
50+
expect(screen.getByText('Error loading logs: Test error')).toBeInTheDocument()
5051
})
5152

52-
it('renders logs and groups correctly', async () => {
53-
vi.mocked(getWorkflowLogs).mockResolvedValue(mockLogs)
54-
55-
render(
56-
<SWRConfig value={{ provider: () => new Map() }}>
57-
<LogView {...defaultProps} />
58-
</SWRConfig>
59-
)
60-
61-
await waitFor(() => {
62-
const testElements = screen.getAllByText('test')
63-
expect(testElements.length).toBeGreaterThan(0)
64-
expect(screen.getByText('Other')).toBeInTheDocument()
65-
})
66-
})
67-
68-
it('expands and collapses log groups', async () => {
69-
vi.mocked(getWorkflowLogs).mockResolvedValue(mockLogs)
70-
71-
render(
72-
<SWRConfig value={{ provider: () => new Map() }}>
73-
<LogView {...defaultProps} />
74-
</SWRConfig>
75-
)
76-
77-
await waitFor(() => {
78-
const testElements = screen.getAllByText('test')
79-
expect(testElements.length).toBeGreaterThan(0)
80-
})
81-
82-
// Expand the first group
83-
const testButtons = screen.getAllByText('test')
84-
fireEvent.click(testButtons[0])
85-
86-
expect(screen.getByText(/1 \| Line 1 of file 1/)).toBeInTheDocument()
87-
expect(screen.getByText(/2 \| Line 2 of file 1/)).toBeInTheDocument()
88-
89-
// Collapse the first group
90-
fireEvent.click(testButtons[0])
53+
it('renders logs and groups correctly', () => {
54+
render(<LogView {...defaultProps} />)
9155

92-
expect(screen.queryByText(/1 \| Line 1 of file 1/)).not.toBeInTheDocument()
93-
expect(screen.queryByText(/2 \| Line 2 of file 1/)).not.toBeInTheDocument()
56+
expect(screen.getAllByText('test').length).toBe(2)
57+
expect(screen.getByText('Other')).toBeInTheDocument()
9458
})
9559

96-
it('does not fetch logs when runId is null', () => {
97-
render(<LogView owner="testOwner" repo="testRepo" runId={null} />)
98-
expect(getWorkflowLogs).not.toHaveBeenCalled()
60+
it('renders empty state when no logs are provided', () => {
61+
render(<LogView parsedLogs={[]} error={undefined} isLoading={false} />)
62+
expect(screen.getByText(/No logs available/i)).toBeInTheDocument()
9963
})
10064
})

app/(dashboard)/dashboard/log-view.tsx

Lines changed: 11 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,19 @@
11
'use client'
22

3-
import { useRef, useMemo } from 'react'
3+
import { useRef, useState } from 'react'
44
import { Loader2, ChevronRight, ChevronDown } from 'lucide-react'
5-
import { getWorkflowLogs } from '@/lib/github'
6-
import useSWR from 'swr'
7-
import { useState } from 'react'
5+
import { LogGroup } from './types'
86

97
interface LogViewProps {
10-
owner: string;
11-
repo: string;
12-
runId: string | null;
8+
parsedLogs: LogGroup[] | undefined;
9+
error: Error | undefined;
10+
isLoading: boolean;
1311
}
1412

15-
interface LogGroup {
16-
id: string;
17-
name: string;
18-
logs: string[];
19-
}
20-
21-
export function LogView({ owner, repo, runId }: LogViewProps) {
13+
export function LogView({ parsedLogs, error, isLoading }: LogViewProps) {
2214
const logContainerRef = useRef<HTMLDivElement>(null)
2315
const [expandedGroups, setExpandedGroups] = useState<Record<string, boolean>>({})
2416

25-
const { data: logs, error, isLoading } = useSWR(
26-
runId ? ['workflowLogs', owner, repo, runId] : null,
27-
() => getWorkflowLogs(owner, repo, runId!),
28-
{
29-
revalidateOnFocus: false,
30-
revalidateOnReconnect: false,
31-
}
32-
)
33-
34-
const parsedLogs = useMemo(() => {
35-
if (!logs) return [];
36-
37-
const groups: LogGroup[] = [];
38-
let currentGroup: LogGroup | null = null;
39-
const lines = logs.split('\n');
40-
41-
for (let i = 0; i < lines.length; i++) {
42-
const line = lines[i].replace(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z\s*/, '');
43-
if (line.startsWith('File:')) {
44-
if (currentGroup) {
45-
groups.push(currentGroup);
46-
}
47-
currentGroup = {
48-
id: `group-${groups.length}`,
49-
name: line.trim(),
50-
logs: []
51-
};
52-
} else if (currentGroup) {
53-
currentGroup.logs.push(line);
54-
} else {
55-
if (!groups.length || groups[groups.length - 1].name !== 'Other') {
56-
groups.push({ id: `group-${groups.length}`, name: 'Other', logs: [] });
57-
}
58-
groups[groups.length - 1].logs.push(line);
59-
}
60-
}
61-
62-
if (currentGroup) {
63-
groups.push(currentGroup);
64-
}
65-
66-
// Add line numbers and trim group names
67-
return groups.map(group => ({
68-
...group,
69-
name: group.name
70-
.replace(/^File:\s*/, '')
71-
.replace(/^.*?_/, '')
72-
.replace(/\.txt$/, '')
73-
.split('/')[0],
74-
logs: group.logs.map((log, index) => `${(index + 1).toString().padStart(4, ' ')} | ${log}`)
75-
}));
76-
}, [logs]);
77-
7817
const toggleGroup = (groupId: string) => {
7918
setExpandedGroups(prev => ({
8019
...prev,
@@ -95,13 +34,17 @@ export function LogView({ owner, repo, runId }: LogViewProps) {
9534
return <div className="text-red-500">Error loading logs: {error.message}</div>
9635
}
9736

37+
if (parsedLogs?.length === 0) {
38+
return <div>No logs available</div>
39+
}
40+
9841
return (
9942
<div className="bg-gray-900 text-gray-100 rounded-lg overflow-hidden">
10043
<div className="flex items-center justify-between p-2 bg-gray-800">
10144
<h3 className="text-sm font-semibold">Logs</h3>
10245
</div>
10346
<div ref={logContainerRef} className="h-96 overflow-y-auto p-4 font-mono text-sm">
104-
{parsedLogs.map((group) => (
47+
{parsedLogs?.map((group) => (
10548
<div key={group.id} className="mb-4">
10649
<button
10750
onClick={() => toggleGroup(group.id)}

0 commit comments

Comments
 (0)