@shopgate/pwa-core 7.30.0-alpha.6 → 7.30.0-alpha.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/classes/AppCommand/index.js +115 -11
  2. package/classes/AppCommand/spec.js +260 -6
  3. package/classes/AppCommandRequest/index.js +129 -20
  4. package/classes/AppPermissionsRequest/AppPermissionsRequest.js +45 -7
  5. package/classes/AppPermissionsRequest/GetAppPermissionsRequest.js +48 -9
  6. package/classes/AppPermissionsRequest/RequestAppPermissionsRequest.js +54 -9
  7. package/classes/Bridge/index.js +34 -4
  8. package/classes/Bridge/spec.js +24 -1
  9. package/classes/BrightnessRequest/index.js +59 -10
  10. package/classes/BrightnessRequest/spec.js +111 -6
  11. package/classes/BrowserConnector/index.js +180 -26
  12. package/classes/Conditioner/index.js +74 -8
  13. package/classes/Conditioner/spec.js +75 -1
  14. package/classes/DataRequest/index.js +116 -13
  15. package/classes/DevServerBridge/index.js +86 -9
  16. package/classes/DevServerBridge/spec.js +231 -14
  17. package/classes/ErrorManager/index.js +144 -20
  18. package/classes/ErrorManager/spec.js +244 -2
  19. package/classes/Event/index.js +101 -15
  20. package/classes/HttpRequest/index.js +182 -21
  21. package/classes/PipelineDependencies/index.js +42 -6
  22. package/classes/PipelineDependencies/spec.js +46 -3
  23. package/classes/PipelineManager/index.js +517 -71
  24. package/classes/PipelineManager/spec.js +733 -15
  25. package/classes/PipelineRequest/index.js +167 -19
  26. package/classes/PipelineRequest/mock.js +118 -21
  27. package/classes/PipelineRequest/spec.js +333 -2
  28. package/classes/PipelineSequence/index.js +34 -6
  29. package/classes/Request/index.js +61 -13
  30. package/classes/RequestBuffer/index.js +43 -6
  31. package/classes/RequestManager/index.js +216 -33
  32. package/classes/RequestManager/spec.js +188 -1
  33. package/classes/Scanner/index.js +246 -67
  34. package/classes/ScannerEvent/index.js +23 -9
  35. package/classes/ScannerEventHandler/index.js +39 -16
  36. package/classes/ScannerEventListener/index.js +84 -24
  37. package/classes/ScannerManager/ScanProcessingError.js +11 -3
  38. package/classes/ScannerManager/index.js +133 -21
  39. package/classes/WebStorageRequest/index.js +76 -9
  40. package/commands/analyticsSetCustomValues.js +8 -2
  41. package/commands/appPermissions.js +10 -3
  42. package/commands/brightness.js +33 -5
  43. package/commands/broadcastEvent.js +8 -2
  44. package/commands/cleanTab.js +11 -3
  45. package/commands/closeInAppBrowser.js +22 -2
  46. package/commands/flushTab.js +8 -2
  47. package/commands/getWebStorageEntry.js +11 -2
  48. package/commands/hideMenuBar.js +8 -2
  49. package/commands/hideNavigationBar.js +8 -2
  50. package/commands/hideSplashScreen.js +8 -2
  51. package/commands/onload.js +13 -3
  52. package/commands/openAppSettings.js +8 -2
  53. package/commands/openPage.js +8 -2
  54. package/commands/openPageExtern.js +8 -2
  55. package/commands/performCommandsAfterDelay.js +11 -3
  56. package/commands/plotProjects.js +65 -7
  57. package/commands/popTabToRoot.js +11 -3
  58. package/commands/registerEvents.js +10 -2
  59. package/commands/scanner.js +76 -7
  60. package/commands/setCookie.js +8 -2
  61. package/commands/setDebugLoggingEnabled.js +8 -2
  62. package/commands/setScrollingEnabled.js +7 -2
  63. package/commands/setWebStorageEntry.js +8 -2
  64. package/commands/shareItem.js +18 -2
  65. package/commands/showNavigationBar.js +8 -2
  66. package/commands/showTab.js +13 -2
  67. package/commands/unifiedTracking.js +128 -30
  68. package/constants/AppCommands.js +6 -1
  69. package/constants/AppEvents.js +9 -1
  70. package/constants/AppPermissions.js +57 -13
  71. package/constants/Command.js +1 -1
  72. package/constants/ErrorHandleTypes.js +2 -1
  73. package/constants/ErrorManager.js +15 -1
  74. package/constants/Pipeline.js +52 -17
  75. package/constants/ProcessTypes.js +3 -1
  76. package/constants/RequestManagerModes.js +19 -7
  77. package/constants/RequestTypes.js +2 -1
  78. package/constants/Scanner.js +39 -10
  79. package/constants/Trilean.js +6 -1
  80. package/emitters/ui.js +2 -1
  81. package/helpers/index.js +66 -8
  82. package/helpers/logGroup.js +56 -8
  83. package/helpers/version.js +216 -22
  84. package/index.js +60 -5
  85. package/package.json +1 -1
@@ -1,18 +1,736 @@
1
- function _typeof(obj){if(typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"){_typeof=function _typeof(obj){return typeof obj;};}else{_typeof=function _typeof(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj;};}return _typeof(obj);}/* eslint-disable extra-rules/no-single-line-objects */import logGroup from"../../helpers/logGroup";// eslint-disable-next-line import/named
2
- import{mockedDispatch}from"../AppCommand";import event from"../Event";import{ERROR_HANDLE_SUPPRESS}from"../../constants/ErrorHandleTypes";import PipelineRequest from"../PipelineRequest";import pipelineManager from'.';import pipelineDependencies from"../PipelineDependencies";import errorManager from"../ErrorManager";import pipelineSequence from"../PipelineSequence";import{PROCESS_LAST,PROCESS_SEQUENTIAL,PROCESS_ALWAYS}from"../../constants/ProcessTypes";import{ETIMEOUT,ENETUNREACH}from"../../constants/Pipeline";jest.mock("../../helpers/logGroup",function(){return jest.fn();});jest.mock("../ErrorManager",function(){return{queue:jest.fn()};});jest.mock("../AppCommand");jest.mock("../Event",function(){return{removeCallback:jest.fn(),addCallback:jest.fn()};});var PIPELINE_NAME='TestPipeline';var PIPELINE_DEPENDANT='PIPELINE_DEPENDANT';var PIPELINE_DEPENDENCY='PIPELINE_DEPENDENCY';/**
1
+ /* eslint-disable extra-rules/no-single-line-objects */
2
+ import logGroup from "../../helpers/logGroup";
3
+ // eslint-disable-next-line import/named
4
+ import { mockedDispatch } from "../AppCommand";
5
+ import event from "../Event";
6
+ import { ERROR_HANDLE_SUPPRESS } from "../../constants/ErrorHandleTypes";
7
+ import PipelineRequest from "../PipelineRequest";
8
+ import pipelineManager from '.';
9
+ import pipelineDependencies from "../PipelineDependencies";
10
+ import errorManager from "../ErrorManager";
11
+ import pipelineSequence from "../PipelineSequence";
12
+ import { PROCESS_LAST, PROCESS_SEQUENTIAL, PROCESS_ALWAYS } from "../../constants/ProcessTypes";
13
+ import { ETIMEOUT, ENETUNREACH } from "../../constants/Pipeline";
14
+ jest.mock("../../helpers/logGroup", () => jest.fn());
15
+ jest.mock("../ErrorManager", () => ({
16
+ queue: jest.fn()
17
+ }));
18
+ jest.mock("../AppCommand");
19
+ jest.mock("../Event", () => ({
20
+ removeCallback: jest.fn(),
21
+ addCallback: jest.fn()
22
+ }));
23
+ const PIPELINE_NAME = 'TestPipeline';
24
+ const PIPELINE_DEPENDANT = 'PIPELINE_DEPENDANT';
25
+ const PIPELINE_DEPENDENCY = 'PIPELINE_DEPENDENCY';
26
+
27
+ /**
3
28
  * Creates a new pipeline request instance.
4
29
  * @param {string} [pipelineName=PIPELINE_NAME] Name of the request pipeline.
5
30
  * @return {Object}
6
- */var createRequest=function createRequest(){var pipelineName=arguments.length>0&&arguments[0]!==undefined?arguments[0]:PIPELINE_NAME;return new PipelineRequest(pipelineName);};describe('PipelineManager',function(){var request;beforeEach(function(){// Reset modules.
7
- pipelineSequence.constructor();pipelineDependencies.constructor();pipelineManager.constructor();// Generate a request and add it to the manager. It can be used for most of the tests.
8
- request=createRequest();pipelineManager.add(request);pipelineDependencies.set(PIPELINE_DEPENDANT,[PIPELINE_DEPENDENCY]);jest.clearAllMocks();});afterEach(function(){var entry=pipelineManager.requests.get(request.serial);if(entry){clearTimeout(entry.timer);}});describe('.constructor()',function(){it('should work as expected',function(){pipelineManager.constructor();expect(pipelineManager.requests.size).toBe(0);expect(pipelineManager.pipelines.size).toBe(0);expect(pipelineManager.suppressedErrors).toHaveLength(0);});});describe('.addSuppressedErrors()',function(){it('should store an error code to suppress',function(){var error=1;pipelineManager.addSuppressedErrors(error);expect(pipelineManager.suppressedErrors).toHaveLength(1);expect(pipelineManager.suppressedErrors[0]).toBe(error);});it('should store multiple error codes to suppress',function(){var errors=[1,2];pipelineManager.addSuppressedErrors(errors);expect(pipelineManager.suppressedErrors).toHaveLength(2);expect(pipelineManager.suppressedErrors).toEqual(errors);});it('should extend the error list with every call',function(){var entryOne=[1,2];var entryTwo=3;pipelineManager.addSuppressedErrors(entryOne);pipelineManager.addSuppressedErrors(entryTwo);expect(pipelineManager.suppressedErrors).toHaveLength(3);expect(pipelineManager.suppressedErrors).toEqual([1,2,3]);});});describe('.add()',function(){it('should add a request to the queue',function(){expect(pipelineManager.requests.size).toEqual(1);expect(pipelineManager.requests.get(request.serial).request).toBe(request);});it('should add multiple requests to the queue',function(){var dispatchSpy=jest.spyOn(pipelineManager,'dispatch');var requestOne=request;var requestTwo=createRequest("".concat(PIPELINE_NAME,"1"));pipelineManager.add(requestOne);pipelineManager.add(requestTwo);expect(pipelineManager.requests.size).toEqual(2);expect(pipelineManager.requests.get(requestOne.serial).request).toBe(requestOne);expect(pipelineManager.requests.get(requestTwo.serial).request).toBe(requestTwo);expect(dispatchSpy).toHaveBeenCalledTimes(2);expect(dispatchSpy).toHaveBeenCalledWith(requestOne.serial);expect(dispatchSpy).toHaveBeenCalledWith(requestTwo.serial);});});describe('.dispatch()',function(){it('should send a request',function(){var createRequestCallbackSpy=jest.spyOn(pipelineManager,'createRequestCallback');var sendRequestSpy=jest.spyOn(pipelineManager,'sendRequest');pipelineManager.constructor();var result=pipelineManager.add(request);expect(result).toBeInstanceOf(Promise);expect(createRequestCallbackSpy).toHaveBeenCalledTimes(1);expect(createRequestCallbackSpy).toHaveBeenCalledWith(request.serial,expect.any(Function),expect.any(Function));expect(sendRequestSpy).toHaveBeenCalledTimes(1);expect(sendRequestSpy).toHaveBeenCalledWith(request.serial);});it('should not send the requests when it has running dependencies',function(){var sendRequestSpy=jest.spyOn(pipelineManager,'sendRequest');var dependant=createRequest(PIPELINE_DEPENDANT);var dependency=createRequest(PIPELINE_DEPENDENCY);pipelineManager.add(dependency);pipelineManager.add(dependant);expect(sendRequestSpy).toHaveBeenCalledTimes(1);expect(sendRequestSpy).toHaveBeenCalledWith(dependency.serial);});it('should resolve when a pipeline response comes in',function(){var response={succcess:true};pipelineManager.constructor();var handler=pipelineManager.add(request);expect(request.callback).toBeInstanceOf(Function);// Simulate a pipeline response event.
9
- request.callback(null,request.serial,response);expect(handler).resolves.toEqual(response);});it('should reject when a pipeline error comes in',function(){var error={message:'Message',code:'CODE'};var expected=new Error(error.message);expected.code=error.code;pipelineManager.constructor();var handler=pipelineManager.add(request);expect(request.callback).toBeInstanceOf(Function);// Simulate a pipeline response event.
10
- request.callback(error,request.serial);expect(handler).rejects.toEqual(expected);});});describe('.createRequestCallback()',function(){var error={message:'Something went wrong',code:'ERROR'};var output={some:'output'};var mockResolve;var mockReject;beforeEach(function(){mockResolve=jest.fn();mockReject=jest.fn();});it('should create a callback like expected',function(){pipelineManager.createRequestCallback(request.serial,mockResolve,mockReject);expect(request.resolve).toBe(mockResolve);expect(request.reject).toBe(mockReject);expect(request.callback).toBeInstanceOf(Function);expect(event.addCallback).toHaveBeenCalledTimes(1);expect(event.addCallback).toHaveBeenCalledWith(request.getEventCallbackName(),request.callback);});describe('should create a callback that invokes handleResults() for default process types',function(){it('should handle the output',function(){var handleResultSpy=jest.spyOn(pipelineManager,'handleResult');request.setResponseProcessed(PROCESS_ALWAYS);pipelineManager.createRequestCallback(request.serial,mockResolve,mockReject);request.callback(null,request.serial,output);expect(handleResultSpy).toHaveBeenCalledTimes(1);expect(handleResultSpy).toHaveBeenCalledWith(request.serial);expect(request.error).toEqual(null);expect(request.output).toEqual(output);});it('should handle the error',function(){var handleResultSpy=jest.spyOn(pipelineManager,'handleResult');request.setResponseProcessed(PROCESS_ALWAYS);pipelineManager.createRequestCallback(request.serial,mockResolve,mockReject);pipelineManager.createRequestCallback(request.serial,mockResolve,mockReject);request.callback(error,request.serial,{});expect(handleResultSpy).toHaveBeenCalledTimes(1);expect(handleResultSpy).toHaveBeenCalledWith(request.serial);expect(request.error).toEqual(error);expect(request.output).toEqual({});});});describe('should create a callback that invokes handleResults() for sequential process types',function(){it('should handle the output',function(){var handleResultSequenceSpy=jest.spyOn(pipelineManager,'handleResultSequence');request.setResponseProcessed(PROCESS_SEQUENTIAL);pipelineManager.createRequestCallback(request.serial,mockResolve,mockReject);request.callback(null,request.serial,output);expect(handleResultSequenceSpy).toHaveBeenCalledTimes(1);expect(request.error).toEqual(null);expect(request.output).toEqual(output);});it('should handle the error',function(){var handleResultSequenceSpy=jest.spyOn(pipelineManager,'handleResultSequence');request.setResponseProcessed(PROCESS_SEQUENTIAL);pipelineManager.createRequestCallback(request.serial,mockResolve,mockReject);pipelineManager.createRequestCallback(request.serial,mockResolve,mockReject);request.callback(error,request.serial,{});expect(handleResultSequenceSpy).toHaveBeenCalledTimes(1);expect(request.error).toEqual(error);expect(request.output).toEqual({});});});describe('should create a callback that invokes handleResults() for process last types',function(){it('should handle the output',function(){var handleResultLastSpy=jest.spyOn(pipelineManager,'handleResultLast');request.setResponseProcessed(PROCESS_LAST);pipelineManager.createRequestCallback(request.serial,mockResolve,mockReject);request.callback(null,request.serial,output);expect(handleResultLastSpy).toHaveBeenCalledTimes(1);expect(request.error).toEqual(null);expect(request.output).toEqual(output);});it('should handle the error',function(){var handleResultLastSpy=jest.spyOn(pipelineManager,'handleResultLast');request.setResponseProcessed(PROCESS_LAST);pipelineManager.createRequestCallback(request.serial,mockResolve,mockReject);pipelineManager.createRequestCallback(request.serial,mockResolve,mockReject);request.callback(error,request.serial,{});expect(handleResultLastSpy).toHaveBeenCalledTimes(1);expect(request.error).toEqual(error);expect(request.output).toEqual({});});});});describe('.hasRunningDependencies()',function(){it('should return true if dependencies are running',function(){var dependant=createRequest(PIPELINE_DEPENDANT);var dependency=createRequest(PIPELINE_DEPENDENCY);pipelineManager.add(dependant);pipelineManager.add(dependency);expect(pipelineManager.hasRunningDependencies(dependant.name)).toBe(true);});it('should return false if no dependencies are running',function(){var dependency=createRequest(PIPELINE_DEPENDENCY);pipelineManager.add(dependency);expect(pipelineManager.hasRunningDependencies(dependency.name)).toBe(false);});});describe('.handleDeferredRequests',function(){it('should send deferred requests when their dependencies are finished',function(){var sendRequestSpy=jest.spyOn(pipelineManager,'sendRequest');var dependant=createRequest(PIPELINE_DEPENDANT);var dependencyOne=createRequest(PIPELINE_DEPENDENCY);var dependencyTwo=createRequest(PIPELINE_DEPENDENCY);pipelineManager.add(dependencyOne);pipelineManager.add(dependencyTwo);pipelineManager.add(dependant);var entryOne=pipelineManager.requests.get(dependencyOne.serial);var entryTwo=pipelineManager.requests.get(dependencyTwo.serial);// Two times called for the depencencies.
11
- expect(sendRequestSpy).toHaveBeenCalledTimes(2);expect(sendRequestSpy).toHaveBeenCalledWith(entryOne.request.serial);expect(sendRequestSpy).toHaveBeenCalledWith(entryTwo.request.serial);pipelineManager.handleDeferredRequests();// Call count didn't change, since dependencies are still running.
12
- expect(sendRequestSpy).toHaveBeenCalledTimes(2);entryOne.request.callback(null,entryOne.request.serial);pipelineManager.handleDeferredRequests();// Call count didn't change, since one dependency is still running.
13
- expect(sendRequestSpy).toHaveBeenCalledTimes(2);entryTwo.request.callback(null,entryTwo.request.serial);pipelineManager.handleDeferredRequests();expect(sendRequestSpy).toHaveBeenCalledTimes(3);expect(sendRequestSpy).toHaveBeenCalledWith(dependant.serial);});});describe('.handleTimeout()',function(){jest.useFakeTimers();it('should handle timeouts like expected',function(done){pipelineManager.constructor();request.setRetries(1);var promise=pipelineManager.add(request);var entry=pipelineManager.requests.get(request.serial);expect(entry.retries).toBe(1);jest.runAllTimers();expect(entry.retries).toBe(0);jest.runAllTimers();promise["catch"](function(_ref){var message=_ref.message,code=_ref.code;expect(message.includes('timed out')).toBeTruthy();expect(code).toBe(ETIMEOUT);done();});});});describe('.handleError()',function(){it('should ignore when error code should be suppressed',function(){pipelineManager.addSuppressedErrors('MY_ERROR');request.reject=jest.fn();request.error={code:'MY_ERROR'};pipelineManager.handleError(request.serial);expect(request.reject).toHaveBeenCalledTimes(1);expect(errorManager.queue).toHaveBeenCalledTimes(0);});it('should ignore when the original error code was sanitized to an error code that should be suppressed',function(){pipelineManager.addSuppressedErrors(ENETUNREACH);request.reject=jest.fn();request.error={code:'-1000'};pipelineManager.handleError(request.serial);expect(request.reject).toHaveBeenCalledTimes(1);expect(errorManager.queue).toHaveBeenCalledTimes(0);});it('should ignore when pipeline is set to ignore specific error code',function(){var req=createRequest(PIPELINE_NAME).setErrorBlacklist(['MY_ERROR']);pipelineManager.add(req);req.reject=jest.fn();req.error={code:'MY_ERROR'};pipelineManager.handleError(req.serial);expect(req.reject).toHaveBeenCalledTimes(1);expect(errorManager.queue).toHaveBeenCalledTimes(0);});it('should not queue an error when all errors are suppressed',function(){var req=createRequest(PIPELINE_NAME).setHandleErrors(ERROR_HANDLE_SUPPRESS);pipelineManager.add(req);req.reject=jest.fn();req.error={code:'MY_ERROR'};pipelineManager.handleError(req.serial);expect(req.reject).toHaveBeenCalledTimes(1);expect(errorManager.queue).toHaveBeenCalledTimes(0);});it('should call the appropriate reject()',function(){request.reject=jest.fn();request.error={code:'MY_ERROR'};pipelineManager.handleError(request.serial);expect(request.reject).toHaveBeenCalledTimes(1);expect(errorManager.queue).toHaveBeenCalledTimes(1);});});describe('.sanitizeError()',function(){it('should convert a numeric -999 code to ETIMEOUT',function(){expect(pipelineManager.sanitizeError({code:-999})).toEqual({code:ETIMEOUT});});it('should convert a string -999 code to ETIMEOUT',function(){expect(pipelineManager.sanitizeError({code:'-999'})).toEqual({code:ETIMEOUT});});it('should convert a numeric -1000 code to ENETUNREACH',function(){expect(pipelineManager.sanitizeError({code:-1000})).toEqual({code:ENETUNREACH});});it('should convert a string -1000 code to ENETUNREACH',function(){expect(pipelineManager.sanitizeError({code:'-1000'})).toEqual({code:ENETUNREACH});});it('should handle undefined as input',function(){expect(pipelineManager.sanitizeError()).toEqual({});});it('should handle errors without code',function(){var message='Message';expect(pipelineManager.sanitizeError({message:message})).toEqual({message:message});});it('should handle a normal error',function(){var error={code:'MY_ERROR',message:'My message'};expect(pipelineManager.sanitizeError(error)).toEqual(error);});});describe('.handleResult()',function(){beforeEach(function(){pipelineManager.constructor();request=createRequest().setResponseProcessed(PROCESS_SEQUENTIAL);pipelineManager.add(request);request.resolve=jest.fn();request.reject=jest.fn();logGroup.mockClear();});it('should work as expected for successful requests',function(){request.output={request:'output'};expect(pipelineSequence.get()[0]).toBe(request.serial);expect(pipelineManager.pipelines.get(request.name)).toBe(1);pipelineManager.handleResult(request.serial);expect(pipelineManager.pipelines.has(request.name)).toBe(false);expect(request.resolve).toHaveBeenCalledWith(request.output);expect(logGroup).toHaveBeenCalledTimes(1);expect(event.removeCallback).toHaveBeenCalledTimes(1);expect(event.removeCallback).toHaveBeenCalledWith(request.getEventCallbackName(),request.callback);expect(pipelineSequence.get()).toHaveLength(0);expect(pipelineManager.requests.size).toBe(0);});it('should work as expected for erroneous requests',function(){request.error={message:'Error',code:'ERROR'};var error=new Error(request.error.message);error.code=request.error.code;expect(pipelineSequence.get()[0]).toBe(request.serial);expect(pipelineManager.pipelines.get(request.name)).toBe(1);pipelineManager.handleResult(request.serial);expect(pipelineManager.pipelines.has(request.name)).toBe(false);expect(request.reject).toHaveBeenCalledWith(error);expect(logGroup).toHaveBeenCalledTimes(1);expect(event.removeCallback).toHaveBeenCalledTimes(1);expect(event.removeCallback).toHaveBeenCalledWith(request.getEventCallbackName(),request.callback);expect(pipelineSequence.get()).toHaveLength(0);expect(pipelineManager.requests.size).toBe(0);});});describe('.handleResultSequence()',function(){var requests;var handleResultSpy;beforeEach(function(){pipelineManager.constructor();pipelineSequence.constructor();handleResultSpy=jest.spyOn(pipelineManager,'handleResult');requests=[1,2,3,4].map(function(suffix){return createRequest("".concat(PIPELINE_NAME).concat(suffix)).setResponseProcessed(PROCESS_SEQUENTIAL);});});it('should handle a sequence as expected when all requests are finished',function(){requests.forEach(function(entry){pipelineManager.add(entry);pipelineManager.requests.get(entry.serial).finished=true;});expect(pipelineSequence.get()).toHaveLength(4);pipelineManager.handleResultSequence();expect(handleResultSpy).toHaveBeenCalledTimes(4);expect(pipelineSequence.get()).toHaveLength(0);});it('should handle a sequence as expected when requests are not finished in order',function(){requests.forEach(function(entry){pipelineManager.add(entry);});var tests=[{index:1,length:4},{index:0,length:2},{index:3,length:2},{index:2,length:0}];tests.forEach(function(_ref2){var index=_ref2.index,length=_ref2.length;// Set the finished flag at the requested index.
14
- pipelineManager.requests.get(requests[index].serial).finished=true;// Run the handler.
15
- pipelineManager.handleResultSequence();// Compare sequence length and handleResult() call count.
16
- expect(pipelineSequence.get()).toHaveLength(length);expect(handleResultSpy).toHaveBeenCalledTimes(requests.length-length);});});it('should remove abandoned serials from the sequence',function(){pipelineSequence.set('1337');pipelineSequence.set('4711');expect(pipelineSequence.get()).toHaveLength(2);pipelineManager.handleResultSequence();expect(pipelineSequence.get()).toHaveLength(0);});});describe('.handleResultLast()',function(){var requests;var handleResultSpy;var decrementSpy;beforeEach(function(){pipelineManager.constructor();handleResultSpy=jest.spyOn(pipelineManager,'handleResult');decrementSpy=jest.spyOn(pipelineManager,'decrementPipelineOngoing');requests=[1,2,3,4].map(function(){return createRequest(PIPELINE_NAME).setResponseProcessed(PROCESS_LAST);});requests.forEach(function(entry){pipelineManager.add(entry);});});it('should the last request as expected',function(){expect(pipelineManager.pipelines.get(PIPELINE_NAME)).toBe(requests.length);var serials=requests.map(function(entry){pipelineManager.handleResultLast(entry.serial);return entry.serial;});expect(decrementSpy).toHaveBeenCalledTimes(serials.length);serials.slice(0,-1).forEach(function(serial){expect(decrementSpy).toHaveBeenCalledWith(serial);});expect(handleResultSpy).toHaveBeenCalledTimes(1);expect(handleResultSpy).toHaveBeenCalledWith(serials[serials.length-1]);expect(pipelineManager.pipelines.get(PIPELINE_NAME)).toBeUndefined();});});describe('.sendRequest()',function(){beforeEach(function(){// Reset the manager to remove the request from the global beforeEach.
17
- pipelineManager.constructor();});it('should ignore invalid serial',function(){pipelineManager.sendRequest('1234');expect(logGroup).not.toHaveBeenCalled();expect(mockedDispatch).not.toHaveBeenCalled();});it('should dispatch a pipeline request to the app',function(){// Adding a new request will invoke .sendRequest(), so no explicit call is necessary.
18
- pipelineManager.add(request);var entry=pipelineManager.requests.get(request.serial);expect(entry.retries).toBe(request.retries);expect(_typeof(entry.timer)).toBe('number');expect(pipelineSequence.get().includes(request.serial)).toBeFalsy();expect(logGroup).toHaveBeenCalledTimes(1);expect(mockedDispatch).toHaveBeenCalledTimes(1);expect(mockedDispatch).toHaveBeenCalledWith({name:pipelineManager.getPipelineNameBySerial(request.serial),serial:request.serial,input:{}});});it('should dispatch a trusted pipeline request to the app',function(){request.setTrusted(true);pipelineManager.add(request);expect(logGroup).toHaveBeenCalledTimes(1);expect(mockedDispatch).toHaveBeenCalledTimes(1);expect(mockedDispatch).toHaveBeenCalledWith({name:pipelineManager.getPipelineNameBySerial(request.serial),serial:request.serial,input:{},type:'trusted'});});it('should dispatch a pipeline request and add it to the sequence',function(){request.setResponseProcessed(PROCESS_SEQUENTIAL);pipelineManager.add(request);var entry=pipelineManager.requests.get(request.serial);expect(entry.retries).toBe(request.retries);expect(_typeof(entry.timer)).toBe('number');expect(pipelineSequence.get().includes(request.serial)).toBeTruthy();expect(logGroup).toHaveBeenCalledTimes(1);expect(mockedDispatch).toHaveBeenCalledTimes(1);});});describe('.addRequestToPipelineSequence()',function(){it('should not add a request to the pipeline sequence when it is not sequential',function(){pipelineManager.addRequestToPipelineSequence(request.serial);expect(pipelineSequence.sequence).toHaveLength(0);});it('should add a request to the pipeline sequence when it is sequential',function(){request.setResponseProcessed(PROCESS_SEQUENTIAL);pipelineManager.addRequestToPipelineSequence(request.serial);expect(pipelineSequence.sequence).toHaveLength(1);expect(pipelineSequence.sequence[0]).toBe(request.serial);});});describe('.removeRequestFromPipelineSequence()',function(){it('should remove a serial from the sequence when no matching request exists',function(){var serial='1337';pipelineSequence.set(serial);expect(pipelineSequence.get()).toHaveLength(1);pipelineManager.removeRequestFromPipelineSequence(serial);expect(pipelineSequence.get()).toHaveLength(0);});it('should not remove a request from the pipeline sequence when it is not sequential',function(){pipelineSequence.set(request.serial);pipelineManager.removeRequestFromPipelineSequence(request.serial);expect(pipelineSequence.get()).toHaveLength(1);});it('should remove a request from the pipeline sequence when it is sequential',function(){request.setResponseProcessed(PROCESS_SEQUENTIAL);pipelineManager.addRequestToPipelineSequence(request.serial);expect(pipelineSequence.get()).toHaveLength(1);pipelineManager.removeRequestFromPipelineSequence(request.serial);expect(pipelineSequence.get()).toHaveLength(0);});});describe('.incrementPipelineOngoing()',function(){it('should ignore invalid serial',function(){var isOngoing=pipelineManager.incrementPipelineOngoing('1234');expect(isOngoing).toBeFalsy();});it('should increase the pipeline ongoing flag',function(){var _request=request,serial=_request.serial;expect(pipelineManager.pipelines.get(request.name)).toBe(1);pipelineManager.incrementPipelineOngoing(serial);expect(pipelineManager.pipelines.get(request.name)).toBe(2);});});describe('.decrementPipelineOngoing()',function(){it('should ignore invalid serial',function(){var isOngoing=pipelineManager.decrementPipelineOngoing('1234');expect(isOngoing).toBeFalsy();});it('should decrease the pipeline ongoing flag',function(){var _request2=request,serial=_request2.serial;pipelineManager.incrementPipelineOngoing(serial);expect(pipelineManager.pipelines.get(request.name)).toBe(2);pipelineManager.decrementPipelineOngoing(serial);expect(pipelineManager.pipelines.get(request.name)).toBe(1);pipelineManager.decrementPipelineOngoing(serial);expect(pipelineManager.pipelines.has(request.name)).toBeFalsy();});});describe('.decrementRetries()',function(){it('should return undefined serial is invalid',function(){var name=pipelineManager.decrementRetries('1234');expect(name).toBeUndefined();});it('should reduce the number of retries by 1',function(){var req=createRequest(PIPELINE_NAME).setRetries(4);pipelineManager.add(req);var serial=req.serial;var instance=pipelineManager.requests.get(serial);pipelineManager.decrementRetries(serial);expect(instance.retries).toEqual(3);});it('should not reduce the number of retries below zero',function(){var req=createRequest(PIPELINE_NAME).setRetries(0);pipelineManager.add(req);var serial=req.serial;var instance=pipelineManager.requests.get(serial);pipelineManager.decrementRetries(serial);expect(instance.retries).toEqual(0);});it('should ignore an invalid serial',function(){var req=createRequest(PIPELINE_NAME).setRetries(4);pipelineManager.add(req);var serial=req.serial;var instance=pipelineManager.requests.get(serial);pipelineManager.decrementRetries('1234');expect(instance.retries).toEqual(4);});});describe('.getPipelineNameBySerial()',function(){it('should return empty name when serial is invalid',function(){var name=pipelineManager.getPipelineNameBySerial('1234');expect(name).toEqual('');});it('should return the correct pipeline name',function(){var _request3=request,serial=_request3.serial;var name=pipelineManager.getPipelineNameBySerial(serial);expect(name).toEqual("".concat(PIPELINE_NAME,".v").concat(request.version));});it('should return a pieplie name witout version suffix',function(){var _request4=request,serial=_request4.serial;var name=pipelineManager.getPipelineNameBySerial(serial,false);expect(name).toEqual(PIPELINE_NAME);});});describe('.getRetriesPrefix()',function(){it('should return an empty string when the request was not retried yet',function(){var result=pipelineManager.getRetriesPrefix(request.serial);expect(_typeof(result)).toBe('string');expect(result).toBe('');});it('should return a string when retires already happened',function(){var entry=pipelineManager.requests.get(request.serial);entry.retries=1;var result=pipelineManager.getRetriesPrefix(request.serial);expect(_typeof(result)).toBe('string');expect(result.length>0).toBeTruthy();});});});/* eslint-enable extra-rules/no-single-line-objects */
31
+ */
32
+ const createRequest = (pipelineName = PIPELINE_NAME) => new PipelineRequest(pipelineName);
33
+
34
+ /**
35
+ * Resets the pipeline sequence instance
36
+ */
37
+ const resetPipelineSequence = () => {
38
+ pipelineSequence.sequence = [];
39
+ };
40
+
41
+ /**
42
+ * Resets the pipeline dependencies instance
43
+ */
44
+ const resetPipelineDependencies = () => {
45
+ pipelineDependencies.dependencies = {};
46
+ };
47
+
48
+ /**
49
+ * Resets the pipeline manager instance
50
+ */
51
+ const resetPipelineManager = () => {
52
+ pipelineManager.requests.clear();
53
+ pipelineManager.pipelines.clear();
54
+ pipelineManager.suppressedErrors = [];
55
+ };
56
+ describe('PipelineManager', () => {
57
+ let request;
58
+ beforeEach(() => {
59
+ // Reset modules.
60
+ resetPipelineSequence();
61
+ resetPipelineDependencies();
62
+ resetPipelineManager();
63
+
64
+ // Generate a request and add it to the manager. It can be used for most of the tests.
65
+ request = createRequest();
66
+ pipelineManager.add(request);
67
+ pipelineDependencies.set(PIPELINE_DEPENDANT, [PIPELINE_DEPENDENCY]);
68
+ jest.clearAllMocks();
69
+ });
70
+ afterEach(() => {
71
+ const entry = pipelineManager.requests.get(request.serial);
72
+ if (entry) {
73
+ clearTimeout(entry.timer);
74
+ }
75
+ });
76
+ describe('.constructor()', () => {
77
+ it('should work as expected', () => {
78
+ resetPipelineManager();
79
+ expect(pipelineManager.requests.size).toBe(0);
80
+ expect(pipelineManager.pipelines.size).toBe(0);
81
+ expect(pipelineManager.suppressedErrors).toHaveLength(0);
82
+ });
83
+ });
84
+ describe('.addSuppressedErrors()', () => {
85
+ it('should store an error code to suppress', () => {
86
+ const error = 1;
87
+ pipelineManager.addSuppressedErrors(error);
88
+ expect(pipelineManager.suppressedErrors).toHaveLength(1);
89
+ expect(pipelineManager.suppressedErrors[0]).toBe(error);
90
+ });
91
+ it('should store multiple error codes to suppress', () => {
92
+ const errors = [1, 2];
93
+ pipelineManager.addSuppressedErrors(errors);
94
+ expect(pipelineManager.suppressedErrors).toHaveLength(2);
95
+ expect(pipelineManager.suppressedErrors).toEqual(errors);
96
+ });
97
+ it('should extend the error list with every call', () => {
98
+ const entryOne = [1, 2];
99
+ const entryTwo = 3;
100
+ pipelineManager.addSuppressedErrors(entryOne);
101
+ pipelineManager.addSuppressedErrors(entryTwo);
102
+ expect(pipelineManager.suppressedErrors).toHaveLength(3);
103
+ expect(pipelineManager.suppressedErrors).toEqual([1, 2, 3]);
104
+ });
105
+ });
106
+ describe('.add()', () => {
107
+ it('should add a request to the queue', () => {
108
+ expect(pipelineManager.requests.size).toEqual(1);
109
+ expect(pipelineManager.requests.get(request.serial).request).toBe(request);
110
+ });
111
+ it('should add multiple requests to the queue', () => {
112
+ const dispatchSpy = jest.spyOn(pipelineManager, 'dispatch');
113
+ const requestOne = request;
114
+ const requestTwo = createRequest(`${PIPELINE_NAME}1`);
115
+ pipelineManager.add(requestOne);
116
+ pipelineManager.add(requestTwo);
117
+ expect(pipelineManager.requests.size).toEqual(2);
118
+ expect(pipelineManager.requests.get(requestOne.serial).request).toBe(requestOne);
119
+ expect(pipelineManager.requests.get(requestTwo.serial).request).toBe(requestTwo);
120
+ expect(dispatchSpy).toHaveBeenCalledTimes(2);
121
+ expect(dispatchSpy).toHaveBeenCalledWith(requestOne.serial);
122
+ expect(dispatchSpy).toHaveBeenCalledWith(requestTwo.serial);
123
+ });
124
+ });
125
+ describe('.dispatch()', () => {
126
+ it('should send a request', () => {
127
+ const createRequestCallbackSpy = jest.spyOn(pipelineManager, 'createRequestCallback');
128
+ const sendRequestSpy = jest.spyOn(pipelineManager, 'sendRequest');
129
+ resetPipelineManager();
130
+ const result = pipelineManager.add(request);
131
+ expect(result).toBeInstanceOf(Promise);
132
+ expect(createRequestCallbackSpy).toHaveBeenCalledTimes(1);
133
+ expect(createRequestCallbackSpy).toHaveBeenCalledWith(request.serial, expect.any(Function), expect.any(Function));
134
+ expect(sendRequestSpy).toHaveBeenCalledTimes(1);
135
+ expect(sendRequestSpy).toHaveBeenCalledWith(request.serial);
136
+ });
137
+ it('should not send the requests when it has running dependencies', () => {
138
+ const sendRequestSpy = jest.spyOn(pipelineManager, 'sendRequest');
139
+ const dependant = createRequest(PIPELINE_DEPENDANT);
140
+ const dependency = createRequest(PIPELINE_DEPENDENCY);
141
+ pipelineManager.add(dependency);
142
+ pipelineManager.add(dependant);
143
+ expect(sendRequestSpy).toHaveBeenCalledTimes(1);
144
+ expect(sendRequestSpy).toHaveBeenCalledWith(dependency.serial);
145
+ });
146
+ it('should resolve when a pipeline response comes in', () => {
147
+ const response = {
148
+ succcess: true
149
+ };
150
+ resetPipelineManager();
151
+ const handler = pipelineManager.add(request);
152
+ expect(request.callback).toBeInstanceOf(Function);
153
+ // Simulate a pipeline response event.
154
+ request.callback(null, request.serial, response);
155
+ expect(handler).resolves.toEqual(response);
156
+ });
157
+ it('should reject when a pipeline error comes in', () => {
158
+ const error = {
159
+ message: 'Message',
160
+ code: 'CODE'
161
+ };
162
+ const expected = new Error(error.message);
163
+ expected.code = error.code;
164
+ resetPipelineManager();
165
+ const handler = pipelineManager.add(request);
166
+ expect(request.callback).toBeInstanceOf(Function);
167
+ // Simulate a pipeline response event.
168
+ request.callback(error, request.serial);
169
+ expect(handler).rejects.toEqual(expected);
170
+ });
171
+ });
172
+ describe('.createRequestCallback()', () => {
173
+ const error = {
174
+ message: 'Something went wrong',
175
+ code: 'ERROR'
176
+ };
177
+ const output = {
178
+ some: 'output'
179
+ };
180
+ let mockResolve;
181
+ let mockReject;
182
+ beforeEach(() => {
183
+ mockResolve = jest.fn();
184
+ mockReject = jest.fn();
185
+ });
186
+ it('should create a callback like expected', () => {
187
+ pipelineManager.createRequestCallback(request.serial, mockResolve, mockReject);
188
+ expect(request.resolve).toBe(mockResolve);
189
+ expect(request.reject).toBe(mockReject);
190
+ expect(request.callback).toBeInstanceOf(Function);
191
+ expect(event.addCallback).toHaveBeenCalledTimes(1);
192
+ expect(event.addCallback).toHaveBeenCalledWith(request.getEventCallbackName(), request.callback);
193
+ });
194
+ describe('should create a callback that invokes handleResults() for default process types', () => {
195
+ it('should handle the output', () => {
196
+ const handleResultSpy = jest.spyOn(pipelineManager, 'handleResult');
197
+ request.setResponseProcessed(PROCESS_ALWAYS);
198
+ pipelineManager.createRequestCallback(request.serial, mockResolve, mockReject);
199
+ request.callback(null, request.serial, output);
200
+ expect(handleResultSpy).toHaveBeenCalledTimes(1);
201
+ expect(handleResultSpy).toHaveBeenCalledWith(request.serial);
202
+ expect(request.error).toEqual(null);
203
+ expect(request.output).toEqual(output);
204
+ });
205
+ it('should handle the error', () => {
206
+ const handleResultSpy = jest.spyOn(pipelineManager, 'handleResult');
207
+ request.setResponseProcessed(PROCESS_ALWAYS);
208
+ pipelineManager.createRequestCallback(request.serial, mockResolve, mockReject);
209
+ pipelineManager.createRequestCallback(request.serial, mockResolve, mockReject);
210
+ request.callback(error, request.serial, {});
211
+ expect(handleResultSpy).toHaveBeenCalledTimes(1);
212
+ expect(handleResultSpy).toHaveBeenCalledWith(request.serial);
213
+ expect(request.error).toEqual(error);
214
+ expect(request.output).toEqual({});
215
+ });
216
+ });
217
+ describe('should create a callback that invokes handleResults() for sequential process types', () => {
218
+ it('should handle the output', () => {
219
+ const handleResultSequenceSpy = jest.spyOn(pipelineManager, 'handleResultSequence');
220
+ request.setResponseProcessed(PROCESS_SEQUENTIAL);
221
+ pipelineManager.createRequestCallback(request.serial, mockResolve, mockReject);
222
+ request.callback(null, request.serial, output);
223
+ expect(handleResultSequenceSpy).toHaveBeenCalledTimes(1);
224
+ expect(request.error).toEqual(null);
225
+ expect(request.output).toEqual(output);
226
+ });
227
+ it('should handle the error', () => {
228
+ const handleResultSequenceSpy = jest.spyOn(pipelineManager, 'handleResultSequence');
229
+ request.setResponseProcessed(PROCESS_SEQUENTIAL);
230
+ pipelineManager.createRequestCallback(request.serial, mockResolve, mockReject);
231
+ pipelineManager.createRequestCallback(request.serial, mockResolve, mockReject);
232
+ request.callback(error, request.serial, {});
233
+ expect(handleResultSequenceSpy).toHaveBeenCalledTimes(1);
234
+ expect(request.error).toEqual(error);
235
+ expect(request.output).toEqual({});
236
+ });
237
+ });
238
+ describe('should create a callback that invokes handleResults() for process last types', () => {
239
+ it('should handle the output', () => {
240
+ const handleResultLastSpy = jest.spyOn(pipelineManager, 'handleResultLast');
241
+ request.setResponseProcessed(PROCESS_LAST);
242
+ pipelineManager.createRequestCallback(request.serial, mockResolve, mockReject);
243
+ request.callback(null, request.serial, output);
244
+ expect(handleResultLastSpy).toHaveBeenCalledTimes(1);
245
+ expect(request.error).toEqual(null);
246
+ expect(request.output).toEqual(output);
247
+ });
248
+ it('should handle the error', () => {
249
+ const handleResultLastSpy = jest.spyOn(pipelineManager, 'handleResultLast');
250
+ request.setResponseProcessed(PROCESS_LAST);
251
+ pipelineManager.createRequestCallback(request.serial, mockResolve, mockReject);
252
+ pipelineManager.createRequestCallback(request.serial, mockResolve, mockReject);
253
+ request.callback(error, request.serial, {});
254
+ expect(handleResultLastSpy).toHaveBeenCalledTimes(1);
255
+ expect(request.error).toEqual(error);
256
+ expect(request.output).toEqual({});
257
+ });
258
+ });
259
+ });
260
+ describe('.hasRunningDependencies()', () => {
261
+ it('should return true if dependencies are running', () => {
262
+ const dependant = createRequest(PIPELINE_DEPENDANT);
263
+ const dependency = createRequest(PIPELINE_DEPENDENCY);
264
+ pipelineManager.add(dependant);
265
+ pipelineManager.add(dependency);
266
+ expect(pipelineManager.hasRunningDependencies(dependant.name)).toBe(true);
267
+ });
268
+ it('should return false if no dependencies are running', () => {
269
+ const dependency = createRequest(PIPELINE_DEPENDENCY);
270
+ pipelineManager.add(dependency);
271
+ expect(pipelineManager.hasRunningDependencies(dependency.name)).toBe(false);
272
+ });
273
+ });
274
+ describe('.handleDeferredRequests', () => {
275
+ it('should send deferred requests when their dependencies are finished', () => {
276
+ const sendRequestSpy = jest.spyOn(pipelineManager, 'sendRequest');
277
+ const dependant = createRequest(PIPELINE_DEPENDANT);
278
+ const dependencyOne = createRequest(PIPELINE_DEPENDENCY);
279
+ const dependencyTwo = createRequest(PIPELINE_DEPENDENCY);
280
+ pipelineManager.add(dependencyOne);
281
+ pipelineManager.add(dependencyTwo);
282
+ pipelineManager.add(dependant);
283
+ const entryOne = pipelineManager.requests.get(dependencyOne.serial);
284
+ const entryTwo = pipelineManager.requests.get(dependencyTwo.serial);
285
+
286
+ // Two times called for the depencencies.
287
+ expect(sendRequestSpy).toHaveBeenCalledTimes(2);
288
+ expect(sendRequestSpy).toHaveBeenCalledWith(entryOne.request.serial);
289
+ expect(sendRequestSpy).toHaveBeenCalledWith(entryTwo.request.serial);
290
+ pipelineManager.handleDeferredRequests();
291
+ // Call count didn't change, since dependencies are still running.
292
+ expect(sendRequestSpy).toHaveBeenCalledTimes(2);
293
+ entryOne.request.callback(null, entryOne.request.serial);
294
+ pipelineManager.handleDeferredRequests();
295
+ // Call count didn't change, since one dependency is still running.
296
+ expect(sendRequestSpy).toHaveBeenCalledTimes(2);
297
+ entryTwo.request.callback(null, entryTwo.request.serial);
298
+ pipelineManager.handleDeferredRequests();
299
+ expect(sendRequestSpy).toHaveBeenCalledTimes(3);
300
+ expect(sendRequestSpy).toHaveBeenCalledWith(dependant.serial);
301
+ });
302
+ });
303
+ describe('.handleTimeout()', () => {
304
+ jest.useFakeTimers();
305
+ it('should handle timeouts like expected', done => {
306
+ resetPipelineManager();
307
+ request.setRetries(1);
308
+ const promise = pipelineManager.add(request);
309
+ const entry = pipelineManager.requests.get(request.serial);
310
+ expect(entry.retries).toBe(1);
311
+ jest.runAllTimers();
312
+ expect(entry.retries).toBe(0);
313
+ jest.runAllTimers();
314
+ promise.catch(({
315
+ message,
316
+ code
317
+ }) => {
318
+ expect(message.includes('timed out')).toBeTruthy();
319
+ expect(code).toBe(ETIMEOUT);
320
+ done();
321
+ });
322
+ });
323
+ });
324
+ describe('.handleError()', () => {
325
+ it('should ignore when error code should be suppressed', () => {
326
+ pipelineManager.addSuppressedErrors('MY_ERROR');
327
+ request.reject = jest.fn();
328
+ request.error = {
329
+ code: 'MY_ERROR'
330
+ };
331
+ pipelineManager.handleError(request.serial);
332
+ expect(request.reject).toHaveBeenCalledTimes(1);
333
+ expect(errorManager.queue).toHaveBeenCalledTimes(0);
334
+ });
335
+ it('should ignore when the original error code was sanitized to an error code that should be suppressed', () => {
336
+ pipelineManager.addSuppressedErrors(ENETUNREACH);
337
+ request.reject = jest.fn();
338
+ request.error = {
339
+ code: '-1000'
340
+ };
341
+ pipelineManager.handleError(request.serial);
342
+ expect(request.reject).toHaveBeenCalledTimes(1);
343
+ expect(errorManager.queue).toHaveBeenCalledTimes(0);
344
+ });
345
+ it('should ignore when pipeline is set to ignore specific error code', () => {
346
+ const req = createRequest(PIPELINE_NAME).setErrorBlacklist(['MY_ERROR']);
347
+ pipelineManager.add(req);
348
+ req.reject = jest.fn();
349
+ req.error = {
350
+ code: 'MY_ERROR'
351
+ };
352
+ pipelineManager.handleError(req.serial);
353
+ expect(req.reject).toHaveBeenCalledTimes(1);
354
+ expect(errorManager.queue).toHaveBeenCalledTimes(0);
355
+ });
356
+ it('should not queue an error when all errors are suppressed', () => {
357
+ const req = createRequest(PIPELINE_NAME).setHandleErrors(ERROR_HANDLE_SUPPRESS);
358
+ pipelineManager.add(req);
359
+ req.reject = jest.fn();
360
+ req.error = {
361
+ code: 'MY_ERROR'
362
+ };
363
+ pipelineManager.handleError(req.serial);
364
+ expect(req.reject).toHaveBeenCalledTimes(1);
365
+ expect(errorManager.queue).toHaveBeenCalledTimes(0);
366
+ });
367
+ it('should call the appropriate reject()', () => {
368
+ request.reject = jest.fn();
369
+ request.error = {
370
+ code: 'MY_ERROR'
371
+ };
372
+ pipelineManager.handleError(request.serial);
373
+ expect(request.reject).toHaveBeenCalledTimes(1);
374
+ expect(errorManager.queue).toHaveBeenCalledTimes(1);
375
+ });
376
+ });
377
+ describe('.sanitizeError()', () => {
378
+ it('should convert a numeric -999 code to ETIMEOUT', () => {
379
+ expect(pipelineManager.sanitizeError({
380
+ code: -999
381
+ })).toEqual({
382
+ code: ETIMEOUT
383
+ });
384
+ });
385
+ it('should convert a string -999 code to ETIMEOUT', () => {
386
+ expect(pipelineManager.sanitizeError({
387
+ code: '-999'
388
+ })).toEqual({
389
+ code: ETIMEOUT
390
+ });
391
+ });
392
+ it('should convert a numeric -1000 code to ENETUNREACH', () => {
393
+ expect(pipelineManager.sanitizeError({
394
+ code: -1000
395
+ })).toEqual({
396
+ code: ENETUNREACH
397
+ });
398
+ });
399
+ it('should convert a string -1000 code to ENETUNREACH', () => {
400
+ expect(pipelineManager.sanitizeError({
401
+ code: '-1000'
402
+ })).toEqual({
403
+ code: ENETUNREACH
404
+ });
405
+ });
406
+ it('should handle undefined as input', () => {
407
+ expect(pipelineManager.sanitizeError()).toEqual({});
408
+ });
409
+ it('should handle errors without code', () => {
410
+ const message = 'Message';
411
+ expect(pipelineManager.sanitizeError({
412
+ message
413
+ })).toEqual({
414
+ message
415
+ });
416
+ });
417
+ it('should handle a normal error', () => {
418
+ const error = {
419
+ code: 'MY_ERROR',
420
+ message: 'My message'
421
+ };
422
+ expect(pipelineManager.sanitizeError(error)).toEqual(error);
423
+ });
424
+ });
425
+ describe('.handleResult()', () => {
426
+ beforeEach(() => {
427
+ resetPipelineManager();
428
+ request = createRequest().setResponseProcessed(PROCESS_SEQUENTIAL);
429
+ pipelineManager.add(request);
430
+ request.resolve = jest.fn();
431
+ request.reject = jest.fn();
432
+ logGroup.mockClear();
433
+ });
434
+ it('should work as expected for successful requests', () => {
435
+ request.output = {
436
+ request: 'output'
437
+ };
438
+ expect(pipelineSequence.get()[0]).toBe(request.serial);
439
+ expect(pipelineManager.pipelines.get(request.name)).toBe(1);
440
+ pipelineManager.handleResult(request.serial);
441
+ expect(pipelineManager.pipelines.has(request.name)).toBe(false);
442
+ expect(request.resolve).toHaveBeenCalledWith(request.output);
443
+ expect(logGroup).toHaveBeenCalledTimes(1);
444
+ expect(event.removeCallback).toHaveBeenCalledTimes(1);
445
+ expect(event.removeCallback).toHaveBeenCalledWith(request.getEventCallbackName(), request.callback);
446
+ expect(pipelineSequence.get()).toHaveLength(0);
447
+ expect(pipelineManager.requests.size).toBe(0);
448
+ });
449
+ it('should work as expected for erroneous requests', () => {
450
+ request.error = {
451
+ message: 'Error',
452
+ code: 'ERROR'
453
+ };
454
+ const error = new Error(request.error.message);
455
+ error.code = request.error.code;
456
+ expect(pipelineSequence.get()[0]).toBe(request.serial);
457
+ expect(pipelineManager.pipelines.get(request.name)).toBe(1);
458
+ pipelineManager.handleResult(request.serial);
459
+ expect(pipelineManager.pipelines.has(request.name)).toBe(false);
460
+ expect(request.reject).toHaveBeenCalledWith(error);
461
+ expect(logGroup).toHaveBeenCalledTimes(1);
462
+ expect(event.removeCallback).toHaveBeenCalledTimes(1);
463
+ expect(event.removeCallback).toHaveBeenCalledWith(request.getEventCallbackName(), request.callback);
464
+ expect(pipelineSequence.get()).toHaveLength(0);
465
+ expect(pipelineManager.requests.size).toBe(0);
466
+ });
467
+ });
468
+ describe('.handleResultSequence()', () => {
469
+ let requests;
470
+ let handleResultSpy;
471
+ beforeEach(() => {
472
+ resetPipelineManager();
473
+ resetPipelineSequence();
474
+ handleResultSpy = jest.spyOn(pipelineManager, 'handleResult');
475
+ requests = [1, 2, 3, 4].map(suffix => createRequest(`${PIPELINE_NAME}${suffix}`).setResponseProcessed(PROCESS_SEQUENTIAL));
476
+ });
477
+ it('should handle a sequence as expected when all requests are finished', () => {
478
+ requests.forEach(entry => {
479
+ pipelineManager.add(entry);
480
+ pipelineManager.requests.get(entry.serial).finished = true;
481
+ });
482
+ expect(pipelineSequence.get()).toHaveLength(4);
483
+ pipelineManager.handleResultSequence();
484
+ expect(handleResultSpy).toHaveBeenCalledTimes(4);
485
+ expect(pipelineSequence.get()).toHaveLength(0);
486
+ });
487
+ it('should handle a sequence as expected when requests are not finished in order', () => {
488
+ requests.forEach(entry => {
489
+ pipelineManager.add(entry);
490
+ });
491
+ const tests = [{
492
+ index: 1,
493
+ length: 4
494
+ }, {
495
+ index: 0,
496
+ length: 2
497
+ }, {
498
+ index: 3,
499
+ length: 2
500
+ }, {
501
+ index: 2,
502
+ length: 0
503
+ }];
504
+ tests.forEach(({
505
+ index,
506
+ length
507
+ }) => {
508
+ // Set the finished flag at the requested index.
509
+ pipelineManager.requests.get(requests[index].serial).finished = true;
510
+ // Run the handler.
511
+ pipelineManager.handleResultSequence();
512
+ // Compare sequence length and handleResult() call count.
513
+ expect(pipelineSequence.get()).toHaveLength(length);
514
+ expect(handleResultSpy).toHaveBeenCalledTimes(requests.length - length);
515
+ });
516
+ });
517
+ it('should remove abandoned serials from the sequence', () => {
518
+ pipelineSequence.set('1337');
519
+ pipelineSequence.set('4711');
520
+ expect(pipelineSequence.get()).toHaveLength(2);
521
+ pipelineManager.handleResultSequence();
522
+ expect(pipelineSequence.get()).toHaveLength(0);
523
+ });
524
+ });
525
+ describe('.handleResultLast()', () => {
526
+ let requests;
527
+ let handleResultSpy;
528
+ let decrementSpy;
529
+ beforeEach(() => {
530
+ resetPipelineManager();
531
+ handleResultSpy = jest.spyOn(pipelineManager, 'handleResult');
532
+ decrementSpy = jest.spyOn(pipelineManager, 'decrementPipelineOngoing');
533
+ requests = [1, 2, 3, 4].map(() => createRequest(PIPELINE_NAME).setResponseProcessed(PROCESS_LAST));
534
+ requests.forEach(entry => {
535
+ pipelineManager.add(entry);
536
+ });
537
+ });
538
+ it('should the last request as expected', () => {
539
+ expect(pipelineManager.pipelines.get(PIPELINE_NAME)).toBe(requests.length);
540
+ const serials = requests.map(entry => {
541
+ pipelineManager.handleResultLast(entry.serial);
542
+ return entry.serial;
543
+ });
544
+ expect(decrementSpy).toHaveBeenCalledTimes(serials.length);
545
+ serials.slice(0, -1).forEach(serial => {
546
+ expect(decrementSpy).toHaveBeenCalledWith(serial);
547
+ });
548
+ expect(handleResultSpy).toHaveBeenCalledTimes(1);
549
+ expect(handleResultSpy).toHaveBeenCalledWith(serials[serials.length - 1]);
550
+ expect(pipelineManager.pipelines.get(PIPELINE_NAME)).toBeUndefined();
551
+ });
552
+ });
553
+ describe('.sendRequest()', () => {
554
+ beforeEach(() => {
555
+ // Reset the manager to remove the request from the global beforeEach.
556
+ resetPipelineManager();
557
+ });
558
+ it('should ignore invalid serial', () => {
559
+ pipelineManager.sendRequest('1234');
560
+ expect(logGroup).not.toHaveBeenCalled();
561
+ expect(mockedDispatch).not.toHaveBeenCalled();
562
+ });
563
+ it('should dispatch a pipeline request to the app', () => {
564
+ // Adding a new request will invoke .sendRequest(), so no explicit call is necessary.
565
+ pipelineManager.add(request);
566
+ const entry = pipelineManager.requests.get(request.serial);
567
+ expect(entry.retries).toBe(request.retries);
568
+ expect(typeof entry.timer).toBe('number');
569
+ expect(pipelineSequence.get().includes(request.serial)).toBeFalsy();
570
+ expect(logGroup).toHaveBeenCalledTimes(1);
571
+ expect(mockedDispatch).toHaveBeenCalledTimes(1);
572
+ expect(mockedDispatch).toHaveBeenCalledWith({
573
+ name: pipelineManager.getPipelineNameBySerial(request.serial),
574
+ serial: request.serial,
575
+ input: {}
576
+ });
577
+ });
578
+ it('should dispatch a trusted pipeline request to the app', () => {
579
+ request.setTrusted(true);
580
+ pipelineManager.add(request);
581
+ expect(logGroup).toHaveBeenCalledTimes(1);
582
+ expect(mockedDispatch).toHaveBeenCalledTimes(1);
583
+ expect(mockedDispatch).toHaveBeenCalledWith({
584
+ name: pipelineManager.getPipelineNameBySerial(request.serial),
585
+ serial: request.serial,
586
+ input: {},
587
+ type: 'trusted'
588
+ });
589
+ });
590
+ it('should dispatch a pipeline request and add it to the sequence', () => {
591
+ request.setResponseProcessed(PROCESS_SEQUENTIAL);
592
+ pipelineManager.add(request);
593
+ const entry = pipelineManager.requests.get(request.serial);
594
+ expect(entry.retries).toBe(request.retries);
595
+ expect(typeof entry.timer).toBe('number');
596
+ expect(pipelineSequence.get().includes(request.serial)).toBeTruthy();
597
+ expect(logGroup).toHaveBeenCalledTimes(1);
598
+ expect(mockedDispatch).toHaveBeenCalledTimes(1);
599
+ });
600
+ });
601
+ describe('.addRequestToPipelineSequence()', () => {
602
+ it('should not add a request to the pipeline sequence when it is not sequential', () => {
603
+ pipelineManager.addRequestToPipelineSequence(request.serial);
604
+ expect(pipelineSequence.sequence).toHaveLength(0);
605
+ });
606
+ it('should add a request to the pipeline sequence when it is sequential', () => {
607
+ request.setResponseProcessed(PROCESS_SEQUENTIAL);
608
+ pipelineManager.addRequestToPipelineSequence(request.serial);
609
+ expect(pipelineSequence.sequence).toHaveLength(1);
610
+ expect(pipelineSequence.sequence[0]).toBe(request.serial);
611
+ });
612
+ });
613
+ describe('.removeRequestFromPipelineSequence()', () => {
614
+ it('should remove a serial from the sequence when no matching request exists', () => {
615
+ const serial = '1337';
616
+ pipelineSequence.set(serial);
617
+ expect(pipelineSequence.get()).toHaveLength(1);
618
+ pipelineManager.removeRequestFromPipelineSequence(serial);
619
+ expect(pipelineSequence.get()).toHaveLength(0);
620
+ });
621
+ it('should not remove a request from the pipeline sequence when it is not sequential', () => {
622
+ pipelineSequence.set(request.serial);
623
+ pipelineManager.removeRequestFromPipelineSequence(request.serial);
624
+ expect(pipelineSequence.get()).toHaveLength(1);
625
+ });
626
+ it('should remove a request from the pipeline sequence when it is sequential', () => {
627
+ request.setResponseProcessed(PROCESS_SEQUENTIAL);
628
+ pipelineManager.addRequestToPipelineSequence(request.serial);
629
+ expect(pipelineSequence.get()).toHaveLength(1);
630
+ pipelineManager.removeRequestFromPipelineSequence(request.serial);
631
+ expect(pipelineSequence.get()).toHaveLength(0);
632
+ });
633
+ });
634
+ describe('.incrementPipelineOngoing()', () => {
635
+ it('should ignore invalid serial', () => {
636
+ const isOngoing = pipelineManager.incrementPipelineOngoing('1234');
637
+ expect(isOngoing).toBeFalsy();
638
+ });
639
+ it('should increase the pipeline ongoing flag', () => {
640
+ const {
641
+ serial
642
+ } = request;
643
+ expect(pipelineManager.pipelines.get(request.name)).toBe(1);
644
+ pipelineManager.incrementPipelineOngoing(serial);
645
+ expect(pipelineManager.pipelines.get(request.name)).toBe(2);
646
+ });
647
+ });
648
+ describe('.decrementPipelineOngoing()', () => {
649
+ it('should ignore invalid serial', () => {
650
+ const isOngoing = pipelineManager.decrementPipelineOngoing('1234');
651
+ expect(isOngoing).toBeFalsy();
652
+ });
653
+ it('should decrease the pipeline ongoing flag', () => {
654
+ const {
655
+ serial
656
+ } = request;
657
+ pipelineManager.incrementPipelineOngoing(serial);
658
+ expect(pipelineManager.pipelines.get(request.name)).toBe(2);
659
+ pipelineManager.decrementPipelineOngoing(serial);
660
+ expect(pipelineManager.pipelines.get(request.name)).toBe(1);
661
+ pipelineManager.decrementPipelineOngoing(serial);
662
+ expect(pipelineManager.pipelines.has(request.name)).toBeFalsy();
663
+ });
664
+ });
665
+ describe('.decrementRetries()', () => {
666
+ it('should return undefined serial is invalid', () => {
667
+ const name = pipelineManager.decrementRetries('1234');
668
+ expect(name).toBeUndefined();
669
+ });
670
+ it('should reduce the number of retries by 1', () => {
671
+ const req = createRequest(PIPELINE_NAME).setRetries(4);
672
+ pipelineManager.add(req);
673
+ const {
674
+ serial
675
+ } = req;
676
+ const instance = pipelineManager.requests.get(serial);
677
+ pipelineManager.decrementRetries(serial);
678
+ expect(instance.retries).toEqual(3);
679
+ });
680
+ it('should not reduce the number of retries below zero', () => {
681
+ const req = createRequest(PIPELINE_NAME).setRetries(0);
682
+ pipelineManager.add(req);
683
+ const {
684
+ serial
685
+ } = req;
686
+ const instance = pipelineManager.requests.get(serial);
687
+ pipelineManager.decrementRetries(serial);
688
+ expect(instance.retries).toEqual(0);
689
+ });
690
+ it('should ignore an invalid serial', () => {
691
+ const req = createRequest(PIPELINE_NAME).setRetries(4);
692
+ pipelineManager.add(req);
693
+ const {
694
+ serial
695
+ } = req;
696
+ const instance = pipelineManager.requests.get(serial);
697
+ pipelineManager.decrementRetries('1234');
698
+ expect(instance.retries).toEqual(4);
699
+ });
700
+ });
701
+ describe('.getPipelineNameBySerial()', () => {
702
+ it('should return empty name when serial is invalid', () => {
703
+ const name = pipelineManager.getPipelineNameBySerial('1234');
704
+ expect(name).toEqual('');
705
+ });
706
+ it('should return the correct pipeline name', () => {
707
+ const {
708
+ serial
709
+ } = request;
710
+ const name = pipelineManager.getPipelineNameBySerial(serial);
711
+ expect(name).toEqual(`${PIPELINE_NAME}.v${request.version}`);
712
+ });
713
+ it('should return a pieplie name witout version suffix', () => {
714
+ const {
715
+ serial
716
+ } = request;
717
+ const name = pipelineManager.getPipelineNameBySerial(serial, false);
718
+ expect(name).toEqual(PIPELINE_NAME);
719
+ });
720
+ });
721
+ describe('.getRetriesPrefix()', () => {
722
+ it('should return an empty string when the request was not retried yet', () => {
723
+ const result = pipelineManager.getRetriesPrefix(request.serial);
724
+ expect(typeof result).toBe('string');
725
+ expect(result).toBe('');
726
+ });
727
+ it('should return a string when retires already happened', () => {
728
+ const entry = pipelineManager.requests.get(request.serial);
729
+ entry.retries = 1;
730
+ const result = pipelineManager.getRetriesPrefix(request.serial);
731
+ expect(typeof result).toBe('string');
732
+ expect(result.length > 0).toBeTruthy();
733
+ });
734
+ });
735
+ });
736
+ /* eslint-enable extra-rules/no-single-line-objects */