Skip to content

Commit 06a7dff

Browse files
committed
feat: add support for all branches in failed tests tab
basically we're going to be encoding a null branch parameter as specifying "all branches". So if a user goes to `<service>/<owner>/<repo>/tests` they will no longer get redirected or told to select a branch, we'll first attempt to fetch the results for all branches from the API. This change will rely on the change to the API which changes the default value of the branch when it's undefined to fetch the "all branches" data instead of the repo's default branch's data.
1 parent d20077c commit 06a7dff

File tree

8 files changed

+121
-67
lines changed

8 files changed

+121
-67
lines changed

src/pages/RepoPage/FailedTestsTab/FailedTestsPage/FailedTestsTable/FailedTestsTable.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,8 @@ const FailedTestsTable = () => {
336336
<div className="mt-4 text-center text-ds-gray-quinary">
337337
<p>No data yet</p>
338338
<p>
339-
To see data for the main branch, merge your PR into the main branch.
339+
To see data for the {testData?.defaultBranch} branch, merge your PR
340+
into the {testData?.defaultBranch} branch.
340341
</p>
341342
</div>
342343
</div>

src/pages/RepoPage/FailedTestsTab/FailedTestsPage/MetricsSection/MetricsSection.test.tsx

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,14 @@ describe('MetricsSection', () => {
148148
})
149149
})
150150

151-
describe('when on default branch', () => {
151+
describe.each([
152+
['default branch', 'main'],
153+
['all branches', ''],
154+
])('when on %s', (_, encodedBranch) => {
152155
it('renders subheaders', async () => {
153156
setup()
154157
render(<MetricsSection />, {
155-
wrapper: wrapper('/gh/owner/repo/tests/main'),
158+
wrapper: wrapper(`/gh/owner/repo/tests/${encodedBranch}`),
156159
})
157160

158161
const runEfficiency = await screen.findByText('Improve CI Run Efficiency')
@@ -164,7 +167,7 @@ describe('MetricsSection', () => {
164167
it('renders total test runtime card', async () => {
165168
setup()
166169
render(<MetricsSection />, {
167-
wrapper: wrapper('/gh/owner/repo/tests/main'),
170+
wrapper: wrapper(`/gh/owner/repo/tests/${encodedBranch}`),
168171
})
169172

170173
const title = await screen.findByText('Total test run time')
@@ -182,7 +185,7 @@ describe('MetricsSection', () => {
182185
it('renders slowest tests card', async () => {
183186
setup()
184187
render(<MetricsSection />, {
185-
wrapper: wrapper('/gh/owner/repo/tests/main'),
188+
wrapper: wrapper(`/gh/owner/repo/tests/${encodedBranch}`),
186189
})
187190

188191
const title = await screen.findByText('Slowest tests')
@@ -199,7 +202,7 @@ describe('MetricsSection', () => {
199202
it('can update the location params on button click', async () => {
200203
const { user } = setup()
201204
render(<MetricsSection />, {
202-
wrapper: wrapper('/gh/owner/repo/tests/main'),
205+
wrapper: wrapper(`/gh/owner/repo/tests/${encodedBranch}`),
203206
})
204207
const select = await screen.findByText('12')
205208
expect(select).toBeInTheDocument()
@@ -217,7 +220,7 @@ describe('MetricsSection', () => {
217220
it('removes the location param on second button click', async () => {
218221
const { user } = setup()
219222
render(<MetricsSection />, {
220-
wrapper: wrapper('/gh/owner/repo/tests/main'),
223+
wrapper: wrapper(`/gh/owner/repo/tests/${encodedBranch}`),
221224
})
222225
const select = await screen.findByText('12')
223226
expect(select).toBeInTheDocument()
@@ -239,7 +242,7 @@ describe('MetricsSection', () => {
239242
it('renders total flaky tests card', async () => {
240243
setup()
241244
render(<MetricsSection />, {
242-
wrapper: wrapper('/gh/owner/repo/tests/main'),
245+
wrapper: wrapper(`/gh/owner/repo/tests/${encodedBranch}`),
243246
})
244247

245248
const title = await screen.findByText('Flaky tests')
@@ -256,7 +259,7 @@ describe('MetricsSection', () => {
256259
it('can update the location params on button click', async () => {
257260
const { user } = setup()
258261
render(<MetricsSection />, {
259-
wrapper: wrapper('/gh/owner/repo/tests/main'),
262+
wrapper: wrapper(`/gh/owner/repo/tests/${encodedBranch}`),
260263
})
261264
const select = await screen.findByText(88)
262265
expect(select).toBeInTheDocument()
@@ -274,7 +277,7 @@ describe('MetricsSection', () => {
274277
it('removes the location param on second button click', async () => {
275278
const { user } = setup()
276279
render(<MetricsSection />, {
277-
wrapper: wrapper('/gh/owner/repo/tests/main'),
280+
wrapper: wrapper(`/gh/owner/repo/tests/${encodedBranch}`),
278281
})
279282
const select = await screen.findByText(88)
280283
expect(select).toBeInTheDocument()
@@ -313,7 +316,7 @@ describe('MetricsSection', () => {
313316
it('renders total failures card', async () => {
314317
setup()
315318
render(<MetricsSection />, {
316-
wrapper: wrapper('/gh/owner/repo/tests/main'),
319+
wrapper: wrapper(`/gh/owner/repo/tests/${encodedBranch}`),
317320
})
318321

319322
const title = await screen.findByText('Cumulative Failures')
@@ -330,7 +333,7 @@ describe('MetricsSection', () => {
330333
it('can update the location params on button click', async () => {
331334
const { user } = setup()
332335
render(<MetricsSection />, {
333-
wrapper: wrapper('/gh/owner/repo/tests/main'),
336+
wrapper: wrapper(`/gh/owner/repo/tests/${encodedBranch}`),
334337
})
335338
const select = await screen.findByText(1)
336339
expect(select).toBeInTheDocument()
@@ -370,7 +373,7 @@ describe('MetricsSection', () => {
370373
it('renders total skips card', async () => {
371374
setup()
372375
render(<MetricsSection />, {
373-
wrapper: wrapper('/gh/owner/repo/tests/main'),
376+
wrapper: wrapper(`/gh/owner/repo/tests/${encodedBranch}`),
374377
})
375378

376379
const title = await screen.findByText('Skipped tests')
@@ -387,7 +390,7 @@ describe('MetricsSection', () => {
387390
it('can update the location params on button click', async () => {
388391
const { user } = setup()
389392
render(<MetricsSection />, {
390-
wrapper: wrapper('/gh/owner/repo/tests/main'),
393+
wrapper: wrapper(`/gh/owner/repo/tests/${encodedBranch}`),
391394
})
392395
const select = await screen.findByText(20)
393396
expect(select).toBeInTheDocument()
@@ -405,7 +408,7 @@ describe('MetricsSection', () => {
405408
it('removes the location param on second button click', async () => {
406409
const { user } = setup()
407410
render(<MetricsSection />, {
408-
wrapper: wrapper('/gh/owner/repo/tests/main'),
411+
wrapper: wrapper(`/gh/owner/repo/tests/${encodedBranch}`),
409412
})
410413
const select = await screen.findByText(20)
411414
expect(select).toBeInTheDocument()

src/pages/RepoPage/FailedTestsTab/FailedTestsPage/MetricsSection/MetricsSection.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -377,9 +377,12 @@ function MetricsSection() {
377377
})
378378

379379
const decodedBranch = getDecodedBranch(branch)
380-
const selectedBranch = decodedBranch ?? testResults?.defaultBranch ?? ''
380+
const selectedBranch = decodedBranch
381381

382-
if (selectedBranch !== testResults?.defaultBranch) {
382+
if (
383+
selectedBranch !== undefined &&
384+
selectedBranch !== testResults?.defaultBranch
385+
) {
383386
return null
384387
}
385388

src/pages/RepoPage/FailedTestsTab/FailedTestsPage/SelectorSection/BranchSelector/BranchSelector.test.tsx

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ interface SetupArgs {
134134
hasNextPage?: boolean
135135
nullOverview?: boolean
136136
nullHead?: boolean
137+
nullBranch?: boolean
137138
}
138139

139140
describe('BranchSelector', () => {
@@ -142,10 +143,12 @@ describe('BranchSelector', () => {
142143
hasNextPage = false,
143144
nullOverview = false,
144145
nullHead = false,
146+
nullBranch = false,
145147
}: SetupArgs = {
146148
hasNextPage: false,
147149
nullOverview: false,
148150
nullHead: false,
151+
nullBranch: false,
149152
}
150153
) {
151154
const user = userEvent.setup()
@@ -182,6 +185,16 @@ describe('BranchSelector', () => {
182185
branch = info.variables?.branch
183186
}
184187

188+
if (nullBranch) {
189+
return HttpResponse.json({
190+
data: {
191+
owner: {
192+
repository: { __typename: 'Repository', branch: null },
193+
},
194+
},
195+
})
196+
}
197+
185198
let mockedBranch = mockBranch(branch)
186199
if (nullHead) {
187200
mockedBranch = mockBranch(branch, null)
@@ -241,7 +254,7 @@ describe('BranchSelector', () => {
241254
wrapper: wrapper(queryClient),
242255
})
243256

244-
const dropDownBtn = await screen.findByText('main')
257+
const dropDownBtn = await screen.findByText('All branches')
245258
expect(dropDownBtn).toBeInTheDocument()
246259
})
247260
})
@@ -255,7 +268,7 @@ describe('BranchSelector', () => {
255268
})
256269

257270
await waitFor(() =>
258-
expect(testLocation.pathname).toBe('/gh/codecov/test-repo/tests/main')
271+
expect(testLocation.pathname).toBe('/gh/codecov/test-repo/tests')
259272
)
260273
})
261274

@@ -286,7 +299,7 @@ describe('BranchSelector', () => {
286299
await user.click(select)
287300

288301
const options = screen.getAllByRole('option')
289-
expect(options[0]).toHaveTextContent('main')
302+
expect(options[0]).toHaveTextContent('All branches')
290303
})
291304

292305
it('navigates to the selected branch', async () => {
@@ -367,7 +380,7 @@ describe('BranchSelector', () => {
367380
wrapper: wrapper(queryClient),
368381
})
369382

370-
const select = await screen.findByText('main')
383+
const select = await screen.findByText('All branches')
371384
await user.click(select)
372385

373386
const input = await screen.findByRole('combobox')
@@ -383,9 +396,13 @@ describe('BranchSelector', () => {
383396
it('displays select a branch in the button', async () => {
384397
const { queryClient } = setup({
385398
nullOverview: true,
399+
nullBranch: true,
386400
})
387401
render(<BranchSelector />, {
388-
wrapper: wrapper(queryClient),
402+
wrapper: wrapper(
403+
queryClient,
404+
'/gh/codecov/test-repo/tests/nonexistent-branch'
405+
),
389406
})
390407

391408
const select = await screen.findByRole('button', {

src/pages/RepoPage/FailedTestsTab/FailedTestsPage/SelectorSection/BranchSelector/BranchSelector.tsx

Lines changed: 54 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ interface URLParams {
1515
branch?: string
1616
}
1717

18+
type Head = { commitid: string } | null
19+
20+
interface BranchSelection {
21+
name: string
22+
value: string
23+
head: Head
24+
}
25+
1826
const getDecodedBranch = (branch?: string) =>
1927
branch ? decodeURIComponent(branch) : undefined
2028

@@ -46,50 +54,60 @@ const BranchSelector = () => {
4654
})
4755

4856
const decodedBranch = getDecodedBranch(branch)
49-
const selectedBranch = decodedBranch ?? overview?.defaultBranch ?? ''
5057

5158
const { data: searchBranchValue } = useBranch({
5259
provider,
5360
owner,
5461
repo,
55-
branch: selectedBranch,
62+
branch: decodedBranch,
5663
opts: {
57-
queryKey: ['GetSelectedBranch', provider, owner, repo, selectedBranch],
58-
enabled: !!selectedBranch,
64+
queryKey: ['GetSelectedBranch', provider, owner, repo, decodedBranch],
65+
enabled: !!decodedBranch,
5966
},
6067
})
6168

62-
let selection = searchBranchValue?.branch
63-
if (!selection) {
64-
selection = {
65-
name: 'Select branch',
66-
head: null,
67-
}
68-
}
69-
70-
if (
71-
selectedBranch === overview?.defaultBranch &&
72-
!branch &&
73-
selection.head !== null
74-
) {
75-
history.push(
76-
failedTestsLink.path({ branch: encodeURIComponent(selection?.name) })
77-
)
78-
}
69+
const selection: BranchSelection = searchBranchValue?.branch
70+
? {
71+
name: searchBranchValue.branch.name,
72+
value: searchBranchValue.branch.name,
73+
head: searchBranchValue.branch.head,
74+
}
75+
: branch
76+
? {
77+
name: 'Select branch',
78+
value: branch,
79+
head: null,
80+
}
81+
: {
82+
name: 'All branches',
83+
value: '',
84+
head: null,
85+
}
7986

8087
const sortedBranchList = useMemo(() => {
81-
if (!branchList?.branches) return []
82-
83-
if (overview?.defaultBranch) {
84-
return [
85-
// Pins the default branch to the top of the list always, filters it from results otherwise
86-
{ name: overview.defaultBranch, head: null },
87-
...branchList.branches.filter(
88-
(branch) => branch.name !== overview.defaultBranch
89-
),
90-
]
88+
if (!branchList?.branches?.length) return []
89+
90+
const allBranches = { name: 'All branches', value: '', head: null as Head }
91+
const defaultBranch = overview?.defaultBranch
92+
? {
93+
name: overview.defaultBranch,
94+
value: overview.defaultBranch,
95+
head: null as Head,
96+
}
97+
: undefined
98+
const branches = branchList.branches
99+
.filter((branch) => branch.name !== defaultBranch?.name)
100+
.map((branch) => ({
101+
name: branch.name,
102+
value: branch.name,
103+
head: branch.head,
104+
}))
105+
106+
if (defaultBranch) {
107+
return [allBranches, defaultBranch, ...branches]
91108
}
92-
return branchList.branches
109+
110+
return [allBranches, ...branches]
93111
}, [overview?.defaultBranch, branchList.branches])
94112

95113
return (
@@ -107,9 +125,11 @@ const BranchSelector = () => {
107125
ariaName="test results branch selector"
108126
items={sortedBranchList}
109127
value={selection}
110-
onChange={(item: Branch) => {
128+
onChange={(item: BranchSelection) => {
111129
history.push(
112-
failedTestsLink.path({ branch: encodeURIComponent(item?.name) })
130+
failedTestsLink.path({
131+
branch: encodeURIComponent(item?.value),
132+
})
113133
)
114134
}}
115135
variant="gray"

src/pages/RepoPage/FailedTestsTab/FailedTestsPage/SelectorSection/SelectorSection.test.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,11 +178,14 @@ describe('SelectorSection', () => {
178178
})
179179
})
180180

181-
describe('when on default branch', () => {
181+
describe.each([
182+
['default branch', 'main'],
183+
['all branches', ''],
184+
])('when on %s', (_, encodedBranch) => {
182185
it('has all four selectors', async () => {
183186
setup()
184187
render(<SelectorSection />, {
185-
wrapper: wrapper('/gh/owner/repo/tests/main'),
188+
wrapper: wrapper(`/gh/owner/repo/tests/${encodedBranch}`),
186189
})
187190

188191
const branchSelector = await screen.findByText('Branch Context')
@@ -198,7 +201,7 @@ describe('SelectorSection', () => {
198201
it('has 60 day retention link', async () => {
199202
setup()
200203
render(<SelectorSection />, {
201-
wrapper: wrapper('/gh/owner/repo/tests/main'),
204+
wrapper: wrapper(`/gh/owner/repo/tests/${encodedBranch}`),
202205
})
203206

204207
const link = await screen.findByRole('link')

0 commit comments

Comments
 (0)