UNPKG

13.1 kBJavaScriptView Raw
1const { OperationQueue } = require('../src/OperationQueue');
2const { QueueEvent } = require('../src/QueueEvent');
3const { TestOperation, TimeOutOperation } = require('./TestOperation');
4const { QueuePriority } = require('../src/QueuePriority');
5const { OperationEvent } = require('../src/OperationEvent');
6const { delay, nextTick } = require('./utils');
7
8describe('OperationQueue', () => {
9
10 describe('function OperationQueue', function () {
11 test('should be defined', () => {
12 expect(OperationQueue).toBeDefined();
13 });
14
15 test('should be instantiated', () => {
16 const operationQueue = new OperationQueue(1);
17
18 expect(operationQueue).toBeDefined();
19 });
20
21 test('inherits from Operation', () => {
22 const operationQueue = new OperationQueue(1);
23
24 expect(operationQueue.__proto__.__proto__.constructor.name).toBe('Object');
25 });
26
27 test('should be valid type', () => {
28 const operationQueue = new OperationQueue(1);
29
30 expect(operationQueue.constructor.name).toBe('OperationQueue');
31 });
32 });
33
34 describe('function addOperation', () => {
35 test('should add a single operation to its operations prop', () => {
36 const operationQueue = new OperationQueue(1);
37 const operation1 = new TestOperation();
38
39 operationQueue.addOperation(operation1);
40
41 expect(operationQueue.operations).toEqual([operation1]);
42 });
43 });
44
45 describe('function addOperations', () => {
46 test('should add multiple operations to its operations prop', () => {
47 const operationQueue = new OperationQueue(1);
48 const operation1 = new TestOperation();
49 const operation2 = new TestOperation();
50
51 operationQueue.addOperations([operation1, operation2]);
52
53 expect(operationQueue.operations).toEqual([operation1, operation2]);
54 })
55 });
56
57 describe('function pause', function () {
58 test('should set/get property isPaused', () => {
59 const operationQueue = new OperationQueue();
60
61 operationQueue.pause();
62
63 expect(operationQueue.isPaused).toEqual(true);
64 });
65
66 test('should not start any newly added opeations when queue is paused', () => {
67 const operationQueue = new OperationQueue();
68 const operation1 = new TestOperation();
69
70 operationQueue.pause();
71 operationQueue.addOperation(operation1);
72
73 expect(operationQueue.runningQueue.length).toBe(0);
74 });
75
76 test('should emit paused event', () => {
77 const pausedFunction = jest.fn(() => {
78 });
79 const operationQueue = new OperationQueue();
80 operationQueue.on(QueueEvent.PAUSED, pausedFunction)
81
82 operationQueue.pause();
83
84 expect(pausedFunction).toHaveBeenCalled();
85 });
86
87 test('should emit paused event only once', () => {
88 const pausedFunction = jest.fn(() => {
89 });
90 const operationQueue = new OperationQueue();
91 operationQueue.on(QueueEvent.PAUSED, pausedFunction)
92
93 operationQueue.pause();
94 operationQueue.pause();
95 operationQueue.pause();
96 operationQueue.pause();
97
98 expect(pausedFunction).toHaveBeenCalledTimes(1);
99 });
100 });
101
102 describe('function off', () => {
103 test('should remove callback from subscriber', async (done) => {
104 const mockFunction = jest.fn(() => {
105 });
106 const operationQueue = new OperationQueue();
107
108 operationQueue.on(OperationEvent.START, mockFunction);
109 operationQueue.off(OperationEvent.START, mockFunction);
110 operationQueue.pause();
111 await nextTick();
112
113 expect(mockFunction).not.toHaveBeenCalled();
114 done();
115 });
116 });
117
118 describe('function resume', function () {
119 test('should un-set/get property isPaused', () => {
120 const operationQueue = new OperationQueue();
121
122 operationQueue.pause();
123 operationQueue.resume();
124
125 expect(operationQueue.isPaused).toEqual(false);
126 });
127
128 test('should start opeations when queue is un-paused', () => {
129 const operationQueue = new OperationQueue();
130 const operation1 = new TestOperation();
131 const operation2 = new TestOperation();
132
133 operationQueue.addOperation(operation1);
134 operationQueue.pause();
135
136 expect(operationQueue.runningQueue.length).toBe(1);
137
138 operationQueue.addOperation(operation2);
139
140 expect(operationQueue.runningQueue.length).toBe(1);
141
142 operationQueue.resume();
143
144 expect(operationQueue.runningQueue.length).toBe(2);
145 });
146
147 test('should emit resumed event', () => {
148 const resumedFunction = jest.fn(() => {
149 });
150 const operationQueue = new OperationQueue();
151 operationQueue.on(QueueEvent.RESUMED, resumedFunction)
152 operationQueue.pause();
153
154 operationQueue.resume();
155
156 expect(resumedFunction).toHaveBeenCalled();
157 });
158
159 test('should emit resumed event only once', () => {
160 const resumedFunction = jest.fn(() => {
161 });
162 const operationQueue = new OperationQueue();
163 operationQueue.on(QueueEvent.PAUSED, resumedFunction)
164 operationQueue.pause();
165
166 operationQueue.resume();
167 operationQueue.resume();
168
169 expect(resumedFunction).toHaveBeenCalledTimes(1);
170 });
171 });
172
173 describe('adding operations while queue is still executing', () => {
174 test('should add operations seperatly, at any given time', () => {
175 const operationQueue = new OperationQueue();
176 const operation1 = new TestOperation();
177 const operation2 = new TestOperation();
178
179 operationQueue.addOperation(operation1);
180 expect(operationQueue.runningQueue.length).toBe(1);
181
182 operationQueue.addOperations([operation2]);
183 expect(operationQueue.runningQueue.length).toBe(2);
184 });
185 });
186
187 describe('function addOperation/addOperations', () => {
188 test('should throw error when operation are dependent form each other', async (done) => {
189 const operationQueue = new OperationQueue();
190 const operation1 = new TestOperation();
191 const operation2 = new TestOperation();
192
193 operation1.dependencies = [operation2];
194 operation2.dependencies = [operation1];
195
196 try {
197 operationQueue.addOperation(operation1);
198 await nextTick();
199 fail('should have failed');
200 } catch (e) {
201 console.log(e);
202 expect(e.constructor.name === 'CircularOperationValidatorError').toBe(true);
203 done();
204 }
205 });
206
207 test('properties before calling start', () => {
208 const operationQueue = new OperationQueue();
209
210 expect(operationQueue.isExecuting).toBe(false);
211 });
212
213 test('properties while running operations', () => {
214 const operationQueue = new OperationQueue();
215 const operation1 = new TimeOutOperation(500);
216
217 operationQueue.addOperation(operation1)
218
219 expect(operationQueue.isExecuting).toBe(true);
220 });
221
222 test('properties after running operations', async () => {
223 const operationQueue = new OperationQueue();
224 const operation1 = new TestOperation();
225
226 operationQueue.addOperation(operation1)
227 await delay(500);
228
229 expect(operationQueue.isExecuting).toBe(false);
230 });
231
232 test('properties after running multiple operations', async (done) => {
233 const operationQueue = new OperationQueue();
234 const operation1 = new TestOperation();
235 const operation2 = new TimeOutOperation(500);
236
237 operationQueue.addOperation(operation1)
238 await nextTick();
239 operationQueue.addOperation(operation2)
240
241 operationQueue.on(QueueEvent.DONE, () => {
242 expect(operationQueue.isExecuting).toBe(false);
243 done();
244 })
245
246 });
247
248 test('should call done event when queue becomes empty', async (done) => {
249 const operationQueue = new OperationQueue();
250 const operation1 = new TestOperation();
251 const doneFn = jest.fn(() => {
252 done();
253 });
254 operationQueue.on(QueueEvent.DONE, doneFn);
255
256 operationQueue.addOperation(operation1);
257
258 await nextTick();
259
260 expect(doneFn).toHaveBeenCalledTimes(1);
261 });
262
263 test('should call done once event when queue becomes empty', async () => {
264 const operationQueue = new OperationQueue();
265 const operation1 = new TestOperation();
266 const doneFn = jest.fn(() => {
267 });
268 operationQueue.on(QueueEvent.DONE, doneFn);
269
270 operationQueue.addOperation(operation1);
271 });
272
273 test('should call promise resolve when operations are re-added', async () => {
274 const operationQueue = new OperationQueue();
275 const operation1 = new TestOperation();
276 const operation2 = new TestOperation();
277 const doneFn = jest.fn(() => {
278 });
279
280 operationQueue.on(QueueEvent.DONE, doneFn);
281
282 operationQueue.addOperation(operation1);
283 operationQueue.addOperation(operation2)
284
285 await nextTick();
286
287 expect(doneFn).toHaveBeenCalledTimes(1);
288 });
289
290 test('should set order queue priority of operations', (done) => {
291 const operationQueue = new OperationQueue();
292 operationQueue.maximumConcurentOperations = 1;
293
294 const operation1 = new TestOperation();
295 operation1.queuePriority = QueuePriority.veryHigh;
296 const operation2 = new TestOperation();
297 operation2.queuePriority = QueuePriority.high;
298 const operation3 = new TestOperation();
299 operation3.queuePriority = QueuePriority.normal;
300 const operation4 = new TestOperation();
301 operation4.queuePriority = QueuePriority.low;
302 const operation5 = new TestOperation();
303 operation5.queuePriority = QueuePriority.veryLow;
304
305 const doneOperations = [];
306 operation1.on(OperationEvent.DONE, () => {
307 doneOperations.push(operation1);
308 });
309 operation2.on(OperationEvent.DONE, () => {
310 doneOperations.push(operation2);
311 });
312 operation3.on(OperationEvent.DONE, () => {
313 doneOperations.push(operation3);
314 });
315 operation4.on(OperationEvent.DONE, () => {
316 doneOperations.push(operation4);
317 });
318 operation5.on(OperationEvent.DONE, () => {
319 doneOperations.push(operation5);
320 });
321
322 operationQueue.addOperations([
323 operation2,
324 operation1,
325 operation4,
326 operation5,
327 operation3
328 ]);
329
330 operationQueue.on(QueueEvent.DONE, () => {
331 expect(doneOperations[0] === operation1);
332 expect(doneOperations[1] === operation2);
333 expect(doneOperations[2] === operation3);
334 expect(doneOperations[3] === operation4);
335 expect(doneOperations[4] === operation5);
336 done();
337 });
338 });
339 });
340
341 describe('function cancel', () => {
342 test('can cancel an operation waiting to be executed in queue', async () => {
343 const operationQueue = new OperationQueue();
344 operationQueue.maximumConcurentOperations = 1;
345
346 const operation1 = new TimeOutOperation(1000);
347 const operation2 = new TestOperation();
348
349 operationQueue.addOperation(operation1);
350 operationQueue.addOperation(operation2);
351 await nextTick();
352 operation2.cancel();
353 await nextTick();
354
355 expect(operationQueue.operations.length).toBe(1);
356 });
357
358 test('cancel last operation to end queue', async (done) => {
359 const operationQueue = new OperationQueue();
360 operationQueue.maximumConcurentOperations = 1;
361 const doneFunction = jest.fn(() => {
362 done();
363 });
364 operationQueue.on(QueueEvent.DONE, doneFunction);
365 const operation = new TestOperation();
366
367 operationQueue.addOperation(operation);
368 operation.cancel();
369 });
370 })
371})
\No newline at end of file