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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
import { start } from '~/code_review/signals';
import diffsEventHub from '~/diffs/event_hub';
import { EVT_MR_PREPARED } from '~/diffs/constants';
import { getDerivedMergeRequestInformation } from '~/diffs/utils/merge_request';
jest.mock('~/diffs/utils/merge_request');
describe('~/code_review', () => {
const io = diffsEventHub;
beforeAll(() => {
getDerivedMergeRequestInformation.mockImplementation(() => ({
namespace: 'x',
project: 'y',
id: '1',
}));
});
describe('start', () => {
it.each`
description | argument
${'no event hub is provided'} | ${{}}
${'no parameters are provided'} | ${undefined}
`('throws an error if $description', async ({ argument }) => {
await expect(() => start(argument)).rejects.toThrow('signalBus is a required argument');
});
describe('observeMergeRequestFinishingPreparation', () => {
const callArgs = {};
const apollo = {};
let querySpy;
let apolloSubscribeSpy;
let subscribeSpy;
let nextSpy;
let unsubscribeSpy;
let observable;
beforeEach(() => {
querySpy = jest.fn();
apolloSubscribeSpy = jest.fn();
subscribeSpy = jest.fn();
unsubscribeSpy = jest.fn();
nextSpy = jest.fn();
observable = {
next: nextSpy,
subscribe: subscribeSpy.mockReturnValue({
unsubscribe: unsubscribeSpy,
}),
};
querySpy.mockResolvedValue({
data: { project: { mergeRequest: { id: 'gql:id:1', preparedAt: 'x' } } },
});
apolloSubscribeSpy.mockReturnValue(observable);
apollo.query = querySpy;
apollo.subscribe = apolloSubscribeSpy;
callArgs.signalBus = io;
callArgs.apolloClient = apollo;
});
it('does not query at all if the page does not seem like a merge request', async () => {
getDerivedMergeRequestInformation.mockImplementationOnce(() => ({}));
await start(callArgs);
expect(querySpy).not.toHaveBeenCalled();
expect(apolloSubscribeSpy).not.toHaveBeenCalled();
});
describe('on a merge request page', () => {
it('requests the preparedAt (and id) for the current merge request', async () => {
await start(callArgs);
expect(querySpy).toHaveBeenCalledWith(
expect.objectContaining({
variables: {
projectPath: 'x/y',
iid: '1',
},
}),
);
});
it('does not subscribe to any updates if the preparedAt value is already populated', async () => {
await start(callArgs);
expect(apolloSubscribeSpy).not.toHaveBeenCalled();
});
describe('if the merge request is still asynchronously preparing', () => {
beforeEach(() => {
querySpy.mockResolvedValue({
data: { project: { mergeRequest: { id: 'gql:id:1', preparedAt: null } } },
});
});
it('subscribes to updates', async () => {
await start(callArgs);
expect(apolloSubscribeSpy).toHaveBeenCalledWith(
expect.objectContaining({ variables: { issuableId: 'gql:id:1' } }),
);
expect(observable.subscribe).toHaveBeenCalled();
});
describe('when the MR has been updated', () => {
let emitSpy;
let behavior;
beforeEach(() => {
emitSpy = jest.spyOn(diffsEventHub, '$emit');
nextSpy.mockImplementation((data) => behavior?.(data));
subscribeSpy.mockImplementation((handler) => {
behavior = handler;
return { unsubscribe: unsubscribeSpy };
});
});
it('does nothing if the MR has not yet finished preparing', async () => {
await start(callArgs);
observable.next({ data: { mergeRequestMergeStatusUpdated: { preparedAt: null } } });
expect(unsubscribeSpy).not.toHaveBeenCalled();
expect(emitSpy).not.toHaveBeenCalled();
});
it('emits an event and unsubscribes when the MR is prepared', async () => {
await start(callArgs);
observable.next({ data: { mergeRequestMergeStatusUpdated: { preparedAt: 'x' } } });
expect(unsubscribeSpy).toHaveBeenCalled();
expect(emitSpy).toHaveBeenCalledWith(EVT_MR_PREPARED);
});
});
});
});
});
});
});
|