Skip to content

Commit ee5184d

Browse files
committed
Say what jobs a test was flaky on
1 parent d13a081 commit ee5184d

File tree

2 files changed

+113
-4
lines changed

2 files changed

+113
-4
lines changed

routes/insights.test.tsx

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,82 @@ Deno.test("tracks flaky tests", async () => {
172172
assertEquals(result.data.flakyTests[0].occurrences, 2);
173173
assertEquals(result.data.flakyTests[0].avgFlakyCount, 2.5);
174174
assertEquals(result.data.flakyTests[0].runIds, [1, 2]);
175+
assertEquals(result.data.flakyTests[0].jobCounts, [{
176+
name: "test-job",
177+
count: 5,
178+
}]);
179+
});
180+
181+
Deno.test("tracks job counts for flaky tests", async () => {
182+
const mockGithub = new MockGitHubApiClient();
183+
const mockDownloader = new MockTestResultsDownloader();
184+
185+
const runs = [
186+
createMockRun(1, "CI", "completed", "main"),
187+
createMockRun(2, "CI", "completed", "main"),
188+
];
189+
190+
mockGithub.mockRuns({ totalCount: 2, runs });
191+
192+
mockDownloader.mockResults(1, [
193+
{
194+
name: "linux-x64",
195+
tests: [
196+
{
197+
name: "test1",
198+
path: "file1.test.ts",
199+
flakyCount: 1,
200+
subTests: [],
201+
},
202+
],
203+
},
204+
{
205+
name: "windows-x64",
206+
tests: [
207+
{
208+
name: "test1",
209+
path: "file1.test.ts",
210+
flakyCount: 2,
211+
subTests: [],
212+
},
213+
],
214+
},
215+
]);
216+
217+
mockDownloader.mockResults(2, [
218+
{
219+
name: "linux-x64",
220+
tests: [
221+
{
222+
name: "test1",
223+
path: "file1.test.ts",
224+
flakyCount: 1,
225+
subTests: [],
226+
},
227+
],
228+
},
229+
]);
230+
231+
const controller = new InsightsPageController(
232+
new NullLogger(),
233+
mockGithub,
234+
mockDownloader,
235+
);
236+
const result = await controller.get();
237+
238+
assertEquals(result.data.flakyTests.length, 1);
239+
assertEquals(result.data.flakyTests[0].name, "test1");
240+
assertEquals(result.data.flakyTests[0].totalFlakyCounts, 4);
241+
assertEquals(result.data.flakyTests[0].occurrences, 3);
242+
assertEquals(result.data.flakyTests[0].jobCounts.length, 2);
243+
244+
// Check job counts (order might vary)
245+
const jobCounts = result.data.flakyTests[0].jobCounts;
246+
const linuxJob = jobCounts.find((j) => j.name === "linux-x64");
247+
const windowsJob = jobCounts.find((j) => j.name === "windows-x64");
248+
249+
assertEquals(linuxJob?.count, 2);
250+
assertEquals(windowsJob?.count, 2);
175251
});
176252

177253
Deno.test("tracks failed tests", async () => {

routes/insights.tsx

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export class InsightsPageController {
6565
occurrences: number;
6666
avgFlakyCount: number;
6767
runIds: number[];
68+
jobCounts: Map<string, number>;
6869
}
6970
>();
7071

@@ -79,7 +80,11 @@ export class InsightsPageController {
7980
}
8081
>();
8182

82-
function processTest(test: RecordedTestResult, runId: number) {
83+
function processTest(
84+
test: RecordedTestResult,
85+
runId: number,
86+
jobName: string,
87+
) {
8388
// Track flaky tests
8489
if (test.flakyCount && test.flakyCount > 0) {
8590
const key = `${test.path}::${test.name}`;
@@ -91,6 +96,10 @@ export class InsightsPageController {
9196
existing.runIds.push(runId);
9297
existing.avgFlakyCount = existing.totalFlakyCounts /
9398
existing.occurrences;
99+
existing.jobCounts.set(
100+
jobName,
101+
(existing.jobCounts.get(jobName) || 0) + test.flakyCount,
102+
);
94103
} else {
95104
flakyTestsMap.set(key, {
96105
name: test.name,
@@ -99,6 +108,7 @@ export class InsightsPageController {
99108
occurrences: 1,
100109
avgFlakyCount: test.flakyCount,
101110
runIds: [runId],
111+
jobCounts: new Map([[jobName, test.flakyCount]]),
102112
});
103113
}
104114
}
@@ -124,18 +134,28 @@ export class InsightsPageController {
124134
}
125135

126136
if (test.subTests) {
127-
test.subTests.forEach((subTest) => processTest(subTest, runId));
137+
test.subTests.forEach((subTest) =>
138+
processTest(subTest, runId, jobName)
139+
);
128140
}
129141
}
130142

131143
allResults.forEach(({ runId, results }) => {
132144
results.forEach((jobResult) => {
133-
jobResult.tests.forEach((test) => processTest(test, runId));
145+
jobResult.tests.forEach((test) =>
146+
processTest(test, runId, jobResult.name)
147+
);
134148
});
135149
});
136150

137151
// Convert to array and sort by total flaky counts
138-
const flakyTests = Array.from(flakyTestsMap.values()).sort(
152+
const flakyTests = Array.from(flakyTestsMap.values()).map((test) => ({
153+
...test,
154+
jobCounts: Array.from(test.jobCounts.entries()).map(([name, count]) => ({
155+
name,
156+
count,
157+
})),
158+
})).sort(
139159
(a, b) => b.totalFlakyCounts - a.totalFlakyCounts,
140160
);
141161

@@ -304,6 +324,19 @@ export default define.page<typeof handler>(function InsightsPage({ data }) {
304324
</span>
305325
</span>
306326
</div>
327+
{test.jobCounts.length > 0 && (
328+
<div class="mt-2 text-xs text-gray-600">
329+
<span class="font-semibold">Jobs:</span>{" "}
330+
{test.jobCounts
331+
.sort((a, b) => b.count - a.count)
332+
.map((job, i) => (
333+
<span key={i}>
334+
{i > 0 && ", "}
335+
{job.name} ({job.count})
336+
</span>
337+
))}
338+
</div>
339+
)}
307340
</div>
308341
<div class="flex-shrink-0">
309342
<div class="bg-yellow-100 text-yellow-800 px-3 py-2 rounded text-center">

0 commit comments

Comments
 (0)