-
Notifications
You must be signed in to change notification settings - Fork 33
Expand file tree
/
Copy pathprComment.test.ts
More file actions
97 lines (77 loc) · 2.98 KB
/
prComment.test.ts
File metadata and controls
97 lines (77 loc) · 2.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import { vi, describe, it, expect, beforeEach } from 'vitest';
import { getOctokit } from '@/lib/github';
import { upsertPrComment } from './prComment';
vi.mock('@/lib/github', () => ({
getOctokit: vi.fn(),
}));
const mockGetOctokit = vi.mocked(getOctokit);
const mockOctokit = {
issues: {
listComments: vi.fn().mockResolvedValue({ data: [] }),
createComment: vi.fn().mockResolvedValue({}),
updateComment: vi.fn().mockResolvedValue({}),
},
};
mockGetOctokit.mockReturnValue(mockOctokit as any);
describe('upsertPrComment', () => {
beforeEach(() => {
vi.restoreAllMocks();
mockGetOctokit.mockReturnValue(mockOctokit as any);
mockOctokit.issues.listComments.mockResolvedValue({ data: [] });
mockOctokit.issues.createComment.mockResolvedValue({});
mockOctokit.issues.updateComment.mockResolvedValue({});
});
it('should serialize concurrent calls for the same PR', async () => {
const callOrder: string[] = [];
const { promise: firstCallBlocked, resolve: resolveFirst } = Promise.withResolvers<void>();
mockOctokit.issues.createComment
.mockImplementationOnce(async () => {
callOrder.push('first:start');
await firstCallBlocked;
callOrder.push('first:end');
return {};
})
.mockImplementationOnce(async () => {
callOrder.push('second:start');
callOrder.push('second:end');
return {};
});
const first = upsertPrComment('mui/material-ui', 42, 'report 1');
const second = upsertPrComment('mui/material-ui', 42, 'report 2');
resolveFirst();
await first;
await second;
expect(callOrder).toEqual(['first:start', 'first:end', 'second:start', 'second:end']);
});
it('should allow concurrent calls for different PRs to run in parallel', async () => {
const callOrder: string[] = [];
const { promise: firstCallBlocked, resolve: resolveFirst } = Promise.withResolvers<void>();
mockOctokit.issues.createComment
.mockImplementationOnce(async () => {
callOrder.push('pr1:start');
await firstCallBlocked;
callOrder.push('pr1:end');
return {};
})
.mockImplementationOnce(async () => {
callOrder.push('pr2:start');
callOrder.push('pr2:end');
return {};
});
const first = upsertPrComment('mui/material-ui', 1, 'report 1');
const second = upsertPrComment('mui/material-ui', 2, 'report 2');
resolveFirst();
await first;
await second;
expect(callOrder).toEqual(['pr1:start', 'pr2:start', 'pr2:end', 'pr1:end']);
});
it('should not poison the queue when a call fails', async () => {
mockOctokit.issues.createComment
.mockRejectedValueOnce(new Error('GitHub API error'))
.mockResolvedValueOnce({});
const first = upsertPrComment('mui/material-ui', 42, 'report 1');
const second = upsertPrComment('mui/material-ui', 42, 'report 2');
await expect(first).rejects.toThrow('GitHub API error');
await expect(second).resolves.toBeUndefined();
});
});