mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-19 15:48:04 +01:00
Merge branch 'api-v3' into sabrecat/v3-payments
This commit is contained in:
@@ -236,7 +236,7 @@ describe('POST /challenges', () => {
|
||||
official: true,
|
||||
});
|
||||
|
||||
expect(challenge.official).to.be.undefined;
|
||||
expect(challenge.official).to.eql(false);
|
||||
});
|
||||
|
||||
it('returns an error when challenge validation fails; doesn\'s save user or group', async () => {
|
||||
@@ -284,7 +284,7 @@ describe('POST /challenges', () => {
|
||||
expect(challenge.name).to.eql(name);
|
||||
expect(challenge.shortName).to.eql(shortName);
|
||||
expect(challenge.description).to.eql(description);
|
||||
expect(challenge.official).to.be.undefined;
|
||||
expect(challenge.official).to.eql(false);
|
||||
expect(challenge.group).to.eql({
|
||||
_id: group._id,
|
||||
privacy: group.privacy,
|
||||
|
||||
@@ -44,6 +44,15 @@ describe('POST /group/:groupId/join', () => {
|
||||
expect(res.leader.profile.name).to.eql(user.profile.name);
|
||||
});
|
||||
|
||||
it('returns an error is user was already a member', async () => {
|
||||
await joiningUser.post(`/groups/${publicGuild._id}/join`);
|
||||
await expect(joiningUser.post(`/groups/${publicGuild._id}/join`)).to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
error: 'NotAuthorized',
|
||||
message: t('userAlreadyInGroup'),
|
||||
});
|
||||
});
|
||||
|
||||
it('promotes joining member in a public empty guild to leader', async () => {
|
||||
await user.post(`/groups/${publicGuild._id}/leave`);
|
||||
|
||||
|
||||
@@ -36,6 +36,6 @@ describe('POST /user/allocate', () => {
|
||||
await user.sync();
|
||||
expect(user.stats.con).to.equal(1);
|
||||
expect(user.stats.points).to.equal(0);
|
||||
expect(res.stats.con).to.equal(1);
|
||||
expect(res.con).to.equal(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -18,11 +18,7 @@ describe('POST /user/allocate-now', () => {
|
||||
let res = await user.post('/user/allocate-now');
|
||||
await user.sync();
|
||||
|
||||
expect(res).to.eql({
|
||||
data: {
|
||||
stats: user.stats,
|
||||
},
|
||||
});
|
||||
expect(res).to.eql(user.stats);
|
||||
expect(user.stats.points).to.equal(0);
|
||||
expect(user.stats.con).to.equal(9);
|
||||
expect(user.stats.int).to.equal(8);
|
||||
|
||||
@@ -36,9 +36,7 @@ describe('POST /user/buy/:key', () => {
|
||||
await user.sync();
|
||||
|
||||
expect(user.stats.hp).to.equal(50);
|
||||
expect(res.data).to.eql({
|
||||
stats: user.stats,
|
||||
});
|
||||
expect(res.data).to.eql(user.stats);
|
||||
expect(res.message).to.equal(t('messageBought', {itemText: potion.text()}));
|
||||
});
|
||||
|
||||
|
||||
@@ -31,11 +31,7 @@ describe('POST /user/buy-mystery-set/:key', () => {
|
||||
|
||||
expect(res.data).to.eql({
|
||||
items: JSON.parse(JSON.stringify(user.items)), // otherwise dates can't be compared
|
||||
purchased: {
|
||||
plan: {
|
||||
consecutive: user.purchased.plan.consecutive,
|
||||
},
|
||||
},
|
||||
purchasedPlanConsecutive: user.purchased.plan.consecutive,
|
||||
});
|
||||
expect(res.message).to.equal(t('hourglassPurchaseSet'));
|
||||
});
|
||||
|
||||
@@ -36,9 +36,7 @@ describe('POST /user/buy-potion', () => {
|
||||
await user.sync();
|
||||
|
||||
expect(user.stats.hp).to.equal(50);
|
||||
expect(res.data).to.eql({
|
||||
stats: user.stats,
|
||||
});
|
||||
expect(res.data).to.eql(user.stats);
|
||||
expect(res.message).to.equal(t('messageBought', {itemText: potion.text()}));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -18,13 +18,13 @@ describe('POST /user/change-class', () => {
|
||||
let res = await user.post('/user/change-class?class=rogue');
|
||||
await user.sync();
|
||||
|
||||
expect(res).to.eql({
|
||||
data: JSON.parse(JSON.stringify({
|
||||
expect(res).to.eql(JSON.parse(
|
||||
JSON.stringify({
|
||||
preferences: user.preferences,
|
||||
stats: user.stats,
|
||||
flags: user.flags,
|
||||
items: user.items,
|
||||
})),
|
||||
});
|
||||
})
|
||||
));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,12 +15,12 @@ describe('POST /user/disable-classes', () => {
|
||||
let res = await user.post('/user/disable-classes');
|
||||
await user.sync();
|
||||
|
||||
expect(res).to.eql({
|
||||
data: JSON.parse(JSON.stringify({
|
||||
expect(res).to.eql(JSON.parse(
|
||||
JSON.stringify({
|
||||
preferences: user.preferences,
|
||||
stats: user.stats,
|
||||
flags: user.flags,
|
||||
})),
|
||||
});
|
||||
})
|
||||
));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -35,8 +35,6 @@ describe('POST /user/equip/:type/:key', () => {
|
||||
let res = await user.post('/user/equip/equipped/weapon_warrior_2');
|
||||
await user.sync();
|
||||
|
||||
expect(res).to.eql({
|
||||
data: JSON.parse(JSON.stringify(user.items)),
|
||||
});
|
||||
expect(res).to.eql(JSON.parse(JSON.stringify(user.items)));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,16 +13,12 @@ describe('POST /user/sleep', () => {
|
||||
|
||||
it('toggles sleep status', async () => {
|
||||
let res = await user.post('/user/sleep');
|
||||
expect(res).to.eql({
|
||||
preferences: {sleep: true},
|
||||
});
|
||||
expect(res).to.eql(true);
|
||||
await user.sync();
|
||||
expect(user.preferences.sleep).to.be.true;
|
||||
|
||||
let res2 = await user.post('/user/sleep');
|
||||
expect(res2).to.eql({
|
||||
preferences: {sleep: false},
|
||||
});
|
||||
expect(res2).to.eql(false);
|
||||
await user.sync();
|
||||
expect(user.preferences.sleep).to.be.false;
|
||||
});
|
||||
|
||||
@@ -16,7 +16,7 @@ describe('POST /user/reset-password', async () => {
|
||||
let response = await user.post(endpoint, {
|
||||
email: user.auth.local.email,
|
||||
});
|
||||
expect(response).to.eql({ message: t('passwordReset') });
|
||||
expect(response).to.eql({ data: {}, message: t('passwordReset') });
|
||||
await user.sync();
|
||||
expect(user.auth.local.hashed_password).to.not.eql(previousPassword);
|
||||
});
|
||||
@@ -25,7 +25,7 @@ describe('POST /user/reset-password', async () => {
|
||||
let response = await user.post(endpoint, {
|
||||
email: 'nonExistent@email.com',
|
||||
});
|
||||
expect(response).to.eql({ message: t('passwordReset') });
|
||||
expect(response).to.eql({ data: {}, message: t('passwordReset') });
|
||||
});
|
||||
|
||||
it('errors if email is not provided', async () => {
|
||||
@@ -36,4 +36,3 @@ describe('POST /user/reset-password', async () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
573
test/api/v3/unit/libs/cron.test.js
Normal file
573
test/api/v3/unit/libs/cron.test.js
Normal file
@@ -0,0 +1,573 @@
|
||||
/* eslint-disable global-require */
|
||||
import moment from 'moment';
|
||||
import { cron } from '../../../../../website/src/libs/api-v3/cron';
|
||||
import { model as User } from '../../../../../website/src/models/user';
|
||||
import * as Tasks from '../../../../../website/src/models/task';
|
||||
import { clone } from 'lodash';
|
||||
import common from '../../../../../common';
|
||||
|
||||
// const scoreTask = common.ops.scoreTask;
|
||||
|
||||
describe('cron', () => {
|
||||
let user;
|
||||
let tasksByType = {habits: [], dailys: [], todos: [], rewards: []};
|
||||
let daysMissed = 0;
|
||||
let analytics = {
|
||||
track: sinon.spy(),
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
user = new User({
|
||||
auth: {
|
||||
local: {
|
||||
username: 'username',
|
||||
lowerCaseUsername: 'username',
|
||||
email: 'email@email.email',
|
||||
salt: 'salt',
|
||||
hashed_password: 'hashed_password', // eslint-disable-line camelcase
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
user._statsComputed = {
|
||||
mp: 10,
|
||||
};
|
||||
});
|
||||
|
||||
it('updates user.auth.timestamps.loggedin and lastCron', () => {
|
||||
let now = new Date();
|
||||
|
||||
cron({user, tasksByType, daysMissed, analytics, now});
|
||||
|
||||
expect(user.auth.timestamps.loggedin).to.equal(now);
|
||||
expect(user.lastCron).to.equal(now);
|
||||
});
|
||||
|
||||
it('updates user.preferences.timezoneOffsetAtLastCron', () => {
|
||||
let timezoneOffsetFromUserPrefs = 1;
|
||||
|
||||
cron({user, tasksByType, daysMissed, analytics, timezoneOffsetFromUserPrefs});
|
||||
|
||||
expect(user.preferences.timezoneOffsetAtLastCron).to.equal(timezoneOffsetFromUserPrefs);
|
||||
});
|
||||
|
||||
it('resets user.items.lastDrop.count', () => {
|
||||
user.items.lastDrop.count = 4;
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(user.items.lastDrop.count).to.equal(0);
|
||||
});
|
||||
|
||||
it('increments user cron count', () => {
|
||||
let cronCountBefore = user.flags.cronCount;
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(user.flags.cronCount).to.be.greaterThan(cronCountBefore);
|
||||
});
|
||||
|
||||
describe('end of the month perks', () => {
|
||||
beforeEach(() => {
|
||||
user.purchased.plan.customerId = 'subscribedId';
|
||||
user.purchased.plan.dateUpdated = moment('012013', 'MMYYYY');
|
||||
});
|
||||
|
||||
it('resets plan.gemsBought on a new month', () => {
|
||||
user.purchased.plan.gemsBought = 10;
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(user.purchased.plan.gemsBought).to.equal(0);
|
||||
});
|
||||
|
||||
it('resets plan.dateUpdated on a new month', () => {
|
||||
let currentMonth = moment().format('MMYYYY');
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(moment(user.purchased.plan.dateUpdated).format('MMYYYY')).to.equal(currentMonth);
|
||||
});
|
||||
|
||||
it('increments plan.consecutive.count', () => {
|
||||
user.purchased.plan.consecutive.count = 0;
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(user.purchased.plan.consecutive.count).to.equal(1);
|
||||
});
|
||||
|
||||
it('decrements plan.consecutive.offset when offset is greater than 0', () => {
|
||||
user.purchased.plan.consecutive.offset = 1;
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(user.purchased.plan.consecutive.offset).to.equal(0);
|
||||
});
|
||||
|
||||
it('increments plan.consecutive.trinkets when user has reached a month that is a multiple of 3', () => {
|
||||
user.purchased.plan.consecutive.count = 5;
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.equal(1);
|
||||
});
|
||||
|
||||
it('increments plan.consecutive.gemCapExtra when user has reached a month that is a multiple of 3', () => {
|
||||
user.purchased.plan.consecutive.count = 5;
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.equal(5);
|
||||
});
|
||||
|
||||
it('does not increment plan.consecutive.gemCapExtra when user has reached the gemCap limit', () => {
|
||||
user.purchased.plan.consecutive.gemCapExtra = 25;
|
||||
user.purchased.plan.consecutive.count = 5;
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.equal(25);
|
||||
});
|
||||
|
||||
it('does not reset plan stats if we are before the last day of the cancelled month', () => {
|
||||
user.purchased.plan.dateTerminated = moment(new Date()).add({days: 1});
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(user.purchased.plan.customerId).to.exist;
|
||||
});
|
||||
|
||||
it('does reset plan stats until we are after the last day of the cancelled month', () => {
|
||||
user.purchased.plan.dateTerminated = moment(new Date()).subtract({days: 1});
|
||||
user.purchased.plan.consecutive.gemCapExtra = 20;
|
||||
user.purchased.plan.consecutive.count = 5;
|
||||
user.purchased.plan.consecutive.offset = 1;
|
||||
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(user.purchased.plan.customerId).to.not.exist;
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.be.empty;
|
||||
expect(user.purchased.plan.consecutive.count).to.be.empty;
|
||||
expect(user.purchased.plan.consecutive.offset).to.be.empty;
|
||||
});
|
||||
});
|
||||
|
||||
describe('end of the month perks when user is not subscribed', () => {
|
||||
it('does not reset plan.gemsBought on a new month', () => {
|
||||
user.purchased.plan.gemsBought = 10;
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(user.purchased.plan.gemsBought).to.equal(10);
|
||||
});
|
||||
|
||||
it('does not reset plan.dateUpdated on a new month', () => {
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(user.purchased.plan.dateUpdated).to.be.empty;
|
||||
});
|
||||
|
||||
it('does not increment plan.consecutive.count', () => {
|
||||
user.purchased.plan.consecutive.count = 0;
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(user.purchased.plan.consecutive.count).to.equal(0);
|
||||
});
|
||||
|
||||
it('does not decrement plan.consecutive.offset when offset is greater than 0', () => {
|
||||
user.purchased.plan.consecutive.offset = 1;
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(user.purchased.plan.consecutive.offset).to.equal(1);
|
||||
});
|
||||
|
||||
it('does not increment plan.consecutive.trinkets when user has reached a month that is a multiple of 3', () => {
|
||||
user.purchased.plan.consecutive.count = 5;
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.equal(0);
|
||||
});
|
||||
|
||||
it('doest not increment plan.consecutive.gemCapExtra when user has reached a month that is a multiple of 3', () => {
|
||||
user.purchased.plan.consecutive.count = 5;
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.equal(0);
|
||||
});
|
||||
|
||||
it('does not increment plan.consecutive.gemCapExtra when user has reached the gemCap limit', () => {
|
||||
user.purchased.plan.consecutive.gemCapExtra = 25;
|
||||
user.purchased.plan.consecutive.count = 5;
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.equal(25);
|
||||
});
|
||||
|
||||
it('does nothing to plan stats if we are before the last day of the cancelled month', () => {
|
||||
user.purchased.plan.dateTerminated = moment(new Date()).add({days: 1});
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(user.purchased.plan.customerId).to.not.exist;
|
||||
});
|
||||
|
||||
xit('does nothing to plan stats when we are after the last day of the cancelled month', () => {
|
||||
user.purchased.plan.dateTerminated = moment(new Date()).subtract({days: 1});
|
||||
user.purchased.plan.consecutive.gemCapExtra = 20;
|
||||
user.purchased.plan.consecutive.count = 5;
|
||||
user.purchased.plan.consecutive.offset = 1;
|
||||
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(user.purchased.plan.customerId).to.exist;
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.exist;
|
||||
expect(user.purchased.plan.consecutive.count).to.exist;
|
||||
expect(user.purchased.plan.consecutive.offset).to.exist;
|
||||
});
|
||||
});
|
||||
|
||||
describe('user is sleeping', () => {
|
||||
beforeEach(() => {
|
||||
user.preferences.sleep = true;
|
||||
});
|
||||
|
||||
it('clears user buffs', () => {
|
||||
user.stats.buffs = {
|
||||
str: 1,
|
||||
int: 1,
|
||||
per: 1,
|
||||
con: 1,
|
||||
stealth: 1,
|
||||
streaks: true,
|
||||
};
|
||||
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(user.stats.buffs.str).to.equal(0);
|
||||
expect(user.stats.buffs.int).to.equal(0);
|
||||
expect(user.stats.buffs.per).to.equal(0);
|
||||
expect(user.stats.buffs.con).to.equal(0);
|
||||
expect(user.stats.buffs.stealth).to.equal(0);
|
||||
expect(user.stats.buffs.streaks).to.be.false;
|
||||
});
|
||||
|
||||
it('resets all dailies without damaging user', () => {
|
||||
let daily = {
|
||||
text: 'test daily',
|
||||
type: 'daily',
|
||||
frequency: 'daily',
|
||||
everyX: 5,
|
||||
startDate: new Date(),
|
||||
};
|
||||
|
||||
let task = new Tasks.daily(Tasks.Task.sanitize(daily)); // eslint-disable-line babel/new-cap
|
||||
tasksByType.dailys.push(task);
|
||||
tasksByType.dailys[0].completed = true;
|
||||
|
||||
let healthBefore = user.stats.hp;
|
||||
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(tasksByType.dailys[0].completed).to.be.false;
|
||||
expect(user.stats.hp).to.equal(healthBefore);
|
||||
});
|
||||
});
|
||||
|
||||
describe('todos', () => {
|
||||
beforeEach(() => {
|
||||
let todo = {
|
||||
text: 'test todo',
|
||||
type: 'todo',
|
||||
value: 0,
|
||||
};
|
||||
|
||||
let task = new Tasks.todo(Tasks.Task.sanitize(todo)); // eslint-disable-line babel/new-cap
|
||||
tasksByType.todos.push(task);
|
||||
});
|
||||
|
||||
it('should make uncompleted todos redder', () => {
|
||||
let valueBefore = tasksByType.todos[0].value;
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(tasksByType.todos[0].value).to.be.lessThan(valueBefore);
|
||||
});
|
||||
|
||||
it('should add history of completed todos to user history', () => {
|
||||
tasksByType.todos[0].completed = true;
|
||||
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(user.history.todos).to.be.lengthOf(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('dailys', () => {
|
||||
beforeEach(() => {
|
||||
let daily = {
|
||||
text: 'test daily',
|
||||
type: 'daily',
|
||||
};
|
||||
|
||||
let task = new Tasks.daily(Tasks.Task.sanitize(daily)); // eslint-disable-line babel/new-cap
|
||||
tasksByType.dailys = [];
|
||||
tasksByType.dailys.push(task);
|
||||
|
||||
user._statsComputed = {
|
||||
con: 1,
|
||||
};
|
||||
});
|
||||
|
||||
it('should add history', () => {
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(tasksByType.dailys[0].history).to.be.lengthOf(1);
|
||||
});
|
||||
|
||||
it('should set tasks completed to false', () => {
|
||||
tasksByType.dailys[0].completed = true;
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(tasksByType.dailys[0].completed).to.be.false;
|
||||
});
|
||||
|
||||
it('should set task checklist to completed for completed dailys', () => {
|
||||
tasksByType.dailys[0].checklist.push({title: 'test', completed: false});
|
||||
tasksByType.dailys[0].completed = true;
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(tasksByType.dailys[0].checklist[0].completed).to.be.true;
|
||||
});
|
||||
|
||||
it('should set task checklist to completed for dailys with scheduled misses', () => {
|
||||
daysMissed = 10;
|
||||
tasksByType.dailys[0].checklist.push({title: 'test', completed: false});
|
||||
tasksByType.dailys[0].startDate = moment(new Date()).subtract({days: 1});
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(tasksByType.dailys[0].checklist[0].completed).to.be.true;
|
||||
});
|
||||
|
||||
it('should do damage for missing a daily', () => {
|
||||
daysMissed = 1;
|
||||
let hpBefore = user.stats.hp;
|
||||
tasksByType.dailys[0].startDate = moment(new Date()).subtract({days: 1});
|
||||
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(user.stats.hp).to.be.lessThan(hpBefore);
|
||||
});
|
||||
|
||||
it('should not do damage for missing a daily if user stealth buff is greater than or equal to days missed', () => {
|
||||
daysMissed = 1;
|
||||
let hpBefore = user.stats.hp;
|
||||
user.stats.buffs.stealth = 2;
|
||||
tasksByType.dailys[0].startDate = moment(new Date()).subtract({days: 1});
|
||||
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(user.stats.hp).to.equal(hpBefore);
|
||||
});
|
||||
|
||||
it('should do less damage for missing a daily with partial completion', () => {
|
||||
daysMissed = 1;
|
||||
let hpBefore = user.stats.hp;
|
||||
tasksByType.dailys[0].startDate = moment(new Date()).subtract({days: 1});
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
let hpDifferenceOfFullyIncompleteDaily = hpBefore - user.stats.hp;
|
||||
|
||||
hpBefore = user.stats.hp;
|
||||
tasksByType.dailys[0].checklist.push({title: 'test', completed: true});
|
||||
tasksByType.dailys[0].checklist.push({title: 'test2', completed: false});
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
let hpDifferenceOfPartiallyIncompleteDaily = hpBefore - user.stats.hp;
|
||||
|
||||
expect(hpDifferenceOfPartiallyIncompleteDaily).to.be.lessThan(hpDifferenceOfFullyIncompleteDaily);
|
||||
});
|
||||
|
||||
it('should decrement quest progress down for missing a daily', () => {
|
||||
daysMissed = 1;
|
||||
tasksByType.dailys[0].startDate = moment(new Date()).subtract({days: 1});
|
||||
|
||||
let progress = cron({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(progress.down).to.equal(-1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('habits', () => {
|
||||
beforeEach(() => {
|
||||
let habit = {
|
||||
text: 'test habit',
|
||||
type: 'habit',
|
||||
};
|
||||
|
||||
let task = new Tasks.habit(Tasks.Task.sanitize(habit)); // eslint-disable-line babel/new-cap
|
||||
tasksByType.habits = [];
|
||||
tasksByType.habits.push(task);
|
||||
});
|
||||
|
||||
it('should decrement only up value', () => {
|
||||
tasksByType.habits[0].value = 1;
|
||||
tasksByType.habits[0].down = false;
|
||||
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(tasksByType.habits[0].value).to.be.lessThan(1);
|
||||
});
|
||||
|
||||
it('should decrement only down value', () => {
|
||||
tasksByType.habits[0].value = 1;
|
||||
tasksByType.habits[0].up = false;
|
||||
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(tasksByType.habits[0].value).to.be.lessThan(1);
|
||||
});
|
||||
|
||||
it('should do nothing to habits with both up and down', () => {
|
||||
tasksByType.habits[0].value = 1;
|
||||
tasksByType.habits[0].up = true;
|
||||
tasksByType.habits[0].down = true;
|
||||
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(tasksByType.habits[0].value).to.equal(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('perfect day', () => {
|
||||
beforeEach(() => {
|
||||
let daily = {
|
||||
text: 'test daily',
|
||||
type: 'daily',
|
||||
};
|
||||
|
||||
let task = new Tasks.daily(Tasks.Task.sanitize(daily)); // eslint-disable-line babel/new-cap
|
||||
tasksByType.dailys = [];
|
||||
tasksByType.dailys.push(task);
|
||||
|
||||
user._statsComputed = {
|
||||
con: 1,
|
||||
};
|
||||
});
|
||||
|
||||
it('stores a new entry in user.history.exp', () => {
|
||||
user.stats.lvl = 2;
|
||||
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(user.history.exp).to.have.lengthOf(1);
|
||||
expect(user.history.exp[0].value).to.equal(150);
|
||||
});
|
||||
|
||||
it('increments perfect day achievement', () => {
|
||||
tasksByType.dailys[0].completed = true;
|
||||
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(user.achievements.perfect).to.equal(1);
|
||||
});
|
||||
|
||||
it('increments user buffs if they have a perfect day', () => {
|
||||
tasksByType.dailys[0].completed = true;
|
||||
|
||||
let previousBuffs = clone(user.stats.buffs);
|
||||
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(user.stats.buffs.str).to.be.greaterThan(previousBuffs.str);
|
||||
expect(user.stats.buffs.int).to.be.greaterThan(previousBuffs.int);
|
||||
expect(user.stats.buffs.per).to.be.greaterThan(previousBuffs.per);
|
||||
expect(user.stats.buffs.con).to.be.greaterThan(previousBuffs.con);
|
||||
});
|
||||
|
||||
it('clears buffs if user does not have a perfect day', () => {
|
||||
daysMissed = 1;
|
||||
tasksByType.dailys[0].completed = false;
|
||||
tasksByType.dailys[0].startDate = moment(new Date()).subtract({days: 1});
|
||||
|
||||
user.stats.buffs = {
|
||||
str: 1,
|
||||
int: 1,
|
||||
per: 1,
|
||||
con: 1,
|
||||
stealth: 0,
|
||||
streaks: true,
|
||||
};
|
||||
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(user.stats.buffs.str).to.equal(0);
|
||||
expect(user.stats.buffs.int).to.equal(0);
|
||||
expect(user.stats.buffs.per).to.equal(0);
|
||||
expect(user.stats.buffs.con).to.equal(0);
|
||||
expect(user.stats.buffs.stealth).to.equal(0);
|
||||
expect(user.stats.buffs.streaks).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
describe('adding mp', () => {
|
||||
it('should add mp to user', () => {
|
||||
let mpBefore = user.stats.mp;
|
||||
tasksByType.dailys[0].completed = true;
|
||||
user._statsComputed.maxMP = 100;
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(user.stats.mp).to.be.greaterThan(mpBefore);
|
||||
});
|
||||
|
||||
it('set user\'s mp to user._statsComputed.maxMP when user.stats.mp is greater', () => {
|
||||
user.stats.mp = 120;
|
||||
user._statsComputed.maxMP = 100;
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(user.stats.mp).to.equal(user._statsComputed.maxMP);
|
||||
});
|
||||
});
|
||||
|
||||
describe('quest progress', () => {
|
||||
beforeEach(() => {
|
||||
let daily = {
|
||||
text: 'test daily',
|
||||
type: 'daily',
|
||||
};
|
||||
|
||||
let task = new Tasks.daily(Tasks.Task.sanitize(daily)); // eslint-disable-line babel/new-cap
|
||||
tasksByType.dailys = [];
|
||||
tasksByType.dailys.push(task);
|
||||
|
||||
user._statsComputed = {
|
||||
con: 1,
|
||||
};
|
||||
|
||||
daysMissed = 1;
|
||||
tasksByType.dailys[0].startDate = moment(new Date()).subtract({days: 1});
|
||||
});
|
||||
|
||||
it('resets user progress', () => {
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(user.party.quest.progress.up).to.equal(0);
|
||||
expect(user.party.quest.progress.down).to.equal(0);
|
||||
expect(user.party.quest.progress.collect).to.be.empty;
|
||||
});
|
||||
|
||||
it('applies the user progress', () => {
|
||||
let progress = cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(progress.down).to.equal(-1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('private messages', () => {
|
||||
let lastMessageId;
|
||||
|
||||
beforeEach(() => {
|
||||
let maxPMs = 200;
|
||||
for (let index = 0; index < maxPMs - 1; index += 1) {
|
||||
let messageId = common.uuid();
|
||||
user.inbox.messages[messageId] = {
|
||||
id: messageId,
|
||||
text: `test ${index}`,
|
||||
timestamp: Number(new Date()),
|
||||
likes: {},
|
||||
flags: {},
|
||||
flagCount: 0,
|
||||
};
|
||||
}
|
||||
|
||||
lastMessageId = common.uuid();
|
||||
user.inbox.messages[lastMessageId] = {
|
||||
id: lastMessageId,
|
||||
text: `test ${lastMessageId}`,
|
||||
timestamp: Number(new Date()),
|
||||
likes: {},
|
||||
flags: {},
|
||||
flagCount: 0,
|
||||
};
|
||||
});
|
||||
|
||||
xit('does not clear pms under 200', () => {
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(user.inbox.messages[lastMessageId]).to.exist;
|
||||
});
|
||||
|
||||
xit('clears pms over 200', () => {
|
||||
let messageId = common.uuid();
|
||||
user.inbox.messages[messageId] = {
|
||||
id: messageId,
|
||||
text: `test ${messageId}`,
|
||||
timestamp: Number(new Date()),
|
||||
likes: {},
|
||||
flags: {},
|
||||
flagCount: 0,
|
||||
};
|
||||
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(user.inbox.messages[messageId]).to.not.exist;
|
||||
});
|
||||
});
|
||||
});
|
||||
176
test/api/v3/unit/middlewares/cronMiddleware.js
Normal file
176
test/api/v3/unit/middlewares/cronMiddleware.js
Normal file
@@ -0,0 +1,176 @@
|
||||
import {
|
||||
generateRes,
|
||||
generateReq,
|
||||
generateNext,
|
||||
generateTodo,
|
||||
generateDaily,
|
||||
} from '../../../../helpers/api-unit.helper';
|
||||
import cronMiddleware from '../../../../../website/src/middlewares/api-v3/cron';
|
||||
import moment from 'moment';
|
||||
import { model as User } from '../../../../../website/src/models/user';
|
||||
import { model as Group } from '../../../../../website/src/models/group';
|
||||
import * as Tasks from '../../../../../website/src/models/task';
|
||||
import analyticsService from '../../../../../website/src/libs/api-v3/analyticsService';
|
||||
import { v4 as generateUUID } from 'uuid';
|
||||
|
||||
describe('cron middleware', () => {
|
||||
let res, req, next;
|
||||
let user;
|
||||
|
||||
beforeEach(() => {
|
||||
res = generateRes();
|
||||
req = generateReq();
|
||||
next = generateNext();
|
||||
user = new User({
|
||||
auth: {
|
||||
local: {
|
||||
username: 'username',
|
||||
lowerCaseUsername: 'username',
|
||||
email: 'email@email.email',
|
||||
salt: 'salt',
|
||||
hashed_password: 'hashed_password', // eslint-disable-line camelcase
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
user._statsComputed = {
|
||||
mp: 10,
|
||||
maxMP: 100,
|
||||
};
|
||||
|
||||
res.locals.user = user;
|
||||
res.analytics = analyticsService;
|
||||
});
|
||||
|
||||
it('calls next when user is not attached', () => {
|
||||
res.locals.user = null;
|
||||
cronMiddleware(req, res, next);
|
||||
expect(next).to.be.calledOnce;
|
||||
});
|
||||
|
||||
it('calls next when days have not been missed', () => {
|
||||
cronMiddleware(req, res, next);
|
||||
expect(next).to.be.calledOnce;
|
||||
});
|
||||
|
||||
it('should clear todos older than 30 days for free users', async (done) => {
|
||||
user.lastCron = moment(new Date()).subtract({days: 2});
|
||||
let task = generateTodo(user);
|
||||
task.dateCompleted = moment(new Date()).subtract({days: 31});
|
||||
task.completed = true;
|
||||
await task.save();
|
||||
|
||||
cronMiddleware(req, res, () => {
|
||||
Tasks.Task.findOne({_id: task}, function (err, taskFound) {
|
||||
expect(err).to.not.exist;
|
||||
expect(taskFound).to.not.exist;
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should not clear todos older than 30 days for subscribed users', (done) => {
|
||||
user.purchased.plan.customerId = 'subscribedId';
|
||||
user.purchased.plan.dateUpdated = moment('012013', 'MMYYYY');
|
||||
user.lastCron = moment(new Date()).subtract({days: 2});
|
||||
let task = generateTodo(user);
|
||||
task.dateCompleted = moment(new Date()).subtract({days: 31});
|
||||
task.completed = true;
|
||||
task.save();
|
||||
|
||||
cronMiddleware(req, res, () => {
|
||||
Tasks.Task.findOne({_id: task}, function (err, taskFound) {
|
||||
expect(err).to.not.exist;
|
||||
expect(taskFound).to.exist;
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should clear todos older than 90 days for subscribed users', (done) => {
|
||||
user.purchased.plan.customerId = 'subscribedId';
|
||||
user.purchased.plan.dateUpdated = moment('012013', 'MMYYYY');
|
||||
user.lastCron = moment(new Date()).subtract({days: 2});
|
||||
|
||||
let task = generateTodo(user);
|
||||
task.dateCompleted = moment(new Date()).subtract({days: 91});
|
||||
task.completed = true;
|
||||
task.save();
|
||||
|
||||
cronMiddleware(req, res, () => {
|
||||
Tasks.Task.findOne({_id: task}, function (err, taskFound) {
|
||||
expect(err).to.not.exist;
|
||||
expect(taskFound).to.not.exist;
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should call next is user was not modified after cron', (done) => {
|
||||
let hpBefore = user.stats.hp;
|
||||
user.lastCron = moment(new Date()).subtract({days: 2});
|
||||
generateDaily(user);
|
||||
|
||||
cronMiddleware(req, res, () => {
|
||||
expect(user.stats.hp).to.be.equal(hpBefore);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('does damage for missing dailies', (done) => {
|
||||
let hpBefore = user.stats.hp;
|
||||
user.lastCron = moment(new Date()).subtract({days: 2});
|
||||
let daily = generateDaily(user);
|
||||
daily.startDate = moment(new Date()).subtract({days: 2});
|
||||
daily.save();
|
||||
|
||||
cronMiddleware(req, res, () => {
|
||||
expect(user.stats.hp).to.be.lessThan(hpBefore);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('updates tasks', (done) => {
|
||||
user.lastCron = moment(new Date()).subtract({days: 2});
|
||||
let todo = generateTodo(user);
|
||||
let todoValueBefore = todo.value;
|
||||
|
||||
cronMiddleware(req, res, () => {
|
||||
Tasks.Task.findOne({_id: todo._id}, function (err, todoFound) {
|
||||
expect(err).to.not.exist;
|
||||
expect(todoFound.value).to.be.lessThan(todoValueBefore);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('applies quest progress', async (done) => {
|
||||
let hpBefore = user.stats.hp;
|
||||
user.lastCron = moment(new Date()).subtract({days: 2});
|
||||
let daily = generateDaily(user);
|
||||
daily.startDate = moment(new Date()).subtract({days: 2});
|
||||
daily.save();
|
||||
|
||||
let questKey = 'dilatory';
|
||||
user.party.quest.key = questKey;
|
||||
|
||||
let party = new Group({
|
||||
type: 'party',
|
||||
name: generateUUID(),
|
||||
leader: user._id,
|
||||
});
|
||||
party.quest.members[user._id] = true;
|
||||
party.quest.key = questKey;
|
||||
await party.save();
|
||||
|
||||
user.party._id = party._id;
|
||||
await user.save();
|
||||
|
||||
party.startQuest(user);
|
||||
|
||||
cronMiddleware(req, res, () => {
|
||||
expect(user.stats.hp).to.be.lessThan(hpBefore);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -35,6 +35,21 @@ describe('response middleware', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('can be passed a third parameter to be used as optional message', () => {
|
||||
responseMiddleware(req, res, next);
|
||||
res.respond(200, {field: 1}, 'hello');
|
||||
|
||||
expect(res.status).to.be.calledOnce;
|
||||
expect(res.json).to.be.calledOnce;
|
||||
|
||||
expect(res.status).to.be.calledWith(200);
|
||||
expect(res.json).to.be.calledWith({
|
||||
success: true,
|
||||
data: {field: 1},
|
||||
message: 'hello',
|
||||
});
|
||||
});
|
||||
|
||||
it('treats status >= 400 as failures', () => {
|
||||
responseMiddleware(req, res, next);
|
||||
res.respond(403, {field: 1});
|
||||
|
||||
@@ -110,7 +110,7 @@ describe('Challenge Model', () => {
|
||||
};
|
||||
|
||||
Tasks.Task.sanitize(req.body);
|
||||
_.assign(task, common.ops.updateTask(task.toObject(), req));
|
||||
_.assign(task, common.ops.updateTask(task.toObject(), req)[0]);
|
||||
|
||||
await challenge.updateTask(task);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user