Merge branch 'develop' into party-chat-translations

# Conflicts:
#	test/api/unit/models/group.test.js
This commit is contained in:
Mateus Etto
2018-06-20 20:24:38 +09:00
799 changed files with 42207 additions and 31980 deletions

View File

@@ -20,8 +20,9 @@ env:
- DISABLE_REQUEST_LOGGING=true - DISABLE_REQUEST_LOGGING=true
matrix: matrix:
- TEST="lint" - TEST="lint"
- TEST="test:api-v3:unit" REQUIRES_SERVER=true COVERAGE=true - TEST="test:api:unit" REQUIRES_SERVER=true COVERAGE=true
- TEST="test:api-v3:integration" REQUIRES_SERVER=true COVERAGE=true - TEST="test:api-v3:integration" REQUIRES_SERVER=true COVERAGE=true
- TEST="test:api-v4:integration" REQUIRES_SERVER=true COVERAGE=true
- TEST="test:sanity" - TEST="test:sanity"
- TEST="test:content" COVERAGE=true - TEST="test:content" COVERAGE=true
- TEST="test:common" COVERAGE=true - TEST="test:common" COVERAGE=true

View File

@@ -17,7 +17,7 @@ RUN npm install -g gulp-cli mocha
# Clone Habitica repo and install dependencies # Clone Habitica repo and install dependencies
RUN mkdir -p /usr/src/habitrpg RUN mkdir -p /usr/src/habitrpg
WORKDIR /usr/src/habitrpg WORKDIR /usr/src/habitrpg
RUN git clone --branch v4.42.4 https://github.com/HabitRPG/habitica.git /usr/src/habitrpg RUN git clone --branch v4.46.2 https://github.com/HabitRPG/habitica.git /usr/src/habitrpg
RUN npm install RUN npm install
RUN gulp build:prod --force RUN gulp build:prod --force

View File

@@ -112,5 +112,6 @@
"CLOUDKARAFKA_USERNAME": "", "CLOUDKARAFKA_USERNAME": "",
"CLOUDKARAFKA_PASSWORD": "", "CLOUDKARAFKA_PASSWORD": "",
"CLOUDKARAFKA_TOPIC_PREFIX": "" "CLOUDKARAFKA_TOPIC_PREFIX": ""
} },
"MIGRATION_CONNECT_STRING": "mongodb://localhost:27017/habitrpg?auto_reconnect=true"
} }

View File

@@ -0,0 +1,100 @@
import max from 'lodash/max';
import mean from 'lodash/mean';
import monk from 'monk';
import round from 'lodash/round';
import sum from 'lodash/sum';
/*
* Output data on subscribers' task histories, formatted for CSV.
* User ID,Count of Dailies,Count of Habits,Total History Size,Max History Size,Mean History Size,Median History Size
*/
const connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
let dbUsers = monk(connectionString).get('users', { castIds: false });
let dbTasks = monk(connectionString).get('tasks', { castIds: false });
function usersReport () {
let allHistoryLengths = [];
console.info('User ID,Count of Dailies,Count of Habits,Total History Size,Max History Size,Mean History Size,Median History Size');
dbUsers.find(
{
$and:
[
{'purchased.plan.planId': {$ne:null}},
{'purchased.plan.planId': {$ne:''}},
],
$or:
[
{'purchased.plan.dateTerminated': null},
{'purchased.plan.dateTerminated': ''},
{'purchased.plan.dateTerminated': {$gt:new Date()}},
],
},
{
fields: {_id: 1},
}
).each((user, {close, pause, resume}) => {
let historyLengths = [];
let habitCount = 0;
let dailyCount = 0;
pause();
return dbTasks.find(
{
userId: user._id,
$or:
[
{type: 'habit'},
{type: 'daily'},
],
},
{
fields: {
type: 1,
history: 1,
},
}
).each((task) => {
if (task.type === 'habit') {
habitCount++;
}
if (task.type === 'daily') {
dailyCount++;
}
if (task.history.length > 0) {
allHistoryLengths.push(task.history.length);
historyLengths.push(task.history.length);
}
}).then(() => {
const totalHistory = sum(historyLengths);
const maxHistory = historyLengths.length > 0 ? max(historyLengths) : 0;
const meanHistory = historyLengths.length > 0 ? round(mean(historyLengths)) : 0;
const medianHistory = historyLengths.length > 0 ? median(historyLengths) : 0;
console.info(`${user._id},${dailyCount},${habitCount},${totalHistory},${maxHistory},${meanHistory},${medianHistory}`);
resume();
});
}).then(() => {
console.info(`Total Subscriber History Entries: ${sum(allHistoryLengths)}`);
console.info(`Largest History Size: ${max(allHistoryLengths)}`);
console.info(`Mean History Size: ${round(mean(allHistoryLengths))}`);
console.info(`Median History Size: ${median(allHistoryLengths)}`);
return process.exit(0);
});
}
function median(values) { // https://gist.github.com/caseyjustus/1166258
values.sort( function(a,b) {return a - b;} );
var half = Math.floor(values.length/2);
if (values.length % 2) {
return values[half];
}
else {
return (values[half-1] + values[half]) / 2.0;
}
}
module.exports = usersReport;

View File

@@ -165,9 +165,9 @@ gulp.task('test:content:safe', gulp.series('test:prepare:build', (cb) => {
pipe(runner); pipe(runner);
})); }));
gulp.task('test:api-v3:unit', (done) => { gulp.task('test:api:unit', (done) => {
let runner = exec( let runner = exec(
testBin('node_modules/.bin/istanbul cover --dir coverage/api-v3-unit node_modules/mocha/bin/_mocha -- test/api/v3/unit --recursive --require ./test/helpers/start-server'), testBin('node_modules/.bin/istanbul cover --dir coverage/api-unit node_modules/mocha/bin/_mocha -- test/api/unit --recursive --require ./test/helpers/start-server'),
(err) => { (err) => {
if (err) { if (err) {
process.exit(1); process.exit(1);
@@ -179,8 +179,8 @@ gulp.task('test:api-v3:unit', (done) => {
pipe(runner); pipe(runner);
}); });
gulp.task('test:api-v3:unit:watch', () => { gulp.task('test:api:unit:watch', () => {
return gulp.watch(['website/server/libs/*', 'test/api/v3/unit/**/*', 'website/server/controllers/**/*'], gulp.series('test:api-v3:unit', done => done())); return gulp.watch(['website/server/libs/*', 'test/api/v3/unit/**/*', 'website/server/controllers/**/*'], gulp.series('test:api:unit', done => done()));
}); });
gulp.task('test:api-v3:integration', (done) => { gulp.task('test:api-v3:integration', (done) => {
@@ -215,17 +215,43 @@ gulp.task('test:api-v3:integration:separate-server', (done) => {
pipe(runner); pipe(runner);
}); });
gulp.task('test:api-v4:integration', (done) => {
let runner = exec(
testBin('node_modules/.bin/istanbul cover --dir coverage/api-v4-integration --report lcovonly node_modules/mocha/bin/_mocha -- test/api/v4 --recursive --require ./test/helpers/start-server'),
{maxBuffer: 500 * 1024},
(err) => {
if (err) {
process.exit(1);
}
done();
}
);
pipe(runner);
});
gulp.task('test:api-v4:integration:separate-server', (done) => {
let runner = exec(
testBin('mocha test/api/v4 --recursive --require ./test/helpers/start-server', 'LOAD_SERVER=0'),
{maxBuffer: 500 * 1024},
(err) => done(err)
);
pipe(runner);
});
gulp.task('test', gulp.series( gulp.task('test', gulp.series(
'test:sanity', 'test:sanity',
'test:content', 'test:content',
'test:common', 'test:common',
'test:api-v3:unit', 'test:api:unit',
'test:api-v3:integration', 'test:api-v3:integration',
'test:api-v4:integration',
done => done() done => done()
)); ));
gulp.task('test:api-v3', gulp.series( gulp.task('test:api-v3', gulp.series(
'test:api-v3:unit', 'test:api:unit',
'test:api-v3:integration', 'test:api-v3:integration',
done => done() done => done()
)); ));

View File

@@ -0,0 +1,107 @@
import monk from 'monk';
import nconf from 'nconf';
import stripePayments from '../../website/server/libs/payments/stripe';
/*
* Ensure that group plan billing is accurate by doing the following:
* 1. Correct the memberCount in all paid groups whose counts are wrong
* 2. Where the above uses Stripe, update their subscription counts in Stripe
*
* Provides output on what groups were fixed, which can be piped to CSV.
*/
const CONNECTION_STRING = nconf.get('MIGRATION_CONNECT_STRING');
let dbGroups = monk(CONNECTION_STRING).get('groups', { castIds: false });
let dbUsers = monk(CONNECTION_STRING).get('users', { castIds: false });
async function fixGroupPlanMembers () {
console.info('Group ID, Customer ID, Plan ID, Quantity, Recorded Member Count, Actual Member Count');
let groupPlanCount = 0;
let fixedGroupCount = 0;
dbGroups.find(
{
$and:
[
{'purchased.plan.planId': {$ne: null}},
{'purchased.plan.planId': {$ne: ''}},
{'purchased.plan.customerId': {$ne: 'cus_9f0DV4g7WHRzpM'}}, // Demo groups
{'purchased.plan.customerId': {$ne: 'cus_9maalqDOFTrvqx'}},
],
$or:
[
{'purchased.plan.dateTerminated': null},
{'purchased.plan.dateTerminated': ''},
],
},
{
fields: {
memberCount: 1,
'purchased.plan': 1,
},
}
).each(async (group, {close, pause, resume}) => { // eslint-disable-line no-unused-vars
pause();
groupPlanCount++;
const canonicalMemberCount = await dbUsers.count(
{
$or:
[
{'party._id': group._id},
{guilds: group._id},
],
}
);
const incorrectMemberCount = group.memberCount !== canonicalMemberCount;
const isMonthlyPlan = group.purchased.plan.planId === 'group_monthly';
const quantityMismatch = group.purchased.plan.quantity !== group.memberCount + 2;
const incorrectQuantity = isMonthlyPlan && quantityMismatch;
if (!incorrectMemberCount && !incorrectQuantity) {
resume();
return;
}
console.info(`${group._id}, ${group.purchased.plan.customerId}, ${group.purchased.plan.planId}, ${group.purchased.plan.quantity}, ${group.memberCount}, ${canonicalMemberCount}`);
const groupUpdate = await dbGroups.update(
{ _id: group._id },
{
$set: {
memberCount: canonicalMemberCount,
},
}
);
if (!groupUpdate) return;
fixedGroupCount++;
if (group.purchased.plan.paymentMethod === 'Stripe') {
await stripePayments.chargeForAdditionalGroupMember(group);
await dbGroups.update(
{_id: group._id},
{$set: {'purchased.plan.quantity': canonicalMemberCount + 2}}
);
}
if (incorrectQuantity) {
await dbGroups.update(
{_id: group._id},
{$set: {'purchased.plan.quantity': canonicalMemberCount + 2}}
);
}
resume();
}).then(() => {
console.info(`Fixed ${fixedGroupCount} out of ${groupPlanCount} active Group Plans`);
return process.exit(0);
}).catch((err) => {
console.log(err);
return process.exit(1);
});
}
module.exports = fixGroupPlanMembers;

View File

@@ -17,5 +17,5 @@ function setUpServer () {
setUpServer(); setUpServer();
// Replace this with your migration // Replace this with your migration
const processUsers = require('./groups/migrate-chat.js'); const processUsers = require('./users/mystery-items.js');
processUsers(); processUsers();

View File

@@ -7,7 +7,7 @@ let authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done
*/ */
let monk = require('monk'); let monk = require('monk');
let connectionString = 'mongodb://sabrecat:z8e8jyRA8CTofMQ@ds013393-a0.mlab.com:13393/habitica?auto_reconnect=true'; let connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true';
let dbTasks = monk(connectionString).get('tasks', { castIds: false }); let dbTasks = monk(connectionString).get('tasks', { castIds: false });
function processTasks (lastId) { function processTasks (lastId) {

View File

@@ -1,11 +1,11 @@
const migrationName = 'mystery-items-201802.js'; // Update per month const migrationName = 'mystery-items-201805.js'; // Update per month
const authorName = 'Sabe'; // in case script author needs to know when their ... const authorName = 'Sabe'; // in case script author needs to know when their ...
const authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done const authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done
/* /*
* Award this month's mystery items to subscribers * Award this month's mystery items to subscribers
*/ */
const MYSTERY_ITEMS = ['back_mystery_201804', 'headAccessory_mystery_201804']; const MYSTERY_ITEMS = ['back_mystery_201805', 'head_mystery_201805'];
const connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE const connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
let monk = require('monk'); let monk = require('monk');

View File

@@ -0,0 +1,109 @@
const migrationName = 'remove-social-users-extra-data.js';
const authorName = 'paglias'; // in case script author needs to know when their ...
const authorUuid = 'ed4c688c-6652-4a92-9d03-a5a79844174a'; // ... own data is done
/*
* Remove not needed data from social profiles
*/
const connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
const monk = require('monk');
const dbUsers = monk(connectionString).get('users', { castIds: false });
function processUsers (lastId) {
// specify a query to limit the affected users (empty for all users):
let query = {
migration: {$ne: migrationName},
$or: [
{ 'auth.facebook.id': { $exists: true } },
{ 'auth.google.id': { $exists: true } },
],
};
if (lastId) {
query._id = {
$gt: lastId,
};
}
dbUsers.find(query, {
sort: {_id: 1},
limit: 250,
})
.then(updateUsers)
.catch((err) => {
console.log(err);
return exiting(1, `ERROR! ${ err}`);
});
}
let progressCount = 1000;
let count = 0;
function updateUsers (users) {
if (!users || users.length === 0) {
console.warn('All appropriate users found and modified.');
displayData();
return;
}
let userPromises = users.map(updateUser);
let lastUser = users[users.length - 1];
return Promise.all(userPromises)
.then(() => {
processUsers(lastUser._id);
});
}
function updateUser (user) {
count++;
const isFacebook = user.auth.facebook && user.auth.facebook.id;
const isGoogle = user.auth.google && user.auth.google.id;
const update = { $set: {} };
if (isFacebook) {
update.$set['auth.facebook'] = {
id: user.auth.facebook.id,
emails: user.auth.facebook.emails,
};
}
if (isGoogle) {
update.$set['auth.google'] = {
id: user.auth.google.id,
emails: user.auth.google.emails,
};
}
dbUsers.update({
_id: user._id,
}, update);
if (count % progressCount === 0) console.warn(`${count } ${ user._id}`);
if (user._id === authorUuid) console.warn(`${authorName } processed`);
}
function displayData () {
console.warn(`\n${ count } users processed\n`);
return exiting(0);
}
function exiting (code, msg) {
code = code || 0; // 0 = success
if (code && !msg) {
msg = 'ERROR!';
}
if (msg) {
if (code) {
console.error(msg);
} else {
console.log(msg);
}
}
process.exit(code);
}
module.exports = processUsers;

11098
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{ {
"name": "habitica", "name": "habitica",
"description": "A habit tracker app which treats your goals like a Role Playing Game.", "description": "A habit tracker app which treats your goals like a Role Playing Game.",
"version": "4.42.6", "version": "4.47.0",
"main": "./website/server/index.js", "main": "./website/server/index.js",
"dependencies": { "dependencies": {
"@slack/client": "^3.8.1", "@slack/client": "^3.8.1",
@@ -61,7 +61,7 @@
"method-override": "^2.3.5", "method-override": "^2.3.5",
"moment": "^2.22.1", "moment": "^2.22.1",
"moment-recur": "^1.0.7", "moment-recur": "^1.0.7",
"mongoose": "^5.1.1", "mongoose": "^5.1.2",
"morgan": "^1.7.0", "morgan": "^1.7.0",
"nconf": "^0.10.0", "nconf": "^0.10.0",
"node-gcm": "^0.14.4", "node-gcm": "^0.14.4",
@@ -90,6 +90,8 @@
"svgo": "^1.0.5", "svgo": "^1.0.5",
"svgo-loader": "^2.1.0", "svgo-loader": "^2.1.0",
"universal-analytics": "^0.4.16", "universal-analytics": "^0.4.16",
"update": "^0.7.4",
"upgrade": "^1.1.0",
"url-loader": "^1.0.0", "url-loader": "^1.0.0",
"useragent": "^2.1.9", "useragent": "^2.1.9",
"uuid": "^3.0.1", "uuid": "^3.0.1",
@@ -119,9 +121,11 @@
"test": "npm run lint && gulp test && gulp apidoc", "test": "npm run lint && gulp test && gulp apidoc",
"test:build": "gulp test:prepare:build", "test:build": "gulp test:prepare:build",
"test:api-v3": "gulp test:api-v3", "test:api-v3": "gulp test:api-v3",
"test:api-v3:unit": "gulp test:api-v3:unit", "test:api:unit": "gulp test:api:unit",
"test:api-v3:integration": "gulp test:api-v3:integration", "test:api-v3:integration": "gulp test:api-v3:integration",
"test:api-v3:integration:separate-server": "NODE_ENV=test gulp test:api-v3:integration:separate-server", "test:api-v3:integration:separate-server": "NODE_ENV=test gulp test:api-v3:integration:separate-server",
"test:api-v4:integration": "gulp test:api-v4:integration",
"test:api-v4:integration:separate-server": "NODE_ENV=test gulp test:api-v4:integration:separate-server",
"test:sanity": "istanbul cover --dir coverage/sanity --report lcovonly node_modules/mocha/bin/_mocha -- test/sanity --recursive", "test:sanity": "istanbul cover --dir coverage/sanity --report lcovonly node_modules/mocha/bin/_mocha -- test/sanity --recursive",
"test:common": "istanbul cover --dir coverage/common --report lcovonly node_modules/mocha/bin/_mocha -- test/common --recursive", "test:common": "istanbul cover --dir coverage/common --report lcovonly node_modules/mocha/bin/_mocha -- test/common --recursive",
"test:content": "istanbul cover --dir coverage/content --report lcovonly node_modules/mocha/bin/_mocha -- test/content --recursive", "test:content": "istanbul cover --dir coverage/content --report lcovonly node_modules/mocha/bin/_mocha -- test/content --recursive",

View File

@@ -1,5 +1,5 @@
/* eslint-disable camelcase */ /* eslint-disable camelcase */
import analyticsService from '../../../../../website/server/libs/analyticsService'; import analyticsService from '../../../../website/server/libs/analyticsService';
import Amplitude from 'amplitude'; import Amplitude from 'amplitude';
import { Visitor } from 'universal-analytics'; import { Visitor } from 'universal-analytics';

View File

@@ -1,4 +1,4 @@
import apiError from '../../../../../website/server/libs/apiError'; import apiError from '../../../../website/server/libs/apiError';
describe('API Messages', () => { describe('API Messages', () => {
const message = 'Only public guilds support pagination.'; const message = 'Only public guilds support pagination.';

View File

@@ -1,4 +1,4 @@
import baseModel from '../../../../../website/server/libs/baseModel'; import baseModel from '../../../../website/server/libs/baseModel';
import mongoose from 'mongoose'; import mongoose from 'mongoose';
describe('Base model plugin', () => { describe('Base model plugin', () => {

View File

@@ -1,7 +1,7 @@
import mongoose from 'mongoose'; import mongoose from 'mongoose';
import { import {
removeFromArray, removeFromArray,
} from '../../../../../website/server/libs/collectionManipulators'; } from '../../../../website/server/libs/collectionManipulators';
describe('Collection Manipulators', () => { describe('Collection Manipulators', () => {
describe('removeFromArray', () => { describe('removeFromArray', () => {

View File

@@ -2,17 +2,18 @@
import moment from 'moment'; import moment from 'moment';
import nconf from 'nconf'; import nconf from 'nconf';
import requireAgain from 'require-again'; import requireAgain from 'require-again';
import { recoverCron, cron } from '../../../../../website/server/libs/cron'; import { recoverCron, cron } from '../../../../website/server/libs/cron';
import { model as User } from '../../../../../website/server/models/user'; import { model as User } from '../../../../website/server/models/user';
import * as Tasks from '../../../../../website/server/models/task'; import * as Tasks from '../../../../website/server/models/task';
import common from '../../../../../website/common'; import common from '../../../../website/common';
import analytics from '../../../../../website/server/libs/analyticsService'; import analytics from '../../../../website/server/libs/analyticsService';
// const scoreTask = common.ops.scoreTask; // const scoreTask = common.ops.scoreTask;
let pathToCronLib = '../../../../../website/server/libs/cron'; let pathToCronLib = '../../../../website/server/libs/cron';
describe('cron', () => { describe('cron', () => {
let clock = null;
let user; let user;
let tasksByType = {habits: [], dailys: [], todos: [], rewards: []}; let tasksByType = {habits: [], dailys: [], todos: [], rewards: []};
let daysMissed = 0; let daysMissed = 0;
@@ -34,6 +35,8 @@ describe('cron', () => {
}); });
afterEach(() => { afterEach(() => {
if (clock !== null)
clock.restore();
analytics.track.restore(); analytics.track.restore();
}); });
@@ -82,14 +85,12 @@ describe('cron', () => {
}); });
it('does not reset plan.gemsBought within the month', () => { it('does not reset plan.gemsBought within the month', () => {
let clock = sinon.useFakeTimers(moment().startOf('month').add(2, 'days').toDate()); clock = sinon.useFakeTimers(moment().startOf('month').add(2, 'days').toDate());
user.purchased.plan.dateUpdated = moment().startOf('month').toDate(); user.purchased.plan.dateUpdated = moment().startOf('month').toDate();
user.purchased.plan.gemsBought = 10; user.purchased.plan.gemsBought = 10;
cron({user, tasksByType, daysMissed, analytics}); cron({user, tasksByType, daysMissed, analytics});
expect(user.purchased.plan.gemsBought).to.equal(10); expect(user.purchased.plan.gemsBought).to.equal(10);
clock.restore();
}); });
it('resets plan.dateUpdated on a new month', () => { it('resets plan.dateUpdated on a new month', () => {
@@ -156,7 +157,6 @@ describe('cron', () => {
}); });
describe('for a 1-month recurring subscription', () => { describe('for a 1-month recurring subscription', () => {
let clock;
// create a user that will be used for all of these tests without a reset before each // create a user that will be used for all of these tests without a reset before each
let user1 = new User({ let user1 = new User({
auth: { auth: {
@@ -187,7 +187,6 @@ describe('cron', () => {
expect(user1.purchased.plan.consecutive.offset).to.equal(0); expect(user1.purchased.plan.consecutive.offset).to.equal(0);
expect(user1.purchased.plan.consecutive.trinkets).to.equal(0); expect(user1.purchased.plan.consecutive.trinkets).to.equal(0);
expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(0); expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(0);
clock.restore();
}); });
it('does not increment consecutive benefits after the second month', () => { it('does not increment consecutive benefits after the second month', () => {
@@ -199,7 +198,6 @@ describe('cron', () => {
expect(user1.purchased.plan.consecutive.offset).to.equal(0); expect(user1.purchased.plan.consecutive.offset).to.equal(0);
expect(user1.purchased.plan.consecutive.trinkets).to.equal(0); expect(user1.purchased.plan.consecutive.trinkets).to.equal(0);
expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(0); expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(0);
clock.restore();
}); });
it('increments consecutive benefits after the third month', () => { it('increments consecutive benefits after the third month', () => {
@@ -211,7 +209,6 @@ describe('cron', () => {
expect(user1.purchased.plan.consecutive.offset).to.equal(0); expect(user1.purchased.plan.consecutive.offset).to.equal(0);
expect(user1.purchased.plan.consecutive.trinkets).to.equal(1); expect(user1.purchased.plan.consecutive.trinkets).to.equal(1);
expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(5); expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(5);
clock.restore();
}); });
it('does not increment consecutive benefits after the fourth month', () => { it('does not increment consecutive benefits after the fourth month', () => {
@@ -223,7 +220,6 @@ describe('cron', () => {
expect(user1.purchased.plan.consecutive.offset).to.equal(0); expect(user1.purchased.plan.consecutive.offset).to.equal(0);
expect(user1.purchased.plan.consecutive.trinkets).to.equal(1); expect(user1.purchased.plan.consecutive.trinkets).to.equal(1);
expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(5); expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(5);
clock.restore();
}); });
it('increments consecutive benefits correctly if user has been absent with continuous subscription', () => { it('increments consecutive benefits correctly if user has been absent with continuous subscription', () => {
@@ -233,12 +229,10 @@ describe('cron', () => {
expect(user1.purchased.plan.consecutive.offset).to.equal(0); expect(user1.purchased.plan.consecutive.offset).to.equal(0);
expect(user1.purchased.plan.consecutive.trinkets).to.equal(3); expect(user1.purchased.plan.consecutive.trinkets).to.equal(3);
expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(15); expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(15);
clock.restore();
}); });
}); });
describe('for a 3-month recurring subscription', () => { describe('for a 3-month recurring subscription', () => {
let clock;
let user3 = new User({ let user3 = new User({
auth: { auth: {
local: { local: {
@@ -266,7 +260,6 @@ describe('cron', () => {
expect(user3.purchased.plan.consecutive.offset).to.equal(2); expect(user3.purchased.plan.consecutive.offset).to.equal(2);
expect(user3.purchased.plan.consecutive.trinkets).to.equal(1); expect(user3.purchased.plan.consecutive.trinkets).to.equal(1);
expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(5); expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(5);
clock.restore();
}); });
it('does not increment consecutive benefits in the middle of the period that they already have benefits for', () => { it('does not increment consecutive benefits in the middle of the period that they already have benefits for', () => {
@@ -276,7 +269,6 @@ describe('cron', () => {
expect(user3.purchased.plan.consecutive.offset).to.equal(1); expect(user3.purchased.plan.consecutive.offset).to.equal(1);
expect(user3.purchased.plan.consecutive.trinkets).to.equal(1); expect(user3.purchased.plan.consecutive.trinkets).to.equal(1);
expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(5); expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(5);
clock.restore();
}); });
it('does not increment consecutive benefits in the final month of the period that they already have benefits for', () => { it('does not increment consecutive benefits in the final month of the period that they already have benefits for', () => {
@@ -286,7 +278,6 @@ describe('cron', () => {
expect(user3.purchased.plan.consecutive.offset).to.equal(0); expect(user3.purchased.plan.consecutive.offset).to.equal(0);
expect(user3.purchased.plan.consecutive.trinkets).to.equal(1); expect(user3.purchased.plan.consecutive.trinkets).to.equal(1);
expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(5); expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(5);
clock.restore();
}); });
it('increments consecutive benefits the month after the second paid period has started', () => { it('increments consecutive benefits the month after the second paid period has started', () => {
@@ -296,7 +287,6 @@ describe('cron', () => {
expect(user3.purchased.plan.consecutive.offset).to.equal(2); expect(user3.purchased.plan.consecutive.offset).to.equal(2);
expect(user3.purchased.plan.consecutive.trinkets).to.equal(2); expect(user3.purchased.plan.consecutive.trinkets).to.equal(2);
expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(10); expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(10);
clock.restore();
}); });
it('does not increment consecutive benefits in the second month of the second period that they already have benefits for', () => { it('does not increment consecutive benefits in the second month of the second period that they already have benefits for', () => {
@@ -306,7 +296,6 @@ describe('cron', () => {
expect(user3.purchased.plan.consecutive.offset).to.equal(1); expect(user3.purchased.plan.consecutive.offset).to.equal(1);
expect(user3.purchased.plan.consecutive.trinkets).to.equal(2); expect(user3.purchased.plan.consecutive.trinkets).to.equal(2);
expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(10); expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(10);
clock.restore();
}); });
it('does not increment consecutive benefits in the final month of the second period that they already have benefits for', () => { it('does not increment consecutive benefits in the final month of the second period that they already have benefits for', () => {
@@ -316,7 +305,6 @@ describe('cron', () => {
expect(user3.purchased.plan.consecutive.offset).to.equal(0); expect(user3.purchased.plan.consecutive.offset).to.equal(0);
expect(user3.purchased.plan.consecutive.trinkets).to.equal(2); expect(user3.purchased.plan.consecutive.trinkets).to.equal(2);
expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(10); expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(10);
clock.restore();
}); });
it('increments consecutive benefits the month after the third paid period has started', () => { it('increments consecutive benefits the month after the third paid period has started', () => {
@@ -326,7 +314,6 @@ describe('cron', () => {
expect(user3.purchased.plan.consecutive.offset).to.equal(2); expect(user3.purchased.plan.consecutive.offset).to.equal(2);
expect(user3.purchased.plan.consecutive.trinkets).to.equal(3); expect(user3.purchased.plan.consecutive.trinkets).to.equal(3);
expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(15); expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(15);
clock.restore();
}); });
it('increments consecutive benefits correctly if user has been absent with continuous subscription', () => { it('increments consecutive benefits correctly if user has been absent with continuous subscription', () => {
@@ -336,12 +323,10 @@ describe('cron', () => {
expect(user3.purchased.plan.consecutive.offset).to.equal(2); expect(user3.purchased.plan.consecutive.offset).to.equal(2);
expect(user3.purchased.plan.consecutive.trinkets).to.equal(4); expect(user3.purchased.plan.consecutive.trinkets).to.equal(4);
expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(20); expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(20);
clock.restore();
}); });
}); });
describe('for a 6-month recurring subscription', () => { describe('for a 6-month recurring subscription', () => {
let clock;
let user6 = new User({ let user6 = new User({
auth: { auth: {
local: { local: {
@@ -369,7 +354,6 @@ describe('cron', () => {
expect(user6.purchased.plan.consecutive.offset).to.equal(5); expect(user6.purchased.plan.consecutive.offset).to.equal(5);
expect(user6.purchased.plan.consecutive.trinkets).to.equal(2); expect(user6.purchased.plan.consecutive.trinkets).to.equal(2);
expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(10); expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(10);
clock.restore();
}); });
it('does not increment consecutive benefits in the final month of the period that they already have benefits for', () => { it('does not increment consecutive benefits in the final month of the period that they already have benefits for', () => {
@@ -379,7 +363,6 @@ describe('cron', () => {
expect(user6.purchased.plan.consecutive.offset).to.equal(0); expect(user6.purchased.plan.consecutive.offset).to.equal(0);
expect(user6.purchased.plan.consecutive.trinkets).to.equal(2); expect(user6.purchased.plan.consecutive.trinkets).to.equal(2);
expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(10); expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(10);
clock.restore();
}); });
it('increments consecutive benefits the month after the second paid period has started', () => { it('increments consecutive benefits the month after the second paid period has started', () => {
@@ -389,7 +372,6 @@ describe('cron', () => {
expect(user6.purchased.plan.consecutive.offset).to.equal(5); expect(user6.purchased.plan.consecutive.offset).to.equal(5);
expect(user6.purchased.plan.consecutive.trinkets).to.equal(4); expect(user6.purchased.plan.consecutive.trinkets).to.equal(4);
expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(20); expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(20);
clock.restore();
}); });
it('increments consecutive benefits the month after the third paid period has started', () => { it('increments consecutive benefits the month after the third paid period has started', () => {
@@ -399,7 +381,6 @@ describe('cron', () => {
expect(user6.purchased.plan.consecutive.offset).to.equal(5); expect(user6.purchased.plan.consecutive.offset).to.equal(5);
expect(user6.purchased.plan.consecutive.trinkets).to.equal(6); expect(user6.purchased.plan.consecutive.trinkets).to.equal(6);
expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(25); expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(25);
clock.restore();
}); });
it('increments consecutive benefits correctly if user has been absent with continuous subscription', () => { it('increments consecutive benefits correctly if user has been absent with continuous subscription', () => {
@@ -409,13 +390,10 @@ describe('cron', () => {
expect(user6.purchased.plan.consecutive.offset).to.equal(5); expect(user6.purchased.plan.consecutive.offset).to.equal(5);
expect(user6.purchased.plan.consecutive.trinkets).to.equal(8); expect(user6.purchased.plan.consecutive.trinkets).to.equal(8);
expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(25); expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(25);
clock.restore();
}); });
}); });
describe('for a 12-month recurring subscription', () => { describe('for a 12-month recurring subscription', () => {
let clock;
let user12 = new User({ let user12 = new User({
auth: { auth: {
local: { local: {
@@ -443,7 +421,6 @@ describe('cron', () => {
expect(user12.purchased.plan.consecutive.offset).to.equal(11); expect(user12.purchased.plan.consecutive.offset).to.equal(11);
expect(user12.purchased.plan.consecutive.trinkets).to.equal(4); expect(user12.purchased.plan.consecutive.trinkets).to.equal(4);
expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(20); expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(20);
clock.restore();
}); });
it('does not increment consecutive benefits in the final month of the period that they already have benefits for', () => { it('does not increment consecutive benefits in the final month of the period that they already have benefits for', () => {
@@ -453,7 +430,6 @@ describe('cron', () => {
expect(user12.purchased.plan.consecutive.offset).to.equal(0); expect(user12.purchased.plan.consecutive.offset).to.equal(0);
expect(user12.purchased.plan.consecutive.trinkets).to.equal(4); expect(user12.purchased.plan.consecutive.trinkets).to.equal(4);
expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(20); expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(20);
clock.restore();
}); });
it('increments consecutive benefits the month after the second paid period has started', () => { it('increments consecutive benefits the month after the second paid period has started', () => {
@@ -463,7 +439,6 @@ describe('cron', () => {
expect(user12.purchased.plan.consecutive.offset).to.equal(11); expect(user12.purchased.plan.consecutive.offset).to.equal(11);
expect(user12.purchased.plan.consecutive.trinkets).to.equal(8); expect(user12.purchased.plan.consecutive.trinkets).to.equal(8);
expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(25); expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(25);
clock.restore();
}); });
it('increments consecutive benefits the month after the third paid period has started', () => { it('increments consecutive benefits the month after the third paid period has started', () => {
@@ -473,7 +448,6 @@ describe('cron', () => {
expect(user12.purchased.plan.consecutive.offset).to.equal(11); expect(user12.purchased.plan.consecutive.offset).to.equal(11);
expect(user12.purchased.plan.consecutive.trinkets).to.equal(12); expect(user12.purchased.plan.consecutive.trinkets).to.equal(12);
expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(25); expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(25);
clock.restore();
}); });
it('increments consecutive benefits correctly if user has been absent with continuous subscription', () => { it('increments consecutive benefits correctly if user has been absent with continuous subscription', () => {
@@ -483,12 +457,10 @@ describe('cron', () => {
expect(user12.purchased.plan.consecutive.offset).to.equal(11); expect(user12.purchased.plan.consecutive.offset).to.equal(11);
expect(user12.purchased.plan.consecutive.trinkets).to.equal(16); expect(user12.purchased.plan.consecutive.trinkets).to.equal(16);
expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(25); expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(25);
clock.restore();
}); });
}); });
describe('for a 3-month gift subscription (non-recurring)', () => { describe('for a 3-month gift subscription (non-recurring)', () => {
let clock;
let user3g = new User({ let user3g = new User({
auth: { auth: {
local: { local: {
@@ -503,7 +475,7 @@ describe('cron', () => {
// user3g has a 3-month gift subscription starting today // user3g has a 3-month gift subscription starting today
user3g.purchased.plan.customerId = 'Gift'; user3g.purchased.plan.customerId = 'Gift';
user3g.purchased.plan.dateUpdated = moment().toDate(); user3g.purchased.plan.dateUpdated = moment().toDate();
user3g.purchased.plan.dateTerminated = moment().add(3, 'months').toDate(); user3g.purchased.plan.dateTerminated = moment().startOf('month').add(3, 'months').add(15, 'days').toDate();
user3g.purchased.plan.planId = null; user3g.purchased.plan.planId = null;
user3g.purchased.plan.consecutive.count = 0; user3g.purchased.plan.consecutive.count = 0;
user3g.purchased.plan.consecutive.offset = 3; user3g.purchased.plan.consecutive.offset = 3;
@@ -517,7 +489,6 @@ describe('cron', () => {
expect(user3g.purchased.plan.consecutive.offset).to.equal(2); expect(user3g.purchased.plan.consecutive.offset).to.equal(2);
expect(user3g.purchased.plan.consecutive.trinkets).to.equal(1); expect(user3g.purchased.plan.consecutive.trinkets).to.equal(1);
expect(user3g.purchased.plan.consecutive.gemCapExtra).to.equal(5); expect(user3g.purchased.plan.consecutive.gemCapExtra).to.equal(5);
clock.restore();
}); });
it('does not increment consecutive benefits in the second month of the gift subscription', () => { it('does not increment consecutive benefits in the second month of the gift subscription', () => {
@@ -527,7 +498,6 @@ describe('cron', () => {
expect(user3g.purchased.plan.consecutive.offset).to.equal(1); expect(user3g.purchased.plan.consecutive.offset).to.equal(1);
expect(user3g.purchased.plan.consecutive.trinkets).to.equal(1); expect(user3g.purchased.plan.consecutive.trinkets).to.equal(1);
expect(user3g.purchased.plan.consecutive.gemCapExtra).to.equal(5); expect(user3g.purchased.plan.consecutive.gemCapExtra).to.equal(5);
clock.restore();
}); });
it('does not increment consecutive benefits in the third month of the gift subscription', () => { it('does not increment consecutive benefits in the third month of the gift subscription', () => {
@@ -537,7 +507,6 @@ describe('cron', () => {
expect(user3g.purchased.plan.consecutive.offset).to.equal(0); expect(user3g.purchased.plan.consecutive.offset).to.equal(0);
expect(user3g.purchased.plan.consecutive.trinkets).to.equal(1); expect(user3g.purchased.plan.consecutive.trinkets).to.equal(1);
expect(user3g.purchased.plan.consecutive.gemCapExtra).to.equal(5); expect(user3g.purchased.plan.consecutive.gemCapExtra).to.equal(5);
clock.restore();
}); });
it('does not increment consecutive benefits in the month after the gift subscription has ended', () => { it('does not increment consecutive benefits in the month after the gift subscription has ended', () => {
@@ -547,12 +516,10 @@ describe('cron', () => {
expect(user3g.purchased.plan.consecutive.offset).to.equal(0); expect(user3g.purchased.plan.consecutive.offset).to.equal(0);
expect(user3g.purchased.plan.consecutive.trinkets).to.equal(1); expect(user3g.purchased.plan.consecutive.trinkets).to.equal(1);
expect(user3g.purchased.plan.consecutive.gemCapExtra).to.equal(0); // erased expect(user3g.purchased.plan.consecutive.gemCapExtra).to.equal(0); // erased
clock.restore();
}); });
}); });
describe('for a 6-month recurring subscription where the user has incorrect consecutive month data from prior bugs', () => { describe('for a 6-month recurring subscription where the user has incorrect consecutive month data from prior bugs', () => {
let clock;
let user6x = new User({ let user6x = new User({
auth: { auth: {
local: { local: {
@@ -580,7 +547,6 @@ describe('cron', () => {
expect(user6x.purchased.plan.consecutive.offset).to.equal(5); expect(user6x.purchased.plan.consecutive.offset).to.equal(5);
expect(user6x.purchased.plan.consecutive.trinkets).to.equal(5); expect(user6x.purchased.plan.consecutive.trinkets).to.equal(5);
expect(user6x.purchased.plan.consecutive.gemCapExtra).to.equal(25); expect(user6x.purchased.plan.consecutive.gemCapExtra).to.equal(25);
clock.restore();
}); });
it('does not increment consecutive benefits in the second month after the fix goes live', () => { it('does not increment consecutive benefits in the second month after the fix goes live', () => {
@@ -590,7 +556,6 @@ describe('cron', () => {
expect(user6x.purchased.plan.consecutive.offset).to.equal(4); expect(user6x.purchased.plan.consecutive.offset).to.equal(4);
expect(user6x.purchased.plan.consecutive.trinkets).to.equal(5); expect(user6x.purchased.plan.consecutive.trinkets).to.equal(5);
expect(user6x.purchased.plan.consecutive.gemCapExtra).to.equal(25); expect(user6x.purchased.plan.consecutive.gemCapExtra).to.equal(25);
clock.restore();
}); });
it('does not increment consecutive benefits in the third month after the fix goes live', () => { it('does not increment consecutive benefits in the third month after the fix goes live', () => {
@@ -600,7 +565,6 @@ describe('cron', () => {
expect(user6x.purchased.plan.consecutive.offset).to.equal(3); expect(user6x.purchased.plan.consecutive.offset).to.equal(3);
expect(user6x.purchased.plan.consecutive.trinkets).to.equal(5); expect(user6x.purchased.plan.consecutive.trinkets).to.equal(5);
expect(user6x.purchased.plan.consecutive.gemCapExtra).to.equal(25); expect(user6x.purchased.plan.consecutive.gemCapExtra).to.equal(25);
clock.restore();
}); });
it('increments consecutive benefits in the seventh month after the fix goes live', () => { it('increments consecutive benefits in the seventh month after the fix goes live', () => {
@@ -610,7 +574,6 @@ describe('cron', () => {
expect(user6x.purchased.plan.consecutive.offset).to.equal(5); expect(user6x.purchased.plan.consecutive.offset).to.equal(5);
expect(user6x.purchased.plan.consecutive.trinkets).to.equal(7); expect(user6x.purchased.plan.consecutive.trinkets).to.equal(7);
expect(user6x.purchased.plan.consecutive.gemCapExtra).to.equal(25); expect(user6x.purchased.plan.consecutive.gemCapExtra).to.equal(25);
clock.restore();
}); });
}); });
}); });
@@ -627,14 +590,12 @@ describe('cron', () => {
}); });
it('does not reset plan.gemsBought within the month', () => { it('does not reset plan.gemsBought within the month', () => {
let clock = sinon.useFakeTimers(moment().startOf('month').add(2, 'days').unix()); clock = sinon.useFakeTimers(moment().startOf('month').add(2, 'days').unix());
user.purchased.plan.dateUpdated = moment().startOf('month').toDate(); user.purchased.plan.dateUpdated = moment().startOf('month').toDate();
user.purchased.plan.gemsBought = 10; user.purchased.plan.gemsBought = 10;
cron({user, tasksByType, daysMissed, analytics}); cron({user, tasksByType, daysMissed, analytics});
expect(user.purchased.plan.gemsBought).to.equal(10); expect(user.purchased.plan.gemsBought).to.equal(10);
clock.restore();
}); });
it('does not reset plan.dateUpdated on a new month', () => { it('does not reset plan.dateUpdated on a new month', () => {
@@ -1040,15 +1001,11 @@ describe('cron', () => {
describe('counters', () => { describe('counters', () => {
let notStartOfWeekOrMonth = new Date(2016, 9, 28).getTime(); // a Friday let notStartOfWeekOrMonth = new Date(2016, 9, 28).getTime(); // a Friday
let clock;
beforeEach(() => { beforeEach(() => {
// Replace system clocks so we can get predictable results // Replace system clocks so we can get predictable results
clock = sinon.useFakeTimers(notStartOfWeekOrMonth); clock = sinon.useFakeTimers(notStartOfWeekOrMonth);
}); });
afterEach(() => {
return clock.restore();
});
it('should reset a daily habit counter each day', () => { it('should reset a daily habit counter each day', () => {
tasksByType.habits[0].counterUp = 1; tasksByType.habits[0].counterUp = 1;

View File

@@ -3,9 +3,9 @@ import got from 'got';
import nconf from 'nconf'; import nconf from 'nconf';
import nodemailer from 'nodemailer'; import nodemailer from 'nodemailer';
import requireAgain from 'require-again'; import requireAgain from 'require-again';
import logger from '../../../../../website/server/libs/logger'; import logger from '../../../../website/server/libs/logger';
import { TAVERN_ID } from '../../../../../website/server/models/group'; import { TAVERN_ID } from '../../../../website/server/models/group';
import { defer } from '../../../../helpers/api-unit.helper'; import { defer } from '../../../helpers/api-unit.helper';
function getUser () { function getUser () {
return { return {
@@ -19,7 +19,6 @@ function getUser () {
emails: [{ emails: [{
value: 'email@facebook', value: 'email@facebook',
}], }],
displayName: 'fb display name',
}, },
}, },
profile: { profile: {
@@ -34,7 +33,7 @@ function getUser () {
} }
describe('emails', () => { describe('emails', () => {
let pathToEmailLib = '../../../../../website/server/libs/email'; let pathToEmailLib = '../../../../website/server/libs/email';
describe('sendEmail', () => { describe('sendEmail', () => {
let sendMailSpy; let sendMailSpy;
@@ -100,7 +99,7 @@ describe('emails', () => {
let data = getUserInfo(user, ['name', 'email', '_id', 'canSend']); let data = getUserInfo(user, ['name', 'email', '_id', 'canSend']);
expect(data).to.have.property('name', user.auth.facebook.displayName); expect(data).to.have.property('name', user.profile.name);
expect(data).to.have.property('email', user.auth.facebook.emails[0].value); expect(data).to.have.property('email', user.auth.facebook.emails[0].value);
expect(data).to.have.property('_id', user._id); expect(data).to.have.property('_id', user._id);
expect(data).to.have.property('canSend', true); expect(data).to.have.property('canSend', true);
@@ -110,13 +109,12 @@ describe('emails', () => {
let attachEmail = requireAgain(pathToEmailLib); let attachEmail = requireAgain(pathToEmailLib);
let getUserInfo = attachEmail.getUserInfo; let getUserInfo = attachEmail.getUserInfo;
let user = getUser(); let user = getUser();
delete user.profile.name;
delete user.auth.local.email; delete user.auth.local.email;
delete user.auth.facebook; delete user.auth.facebook;
let data = getUserInfo(user, ['name', 'email', '_id', 'canSend']); let data = getUserInfo(user, ['name', 'email', '_id', 'canSend']);
expect(data).to.have.property('name', user.auth.local.username); expect(data).to.have.property('name', user.profile.name);
expect(data).not.to.have.property('email'); expect(data).not.to.have.property('email');
expect(data).to.have.property('_id', user._id); expect(data).to.have.property('_id', user._id);
expect(data).to.have.property('canSend', true); expect(data).to.have.property('canSend', true);

View File

@@ -1,7 +1,7 @@
import { import {
encrypt, encrypt,
decrypt, decrypt,
} from '../../../../../website/server/libs/encryption'; } from '../../../../website/server/libs/encryption';
describe('encryption', () => { describe('encryption', () => {
it('can encrypt and decrypt', () => { it('can encrypt and decrypt', () => {

View File

@@ -5,7 +5,7 @@ import {
BadRequest, BadRequest,
InternalServerError, InternalServerError,
NotFound, NotFound,
} from '../../../../../website/server/libs/errors'; } from '../../../../website/server/libs/errors';
describe('Custom Errors', () => { describe('Custom Errors', () => {
describe('CustomError', () => { describe('CustomError', () => {

View File

@@ -2,7 +2,7 @@ import {
translations, translations,
localePath, localePath,
langCodes, langCodes,
} from '../../../../../website/server/libs/i18n'; } from '../../../../website/server/libs/i18n';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';

View File

@@ -1,8 +1,8 @@
import winston from 'winston'; import winston from 'winston';
import logger from '../../../../../website/server/libs/logger'; import logger from '../../../../website/server/libs/logger';
import { import {
NotFound, NotFound,
} from '../../../../../website/server/libs//errors'; } from '../../../../website/server/libs//errors';
describe('logger', () => { describe('logger', () => {
let logSpy; let logSpy;

View File

@@ -2,11 +2,11 @@
import { import {
encrypt, encrypt,
} from '../../../../../website/server/libs/encryption'; } from '../../../../website/server/libs/encryption';
import moment from 'moment'; import moment from 'moment';
import { import {
generateUser, generateUser,
} from '../../../../helpers/api-integration/v3'; } from '../../../helpers/api-integration/v3';
import { import {
sha1Encrypt as sha1EncryptPassword, sha1Encrypt as sha1EncryptPassword,
sha1MakeSalt, sha1MakeSalt,
@@ -15,7 +15,7 @@ import {
compare, compare,
convertToBcrypt, convertToBcrypt,
validatePasswordResetCodeAndFindUser, validatePasswordResetCodeAndFindUser,
} from '../../../../../website/server/libs/password'; } from '../../../../website/server/libs/password';
describe('Password Utilities', () => { describe('Password Utilities', () => {
describe('compare', () => { describe('compare', () => {

View File

@@ -2,11 +2,11 @@ import moment from 'moment';
import { import {
generateGroup, generateGroup,
} from '../../../../../../helpers/api-unit.helper.js'; } from '../../../../../helpers/api-unit.helper.js';
import { model as User } from '../../../../../../../website/server/models/user'; import { model as User } from '../../../../../../website/server/models/user';
import amzLib from '../../../../../../../website/server/libs/payments/amazon'; import amzLib from '../../../../../../website/server/libs/payments/amazon';
import payments from '../../../../../../../website/server/libs/payments/payments'; import payments from '../../../../../../website/server/libs/payments/payments';
import common from '../../../../../../../website/common'; import common from '../../../../../../website/common';
import { createNonLeaderGroupMember } from '../paymentHelpers'; import { createNonLeaderGroupMember } from '../paymentHelpers';
const i18n = common.i18n; const i18n = common.i18n;

View File

@@ -1,7 +1,7 @@
import { model as User } from '../../../../../../../website/server/models/user'; import { model as User } from '../../../../../../website/server/models/user';
import amzLib from '../../../../../../../website/server/libs/payments/amazon'; import amzLib from '../../../../../../website/server/libs/payments/amazon';
import payments from '../../../../../../../website/server/libs/payments/payments'; import payments from '../../../../../../website/server/libs/payments/payments';
import common from '../../../../../../../website/common'; import common from '../../../../../../website/common';
const i18n = common.i18n; const i18n = common.i18n;

View File

@@ -2,12 +2,12 @@ import cc from 'coupon-code';
import { import {
generateGroup, generateGroup,
} from '../../../../../../helpers/api-unit.helper.js'; } from '../../../../../helpers/api-unit.helper.js';
import { model as User } from '../../../../../../../website/server/models/user'; import { model as User } from '../../../../../../website/server/models/user';
import { model as Coupon } from '../../../../../../../website/server/models/coupon'; import { model as Coupon } from '../../../../../../website/server/models/coupon';
import amzLib from '../../../../../../../website/server/libs/payments/amazon'; import amzLib from '../../../../../../website/server/libs/payments/amazon';
import payments from '../../../../../../../website/server/libs/payments/payments'; import payments from '../../../../../../website/server/libs/payments/payments';
import common from '../../../../../../../website/common'; import common from '../../../../../../website/common';
const i18n = common.i18n; const i18n = common.i18n;

View File

@@ -2,11 +2,11 @@ import uuid from 'uuid';
import { import {
generateGroup, generateGroup,
} from '../../../../../../helpers/api-unit.helper.js'; } from '../../../../../helpers/api-unit.helper.js';
import { model as User } from '../../../../../../../website/server/models/user'; import { model as User } from '../../../../../../website/server/models/user';
import { model as Group } from '../../../../../../../website/server/models/group'; import { model as Group } from '../../../../../../website/server/models/group';
import amzLib from '../../../../../../../website/server/libs/payments/amazon'; import amzLib from '../../../../../../website/server/libs/payments/amazon';
import payments from '../../../../../../../website/server/libs/payments/payments'; import payments from '../../../../../../website/server/libs/payments/payments';
describe('#upgradeGroupPlan', () => { describe('#upgradeGroupPlan', () => {
let spy, data, user, group, uuidString; let spy, data, user, group, uuidString;

View File

@@ -1,10 +1,10 @@
/* eslint-disable camelcase */ /* eslint-disable camelcase */
import iapModule from '../../../../../../website/server/libs/inAppPurchases'; import iapModule from '../../../../../website/server/libs/inAppPurchases';
import payments from '../../../../../../website/server/libs/payments/payments'; import payments from '../../../../../website/server/libs/payments/payments';
import applePayments from '../../../../../../website/server/libs/payments/apple'; import applePayments from '../../../../../website/server/libs/payments/apple';
import iap from '../../../../../../website/server/libs/inAppPurchases'; import iap from '../../../../../website/server/libs/inAppPurchases';
import {model as User} from '../../../../../../website/server/models/user'; import {model as User} from '../../../../../website/server/models/user';
import common from '../../../../../../website/common'; import common from '../../../../../website/common';
import moment from 'moment'; import moment from 'moment';
const i18n = common.i18n; const i18n = common.i18n;

View File

@@ -1,10 +1,10 @@
/* eslint-disable camelcase */ /* eslint-disable camelcase */
import iapModule from '../../../../../../website/server/libs/inAppPurchases'; import iapModule from '../../../../../website/server/libs/inAppPurchases';
import payments from '../../../../../../website/server/libs/payments/payments'; import payments from '../../../../../website/server/libs/payments/payments';
import googlePayments from '../../../../../../website/server/libs/payments/google'; import googlePayments from '../../../../../website/server/libs/payments/google';
import iap from '../../../../../../website/server/libs/inAppPurchases'; import iap from '../../../../../website/server/libs/inAppPurchases';
import {model as User} from '../../../../../../website/server/models/user'; import {model as User} from '../../../../../website/server/models/user';
import common from '../../../../../../website/common'; import common from '../../../../../website/common';
import moment from 'moment'; import moment from 'moment';
const i18n = common.i18n; const i18n = common.i18n;

View File

@@ -1,13 +1,13 @@
import moment from 'moment'; import moment from 'moment';
import * as sender from '../../../../../../../website/server/libs/email'; import * as sender from '../../../../../../website/server/libs/email';
import * as api from '../../../../../../../website/server/libs/payments/payments'; import * as api from '../../../../../../website/server/libs/payments/payments';
import { model as User } from '../../../../../../../website/server/models/user'; import { model as User } from '../../../../../../website/server/models/user';
import { model as Group } from '../../../../../../../website/server/models/group'; import { model as Group } from '../../../../../../website/server/models/group';
import { import {
generateGroup, generateGroup,
} from '../../../../../../helpers/api-unit.helper.js'; } from '../../../../../helpers/api-unit.helper.js';
import i18n from '../../../../../../../website/common/script/i18n'; import i18n from '../../../../../../website/common/script/i18n';
describe('Canceling a subscription for group', () => { describe('Canceling a subscription for group', () => {
let plan, group, user, data; let plan, group, user, data;

View File

@@ -2,16 +2,16 @@ import moment from 'moment';
import stripeModule from 'stripe'; import stripeModule from 'stripe';
import nconf from 'nconf'; import nconf from 'nconf';
import * as sender from '../../../../../../../website/server/libs/email'; import * as sender from '../../../../../../website/server/libs/email';
import * as api from '../../../../../../../website/server/libs/payments/payments'; import * as api from '../../../../../../website/server/libs/payments/payments';
import amzLib from '../../../../../../../website/server/libs/payments/amazon'; import amzLib from '../../../../../../website/server/libs/payments/amazon';
import paypalPayments from '../../../../../../../website/server/libs/payments/paypal'; import paypalPayments from '../../../../../../website/server/libs/payments/paypal';
import stripePayments from '../../../../../../../website/server/libs/payments/stripe'; import stripePayments from '../../../../../../website/server/libs/payments/stripe';
import { model as User } from '../../../../../../../website/server/models/user'; import { model as User } from '../../../../../../website/server/models/user';
import { model as Group } from '../../../../../../../website/server/models/group'; import { model as Group } from '../../../../../../website/server/models/group';
import { import {
generateGroup, generateGroup,
} from '../../../../../../helpers/api-unit.helper.js'; } from '../../../../../helpers/api-unit.helper.js';
describe('Purchasing a group plan for group', () => { describe('Purchasing a group plan for group', () => {
const EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_GOOGLE = 'Google_subscription'; const EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_GOOGLE = 'Google_subscription';
@@ -443,8 +443,7 @@ describe('Purchasing a group plan for group', () => {
await api.createSubscription(data); await api.createSubscription(data);
let updatedUser = await User.findById(recipient._id).exec(); const updatedUser = await User.findById(recipient._id).exec();
expect(updatedUser.purchased.plan.extraMonths).to.within(2, 3); expect(updatedUser.purchased.plan.extraMonths).to.within(2, 3);
}); });

View File

@@ -1,4 +1,4 @@
import { model as User } from '../../../../../../website/server/models/user'; import { model as User } from '../../../../../website/server/models/user';
export async function createNonLeaderGroupMember (group) { export async function createNonLeaderGroupMember (group) {
let nonLeader = new User(); let nonLeader = new User();

View File

@@ -1,14 +1,14 @@
import moment from 'moment'; import moment from 'moment';
import * as sender from '../../../../../../website/server/libs/email'; import * as sender from '../../../../../website/server/libs/email';
import * as api from '../../../../../../website/server/libs/payments/payments'; import * as api from '../../../../../website/server/libs/payments/payments';
import analytics from '../../../../../../website/server/libs/analyticsService'; import analytics from '../../../../../website/server/libs/analyticsService';
import notifications from '../../../../../../website/server/libs/pushNotifications'; import notifications from '../../../../../website/server/libs/pushNotifications';
import { model as User } from '../../../../../../website/server/models/user'; import { model as User } from '../../../../../website/server/models/user';
import { translate as t } from '../../../../../helpers/api-v3-integration.helper'; import { translate as t } from '../../../../helpers/api-integration/v3';
import { import {
generateGroup, generateGroup,
} from '../../../../../helpers/api-unit.helper.js'; } from '../../../../helpers/api-unit.helper.js';
describe('payments/index', () => { describe('payments/index', () => {
let user, group, data, plan; let user, group, data, plan;
@@ -210,7 +210,7 @@ describe('payments/index', () => {
let msg = '\`Hello recipient, sender has sent you 3 months of subscription!\`'; let msg = '\`Hello recipient, sender has sent you 3 months of subscription!\`';
expect(user.sendMessage).to.be.calledOnce; expect(user.sendMessage).to.be.calledOnce;
expect(user.sendMessage).to.be.calledWith(recipient, { receiverMsg: msg, senderMsg: msg }); expect(user.sendMessage).to.be.calledWith(recipient, { receiverMsg: msg, senderMsg: msg, save: false });
}); });
it('sends an email about the gift', async () => { it('sends an email about the gift', async () => {
@@ -629,7 +629,7 @@ describe('payments/index', () => {
await api.buyGems(data); await api.buyGems(data);
let msg = '\`Hello recipient, sender has sent you 4 gems!\`'; let msg = '\`Hello recipient, sender has sent you 4 gems!\`';
expect(user.sendMessage).to.be.calledWith(recipient, { receiverMsg: msg, senderMsg: msg }); expect(user.sendMessage).to.be.calledWith(recipient, { receiverMsg: msg, senderMsg: msg, save: false });
}); });
it('sends a message from purchaser to recipient wtih custom message', async () => { it('sends a message from purchaser to recipient wtih custom message', async () => {
@@ -638,7 +638,7 @@ describe('payments/index', () => {
await api.buyGems(data); await api.buyGems(data);
const msg = `\`Hello recipient, sender has sent you 4 gems!\` ${data.gift.message}`; const msg = `\`Hello recipient, sender has sent you 4 gems!\` ${data.gift.message}`;
expect(user.sendMessage).to.be.calledWith(recipient, { receiverMsg: msg, senderMsg: msg }); expect(user.sendMessage).to.be.calledWith(recipient, { receiverMsg: msg, senderMsg: msg, save: false });
}); });
it('sends a push notification if user did not gift to self', async () => { it('sends a push notification if user did not gift to self', async () => {
@@ -667,7 +667,7 @@ describe('payments/index', () => {
return `\`${messageContent}\``; return `\`${messageContent}\``;
}); });
expect(user.sendMessage).to.be.calledWith(recipient, { receiverMsg: recipientsMessageContent, senderMsg: sendersMessageContent }); expect(user.sendMessage).to.be.calledWith(recipient, { receiverMsg: recipientsMessageContent, senderMsg: sendersMessageContent, save: false });
}); });
}); });
}); });

View File

@@ -1,7 +1,7 @@
/* eslint-disable camelcase */ /* eslint-disable camelcase */
import paypalPayments from '../../../../../../../website/server/libs/payments/paypal'; import paypalPayments from '../../../../../../website/server/libs/payments/paypal';
import payments from '../../../../../../../website/server/libs/payments/payments'; import payments from '../../../../../../website/server/libs/payments/payments';
import { model as User } from '../../../../../../../website/server/models/user'; import { model as User } from '../../../../../../website/server/models/user';
describe('checkout success', () => { describe('checkout success', () => {
const subKey = 'basic_3mo'; const subKey = 'basic_3mo';

View File

@@ -1,9 +1,9 @@
/* eslint-disable camelcase */ /* eslint-disable camelcase */
import nconf from 'nconf'; import nconf from 'nconf';
import paypalPayments from '../../../../../../../website/server/libs/payments/paypal'; import paypalPayments from '../../../../../../website/server/libs/payments/paypal';
import { model as User } from '../../../../../../../website/server/models/user'; import { model as User } from '../../../../../../website/server/models/user';
import common from '../../../../../../../website/common'; import common from '../../../../../../website/common';
const BASE_URL = nconf.get('BASE_URL'); const BASE_URL = nconf.get('BASE_URL');
const i18n = common.i18n; const i18n = common.i18n;

View File

@@ -1,10 +1,10 @@
/* eslint-disable camelcase */ /* eslint-disable camelcase */
import paypalPayments from '../../../../../../../website/server/libs/payments/paypal'; import paypalPayments from '../../../../../../website/server/libs/payments/paypal';
import payments from '../../../../../../../website/server/libs/payments/payments'; import payments from '../../../../../../website/server/libs/payments/payments';
import { import {
generateGroup, generateGroup,
} from '../../../../../../helpers/api-unit.helper.js'; } from '../../../../../helpers/api-unit.helper.js';
import { model as User } from '../../../../../../../website/server/models/user'; import { model as User } from '../../../../../../website/server/models/user';
describe('ipn', () => { describe('ipn', () => {
const subKey = 'basic_3mo'; const subKey = 'basic_3mo';

View File

@@ -1,11 +1,11 @@
/* eslint-disable camelcase */ /* eslint-disable camelcase */
import paypalPayments from '../../../../../../../website/server/libs/payments/paypal'; import paypalPayments from '../../../../../../website/server/libs/payments/paypal';
import payments from '../../../../../../../website/server/libs/payments/payments'; import payments from '../../../../../../website/server/libs/payments/payments';
import { import {
generateGroup, generateGroup,
} from '../../../../../../helpers/api-unit.helper.js'; } from '../../../../../helpers/api-unit.helper.js';
import { model as User } from '../../../../../../../website/server/models/user'; import { model as User } from '../../../../../../website/server/models/user';
import common from '../../../../../../../website/common'; import common from '../../../../../../website/common';
import { createNonLeaderGroupMember } from '../paymentHelpers'; import { createNonLeaderGroupMember } from '../paymentHelpers';
const i18n = common.i18n; const i18n = common.i18n;

View File

@@ -1,11 +1,11 @@
/* eslint-disable camelcase */ /* eslint-disable camelcase */
import paypalPayments from '../../../../../../../website/server/libs/payments/paypal'; import paypalPayments from '../../../../../../website/server/libs/payments/paypal';
import payments from '../../../../../../../website/server/libs/payments/payments'; import payments from '../../../../../../website/server/libs/payments/payments';
import { import {
generateGroup, generateGroup,
} from '../../../../../../helpers/api-unit.helper.js'; } from '../../../../../helpers/api-unit.helper.js';
import { model as User } from '../../../../../../../website/server/models/user'; import { model as User } from '../../../../../../website/server/models/user';
import common from '../../../../../../../website/common'; import common from '../../../../../../website/common';
describe('subscribeSuccess', () => { describe('subscribeSuccess', () => {
const subKey = 'basic_3mo'; const subKey = 'basic_3mo';

View File

@@ -2,9 +2,9 @@
import moment from 'moment'; import moment from 'moment';
import cc from 'coupon-code'; import cc from 'coupon-code';
import paypalPayments from '../../../../../../../website/server/libs/payments/paypal'; import paypalPayments from '../../../../../../website/server/libs/payments/paypal';
import { model as Coupon } from '../../../../../../../website/server/models/coupon'; import { model as Coupon } from '../../../../../../website/server/models/coupon';
import common from '../../../../../../../website/common'; import common from '../../../../../../website/common';
const i18n = common.i18n; const i18n = common.i18n;

View File

@@ -2,11 +2,11 @@ import stripeModule from 'stripe';
import { import {
generateGroup, generateGroup,
} from '../../../../../../helpers/api-unit.helper.js'; } from '../../../../../helpers/api-unit.helper.js';
import { model as User } from '../../../../../../../website/server/models/user'; import { model as User } from '../../../../../../website/server/models/user';
import stripePayments from '../../../../../../../website/server/libs/payments/stripe'; import stripePayments from '../../../../../../website/server/libs/payments/stripe';
import payments from '../../../../../../../website/server/libs/payments/payments'; import payments from '../../../../../../website/server/libs/payments/payments';
import common from '../../../../../../../website/common'; import common from '../../../../../../website/common';
const i18n = common.i18n; const i18n = common.i18n;

View File

@@ -3,12 +3,12 @@ import cc from 'coupon-code';
import { import {
generateGroup, generateGroup,
} from '../../../../../../helpers/api-unit.helper.js'; } from '../../../../../helpers/api-unit.helper.js';
import { model as User } from '../../../../../../../website/server/models/user'; import { model as User } from '../../../../../../website/server/models/user';
import { model as Coupon } from '../../../../../../../website/server/models/coupon'; import { model as Coupon } from '../../../../../../website/server/models/coupon';
import stripePayments from '../../../../../../../website/server/libs/payments/stripe'; import stripePayments from '../../../../../../website/server/libs/payments/stripe';
import payments from '../../../../../../../website/server/libs/payments/payments'; import payments from '../../../../../../website/server/libs/payments/payments';
import common from '../../../../../../../website/common'; import common from '../../../../../../website/common';
const i18n = common.i18n; const i18n = common.i18n;

View File

@@ -1,9 +1,9 @@
import stripeModule from 'stripe'; import stripeModule from 'stripe';
import { model as User } from '../../../../../../../website/server/models/user'; import { model as User } from '../../../../../../website/server/models/user';
import stripePayments from '../../../../../../../website/server/libs/payments/stripe'; import stripePayments from '../../../../../../website/server/libs/payments/stripe';
import payments from '../../../../../../../website/server/libs/payments/payments'; import payments from '../../../../../../website/server/libs/payments/payments';
import common from '../../../../../../../website/common'; import common from '../../../../../../website/common';
const i18n = common.i18n; const i18n = common.i18n;
@@ -37,6 +37,22 @@ describe('checkout', () => {
payments.createSubscription.restore(); payments.createSubscription.restore();
}); });
it('should error if there is no token', async () => {
await expect(stripePayments.checkout({
user,
gift,
groupId,
email,
headers,
coupon,
}, stripe))
.to.eventually.be.rejected.and.to.eql({
httpCode: 400,
message: 'Missing req.body.id',
name: 'BadRequest',
});
});
it('should error if gem amount is too low', async () => { it('should error if gem amount is too low', async () => {
let receivingUser = new User(); let receivingUser = new User();
receivingUser.save(); receivingUser.save();
@@ -64,7 +80,6 @@ describe('checkout', () => {
}); });
}); });
it('should error if user cannot get gems', async () => { it('should error if user cannot get gems', async () => {
gift = undefined; gift = undefined;
sinon.stub(user, 'canGetGems').returnsPromise().resolves(false); sinon.stub(user, 'canGetGems').returnsPromise().resolves(false);

View File

@@ -2,10 +2,10 @@ import stripeModule from 'stripe';
import { import {
generateGroup, generateGroup,
} from '../../../../../../helpers/api-unit.helper.js'; } from '../../../../../helpers/api-unit.helper.js';
import { model as User } from '../../../../../../../website/server/models/user'; import { model as User } from '../../../../../../website/server/models/user';
import stripePayments from '../../../../../../../website/server/libs/payments/stripe'; import stripePayments from '../../../../../../website/server/libs/payments/stripe';
import common from '../../../../../../../website/common'; import common from '../../../../../../website/common';
const i18n = common.i18n; const i18n = common.i18n;

View File

@@ -2,12 +2,12 @@ import stripeModule from 'stripe';
import { import {
generateGroup, generateGroup,
} from '../../../../../../helpers/api-unit.helper.js'; } from '../../../../../helpers/api-unit.helper.js';
import { model as User } from '../../../../../../../website/server/models/user'; import { model as User } from '../../../../../../website/server/models/user';
import stripePayments from '../../../../../../../website/server/libs/payments/stripe'; import stripePayments from '../../../../../../website/server/libs/payments/stripe';
import payments from '../../../../../../../website/server/libs/payments/payments'; import payments from '../../../../../../website/server/libs/payments/payments';
import common from '../../../../../../../website/common'; import common from '../../../../../../website/common';
import logger from '../../../../../../../website/server/libs/logger'; import logger from '../../../../../../website/server/libs/logger';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import moment from 'moment'; import moment from 'moment';

View File

@@ -2,11 +2,11 @@ import stripeModule from 'stripe';
import { import {
generateGroup, generateGroup,
} from '../../../../../../helpers/api-unit.helper.js'; } from '../../../../../helpers/api-unit.helper.js';
import { model as User } from '../../../../../../../website/server/models/user'; import { model as User } from '../../../../../../website/server/models/user';
import { model as Group } from '../../../../../../../website/server/models/group'; import { model as Group } from '../../../../../../website/server/models/group';
import stripePayments from '../../../../../../../website/server/libs/payments/stripe'; import stripePayments from '../../../../../../website/server/libs/payments/stripe';
import payments from '../../../../../../../website/server/libs/payments/payments'; import payments from '../../../../../../website/server/libs/payments/payments';
describe('Stripe - Upgrade Group Plan', () => { describe('Stripe - Upgrade Group Plan', () => {
const stripe = stripeModule('test'); const stripe = stripeModule('test');

View File

@@ -1,7 +1,7 @@
import { preenHistory } from '../../../../../website/server/libs/preening'; import { preenHistory } from '../../../../website/server/libs/preening';
import moment from 'moment'; import moment from 'moment';
import sinon from 'sinon'; // eslint-disable-line no-shadow import sinon from 'sinon'; // eslint-disable-line no-shadow
import { generateHistory } from '../../../../helpers/api-unit.helper.js'; import { generateHistory } from '../../../helpers/api-unit.helper.js';
describe('preenHistory', () => { describe('preenHistory', () => {
let clock; let clock;

View File

@@ -1,4 +1,4 @@
import { model as User } from '../../../../../website/server/models/user'; import { model as User } from '../../../../website/server/models/user';
import requireAgain from 'require-again'; import requireAgain from 'require-again';
import pushNotify from 'push-notify'; import pushNotify from 'push-notify';
import nconf from 'nconf'; import nconf from 'nconf';
@@ -7,7 +7,7 @@ import gcmLib from 'node-gcm'; // works with FCM notifications too
describe('pushNotifications', () => { describe('pushNotifications', () => {
let user; let user;
let sendPushNotification; let sendPushNotification;
let pathToPushNotifications = '../../../../../website/server/libs/pushNotifications'; let pathToPushNotifications = '../../../../website/server/libs/pushNotifications';
let fcmSendSpy; let fcmSendSpy;
let apnSendSpy; let apnSendSpy;

View File

@@ -1,4 +1,4 @@
import setupNconf from '../../../../../website/server/libs/setupNconf'; import setupNconf from '../../../../website/server/libs/setupNconf';
import path from 'path'; import path from 'path';
import nconf from 'nconf'; import nconf from 'nconf';

View File

@@ -1,10 +1,11 @@
/* eslint-disable camelcase */ /* eslint-disable camelcase */
import { IncomingWebhook } from '@slack/client'; import { IncomingWebhook } from '@slack/client';
import requireAgain from 'require-again'; import requireAgain from 'require-again';
import slack from '../../../../../website/server/libs/slack'; import slack from '../../../../website/server/libs/slack';
import logger from '../../../../../website/server/libs/logger'; import logger from '../../../../website/server/libs/logger';
import { TAVERN_ID } from '../../../../../website/server/models/group'; import { TAVERN_ID } from '../../../../website/server/models/group';
import nconf from 'nconf'; import nconf from 'nconf';
import moment from 'moment';
describe('slack', () => { describe('slack', () => {
describe('sendFlagNotification', () => { describe('sendFlagNotification', () => {
@@ -45,13 +46,15 @@ describe('slack', () => {
it('sends a slack webhook', () => { it('sends a slack webhook', () => {
slack.sendFlagNotification(data); slack.sendFlagNotification(data);
const timestamp = `${moment(data.message.timestamp).utc().format('YYYY-MM-DD HH:mm')} UTC`;
expect(IncomingWebhook.prototype.send).to.be.calledOnce; expect(IncomingWebhook.prototype.send).to.be.calledOnce;
expect(IncomingWebhook.prototype.send).to.be.calledWith({ expect(IncomingWebhook.prototype.send).to.be.calledWith({
text: 'flagger (flagger-id; language: flagger-lang) flagged a message', text: 'flagger (flagger-id; language: flagger-lang) flagged a message',
attachments: [{ attachments: [{
fallback: 'Flag Message', fallback: 'Flag Message',
color: 'danger', color: 'danger',
author_name: 'Author - author@example.com - author-id', author_name: `Author - author@example.com - author-id\n${timestamp}`,
title: 'Flag in Some group - (private guild)', title: 'Flag in Some group - (private guild)',
title_link: undefined, title_link: undefined,
text: 'some text', text: 'some text',
@@ -97,9 +100,11 @@ describe('slack', () => {
slack.sendFlagNotification(data); slack.sendFlagNotification(data);
const timestamp = `${moment(data.message.timestamp).utc().format('YYYY-MM-DD HH:mm')} UTC`;
expect(IncomingWebhook.prototype.send).to.be.calledWithMatch({ expect(IncomingWebhook.prototype.send).to.be.calledWithMatch({
attachments: [sandbox.match({ attachments: [sandbox.match({
author_name: 'System Message', author_name: `System Message\n${timestamp}`,
})], })],
}); });
}); });
@@ -107,7 +112,7 @@ describe('slack', () => {
it('noops if no flagging url is provided', () => { it('noops if no flagging url is provided', () => {
sandbox.stub(nconf, 'get').withArgs('SLACK:FLAGGING_URL').returns(''); sandbox.stub(nconf, 'get').withArgs('SLACK:FLAGGING_URL').returns('');
sandbox.stub(logger, 'error'); sandbox.stub(logger, 'error');
let reRequiredSlack = requireAgain('../../../../../website/server/libs/slack'); let reRequiredSlack = requireAgain('../../../../website/server/libs/slack');
expect(logger.error).to.be.calledOnce; expect(logger.error).to.be.calledOnce;

View File

@@ -3,13 +3,13 @@ import {
getTasks, getTasks,
syncableAttrs, syncableAttrs,
moveTask, moveTask,
} from '../../../../../website/server/libs/taskManager'; } from '../../../../website/server/libs/taskManager';
import i18n from '../../../../../website/common/script/i18n'; import i18n from '../../../../website/common/script/i18n';
import { import {
generateUser, generateUser,
generateGroup, generateGroup,
generateChallenge, generateChallenge,
} from '../../../../helpers/api-unit.helper.js'; } from '../../../helpers/api-unit.helper.js';
describe('taskManager', () => { describe('taskManager', () => {
let user, group, challenge; let user, group, challenge;

View File

@@ -6,11 +6,14 @@ import {
taskActivityWebhook, taskActivityWebhook,
questActivityWebhook, questActivityWebhook,
userActivityWebhook, userActivityWebhook,
} from '../../../../../website/server/libs/webhook'; } from '../../../../website/server/libs/webhook';
import {
model as User,
} from '../../../../website/server/models/user';
import { import {
generateUser, generateUser,
} from '../../../../helpers/api-unit.helper.js'; } from '../../../helpers/api-unit.helper.js';
import { defer } from '../../../../helpers/api-unit.helper'; import { defer } from '../../../helpers/api-unit.helper';
describe('webhooks', () => { describe('webhooks', () => {
let webhooks, user; let webhooks, user;
@@ -306,17 +309,6 @@ describe('webhooks', () => {
return this; return this;
}, },
}, },
addComputedStatsToJSONObj () {
let mockStats = Object.assign({
maxHealth: 50,
maxMP: 103,
toNextLevel: 40,
}, this.stats);
delete mockStats.toJSON;
return mockStats;
},
}, },
task: { task: {
text: 'text', text: 'text',
@@ -324,6 +316,15 @@ describe('webhooks', () => {
direction: 'up', direction: 'up',
delta: 176, delta: 176,
}; };
let mockStats = Object.assign({
maxHealth: 50,
maxMP: 103,
toNextLevel: 40,
}, data.user.stats);
delete mockStats.toJSON;
sandbox.stub(User, 'addComputedStatsToJSONObj').returns(mockStats);
}); });
it('sends task and stats data', () => { it('sends task and stats data', () => {

View File

@@ -3,14 +3,14 @@ import {
generateRes, generateRes,
generateReq, generateReq,
generateNext, generateNext,
} from '../../../../helpers/api-unit.helper'; } from '../../../helpers/api-unit.helper';
import analyticsService from '../../../../../website/server/libs/analyticsService'; import analyticsService from '../../../../website/server/libs/analyticsService';
import nconf from 'nconf'; import nconf from 'nconf';
import requireAgain from 'require-again'; import requireAgain from 'require-again';
describe('analytics middleware', () => { describe('analytics middleware', () => {
let res, req, next; let res, req, next;
let pathToAnalyticsMiddleware = '../../../../../website/server/middlewares/analytics'; let pathToAnalyticsMiddleware = '../../../../website/server/middlewares/analytics';
beforeEach(() => { beforeEach(() => {
res = generateRes(); res = generateRes();

View File

@@ -1,8 +1,8 @@
import { import {
generateRes, generateRes,
generateReq, generateReq,
} from '../../../../helpers/api-unit.helper'; } from '../../../helpers/api-unit.helper';
import { authWithHeaders as authWithHeadersFactory } from '../../../../../website/server/middlewares/auth'; import { authWithHeaders as authWithHeadersFactory } from '../../../../website/server/middlewares/auth';
describe('auth middleware', () => { describe('auth middleware', () => {
let res, req, user; let res, req, user;

View File

@@ -3,8 +3,8 @@ import {
generateRes, generateRes,
generateReq, generateReq,
generateNext, generateNext,
} from '../../../../helpers/api-unit.helper'; } from '../../../helpers/api-unit.helper';
import cors from '../../../../../website/server/middlewares/cors'; import cors from '../../../../website/server/middlewares/cors';
describe('cors middleware', () => { describe('cors middleware', () => {
let res, req, next; let res, req, next;

View File

@@ -3,14 +3,14 @@ import {
generateReq, generateReq,
generateTodo, generateTodo,
generateDaily, generateDaily,
} from '../../../../helpers/api-unit.helper'; } from '../../../helpers/api-unit.helper';
import cronMiddleware from '../../../../../website/server/middlewares/cron'; import cronMiddleware from '../../../../website/server/middlewares/cron';
import moment from 'moment'; import moment from 'moment';
import { model as User } from '../../../../../website/server/models/user'; import { model as User } from '../../../../website/server/models/user';
import { model as Group } from '../../../../../website/server/models/group'; import { model as Group } from '../../../../website/server/models/group';
import * as Tasks from '../../../../../website/server/models/task'; import * as Tasks from '../../../../website/server/models/task';
import analyticsService from '../../../../../website/server/libs/analyticsService'; import analyticsService from '../../../../website/server/libs/analyticsService';
import * as cronLib from '../../../../../website/server/libs/cron'; import * as cronLib from '../../../../website/server/libs/cron';
import { v4 as generateUUID } from 'uuid'; import { v4 as generateUUID } from 'uuid';
const CRON_TIMEOUT_WAIT = new Date(60 * 60 * 1000).getTime(); const CRON_TIMEOUT_WAIT = new Date(60 * 60 * 1000).getTime();
@@ -166,8 +166,11 @@ describe('cron middleware', () => {
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
cronMiddleware(req, res, (err) => { cronMiddleware(req, res, (err) => {
if (err) return reject(err); if (err) return reject(err);
expect(user.stats.hp).to.be.lessThan(hpBefore); User.findOne({_id: user._id}, function (secondErr, updatedUser) {
resolve(); if (secondErr) return reject(secondErr);
expect(updatedUser.stats.hp).to.be.lessThan(hpBefore);
resolve();
});
}); });
}); });
}); });
@@ -176,7 +179,7 @@ describe('cron middleware', () => {
user.lastCron = moment(new Date()).subtract({days: 2}); user.lastCron = moment(new Date()).subtract({days: 2});
let todo = generateTodo(user); let todo = generateTodo(user);
let todoValueBefore = todo.value; let todoValueBefore = todo.value;
await user.save(); await Promise.all([todo.save(), user.save()]);
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
cronMiddleware(req, res, (err) => { cronMiddleware(req, res, (err) => {
@@ -217,8 +220,11 @@ describe('cron middleware', () => {
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
cronMiddleware(req, res, (err) => { cronMiddleware(req, res, (err) => {
if (err) return reject(err); if (err) return reject(err);
expect(user.stats.hp).to.be.lessThan(hpBefore); User.findOne({_id: user._id}, function (secondErr, updatedUser) {
resolve(); if (secondErr) return reject(secondErr);
expect(updatedUser.stats.hp).to.be.lessThan(hpBefore);
resolve();
});
}); });
}); });
}); });

View File

@@ -3,11 +3,11 @@ import {
generateRes, generateRes,
generateReq, generateReq,
generateNext, generateNext,
} from '../../../../helpers/api-unit.helper'; } from '../../../helpers/api-unit.helper';
import i18n from '../../../../../website/common/script/i18n'; import i18n from '../../../../website/common/script/i18n';
import { ensureAdmin, ensureSudo } from '../../../../../website/server/middlewares/ensureAccessRight'; import { ensureAdmin, ensureSudo } from '../../../../website/server/middlewares/ensureAccessRight';
import { NotAuthorized } from '../../../../../website/server/libs/errors'; import { NotAuthorized } from '../../../../website/server/libs/errors';
import apiError from '../../../../../website/server/libs/apiError'; import apiError from '../../../../website/server/libs/apiError';
describe('ensure access middlewares', () => { describe('ensure access middlewares', () => {
let res, req, next; let res, req, next;

View File

@@ -3,9 +3,9 @@ import {
generateRes, generateRes,
generateReq, generateReq,
generateNext, generateNext,
} from '../../../../helpers/api-unit.helper'; } from '../../../helpers/api-unit.helper';
import ensureDevelpmentMode from '../../../../../website/server/middlewares/ensureDevelpmentMode'; import ensureDevelpmentMode from '../../../../website/server/middlewares/ensureDevelpmentMode';
import { NotFound } from '../../../../../website/server/libs/errors'; import { NotFound } from '../../../../website/server/libs/errors';
import nconf from 'nconf'; import nconf from 'nconf';
describe('developmentMode middleware', () => { describe('developmentMode middleware', () => {

View File

@@ -2,17 +2,17 @@ import {
generateRes, generateRes,
generateReq, generateReq,
generateNext, generateNext,
} from '../../../../helpers/api-unit.helper'; } from '../../../helpers/api-unit.helper';
import errorHandler from '../../../../../website/server/middlewares/errorHandler'; import errorHandler from '../../../../website/server/middlewares/errorHandler';
import responseMiddleware from '../../../../../website/server/middlewares/response'; import responseMiddleware from '../../../../website/server/middlewares/response';
import { import {
getUserLanguage, getUserLanguage,
attachTranslateFunction, attachTranslateFunction,
} from '../../../../../website/server/middlewares/language'; } from '../../../../website/server/middlewares/language';
import { BadRequest } from '../../../../../website/server/libs/errors'; import { BadRequest } from '../../../../website/server/libs/errors';
import logger from '../../../../../website/server/libs/logger'; import logger from '../../../../website/server/libs/logger';
describe('errorHandler', () => { describe('errorHandler', () => {
let res, req, next; let res, req, next;

View File

@@ -2,13 +2,13 @@ import {
generateRes, generateRes,
generateReq, generateReq,
generateNext, generateNext,
} from '../../../../helpers/api-unit.helper'; } from '../../../helpers/api-unit.helper';
import { import {
getUserLanguage, getUserLanguage,
attachTranslateFunction, attachTranslateFunction,
} from '../../../../../website/server/middlewares/language'; } from '../../../../website/server/middlewares/language';
import common from '../../../../../website/common'; import common from '../../../../website/common';
import { model as User } from '../../../../../website/server/models/user'; import { model as User } from '../../../../website/server/models/user';
const i18n = common.i18n; const i18n = common.i18n;

View File

@@ -2,13 +2,13 @@ import {
generateRes, generateRes,
generateReq, generateReq,
generateNext, generateNext,
} from '../../../../helpers/api-unit.helper'; } from '../../../helpers/api-unit.helper';
import nconf from 'nconf'; import nconf from 'nconf';
import requireAgain from 'require-again'; import requireAgain from 'require-again';
describe('maintenance mode middleware', () => { describe('maintenance mode middleware', () => {
let res, req, next; let res, req, next;
let pathToMaintenanceModeMiddleware = '../../../../../website/server/middlewares/maintenanceMode'; let pathToMaintenanceModeMiddleware = '../../../../website/server/middlewares/maintenanceMode';
beforeEach(() => { beforeEach(() => {
res = generateRes(); res = generateRes();

View File

@@ -2,13 +2,13 @@ import {
generateRes, generateRes,
generateReq, generateReq,
generateNext, generateNext,
} from '../../../../helpers/api-unit.helper'; } from '../../../helpers/api-unit.helper';
import nconf from 'nconf'; import nconf from 'nconf';
import requireAgain from 'require-again'; import requireAgain from 'require-again';
describe('redirects middleware', () => { describe('redirects middleware', () => {
let res, req, next; let res, req, next;
let pathToRedirectsMiddleware = '../../../../../website/server/middlewares/redirects'; let pathToRedirectsMiddleware = '../../../../website/server/middlewares/redirects';
beforeEach(() => { beforeEach(() => {
res = generateRes(); res = generateRes();

View File

@@ -2,9 +2,9 @@ import {
generateRes, generateRes,
generateReq, generateReq,
generateNext, generateNext,
} from '../../../../helpers/api-unit.helper'; } from '../../../helpers/api-unit.helper';
import responseMiddleware from '../../../../../website/server/middlewares/response'; import responseMiddleware from '../../../../website/server/middlewares/response';
import packageInfo from '../../../../../package.json'; import packageInfo from '../../../../package.json';
describe('response middleware', () => { describe('response middleware', () => {
let res, req, next; let res, req, next;

View File

@@ -1,8 +1,8 @@
import { model as Challenge } from '../../../../../website/server/models/challenge'; import { model as Challenge } from '../../../../website/server/models/challenge';
import { model as Group } from '../../../../../website/server/models/group'; import { model as Group } from '../../../../website/server/models/group';
import { model as User } from '../../../../../website/server/models/user'; import { model as User } from '../../../../website/server/models/user';
import * as Tasks from '../../../../../website/server/models/task'; import * as Tasks from '../../../../website/server/models/task';
import common from '../../../../../website/common/'; import common from '../../../../website/common/';
import { each, find } from 'lodash'; import { each, find } from 'lodash';
describe('Challenge Model', () => { describe('Challenge Model', () => {

View File

@@ -1,23 +1,23 @@
import moment from 'moment'; import moment from 'moment';
import { v4 as generateUUID } from 'uuid'; import { v4 as generateUUID } from 'uuid';
import validator from 'validator'; import validator from 'validator';
import { sleep, translationCheck } from '../../../../helpers/api-unit.helper'; import { sleep, translationCheck } from '../../../helpers/api-unit.helper';
import { import {
SPAM_MESSAGE_LIMIT, SPAM_MESSAGE_LIMIT,
SPAM_MIN_EXEMPT_CONTRIB_LEVEL, SPAM_MIN_EXEMPT_CONTRIB_LEVEL,
SPAM_WINDOW_LENGTH, SPAM_WINDOW_LENGTH,
INVITES_LIMIT, INVITES_LIMIT,
model as Group, model as Group,
} from '../../../../../website/server/models/group'; } from '../../../../website/server/models/group';
import { model as User } from '../../../../../website/server/models/user'; import { model as User } from '../../../../website/server/models/user';
import { quests as questScrolls } from '../../../../../website/common/script/content'; import { quests as questScrolls } from '../../../../website/common/script/content';
import { import {
groupChatReceivedWebhook, groupChatReceivedWebhook,
questActivityWebhook, questActivityWebhook,
} from '../../../../../website/server/libs/webhook'; } from '../../../../website/server/libs/webhook';
import * as email from '../../../../../website/server/libs/email'; import * as email from '../../../../website/server/libs/email';
import { TAVERN_ID } from '../../../../../website/common/script/'; import { TAVERN_ID } from '../../../../website/common/script/';
import shared from '../../../../../website/common'; import shared from '../../../../website/common';
describe('Group Model', () => { describe('Group Model', () => {
let party, questLeader, participatingMember, nonParticipatingMember, undecidedMember; let party, questLeader, participatingMember, nonParticipatingMember, undecidedMember;

View File

@@ -1,7 +1,7 @@
import { model as Challenge } from '../../../../../website/server/models/challenge'; import { model as Challenge } from '../../../../website/server/models/challenge';
import { model as Group } from '../../../../../website/server/models/group'; import { model as Group } from '../../../../website/server/models/group';
import { model as User } from '../../../../../website/server/models/user'; import { model as User } from '../../../../website/server/models/user';
import * as Tasks from '../../../../../website/server/models/task'; import * as Tasks from '../../../../website/server/models/task';
import { each, find, findIndex } from 'lodash'; import { each, find, findIndex } from 'lodash';
describe('Group Task Methods', () => { describe('Group Task Methods', () => {

View File

@@ -1,10 +1,10 @@
import { model as Challenge } from '../../../../../website/server/models/challenge'; import { model as Challenge } from '../../../../website/server/models/challenge';
import { model as Group } from '../../../../../website/server/models/group'; import { model as Group } from '../../../../website/server/models/group';
import { model as User } from '../../../../../website/server/models/user'; import { model as User } from '../../../../website/server/models/user';
import * as Tasks from '../../../../../website/server/models/task'; import * as Tasks from '../../../../website/server/models/task';
import { InternalServerError } from '../../../../../website/server/libs/errors'; import { InternalServerError } from '../../../../website/server/libs/errors';
import { each } from 'lodash'; import { each } from 'lodash';
import { generateHistory } from '../../../../helpers/api-unit.helper.js'; import { generateHistory } from '../../../helpers/api-unit.helper.js';
describe('Task Model', () => { describe('Task Model', () => {
let guild, leader, challenge, task; let guild, leader, challenge, task;

View File

@@ -1,7 +1,7 @@
import moment from 'moment'; import moment from 'moment';
import { model as User } from '../../../../../website/server/models/user'; import { model as User } from '../../../../website/server/models/user';
import { model as Group } from '../../../../../website/server/models/group'; import { model as Group } from '../../../../website/server/models/group';
import common from '../../../../../website/common'; import common from '../../../../website/common';
describe('User Model', () => { describe('User Model', () => {
it('keeps user._tmp when calling .toJSON', () => { it('keeps user._tmp when calling .toJSON', () => {
@@ -42,13 +42,48 @@ describe('User Model', () => {
expect(userToJSON.stats.maxHealth).to.not.exist; expect(userToJSON.stats.maxHealth).to.not.exist;
expect(userToJSON.stats.toNextLevel).to.not.exist; expect(userToJSON.stats.toNextLevel).to.not.exist;
user.addComputedStatsToJSONObj(userToJSON.stats); User.addComputedStatsToJSONObj(userToJSON.stats, userToJSON);
expect(userToJSON.stats.maxMP).to.exist; expect(userToJSON.stats.maxMP).to.exist;
expect(userToJSON.stats.maxHealth).to.equal(common.maxHealth); expect(userToJSON.stats.maxHealth).to.equal(common.maxHealth);
expect(userToJSON.stats.toNextLevel).to.equal(common.tnl(user.stats.lvl)); expect(userToJSON.stats.toNextLevel).to.equal(common.tnl(user.stats.lvl));
}); });
it('can transform user object without mongoose helpers', async () => {
let user = new User();
await user.save();
let userToJSON = await User.findById(user._id).lean().exec();
expect(userToJSON.stats.maxMP).to.not.exist;
expect(userToJSON.stats.maxHealth).to.not.exist;
expect(userToJSON.stats.toNextLevel).to.not.exist;
expect(userToJSON.id).to.not.exist;
User.transformJSONUser(userToJSON);
expect(userToJSON.id).to.equal(userToJSON._id);
expect(userToJSON.stats.maxMP).to.not.exist;
expect(userToJSON.stats.maxHealth).to.not.exist;
expect(userToJSON.stats.toNextLevel).to.not.exist;
});
it('can transform user object without mongoose helpers (including computed stats)', async () => {
let user = new User();
await user.save();
let userToJSON = await User.findById(user._id).lean().exec();
expect(userToJSON.stats.maxMP).to.not.exist;
expect(userToJSON.stats.maxHealth).to.not.exist;
expect(userToJSON.stats.toNextLevel).to.not.exist;
User.transformJSONUser(userToJSON, true);
expect(userToJSON.id).to.equal(userToJSON._id);
expect(userToJSON.stats.maxMP).to.exist;
expect(userToJSON.stats.maxHealth).to.equal(common.maxHealth);
expect(userToJSON.stats.toNextLevel).to.equal(common.tnl(user.stats.lvl));
});
context('notifications', () => { context('notifications', () => {
it('can add notifications without data', () => { it('can add notifications without data', () => {
let user = new User(); let user = new User();

View File

@@ -1,4 +1,4 @@
import { model as UserNotification } from '../../../../../website/server/models/userNotification'; import { model as UserNotification } from '../../../../website/server/models/userNotification';
describe('UserNotification Model', () => { describe('UserNotification Model', () => {
context('convertNotificationsToSafeJson', () => { context('convertNotificationsToSafeJson', () => {

View File

@@ -1,7 +1,7 @@
import { model as Webhook } from '../../../../../website/server/models/webhook'; import { model as Webhook } from '../../../../website/server/models/webhook';
import { BadRequest } from '../../../../../website/server/libs/errors'; import { BadRequest } from '../../../../website/server/libs/errors';
import { v4 as generateUUID } from 'uuid'; import { v4 as generateUUID } from 'uuid';
import apiError from '../../../../../website/server/libs/apiError'; import apiError from '../../../../website/server/libs/apiError';
describe('Webhook Model', () => { describe('Webhook Model', () => {
context('Instance Methods', () => { context('Instance Methods', () => {

View File

@@ -5,7 +5,7 @@ import {
sleep, sleep,
checkExistence, checkExistence,
translate as t, translate as t,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
import { v4 as generateUUID } from 'uuid'; import { v4 as generateUUID } from 'uuid';
describe('DELETE /challenges/:challengeId', () => { describe('DELETE /challenges/:challengeId', () => {
@@ -41,6 +41,7 @@ describe('DELETE /challenges/:challengeId', () => {
group = populatedGroup.group; group = populatedGroup.group;
challenge = await generateChallenge(groupLeader, group); challenge = await generateChallenge(groupLeader, group);
await groupLeader.post(`/challenges/${challenge._id}/join`);
await groupLeader.post(`/tasks/challenge/${challenge._id}`, [ await groupLeader.post(`/tasks/challenge/${challenge._id}`, [
{type: 'habit', text: taskText}, {type: 'habit', text: taskText},

View File

@@ -3,7 +3,7 @@ import {
createAndPopulateGroup, createAndPopulateGroup,
generateChallenge, generateChallenge,
translate as t, translate as t,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
import { v4 as generateUUID } from 'uuid'; import { v4 as generateUUID } from 'uuid';
describe('GET /challenges/:challengeId', () => { describe('GET /challenges/:challengeId', () => {
@@ -33,9 +33,11 @@ describe('GET /challenges/:challengeId', () => {
group = populatedGroup.group; group = populatedGroup.group;
challenge = await generateChallenge(groupLeader, group); challenge = await generateChallenge(groupLeader, group);
await groupLeader.post(`/challenges/${challenge._id}/join`);
}); });
it('should return challenge data', async () => { it('should return challenge data', async () => {
await challenge.sync();
let chal = await user.get(`/challenges/${challenge._id}`); let chal = await user.get(`/challenges/${challenge._id}`);
expect(chal.memberCount).to.equal(challenge.memberCount); expect(chal.memberCount).to.equal(challenge.memberCount);
expect(chal.name).to.equal(challenge.name); expect(chal.name).to.equal(challenge.name);
@@ -80,6 +82,7 @@ describe('GET /challenges/:challengeId', () => {
challenge = await generateChallenge(groupLeader, group); challenge = await generateChallenge(groupLeader, group);
await members[0].post(`/challenges/${challenge._id}/join`); await members[0].post(`/challenges/${challenge._id}/join`);
await groupLeader.post(`/challenges/${challenge._id}/join`);
}); });
it('fails if user doesn\'t have access to the challenge', async () => { it('fails if user doesn\'t have access to the challenge', async () => {
@@ -134,6 +137,7 @@ describe('GET /challenges/:challengeId', () => {
challenge = await generateChallenge(groupLeader, group); challenge = await generateChallenge(groupLeader, group);
await members[0].post(`/challenges/${challenge._id}/join`); await members[0].post(`/challenges/${challenge._id}/join`);
await groupLeader.post(`/challenges/${challenge._id}/join`);
}); });
it('fails if user doesn\'t have access to the challenge', async () => { it('fails if user doesn\'t have access to the challenge', async () => {

View File

@@ -4,7 +4,7 @@ import {
generateChallenge, generateChallenge,
translate as t, translate as t,
sleep, sleep,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
import { v4 as generateUUID } from 'uuid'; import { v4 as generateUUID } from 'uuid';
describe('GET /challenges/:challengeId/export/csv', () => { describe('GET /challenges/:challengeId/export/csv', () => {
@@ -24,6 +24,7 @@ describe('GET /challenges/:challengeId/export/csv', () => {
members = populatedGroup.members; members = populatedGroup.members;
challenge = await generateChallenge(groupLeader, group); challenge = await generateChallenge(groupLeader, group);
await groupLeader.post(`/challenges/${challenge._id}/join`);
await members[0].post(`/challenges/${challenge._id}/join`); await members[0].post(`/challenges/${challenge._id}/join`);
await members[1].post(`/challenges/${challenge._id}/join`); await members[1].post(`/challenges/${challenge._id}/join`);
await members[2].post(`/challenges/${challenge._id}/join`); await members[2].post(`/challenges/${challenge._id}/join`);

View File

@@ -3,7 +3,7 @@ import {
generateGroup, generateGroup,
generateChallenge, generateChallenge,
translate as t, translate as t,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
import { v4 as generateUUID } from 'uuid'; import { v4 as generateUUID } from 'uuid';
describe('GET /challenges/:challengeId/members', () => { describe('GET /challenges/:challengeId/members', () => {
@@ -45,6 +45,7 @@ describe('GET /challenges/:challengeId/members', () => {
let leader = await generateUser({balance: 4}); let leader = await generateUser({balance: 4});
let group = await generateGroup(leader, {type: 'guild', privacy: 'public', name: generateUUID()}); let group = await generateGroup(leader, {type: 'guild', privacy: 'public', name: generateUUID()});
let challenge = await generateChallenge(leader, group); let challenge = await generateChallenge(leader, group);
await leader.post(`/challenges/${challenge._id}/join`);
let res = await user.get(`/challenges/${challenge._id}/members`); let res = await user.get(`/challenges/${challenge._id}/members`);
expect(res[0]).to.eql({ expect(res[0]).to.eql({
_id: leader._id, _id: leader._id,
@@ -59,6 +60,7 @@ describe('GET /challenges/:challengeId/members', () => {
let anotherUser = await generateUser({balance: 3}); let anotherUser = await generateUser({balance: 3});
let group = await generateGroup(anotherUser, {type: 'guild', privacy: 'public', name: generateUUID()}); let group = await generateGroup(anotherUser, {type: 'guild', privacy: 'public', name: generateUUID()});
let challenge = await generateChallenge(anotherUser, group); let challenge = await generateChallenge(anotherUser, group);
await anotherUser.post(`/challenges/${challenge._id}/join`);
let res = await user.get(`/challenges/${challenge._id}/members`); let res = await user.get(`/challenges/${challenge._id}/members`);
expect(res[0]).to.eql({ expect(res[0]).to.eql({
_id: anotherUser._id, _id: anotherUser._id,
@@ -72,6 +74,7 @@ describe('GET /challenges/:challengeId/members', () => {
it('returns only first 30 members if req.query.includeAllMembers is not true', async () => { it('returns only first 30 members if req.query.includeAllMembers is not true', async () => {
let group = await generateGroup(user, {type: 'party', name: generateUUID()}); let group = await generateGroup(user, {type: 'party', name: generateUUID()});
let challenge = await generateChallenge(user, group); let challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
let usersToGenerate = []; let usersToGenerate = [];
for (let i = 0; i < 31; i++) { for (let i = 0; i < 31; i++) {
@@ -90,6 +93,7 @@ describe('GET /challenges/:challengeId/members', () => {
it('returns only first 30 members if req.query.includeAllMembers is not defined', async () => { it('returns only first 30 members if req.query.includeAllMembers is not defined', async () => {
let group = await generateGroup(user, {type: 'party', name: generateUUID()}); let group = await generateGroup(user, {type: 'party', name: generateUUID()});
let challenge = await generateChallenge(user, group); let challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
let usersToGenerate = []; let usersToGenerate = [];
for (let i = 0; i < 31; i++) { for (let i = 0; i < 31; i++) {
@@ -108,6 +112,7 @@ describe('GET /challenges/:challengeId/members', () => {
it('returns all members if req.query.includeAllMembers is true', async () => { it('returns all members if req.query.includeAllMembers is true', async () => {
let group = await generateGroup(user, {type: 'party', name: generateUUID()}); let group = await generateGroup(user, {type: 'party', name: generateUUID()});
let challenge = await generateChallenge(user, group); let challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
let usersToGenerate = []; let usersToGenerate = [];
for (let i = 0; i < 31; i++) { for (let i = 0; i < 31; i++) {
@@ -127,6 +132,7 @@ describe('GET /challenges/:challengeId/members', () => {
this.timeout(30000); // @TODO: times out after 8 seconds this.timeout(30000); // @TODO: times out after 8 seconds
let group = await generateGroup(user, {type: 'party', name: generateUUID()}); let group = await generateGroup(user, {type: 'party', name: generateUUID()});
let challenge = await generateChallenge(user, group); let challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
let usersToGenerate = []; let usersToGenerate = [];
for (let i = 0; i < 57; i++) { for (let i = 0; i < 57; i++) {
@@ -147,6 +153,7 @@ describe('GET /challenges/:challengeId/members', () => {
it('supports using req.query.search to get search members', async () => { it('supports using req.query.search to get search members', async () => {
let group = await generateGroup(user, {type: 'party', name: generateUUID()}); let group = await generateGroup(user, {type: 'party', name: generateUUID()});
let challenge = await generateChallenge(user, group); let challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
let usersToGenerate = []; let usersToGenerate = [];
for (let i = 0; i < 3; i++) { for (let i = 0; i < 3; i++) {

View File

@@ -3,7 +3,7 @@ import {
generateChallenge, generateChallenge,
generateGroup, generateGroup,
translate as t, translate as t,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
import { v4 as generateUUID } from 'uuid'; import { v4 as generateUUID } from 'uuid';
describe('GET /challenges/:challengeId/members/:memberId', () => { describe('GET /challenges/:challengeId/members/:memberId', () => {
@@ -50,6 +50,7 @@ describe('GET /challenges/:challengeId/members/:memberId', () => {
it('fails if user doesn\'t have access to the challenge', async () => { it('fails if user doesn\'t have access to the challenge', async () => {
let group = await generateGroup(user, {type: 'party', name: generateUUID()}); let group = await generateGroup(user, {type: 'party', name: generateUUID()});
let challenge = await generateChallenge(user, group); let challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
let anotherUser = await generateUser(); let anotherUser = await generateUser();
let member = await generateUser(); let member = await generateUser();
await expect(anotherUser.get(`/challenges/${challenge._id}/members/${member._id}`)).to.eventually.be.rejected.and.eql({ await expect(anotherUser.get(`/challenges/${challenge._id}/members/${member._id}`)).to.eventually.be.rejected.and.eql({
@@ -62,6 +63,7 @@ describe('GET /challenges/:challengeId/members/:memberId', () => {
it('fails if member is not part of the challenge', async () => { it('fails if member is not part of the challenge', async () => {
let group = await generateGroup(user, {type: 'party', name: generateUUID()}); let group = await generateGroup(user, {type: 'party', name: generateUUID()});
let challenge = await generateChallenge(user, group); let challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
let member = await generateUser(); let member = await generateUser();
await expect(user.get(`/challenges/${challenge._id}/members/${member._id}`)).to.eventually.be.rejected.and.eql({ await expect(user.get(`/challenges/${challenge._id}/members/${member._id}`)).to.eventually.be.rejected.and.eql({
code: 404, code: 404,
@@ -74,6 +76,7 @@ describe('GET /challenges/:challengeId/members/:memberId', () => {
let groupLeader = await generateUser({balance: 4}); let groupLeader = await generateUser({balance: 4});
let group = await generateGroup(groupLeader, {type: 'guild', privacy: 'public', name: generateUUID()}); let group = await generateGroup(groupLeader, {type: 'guild', privacy: 'public', name: generateUUID()});
let challenge = await generateChallenge(groupLeader, group); let challenge = await generateChallenge(groupLeader, group);
await groupLeader.post(`/challenges/${challenge._id}/join`);
let taskText = 'Test Text'; let taskText = 'Test Text';
await groupLeader.post(`/tasks/challenge/${challenge._id}`, [{type: 'habit', text: taskText}]); await groupLeader.post(`/tasks/challenge/${challenge._id}`, [{type: 'habit', text: taskText}]);
@@ -86,6 +89,7 @@ describe('GET /challenges/:challengeId/members/:memberId', () => {
it('returns the member tasks for the challenges', async () => { it('returns the member tasks for the challenges', async () => {
let group = await generateGroup(user, {type: 'party', name: generateUUID()}); let group = await generateGroup(user, {type: 'party', name: generateUUID()});
let challenge = await generateChallenge(user, group); let challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
await user.post(`/tasks/challenge/${challenge._id}`, [{type: 'habit', text: 'Test Text'}]); await user.post(`/tasks/challenge/${challenge._id}`, [{type: 'habit', text: 'Test Text'}]);
let memberProgress = await user.get(`/challenges/${challenge._id}/members/${user._id}`); let memberProgress = await user.get(`/challenges/${challenge._id}/members/${user._id}`);
@@ -98,6 +102,7 @@ describe('GET /challenges/:challengeId/members/:memberId', () => {
it('returns the tasks without the tags and checklist', async () => { it('returns the tasks without the tags and checklist', async () => {
let group = await generateGroup(user, {type: 'party', name: generateUUID()}); let group = await generateGroup(user, {type: 'party', name: generateUUID()});
let challenge = await generateChallenge(user, group); let challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
let taskText = 'Test Text'; let taskText = 'Test Text';
await user.post(`/tasks/challenge/${challenge._id}`, [{ await user.post(`/tasks/challenge/${challenge._id}`, [{
type: 'todo', type: 'todo',

View File

@@ -3,7 +3,7 @@ import {
generateChallenge, generateChallenge,
createAndPopulateGroup, createAndPopulateGroup,
translate as t, translate as t,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
import { TAVERN_ID } from '../../../../../website/common/script/constants'; import { TAVERN_ID } from '../../../../../website/common/script/constants';
describe('GET challenges/groups/:groupId', () => { describe('GET challenges/groups/:groupId', () => {
@@ -25,7 +25,9 @@ describe('GET challenges/groups/:groupId', () => {
nonMember = await generateUser(); nonMember = await generateUser();
challenge = await generateChallenge(user, group); challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
challenge2 = await generateChallenge(user, group); challenge2 = await generateChallenge(user, group);
await user.post(`/challenges/${challenge2._id}/join`);
}); });
it('should return group challenges for non member with populated leader', async () => { it('should return group challenges for non member with populated leader', async () => {
@@ -73,6 +75,7 @@ describe('GET challenges/groups/:groupId', () => {
expect(foundChallengeIndex).to.eql(0); expect(foundChallengeIndex).to.eql(0);
let newChallenge = await generateChallenge(user, publicGuild); let newChallenge = await generateChallenge(user, publicGuild);
await user.post(`/challenges/${newChallenge._id}/join`);
challenges = await user.get(`/challenges/groups/${publicGuild._id}`); challenges = await user.get(`/challenges/groups/${publicGuild._id}`);
@@ -99,7 +102,9 @@ describe('GET challenges/groups/:groupId', () => {
nonMember = await generateUser(); nonMember = await generateUser();
challenge = await generateChallenge(user, group); challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
challenge2 = await generateChallenge(user, group); challenge2 = await generateChallenge(user, group);
await user.post(`/challenges/${challenge2._id}/join`);
}); });
it('should prevent non-member from seeing challenges', async () => { it('should prevent non-member from seeing challenges', async () => {
@@ -156,9 +161,12 @@ describe('GET challenges/groups/:groupId', () => {
slug: 'habitica_official', slug: 'habitica_official',
}], }],
}); });
await user.post(`/challenges/${officialChallenge._id}/join`);
challenge = await generateChallenge(user, group); challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
challenge2 = await generateChallenge(user, group); challenge2 = await generateChallenge(user, group);
await user.post(`/challenges/${challenge2._id}/join`);
}); });
it('should return official challenges first', async () => { it('should return official challenges first', async () => {
@@ -178,6 +186,7 @@ describe('GET challenges/groups/:groupId', () => {
expect(foundChallengeIndex).to.eql(1); expect(foundChallengeIndex).to.eql(1);
let newChallenge = await generateChallenge(user, publicGuild); let newChallenge = await generateChallenge(user, publicGuild);
await user.post(`/challenges/${newChallenge._id}/join`);
challenges = await user.get(`/challenges/groups/${publicGuild._id}`); challenges = await user.get(`/challenges/groups/${publicGuild._id}`);
@@ -203,7 +212,9 @@ describe('GET challenges/groups/:groupId', () => {
nonMember = await generateUser(); nonMember = await generateUser();
challenge = await generateChallenge(user, group); challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
challenge2 = await generateChallenge(user, group); challenge2 = await generateChallenge(user, group);
await user.post(`/challenges/${challenge2._id}/join`);
}); });
it('should prevent non-member from seeing challenges', async () => { it('should prevent non-member from seeing challenges', async () => {
@@ -263,7 +274,9 @@ describe('GET challenges/groups/:groupId', () => {
tavern = await user.get(`/groups/${TAVERN_ID}`); tavern = await user.get(`/groups/${TAVERN_ID}`);
challenge = await generateChallenge(user, tavern, {prize: 1}); challenge = await generateChallenge(user, tavern, {prize: 1});
await user.post(`/challenges/${challenge._id}/join`);
challenge2 = await generateChallenge(user, tavern, {prize: 1}); challenge2 = await generateChallenge(user, tavern, {prize: 1});
await user.post(`/challenges/${challenge2._id}/join`);
}); });
it('should return tavern challenges with populated leader', async () => { it('should return tavern challenges with populated leader', async () => {

View File

@@ -2,7 +2,7 @@ import {
generateUser, generateUser,
generateChallenge, generateChallenge,
createAndPopulateGroup, createAndPopulateGroup,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
describe('GET challenges/user', () => { describe('GET challenges/user', () => {
context('no official challenges', () => { context('no official challenges', () => {
@@ -24,7 +24,9 @@ describe('GET challenges/user', () => {
nonMember = await generateUser(); nonMember = await generateUser();
challenge = await generateChallenge(user, group); challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
challenge2 = await generateChallenge(user, group); challenge2 = await generateChallenge(user, group);
await user.post(`/challenges/${challenge2._id}/join`);
}); });
it('should return challenges user has joined', async () => { it('should return challenges user has joined', async () => {
@@ -146,6 +148,7 @@ describe('GET challenges/user', () => {
expect(foundChallengeIndex).to.eql(0); expect(foundChallengeIndex).to.eql(0);
let newChallenge = await generateChallenge(user, publicGuild); let newChallenge = await generateChallenge(user, publicGuild);
await user.post(`/challenges/${newChallenge._id}/join`);
challenges = await user.get('/challenges/user'); challenges = await user.get('/challenges/user');
@@ -164,6 +167,7 @@ describe('GET challenges/user', () => {
}); });
let privateChallenge = await generateChallenge(groupLeader, group); let privateChallenge = await generateChallenge(groupLeader, group);
await groupLeader.post(`/challenges/${privateChallenge._id}/join`);
let challenges = await nonMember.get('/challenges/user'); let challenges = await nonMember.get('/challenges/user');
@@ -198,9 +202,12 @@ describe('GET challenges/user', () => {
slug: 'habitica_official', slug: 'habitica_official',
}], }],
}); });
await user.post(`/challenges/${officialChallenge._id}/join`);
challenge = await generateChallenge(user, group); challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
challenge2 = await generateChallenge(user, group); challenge2 = await generateChallenge(user, group);
await user.post(`/challenges/${challenge2._id}/join`);
}); });
it('should return official challenges first', async () => { it('should return official challenges first', async () => {
@@ -220,6 +227,7 @@ describe('GET challenges/user', () => {
expect(foundChallengeIndex).to.eql(1); expect(foundChallengeIndex).to.eql(1);
let newChallenge = await generateChallenge(user, publicGuild); let newChallenge = await generateChallenge(user, publicGuild);
await user.post(`/challenges/${newChallenge._id}/join`);
challenges = await user.get('/challenges/user'); challenges = await user.get('/challenges/user');
@@ -252,12 +260,14 @@ describe('GET challenges/user', () => {
await user.update({balance: 20}); await user.update({balance: 20});
for (let i = 0; i < 11; i += 1) { for (let i = 0; i < 11; i += 1) {
await generateChallenge(user, group); // eslint-disable-line let challenge = await generateChallenge(user, group); // eslint-disable-line
await user.post(`/challenges/${challenge._id}/join`); // eslint-disable-line
} }
}); });
it('returns public guilds filtered by category', async () => { it('returns public guilds filtered by category', async () => {
const categoryChallenge = await generateChallenge(user, guild, {categories}); const categoryChallenge = await generateChallenge(user, guild, {categories});
await user.post(`/challenges/${categoryChallenge._id}/join`);
const challenges = await user.get(`/challenges/user?categories=${categories[0].slug}`); const challenges = await user.get(`/challenges/user?categories=${categories[0].slug}`);
expect(challenges[0]._id).to.eql(categoryChallenge._id); expect(challenges[0]._id).to.eql(categoryChallenge._id);

View File

@@ -2,7 +2,7 @@ import {
generateUser, generateUser,
createAndPopulateGroup, createAndPopulateGroup,
translate as t, translate as t,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
import { v4 as generateUUID } from 'uuid'; import { v4 as generateUUID } from 'uuid';
describe('POST /challenges', () => { describe('POST /challenges', () => {
@@ -242,7 +242,6 @@ describe('POST /challenges', () => {
it('returns an error when challenge validation fails; doesn\'s save user or group', async () => { it('returns an error when challenge validation fails; doesn\'s save user or group', async () => {
let oldChallengeCount = group.challengeCount; let oldChallengeCount = group.challengeCount;
let oldUserBalance = groupLeader.balance; let oldUserBalance = groupLeader.balance;
let oldUserChallenges = groupLeader.challenges;
let oldGroupBalance = group.balance; let oldGroupBalance = group.balance;
await expect(groupLeader.post('/challenges', { await expect(groupLeader.post('/challenges', {
@@ -260,7 +259,6 @@ describe('POST /challenges', () => {
expect(group.challengeCount).to.eql(oldChallengeCount); expect(group.challengeCount).to.eql(oldChallengeCount);
expect(group.balance).to.eql(oldGroupBalance); expect(group.balance).to.eql(oldGroupBalance);
expect(groupLeader.balance).to.eql(oldUserBalance); expect(groupLeader.balance).to.eql(oldUserBalance);
expect(groupLeader.challenges).to.eql(oldUserChallenges);
}); });
it('sets all properites of the challenge as passed', async () => { it('sets all properites of the challenge as passed', async () => {
@@ -291,18 +289,19 @@ describe('POST /challenges', () => {
name: group.name, name: group.name,
type: group.type, type: group.type,
}); });
expect(challenge.memberCount).to.eql(1); expect(challenge.memberCount).to.eql(0);
expect(challenge.prize).to.eql(prize); expect(challenge.prize).to.eql(prize);
}); });
it('adds challenge to creator\'s challenges', async () => { it('does not add challenge to creator\'s challenges', async () => {
let challenge = await groupLeader.post('/challenges', { await groupLeader.post('/challenges', {
group: group._id, group: group._id,
name: 'Test Challenge', name: 'Test Challenge',
shortName: 'TC Label', shortName: 'TC Label',
}); });
await expect(groupLeader.sync()).to.eventually.have.property('challenges').to.include(challenge._id); await groupLeader.sync();
expect(groupLeader.challenges.length).to.equal(0);
}); });
it('awards achievement if this is creator\'s first challenge', async () => { it('awards achievement if this is creator\'s first challenge', async () => {

View File

@@ -3,7 +3,7 @@ import {
generateChallenge, generateChallenge,
createAndPopulateGroup, createAndPopulateGroup,
translate as t, translate as t,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
import { v4 as generateUUID } from 'uuid'; import { v4 as generateUUID } from 'uuid';
describe('POST /challenges/:challengeId/join', () => { describe('POST /challenges/:challengeId/join', () => {
@@ -43,6 +43,7 @@ describe('POST /challenges/:challengeId/join', () => {
authorizedUser = populatedGroup.members[0]; authorizedUser = populatedGroup.members[0];
challenge = await generateChallenge(groupLeader, group); challenge = await generateChallenge(groupLeader, group);
await groupLeader.post(`/challenges/${challenge._id}/join`);
}); });
it('returns an error when user doesn\'t have permissions to access the challenge', async () => { it('returns an error when user doesn\'t have permissions to access the challenge', async () => {
@@ -91,6 +92,7 @@ describe('POST /challenges/:challengeId/join', () => {
}); });
it('increases memberCount of challenge', async () => { it('increases memberCount of challenge', async () => {
await challenge.sync();
let oldMemberCount = challenge.memberCount; let oldMemberCount = challenge.memberCount;
await authorizedUser.post(`/challenges/${challenge._id}/join`); await authorizedUser.post(`/challenges/${challenge._id}/join`);

View File

@@ -3,7 +3,7 @@ import {
generateChallenge, generateChallenge,
createAndPopulateGroup, createAndPopulateGroup,
translate as t, translate as t,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
import { v4 as generateUUID } from 'uuid'; import { v4 as generateUUID } from 'uuid';
describe('POST /challenges/:challengeId/leave', () => { describe('POST /challenges/:challengeId/leave', () => {
@@ -48,6 +48,7 @@ describe('POST /challenges/:challengeId/leave', () => {
notInGroupLeavingUser = populatedGroup.members[2]; notInGroupLeavingUser = populatedGroup.members[2];
challenge = await generateChallenge(groupLeader, group); challenge = await generateChallenge(groupLeader, group);
await groupLeader.post(`/challenges/${challenge._id}/join`);
taskText = 'A challenge task text'; taskText = 'A challenge task text';

View File

@@ -5,7 +5,7 @@ import {
sleep, sleep,
checkExistence, checkExistence,
translate as t, translate as t,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
import { v4 as generateUUID } from 'uuid'; import { v4 as generateUUID } from 'uuid';
describe('POST /challenges/:challengeId/winner/:winnerId', () => { describe('POST /challenges/:challengeId/winner/:winnerId', () => {
@@ -58,6 +58,7 @@ describe('POST /challenges/:challengeId/winner/:winnerId', () => {
challenge = await generateChallenge(groupLeader, group, { challenge = await generateChallenge(groupLeader, group, {
prize: 1, prize: 1,
}); });
await groupLeader.post(`/challenges/${challenge._id}/join`);
await groupLeader.post(`/tasks/challenge/${challenge._id}`, [ await groupLeader.post(`/tasks/challenge/${challenge._id}`, [
{type: 'habit', text: taskText}, {type: 'habit', text: taskText},

View File

@@ -1,7 +1,7 @@
import { import {
generateUser, generateUser,
generateGroup, generateGroup,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
describe('POST /challenges/:challengeId/clone', () => { describe('POST /challenges/:challengeId/clone', () => {
it('clones a challenge', async () => { it('clones a challenge', async () => {

View File

@@ -3,7 +3,7 @@ import {
generateChallenge, generateChallenge,
createAndPopulateGroup, createAndPopulateGroup,
translate as t, translate as t,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
describe('PUT /challenges/:challengeId', () => { describe('PUT /challenges/:challengeId', () => {
let privateGuild, user, nonMember, challenge, member; let privateGuild, user, nonMember, challenge, member;
@@ -25,6 +25,7 @@ describe('PUT /challenges/:challengeId', () => {
member = members[0]; member = members[0];
challenge = await generateChallenge(user, group); challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
await member.post(`/challenges/${challenge._id}/join`); await member.post(`/challenges/${challenge._id}/join`);
}); });

View File

@@ -2,7 +2,7 @@ import {
createAndPopulateGroup, createAndPopulateGroup,
generateUser, generateUser,
translate as t, translate as t,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
import { v4 as generateUUID } from 'uuid'; import { v4 as generateUUID } from 'uuid';
describe('DELETE /groups/:groupId/chat/:chatId', () => { describe('DELETE /groups/:groupId/chat/:chatId', () => {

View File

@@ -2,7 +2,7 @@ import {
generateUser, generateUser,
generateGroup, generateGroup,
translate as t, translate as t,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
describe('GET /groups/:groupId/chat', () => { describe('GET /groups/:groupId/chat', () => {
let user; let user;

View File

@@ -1,7 +1,7 @@
import { import {
generateUser, generateUser,
translate as t, translate as t,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
import { find } from 'lodash'; import { find } from 'lodash';
describe('POST /chat/:chatId/flag', () => { describe('POST /chat/:chatId/flag', () => {

View File

@@ -1,7 +1,7 @@
import { import {
createAndPopulateGroup, createAndPopulateGroup,
translate as t, translate as t,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
import { find } from 'lodash'; import { find } from 'lodash';
describe('POST /chat/:chatId/like', () => { describe('POST /chat/:chatId/like', () => {

View File

@@ -4,7 +4,7 @@ import {
translate as t, translate as t,
sleep, sleep,
server, server,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
import { import {
SPAM_MESSAGE_LIMIT, SPAM_MESSAGE_LIMIT,
SPAM_MIN_EXEMPT_CONTRIB_LEVEL, SPAM_MIN_EXEMPT_CONTRIB_LEVEL,

View File

@@ -1,7 +1,7 @@
import { import {
createAndPopulateGroup, createAndPopulateGroup,
sleep, sleep,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
describe('POST /groups/:id/chat/seen', () => { describe('POST /groups/:id/chat/seen', () => {
context('Guild', () => { context('Guild', () => {

View File

@@ -2,7 +2,7 @@ import {
createAndPopulateGroup, createAndPopulateGroup,
generateUser, generateUser,
translate as t, translate as t,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
import config from '../../../../../config.json'; import config from '../../../../../config.json';
import { v4 as generateUUID } from 'uuid'; import { v4 as generateUUID } from 'uuid';

View File

@@ -1,7 +1,7 @@
import { import {
requester, requester,
translate as t, translate as t,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
import i18n from '../../../../../website/common/script/i18n'; import i18n from '../../../../../website/common/script/i18n';
describe('GET /content', () => { describe('GET /content', () => {

View File

@@ -1,7 +1,7 @@
import { import {
generateUser, generateUser,
resetHabiticaDB, resetHabiticaDB,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
import apiError from '../../../../../website/server/libs/apiError'; import apiError from '../../../../../website/server/libs/apiError';
describe('GET /coupons/', () => { describe('GET /coupons/', () => {

View File

@@ -2,7 +2,7 @@ import {
generateUser, generateUser,
translate as t, translate as t,
resetHabiticaDB, resetHabiticaDB,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
describe('POST /coupons/enter/:code', () => { describe('POST /coupons/enter/:code', () => {
let user; let user;

View File

@@ -2,7 +2,7 @@ import {
generateUser, generateUser,
translate as t, translate as t,
resetHabiticaDB, resetHabiticaDB,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
import couponCode from 'coupon-code'; import couponCode from 'coupon-code';
import apiError from '../../../../../website/server/libs/apiError'; import apiError from '../../../../../website/server/libs/apiError';

View File

@@ -2,7 +2,7 @@ import {
generateUser, generateUser,
requester, requester,
resetHabiticaDB, resetHabiticaDB,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
describe('POST /coupons/validate/:code', () => { describe('POST /coupons/validate/:code', () => {
let api = requester(); let api = requester();

View File

@@ -1,7 +1,7 @@
import { import {
generateUser, generateUser,
translate as t, translate as t,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
import { v4 as generateUUID } from 'uuid'; import { v4 as generateUUID } from 'uuid';
xdescribe('GET /export/avatar-:memberId.html', () => { xdescribe('GET /export/avatar-:memberId.html', () => {

View File

@@ -1,6 +1,6 @@
import { import {
generateUser, generateUser,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
import { import {
updateDocument, updateDocument,
} from '../../../../helpers/mongo'; } from '../../../../helpers/mongo';

View File

@@ -1,6 +1,6 @@
import { import {
generateUser, generateUser,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
describe('GET /export/inbox.html', () => { describe('GET /export/inbox.html', () => {
let user; let user;

View File

@@ -1,6 +1,6 @@
import { import {
generateUser, generateUser,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
describe('GET /export/userdata.json', () => { describe('GET /export/userdata.json', () => {
it('should return a valid JSON file with user data', async () => { it('should return a valid JSON file with user data', async () => {

View File

@@ -1,6 +1,6 @@
import { import {
generateUser, generateUser,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
import xml2js from 'xml2js'; import xml2js from 'xml2js';
import util from 'util'; import util from 'util';

View File

@@ -1,7 +1,7 @@
import nconf from 'nconf'; import nconf from 'nconf';
import { import {
generateUser, generateUser,
} from '../../../../helpers/api-v3-integration.helper'; } from '../../../../helpers/api-integration/v3';
describe('POST /debug/add-hourglass', () => { describe('POST /debug/add-hourglass', () => {
let userToGetHourGlass; let userToGetHourGlass;

Some files were not shown because too many files have changed in this diff Show More