10.3 KB336 lines
Blame
1/**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8import type {DiffId, DiffSummary} from '../types';
9
10import {act, fireEvent, render, screen, within} from '@testing-library/react';
11import {PullRequestState} from '../../../isl-server/src/github/generated/graphql';
12import App from '../App';
13import platform from '../platform';
14import {
15 COMMIT,
16 closeCommitInfoSidebar,
17 expectMessageSentToServer,
18 resetTestMessages,
19 simulateCommits,
20 simulateMessageFromServer,
21 suppressReactErrorBoundaryErrorMessages,
22} from '../testUtils';
23
24describe('GitHubPRBadge', () => {
25 beforeEach(() => {
26 resetTestMessages();
27 render(<App />);
28 act(() => {
29 closeCommitInfoSidebar();
30 simulateCommits({
31 value: [
32 COMMIT('1', 'some public base', '0', {phase: 'public', diffId: '2'}),
33 COMMIT('a', 'Commit A', '1', {diffId: '10'}),
34 COMMIT('b', 'Commit B', 'a', {isDot: true, diffId: '11'}),
35 COMMIT('c', 'Commit C', '1'),
36 ],
37 });
38 });
39 });
40
41 it("doesn't render any github component when we don't know the remote repo provider", () => {
42 expect(screen.queryAllByTestId('diff-spinner')).toHaveLength(0);
43 });
44
45 describe('in github repo', () => {
46 beforeEach(() => {
47 act(() => {
48 simulateMessageFromServer({
49 type: 'repoInfo',
50 info: {
51 type: 'success',
52 command: 'sl',
53 repoRoot: '/path/to/testrepo',
54 dotdir: '/path/to/testrepo/.sl',
55 codeReviewSystem: {
56 type: 'github',
57 repo: 'testrepo',
58 owner: 'myusername',
59 hostname: 'github.com',
60 },
61 pullRequestDomain: undefined,
62 preferredSubmitCommand: 'pr',
63 isEdenFs: false,
64 },
65 });
66 });
67 });
68
69 it('requests a diff fetch on mount', () => {
70 expectMessageSentToServer({
71 type: 'fetchDiffSummaries',
72 });
73 });
74
75 it('renders spinners for commits with github PRs', () => {
76 expect(screen.queryAllByTestId('diff-spinner')).toHaveLength(2);
77 });
78
79 describe('after PRs loaded', () => {
80 beforeEach(() => {
81 act(() => {
82 simulateMessageFromServer({
83 type: 'fetchedDiffSummaries',
84 summaries: {
85 value: new Map<DiffId, DiffSummary>([
86 [
87 '10',
88 {
89 number: '10',
90 state: PullRequestState.Open,
91 title: 'PR A',
92 type: 'github',
93 url: 'https://github.com/myusername/testrepo/pull/10',
94 anyUnresolvedComments: false,
95 commentCount: 0,
96 commitMessage: 'PR A',
97 base: '1',
98 head: 'a',
99 branchName: 'origin/sl-pr-a',
100 },
101 ],
102 [
103 '11',
104 {
105 number: '11',
106 state: PullRequestState.Closed,
107 title: 'PR B',
108 type: 'github',
109 url: 'https://github.com/myusername/testrepo/pull/11',
110 anyUnresolvedComments: false,
111 commentCount: 0,
112 commitMessage: 'PR B',
113 base: 'a',
114 head: 'b',
115 branchName: 'origin/sl-pr-b',
116 },
117 ],
118 ]),
119 },
120 });
121 });
122 });
123
124 it("doesn't show spinners anymore", () => {
125 expect(screen.queryByTestId('diff-spinner')).not.toBeInTheDocument();
126 });
127
128 it('renders PR badges', () => {
129 expect(screen.queryAllByTestId('github-diff-info')).toHaveLength(2);
130 expect(
131 within(
132 within(screen.getByTestId('commit-a')).getByTestId('github-diff-info'),
133 ).queryByText('Open'),
134 ).toBeInTheDocument();
135 expect(
136 within(
137 within(screen.getByTestId('commit-b')).getByTestId('github-diff-info'),
138 ).queryByText('Closed'),
139 ).toBeInTheDocument();
140 });
141
142 it('does not render PR badge for public commits', () => {
143 expect(
144 within(screen.getByTestId('commit-1')).queryByTestId('github-diff-info'),
145 ).not.toBeInTheDocument();
146 });
147
148 it('shows PR numbers if config enabled', () => {
149 expect(screen.queryAllByTestId('github-diff-info')).toHaveLength(2);
150 act(() => {
151 simulateMessageFromServer({
152 type: 'gotConfig',
153 name: 'isl.show-diff-number',
154 value: 'true',
155 });
156 });
157 expect(
158 within(
159 within(screen.getByTestId('commit-a')).getByTestId('github-diff-info'),
160 ).queryByText('#10'),
161 ).toBeInTheDocument();
162 expect(
163 within(
164 within(screen.getByTestId('commit-b')).getByTestId('github-diff-info'),
165 ).queryByText('#11'),
166 ).toBeInTheDocument();
167 });
168
169 describe('url opener', () => {
170 beforeEach(() => {
171 jest.spyOn(platform, 'openExternalLink').mockImplementation(() => undefined);
172 });
173
174 it('opens with default uri', () => {
175 const prA = within(
176 within(screen.getByTestId('commit-a')).getByTestId('github-diff-info'),
177 ).getByText('open', {exact: false});
178 fireEvent.click(prA);
179
180 expect(platform.openExternalLink).toHaveBeenCalledWith(
181 'https://github.com/myusername/testrepo/pull/10',
182 );
183 });
184
185 it('uses custom opener', () => {
186 act(() => {
187 simulateMessageFromServer({
188 type: 'repoInfo',
189 info: {
190 type: 'success',
191 command: 'sl',
192 repoRoot: '/path/to/testrepo',
193 dotdir: '/path/to/testrepo/.sl',
194 codeReviewSystem: {
195 type: 'github',
196 repo: 'testrepo',
197 owner: 'myusername',
198 hostname: 'github.com',
199 },
200 pullRequestDomain: 'https://myreviewsite.dev',
201 preferredSubmitCommand: 'pr',
202 isEdenFs: false,
203 },
204 });
205 });
206
207 const prA = within(
208 within(screen.getByTestId('commit-a')).getByTestId('github-diff-info'),
209 ).getByText('open', {exact: false});
210 fireEvent.click(prA);
211
212 expect(platform.openExternalLink).toHaveBeenCalledWith(
213 'https://myreviewsite.dev/myusername/testrepo/pull/10',
214 );
215 });
216
217 it('uses custom opener with relaxed format', () => {
218 act(() => {
219 simulateMessageFromServer({
220 type: 'repoInfo',
221 info: {
222 type: 'success',
223 command: 'sl',
224 repoRoot: '/path/to/testrepo',
225 dotdir: '/path/to/testrepo/.sl',
226 codeReviewSystem: {
227 type: 'github',
228 repo: 'testrepo',
229 owner: 'myusername',
230 hostname: 'github.com',
231 },
232 // no leading https://, adds custom prefix
233 pullRequestDomain: 'myreviewsite.dev/codereview',
234 preferredSubmitCommand: 'pr',
235 isEdenFs: false,
236 },
237 });
238 });
239
240 const prA = within(
241 within(screen.getByTestId('commit-a')).getByTestId('github-diff-info'),
242 ).getByText('open', {exact: false});
243 fireEvent.click(prA);
244
245 expect(platform.openExternalLink).toHaveBeenCalledWith(
246 'https://myreviewsite.dev/codereview/myusername/testrepo/pull/10',
247 );
248 });
249 });
250 });
251
252 describe('after error', () => {
253 suppressReactErrorBoundaryErrorMessages();
254
255 beforeEach(() => {
256 act(() => {
257 simulateMessageFromServer({
258 type: 'fetchedDiffSummaries',
259 summaries: {
260 error: new Error('something failed'),
261 },
262 });
263 });
264 });
265
266 it('shows error', () => {
267 expect(screen.queryByText('something failed')).toBeInTheDocument();
268 expect(screen.queryAllByTestId('github-error')).toHaveLength(2);
269 });
270 });
271
272 it('can recover from errors', () => {
273 const successful = {
274 value: new Map<DiffId, DiffSummary>([
275 [
276 '10',
277 {
278 number: '10',
279 state: PullRequestState.Open,
280 title: 'PR A',
281 type: 'github',
282 url: 'https://github.com/myusername/testrepo/pull/10',
283 anyUnresolvedComments: false,
284 commentCount: 0,
285 commitMessage: 'PR a',
286 base: '1',
287 head: 'a',
288 branchName: 'origin/sl-pr-a',
289 },
290 ],
291 ]),
292 };
293
294 const error = {error: new Error('something failed')};
295
296 // start with success
297 act(() => {
298 simulateMessageFromServer({
299 type: 'fetchedDiffSummaries',
300 summaries: successful,
301 });
302 });
303 expect(screen.queryByText('something failed')).not.toBeInTheDocument();
304 expect(screen.queryAllByTestId('github-error')).toHaveLength(0);
305 expect(
306 within(within(screen.getByTestId('commit-a')).getByTestId('github-diff-info')).queryByText(
307 'Open',
308 ),
309 ).toBeInTheDocument();
310
311 // simulate error
312 act(() => {
313 simulateMessageFromServer({
314 type: 'fetchedDiffSummaries',
315 summaries: error,
316 });
317 });
318 expect(screen.queryByText('something failed')).toBeInTheDocument();
319 expect(screen.queryAllByTestId('github-error')).toHaveLength(2);
320
321 // recover from error: get normal data again
322 act(() => {
323 simulateMessageFromServer({
324 type: 'fetchedDiffSummaries',
325 summaries: successful,
326 });
327 });
328 expect(screen.queryByText('something failed')).not.toBeInTheDocument();
329 expect(screen.queryAllByTestId('github-error')).toHaveLength(0);
330 expect(
331 within(screen.getByTestId('commit-a')).getByTestId('github-diff-info'),
332 ).toBeInTheDocument();
333 });
334 });
335});
336