import { v4 as generateUUID } from 'uuid'; import { model as Webhook } from '../../../../website/server/models/webhook'; import { BadRequest } from '../../../../website/server/libs/errors'; import { apiError } from '../../../../website/server/libs/apiError'; describe('Webhook Model', () => { context('Instance Methods', () => { describe('#formatOptions', () => { let res; beforeEach(() => { res = { t: sandbox.spy(), }; }); context('type is taskActivity', () => { let config; beforeEach(() => { config = { type: 'taskActivity', url: 'https//exmaple.com/endpoint', options: { created: true, updated: true, deleted: true, scored: true, checklistScored: true, }, }; }); it('it provides default values for options', () => { delete config.options; const wh = new Webhook(config); wh.formatOptions(res); expect(wh.options).to.eql({ checklistScored: false, created: false, updated: false, deleted: false, scored: true, }); }); it('provides missing task options', () => { delete config.options.created; const wh = new Webhook(config); wh.formatOptions(res); expect(wh.options).to.eql({ checklistScored: true, created: false, updated: true, deleted: true, scored: true, }); }); it('discards additional options', () => { config.options.foo = 'another option'; const wh = new Webhook(config); wh.formatOptions(res); expect(wh.options.foo).to.not.exist; expect(wh.options).to.eql({ checklistScored: true, created: true, updated: true, deleted: true, scored: true, }); }); ['created', 'updated', 'deleted', 'scored', 'checklistScored'].forEach(option => { it(`validates that ${option} is a boolean`, done => { config.options[option] = 'not a boolean'; try { const wh = new Webhook(config); wh.formatOptions(res); } catch (err) { expect(err).to.be.an.instanceOf(BadRequest); expect(res.t).to.be.calledOnce; expect(res.t).to.be.calledWith('webhookBooleanOption', { option }); done(); } }); }); }); context('type is userActivity', () => { let config; beforeEach(() => { config = { type: 'userActivity', url: 'https//exmaple.com/endpoint', options: { petHatched: true, mountRaised: true, leveledUp: true, }, }; }); it('it provides default values for options', () => { delete config.options; const wh = new Webhook(config); wh.formatOptions(res); expect(wh.options).to.eql({ petHatched: false, mountRaised: false, leveledUp: false, }); }); it('provides missing user options', () => { delete config.options.petHatched; const wh = new Webhook(config); wh.formatOptions(res); expect(wh.options).to.eql({ petHatched: false, mountRaised: true, leveledUp: true, }); }); it('discards additional options', () => { config.options.foo = 'another option'; const wh = new Webhook(config); wh.formatOptions(res); expect(wh.options.foo).to.not.exist; expect(wh.options).to.eql({ petHatched: true, mountRaised: true, leveledUp: true, }); }); ['petHatched', 'petHatched', 'leveledUp'].forEach(option => { it(`validates that ${option} is a boolean`, done => { config.options[option] = 'not a boolean'; try { const wh = new Webhook(config); wh.formatOptions(res); } catch (err) { expect(err).to.be.an.instanceOf(BadRequest); expect(res.t).to.be.calledOnce; expect(res.t).to.be.calledWith('webhookBooleanOption', { option }); done(); } }); }); }); context('type is questActivity', () => { let config; beforeEach(() => { config = { type: 'questActivity', url: 'https//exmaple.com/endpoint', options: { questStarted: true, questFinished: true, questInvited: true, }, }; }); it('it provides default values for options', () => { delete config.options; const wh = new Webhook(config); wh.formatOptions(res); expect(wh.options).to.eql({ questStarted: false, questFinished: false, questInvited: false, }); }); it('provides missing user options', () => { delete config.options.questStarted; const wh = new Webhook(config); wh.formatOptions(res); expect(wh.options).to.eql({ questStarted: false, questFinished: true, questInvited: true, }); }); it('discards additional options', () => { config.options.foo = 'another option'; const wh = new Webhook(config); wh.formatOptions(res); expect(wh.options.foo).to.not.exist; expect(wh.options).to.eql({ questStarted: true, questFinished: true, questInvited: true, }); }); ['questStarted', 'questFinished'].forEach(option => { it(`validates that ${option} is a boolean`, done => { config.options[option] = 'not a boolean'; try { const wh = new Webhook(config); wh.formatOptions(res); } catch (err) { expect(err).to.be.an.instanceOf(BadRequest); expect(res.t).to.be.calledOnce; expect(res.t).to.be.calledWith('webhookBooleanOption', { option }); done(); } }); }); }); context('type is groupChatReceived', () => { let config; beforeEach(() => { config = { type: 'groupChatReceived', url: 'https//exmaple.com/endpoint', options: { groupId: generateUUID(), }, }; }); it('creates options', () => { const wh = new Webhook(config); wh.formatOptions(res); expect(wh.options).to.eql(config.options); }); it('discards additional objects', () => { config.options.foo = 'another thing'; const wh = new Webhook(config); wh.formatOptions(res); expect(wh.options.foo).to.not.exist; expect(wh.options).to.eql({ groupId: config.options.groupId, }); }); it('requires groupId option to be a uuid', done => { config.options.groupId = 'not a uuid'; try { const wh = new Webhook(config); wh.formatOptions(res); } catch (err) { expect(err).to.be.an.instanceOf(BadRequest); expect(err.message).to.eql(apiError('groupIdRequired')); done(); } }); }); context('type is globalActivity', () => { let config; beforeEach(() => { config = { type: 'globalActivity', url: 'https//exmaple.com/endpoint', options: { }, }; }); it('discards additional objects', () => { config.options.foo = 'another thing'; const wh = new Webhook(config); wh.formatOptions(res); expect(wh.options.foo).to.not.exist; expect(wh.options).to.eql({}); }); }); }); }); });