From 08a56d1f2e39d41b48591704910bee4060bbb4d6 Mon Sep 17 00:00:00 2001 From: Aarya1402 Date: Mon, 18 May 2026 10:33:13 +0530 Subject: [PATCH 01/17] test(ui): add test coverage for ui components d4f81b746 --- package.json | 5 +++++ src/components/ui/Button.test.tsx | 16 ++++++++++++++++ src/test/setup.ts | 1 + vite.config.ts | 7 ++++++- 4 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 src/components/ui/Button.test.tsx create mode 100644 src/test/setup.ts diff --git a/package.json b/package.json index 89d9182..68ee688 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,10 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.2", + "@testing-library/user-event": "^14.6.1", + "@types/jsdom": "^28.0.3", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "eslint": "^10.2.1", @@ -40,6 +44,7 @@ "eslint-plugin-react-refresh": "^0.5.2", "globals": "^17.5.0", "husky": "^9.1.7", + "jsdom": "^29.1.1", "lint-staged": "^16.4.0", "prettier": "^3.8.3", "typescript-eslint": "^8.58.2", diff --git a/src/components/ui/Button.test.tsx b/src/components/ui/Button.test.tsx new file mode 100644 index 0000000..f536318 --- /dev/null +++ b/src/components/ui/Button.test.tsx @@ -0,0 +1,16 @@ +import { render, screen } from '@testing-library/react'; +import { Button } from './Button'; +import { describe, it, expect } from 'vitest'; + +describe('Button component', () => { + it('renders children correctly', () => { + render(); + expect(screen.getByText('Click Me')).toBeInTheDocument(); + }); + + it('shows loading state when loading prop is true', () => { + render(); + expect(screen.getByText('⏳')).toBeInTheDocument(); + expect(screen.getByRole('button')).toBeDisabled(); + }); +}); diff --git a/src/test/setup.ts b/src/test/setup.ts new file mode 100644 index 0000000..7b0828b --- /dev/null +++ b/src/test/setup.ts @@ -0,0 +1 @@ +import '@testing-library/jest-dom'; diff --git a/vite.config.ts b/vite.config.ts index 0e77097..80a6bac 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,4 +1,4 @@ -import { defineConfig } from 'vite'; +import { defineConfig } from 'vitest/config'; import react from '@vitejs/plugin-react'; import tailwindcss from '@tailwindcss/vite'; import path from 'path'; @@ -14,4 +14,9 @@ export default defineConfig({ port: 5173, open: true, }, + test: { + environment: 'jsdom', + setupFiles: ['./src/test/setup.ts'], + globals: true, + }, }); From 5846beb9022aadeeacecf08b95c6f3a84fa4026e Mon Sep 17 00:00:00 2001 From: Aarya1402 Date: Mon, 18 May 2026 10:40:13 +0530 Subject: [PATCH 02/17] test(ui): add test coverage for Input component d4f81b746 --- src/components/ui/Input.test.tsx | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/components/ui/Input.test.tsx diff --git a/src/components/ui/Input.test.tsx b/src/components/ui/Input.test.tsx new file mode 100644 index 0000000..9447760 --- /dev/null +++ b/src/components/ui/Input.test.tsx @@ -0,0 +1,23 @@ +import { render, screen } from '@testing-library/react'; +import { Input } from './Input'; +import { describe, it, expect } from 'vitest'; +import React from 'react'; + +describe('Input component', () => { + it('renders correctly', () => { + render(); + expect(screen.getByPlaceholderText('Enter text')).toBeInTheDocument(); + }); + + it('passes ref correctly', () => { + const ref = React.createRef(); + render(); + expect(ref.current).toBeInstanceOf(HTMLInputElement); + }); + + it('applies error styles when hasError is true', () => { + render(); + const input = screen.getByTestId('error-input'); + expect(input.style.border).toContain('var(--status-error)'); + }); +}); From 551ca41befe453be82caa692f01c0777449fa135 Mon Sep 17 00:00:00 2001 From: Aarya1402 Date: Mon, 18 May 2026 10:41:10 +0530 Subject: [PATCH 03/17] test(ui): add test coverage for Panel component d4f81b746 --- src/components/ui/Panel.test.tsx | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/components/ui/Panel.test.tsx diff --git a/src/components/ui/Panel.test.tsx b/src/components/ui/Panel.test.tsx new file mode 100644 index 0000000..9ac0af9 --- /dev/null +++ b/src/components/ui/Panel.test.tsx @@ -0,0 +1,25 @@ +import { render, screen } from '@testing-library/react'; +import { Panel } from './Panel'; +import { describe, it, expect } from 'vitest'; +import React from 'react'; + +describe('Panel component', () => { + it('renders children correctly', () => { + render(Panel Content); + expect(screen.getByText('Panel Content')).toBeInTheDocument(); + }); + + it('renders title when provided', () => { + render(Content); + expect(screen.getByText('[ Test Title ]')).toBeInTheDocument(); + }); + + it('renders headerRight when provided', () => { + render( + Action}> + Content + , + ); + expect(screen.getByRole('button', { name: 'Action' })).toBeInTheDocument(); + }); +}); From 0c59bd4d0dcb66c18177d3ea4d69eaf6490783bb Mon Sep 17 00:00:00 2001 From: Aarya1402 Date: Mon, 18 May 2026 10:44:17 +0530 Subject: [PATCH 04/17] test(ui): add test coverage for ProgressBar component d4f81b746 --- src/components/ui/ProgressBar.test.tsx | 35 ++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/components/ui/ProgressBar.test.tsx diff --git a/src/components/ui/ProgressBar.test.tsx b/src/components/ui/ProgressBar.test.tsx new file mode 100644 index 0000000..824f1be --- /dev/null +++ b/src/components/ui/ProgressBar.test.tsx @@ -0,0 +1,35 @@ +import { render, screen } from '@testing-library/react'; +import { ProgressBar } from './ProgressBar'; +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; +import React from 'react'; + +describe('ProgressBar component', () => { + beforeEach(() => { + vi.useFakeTimers(); + }); + + afterEach(() => { + vi.useRealTimers(); + }); + + it('renders correctly with current and total', () => { + render(); + expect(screen.getByText(/5\/10 \(50%\)/)).toBeInTheDocument(); + }); + + it('renders label when provided', () => { + render(); + expect(screen.getByText('Processing')).toBeInTheDocument(); + }); + + it('hides count when showCount is false', () => { + render(); + expect(screen.queryByText(/5\/10 \(50%\)/)).not.toBeInTheDocument(); + }); + + it('shows ETA when startTime is provided', () => { + const startTime = Date.now(); + render(); + expect(screen.getByText(/ETA:/)).toBeInTheDocument(); + }); +}); From 770be7f3f4e2511d6ec1322912c7e7a6833f2502 Mon Sep 17 00:00:00 2001 From: Aarya1402 Date: Mon, 18 May 2026 10:44:45 +0530 Subject: [PATCH 05/17] test(ui): add test coverage for ScrollArea component d4f81b746 --- src/components/ui/ScrollArea.test.tsx | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/components/ui/ScrollArea.test.tsx diff --git a/src/components/ui/ScrollArea.test.tsx b/src/components/ui/ScrollArea.test.tsx new file mode 100644 index 0000000..9c66da8 --- /dev/null +++ b/src/components/ui/ScrollArea.test.tsx @@ -0,0 +1,27 @@ +import { render, screen } from '@testing-library/react'; +import { ScrollArea } from './ScrollArea'; +import { describe, it, expect } from 'vitest'; +import React from 'react'; + +describe('ScrollArea component', () => { + it('renders children correctly', () => { + render(Scrollable Content); + expect(screen.getByText('Scrollable Content')).toBeInTheDocument(); + }); + + it('applies maxHeight when provided', () => { + render( + + Content + , + ); + const element = screen.getByTestId('scroll-area'); + expect(element.style.maxHeight).toBe('200px'); + }); + + it('passes innerRef correctly', () => { + const ref = React.createRef(); + render(Content); + expect(ref.current).toBeInstanceOf(HTMLDivElement); + }); +}); From 07ddfe5002151b4c211e4babfc49cf067afdc1a7 Mon Sep 17 00:00:00 2001 From: Aarya1402 Date: Mon, 18 May 2026 10:45:06 +0530 Subject: [PATCH 06/17] test(ui): add test coverage for MarkdownRenderer component d4f81b746 --- src/components/ui/MarkdownRenderer.test.tsx | 25 +++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/components/ui/MarkdownRenderer.test.tsx diff --git a/src/components/ui/MarkdownRenderer.test.tsx b/src/components/ui/MarkdownRenderer.test.tsx new file mode 100644 index 0000000..dc2469e --- /dev/null +++ b/src/components/ui/MarkdownRenderer.test.tsx @@ -0,0 +1,25 @@ +import { render, screen } from '@testing-library/react'; +import { MarkdownRenderer } from './MarkdownRenderer'; +import { describe, it, expect } from 'vitest'; +import React from 'react'; + +describe('MarkdownRenderer component', () => { + it('renders markdown content correctly', () => { + render(); + // Testing specific output depends on react-markdown, we just test if the component renders the text + expect(screen.getByText('Hello World')).toBeInTheDocument(); + }); + + it('renders code blocks correctly', () => { + render(); + expect(screen.getByText('inline code')).toBeInTheDocument(); + expect(screen.getByText('inline code').tagName).toBe('CODE'); + }); + + it('renders links correctly', () => { + render(); + const link = screen.getByRole('link', { name: 'GitHub' }); + expect(link).toBeInTheDocument(); + expect(link).toHaveAttribute('href', 'https://github.com'); + }); +}); From fdfd964e5f4571f571f21bfd0fe806471d74e14e Mon Sep 17 00:00:00 2001 From: Aarya1402 Date: Mon, 18 May 2026 10:46:06 +0530 Subject: [PATCH 07/17] fix(ui): fix failing ScrollArea test d4f81b746 --- src/components/ui/ScrollArea.test.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/components/ui/ScrollArea.test.tsx b/src/components/ui/ScrollArea.test.tsx index 9c66da8..8079ef4 100644 --- a/src/components/ui/ScrollArea.test.tsx +++ b/src/components/ui/ScrollArea.test.tsx @@ -10,12 +10,8 @@ describe('ScrollArea component', () => { }); it('applies maxHeight when provided', () => { - render( - - Content - , - ); - const element = screen.getByTestId('scroll-area'); + render(Scroll Area Content); + const element = screen.getByText('Scroll Area Content'); expect(element.style.maxHeight).toBe('200px'); }); From bbe3244108ce9b68ce7a50f98df8ba9b7d6dbf8e Mon Sep 17 00:00:00 2001 From: Aarya1402 Date: Mon, 18 May 2026 10:47:26 +0530 Subject: [PATCH 08/17] test(terminal): add test coverage for TerminalInput component d4f81b746 --- .../terminal/TerminalInput.test.tsx | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/components/terminal/TerminalInput.test.tsx b/src/components/terminal/TerminalInput.test.tsx index e69de29..7fa17b1 100644 --- a/src/components/terminal/TerminalInput.test.tsx +++ b/src/components/terminal/TerminalInput.test.tsx @@ -0,0 +1,40 @@ +import { render, screen, fireEvent } from '@testing-library/react'; +import { TerminalInput } from './TerminalInput'; +import { describe, it, expect, vi } from 'vitest'; +import React from 'react'; + +describe('TerminalInput component', () => { + it('renders correctly', () => { + const onChange = vi.fn(); + const onSubmit = vi.fn(); + render(); + expect(screen.getByPlaceholderText('Type here...')).toBeInTheDocument(); + }); + + it('calls onChange when typing', () => { + const onChange = vi.fn(); + const onSubmit = vi.fn(); + render(); + const input = screen.getByPlaceholderText('Type here...'); + fireEvent.change(input, { target: { value: 'hello' } }); + expect(onChange).toHaveBeenCalledWith('hello'); + }); + + it('calls onSubmit when Enter is pressed', () => { + const onChange = vi.fn(); + const onSubmit = vi.fn(); + render(); + const input = screen.getByPlaceholderText('Type here...'); + fireEvent.keyDown(input, { key: 'Enter', code: 'Enter' }); + expect(onSubmit).toHaveBeenCalled(); + }); + + it('clears input when Escape is pressed', () => { + const onChange = vi.fn(); + const onSubmit = vi.fn(); + render(); + const input = screen.getByPlaceholderText('Type here...'); + fireEvent.keyDown(input, { key: 'Escape', code: 'Escape' }); + expect(onChange).toHaveBeenCalledWith(''); + }); +}); From 08d57fdc51f087d1f1c13553dd113f542d85edfb Mon Sep 17 00:00:00 2001 From: Aarya1402 Date: Mon, 18 May 2026 10:55:24 +0530 Subject: [PATCH 09/17] fix(types): add jest-dom type reference d4f81b746 --- vite-env.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/vite-env.d.ts b/vite-env.d.ts index e92b4bd..6560e54 100644 --- a/vite-env.d.ts +++ b/vite-env.d.ts @@ -1,4 +1,5 @@ /// +/// interface ImportMetaEnv { readonly VITE_GITHUB_TOKEN: string; From ce5459f2b32f017cf306193e7bf332fc1868d9a9 Mon Sep 17 00:00:00 2001 From: Aarya1402 Date: Mon, 18 May 2026 15:27:58 +0530 Subject: [PATCH 10/17] test(issue): add test coverage for IssueMetadata component d4f81b746 --- src/components/issue/IssueMetadata.test.tsx | 60 +++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 src/components/issue/IssueMetadata.test.tsx diff --git a/src/components/issue/IssueMetadata.test.tsx b/src/components/issue/IssueMetadata.test.tsx new file mode 100644 index 0000000..cc611a7 --- /dev/null +++ b/src/components/issue/IssueMetadata.test.tsx @@ -0,0 +1,60 @@ +import { render, screen } from '@testing-library/react'; +import { IssueMetadata } from './IssueMetadata'; +import { describe, it, expect } from 'vitest'; +import type { AnalysisResult } from '../../lib/types'; +import React from 'react'; + +const mockAnalysis: AnalysisResult = { + summary: 'This is a summary', + status: 'active', + progress_estimate: 'early', + is_actionable_code_change: true, + not_mergeable_reason: null, + complexity: 3, + skills_required: ['React', 'TypeScript'], + newcomer_friendliness: 4, + doability_score: 80, + analysis_notes: 'Some notes', +}; + +describe('IssueMetadata component', () => { + it('renders all analysis metrics correctly', () => { + render(); + + expect(screen.getByText('Doability')).toBeInTheDocument(); + expect(screen.getByText('80/100')).toBeInTheDocument(); + + expect(screen.getByText('Status')).toBeInTheDocument(); + expect(screen.getByText('Active')).toBeInTheDocument(); + + expect(screen.getByText('Complexity')).toBeInTheDocument(); + expect(screen.getByText(/Moderate/)).toBeInTheDocument(); + + expect(screen.getByText('Friendliness')).toBeInTheDocument(); + expect(screen.getByText(/Beginner Friendly/)).toBeInTheDocument(); + + expect(screen.getByText('React')).toBeInTheDocument(); + expect(screen.getByText('TypeScript')).toBeInTheDocument(); + }); + + it('renders merge blocker when not_mergeable_reason is provided', () => { + const analysisWithBlocker: AnalysisResult = { + ...mockAnalysis, + not_mergeable_reason: 'Missing details', + }; + render(); + + expect(screen.getByText('Blocker')).toBeInTheDocument(); + expect(screen.getByText('Missing details')).toBeInTheDocument(); + }); + + it('renders "none specified" when skills_required is empty', () => { + const analysisNoSkills: AnalysisResult = { + ...mockAnalysis, + skills_required: [], + }; + render(); + + expect(screen.getByText('none specified')).toBeInTheDocument(); + }); +}); From 515cad7d603370b074994e8df8160d52db0d4aa8 Mon Sep 17 00:00:00 2001 From: Aarya1402 Date: Mon, 18 May 2026 15:28:50 +0530 Subject: [PATCH 11/17] test(issue): add test coverage for IssueListItem component d4f81b746 --- src/components/issue/IssueListItem.test.tsx | 63 +++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 src/components/issue/IssueListItem.test.tsx diff --git a/src/components/issue/IssueListItem.test.tsx b/src/components/issue/IssueListItem.test.tsx new file mode 100644 index 0000000..2759656 --- /dev/null +++ b/src/components/issue/IssueListItem.test.tsx @@ -0,0 +1,63 @@ +import { render, screen, fireEvent } from '@testing-library/react'; +import { IssueListItem } from './IssueListItem'; +import { describe, it, expect, vi } from 'vitest'; +import type { RankedIssue } from '../../lib/types'; +import React from 'react'; + +const mockIssue: RankedIssue = { + number: 101, + title: 'Optimize database queries', + updated_at: new Date(Date.now() - 3600000).toISOString(), // 1 hour ago + score: 95, + user: { login: 'octocat', avatar_url: '', html_url: '' }, + labels: [], + assignees: [], + comments_count: 0, + created_at: new Date(Date.now() - 7200000).toISOString(), + html_url: '', + state: 'open', +}; + +describe('IssueListItem component', () => { + it('renders standard fields correctly', () => { + const onClick = vi.fn(); + render(); + + expect(screen.getByText('1.')).toBeInTheDocument(); + expect(screen.getByText('#101')).toBeInTheDocument(); + expect(screen.getByText('Optimize database queries')).toBeInTheDocument(); + expect(screen.getByText('[95]')).toBeInTheDocument(); + expect(screen.getByText('1h ago')).toBeInTheDocument(); + }); + + it('triggers onClick when clicked', () => { + const onClick = vi.fn(); + render(); + + fireEvent.click(screen.getByText('Optimize database queries')); + expect(onClick).toHaveBeenCalled(); + }); + + it('renders status prefix tag when analysis exists', () => { + const issueWithAnalysis: RankedIssue = { + ...mockIssue, + analysis: { + summary: 'Discussion required', + status: 'discussion', + progress_estimate: 'not_started', + is_actionable_code_change: false, + not_mergeable_reason: null, + complexity: 1, + skills_required: [], + newcomer_friendliness: 5, + doability_score: 50, + analysis_notes: '', + }, + }; + + render( + , + ); + expect(screen.getByText('[DISCUSSION]')).toBeInTheDocument(); + }); +}); From cef213f6149c007c3428280e87610cc7e9ea9fad Mon Sep 17 00:00:00 2001 From: Aarya1402 Date: Mon, 18 May 2026 15:31:07 +0530 Subject: [PATCH 12/17] test(issue): add test coverage for IssueList component d4f81b746 --- src/components/issue/IssueList.test.tsx | 120 ++++++++++++++++++++++++ src/test/setup.ts | 3 + 2 files changed, 123 insertions(+) create mode 100644 src/components/issue/IssueList.test.tsx diff --git a/src/components/issue/IssueList.test.tsx b/src/components/issue/IssueList.test.tsx new file mode 100644 index 0000000..e2d99af --- /dev/null +++ b/src/components/issue/IssueList.test.tsx @@ -0,0 +1,120 @@ +import { render, screen, fireEvent, waitFor } from '@testing-library/react'; +import { IssueList } from './IssueList'; +import { describe, it, expect, vi } from 'vitest'; +import type { RankedIssue } from '../../lib/types'; +import React from 'react'; + +const mockIssues: RankedIssue[] = [ + { + number: 1, + title: 'Bug in routing', + updated_at: new Date().toISOString(), + score: 80, + user: { login: 'coder1', avatar_url: '', html_url: '' }, + labels: [{ name: 'bug', color: 'red' }], + assignees: [], + comments_count: 0, + created_at: new Date().toISOString(), + html_url: '', + state: 'open', + }, + { + number: 2, + title: 'Style updates for login page', + updated_at: new Date().toISOString(), + score: 60, + user: { login: 'designer1', avatar_url: '', html_url: '' }, + labels: [{ name: 'design', color: 'blue' }], + assignees: [], + comments_count: 0, + created_at: new Date().toISOString(), + html_url: '', + state: 'open', + }, +]; + +describe('IssueList component', () => { + it('renders issues correctly', () => { + render( + , + ); + + expect(screen.getByText('Bug in routing')).toBeInTheDocument(); + expect(screen.getByText('Style updates for login page')).toBeInTheDocument(); + expect(screen.getByText('2 items')).toBeInTheDocument(); + }); + + it('triggers onSearchChange when typing in search input', () => { + const onSearchChange = vi.fn(); + render( + , + ); + + const input = screen.getByPlaceholderText(/Search issues.../); + fireEvent.change(input, { target: { value: 'routing' } }); + expect(onSearchChange).toHaveBeenCalledWith('routing'); + }); + + it('filters issues based on searchQuery prop', () => { + render( + , + ); + + expect(screen.getByText('Bug in routing')).toBeInTheDocument(); + expect(screen.queryByText('Style updates for login page')).not.toBeInTheDocument(); + expect(screen.getByText('1 items')).toBeInTheDocument(); + }); + + it('triggers onSelect when an issue item is clicked', () => { + const onSelect = vi.fn(); + render( + , + ); + + fireEvent.click(screen.getByText('Style updates for login page')); + expect(onSelect).toHaveBeenCalledWith(2); + }); + + it('shows no issues found message when filtered list is empty', () => { + render( + , + ); + + expect(screen.getByText('No issues match your search.')).toBeInTheDocument(); + }); +}); diff --git a/src/test/setup.ts b/src/test/setup.ts index 7b0828b..b6a8d47 100644 --- a/src/test/setup.ts +++ b/src/test/setup.ts @@ -1 +1,4 @@ import '@testing-library/jest-dom'; +import { vi } from 'vitest'; + +window.HTMLElement.prototype.scrollIntoView = vi.fn(); From 7aba77407ad02a0f8ee29debdff13e348712c268 Mon Sep 17 00:00:00 2001 From: Aarya1402 Date: Mon, 18 May 2026 15:31:41 +0530 Subject: [PATCH 13/17] test(issue): add test coverage for IssueDetail component d4f81b746 --- src/components/issue/IssueDetail.test.tsx | 70 +++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 src/components/issue/IssueDetail.test.tsx diff --git a/src/components/issue/IssueDetail.test.tsx b/src/components/issue/IssueDetail.test.tsx new file mode 100644 index 0000000..d9c876c --- /dev/null +++ b/src/components/issue/IssueDetail.test.tsx @@ -0,0 +1,70 @@ +import { render, screen } from '@testing-library/react'; +import { IssueDetail } from './IssueDetail'; +import { describe, it, expect } from 'vitest'; +import type { RankedIssue } from '../../lib/types'; +import React from 'react'; + +const mockIssue: RankedIssue = { + number: 101, + title: 'Fix styling of buttons', + body: 'Please fix the styled buttons on the home screen.', + updated_at: new Date().toISOString(), + score: 90, + user: { login: 'github_user', avatar_url: '', html_url: '' }, + labels: [{ name: 'ui-bug', color: 'ff0000' }], + assignees: [], + comments_count: 1, + created_at: new Date().toISOString(), + html_url: 'https://github.com/example/repo/issues/101', + state: 'open', + analysis: { + summary: 'Simple styling adjustment.', + status: 'active', + progress_estimate: 'early', + is_actionable_code_change: true, + not_mergeable_reason: null, + complexity: 1, + skills_required: ['CSS'], + newcomer_friendliness: 5, + doability_score: 95, + analysis_notes: 'Notes here.', + }, + comments: [ + { + id: 1, + user: { login: 'commenter', avatar_url: '', html_url: '' }, + body: 'I will take a look.', + created_at: new Date().toISOString(), + updated_at: new Date().toISOString(), + }, + ], +}; + +describe('IssueDetail component', () => { + it('renders select issue placeholder when issue is null', () => { + render(); + expect(screen.getByText('Select an issue to view details')).toBeInTheDocument(); + }); + + it('renders all details when issue is provided', () => { + render(); + + expect(screen.getByText('#101 — Fix styling of buttons')).toBeInTheDocument(); + expect(screen.getByText('github_user')).toBeInTheDocument(); + expect(screen.getByText('1 comments')).toBeInTheDocument(); + expect(screen.getByText('ui-bug')).toBeInTheDocument(); + + // AI Analysis section + expect(screen.getByText('Simple styling adjustment.')).toBeInTheDocument(); + expect(screen.getByText('Notes here.')).toBeInTheDocument(); + + // Comments section + expect(screen.getByText('@commenter')).toBeInTheDocument(); + expect(screen.getByText('I will take a look.')).toBeInTheDocument(); + + // Issue Body + expect( + screen.getByText('Please fix the styled buttons on the home screen.'), + ).toBeInTheDocument(); + }); +}); From d1b7ab9af04be070a6096a4d86376a999a488dab Mon Sep 17 00:00:00 2001 From: Aarya1402 Date: Mon, 18 May 2026 15:32:32 +0530 Subject: [PATCH 14/17] test(issue): fix missing required body property in tests d4f81b746 --- src/components/issue/IssueList.test.tsx | 2 ++ src/components/issue/IssueListItem.test.tsx | 1 + 2 files changed, 3 insertions(+) diff --git a/src/components/issue/IssueList.test.tsx b/src/components/issue/IssueList.test.tsx index e2d99af..bc08b02 100644 --- a/src/components/issue/IssueList.test.tsx +++ b/src/components/issue/IssueList.test.tsx @@ -8,6 +8,7 @@ const mockIssues: RankedIssue[] = [ { number: 1, title: 'Bug in routing', + body: null, updated_at: new Date().toISOString(), score: 80, user: { login: 'coder1', avatar_url: '', html_url: '' }, @@ -21,6 +22,7 @@ const mockIssues: RankedIssue[] = [ { number: 2, title: 'Style updates for login page', + body: null, updated_at: new Date().toISOString(), score: 60, user: { login: 'designer1', avatar_url: '', html_url: '' }, diff --git a/src/components/issue/IssueListItem.test.tsx b/src/components/issue/IssueListItem.test.tsx index 2759656..2db64ba 100644 --- a/src/components/issue/IssueListItem.test.tsx +++ b/src/components/issue/IssueListItem.test.tsx @@ -7,6 +7,7 @@ import React from 'react'; const mockIssue: RankedIssue = { number: 101, title: 'Optimize database queries', + body: null, updated_at: new Date(Date.now() - 3600000).toISOString(), // 1 hour ago score: 95, user: { login: 'octocat', avatar_url: '', html_url: '' }, From 123198058956a06036fda39faeb89de6ca05e24c Mon Sep 17 00:00:00 2001 From: Aarya1402 <124037849+Aarya1402@users.noreply.github.com> Date: Mon, 18 May 2026 17:03:04 +0530 Subject: [PATCH 15/17] Update src/components/issue/IssueList.test.tsx Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/components/issue/IssueList.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/issue/IssueList.test.tsx b/src/components/issue/IssueList.test.tsx index bc08b02..301b274 100644 --- a/src/components/issue/IssueList.test.tsx +++ b/src/components/issue/IssueList.test.tsx @@ -1,4 +1,4 @@ -import { render, screen, fireEvent, waitFor } from '@testing-library/react'; +import { render, screen, fireEvent } from '@testing-library/react'; import { IssueList } from './IssueList'; import { describe, it, expect, vi } from 'vitest'; import type { RankedIssue } from '../../lib/types'; From 3e9bbbea2c8b8e1a2cea78fea24a2e71ea0b9686 Mon Sep 17 00:00:00 2001 From: Aarya1402 <124037849+Aarya1402@users.noreply.github.com> Date: Mon, 18 May 2026 17:03:27 +0530 Subject: [PATCH 16/17] Update src/components/ui/Input.test.tsx Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/components/ui/Input.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ui/Input.test.tsx b/src/components/ui/Input.test.tsx index 9447760..9b0ca9b 100644 --- a/src/components/ui/Input.test.tsx +++ b/src/components/ui/Input.test.tsx @@ -18,6 +18,6 @@ describe('Input component', () => { it('applies error styles when hasError is true', () => { render(); const input = screen.getByTestId('error-input'); - expect(input.style.border).toContain('var(--status-error)'); + expect(input).toHaveStyle({ border: '1px solid var(--status-error)' }); }); }); From 1b9019fd6ebcc328185815478013002fc3ce3af2 Mon Sep 17 00:00:00 2001 From: Aarya1402 Date: Mon, 18 May 2026 17:10:47 +0530 Subject: [PATCH 17/17] test(issue): resolve PR review feedback and fix pluralization bug --- src/components/issue/IssueDetail.test.tsx | 2 +- src/components/issue/IssueDetail.tsx | 3 ++- src/components/issue/IssueList.test.tsx | 24 +++++++++++++++++++++ src/components/issue/IssueListItem.test.tsx | 21 ++++++++++++------ 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/components/issue/IssueDetail.test.tsx b/src/components/issue/IssueDetail.test.tsx index d9c876c..1263476 100644 --- a/src/components/issue/IssueDetail.test.tsx +++ b/src/components/issue/IssueDetail.test.tsx @@ -51,7 +51,7 @@ describe('IssueDetail component', () => { expect(screen.getByText('#101 — Fix styling of buttons')).toBeInTheDocument(); expect(screen.getByText('github_user')).toBeInTheDocument(); - expect(screen.getByText('1 comments')).toBeInTheDocument(); + expect(screen.getByText('1 comment')).toBeInTheDocument(); expect(screen.getByText('ui-bug')).toBeInTheDocument(); // AI Analysis section diff --git a/src/components/issue/IssueDetail.tsx b/src/components/issue/IssueDetail.tsx index d06f809..6894757 100644 --- a/src/components/issue/IssueDetail.tsx +++ b/src/components/issue/IssueDetail.tsx @@ -130,7 +130,8 @@ export function IssueDetail({ issue }: IssueDetailProps) { {formatTimestamp(issue.created_at)} - {issue.comments_count} comments + {issue.comments_count}{' '} + {issue.comments_count === 1 ? 'comment' : 'comments'} Updated {formatTimeAgo(issue.updated_at)} diff --git a/src/components/issue/IssueList.test.tsx b/src/components/issue/IssueList.test.tsx index 301b274..f8819a7 100644 --- a/src/components/issue/IssueList.test.tsx +++ b/src/components/issue/IssueList.test.tsx @@ -119,4 +119,28 @@ describe('IssueList component', () => { expect(screen.getByText('No issues match your search.')).toBeInTheDocument(); }); + + it('verifies that scrollIntoView is called on the selected item', () => { + const scrollMock = vi.fn(); + const originalGetElementById = document.getElementById; + document.getElementById = vi.fn().mockReturnValue({ + scrollIntoView: scrollMock, + }); + + render( + , + ); + + expect(document.getElementById).toHaveBeenCalledWith('issue-0'); + expect(scrollMock).toHaveBeenCalledWith({ block: 'nearest', behavior: 'smooth' }); + + document.getElementById = originalGetElementById; + }); }); diff --git a/src/components/issue/IssueListItem.test.tsx b/src/components/issue/IssueListItem.test.tsx index 2db64ba..e9492d0 100644 --- a/src/components/issue/IssueListItem.test.tsx +++ b/src/components/issue/IssueListItem.test.tsx @@ -1,10 +1,10 @@ import { render, screen, fireEvent } from '@testing-library/react'; import { IssueListItem } from './IssueListItem'; -import { describe, it, expect, vi } from 'vitest'; +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import type { RankedIssue } from '../../lib/types'; import React from 'react'; -const mockIssue: RankedIssue = { +const getMockIssue = (): RankedIssue => ({ number: 101, title: 'Optimize database queries', body: null, @@ -17,12 +17,21 @@ const mockIssue: RankedIssue = { created_at: new Date(Date.now() - 7200000).toISOString(), html_url: '', state: 'open', -}; +}); describe('IssueListItem component', () => { + beforeEach(() => { + vi.useFakeTimers(); + vi.setSystemTime(new Date('2026-05-18T12:00:00Z')); + }); + + afterEach(() => { + vi.useRealTimers(); + }); + it('renders standard fields correctly', () => { const onClick = vi.fn(); - render(); + render(); expect(screen.getByText('1.')).toBeInTheDocument(); expect(screen.getByText('#101')).toBeInTheDocument(); @@ -33,7 +42,7 @@ describe('IssueListItem component', () => { it('triggers onClick when clicked', () => { const onClick = vi.fn(); - render(); + render(); fireEvent.click(screen.getByText('Optimize database queries')); expect(onClick).toHaveBeenCalled(); @@ -41,7 +50,7 @@ describe('IssueListItem component', () => { it('renders status prefix tag when analysis exists', () => { const issueWithAnalysis: RankedIssue = { - ...mockIssue, + ...getMockIssue(), analysis: { summary: 'Discussion required', status: 'discussion',