Webhooks v2 (and other fixes) (#10265)

* begin implementing global webhooks

* add checklist item scored webhook

* add pet hatched and mount raised webhooks (no tests)

* fix typo

* add lvl up webhooks, remove corrupt notifications and reorganize pre-save hook

* fix typo

* add some tests, globalActivity webhook

* fix bug in global activiy webhook and add more tests

* add tests and fix typo for petHatched and mountRaised webhooks

* fix errors and add tests for level up webhook

* wip: add default data to all webhooks, change signature for WebhookSender.send (missing tests)

* remove unused code

* fix unit tests

* fix chat webhooks

* remove console

* fix lint

* add and fix webhook tests

* add questStarted webhook and questActivity type

* add unit tests

* add finial tests and features
This commit is contained in:
Matteo Pagliazzi
2018-04-29 20:07:14 +02:00
committed by GitHub
parent cf274310a8
commit 5f0ef2d8f0
19 changed files with 1034 additions and 114 deletions
@@ -81,6 +81,49 @@ describe('POST /tasks/:id/score/:direction', () => {
expect(body.direction).to.eql('up');
expect(body.delta).to.be.greaterThan(0);
});
context('sending user activity webhooks', () => {
before(async () => {
await server.start();
});
after(async () => {
await server.close();
});
it('sends user activity webhook when the user levels up', async () => {
let uuid = generateUUID();
await user.post('/user/webhook', {
url: `http://localhost:${server.port}/webhooks/${uuid}`,
type: 'userActivity',
enabled: true,
options: {
leveledUp: true,
},
});
const initialLvl = user.stats.lvl;
await user.update({
'stats.exp': 3000,
});
let task = await user.post('/tasks/user', {
text: 'test habit',
type: 'habit',
});
await user.post(`/tasks/${task.id}/score/up`);
await user.sync();
await sleep();
let body = server.getWebhookData(uuid);
expect(body.type).to.eql('leveledUp');
expect(body.initialLvl).to.eql(initialLvl);
expect(body.finalLvl).to.eql(user.stats.lvl);
});
});
});
context('todos', () => {
@@ -1,6 +1,8 @@
import {
generateUser,
translate as t,
server,
sleep,
} from '../../../../../helpers/api-integration/v3';
import { v4 as generateUUID } from 'uuid';
@@ -94,4 +96,49 @@ describe('POST /tasks/:taskId/checklist/:itemId/score', () => {
message: t('checklistItemNotFound'),
});
});
context('sending task activity webhooks', () => {
before(async () => {
await server.start();
});
after(async () => {
await server.close();
});
it('sends task activity webhooks', async () => {
let uuid = generateUUID();
await user.post('/user/webhook', {
url: `http://localhost:${server.port}/webhooks/${uuid}`,
type: 'taskActivity',
enabled: true,
options: {
checklistScored: true,
updated: false,
},
});
let task = await user.post('/tasks/user', {
text: 'test daily',
type: 'daily',
});
let updatedTask = await user.post(`/tasks/${task.id}/checklist`, {
text: 'checklist item text',
});
let checklistItem = updatedTask.checklist[0];
let scoredItemTask = await user.post(`/tasks/${task.id}/checklist/${checklistItem.id}/score`);
await sleep();
let body = server.getWebhookData(uuid);
expect(body.type).to.eql('checklistScored');
expect(body.task).to.eql(scoredItemTask);
expect(body.item).to.eql(scoredItemTask.checklist[0]);
});
});
});
@@ -3,8 +3,11 @@
import {
generateUser,
translate as t,
server,
sleep,
} from '../../../../helpers/api-integration/v3';
import content from '../../../../../website/common/script/content';
import { v4 as generateUUID } from 'uuid';
describe('POST /user/feed/:pet/:food', () => {
let user;
@@ -37,4 +40,41 @@ describe('POST /user/feed/:pet/:food', () => {
expect(user.items.food.Milk).to.equal(1);
expect(user.items.pets['Wolf-Base']).to.equal(7);
});
context('sending user activity webhooks', () => {
before(async () => {
await server.start();
});
after(async () => {
await server.close();
});
it('sends user activity webhook when a new mount is raised', async () => {
let uuid = generateUUID();
await user.post('/user/webhook', {
url: `http://localhost:${server.port}/webhooks/${uuid}`,
type: 'userActivity',
enabled: true,
options: {
mountRaised: true,
},
});
await user.update({
'items.pets.Wolf-Base': 49,
'items.food.Milk': 2,
});
let res = await user.post('/user/feed/Wolf-Base/Milk');
await sleep();
let body = server.getWebhookData(uuid);
expect(body.type).to.eql('mountRaised');
expect(body.pet).to.eql('Wolf-Base');
expect(body.message).to.eql(res.message);
});
});
});
@@ -1,7 +1,10 @@
import {
generateUser,
translate as t,
server,
sleep,
} from '../../../../helpers/api-integration/v3';
import { v4 as generateUUID } from 'uuid';
describe('POST /user/hatch/:egg/:hatchingPotion', () => {
let user;
@@ -28,4 +31,41 @@ describe('POST /user/hatch/:egg/:hatchingPotion', () => {
data: JSON.parse(JSON.stringify(user.items)),
});
});
context('sending user activity webhooks', () => {
before(async () => {
await server.start();
});
after(async () => {
await server.close();
});
it('sends user activity webhook when a new pet is hatched', async () => {
let uuid = generateUUID();
await user.post('/user/webhook', {
url: `http://localhost:${server.port}/webhooks/${uuid}`,
type: 'userActivity',
enabled: true,
options: {
petHatched: true,
},
});
await user.update({
'items.eggs.Wolf': 1,
'items.hatchingPotions.Base': 1,
});
let res = await user.post('/user/hatch/Wolf/Base');
await sleep();
let body = server.getWebhookData(uuid);
expect(body.type).to.eql('petHatched');
expect(body.pet).to.eql('Wolf-Base');
expect(body.message).to.eql(res.message);
});
});
});
@@ -116,6 +116,7 @@ describe('POST /user/webhook', () => {
let webhook = await user.post('/user/webhook', body);
expect(webhook.options).to.eql({
checklistScored: false,
created: false,
updated: false,
deleted: false,
@@ -126,6 +127,7 @@ describe('POST /user/webhook', () => {
it('can set taskActivity options', async () => {
body.type = 'taskActivity';
body.options = {
checklistScored: true,
created: true,
updated: true,
deleted: true,
@@ -135,6 +137,7 @@ describe('POST /user/webhook', () => {
let webhook = await user.post('/user/webhook', body);
expect(webhook.options).to.eql({
checklistScored: true,
created: true,
updated: true,
deleted: true,
@@ -145,6 +148,7 @@ describe('POST /user/webhook', () => {
it('discards extra properties in taskActivity options', async () => {
body.type = 'taskActivity';
body.options = {
checklistScored: false,
created: true,
updated: true,
deleted: true,
@@ -156,6 +160,7 @@ describe('POST /user/webhook', () => {
expect(webhook.options.foo).to.not.exist;
expect(webhook.options).to.eql({
checklistScored: false,
created: true,
updated: true,
deleted: true,
@@ -218,4 +223,16 @@ describe('POST /user/webhook', () => {
groupId: body.options.groupId,
});
});
it('discards extra properties in globalActivity options', async () => {
body.type = 'globalActivity';
body.options = {
foo: 'bar',
};
let webhook = await user.post('/user/webhook', body);
expect(webhook.options.foo).to.not.exist;
expect(webhook.options).to.eql({});
});
});
@@ -95,6 +95,7 @@ describe('PUT /user/webhook/:id', () => {
let webhook = await user.put(`/user/webhook/${webhookToUpdate.id}`, {type, options});
expect(webhook.options).to.eql({
checklistScored: false, // starting value
created: true, // starting value
updated: false,
deleted: true,
+283 -22
View File
@@ -4,11 +4,16 @@ import {
taskScoredWebhook,
groupChatReceivedWebhook,
taskActivityWebhook,
questActivityWebhook,
userActivityWebhook,
} from '../../../../../website/server/libs/webhook';
import {
generateUser,
} from '../../../../helpers/api-unit.helper.js';
import { defer } from '../../../../helpers/api-unit.helper';
describe('webhooks', () => {
let webhooks;
let webhooks, user;
beforeEach(() => {
sandbox.stub(got, 'post').returns(defer().promise);
@@ -23,6 +28,26 @@ describe('webhooks', () => {
updated: true,
deleted: true,
scored: true,
checklistScored: true,
},
}, {
id: 'questActivity',
url: 'http://quest-activity.com',
enabled: true,
type: 'questActivity',
options: {
questStarted: true,
questFinised: true,
},
}, {
id: 'userActivity',
url: 'http://user-activity.com',
enabled: true,
type: 'userActivity',
options: {
petHatched: true,
mountRaised: true,
leveledUp: true,
},
}, {
id: 'groupChatReceived',
@@ -33,6 +58,9 @@ describe('webhooks', () => {
groupId: 'group-id',
},
}];
user = generateUser();
user.webhooks = webhooks;
});
afterEach(() => {
@@ -57,7 +85,8 @@ describe('webhooks', () => {
let body = { foo: 'bar' };
sendWebhook.send([{id: 'custom-webhook', url: 'http://custom-url.com', enabled: true, type: 'custom'}], body);
user.webhooks = [{id: 'custom-webhook', url: 'http://custom-url.com', enabled: true, type: 'custom'}];
sendWebhook.send(user, body);
expect(WebhookSender.defaultTransformData).to.be.calledOnce;
expect(got.post).to.be.calledOnce;
@@ -67,6 +96,30 @@ describe('webhooks', () => {
});
});
it('adds default data (user and webhookType) to the body', () => {
let sendWebhook = new WebhookSender({
type: 'custom',
});
sandbox.spy(sendWebhook, 'attachDefaultData');
let body = { foo: 'bar' };
user.webhooks = [{id: 'custom-webhook', url: 'http://custom-url.com', enabled: true, type: 'custom'}];
sendWebhook.send(user, body);
expect(sendWebhook.attachDefaultData).to.be.calledOnce;
expect(got.post).to.be.calledOnce;
expect(got.post).to.be.calledWithMatch('http://custom-url.com', {
json: true,
});
expect(body).to.eql({
foo: 'bar',
user: {_id: user._id},
webhookType: 'custom',
});
});
it('can pass in a data transformation function', () => {
sandbox.spy(WebhookSender, 'defaultTransformData');
let sendWebhook = new WebhookSender({
@@ -80,7 +133,8 @@ describe('webhooks', () => {
let body = { foo: 'bar' };
sendWebhook.send([{id: 'custom-webhook', url: 'http://custom-url.com', enabled: true, type: 'custom'}], body);
user.webhooks = [{id: 'custom-webhook', url: 'http://custom-url.com', enabled: true, type: 'custom'}];
sendWebhook.send(user, body);
expect(WebhookSender.defaultTransformData).to.not.be.called;
expect(got.post).to.be.calledOnce;
@@ -93,7 +147,7 @@ describe('webhooks', () => {
});
});
it('provieds a default filter function', () => {
it('provides a default filter function', () => {
sandbox.spy(WebhookSender, 'defaultWebhookFilter');
let sendWebhook = new WebhookSender({
type: 'custom',
@@ -101,7 +155,8 @@ describe('webhooks', () => {
let body = { foo: 'bar' };
sendWebhook.send([{id: 'custom-webhook', url: 'http://custom-url.com', enabled: true, type: 'custom'}], body);
user.webhooks = [{id: 'custom-webhook', url: 'http://custom-url.com', enabled: true, type: 'custom'}];
sendWebhook.send(user, body);
expect(WebhookSender.defaultWebhookFilter).to.be.calledOnce;
});
@@ -117,7 +172,8 @@ describe('webhooks', () => {
let body = { foo: 'bar' };
sendWebhook.send([{id: 'custom-webhook', url: 'http://custom-url.com', enabled: true, type: 'custom'}], body);
user.webhooks = [{id: 'custom-webhook', url: 'http://custom-url.com', enabled: true, type: 'custom'}];
sendWebhook.send(user, body);
expect(WebhookSender.defaultWebhookFilter).to.not.be.called;
expect(got.post).to.not.be.called;
@@ -134,10 +190,11 @@ describe('webhooks', () => {
let body = { foo: 'bar' };
sendWebhook.send([
user.webhooks = [
{ id: 'custom-webhook', url: 'http://custom-url.com', enabled: true, type: 'custom', options: { foo: 'bar' }},
{ id: 'other-custom-webhook', url: 'http://other-custom-url.com', enabled: true, type: 'custom', options: { foo: 'foo' }},
], body);
];
sendWebhook.send(user, body);
expect(got.post).to.be.calledOnce;
expect(got.post).to.be.calledWithMatch('http://custom-url.com');
@@ -150,7 +207,8 @@ describe('webhooks', () => {
let body = { foo: 'bar' };
sendWebhook.send([{id: 'custom-webhook', url: 'http://custom-url.com', enabled: false, type: 'custom'}], body);
user.webhooks = [{id: 'custom-webhook', url: 'http://custom-url.com', enabled: false, type: 'custom'}];
sendWebhook.send(user, body);
expect(got.post).to.not.be.called;
});
@@ -162,7 +220,8 @@ describe('webhooks', () => {
let body = { foo: 'bar' };
sendWebhook.send([{id: 'custom-webhook', url: 'httxp://custom-url!!', enabled: true, type: 'custom'}], body);
user.webhooks = [{id: 'custom-webhook', url: 'httxp://custom-url!!!', enabled: true, type: 'custom'}];
sendWebhook.send(user, body);
expect(got.post).to.not.be.called;
});
@@ -174,10 +233,30 @@ describe('webhooks', () => {
let body = { foo: 'bar' };
sendWebhook.send([
user.webhooks = [
{ id: 'custom-webhook', url: 'http://custom-url.com', enabled: true, type: 'custom'},
{ id: 'other-webhook', url: 'http://other-url.com', enabled: true, type: 'other'},
], body);
];
sendWebhook.send(user, body);
expect(got.post).to.be.calledOnce;
expect(got.post).to.be.calledWithMatch('http://custom-url.com', {
body,
json: true,
});
});
it('sends every type of activity to global webhooks', () => {
let sendWebhook = new WebhookSender({
type: 'custom',
});
let body = { foo: 'bar' };
user.webhooks = [
{ id: 'global-webhook', url: 'http://custom-url.com', enabled: true, type: 'globalActivity'},
];
sendWebhook.send(user, body);
expect(got.post).to.be.calledOnce;
expect(got.post).to.be.calledWithMatch('http://custom-url.com', {
@@ -193,10 +272,11 @@ describe('webhooks', () => {
let body = { foo: 'bar' };
sendWebhook.send([
user.webhooks = [
{ id: 'custom-webhook', url: 'http://custom-url.com', enabled: true, type: 'custom'},
{ id: 'other-custom-webhook', url: 'http://other-url.com', enabled: true, type: 'custom'},
], body);
];
sendWebhook.send(user, body);
expect(got.post).to.be.calledTwice;
expect(got.post).to.be.calledWithMatch('http://custom-url.com', {
@@ -216,7 +296,6 @@ describe('webhooks', () => {
beforeEach(() => {
data = {
user: {
_id: 'user-id',
_tmp: {foo: 'bar'},
stats: {
lvl: 5,
@@ -248,15 +327,54 @@ describe('webhooks', () => {
});
it('sends task and stats data', () => {
taskScoredWebhook.send(webhooks, data);
taskScoredWebhook.send(user, data);
expect(got.post).to.be.calledOnce;
expect(got.post).to.be.calledWithMatch(webhooks[0].url, {
json: true,
body: {
type: 'scored',
webhookType: 'taskActivity',
user: {
_id: 'user-id',
_id: user._id,
_tmp: {foo: 'bar'},
stats: {
lvl: 5,
int: 10,
str: 5,
exp: 423,
toNextLevel: 40,
maxHealth: 50,
maxMP: 103,
},
},
task: {
text: 'text',
},
direction: 'up',
delta: 176,
},
});
});
it('sends task and stats data to globalActivity webhookd', () => {
user.webhooks = [{
id: 'globalActivity',
url: 'http://global-activity.com',
enabled: true,
type: 'globalActivity',
}];
taskScoredWebhook.send(user, data);
expect(got.post).to.be.calledOnce;
expect(got.post).to.be.calledWithMatch('http://global-activity.com', {
json: true,
body: {
type: 'scored',
webhookType: 'taskActivity',
user: {
_id: user._id,
_tmp: {foo: 'bar'},
stats: {
lvl: 5,
@@ -280,7 +398,7 @@ describe('webhooks', () => {
it('does not send task scored data if scored option is not true', () => {
webhooks[0].options.scored = false;
taskScoredWebhook.send(webhooks, data);
taskScoredWebhook.send(user, data);
expect(got.post).to.not.be.called;
});
@@ -301,13 +419,17 @@ describe('webhooks', () => {
it(`sends ${type} tasks`, () => {
data.type = type;
taskActivityWebhook.send(webhooks, data);
taskActivityWebhook.send(user, data);
expect(got.post).to.be.calledOnce;
expect(got.post).to.be.calledWithMatch(webhooks[0].url, {
json: true,
body: {
type,
webhookType: 'taskActivity',
user: {
_id: user._id,
},
task: data.task,
},
});
@@ -317,7 +439,142 @@ describe('webhooks', () => {
data.type = type;
webhooks[0].options[type] = false;
taskActivityWebhook.send(webhooks, data);
taskActivityWebhook.send(user, data);
expect(got.post).to.not.be.called;
});
});
describe('checklistScored', () => {
beforeEach(() => {
data = {
task: {
text: 'text',
},
item: {
text: 'item-text',
},
};
});
it('sends \'checklistScored\' tasks', () => {
data.type = 'checklistScored';
taskActivityWebhook.send(user, data);
expect(got.post).to.be.calledOnce;
expect(got.post).to.be.calledWithMatch(webhooks[0].url, {
json: true,
body: {
webhookType: 'taskActivity',
user: {
_id: user._id,
},
type: data.type,
task: data.task,
item: data.item,
},
});
});
it('does not send task \'checklistScored\' data if \'checklistScored\' option is not true', () => {
data.type = 'checklistScored';
webhooks[0].options.checklistScored = false;
taskActivityWebhook.send(user, data);
expect(got.post).to.not.be.called;
});
});
});
describe('userActivityWebhook', () => {
let data;
beforeEach(() => {
data = {
something: true,
};
});
['petHatched', 'mountRaised', 'leveledUp'].forEach((type) => {
it(`sends ${type} webhooks`, () => {
data.type = type;
userActivityWebhook.send(user, data);
expect(got.post).to.be.calledOnce;
expect(got.post).to.be.calledWithMatch(webhooks[2].url, {
json: true,
body: {
type,
webhookType: 'userActivity',
user: {
_id: user._id,
},
something: true,
},
});
});
it(`does not send webhook ${type} data if ${type} option is not true`, () => {
data.type = type;
webhooks[2].options[type] = false;
userActivityWebhook.send(user, data);
expect(got.post).to.not.be.called;
});
});
});
describe('questActivityWebhook', () => {
let data;
beforeEach(() => {
data = {
group: {
id: 'group-id',
name: 'some group',
otherData: 'foo',
},
quest: {
key: 'some-key',
},
};
});
['questStarted', 'questFinised'].forEach((type) => {
it(`sends ${type} webhooks`, () => {
data.type = type;
questActivityWebhook.send(user, data);
expect(got.post).to.be.calledOnce;
expect(got.post).to.be.calledWithMatch(webhooks[1].url, {
json: true,
body: {
type,
webhookType: 'questActivity',
user: {
_id: user._id,
},
group: {
id: 'group-id',
name: 'some group',
},
quest: {
key: 'some-key',
},
},
});
});
it(`does not send webhook ${type} data if ${type} option is not true`, () => {
data.type = type;
webhooks[1].options[type] = false;
userActivityWebhook.send(user, data);
expect(got.post).to.not.be.called;
});
@@ -338,12 +595,16 @@ describe('webhooks', () => {
},
};
groupChatReceivedWebhook.send(webhooks, data);
groupChatReceivedWebhook.send(user, data);
expect(got.post).to.be.calledOnce;
expect(got.post).to.be.calledWithMatch(webhooks[webhooks.length - 1].url, {
json: true,
body: {
webhookType: 'groupChatReceived',
user: {
_id: user._id,
},
group: {
id: 'group-id',
name: 'some group',
@@ -369,7 +630,7 @@ describe('webhooks', () => {
},
};
groupChatReceivedWebhook.send(webhooks, data);
groupChatReceivedWebhook.send(user, data);
expect(got.post).to.not.be.called;
});
+86 -5
View File
@@ -11,7 +11,10 @@ import {
} from '../../../../../website/server/models/group';
import { model as User } from '../../../../../website/server/models/user';
import { quests as questScrolls } from '../../../../../website/common/script/content';
import { groupChatReceivedWebhook } from '../../../../../website/server/libs/webhook';
import {
groupChatReceivedWebhook,
questActivityWebhook,
} from '../../../../../website/server/libs/webhook';
import * as email from '../../../../../website/server/libs/email';
import { TAVERN_ID } from '../../../../../website/common/script/';
import shared from '../../../../../website/common';
@@ -21,6 +24,7 @@ describe('Group Model', () => {
beforeEach(async () => {
sandbox.stub(email, 'sendTxn');
sandbox.stub(questActivityWebhook, 'send');
party = new Group({
name: 'test party',
@@ -1189,6 +1193,47 @@ describe('Group Model', () => {
expect(typeOfEmail).to.eql('quest-started');
});
it('sends webhook to participating members that quest has started', async () => {
// should receive webhook
participatingMember.webhooks = [{
type: 'questActivity',
url: 'http://someurl.com',
options: {
questStarted: true,
},
}];
questLeader.webhooks = [{
type: 'questActivity',
url: 'http://someurl.com',
options: {
questStarted: true,
},
}];
await Promise.all([participatingMember.save(), questLeader.save()]);
await party.startQuest(nonParticipatingMember);
await sleep(0.5);
expect(questActivityWebhook.send).to.be.calledTwice; // for 2 participating members
let args = questActivityWebhook.send.args[0];
let webhooks = args[0].webhooks;
let webhookOwner = args[0]._id;
let options = args[1];
expect(webhooks).to.have.a.lengthOf(1);
if (webhookOwner === questLeader._id) {
expect(webhooks[0].id).to.eql(questLeader.webhooks[0].id);
} else {
expect(webhooks[0].id).to.eql(participatingMember.webhooks[0].id);
}
expect(webhooks[0].type).to.eql('questActivity');
expect(options.group).to.eql(party);
expect(options.quest.key).to.eql('whale');
});
it('sends email only to members who have not opted out', async () => {
participatingMember.preferences.emailNotifications.questStarted = false;
questLeader.preferences.emailNotifications.questStarted = true;
@@ -1570,6 +1615,42 @@ describe('Group Model', () => {
});
});
it('sends webhook to participating members that quest has finished', async () => {
// should receive webhook
participatingMember.webhooks = [{
type: 'questActivity',
url: 'http://someurl.com',
options: {
questFinished: true,
},
}];
questLeader.webhooks = [{
type: 'questActivity',
url: 'http://someurl.com',
options: {
questStarted: true, // will not receive the webhook
},
}];
await Promise.all([participatingMember.save(), questLeader.save()]);
await party.finishQuest(quest);
await sleep(0.5);
expect(questActivityWebhook.send).to.be.calledOnce;
let args = questActivityWebhook.send.args[0];
let webhooks = args[0].webhooks;
let options = args[1];
expect(webhooks).to.have.a.lengthOf(1);
expect(webhooks[0].id).to.eql(participatingMember.webhooks[0].id);
expect(webhooks[0].type).to.eql('questActivity');
expect(options.group).to.eql(party);
expect(options.quest.key).to.eql(quest.key);
});
context('World quests in Tavern', () => {
let tavernQuest;
@@ -1685,7 +1766,7 @@ describe('Group Model', () => {
expect(groupChatReceivedWebhook.send).to.be.calledOnce;
let args = groupChatReceivedWebhook.send.args[0];
let webhooks = args[0];
let webhooks = args[0].webhooks;
let options = args[1];
expect(webhooks).to.have.a.lengthOf(1);
@@ -1749,9 +1830,9 @@ describe('Group Model', () => {
expect(groupChatReceivedWebhook.send).to.be.calledThrice;
let args = groupChatReceivedWebhook.send.args;
expect(args.find(arg => arg[0][0].id === memberWithWebhook.webhooks[0].id)).to.be.exist;
expect(args.find(arg => arg[0][0].id === memberWithWebhook2.webhooks[0].id)).to.be.exist;
expect(args.find(arg => arg[0][0].id === memberWithWebhook3.webhooks[0].id)).to.be.exist;
expect(args.find(arg => arg[0].webhooks[0].id === memberWithWebhook.webhooks[0].id)).to.be.exist;
expect(args.find(arg => arg[0].webhooks[0].id === memberWithWebhook2.webhooks[0].id)).to.be.exist;
expect(args.find(arg => arg[0].webhooks[0].id === memberWithWebhook3.webhooks[0].id)).to.be.exist;
});
});
+177 -1
View File
@@ -24,6 +24,7 @@ describe('Webhook Model', () => {
updated: true,
deleted: true,
scored: true,
checklistScored: true,
},
};
});
@@ -36,6 +37,7 @@ describe('Webhook Model', () => {
wh.formatOptions(res);
expect(wh.options).to.eql({
checklistScored: false,
created: false,
updated: false,
deleted: false,
@@ -51,6 +53,7 @@ describe('Webhook Model', () => {
wh.formatOptions(res);
expect(wh.options).to.eql({
checklistScored: true,
created: false,
updated: true,
deleted: true,
@@ -67,6 +70,7 @@ describe('Webhook Model', () => {
expect(wh.options.foo).to.not.exist;
expect(wh.options).to.eql({
checklistScored: true,
created: true,
updated: true,
deleted: true,
@@ -74,7 +78,155 @@ describe('Webhook Model', () => {
});
});
['created', 'updated', 'deleted', 'scored'].forEach((option) => {
['created', 'updated', 'deleted', 'scored', 'checklistScored'].forEach((option) => {
it(`validates that ${option} is a boolean`, (done) => {
config.options[option] = 'not a boolean';
try {
let 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;
let 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;
let 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';
let 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 {
let 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,
},
};
});
it('it provides default values for options', () => {
delete config.options;
let wh = new Webhook(config);
wh.formatOptions(res);
expect(wh.options).to.eql({
questStarted: false,
questFinished: false,
});
});
it('provides missing user options', () => {
delete config.options.questStarted;
let wh = new Webhook(config);
wh.formatOptions(res);
expect(wh.options).to.eql({
questStarted: false,
questFinished: true,
});
});
it('discards additional options', () => {
config.options.foo = 'another option';
let wh = new Webhook(config);
wh.formatOptions(res);
expect(wh.options.foo).to.not.exist;
expect(wh.options).to.eql({
questStarted: true,
questFinished: true,
});
});
['questStarted', 'questFinished'].forEach((option) => {
it(`validates that ${option} is a boolean`, (done) => {
config.options[option] = 'not a boolean';
@@ -141,6 +293,30 @@ describe('Webhook Model', () => {
}
});
});
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';
let wh = new Webhook(config);
wh.formatOptions(res);
expect(wh.options.foo).to.not.exist;
expect(wh.options).to.eql({});
});
});
});
});
});