mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-15 05:37:22 +01:00
314 lines
7.7 KiB
JavaScript
314 lines
7.7 KiB
JavaScript
import { v4 as generateUUID } from 'uuid';
|
|
import {
|
|
generateUser,
|
|
translate as t,
|
|
} from '../../../../helpers/api-integration/v3';
|
|
import { apiError } from '../../../../../website/server/libs/apiError';
|
|
|
|
describe('POST /user/webhook', () => {
|
|
let user; let
|
|
body;
|
|
|
|
beforeEach(async () => {
|
|
user = await generateUser();
|
|
body = {
|
|
id: generateUUID(),
|
|
url: 'https://example.com/endpoint',
|
|
type: 'taskActivity',
|
|
enabled: false,
|
|
};
|
|
});
|
|
|
|
it('requires a url', async () => {
|
|
delete body.url;
|
|
|
|
await expect(user.post('/user/webhook', body)).to.eventually.be.rejected.and.eql({
|
|
code: 400,
|
|
error: 'BadRequest',
|
|
message: 'User validation failed',
|
|
});
|
|
});
|
|
|
|
it('requires custom id to be a uuid', async () => {
|
|
body.id = 'not-a-uuid';
|
|
|
|
await expect(user.post('/user/webhook', body)).to.eventually.be.rejected.and.eql({
|
|
code: 400,
|
|
error: 'BadRequest',
|
|
message: 'User validation failed',
|
|
});
|
|
});
|
|
|
|
it('defaults id to a uuid', async () => {
|
|
delete body.id;
|
|
|
|
const webhook = await user.post('/user/webhook', body);
|
|
|
|
expect(webhook.id).to.exist;
|
|
});
|
|
|
|
it('requires type to be of an accetable type', async () => {
|
|
body.type = 'not a valid type';
|
|
|
|
await expect(user.post('/user/webhook', body)).to.eventually.be.rejected.and.eql({
|
|
code: 400,
|
|
error: 'BadRequest',
|
|
message: 'User validation failed',
|
|
});
|
|
});
|
|
|
|
it('defaults enabled to true', async () => {
|
|
delete body.enabled;
|
|
|
|
const webhook = await user.post('/user/webhook', body);
|
|
|
|
expect(webhook.enabled).to.be.true;
|
|
});
|
|
|
|
it('can pass a label', async () => {
|
|
body.label = 'Custom Label';
|
|
|
|
const webhook = await user.post('/user/webhook', body);
|
|
|
|
expect(webhook.label).to.equal('Custom Label');
|
|
});
|
|
|
|
it('defaults type to taskActivity', async () => {
|
|
delete body.type;
|
|
|
|
const webhook = await user.post('/user/webhook', body);
|
|
|
|
expect(webhook.type).to.eql('taskActivity');
|
|
});
|
|
|
|
it('ignores protected fields', async () => {
|
|
body.failures = 3;
|
|
body.lastFailureAt = new Date();
|
|
|
|
const webhook = await user.post('/user/webhook', body);
|
|
|
|
expect(webhook.failures).to.eql(0);
|
|
expect(webhook.lastFailureAt).to.eql(undefined);
|
|
});
|
|
|
|
it('successfully adds the webhook', async () => {
|
|
expect(user.webhooks).to.eql([]);
|
|
|
|
const response = await user.post('/user/webhook', body);
|
|
|
|
expect(response.id).to.eql(body.id);
|
|
expect(response.type).to.eql(body.type);
|
|
expect(response.url).to.eql(body.url);
|
|
expect(response.enabled).to.eql(body.enabled);
|
|
|
|
await user.sync();
|
|
|
|
expect(user.webhooks).to.not.eql([]);
|
|
|
|
const webhook = user.webhooks[0];
|
|
|
|
expect(webhook.enabled).to.be.false;
|
|
expect(webhook.type).to.eql('taskActivity');
|
|
expect(webhook.url).to.eql(body.url);
|
|
});
|
|
|
|
it('cannot use an id of a webhook that already exists', async () => {
|
|
await user.post('/user/webhook', body);
|
|
|
|
await expect(user.post('/user/webhook', body)).to.eventually.be.rejected.and.eql({
|
|
code: 400,
|
|
error: 'BadRequest',
|
|
message: t('webhookIdAlreadyTaken', { id: body.id }),
|
|
});
|
|
});
|
|
|
|
it('defaults taskActivity options', async () => {
|
|
body.type = 'taskActivity';
|
|
|
|
const webhook = await user.post('/user/webhook', body);
|
|
|
|
expect(webhook.options).to.eql({
|
|
checklistScored: false,
|
|
created: false,
|
|
updated: false,
|
|
deleted: false,
|
|
scored: true,
|
|
});
|
|
});
|
|
|
|
it('can set taskActivity options', async () => {
|
|
body.type = 'taskActivity';
|
|
body.options = {
|
|
checklistScored: true,
|
|
created: true,
|
|
updated: true,
|
|
deleted: true,
|
|
scored: false,
|
|
};
|
|
|
|
const webhook = await user.post('/user/webhook', body);
|
|
|
|
expect(webhook.options).to.eql({
|
|
checklistScored: true,
|
|
created: true,
|
|
updated: true,
|
|
deleted: true,
|
|
scored: false,
|
|
});
|
|
});
|
|
|
|
it('discards extra properties in taskActivity options', async () => {
|
|
body.type = 'taskActivity';
|
|
body.options = {
|
|
checklistScored: false,
|
|
created: true,
|
|
updated: true,
|
|
deleted: true,
|
|
scored: false,
|
|
foo: 'bar',
|
|
};
|
|
|
|
const webhook = await user.post('/user/webhook', body);
|
|
|
|
expect(webhook.options.foo).to.not.exist;
|
|
expect(webhook.options).to.eql({
|
|
checklistScored: false,
|
|
created: true,
|
|
updated: true,
|
|
deleted: true,
|
|
scored: false,
|
|
});
|
|
});
|
|
|
|
['created', 'updated', 'deleted', 'scored'].forEach(option => {
|
|
it(`requires taskActivity option ${option} to be a boolean`, async () => {
|
|
body.type = 'taskActivity';
|
|
body.options = {
|
|
[option]: 'not a boolean',
|
|
};
|
|
|
|
await expect(user.post('/user/webhook', body)).to.eventually.be.rejected.and.eql({
|
|
code: 400,
|
|
error: 'BadRequest',
|
|
message: t('webhookBooleanOption', { option }),
|
|
});
|
|
});
|
|
});
|
|
|
|
it('can set groupChatReceived options', async () => {
|
|
body.type = 'groupChatReceived';
|
|
body.options = {
|
|
groupId: generateUUID(),
|
|
};
|
|
|
|
const webhook = await user.post('/user/webhook', body);
|
|
|
|
expect(webhook.options).to.eql({
|
|
groupId: body.options.groupId,
|
|
});
|
|
});
|
|
|
|
it('groupChatReceived options requires a uuid for the groupId', async () => {
|
|
body.type = 'groupChatReceived';
|
|
body.options = {
|
|
groupId: 'not-a-uuid',
|
|
};
|
|
|
|
await expect(user.post('/user/webhook', body)).to.eventually.be.rejected.and.eql({
|
|
code: 400,
|
|
error: 'BadRequest',
|
|
message: apiError('groupIdRequired'),
|
|
});
|
|
});
|
|
|
|
it('discards extra properties in groupChatReceived options', async () => {
|
|
body.type = 'groupChatReceived';
|
|
body.options = {
|
|
groupId: generateUUID(),
|
|
foo: 'bar',
|
|
};
|
|
|
|
const webhook = await user.post('/user/webhook', body);
|
|
|
|
expect(webhook.options.foo).to.not.exist;
|
|
expect(webhook.options).to.eql({
|
|
groupId: body.options.groupId,
|
|
});
|
|
});
|
|
|
|
it('defaults questActivity options', async () => {
|
|
body.type = 'questActivity';
|
|
|
|
const webhook = await user.post('/user/webhook', body);
|
|
|
|
expect(webhook.options).to.eql({
|
|
questStarted: false,
|
|
questFinished: false,
|
|
questInvited: false,
|
|
});
|
|
});
|
|
|
|
it('can set questActivity options', async () => {
|
|
body.type = 'questActivity';
|
|
body.options = {
|
|
questStarted: true,
|
|
questFinished: true,
|
|
questInvited: true,
|
|
};
|
|
|
|
const webhook = await user.post('/user/webhook', body);
|
|
|
|
expect(webhook.options).to.eql({
|
|
questStarted: true,
|
|
questFinished: true,
|
|
questInvited: true,
|
|
});
|
|
});
|
|
|
|
it('discards extra properties in questActivity options', async () => {
|
|
body.type = 'questActivity';
|
|
body.options = {
|
|
questStarted: false,
|
|
questFinished: true,
|
|
questInvited: true,
|
|
foo: 'bar',
|
|
};
|
|
|
|
const webhook = await user.post('/user/webhook', body);
|
|
|
|
expect(webhook.options.foo).to.not.exist;
|
|
expect(webhook.options).to.eql({
|
|
questStarted: false,
|
|
questFinished: true,
|
|
questInvited: true,
|
|
});
|
|
});
|
|
|
|
['questStarted', 'questFinished', 'questInvited'].forEach(option => {
|
|
it(`requires questActivity option ${option} to be a boolean`, async () => {
|
|
body.type = 'questActivity';
|
|
body.options = {
|
|
[option]: 'not a boolean',
|
|
};
|
|
|
|
await expect(user.post('/user/webhook', body)).to.eventually.be.rejected.and.eql({
|
|
code: 400,
|
|
error: 'BadRequest',
|
|
message: t('webhookBooleanOption', { option }),
|
|
});
|
|
});
|
|
});
|
|
|
|
it('discards extra properties in globalActivity options', async () => {
|
|
body.type = 'globalActivity';
|
|
body.options = {
|
|
foo: 'bar',
|
|
};
|
|
|
|
const webhook = await user.post('/user/webhook', body);
|
|
|
|
expect(webhook.options.foo).to.not.exist;
|
|
expect(webhook.options).to.eql({});
|
|
});
|
|
});
|