UNPKG

courtbot-engine

Version:

An engine for courtbot-like functionality to be included in city/county services sites.

524 lines (413 loc) 22.8 kB
import setup from './setup'; import courtbotError from '../src/courtbotError'; import { COURTBOT_ERROR_TYPES } from '../src/courtbotError'; import proxyquire from 'proxyquire'; describe(`events`, () => { const {sandbox, expect, chance} = setup(); let testee; let emitter; let dummyCase; let dummyParty; let dummyPartyList; let dummyPartyArray; let reducedDummyPartyList; let dummyEventList; let reducedDummyEventList; let duplicatePartyList; let reducedDuplicatePartyList; let retrieveErrorStub; let emptyResult; let log4js; let traceStub; let debugStub; let infoStub; let logStub; let warnStub; let errorStub; let fatalStub; beforeEach(() => { traceStub = sandbox.stub(); debugStub = sandbox.stub(); infoStub = sandbox.stub(); logStub = sandbox.stub(); warnStub = sandbox.stub(); errorStub = sandbox.stub(); fatalStub = sandbox.stub(); log4js = { getLogger: sandbox.stub().returns({ trace: traceStub, debug: debugStub, info: infoStub, log: logStub, warn: warnStub, error: errorStub, fatal: fatalStub }) } testee = proxyquire(`../src/events.js`, { log4js }); emitter = testee.default; dummyCase = -1; dummyParty = -1; dummyPartyList = [[{name: `a`}, {name: `b`}], {name: `c`}]; reducedDummyPartyList = [{name: `a`}, {name: `b`}, {name: `c`}]; dummyEventList = [{date: `1`}, [{date: '2'}, {date: `3`}]]; reducedDummyEventList = [{date: `1`}, {date: '2'}, {date: `3`}]; duplicatePartyList = [{name: `a`}, {name: `b`}, {name: `a`}]; reducedDuplicatePartyList = [{name: `a`}, {name: `b`}]; retrieveErrorStub = sandbox.stub(); emptyResult = { promises: [] }; }); afterEach(() => { // So that we don't have all the listeners adding all the things emitter.removeAllListeners(); }); describe(`getCaseParties()`, () => { it(`the emitter should emit the retrieve-parties event`, () => { return expect(testee.getCaseParties).to.emitFrom(emitter, `retrieve-parties`); }); it(`should pass the casenumber and the empty result object to the event listener`, () => { return expect(() => {testee.getCaseParties(dummyCase)}).to.emitFrom(emitter, `retrieve-parties`, dummyCase, emptyResult); }); it(`if no errors in data retrieval, should return a concatenated array of all party names found`, () => { emitter.on(`retrieve-parties`, (casenumber, result) => { dummyPartyList.forEach((elem) => { result.promises.push(Promise.resolve(elem)); }); }); return testee.getCaseParties(dummyCase).should.eventually.deep.equal(reducedDummyPartyList); }); it(`should handle a combination of strings, objects whose "name" property is a string, and arrays of such objects`, () => { const dummyPartyString = `a,b`; const dummyPartyObject = {name: `c,d`}; dummyPartyArray = [{name: `e,f` }, {name: `g,h`}]; let output = [{name: `a,b`}, {name: `c,d`}, {name: `e,f`}, {name: `g,h`}]; emitter.on(`retrieve-parties`, (casenumber, result) => { result.promises.push(Promise.resolve(dummyPartyString)); result.promises.push(Promise.resolve(dummyPartyObject)); result.promises.push(Promise.resolve(dummyPartyArray)); }); return testee.getCaseParties(dummyCase).should.eventually.deep.equal(output); }); it(`if an array of objects contains some malformed items, it should process the remainder correctly`, () => { dummyPartyArray = [{name: `a`}, undefined, null, {notright: `hi`}, 2, NaN, Symbol(`foo`), () => {}, [], {name: `b`}, true, {name: `c`}]; emitter.on(`retrieve-parties`, (casenumber, result) => { result.promises.push(Promise.resolve(dummyPartyArray)); }); return testee.getCaseParties(dummyCase).should.eventually.deep.equal(reducedDummyPartyList); }); it(`should only return unique parties if duplicate parties are found`, () => { emitter.on(`retrieve-parties`, (casenumber, result) => { duplicatePartyList.forEach((elem) => { result.promises.push(Promise.resolve(elem)); }); }); return testee.getCaseParties(dummyCase).should.eventually.deep.equal(reducedDuplicatePartyList); }); it(`if there are errors in data retrieval, should return only a concatenated array of all parties found by default`, () => { emitter.on(`retrieve-parties`, (casenumber, result) => { dummyPartyList.forEach((elem) => { result.promises.push(Promise.resolve(elem)); }); result.promises.push(Promise.reject(`failed`)); }); return testee.getCaseParties(dummyCase).should.eventually.deep.equal(reducedDummyPartyList); }); describe(`error behavior`, () => { it(`if there are errors in data retrieval, should emit the retrieve-parties-error event by default`, () => { emitter.on(`retrieve-parties`, (casenumber, result) => { dummyPartyList.forEach((elem) => { result.promises.push(Promise.resolve(elem)); }); result.promises.push(Promise.reject(`1`)); result.promises.push(Promise.reject(`2`)); result.promises.push(Promise.reject(`3`)); }); return expect(() => { testee.getCaseParties(dummyCase) }).to.emitFrom(emitter, `retrieve-parties`); }); it(`if there are errors in data retrieval, should emit retrieve-parties-error by default with an array of courtbotErrors with at least one error`, () => { emitter.on(`retrieve-parties-error`, (errors) => { expect(errors).to.be.an(`Array`); expect(errors).to.not.be.empty; expect(errors.every((e) => { return e.isCourtbotError === true })).to.equal(true); }); emitter.on(`retrieve-parties`, (casenumber, result) => { dummyPartyList.forEach((elem) => { result.promises.push(Promise.resolve(elem)); }); result.promises.push(Promise.reject(`1`)); result.promises.push(Promise.reject(`2`)); result.promises.push(Promise.reject(`3`)); }); return testee.getCaseParties(dummyCase); }); it(`should place the data from non-courtbotError non-objects into courtbotError.initialError.data`, () => { let testData = `testing`; emitter.on(`retrieve-parties-error`, (errors) => { expect(errors[0].initialError.data).to.equal(testData); }); emitter.on(`retrieve-parties`, (casenumber, result) => { dummyPartyList.forEach((elem) => { result.promises.push(Promise.resolve(elem)); }); result.promises.push(Promise.reject(testData)); }); return testee.getCaseParties(dummyCase); }); it(`should place the data from non-courtbotError objects into courtbotError.initialError`, () => { let testData = new Error(`testing`); emitter.on(`retrieve-parties-error`, (errors) => { expect(errors[0].initialError).to.deep.equal(testData); }); emitter.on(`retrieve-parties`, (casenumber, result) => { dummyPartyList.forEach((elem) => { result.promises.push(Promise.resolve(elem)); }); result.promises.push(Promise.reject(testData)); }); return testee.getCaseParties(dummyCase); }); it('should not emit the retrieve-parties-error event if the 1s bit of errorMode is off', () => { emitter.on(`retrieve-parties`, (casenumber, result) => { dummyPartyList.forEach((elem) => { result.promises.push(Promise.resolve(elem)); }); result.promises.push(Promise.reject(`1`)); }); return expect(() => {testee.getCaseParties(dummyCase, 2)}).to.not.emitFrom(emitter, `retrieve-parties-error`); }); it('should return a { parties: [], errors: [] } object if the returnErrorsWithData property is true', () => { emitter.on(`retrieve-parties`, (casenumber, result) => { dummyPartyList.forEach((elem) => { result.promises.push(Promise.resolve(elem)); }); result.promises.push(Promise.reject(`1`)); result.promises.push(Promise.reject(`2`)); result.promises.push(Promise.reject(`3`)); }); return testee.getCaseParties(dummyCase, {returnErrorsWithData: true}) .then((result) => { expect(result.errors.every((e) => { return e.isCourtbotError === true })).to.equal(true); expect(result.parties).to.deep.equal(reducedDummyPartyList); }); }); // Begin enhanced logging it(`should emit a courtbotError of type COURBOT_ERROR_TYPES.API.GET and the correct case number if a promise rejects with a non-courtbotError`, () => { emitter.on(`retrieve-parties`, (casenumber, result) => { result.promises.push(Promise.reject(`fail`)); }); emitter.on(`retrieve-parties-error`, (errors) => { expect(errors[0].type).to.equal(COURTBOT_ERROR_TYPES.API.GET); expect(errors[0].case).to.equal(dummyCase); }); return testee.getCaseParties(dummyCase); }); it(`should emit a courtbotError of type COURTBOT_ERROR_TYPES.API.GET and the correct case number if a promise resolves with an object that does not have a "name" property`, () => { emitter.on(`retrieve-parties`, (casenumber, result) => { result.promises.push(Promise.resolve({ notname: `a,b,c` })); }); emitter.on(`retrieve-parties-error`, (errors) => { expect(errors[0].type).to.equal(COURTBOT_ERROR_TYPES.API.GET); expect(errors[0].case).to.equal(dummyCase); }); return testee.getCaseParties(dummyCase); }); it('should emit a courtbotError of type COURTBOT_ERROR_TYPES.API.GET and the correct case number if a promise resolves with an array of objects, some of which do not have a "name" property. It should also count the number of malformed items.', () => { emitter.on(`retrieve-parties`, (casenumber, result) => { result.promises.push(Promise.resolve([{ notname: `a,b,c` }, dummyPartyList, { a: true }, { b: false }])); }); emitter.on(`retrieve-parties-error`, (errors) => { expect(errors[0].type).to.equal(COURTBOT_ERROR_TYPES.API.GET); expect(errors[0].case).to.equal(dummyCase); }); return testee.getCaseParties(dummyCase); }); }); describe(`log4js`, () => { it(`should send something to log4js when handling a rejected promise`, () => { emitter.on(`retrieve-parties`, (casenumber, result) => { result.promises.push(Promise.reject(`failed`)); }); return testee.getCaseParties(dummyCase).then(() => { let logged = traceStub.called || debugStub.called || infoStub.called || logStub.called || warnStub.called || errorStub.called || fatalStub.called; expect(logged).to.equal(true); }); }); it(`should send something to log4js when handling malformed data`, () => { emitter.on(`retrieve-parties`, (casenumber, result) => { result.promises.push(Promise.resolve({ notname: `notname`})); }); return testee.getCaseParties(dummyCase).then(() => { let logged = traceStub.called || debugStub.called || infoStub.called || logStub.called || warnStub.called || errorStub.called || fatalStub.called; expect(logged).to.equal(true); }); }); }); }); describe(`getCasePartyEvents()`, () => { it(`the emitter should emit the retrieve-party-events event`, () => { return expect(testee.getCasePartyEvents).to.emitFrom(emitter, `retrieve-party-events`); }); it(`should pass the casenumber, party and the empty result object to the event listener`, () => { return expect(() => {testee.getCasePartyEvents(dummyCase, dummyParty)}).to.emitFrom(emitter, `retrieve-party-events`, dummyCase, dummyParty, emptyResult); }); it(`if no errors in data retrieval, should return a concatenated array of all party names found`, () => { emitter.on(`retrieve-party-events`, (casenumber, party, result) => { dummyEventList.forEach((elem) => { result.promises.push(Promise.resolve(elem)); }); }); return testee.getCasePartyEvents(dummyCase, dummyParty).should.eventually.deep.equal(reducedDummyEventList); }); it(`if there are errors in data retrieval, should return only a concatenated array of all parties found by default`, () => { emitter.on(`retrieve-party-events`, (casenumber, party, result) => { dummyEventList.forEach((elem) => { result.promises.push(Promise.resolve(elem)); }); result.promises.push(Promise.reject(`failed`)); }); return testee.getCasePartyEvents(dummyCase).should.eventually.deep.equal(reducedDummyEventList); }); it(`if there are errors in data retrieval, should emit the retrieve-party-events-error event by default`, () => { emitter.on(`retrieve-party-events-error`, retrieveErrorStub); emitter.on(`retrieve-party-events`, (casenumber, party, result) => { dummyEventList.forEach((elem) => { result.promises.push(Promise.resolve(elem)); }); result.promises.push(Promise.reject(`1`)); result.promises.push(Promise.reject(`2`)); result.promises.push(Promise.reject(`3`)); }); // This test fails, but should be equivalent to the uncommented test. Will look into it later, but it works for now // No sense wasting time // return expect(() => { testee.getCasePartyEvents(dummyCase, dummyParty) }).to.emitFrom(emitter, `retrieve-party-events-error`); return testee.getCasePartyEvents(dummyCase, dummyParty) .then(() => { expect(retrieveErrorStub).to.have.been.called(); }); }); it(`if there are errors in data retrieval, should emit retrieve-party-events-error by default with an array of courtbotErrors with at least one error`, () => { emitter.on(`retrieve-party-events-error`, (errors) => { expect(errors).to.be.an(`Array`); expect(errors).to.not.be.empty; expect(errors.every((e) => { return e.isCourtbotError === true })).to.equal(true); }); emitter.on(`retrieve-party-events`, (casenumber, party, result) => { dummyEventList.forEach((elem) => { result.promises.push(Promise.resolve(elem)); }); result.promises.push(Promise.reject(`1`)); result.promises.push(Promise.reject(`2`)); result.promises.push(Promise.reject(`3`)); }); return testee.getCasePartyEvents(dummyCase); }); it(`should place the data from non-courtbotError non-objects into courtbotError.initialError.data`, () => { let testData = `testing`; emitter.on(`retrieve-party-events-error`, (errors) => { expect(errors[0].initialError.data).to.equal(testData); }); emitter.on(`retrieve-party-events`, (casenumber, party, result) => { dummyEventList.forEach((elem) => { result.promises.push(Promise.resolve(elem)); }); result.promises.push(Promise.reject(testData)); }); return testee.getCasePartyEvents(dummyCase, dummyParty); }); it(`should place the data from non-courtbotError objects into courtbotError.initialError`, () => { let testData = new Error(`testing`); emitter.on(`retrieve-party-events-error`, (errors) => { expect(errors[0].initialError).to.deep.equal(testData); }); emitter.on(`retrieve-party-events`, (casenumber, party, result) => { dummyEventList.forEach((elem) => { result.promises.push(Promise.resolve(elem)); }); result.promises.push(Promise.reject(testData)); }); return testee.getCaseParties(dummyCase, dummyParty); }); it('should not place anything in intial error if the data error is a courtbotError', () => { let testData = new courtbotError(``); emitter.on(`retrieve-party-events-error`, (errors) => { expect(errors[0].initialError).to.deep.equal(null); }); emitter.on(`retrieve-party-events`, (casenumber, party, result) => { dummyEventList.forEach((elem) => { result.promises.push(Promise.resolve(elem)); }); result.promises.push(Promise.reject(testData)); }); return testee.getCasePartyEvents(dummyCase, dummyParty); }); it('should not emit the retrieve-parties-error event if the 1s bit of errorMode is off', () => { emitter.on(`retrieve-party-events-error`, retrieveErrorStub); emitter.on(`retrieve-party-events`, (casenumber, party, result) => { dummyEventList.forEach((elem) => { result.promises.push(Promise.resolve(elem)); }); result.promises.push(Promise.reject(`1`)); }); return testee.getCasePartyEvents(dummyCase, dummyParty, 2) .then(() => { expect(retrieveErrorStub).to.not.have.been.called(); }); }); it('should return a { events: [], errors: [] } object if the 2s bit of errorMode is on', () => { emitter.on(`retrieve-party-events`, (casenumber, party, result) => { dummyEventList.forEach((elem) => { result.promises.push(Promise.resolve(elem)); }); result.promises.push(Promise.reject(`1`)); result.promises.push(Promise.reject(`2`)); result.promises.push(Promise.reject(`3`)); }); return testee.getCasePartyEvents(dummyCase, dummyParty, 2) .then((result) => { expect(result.errors.every((e) => { return e.isCourtbotError === true })).to.equal(true); expect(result.events).to.deep.equal(reducedDummyEventList); }); }); describe(`log4js`, () => { it(`should send something to log4js when handling a rejected promise`, () => { emitter.on(`retrieve-party-events`, (casenumber, party, result) => { result.promises.push(Promise.reject(`failed`)); }); return testee.getCasePartyEvents(dummyCase, dummyParty).then(() => { let logged = traceStub.called || debugStub.called || infoStub.called || logStub.called || warnStub.called || errorStub.called || fatalStub.called; expect(logged).to.equal(true); }); }); }); }); describe(`sendNonReplyMessage`, () => { let dummyTo, dummyMsg, dummyCommunicationType; beforeEach(() => { dummyTo = chance.phone(); dummyMsg = chance.word(); dummyCommunicationType = chance.word(); }); it(`the emitter should emit the send-non-reply event`, () => { return expect(testee.sendNonReplyMessage).to.emitFrom(emitter, `send-non-reply`); }); it(`should pass the an address, msg, communication type and the empty result object to the event listener`, () => { return expect(() => {testee.sendNonReplyMessage(dummyTo, dummyMsg, dummyCommunicationType)}).to.emitFrom(emitter, `send-non-reply`, {to: dummyTo, msg: dummyMsg, communicationType: dummyCommunicationType, result: emptyResult}); }); it('should return result.promise if result.promise is set', () => { const prom = new Promise(function() {}); emitter.on(`send-non-reply`, (o) => { o.result.promise = prom; }); expect(testee.sendNonReplyMessage(dummyTo, dummyMsg, dummyCommunicationType)).to.eql(prom); }); it('should return result.promises wrapped in an all if result.promises is set', () => { const prom = new Promise(function() {}); emitter.on(`send-non-reply`, (o) => { o.result.promises = [prom]; }); expect(testee.sendNonReplyMessage(dummyTo, dummyMsg, dummyCommunicationType)).to.eql(Promise.all([prom])); }); }); });