Skip to content

Commit

Permalink
Improve Update Test to Fix button by providing logs to the AI (anti-w…
Browse files Browse the repository at this point in the history
  • Loading branch information
slavingia authored Oct 20, 2024
2 parents df46062 + 695abed commit ad1e477
Show file tree
Hide file tree
Showing 8 changed files with 322 additions and 425 deletions.
116 changes: 40 additions & 76 deletions app/(dashboard)/dashboard/log-view.test.tsx
Original file line number Diff line number Diff line change
@@ -1,100 +1,64 @@
import React from 'react'
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import { render, screen } from '@testing-library/react'
import { LogView } from './log-view'
import { getWorkflowLogs } from '@/lib/github'
import { vi, describe, it, expect, beforeEach } from 'vitest'
import { SWRConfig } from 'swr'

vi.mock('@/lib/github', () => ({
getWorkflowLogs: vi.fn(),
}))

const mockLogs = `
2023-05-01T12:00:00.000Z File: test/file1.txt
Line 1 of file 1
Line 2 of file 1
2023-05-01T12:01:00.000Z File: test/file2.txt
Line 1 of file 2
Line 2 of file 2
2023-05-01T12:02:00.000Z Some other log
`
const mockParsedLogs = [
{
id: 'group-0',
name: 'test',
logs: [
'1 | Line 1 of file 1',
'2 | Line 2 of file 1'
]
},
{
id: 'group-1',
name: 'test',
logs: [
'1 | Line 1 of file 2',
'2 | Line 2 of file 2'
]
},
{
id: 'group-2',
name: 'Other',
logs: [
'1 | Some other log'
]
}
]

describe('LogView', () => {
const defaultProps = {
owner: 'testOwner',
repo: 'testRepo',
runId: '123',
parsedLogs: mockParsedLogs,
error: undefined,
isLoading: false,
}

beforeEach(() => {
vi.clearAllMocks()
})

it('renders loading state', () => {
render(<LogView {...defaultProps} />)
render(<LogView {...defaultProps} isLoading={true} />)
expect(screen.getByText('Loading logs...')).toBeInTheDocument()
})

it('renders error state', async () => {
vi.mocked(getWorkflowLogs).mockRejectedValue(new Error('Test error'))

render(
<SWRConfig value={{ provider: () => new Map() }}>
<LogView {...defaultProps} />
</SWRConfig>
)

await waitFor(() => {
expect(screen.getByText('Error loading logs: Test error')).toBeInTheDocument()
})
it('renders error state', () => {
render(<LogView {...defaultProps} error={new Error('Test error')} />)
expect(screen.getByText('Error loading logs: Test error')).toBeInTheDocument()
})

it('renders logs and groups correctly', async () => {
vi.mocked(getWorkflowLogs).mockResolvedValue(mockLogs)

render(
<SWRConfig value={{ provider: () => new Map() }}>
<LogView {...defaultProps} />
</SWRConfig>
)

await waitFor(() => {
const testElements = screen.getAllByText('test')
expect(testElements.length).toBeGreaterThan(0)
expect(screen.getByText('Other')).toBeInTheDocument()
})
})

it('expands and collapses log groups', async () => {
vi.mocked(getWorkflowLogs).mockResolvedValue(mockLogs)

render(
<SWRConfig value={{ provider: () => new Map() }}>
<LogView {...defaultProps} />
</SWRConfig>
)

await waitFor(() => {
const testElements = screen.getAllByText('test')
expect(testElements.length).toBeGreaterThan(0)
})

// Expand the first group
const testButtons = screen.getAllByText('test')
fireEvent.click(testButtons[0])

expect(screen.getByText(/1 \| Line 1 of file 1/)).toBeInTheDocument()
expect(screen.getByText(/2 \| Line 2 of file 1/)).toBeInTheDocument()

// Collapse the first group
fireEvent.click(testButtons[0])
it('renders logs and groups correctly', () => {
render(<LogView {...defaultProps} />)

expect(screen.queryByText(/1 \| Line 1 of file 1/)).not.toBeInTheDocument()
expect(screen.queryByText(/2 \| Line 2 of file 1/)).not.toBeInTheDocument()
expect(screen.getAllByText('test').length).toBe(2)
expect(screen.getByText('Other')).toBeInTheDocument()
})

it('does not fetch logs when runId is null', () => {
render(<LogView owner="testOwner" repo="testRepo" runId={null} />)
expect(getWorkflowLogs).not.toHaveBeenCalled()
it('renders empty state when no logs are provided', () => {
render(<LogView parsedLogs={[]} error={undefined} isLoading={false} />)
expect(screen.getByText(/No logs available/i)).toBeInTheDocument()
})
})
79 changes: 11 additions & 68 deletions app/(dashboard)/dashboard/log-view.tsx
Original file line number Diff line number Diff line change
@@ -1,80 +1,19 @@
'use client'

import { useRef, useMemo } from 'react'
import { useRef, useState } from 'react'
import { Loader2, ChevronRight, ChevronDown } from 'lucide-react'
import { getWorkflowLogs } from '@/lib/github'
import useSWR from 'swr'
import { useState } from 'react'
import { LogGroup } from './types'

interface LogViewProps {
owner: string;
repo: string;
runId: string | null;
parsedLogs: LogGroup[] | undefined;
error: Error | undefined;
isLoading: boolean;
}

interface LogGroup {
id: string;
name: string;
logs: string[];
}

export function LogView({ owner, repo, runId }: LogViewProps) {
export function LogView({ parsedLogs, error, isLoading }: LogViewProps) {
const logContainerRef = useRef<HTMLDivElement>(null)
const [expandedGroups, setExpandedGroups] = useState<Record<string, boolean>>({})

const { data: logs, error, isLoading } = useSWR(
runId ? ['workflowLogs', owner, repo, runId] : null,
() => getWorkflowLogs(owner, repo, runId!),
{
revalidateOnFocus: false,
revalidateOnReconnect: false,
}
)

const parsedLogs = useMemo(() => {
if (!logs) return [];

const groups: LogGroup[] = [];
let currentGroup: LogGroup | null = null;
const lines = logs.split('\n');

for (let i = 0; i < lines.length; i++) {
const line = lines[i].replace(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z\s*/, '');
if (line.startsWith('File:')) {
if (currentGroup) {
groups.push(currentGroup);
}
currentGroup = {
id: `group-${groups.length}`,
name: line.trim(),
logs: []
};
} else if (currentGroup) {
currentGroup.logs.push(line);
} else {
if (!groups.length || groups[groups.length - 1].name !== 'Other') {
groups.push({ id: `group-${groups.length}`, name: 'Other', logs: [] });
}
groups[groups.length - 1].logs.push(line);
}
}

if (currentGroup) {
groups.push(currentGroup);
}

// Add line numbers and trim group names
return groups.map(group => ({
...group,
name: group.name
.replace(/^File:\s*/, '')
.replace(/^.*?_/, '')
.replace(/\.txt$/, '')
.split('/')[0],
logs: group.logs.map((log, index) => `${(index + 1).toString().padStart(4, ' ')} | ${log}`)
}));
}, [logs]);

const toggleGroup = (groupId: string) => {
setExpandedGroups(prev => ({
...prev,
Expand All @@ -95,13 +34,17 @@ export function LogView({ owner, repo, runId }: LogViewProps) {
return <div className="text-red-500">Error loading logs: {error.message}</div>
}

if (parsedLogs?.length === 0) {
return <div>No logs available</div>
}

return (
<div className="bg-gray-900 text-gray-100 rounded-lg overflow-hidden">
<div className="flex items-center justify-between p-2 bg-gray-800">
<h3 className="text-sm font-semibold">Logs</h3>
</div>
<div ref={logContainerRef} className="h-96 overflow-y-auto p-4 font-mono text-sm">
{parsedLogs.map((group) => (
{parsedLogs?.map((group) => (
<div key={group.id} className="mb-4">
<button
onClick={() => toggleGroup(group.id)}
Expand Down
Loading

0 comments on commit ad1e477

Please sign in to comment.