UNPKG

orator

Version:

Unopinionated API http server abstraction - REST or IPC

950 lines (880 loc) 28.9 kB
/** * Unit tests for Orator complex routes and static file serving * * @license MIT * * @author Steven Velozo <steven@velozo.com> */ const libOrator = require('../source/Orator.js'); const Chai = require("chai"); const Expect = Chai.expect; const Assert = Chai.assert; const libFable = require('fable'); const libPath = require('path'); const defaultFableSettings = ( { Product:'Orator-ComplexRouteTests', ProductVersion: '0.0.0', APIServerPort: 0 }); suite ( 'Orator', () => { suite ( 'Multiple HTTP Verbs', () => { test ( 'ipc should be able to handle POST routes', (fDone) => { let tmpFable = new libFable(defaultFableSettings); tmpFable.serviceManager.addServiceType('Orator', libOrator); let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {}); tmpOrator.startService(); tmpOrator.serviceServer.post ( '/api/item', (pRequest, pResponse, fNext) => { pResponse.send({Created: true, Method: 'POST'}); return fNext(); } ); tmpOrator.invoke('POST', '/api/item', {Name: 'TestItem'}, (pError, pResponseData) => { let tmpResponseObject = JSON.parse(pResponseData); Expect(tmpResponseObject).to.have.a.property('Created'); Expect(tmpResponseObject.Created).to.equal(true); Expect(tmpResponseObject.Method).to.equal('POST'); tmpOrator.log.info(`POST /api/item responded with [${pResponseData}]`); return fDone(); }); } ); test ( 'ipc should be able to handle PUT routes', (fDone) => { let tmpFable = new libFable(defaultFableSettings); tmpFable.serviceManager.addServiceType('Orator', libOrator); let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {}); tmpOrator.startService(); tmpOrator.serviceServer.put ( '/api/item/:id', (pRequest, pResponse, fNext) => { pResponse.send({Updated: true, ID: pRequest.params.id, Method: 'PUT'}); return fNext(); } ); tmpOrator.invoke('PUT', '/api/item/42', {Name: 'UpdatedItem'}, (pError, pResponseData) => { let tmpResponseObject = JSON.parse(pResponseData); Expect(tmpResponseObject).to.have.a.property('Updated'); Expect(tmpResponseObject.Updated).to.equal(true); Expect(tmpResponseObject.ID).to.equal('42'); Expect(tmpResponseObject.Method).to.equal('PUT'); tmpOrator.log.info(`PUT /api/item/42 responded with [${pResponseData}]`); return fDone(); }); } ); test ( 'ipc should be able to handle DELETE routes', (fDone) => { let tmpFable = new libFable(defaultFableSettings); tmpFable.serviceManager.addServiceType('Orator', libOrator); let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {}); tmpOrator.startService(); tmpOrator.serviceServer.del ( '/api/item/:id', (pRequest, pResponse, fNext) => { pResponse.send({Deleted: true, ID: pRequest.params.id, Method: 'DELETE'}); return fNext(); } ); tmpOrator.invoke('DELETE', '/api/item/99', null, (pError, pResponseData) => { let tmpResponseObject = JSON.parse(pResponseData); Expect(tmpResponseObject).to.have.a.property('Deleted'); Expect(tmpResponseObject.Deleted).to.equal(true); Expect(tmpResponseObject.ID).to.equal('99'); Expect(tmpResponseObject.Method).to.equal('DELETE'); tmpOrator.log.info(`DELETE /api/item/99 responded with [${pResponseData}]`); return fDone(); }); } ); test ( 'ipc should be able to handle PATCH routes', (fDone) => { let tmpFable = new libFable(defaultFableSettings); tmpFable.serviceManager.addServiceType('Orator', libOrator); let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {}); tmpOrator.startService(); tmpOrator.serviceServer.patch ( '/api/item/:id', (pRequest, pResponse, fNext) => { pResponse.send({Patched: true, ID: pRequest.params.id, Method: 'PATCH'}); return fNext(); } ); tmpOrator.invoke('PATCH', '/api/item/7', null, (pError, pResponseData) => { let tmpResponseObject = JSON.parse(pResponseData); Expect(tmpResponseObject).to.have.a.property('Patched'); Expect(tmpResponseObject.Patched).to.equal(true); Expect(tmpResponseObject.ID).to.equal('7'); Expect(tmpResponseObject.Method).to.equal('PATCH'); tmpOrator.log.info(`PATCH /api/item/7 responded with [${pResponseData}]`); return fDone(); }); } ); test ( 'ipc should be able to register and invoke all verb types in the same service', (fDone) => { let tmpFable = new libFable(defaultFableSettings); tmpFable.serviceManager.addServiceType('Orator', libOrator); let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {}); tmpOrator.startService(); // Register multiple verbs on the same path pattern tmpOrator.serviceServer.get('/api/resource/:id', (pRequest, pResponse, fNext) => { pResponse.send({Action: 'read', ID: pRequest.params.id}); return fNext(); }); tmpOrator.serviceServer.post('/api/resource', (pRequest, pResponse, fNext) => { pResponse.send({Action: 'create'}); return fNext(); }); tmpOrator.serviceServer.put('/api/resource/:id', (pRequest, pResponse, fNext) => { pResponse.send({Action: 'update', ID: pRequest.params.id}); return fNext(); }); tmpOrator.serviceServer.del('/api/resource/:id', (pRequest, pResponse, fNext) => { pResponse.send({Action: 'delete', ID: pRequest.params.id}); return fNext(); }); tmpFable.Utility.waterfall([ (fStageComplete) => { tmpOrator.invoke('GET', '/api/resource/10', null, (pError, pResponseData) => { let tmpResponseObject = JSON.parse(pResponseData); Expect(tmpResponseObject.Action).to.equal('read'); Expect(tmpResponseObject.ID).to.equal('10'); return fStageComplete(); }); }, (fStageComplete) => { tmpOrator.invoke('POST', '/api/resource', {Name: 'New'}, (pError, pResponseData) => { let tmpResponseObject = JSON.parse(pResponseData); Expect(tmpResponseObject.Action).to.equal('create'); return fStageComplete(); }); }, (fStageComplete) => { tmpOrator.invoke('PUT', '/api/resource/10', {Name: 'Updated'}, (pError, pResponseData) => { let tmpResponseObject = JSON.parse(pResponseData); Expect(tmpResponseObject.Action).to.equal('update'); Expect(tmpResponseObject.ID).to.equal('10'); return fStageComplete(); }); }, (fStageComplete) => { tmpOrator.invoke('DELETE', '/api/resource/10', null, (pError, pResponseData) => { let tmpResponseObject = JSON.parse(pResponseData); Expect(tmpResponseObject.Action).to.equal('delete'); Expect(tmpResponseObject.ID).to.equal('10'); return fStageComplete(); }); } ], (pError) => { tmpOrator.log.info('All CRUD operations completed successfully via IPC'); return fDone(); }); } ); } ); suite ( 'Complex Route Patterns', () => { test ( 'ipc should be able to handle multiple URL parameters', (fDone) => { let tmpFable = new libFable(defaultFableSettings); tmpFable.serviceManager.addServiceType('Orator', libOrator); let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {}); tmpOrator.startService(); tmpOrator.serviceServer.get ( '/api/:entity/:id/child/:childId', (pRequest, pResponse, fNext) => { pResponse.send( { Entity: pRequest.params.entity, ID: pRequest.params.id, ChildID: pRequest.params.childId }); return fNext(); } ); tmpOrator.invoke('GET', '/api/Author/5/child/12', null, (pError, pResponseData) => { let tmpResponseObject = JSON.parse(pResponseData); Expect(tmpResponseObject.Entity).to.equal('Author'); Expect(tmpResponseObject.ID).to.equal('5'); Expect(tmpResponseObject.ChildID).to.equal('12'); tmpOrator.log.info(`Nested route responded with entity [${tmpResponseObject.Entity}] id [${tmpResponseObject.ID}] child [${tmpResponseObject.ChildID}]`); return fDone(); }); } ); test ( 'ipc should be able to handle routes that return string responses', (fDone) => { let tmpFable = new libFable(defaultFableSettings); tmpFable.serviceManager.addServiceType('Orator', libOrator); let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {}); tmpOrator.startService(); tmpOrator.serviceServer.get ( '/api/version', (pRequest, pResponse, fNext) => { pResponse.send('1.0.0'); return fNext(); } ); tmpOrator.invoke('GET', '/api/version', null, (pError, pResponseData) => { Expect(pResponseData).to.equal('1.0.0'); tmpOrator.log.info(`String endpoint responded with [${pResponseData}]`); return fDone(); }); } ); test ( 'ipc should handle chained route handlers sequentially', (fDone) => { let tmpFable = new libFable(defaultFableSettings); tmpFable.serviceManager.addServiceType('Orator', libOrator); let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {}); tmpOrator.startService(); // Register a route with multiple handler functions chained together tmpOrator.serviceServer.get ( '/api/chained/:value', // First handler: decorate the request (pRequest, pResponse, fNext) => { pRequest.Decorated = true; pRequest.ProcessingSteps = ['step1']; return fNext(); }, // Second handler: add more decoration (pRequest, pResponse, fNext) => { pRequest.ProcessingSteps.push('step2'); return fNext(); }, // Third handler: send the response (pRequest, pResponse, fNext) => { pResponse.send( { Value: pRequest.params.value, Decorated: pRequest.Decorated, Steps: pRequest.ProcessingSteps }); return fNext(); } ); tmpOrator.invoke('GET', '/api/chained/TestValue', null, (pError, pResponseData) => { let tmpResponseObject = JSON.parse(pResponseData); Expect(tmpResponseObject.Value).to.equal('TestValue'); Expect(tmpResponseObject.Decorated).to.equal(true); Expect(tmpResponseObject.Steps).to.be.an('array'); Expect(tmpResponseObject.Steps).to.have.lengthOf(2); Expect(tmpResponseObject.Steps[0]).to.equal('step1'); Expect(tmpResponseObject.Steps[1]).to.equal('step2'); tmpOrator.log.info(`Chained handler responded after ${tmpResponseObject.Steps.length} processing steps`); return fDone(); }); } ); test ( 'ipc should handle post-behavior functions after route handlers', (fDone) => { let tmpFable = new libFable(defaultFableSettings); tmpFable.serviceManager.addServiceType('Orator', libOrator); let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {}); tmpOrator.startService(); let tmpPostBehaviorExecuted = false; // Add a post-behavior function tmpOrator.serviceServer.addPostBehaviorFunction( (pRequest, pResponse, fNext) => { tmpPostBehaviorExecuted = true; return fNext(); }); tmpOrator.serviceServer.get ( '/api/postbehavior', (pRequest, pResponse, fNext) => { pResponse.send({Message: 'Handled'}); return fNext(); } ); tmpOrator.invoke('GET', '/api/postbehavior', null, (pError, pResponseData) => { let tmpResponseObject = JSON.parse(pResponseData); Expect(tmpResponseObject.Message).to.equal('Handled'); Expect(tmpPostBehaviorExecuted).to.equal(true, 'Post-behavior function should have executed'); tmpOrator.log.info(`Post-behavior test completed, postBehaviorExecuted: ${tmpPostBehaviorExecuted}`); return fDone(); }); } ); } ); suite ( 'Service Lifecycle', () => { test ( 'orator should be able to stop and report inactive status', (fDone) => { let tmpFable = new libFable(defaultFableSettings); tmpFable.serviceManager.addServiceType('Orator', libOrator); let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {}); tmpOrator.startService( () => { Expect(tmpOrator.serviceServer.Active).to.equal(true); tmpOrator.stopService( () => { Expect(tmpOrator.serviceServer.Active).to.equal(false); tmpOrator.log.info('Service started and stopped successfully'); return fDone(); }); }); } ); test ( 'orator should warn when stopping a service that has not been initialized', (fDone) => { let tmpFable = new libFable(defaultFableSettings); tmpFable.serviceManager.addServiceType('Orator', libOrator); let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {}); // Try to stop without starting tmpOrator.stopService( (pError) => { Expect(pError).to.be.a('string'); tmpOrator.log.info(`Stop-before-init warning: ${pError}`); return fDone(); }); } ); test ( 'orator should use ServicePort from options and fall back to defaults', (fDone) => { // ServicePort passed directly in options should be used let tmpFable = new libFable( { Product:'Orator-PortTest', ProductVersion: '0.0.0' }); tmpFable.serviceManager.addServiceType('Orator', libOrator); let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {ServicePort: 9999}); Expect(tmpOrator.options.ServicePort).to.equal(9999); // Test the legacy APIServerPort migration from fable settings let tmpFableLegacy = new libFable( { Product:'Orator-LegacyPortTest', ProductVersion: '0.0.0', APIServerPort: 7777 }); tmpFableLegacy.serviceManager.addServiceType('Orator', libOrator); let tmpOratorLegacy = tmpFableLegacy.serviceManager.instantiateServiceProvider('Orator', {}); Expect(tmpOratorLegacy.options.ServicePort).to.equal(7777); // Test the default port when nothing is configured let tmpFableDefault = new libFable( { Product:'Orator-DefaultPortTest', ProductVersion: '0.0.0' }); tmpFableDefault.serviceManager.addServiceType('Orator', libOrator); let tmpOratorDefault = tmpFableDefault.serviceManager.instantiateServiceProvider('Orator', {}); Expect(tmpOratorDefault.options.ServicePort).to.equal(8080); tmpOrator.log.info('Port configuration tests passed'); return fDone(); } ); test ( 'orator should provide a legacy webServer property', (fDone) => { let tmpFable = new libFable(defaultFableSettings); tmpFable.serviceManager.addServiceType('Orator', libOrator); let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {}); tmpOrator.initialize( () => { Expect(tmpOrator.webServer).to.be.an('object'); Expect(tmpOrator.webServer).to.equal(tmpOrator.serviceServer); Expect(tmpOrator.webServer.ServiceServerType).to.equal('IPC'); tmpOrator.log.info('Legacy webServer alias verified'); return fDone(); }); } ); test ( 'orator legacy startWebServer and stopWebServer should work', (fDone) => { let tmpFable = new libFable(defaultFableSettings); tmpFable.serviceManager.addServiceType('Orator', libOrator); let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {}); tmpOrator.startWebServer( () => { Expect(tmpOrator.serviceServer.Active).to.equal(true); tmpOrator.stopWebServer( () => { Expect(tmpOrator.serviceServer.Active).to.equal(false); tmpOrator.log.info('Legacy start/stop methods verified'); return fDone(); }); }); } ); } ); suite ( 'Static File Serving', () => { test ( 'addStaticRoute should return false when no file path is provided', (fDone) => { let tmpFable = new libFable(defaultFableSettings); tmpFable.serviceManager.addServiceType('Orator', libOrator); let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {}); tmpOrator.initialize( () => { let tmpResult = tmpOrator.addStaticRoute(); Expect(tmpResult).to.equal(false); tmpOrator.log.info('addStaticRoute correctly rejected missing file path'); return fDone(); }); } ); test ( 'addStaticRoute should return true with a valid file path', (fDone) => { let tmpFable = new libFable(defaultFableSettings); tmpFable.serviceManager.addServiceType('Orator', libOrator); let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {}); tmpOrator.initialize( () => { let tmpStaticPath = libPath.normalize(__dirname + '/static_content/'); let tmpResult = tmpOrator.addStaticRoute(tmpStaticPath); Expect(tmpResult).to.equal(true); tmpOrator.log.info(`addStaticRoute mapped [${tmpStaticPath}] successfully`); return fDone(); }); } ); test ( 'addStaticRoute should accept all optional parameters', (fDone) => { let tmpFable = new libFable(defaultFableSettings); tmpFable.serviceManager.addServiceType('Orator', libOrator); let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {}); tmpOrator.initialize( () => { let tmpStaticPath = libPath.normalize(__dirname + '/static_content/'); let tmpResult = tmpOrator.addStaticRoute(tmpStaticPath, 'about.html', '/content/*', '/content/', {maxAge: '1d'}); Expect(tmpResult).to.equal(true); tmpOrator.log.info('addStaticRoute accepted all optional parameters'); return fDone(); }); } ); test ( 'addStaticRoute should reject non-string file paths', (fDone) => { let tmpFable = new libFable(defaultFableSettings); tmpFable.serviceManager.addServiceType('Orator', libOrator); let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {}); tmpOrator.initialize( () => { Expect(tmpOrator.addStaticRoute(42)).to.equal(false); Expect(tmpOrator.addStaticRoute(null)).to.equal(false); Expect(tmpOrator.addStaticRoute({})).to.equal(false); Expect(tmpOrator.addStaticRoute(true)).to.equal(false); tmpOrator.log.info('addStaticRoute rejected all non-string file paths'); return fDone(); }); } ); } ); suite ( 'Route Validation', () => { test ( 'service server should reject non-string route parameters', (fDone) => { let tmpFable = new libFable(defaultFableSettings); tmpFable.serviceManager.addServiceType('Orator', libOrator); let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {}); tmpOrator.initialize( () => { Expect(tmpOrator.serviceServer.get(42)).to.equal(false); Expect(tmpOrator.serviceServer.post(null)).to.equal(false); Expect(tmpOrator.serviceServer.put(undefined)).to.equal(false); Expect(tmpOrator.serviceServer.del({})).to.equal(false); Expect(tmpOrator.serviceServer.patch([])).to.equal(false); Expect(tmpOrator.serviceServer.opts(true)).to.equal(false); tmpOrator.log.info('All verb methods correctly rejected non-string routes'); return fDone(); }); } ); test ( 'service server use should reject non-function handlers', (fDone) => { let tmpFable = new libFable(defaultFableSettings); tmpFable.serviceManager.addServiceType('Orator', libOrator); let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {}); tmpOrator.initialize( () => { Expect(tmpOrator.serviceServer.use('not a function')).to.equal(false); Expect(tmpOrator.serviceServer.use(42)).to.equal(false); Expect(tmpOrator.serviceServer.use(null)).to.equal(false); tmpOrator.log.info('use() correctly rejected non-function handlers'); return fDone(); }); } ); } ); suite ( 'Middleware and Complex Behavior Pipeline', () => { test ( 'multiple pre-behavior functions should execute in order', (fDone) => { let tmpFable = new libFable(defaultFableSettings); tmpFable.serviceManager.addServiceType('Orator', libOrator); let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {}); tmpOrator.startService(); // Add three pre-behavior functions that build up an array tmpOrator.serviceServer.use( (pRequest, pResponse, fNext) => { pRequest.Pipeline = ['first']; return fNext(); }); tmpOrator.serviceServer.use( (pRequest, pResponse, fNext) => { pRequest.Pipeline.push('second'); return fNext(); }); tmpOrator.serviceServer.use( (pRequest, pResponse, fNext) => { pRequest.Pipeline.push('third'); return fNext(); }); tmpOrator.serviceServer.get ( '/api/pipeline', (pRequest, pResponse, fNext) => { pResponse.send({Pipeline: pRequest.Pipeline}); return fNext(); } ); tmpOrator.invoke('GET', '/api/pipeline', null, (pError, pResponseData) => { let tmpResponseObject = JSON.parse(pResponseData); Expect(tmpResponseObject.Pipeline).to.be.an('array'); Expect(tmpResponseObject.Pipeline).to.have.lengthOf(3); Expect(tmpResponseObject.Pipeline[0]).to.equal('first'); Expect(tmpResponseObject.Pipeline[1]).to.equal('second'); Expect(tmpResponseObject.Pipeline[2]).to.equal('third'); tmpOrator.log.info(`Pipeline executed in order: ${tmpResponseObject.Pipeline.join(' -> ')}`); return fDone(); }); } ); test ( 'pre-behavior and post-behavior functions should bracket the route handler', (fDone) => { let tmpFable = new libFable(defaultFableSettings); tmpFable.serviceManager.addServiceType('Orator', libOrator); let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {}); tmpOrator.startService(); let tmpExecutionOrder = []; tmpOrator.serviceServer.use( (pRequest, pResponse, fNext) => { tmpExecutionOrder.push('pre'); return fNext(); }); tmpOrator.serviceServer.addPostBehaviorFunction( (pRequest, pResponse, fNext) => { tmpExecutionOrder.push('post'); return fNext(); }); tmpOrator.serviceServer.get ( '/api/bracket', (pRequest, pResponse, fNext) => { tmpExecutionOrder.push('handler'); pResponse.send({Order: 'captured'}); return fNext(); } ); tmpOrator.invoke('GET', '/api/bracket', null, (pError, pResponseData) => { Expect(tmpExecutionOrder).to.have.lengthOf(3); Expect(tmpExecutionOrder[0]).to.equal('pre'); Expect(tmpExecutionOrder[1]).to.equal('handler'); Expect(tmpExecutionOrder[2]).to.equal('post'); tmpOrator.log.info(`Execution order: ${tmpExecutionOrder.join(' -> ')}`); return fDone(); }); } ); test ( 'middleware should share request state across separate invoke calls', (fDone) => { let tmpFable = new libFable(defaultFableSettings); tmpFable.serviceManager.addServiceType('Orator', libOrator); let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {}); tmpOrator.startService(); let tmpRequestCount = 0; // Middleware that counts requests tmpOrator.serviceServer.use( (pRequest, pResponse, fNext) => { tmpRequestCount++; pRequest.RequestNumber = tmpRequestCount; return fNext(); }); tmpOrator.serviceServer.get ( '/api/counted', (pRequest, pResponse, fNext) => { pResponse.send({RequestNumber: pRequest.RequestNumber}); return fNext(); } ); tmpFable.Utility.waterfall([ (fStageComplete) => { tmpOrator.invoke('GET', '/api/counted', null, (pError, pResponseData) => { let tmpResponseObject = JSON.parse(pResponseData); Expect(tmpResponseObject.RequestNumber).to.equal(1); return fStageComplete(); }); }, (fStageComplete) => { tmpOrator.invoke('GET', '/api/counted', null, (pError, pResponseData) => { let tmpResponseObject = JSON.parse(pResponseData); Expect(tmpResponseObject.RequestNumber).to.equal(2); return fStageComplete(); }); }, (fStageComplete) => { tmpOrator.invoke('GET', '/api/counted', null, (pError, pResponseData) => { let tmpResponseObject = JSON.parse(pResponseData); Expect(tmpResponseObject.RequestNumber).to.equal(3); return fStageComplete(); }); } ], (pError) => { Expect(tmpRequestCount).to.equal(3); tmpOrator.log.info(`Request counter middleware tracked ${tmpRequestCount} invocations`); return fDone(); }); } ); } ); suite ( 'IPC Server Properties', () => { test ( 'ipc service server should have correct properties', (fDone) => { let tmpFable = new libFable(defaultFableSettings); tmpFable.serviceManager.addServiceType('Orator', libOrator); let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {}); tmpOrator.initialize( () => { Expect(tmpOrator.serviceServer.ServiceServerType).to.equal('IPC'); Expect(tmpOrator.serviceServer.URL).to.equal('IPC'); Expect(tmpOrator.serviceServer.Port).to.equal(0); Expect(tmpOrator.serviceServer.Active).to.equal(false); Expect(tmpOrator.serviceServer.Name).to.equal('Orator-ComplexRouteTests'); tmpOrator.log.info('IPC service server properties verified'); return fDone(); }); } ); test ( 'ipc bodyParser should return a passthrough function', (fDone) => { let tmpFable = new libFable(defaultFableSettings); tmpFable.serviceManager.addServiceType('Orator', libOrator); let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {}); tmpOrator.initialize( () => { let tmpBodyParser = tmpOrator.serviceServer.bodyParser(); Expect(tmpBodyParser).to.be.a('function'); // The IPC body parser should be a no-op passthrough let tmpNextCalled = false; tmpBodyParser({}, {}, () => { tmpNextCalled = true; }); Expect(tmpNextCalled).to.equal(true); tmpOrator.log.info('IPC bodyParser is a passthrough function'); return fDone(); }); } ); } ); } );