Skip to content

Commit c245014

Browse files
authored
cover pull-request.tsx with tests (#40)
2 parents 2a5f8ed + f88df3d commit c245014

File tree

1 file changed

+262
-0
lines changed

1 file changed

+262
-0
lines changed
Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
import React from 'react';
2+
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
3+
import { PullRequestItem } from './pull-request';
4+
import { vi, describe, it, expect, beforeEach } from 'vitest';
5+
import { PullRequest, TestFile } from './types';
6+
import { generateTestsResponseSchema } from "@/app/api/generate-tests/schema";
7+
8+
vi.mock('@/lib/github', () => ({
9+
getPullRequestInfo: vi.fn(),
10+
commitChangesToPullRequest: vi.fn(),
11+
}));
12+
13+
vi.mock('@/hooks/use-toast', () => ({
14+
useToast: vi.fn(() => ({
15+
toast: vi.fn(),
16+
})),
17+
}));
18+
19+
vi.mock('next/link', () => ({
20+
default: ({ children, href }: { children: React.ReactNode; href: string }) => (
21+
<a href={href}>{children}</a>
22+
),
23+
}));
24+
25+
vi.mock('react-diff-viewer', () => ({
26+
default: () => <div data-testid="react-diff-viewer">Mocked Diff Viewer</div>,
27+
}));
28+
29+
describe('PullRequestItem', () => {
30+
const mockPullRequest: PullRequest = {
31+
id: 1,
32+
title: 'Test PR',
33+
number: 123,
34+
buildStatus: 'success',
35+
isDraft: false,
36+
branchName: 'feature-branch',
37+
repository: {
38+
id: 1,
39+
name: 'test-repo',
40+
full_name: 'owner/test-repo',
41+
owner: {
42+
login: 'owner',
43+
},
44+
},
45+
};
46+
47+
beforeEach(() => {
48+
vi.clearAllMocks();
49+
global.fetch = vi.fn();
50+
});
51+
52+
it('renders the pull request information correctly', () => {
53+
render(<PullRequestItem pullRequest={mockPullRequest} />);
54+
expect(screen.getByText('Test PR')).toBeInTheDocument();
55+
expect(screen.getByText('#123')).toBeInTheDocument();
56+
expect(screen.getByText('Build: success')).toBeInTheDocument();
57+
});
58+
59+
it('handles "Write new tests" button click', async () => {
60+
const { getPullRequestInfo } = await import('@/lib/github');
61+
vi.mocked(getPullRequestInfo).mockResolvedValue({
62+
diff: 'mock diff',
63+
testFiles: [{ name: 'test.ts', content: 'test content' }],
64+
});
65+
66+
vi.mocked(global.fetch).mockResolvedValue({
67+
ok: true,
68+
json: () => Promise.resolve([{ name: 'generated_test.ts', content: 'generated content' }]),
69+
} as Response);
70+
71+
render(<PullRequestItem pullRequest={mockPullRequest} />);
72+
const writeTestsButton = screen.getByText('Write new tests');
73+
fireEvent.click(writeTestsButton);
74+
75+
await waitFor(() => {
76+
expect(screen.getByText('Analyzing PR diff...')).toBeInTheDocument();
77+
});
78+
79+
await waitFor(() => {
80+
expect(screen.getByText('generated_test.ts')).toBeInTheDocument();
81+
expect(screen.getByTestId('react-diff-viewer')).toBeInTheDocument();
82+
});
83+
});
84+
85+
it('handles "Update tests to fix" button click', async () => {
86+
const failedPR = { ...mockPullRequest, buildStatus: 'failure' };
87+
const { getPullRequestInfo } = await import('@/lib/github');
88+
vi.mocked(getPullRequestInfo).mockResolvedValue({
89+
diff: 'mock diff',
90+
testFiles: [{ name: 'test.ts', content: 'test content' }],
91+
});
92+
93+
vi.mocked(global.fetch).mockResolvedValue({
94+
ok: true,
95+
json: () => Promise.resolve([{ name: 'fixed_test.ts', content: 'fixed content' }]),
96+
} as Response);
97+
98+
render(<PullRequestItem pullRequest={failedPR} />);
99+
const updateTestsButton = screen.getByText('Update tests to fix');
100+
fireEvent.click(updateTestsButton);
101+
102+
await waitFor(() => {
103+
expect(screen.getByText('Analyzing PR diff...')).toBeInTheDocument();
104+
});
105+
106+
await waitFor(() => {
107+
expect(screen.getByText('fixed_test.ts')).toBeInTheDocument();
108+
expect(screen.getByTestId('react-diff-viewer')).toBeInTheDocument();
109+
});
110+
});
111+
112+
it('handles errors when generating tests', async () => {
113+
const { getPullRequestInfo } = await import('@/lib/github');
114+
vi.mocked(getPullRequestInfo).mockResolvedValue({
115+
diff: 'mock diff',
116+
testFiles: [{ name: 'test.ts', content: 'test content' }],
117+
});
118+
119+
vi.mocked(global.fetch).mockResolvedValue({
120+
ok: false,
121+
} as Response);
122+
123+
const { useToast } = await import('@/hooks/use-toast');
124+
const mockToast = vi.fn();
125+
vi.mocked(useToast).mockReturnValue({ toast: mockToast });
126+
127+
render(<PullRequestItem pullRequest={mockPullRequest} />);
128+
const writeTestsButton = screen.getByText('Write new tests');
129+
fireEvent.click(writeTestsButton);
130+
131+
await waitFor(() => {
132+
expect(screen.getByText('Failed to generate test files.')).toBeInTheDocument();
133+
});
134+
});
135+
136+
it('handles committing changes', async () => {
137+
const { commitChangesToPullRequest } = await import('@/lib/github');
138+
vi.mocked(commitChangesToPullRequest).mockResolvedValue('https://github.com/commit/123');
139+
140+
vi.mocked(global.fetch).mockResolvedValue({
141+
ok: true,
142+
json: () => Promise.resolve([{ name: 'generated_test.ts', content: 'generated content' }]),
143+
} as Response);
144+
145+
const { useToast } = await import('@/hooks/use-toast');
146+
const mockToast = vi.fn();
147+
vi.mocked(useToast).mockReturnValue({ toast: mockToast });
148+
149+
render(<PullRequestItem pullRequest={mockPullRequest} />);
150+
const writeTestsButton = screen.getByText('Write new tests');
151+
fireEvent.click(writeTestsButton);
152+
153+
await waitFor(() => {
154+
expect(screen.getByText('generated_test.ts')).toBeInTheDocument();
155+
});
156+
157+
const commitButton = screen.getByText('Commit changes');
158+
fireEvent.click(commitButton);
159+
160+
await waitFor(() => {
161+
expect(commitChangesToPullRequest).toHaveBeenCalled();
162+
expect(mockToast).toHaveBeenCalledWith(expect.objectContaining({
163+
title: 'Changes committed successfully',
164+
}));
165+
});
166+
});
167+
168+
it('handles canceling changes', async () => {
169+
vi.mocked(global.fetch).mockResolvedValue({
170+
ok: true,
171+
json: () => Promise.resolve([{ name: 'generated_test.ts', content: 'generated content' }]),
172+
} as Response);
173+
174+
render(<PullRequestItem pullRequest={mockPullRequest} />);
175+
const writeTestsButton = screen.getByText('Write new tests');
176+
fireEvent.click(writeTestsButton);
177+
178+
await waitFor(() => {
179+
expect(screen.getByText('generated_test.ts')).toBeInTheDocument();
180+
});
181+
182+
const cancelButton = screen.getByText('Cancel');
183+
fireEvent.click(cancelButton);
184+
185+
expect(screen.queryByText('generated_test.ts')).not.toBeInTheDocument();
186+
});
187+
188+
it('handles file toggle', async () => {
189+
vi.mocked(global.fetch).mockResolvedValue({
190+
ok: true,
191+
json: () => Promise.resolve([{ name: 'generated_test.ts', content: 'generated content' }]),
192+
} as Response);
193+
194+
render(<PullRequestItem pullRequest={mockPullRequest} />);
195+
const writeTestsButton = screen.getByText('Write new tests');
196+
fireEvent.click(writeTestsButton);
197+
198+
await waitFor(() => {
199+
expect(screen.getByText('generated_test.ts')).toBeInTheDocument();
200+
});
201+
202+
const checkbox = screen.getByRole('checkbox');
203+
fireEvent.click(checkbox);
204+
205+
expect(checkbox).not.toBeChecked();
206+
});
207+
208+
it('disables commit button when no files are selected', async () => {
209+
vi.mocked(global.fetch).mockResolvedValue({
210+
ok: true,
211+
json: () => Promise.resolve([{ name: 'generated_test.ts', content: 'generated content' }]),
212+
} as Response);
213+
214+
render(<PullRequestItem pullRequest={mockPullRequest} />);
215+
const writeTestsButton = screen.getByText('Write new tests');
216+
fireEvent.click(writeTestsButton);
217+
218+
await waitFor(() => {
219+
expect(screen.getByText('generated_test.ts')).toBeInTheDocument();
220+
});
221+
222+
const checkbox = screen.getByRole('checkbox');
223+
fireEvent.click(checkbox);
224+
225+
const commitButton = screen.getByText('Commit changes');
226+
expect(commitButton).toBeDisabled();
227+
});
228+
229+
it('handles errors when committing changes', async () => {
230+
const { commitChangesToPullRequest } = await import('@/lib/github');
231+
vi.mocked(commitChangesToPullRequest).mockRejectedValue(new Error('Commit failed'));
232+
233+
vi.mocked(global.fetch).mockResolvedValue({
234+
ok: true,
235+
json: () => Promise.resolve([{ name: 'generated_test.ts', content: 'generated content' }]),
236+
} as Response);
237+
238+
const { useToast } = await import('@/hooks/use-toast');
239+
const mockToast = vi.fn();
240+
vi.mocked(useToast).mockReturnValue({ toast: mockToast });
241+
242+
render(<PullRequestItem pullRequest={mockPullRequest} />);
243+
const writeTestsButton = screen.getByText('Write new tests');
244+
fireEvent.click(writeTestsButton);
245+
246+
await waitFor(() => {
247+
expect(screen.getByText('generated_test.ts')).toBeInTheDocument();
248+
});
249+
250+
const commitButton = screen.getByText('Commit changes');
251+
fireEvent.click(commitButton);
252+
253+
await waitFor(() => {
254+
expect(screen.getByText('Failed to commit changes. Please try again.')).toBeInTheDocument();
255+
expect(mockToast).toHaveBeenCalledWith(expect.objectContaining({
256+
title: 'Error',
257+
description: 'Failed to commit changes. Please try again.',
258+
variant: 'destructive',
259+
}));
260+
});
261+
});
262+
});

0 commit comments

Comments
 (0)