mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-18 15:17:25 +01:00
* Added all ui components back * Added group ui items back and initial group approval directive * Added approval list view with approving functionality * Added notification display for group approvals * Fixed linting issues * Removed expectation from beforeEach * Moved string to locale * Added per use group plan for stripe * Added tests for stripe group plan upgrade * Removed paypal option * Abstract sub blocks. Hit group sub block from user settings page. Added group subscriptin beneifts display * Fixed lint issue * Added pricing and adjusted styles * Moved text to translations * Added group email types * Fixed typo * Fixed group plan abstraction and other style issues * Fixed email unit test * Added type to group plan to filter our group plans * Removed dev protection from routes * Removed hard coding and fixed upgrade plan * Added error when group has subscription and tries to remove * Fixed payment unit tests * Added custom string and moved subscription check up in the logic * Added ability for old leader to delete subscription the created * Allowed old guild leader to edit their group subscription * Fixed linting and tests * Added group sub page to user sub settings * Added approval and group tasks requests back. Hid user group sub on profile * Added group tasks sync after adding to allow for editing * Fixed promise chain when resolving group * Added approvals to group promise chain * Ensured compelted group todos are not delted at cron * Updated copy and other minor styles * Added group field to tags and recolored group tag. * Added chat message when task is claimed * Preventing task scoring when approval is needed * Added approval requested indicator * Updated column with for tasks on group page * Added checklist sync on assign * Added sync for checklist items * Added checkilist sync when task is updated * Added checklist sync remove * Sanatized group tasks when updated * Fixed lint issues * Added instant scoring of approved task * Added task modal * Fixed editing of challenge and group tasks * Added cancel button * Added add new checklist option to update sync * Added remove for checklist * Added checklist update * Added difference check and sync for checklist if there is a diff * Fixed task syncing * Fixed linting issues * Fixed styles and karma tests * Fixed minor style issues * Fixed obj transfer on scope * Fixed broken tests * Added new benefits page * Updated group page styles * Updated benefits page style * Added translations * Prevented sync with empty trask list * Added task title to edit modal * Added new group plans page and upgrade redirect * Added group plans redirect to upgrade * Fixed party home page being hidden and home button click * Fixed dynamic changing of task status and grey popup * Fixed tag editing * Hid benifites information if group has subscription * Added quotes to task name * Fixed issue with assigning multiple users * Added new group plans ctrl * Hid menu from public guilds * Fixed task sync issue * Updated placeholder for assign field * Added correct cost to subscribe details * Hid create, edit, delete task options from non group leaders * Prevented some front end modifications to group tasks * Hid tags option from group original task * Added refresh for approvals and group tasks * Prepend new group tasks * Fix last checklist item sync * Fixed casing issue with tags * Added claimed by message on hover * Prevent user from deleting assigned task * Added single route for group plan sign up and payments * Abstracted stripe payments and added initial tests * Abstracted amazon and added initial tests * Fixed create group message * Update group id check and return group * Updated to use the new returned group * Fixed linting and promise issues * Fixed broken leave test after merge issue * Fixed undefined approval error and editing/deleting challenge tasks * Add pricing to group plans, removed confirmation, and fixed redirect after payment * Updated group plan cost text
231 lines
8.2 KiB
JavaScript
231 lines
8.2 KiB
JavaScript
import scoreTask from '../../../website/common/script/ops/scoreTask';
|
|
import {
|
|
generateUser,
|
|
generateDaily,
|
|
generateHabit,
|
|
generateTodo,
|
|
generateReward,
|
|
} from '../../helpers/common.helper';
|
|
import common from '../../../website/common';
|
|
import i18n from '../../../website/common/script/i18n';
|
|
import {
|
|
NotAuthorized,
|
|
} from '../../../website/common/script/libs/errors';
|
|
|
|
let EPSILON = 0.0001; // negligible distance between datapoints
|
|
|
|
/* Helper Functions */
|
|
let rewrapUser = (user) => {
|
|
user._wrapped = false;
|
|
common.wrap(user);
|
|
return user;
|
|
};
|
|
|
|
let beforeAfter = () => {
|
|
let beforeUser = generateUser();
|
|
let afterUser = _.cloneDeep(beforeUser);
|
|
rewrapUser(afterUser);
|
|
|
|
return {
|
|
beforeUser,
|
|
afterUser,
|
|
};
|
|
};
|
|
|
|
let expectGainedPoints = (beforeUser, afterUser, beforeTask, afterTask) => {
|
|
expect(afterUser.stats.hp).to.eql(50);
|
|
expect(afterUser.stats.exp).to.be.greaterThan(beforeUser.stats.exp);
|
|
expect(afterUser.stats.gp).to.be.greaterThan(beforeUser.stats.gp);
|
|
expect(afterTask.value).to.be.greaterThan(beforeTask.value);
|
|
if (afterTask.type === 'habit') {
|
|
expect(afterTask.history).to.have.length(1);
|
|
}
|
|
};
|
|
|
|
let expectClosePoints = (beforeUser, afterUser, beforeTask, task) => {
|
|
expect(Math.abs(afterUser.stats.exp - beforeUser.stats.exp)).to.be.lessThan(EPSILON);
|
|
expect(Math.abs(afterUser.stats.gp - beforeUser.stats.gp)).to.be.lessThan(EPSILON);
|
|
expect(Math.abs(task.value - beforeTask.value)).to.be.lessThan(EPSILON);
|
|
};
|
|
|
|
function expectRoughlyEqualDates (date1, date2) {
|
|
date1 = date1.valueOf();
|
|
date2 = date2.valueOf();
|
|
expect(date1).to.be.within(date2 - 100, date2 + 100);
|
|
}
|
|
|
|
describe('shared.ops.scoreTask', () => {
|
|
let ref;
|
|
|
|
beforeEach(() => {
|
|
ref = beforeAfter();
|
|
});
|
|
|
|
it('throws an error when scoring a reward if user does not have enough gold', (done) => {
|
|
let reward = generateReward({ userId: ref.afterUser._id, text: 'some reward', value: 100 });
|
|
try {
|
|
scoreTask({ user: ref.afterUser, task: reward });
|
|
} catch (err) {
|
|
expect(err).to.be.an.instanceof(NotAuthorized);
|
|
expect(err.message).to.eql(i18n.t('messageNotEnoughGold'));
|
|
done();
|
|
}
|
|
});
|
|
|
|
it('checks that the streak parameters affects the score', () => {
|
|
let task = generateDaily({ userId: ref.afterUser._id, text: 'task to check streak' });
|
|
scoreTask({ user: ref.afterUser, task, direction: 'up', cron: false });
|
|
scoreTask({ user: ref.afterUser, task, direction: 'up', cron: false });
|
|
expect(task.streak).to.eql(2);
|
|
});
|
|
|
|
it('completes when the task direction is up', () => {
|
|
let task = generateTodo({ userId: ref.afterUser._id, text: 'todo to complete', cron: false });
|
|
scoreTask({ user: ref.afterUser, task, direction: 'up' });
|
|
expect(task.completed).to.eql(true);
|
|
expectRoughlyEqualDates(task.dateCompleted, new Date());
|
|
});
|
|
|
|
it('uncompletes when the task direction is down', () => {
|
|
let task = generateTodo({ userId: ref.afterUser._id, text: 'todo to complete', cron: false });
|
|
scoreTask({ user: ref.afterUser, task, direction: 'down' });
|
|
expect(task.completed).to.eql(false);
|
|
expect(task.dateCompleted).to.not.exist;
|
|
});
|
|
|
|
describe('verifies that times parameter in scoring works', () => {
|
|
let habit;
|
|
|
|
beforeEach(() => {
|
|
ref = beforeAfter();
|
|
habit = generateHabit({ userId: ref.afterUser._id, text: 'some habit' });
|
|
});
|
|
|
|
it('works', () => {
|
|
let delta1, delta2, delta3;
|
|
|
|
delta1 = scoreTask({ user: ref.afterUser, task: habit, direction: 'up', times: 5, cron: false });
|
|
|
|
ref = beforeAfter();
|
|
habit = generateHabit({ userId: ref.afterUser._id, text: 'some habit' });
|
|
|
|
delta2 = scoreTask({ user: ref.afterUser, task: habit, direction: 'up', times: 4, cron: false });
|
|
|
|
ref = beforeAfter();
|
|
habit = generateHabit({ userId: ref.afterUser._id, text: 'some habit' });
|
|
|
|
delta3 = scoreTask({ user: ref.afterUser, task: habit, direction: 'up', times: 5, cron: false });
|
|
|
|
expect(Math.abs(delta1 - delta2)).to.be.greaterThan(EPSILON);
|
|
expect(Math.abs(delta1 - delta3)).to.be.lessThan(EPSILON);
|
|
});
|
|
});
|
|
|
|
describe('scores', () => {
|
|
let options = {};
|
|
let habit;
|
|
let freshDaily, daily;
|
|
let freshTodo, todo;
|
|
|
|
beforeEach(() => {
|
|
ref = beforeAfter(options);
|
|
habit = generateHabit({ userId: ref.afterUser._id, text: 'some habit' });
|
|
freshDaily = generateDaily({ userId: ref.afterUser._id, text: 'some daily' });
|
|
daily = generateDaily({ userId: ref.afterUser._id, text: 'some daily' });
|
|
freshTodo = generateTodo({ userId: ref.afterUser._id, text: 'some todo' });
|
|
todo = generateTodo({ userId: ref.afterUser._id, text: 'some todo' });
|
|
|
|
expect(habit.history.length).to.eql(0);
|
|
|
|
// before and after are the same user
|
|
expect(ref.beforeUser._id).to.exist;
|
|
expect(ref.beforeUser._id).to.eql(ref.afterUser._id);
|
|
});
|
|
|
|
it('and increments quest progress', () => {
|
|
expect(ref.afterUser.party.quest.progress.up).to.eql(0);
|
|
ref.afterUser.party.quest.key = 'gryphon';
|
|
|
|
scoreTask({ user: ref.afterUser, task: habit, direction: 'up', cron: false });
|
|
let firstTaskDelta = ref.afterUser.party.quest.progress.up;
|
|
expect(firstTaskDelta).to.be.greaterThan(0);
|
|
expect(ref.afterUser._tmp.quest.progressDelta).to.eql(firstTaskDelta);
|
|
|
|
scoreTask({ user: ref.afterUser, task: habit, direction: 'up', cron: false });
|
|
let secondTaskDelta = ref.afterUser.party.quest.progress.up - firstTaskDelta;
|
|
expect(secondTaskDelta).to.be.greaterThan(0);
|
|
expect(ref.afterUser._tmp.quest.progressDelta).to.eql(secondTaskDelta);
|
|
});
|
|
|
|
it('does not modify stats when task need approval', () => {
|
|
todo.group.approval.required = true;
|
|
options = { user: ref.afterUser, task: todo, direction: 'up', times: 5, cron: false };
|
|
scoreTask(options);
|
|
|
|
expect(ref.afterUser.stats.hp).to.eql(50);
|
|
expect(ref.afterUser.stats.exp).to.equal(ref.beforeUser.stats.exp);
|
|
expect(ref.afterUser.stats.gp).to.equal(ref.beforeUser.stats.gp);
|
|
});
|
|
|
|
context('habits', () => {
|
|
it('up', () => {
|
|
options = { user: ref.afterUser, task: habit, direction: 'up', times: 5, cron: false };
|
|
scoreTask(options);
|
|
|
|
expect(habit.history.length).to.eql(1);
|
|
expect(habit.value).to.be.greaterThan(0);
|
|
|
|
expect(ref.afterUser.stats.hp).to.eql(50);
|
|
expect(ref.afterUser.stats.exp).to.be.greaterThan(ref.beforeUser.stats.exp);
|
|
expect(ref.afterUser.stats.gp).to.be.greaterThan(ref.beforeUser.stats.gp);
|
|
});
|
|
|
|
it('down', () => {
|
|
scoreTask({user: ref.afterUser, task: habit, direction: 'down', times: 5, cron: false}, {});
|
|
|
|
expect(habit.history.length).to.eql(1);
|
|
expect(habit.value).to.be.lessThan(0);
|
|
|
|
expect(ref.afterUser.stats.hp).to.be.lessThan(ref.beforeUser.stats.hp);
|
|
expect(ref.afterUser.stats.exp).to.eql(0);
|
|
expect(ref.afterUser.stats.gp).to.eql(0);
|
|
});
|
|
});
|
|
|
|
context('dailys', () => {
|
|
it('up', () => {
|
|
expect(daily.completed).to.not.eql(true);
|
|
scoreTask({user: ref.afterUser, task: daily, direction: 'up'});
|
|
expectGainedPoints(ref.beforeUser, ref.afterUser, freshDaily, daily);
|
|
expect(daily.completed).to.eql(true);
|
|
});
|
|
|
|
it('up, down', () => {
|
|
scoreTask({user: ref.afterUser, task: daily, direction: 'up'});
|
|
scoreTask({user: ref.afterUser, task: daily, direction: 'down'});
|
|
expectClosePoints(ref.beforeUser, ref.afterUser, freshDaily, daily);
|
|
});
|
|
|
|
it('sets completed = false on direction = down', () => {
|
|
daily.completed = true;
|
|
expect(daily.completed).to.not.eql(false);
|
|
scoreTask({user: ref.afterUser, task: daily, direction: 'down'});
|
|
expect(daily.completed).to.eql(false);
|
|
});
|
|
});
|
|
|
|
context('todos', () => {
|
|
it('up', () => {
|
|
scoreTask({user: ref.afterUser, task: todo, direction: 'up'});
|
|
expectGainedPoints(ref.beforeUser, ref.afterUser, freshTodo, todo);
|
|
});
|
|
|
|
it('up, down', () => {
|
|
scoreTask({user: ref.afterUser, task: todo, direction: 'up'});
|
|
scoreTask({user: ref.afterUser, task: todo, direction: 'down'});
|
|
expectClosePoints(ref.beforeUser, ref.afterUser, freshTodo, todo);
|
|
});
|
|
});
|
|
});
|
|
});
|