Merge branch 'develop' into party-chat-translations
# Conflicts: # website/server/models/group.js
This commit is contained in:
@@ -60,9 +60,9 @@ describe('GET /challenges/:challengeId/export/csv', () => {
|
||||
});
|
||||
|
||||
it('should return a valid CSV file with export data', async () => {
|
||||
let res = await members[0].get(`/challenges/${challenge._id}/export/csv`);
|
||||
let sortedMembers = _.sortBy([members[0], members[1], members[2], groupLeader], '_id');
|
||||
let splitRes = res.split('\n');
|
||||
const res = await members[0].get(`/challenges/${challenge._id}/export/csv`);
|
||||
const sortedMembers = _.sortBy([members[0], members[1], members[2], groupLeader], '_id');
|
||||
const splitRes = res.split('\n');
|
||||
|
||||
expect(splitRes[0]).to.equal('UUID,name,Task,Value,Notes,Streak,Task,Value,Notes,Streak');
|
||||
expect(splitRes[1]).to.equal(`${sortedMembers[0]._id},${sortedMembers[0].profile.name},habit:Task 1,0,,0,todo:Task 2,0,,0`);
|
||||
@@ -71,4 +71,16 @@ describe('GET /challenges/:challengeId/export/csv', () => {
|
||||
expect(splitRes[4]).to.equal(`${sortedMembers[3]._id},${sortedMembers[3].profile.name},habit:Task 1,0,,0,todo:Task 2,0,,0`);
|
||||
expect(splitRes[5]).to.equal('');
|
||||
});
|
||||
|
||||
it('should successfully return when it contains erroneous residue user data', async () => {
|
||||
await members[0].update({challenges: []});
|
||||
const res = await members[1].get(`/challenges/${challenge._id}/export/csv`);
|
||||
const sortedMembers = _.sortBy([members[1], members[2], groupLeader], '_id');
|
||||
const splitRes = res.split('\n');
|
||||
expect(splitRes[0]).to.equal('UUID,name,Task,Value,Notes,Streak,Task,Value,Notes,Streak');
|
||||
expect(splitRes[1]).to.equal(`${sortedMembers[0]._id},${sortedMembers[0].profile.name},habit:Task 1,0,,0,todo:Task 2,0,,0`);
|
||||
expect(splitRes[2]).to.equal(`${sortedMembers[1]._id},${sortedMembers[1].profile.name},habit:Task 1,0,,0,todo:Task 2,0,,0`);
|
||||
expect(splitRes[3]).to.equal(`${sortedMembers[2]._id},${sortedMembers[2].profile.name},habit:Task 1,0,,0,todo:Task 2,0,,0`);
|
||||
expect(splitRes[4]).to.equal('');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -32,7 +32,8 @@ describe('GET /groups/:groupId/chat', () => {
|
||||
it('returns Guild chat', async () => {
|
||||
const chat = await user.get(`/groups/${group._id}/chat`);
|
||||
|
||||
expect(chat).to.eql(group.chat);
|
||||
expect(chat[0].id).to.eql(group.chat[0].id);
|
||||
expect(chat[1].id).to.eql(group.chat[1].id);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
generateUser,
|
||||
resetHabiticaDB,
|
||||
} from '../../../../helpers/api-v3-integration.helper';
|
||||
import apiMessages from '../../../../../website/server/libs/apiMessages';
|
||||
import apiError from '../../../../../website/server/libs/apiError';
|
||||
|
||||
describe('GET /coupons/', () => {
|
||||
let user;
|
||||
@@ -19,7 +19,7 @@ describe('GET /coupons/', () => {
|
||||
await expect(user.get('/coupons')).to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
error: 'NotAuthorized',
|
||||
message: apiMessages('noSudoAccess'),
|
||||
message: apiError('noSudoAccess'),
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
resetHabiticaDB,
|
||||
} from '../../../../helpers/api-v3-integration.helper';
|
||||
import couponCode from 'coupon-code';
|
||||
import apiMessages from '../../../../../website/server/libs/apiMessages';
|
||||
import apiError from '../../../../../website/server/libs/apiError';
|
||||
|
||||
describe('POST /coupons/generate/:event', () => {
|
||||
let user;
|
||||
@@ -26,7 +26,7 @@ describe('POST /coupons/generate/:event', () => {
|
||||
await expect(user.post('/coupons/generate/aaa')).to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
error: 'NotAuthorized',
|
||||
message: apiMessages('noSudoAccess'),
|
||||
message: apiError('noSudoAccess'),
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
import {
|
||||
TAVERN_ID,
|
||||
} from '../../../../../website/server/models/group';
|
||||
import apiMessages from '../../../../../website/server/libs/apiMessages';
|
||||
import apiError from '../../../../../website/server/libs/apiError';
|
||||
|
||||
describe('GET /groups', () => {
|
||||
let user;
|
||||
@@ -167,7 +167,7 @@ describe('GET /groups', () => {
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: apiMessages('guildsOnlyPaginate'),
|
||||
message: apiError('guildsOnlyPaginate'),
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
import {
|
||||
generateUser,
|
||||
translate as t,
|
||||
} from '../../../../../helpers/api-integration/v3';
|
||||
import paypalPayments from '../../../../../../website/server/libs/payments/paypal';
|
||||
import apiError from '../../../../../../website/server/libs/apiError';
|
||||
|
||||
describe('payments : paypal #checkoutSuccess', () => {
|
||||
let endpoint = '/paypal/checkout/success';
|
||||
@@ -17,7 +17,7 @@ describe('payments : paypal #checkoutSuccess', () => {
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('missingPaymentId'),
|
||||
message: apiError('missingPaymentId'),
|
||||
});
|
||||
});
|
||||
|
||||
@@ -26,7 +26,7 @@ describe('payments : paypal #checkoutSuccess', () => {
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('missingCustomerId'),
|
||||
message: apiError('missingCustomerId'),
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import {
|
||||
generateUser,
|
||||
translate as t,
|
||||
} from '../../../../../helpers/api-integration/v3';
|
||||
import paypalPayments from '../../../../../../website/server/libs/payments/paypal';
|
||||
import shared from '../../../../../../website/common';
|
||||
import apiError from '../../../../../../website/server/libs/apiError';
|
||||
|
||||
describe('payments : paypal #subscribe', () => {
|
||||
let endpoint = '/paypal/subscribe';
|
||||
@@ -17,7 +17,7 @@ describe('payments : paypal #subscribe', () => {
|
||||
await expect(user.get(endpoint)).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('missingSubKey'),
|
||||
message: apiError('missingSubKey'),
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
generateUser,
|
||||
translate as t,
|
||||
} from '../../../../../helpers/api-integration/v3';
|
||||
import apiError from '../../../../../../website/server/libs/apiError';
|
||||
import paypalPayments from '../../../../../../website/server/libs/payments/paypal';
|
||||
|
||||
describe('payments : paypal #subscribeSuccess', () => {
|
||||
@@ -16,7 +16,7 @@ describe('payments : paypal #subscribeSuccess', () => {
|
||||
await expect(user.get(endpoint)).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('missingPaypalBlock'),
|
||||
message: apiError('missingPaypalBlock'),
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
import { v4 as generateUUID } from 'uuid';
|
||||
import { quests as questScrolls } from '../../../../../website/common/script/content';
|
||||
import { model as Chat } from '../../../../../website/server/models/chat';
|
||||
import apiError from '../../../../../website/server/libs/apiError';
|
||||
|
||||
describe('POST /groups/:groupId/quests/invite/:questKey', () => {
|
||||
let questingGroup;
|
||||
@@ -69,7 +70,7 @@ describe('POST /groups/:groupId/quests/invite/:questKey', () => {
|
||||
await expect(leader.post(`/groups/${questingGroup._id}/quests/invite/${FAKE_QUEST}`)).to.eventually.be.rejected.and.eql({
|
||||
code: 404,
|
||||
error: 'NotFound',
|
||||
message: t('questNotFound', {key: FAKE_QUEST}),
|
||||
message: apiError('questNotFound', {key: FAKE_QUEST}),
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
+47
@@ -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]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
|
||||
import { v4 as generateUUID } from 'uuid';
|
||||
import { find } from 'lodash';
|
||||
import apiError from '../../../../../website/server/libs/apiError';
|
||||
|
||||
describe('POST /user/class/cast/:spellId', () => {
|
||||
let user;
|
||||
@@ -24,7 +25,7 @@ describe('POST /user/class/cast/:spellId', () => {
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 404,
|
||||
error: 'NotFound',
|
||||
message: t('spellNotFound', {spellId}),
|
||||
message: apiError('spellNotFound', {spellId}),
|
||||
});
|
||||
});
|
||||
|
||||
@@ -34,7 +35,7 @@ describe('POST /user/class/cast/:spellId', () => {
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 404,
|
||||
error: 'NotFound',
|
||||
message: t('spellNotFound', {spellId}),
|
||||
message: apiError('spellNotFound', {spellId}),
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
translate as t,
|
||||
} from '../../../../../helpers/api-integration/v3';
|
||||
import shared from '../../../../../../website/common/script';
|
||||
import apiError from '../../../../../../website/server/libs/apiError';
|
||||
|
||||
let content = shared.content;
|
||||
|
||||
@@ -24,7 +25,7 @@ describe('POST /user/buy/:key', () => {
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 404,
|
||||
error: 'NotFound',
|
||||
message: t('itemNotFound', {key: 'notExisting'}),
|
||||
message: apiError('itemNotFound', {key: 'notExisting'}),
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
import {
|
||||
generateUser,
|
||||
translate as t,
|
||||
} from '../../../../../helpers/api-integration/v3';
|
||||
import apiError from '../../../../../../website/server/libs/apiError';
|
||||
|
||||
describe('POST /user/buy-gear/:key', () => {
|
||||
let user;
|
||||
@@ -21,7 +21,7 @@ describe('POST /user/buy-gear/:key', () => {
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 404,
|
||||
error: 'NotFound',
|
||||
message: t('itemNotFound', {key: 'notExisting'}),
|
||||
message: apiError('itemNotFound', {key: 'notExisting'}),
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
translate as t,
|
||||
} from '../../../../../helpers/api-integration/v3';
|
||||
import shared from '../../../../../../website/common/script';
|
||||
import apiError from '../../../../../../website/server/libs/apiError';
|
||||
|
||||
let content = shared.content;
|
||||
|
||||
@@ -20,7 +21,7 @@ describe('POST /user/buy-quest/:key', () => {
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 404,
|
||||
error: 'NotFound',
|
||||
message: t('questNotFound', {key: 'notExisting'}),
|
||||
message: apiError('questNotFound', {key: 'notExisting'}),
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
translate as t,
|
||||
} from '../../../../../helpers/api-integration/v3';
|
||||
import shared from '../../../../../../website/common/script';
|
||||
import apiError from '../../../../../../website/server/libs/apiError';
|
||||
|
||||
let content = shared.content;
|
||||
|
||||
@@ -20,7 +21,7 @@ describe('POST /user/buy-special-spell/:key', () => {
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 404,
|
||||
error: 'NotFound',
|
||||
message: t('spellNotFound', {spellId: 'notExisting'}),
|
||||
message: apiError('spellNotFound', {spellId: 'notExisting'}),
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
generateUser,
|
||||
translate as t,
|
||||
} from '../../../../../helpers/api-integration/v3';
|
||||
import apiError from '../../../../../../website/server/libs/apiError';
|
||||
|
||||
describe('POST /user/allocate', () => {
|
||||
let user;
|
||||
@@ -17,7 +18,7 @@ describe('POST /user/allocate', () => {
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('invalidAttribute', {attr: 'invalid'}),
|
||||
message: apiError('invalidAttribute', {attr: 'invalid'}),
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
translate as t,
|
||||
} from '../../../../helpers/api-integration/v3';
|
||||
import { v4 as generateUUID } from 'uuid';
|
||||
import apiError from '../../../../../website/server/libs/apiError';
|
||||
|
||||
describe('POST /user/webhook', () => {
|
||||
let user, body;
|
||||
@@ -116,6 +117,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 +128,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 +138,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 +149,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 +161,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,
|
||||
@@ -200,7 +206,7 @@ describe('POST /user/webhook', () => {
|
||||
await expect(user.post('/user/webhook', body)).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('groupIdRequired'),
|
||||
message: apiError('groupIdRequired'),
|
||||
});
|
||||
});
|
||||
|
||||
@@ -218,4 +224,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({});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
translate as t,
|
||||
} from '../../../../helpers/api-integration/v3';
|
||||
import { v4 as generateUUID} from 'uuid';
|
||||
import apiError from '../../../../../website/server/libs/apiError';
|
||||
|
||||
describe('PUT /user/webhook/:id', () => {
|
||||
let user, webhookToUpdate;
|
||||
@@ -95,6 +96,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,
|
||||
@@ -126,7 +128,7 @@ describe('PUT /user/webhook/:id', () => {
|
||||
await expect(user.put(`/user/webhook/${webhookToUpdate.id}`, {type, options})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('groupIdRequired'),
|
||||
message: apiError('groupIdRequired'),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import apiMessages from '../../../../../website/server/libs/apiMessages';
|
||||
import apiError from '../../../../../website/server/libs/apiError';
|
||||
|
||||
describe('API Messages', () => {
|
||||
const message = 'Only public guilds support pagination.';
|
||||
it('returns an API message', () => {
|
||||
expect(apiMessages('guildsOnlyPaginate')).to.equal(message);
|
||||
expect(apiError('guildsOnlyPaginate')).to.equal(message);
|
||||
});
|
||||
|
||||
it('throws if the API message does not exist', () => {
|
||||
expect(() => apiMessages('iDoNotExist')).to.throw;
|
||||
expect(() => apiError('iDoNotExist')).to.throw;
|
||||
});
|
||||
|
||||
it('clones the passed variables', () => {
|
||||
let vars = {a: 1};
|
||||
sandbox.stub(_, 'clone').returns({});
|
||||
apiMessages('guildsOnlyPaginate', vars);
|
||||
apiError('guildsOnlyPaginate', vars);
|
||||
expect(_.clone).to.have.been.calledOnce;
|
||||
expect(_.clone).to.have.been.calledWith(vars);
|
||||
});
|
||||
@@ -22,7 +22,7 @@ describe('API Messages', () => {
|
||||
let vars = {a: 1};
|
||||
let stub = sinon.stub().returns('string');
|
||||
sandbox.stub(_, 'template').returns(stub);
|
||||
apiMessages('guildsOnlyPaginate', vars);
|
||||
apiError('guildsOnlyPaginate', vars);
|
||||
expect(_.template).to.have.been.calledOnce;
|
||||
expect(_.template).to.have.been.calledWith(message);
|
||||
expect(stub).to.have.been.calledOnce;
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
@@ -15,7 +15,7 @@ describe('auth middleware', () => {
|
||||
|
||||
describe('auth with headers', () => {
|
||||
it('allows to specify a list of user field that we do not want to load', (done) => {
|
||||
const authWithHeaders = authWithHeadersFactory(false, {
|
||||
const authWithHeaders = authWithHeadersFactory({
|
||||
userFieldsToExclude: ['items', 'flags', 'auth.timestamps'],
|
||||
});
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
import i18n from '../../../../../website/common/script/i18n';
|
||||
import { ensureAdmin, ensureSudo } from '../../../../../website/server/middlewares/ensureAccessRight';
|
||||
import { NotAuthorized } from '../../../../../website/server/libs/errors';
|
||||
import apiMessages from '../../../../../website/server/libs/apiMessages';
|
||||
import apiError from '../../../../../website/server/libs/apiError';
|
||||
|
||||
describe('ensure access middlewares', () => {
|
||||
let res, req, next;
|
||||
@@ -46,7 +46,7 @@ describe('ensure access middlewares', () => {
|
||||
ensureSudo(req, res, next);
|
||||
|
||||
const calledWith = next.getCall(0).args;
|
||||
expect(calledWith[0].message).to.equal(apiMessages('noSudoAccess'));
|
||||
expect(calledWith[0].message).to.equal(apiError('noSudoAccess'));
|
||||
expect(calledWith[0] instanceof NotAuthorized).to.equal(true);
|
||||
});
|
||||
|
||||
|
||||
@@ -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',
|
||||
@@ -1389,6 +1393,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;
|
||||
@@ -1770,6 +1815,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;
|
||||
|
||||
@@ -1885,7 +1966,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);
|
||||
@@ -1949,9 +2030,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;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { model as Webhook } from '../../../../../website/server/models/webhook';
|
||||
import { BadRequest } from '../../../../../website/server/libs/errors';
|
||||
import { v4 as generateUUID } from 'uuid';
|
||||
import apiError from '../../../../../website/server/libs/apiError';
|
||||
|
||||
describe('Webhook Model', () => {
|
||||
context('Instance Methods', () => {
|
||||
@@ -24,6 +25,7 @@ describe('Webhook Model', () => {
|
||||
updated: true,
|
||||
deleted: true,
|
||||
scored: true,
|
||||
checklistScored: true,
|
||||
},
|
||||
};
|
||||
});
|
||||
@@ -36,6 +38,7 @@ describe('Webhook Model', () => {
|
||||
wh.formatOptions(res);
|
||||
|
||||
expect(wh.options).to.eql({
|
||||
checklistScored: false,
|
||||
created: false,
|
||||
updated: false,
|
||||
deleted: false,
|
||||
@@ -51,6 +54,7 @@ describe('Webhook Model', () => {
|
||||
wh.formatOptions(res);
|
||||
|
||||
expect(wh.options).to.eql({
|
||||
checklistScored: true,
|
||||
created: false,
|
||||
updated: true,
|
||||
deleted: true,
|
||||
@@ -67,6 +71,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 +79,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';
|
||||
|
||||
@@ -135,12 +288,36 @@ describe('Webhook Model', () => {
|
||||
wh.formatOptions(res);
|
||||
} catch (err) {
|
||||
expect(err).to.be.an.instanceOf(BadRequest);
|
||||
expect(res.t).to.be.calledOnce;
|
||||
expect(res.t).to.be.calledWith('groupIdRequired');
|
||||
|
||||
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';
|
||||
|
||||
let wh = new Webhook(config);
|
||||
|
||||
wh.formatOptions(res);
|
||||
|
||||
expect(wh.options.foo).to.not.exist;
|
||||
expect(wh.options).to.eql({});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user