mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-16 14:17:22 +01:00
Compare commits
121 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79c3efaf9c | ||
|
|
74c6a891fc | ||
|
|
9a5d17f538 | ||
|
|
070c4a8fbd | ||
|
|
2bbc4f4f4d | ||
|
|
39c00ea433 | ||
|
|
dd6c1c764a | ||
|
|
9b456d1760 | ||
|
|
acf1031317 | ||
|
|
5d45204d8b | ||
|
|
37a71924fe | ||
|
|
9cf2408988 | ||
|
|
638525f8d8 | ||
|
|
2c37ba3cee | ||
|
|
ad5b2fe540 | ||
|
|
bfb6daad51 | ||
|
|
281b8e2b7c | ||
|
|
3f88ea2378 | ||
|
|
9c6275d4ab | ||
|
|
fd3c8ddc8b | ||
|
|
72f47ad4e6 | ||
|
|
74c9a1b02d | ||
|
|
ffa561473c | ||
|
|
080ffae4e1 | ||
|
|
e395182c95 | ||
|
|
68f4275c44 | ||
|
|
4bf4c3a6c2 | ||
|
|
f00bb29192 | ||
|
|
016447ec77 | ||
|
|
fa024e071b | ||
|
|
28fec237fe | ||
|
|
e4bb82768c | ||
|
|
65eca22407 | ||
|
|
cea1597ee1 | ||
|
|
3906952154 | ||
|
|
6169b9d0ae | ||
|
|
69cac7e504 | ||
|
|
febf3f0024 | ||
|
|
563f40e4b7 | ||
|
|
e2b06161e1 | ||
|
|
e7de8b8e2f | ||
|
|
a0624d9507 | ||
|
|
cddd0df4f2 | ||
|
|
220bfb3517 | ||
|
|
2106a5ebd3 | ||
|
|
bbffa9830b | ||
|
|
caa546eb62 | ||
|
|
4e83059652 | ||
|
|
903cdb36ef | ||
|
|
d8128cc3db | ||
|
|
f888e80b01 | ||
|
|
fd7aedbff2 | ||
|
|
6c5234313d | ||
|
|
08aa5758b4 | ||
|
|
1415e344c0 | ||
|
|
2ce7915f06 | ||
|
|
838c8b4e08 | ||
|
|
1590d955cd | ||
|
|
2690caed35 | ||
|
|
dc2d4fa10b | ||
|
|
1540ec89ee | ||
|
|
f304d4fe52 | ||
|
|
023e433a5c | ||
|
|
ef4aeb29ab | ||
|
|
2b80931202 | ||
|
|
2950713712 | ||
|
|
118f3bd1bb | ||
|
|
69f1343ea8 | ||
|
|
918ee02d64 | ||
|
|
0cac34dd26 | ||
|
|
1c859fc91f | ||
|
|
857aa5827b | ||
|
|
28e8ec2d2c | ||
|
|
856f13d213 | ||
|
|
121fd38bd1 | ||
|
|
36d72f5f7a | ||
|
|
f1b8bd80e7 | ||
|
|
84d2ce6a3f | ||
|
|
76010e6c8f | ||
|
|
c707b6c99b | ||
|
|
e4bd466cc7 | ||
|
|
001b8eb894 | ||
|
|
9abcfe8614 | ||
|
|
bc6102551d | ||
|
|
959a3ff85b | ||
|
|
518b874f64 | ||
|
|
6cc359a935 | ||
|
|
514d35c0be | ||
|
|
13da92ea68 | ||
|
|
03c4d82b7d | ||
|
|
d905ab7f86 | ||
|
|
c6560b6b1b | ||
|
|
c61f660255 | ||
|
|
2f1b683ec9 | ||
|
|
47bb217068 | ||
|
|
f49fd05da1 | ||
|
|
b0341aa06f | ||
|
|
b07ec18e33 | ||
|
|
12930a2bac | ||
|
|
91f5c47d9d | ||
|
|
fe7850d10f | ||
|
|
c5c2da75bf | ||
|
|
969607cd3b | ||
|
|
2a1f52a359 | ||
|
|
47d9594679 | ||
|
|
97e40c81f3 | ||
|
|
c8b61a2f7d | ||
|
|
e9543f0d28 | ||
|
|
77b88490e4 | ||
|
|
7fc2500bfd | ||
|
|
fb229acb58 | ||
|
|
6ce83d1fa4 | ||
|
|
2be4815aea | ||
|
|
1dbc42f48a | ||
|
|
89279c8aed | ||
|
|
faedb13598 | ||
|
|
c0c74659c5 | ||
|
|
bf5ad2db1f | ||
|
|
7d99873960 | ||
|
|
e02ef00397 | ||
|
|
23c5c4211c |
3
.dockerignore
Normal file
3
.dockerignore
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
node_modules
|
||||||
|
.git
|
||||||
|
website
|
||||||
@@ -20,8 +20,4 @@ website/common/browserify.js
|
|||||||
test/content/**/*
|
test/content/**/*
|
||||||
Gruntfile.js
|
Gruntfile.js
|
||||||
gulpfile.js
|
gulpfile.js
|
||||||
gulp
|
gulp
|
||||||
webpack
|
|
||||||
test/client/e2e
|
|
||||||
test/client/unit/index.js
|
|
||||||
test/client/unit/karma.conf.js
|
|
||||||
@@ -20,17 +20,19 @@ RUN apt-get install -y \
|
|||||||
RUN curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
|
RUN curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
|
||||||
RUN apt-get install -y nodejs
|
RUN apt-get install -y nodejs
|
||||||
|
|
||||||
|
# Install npm@latest
|
||||||
|
RUN curl -sL https://www.npmjs.org/install.sh | sh
|
||||||
|
|
||||||
# Clean up package management
|
# Clean up package management
|
||||||
RUN apt-get clean
|
RUN apt-get clean
|
||||||
RUN rm -rf /var/lib/apt/lists/*
|
RUN rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Install global packages
|
# Install global packages
|
||||||
RUN npm install -g npm@4
|
RUN npm install -g gulp grunt-cli bower mocha
|
||||||
RUN npm install -g gulp grunt-cli bower
|
|
||||||
|
|
||||||
# Clone Habitica repo and install dependencies
|
# Clone Habitica repo and install dependencies
|
||||||
WORKDIR /habitrpg
|
WORKDIR /habitrpg
|
||||||
RUN git clone https://github.com/HabitRPG/habitrpg.git /habitrpg
|
RUN git clone https://github.com/HabitRPG/habitica.git /habitrpg
|
||||||
RUN npm install
|
RUN npm install
|
||||||
RUN bower install --allow-root
|
RUN bower install --allow-root
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Habitica [](https://travis-ci.org/HabitRPG/habitica) [](https://codeclimate.com/github/HabitRPG/habitrpg) [](https://coveralls.io/r/HabitRPG/habitrpg?branch=develop) [](https://www.bountysource.com/trackers/68393-habitrpg?utm_source=68393&utm_medium=shield&utm_campaign=TRACKER_BADGE)
|
Habitica [](https://travis-ci.org/HabitRPG/habitica) [](https://codeclimate.com/github/HabitRPG/habitrpg) [](https://coveralls.io/github/HabitRPG/habitica?branch=develop) [](https://www.bountysource.com/trackers/68393-habitrpg?utm_source=68393&utm_medium=shield&utm_campaign=TRACKER_BADGE)
|
||||||
===============
|
===============
|
||||||
|
|
||||||
[Habitica](https://habitica.com) is an open source habit building program which treats your life like a Role Playing Game. Level up as you succeed, lose HP as you fail, earn money to buy weapons and armor.
|
[Habitica](https://habitica.com) is an open source habit building program which treats your life like a Role Playing Game. Level up as you succeed, lose HP as you fail, earn money to buy weapons and armor.
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
web:
|
web:
|
||||||
volumes:
|
volumes:
|
||||||
- '.:/habitrpg'
|
- '.:/habitrpg'
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
web:
|
web:
|
||||||
build: .
|
build: .
|
||||||
ports:
|
ports:
|
||||||
- "3000:3000"
|
- "3000:3000"
|
||||||
links:
|
links:
|
||||||
- mongo
|
- mongo
|
||||||
environment:
|
environment:
|
||||||
- NODE_DB_URI=mongodb://mongo/habitrpg
|
- NODE_DB_URI=mongodb://mongo/habitrpg
|
||||||
|
|
||||||
mongo:
|
mongo:
|
||||||
image: mongo
|
image: mongo
|
||||||
ports:
|
ports:
|
||||||
- "27017:27017"
|
- "27017:27017"
|
||||||
|
|||||||
@@ -84,8 +84,8 @@ gulp.task('transifex:malformedStrings', () => {
|
|||||||
let malformedString = `${lang} - ${file} - ${key} - ${translationString}`;
|
let malformedString = `${lang} - ${file} - ${key} - ${translationString}`;
|
||||||
stringsWithMalformedInterpolations.push(malformedString);
|
stringsWithMalformedInterpolations.push(malformedString);
|
||||||
} else if (englishOccurences.length !== translationOccurences.length && !malformedStringExceptions[key]) {
|
} else if (englishOccurences.length !== translationOccurences.length && !malformedStringExceptions[key]) {
|
||||||
let missingInterploationString = `${lang} - ${file} - ${key} - ${translationString}`;
|
let missingInterpolationString = `${lang} - ${file} - ${key} - ${translationString}`;
|
||||||
stringsWithIncorrectNumberOfInterpolations.push(missingInterploationString);
|
stringsWithIncorrectNumberOfInterpolations.push(missingInterpolationString);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
73
migrations/20161230_nye_hats.js
Normal file
73
migrations/20161230_nye_hats.js
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
var migrationName = '20161230_nye_hats.js';
|
||||||
|
var authorName = 'Sabe'; // in case script author needs to know when their ...
|
||||||
|
var authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; //... own data is done
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Yearly New Year's party hat award
|
||||||
|
*/
|
||||||
|
|
||||||
|
var mongo = require('mongoskin');
|
||||||
|
|
||||||
|
var connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
|
||||||
|
|
||||||
|
var dbUsers = mongo.db(connectionString).collection('users');
|
||||||
|
|
||||||
|
// specify a query to limit the affected users (empty for all users):
|
||||||
|
var query = {
|
||||||
|
'migration':{$ne:migrationName},
|
||||||
|
'auth.timestamps.loggedin':{$gt:new Date('2016-11-30')} // Remove after first run
|
||||||
|
};
|
||||||
|
|
||||||
|
// specify fields we are interested in to limit retrieved data (empty if we're not reading data):
|
||||||
|
var fields = {
|
||||||
|
'items.gear.owned': 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
console.warn('Updating users...');
|
||||||
|
var progressCount = 1000;
|
||||||
|
var count = 0;
|
||||||
|
dbUsers.findEach(query, fields, {batchSize:250}, function(err, user) {
|
||||||
|
if (err) { return exiting(1, 'ERROR! ' + err); }
|
||||||
|
if (!user) {
|
||||||
|
console.warn('All appropriate users found and modified.');
|
||||||
|
setTimeout(displayData, 300000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
|
||||||
|
// specify user data to change:
|
||||||
|
var set = {};
|
||||||
|
|
||||||
|
if (typeof user.items.gear.owned.head_special_nye2015 !== 'undefined') {
|
||||||
|
set = {'migration':migrationName, 'items.gear.owned.head_special_nye2016':false};
|
||||||
|
} else if (typeof user.items.gear.owned.head_special_nye2014 !== 'undefined') {
|
||||||
|
set = {'migration':migrationName, 'items.gear.owned.head_special_nye2015':false};
|
||||||
|
} else if (typeof user.items.gear.owned.head_special_nye !== 'undefined') {
|
||||||
|
set = {'migration':migrationName, 'items.gear.owned.head_special_nye2014':false};
|
||||||
|
} else {
|
||||||
|
set = {'migration':migrationName, 'items.gear.owned.head_special_nye':false};
|
||||||
|
}
|
||||||
|
|
||||||
|
dbUsers.update({_id:user._id}, {$set:set});
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
113
migrations/20170120_missing_incentive.js
Normal file
113
migrations/20170120_missing_incentive.js
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
var migrationName = '20170120_missing_incentive.js';
|
||||||
|
var authorName = 'Sabe'; // in case script author needs to know when their ...
|
||||||
|
var authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; //... own data is done
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Award missing Royal Purple Hatching Potion to users with 55+ check-ins
|
||||||
|
* Reduce users with impossible check-in counts to a reasonable number
|
||||||
|
*/
|
||||||
|
|
||||||
|
import monk from 'monk';
|
||||||
|
import common from '../website/common';
|
||||||
|
|
||||||
|
var connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
|
||||||
|
var dbUsers = monk(connectionString).get('users', { castIds: false });
|
||||||
|
|
||||||
|
function processUsers(lastId) {
|
||||||
|
// specify a query to limit the affected users (empty for all users):
|
||||||
|
var query = {
|
||||||
|
'loginIncentives': {$gt:54},
|
||||||
|
'migration': {$ne: migrationName},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (lastId) {
|
||||||
|
query._id = {
|
||||||
|
$gt: lastId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dbUsers.find(query, {
|
||||||
|
sort: {_id: 1},
|
||||||
|
limit: 250,
|
||||||
|
fields: [] // specify fields we are interested in to limit retrieved data (empty if we're not reading data):
|
||||||
|
})
|
||||||
|
.then(updateUsers)
|
||||||
|
.catch(function (err) {
|
||||||
|
console.log(err);
|
||||||
|
return exiting(1, 'ERROR! ' + err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var progressCount = 1000;
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
|
function updateUsers (users) {
|
||||||
|
if (!users || users.length === 0) {
|
||||||
|
console.warn('All appropriate users found and modified.');
|
||||||
|
displayData();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var userPromises = users.map(updateUser);
|
||||||
|
var lastUser = users[users.length - 1];
|
||||||
|
|
||||||
|
return Promise.all(userPromises)
|
||||||
|
.then(function () {
|
||||||
|
processUsers(lastUser._id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateUser (user) {
|
||||||
|
count++;
|
||||||
|
|
||||||
|
var language = user.preferences.language || 'en';
|
||||||
|
var set = {'migration': migrationName};
|
||||||
|
var inc = {'items.hatchingPotions.RoyalPurple': 1};
|
||||||
|
if (user.loginIncentives > 58) {
|
||||||
|
set = {'migration': migrationName, 'loginIncentives': 58};
|
||||||
|
}
|
||||||
|
var push = {
|
||||||
|
'notifications': {
|
||||||
|
'type': 'LOGIN_INCENTIVE',
|
||||||
|
'data': {
|
||||||
|
'nextRewardAt': 60,
|
||||||
|
'rewardKey': [
|
||||||
|
'Pet_HatchingPotion_Purple',
|
||||||
|
],
|
||||||
|
'rewardText': common.i18n.t('potion', {potionType: common.i18n.t('hatchingPotionRoyalPurple', language)}, language),
|
||||||
|
'reward': [
|
||||||
|
{
|
||||||
|
'premium': true,
|
||||||
|
'key': 'RoyalPurple',
|
||||||
|
'limited': true,
|
||||||
|
'value': 2,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'message': common.i18n.t('unlockedCheckInReward', language),
|
||||||
|
},
|
||||||
|
'id': common.uuid(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
dbUsers.update({_id: user._id}, {$set:set, $push:push, $inc:inc});
|
||||||
|
|
||||||
|
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;
|
||||||
21
migrations/migration-runner.js
Normal file
21
migrations/migration-runner.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
require("babel-register");
|
||||||
|
require("babel-polyfill");
|
||||||
|
|
||||||
|
// This file must use ES5, everything required can be in ES6
|
||||||
|
|
||||||
|
function setUpServer () {
|
||||||
|
var nconf = require('nconf');
|
||||||
|
var mongoose = require('mongoose');
|
||||||
|
var Bluebird = require('bluebird');
|
||||||
|
var setupNconf = require('../website/server/libs/setupNconf');
|
||||||
|
setupNconf();
|
||||||
|
// We require src/server and npt src/index because
|
||||||
|
// 1. nconf is already setup
|
||||||
|
// 2. we don't need clustering
|
||||||
|
require('../website/server/server'); // eslint-disable-line global-require
|
||||||
|
}
|
||||||
|
setUpServer();
|
||||||
|
|
||||||
|
// Replace this with your migration
|
||||||
|
var processUsers = require('./new_stuff');
|
||||||
|
processUsers();
|
||||||
@@ -6,49 +6,70 @@ var authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; //... own data is done
|
|||||||
* set the newStuff flag in all user accounts so they see a Bailey message
|
* set the newStuff flag in all user accounts so they see a Bailey message
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var mongo = require('mongoskin');
|
var monk = require('monk');
|
||||||
|
|
||||||
var connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
|
var connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
|
||||||
|
var dbUsers = monk(connectionString).get('users', { castIds: false });
|
||||||
|
|
||||||
var dbUsers = mongo.db(connectionString).collection('users');
|
|
||||||
|
|
||||||
// specify a query to limit the affected users (empty for all users):
|
function processUsers(lastId) {
|
||||||
var query = {
|
// specify a query to limit the affected users (empty for all users):
|
||||||
'flags.newStuff':{$ne:true}
|
var query = {
|
||||||
};
|
'flags.newStuff': {$ne:true},
|
||||||
|
};
|
||||||
|
|
||||||
// specify fields we are interested in to limit retrieved data (empty if we're not reading data):
|
if (lastId) {
|
||||||
var fields = {
|
query._id = {
|
||||||
};
|
$gt: lastId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dbUsers.find(query, {
|
||||||
|
sort: {_id: 1},
|
||||||
|
limit: 250,
|
||||||
|
fields: [] // specify fields we are interested in to limit retrieved data (empty if we're not reading data):
|
||||||
|
})
|
||||||
|
.then(updateUsers)
|
||||||
|
.catch(function (err) {
|
||||||
|
console.log(err);
|
||||||
|
return exiting(1, 'ERROR! ' + err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
console.warn('Updating users...');
|
|
||||||
var progressCount = 1000;
|
var progressCount = 1000;
|
||||||
var count = 0;
|
var count = 0;
|
||||||
dbUsers.findEach(query, fields, {batchSize:250}, function(err, user) {
|
|
||||||
if (err) { return exiting(1, 'ERROR! ' + err); }
|
function updateUsers (users) {
|
||||||
if (!user) {
|
if (!users || users.length === 0) {
|
||||||
console.warn('All appropriate users found and modified.');
|
console.warn('All appropriate users found and modified.');
|
||||||
setTimeout(displayData, 300000);
|
displayData();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var userPaymentPromises = users.map(updateUser);
|
||||||
|
var lastUser = users[users.length - 1];
|
||||||
|
|
||||||
|
return Promise.all(userPaymentPromises)
|
||||||
|
.then(function () {
|
||||||
|
processUsers(lastUser._id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateUser (user) {
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
// specify user data to change:
|
var set = {'flags.newStuff': true};
|
||||||
var set = {'flags.newStuff':true};
|
|
||||||
|
|
||||||
dbUsers.update({_id:user._id}, {$set:set});
|
dbUsers.update({_id: user._id}, {$set:set});
|
||||||
|
|
||||||
if (count%progressCount == 0) console.warn(count + ' ' + user._id);
|
if (count % progressCount == 0) console.warn(count + ' ' + user._id);
|
||||||
if (user._id == authorUuid) console.warn(authorName + ' processed');
|
if (user._id == authorUuid) console.warn(authorName + ' processed');
|
||||||
});
|
}
|
||||||
|
|
||||||
|
|
||||||
function displayData() {
|
function displayData() {
|
||||||
console.warn('\n' + count + ' users processed\n');
|
console.warn('\n' + count + ' users processed\n');
|
||||||
return exiting(0);
|
return exiting(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function exiting(code, msg) {
|
function exiting(code, msg) {
|
||||||
code = code || 0; // 0 = success
|
code = code || 0; // 0 = success
|
||||||
if (code && !msg) { msg = 'ERROR!'; }
|
if (code && !msg) { msg = 'ERROR!'; }
|
||||||
@@ -58,3 +79,5 @@ function exiting(code, msg) {
|
|||||||
}
|
}
|
||||||
process.exit(code);
|
process.exit(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports = processUsers;
|
||||||
|
|||||||
115
migrations/restore-profile-data.js
Normal file
115
migrations/restore-profile-data.js
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
var migrationName = 'restore_profile_data.js';
|
||||||
|
var authorName = 'ThehollidayInn'; // in case script author needs to know when their ...
|
||||||
|
var authorUuid = ''; //... own data is done
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if users have empty profile data in new database and update it with old database info
|
||||||
|
*/
|
||||||
|
|
||||||
|
var monk = require('monk');
|
||||||
|
var connectionString = ''; // FOR TEST DATABASE
|
||||||
|
var dbUsers = monk(connectionString).get('users', { castIds: false });
|
||||||
|
|
||||||
|
var monk2 = require('monk');
|
||||||
|
var oldDbConnectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
|
||||||
|
var olDbUsers = monk2(oldDbConnectionString).get('users', { castIds: false });
|
||||||
|
|
||||||
|
function processUsers(lastId)
|
||||||
|
{
|
||||||
|
// specify a query to limit the affected users (empty for all users):
|
||||||
|
var query = {
|
||||||
|
// 'profile.name': 'profile name not found',
|
||||||
|
'profile.blurb': null,
|
||||||
|
// 'auth.timestamps.loggedin': {$gt: new Date('11/30/2016')},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (lastId) {
|
||||||
|
query._id = {
|
||||||
|
$gt: lastId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dbUsers.find(query, {
|
||||||
|
sort: {_id: 1},
|
||||||
|
limit: 250,
|
||||||
|
fields: ['_id', 'profile', 'auth.timestamps.loggedin'] // specify fields we are interested in to limit retrieved data (empty if we're not reading data):
|
||||||
|
})
|
||||||
|
.then(updateUsers)
|
||||||
|
.catch(function (err) {
|
||||||
|
console.log(err);
|
||||||
|
return exiting(1, 'ERROR! ' + err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var progressCount = 1000;
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
|
function updateUsers (users) {
|
||||||
|
if (!users || users.length === 0) {
|
||||||
|
console.warn('All appropriate users found and modified.');
|
||||||
|
setTimeout(displayData, 300000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var userPaymentPromises = users.map(updateUser);
|
||||||
|
var lastUser = users[users.length - 1];
|
||||||
|
|
||||||
|
return Promise.all(userPaymentPromises)
|
||||||
|
.then(function () {
|
||||||
|
processUsers(lastUser._id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateUser (user) {
|
||||||
|
count++;
|
||||||
|
|
||||||
|
if (!user.profile.name || user.profile.name === 'profile name not found' || !user.profile.imageUrl || !user.profile.blurb) {
|
||||||
|
return olDbUsers.findOne({_id: user._id}, '_id profile')
|
||||||
|
.then((oldUserData) => {
|
||||||
|
if (!oldUserData) return;
|
||||||
|
// specify user data to change:
|
||||||
|
var set = {};
|
||||||
|
|
||||||
|
if (oldUserData.profile.name === 'profile name not found') return;
|
||||||
|
|
||||||
|
var userNeedsProfileName = !user.profile.name || user.profile.name === 'profile name not found';
|
||||||
|
if (userNeedsProfileName && oldUserData.profile.name) {
|
||||||
|
set['profile.name'] = oldUserData.profile.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!user.profile.imageUrl && oldUserData.profile.imageUrl) {
|
||||||
|
set['profile.imageUrl'] = oldUserData.profile.imageUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!user.profile.blurb && oldUserData.profile.blurb) {
|
||||||
|
set['profile.blurb'] = oldUserData.profile.blurb;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Object.keys(set).length !== 0 && set.constructor === Object) {
|
||||||
|
console.log(set)
|
||||||
|
return dbUsers.update({_id: user._id}, {$set:set});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
processUsers()
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
var migrationName = '20161201_takeThis.js';
|
var migrationName = '20170103_takeThis.js'; // Update per month
|
||||||
var authorName = 'Sabe'; // in case script author needs to know when their ...
|
var authorName = 'Sabe'; // in case script author needs to know when their ...
|
||||||
var authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; //... own data is done
|
var authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; //... own data is done
|
||||||
|
|
||||||
@@ -38,7 +38,9 @@ dbUsers.findEach(query, fields, {batchSize:250}, function(err, user) {
|
|||||||
// specify user data to change:
|
// specify user data to change:
|
||||||
var set = {};
|
var set = {};
|
||||||
|
|
||||||
if (typeof user.items.gear.owned.body_special_takeThis !== 'undefined') {
|
if (typeof user.items.gear.owned.back_special_takeThis !== 'undefined') {
|
||||||
|
set = {'migration':migrationName};
|
||||||
|
{ else if (typeof user.items.gear.owned.body_special_takeThis !== 'undefined') {
|
||||||
set = {'migration':migrationName, 'items.gear.owned.back_special_takeThis':false};
|
set = {'migration':migrationName, 'items.gear.owned.back_special_takeThis':false};
|
||||||
} else if (typeof user.items.gear.owned.head_special_takeThis !== 'undefined') {
|
} else if (typeof user.items.gear.owned.head_special_takeThis !== 'undefined') {
|
||||||
set = {'migration':migrationName, 'items.gear.owned.body_special_takeThis':false};
|
set = {'migration':migrationName, 'items.gear.owned.body_special_takeThis':false};
|
||||||
799
npm-shrinkwrap.json
generated
799
npm-shrinkwrap.json
generated
File diff suppressed because it is too large
Load Diff
@@ -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": "3.64.0",
|
"version": "3.71.0",
|
||||||
"main": "./website/server/index.js",
|
"main": "./website/server/index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@slack/client": "3.6.0",
|
"@slack/client": "3.6.0",
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
"async": "^1.5.0",
|
"async": "^1.5.0",
|
||||||
"autoprefixer": "^6.4.0",
|
"autoprefixer": "^6.4.0",
|
||||||
"aws-sdk": "^2.0.25",
|
"aws-sdk": "^2.0.25",
|
||||||
|
"axios": "^0.15.3",
|
||||||
"babel-core": "^6.0.0",
|
"babel-core": "^6.0.0",
|
||||||
"babel-loader": "^6.0.0",
|
"babel-loader": "^6.0.0",
|
||||||
"babel-plugin-syntax-async-functions": "^6.13.0",
|
"babel-plugin-syntax-async-functions": "^6.13.0",
|
||||||
@@ -118,7 +119,6 @@
|
|||||||
"vue": "^2.1.0",
|
"vue": "^2.1.0",
|
||||||
"vue-hot-reload-api": "^1.2.0",
|
"vue-hot-reload-api": "^1.2.0",
|
||||||
"vue-loader": "^10.0.0",
|
"vue-loader": "^10.0.0",
|
||||||
"vue-resource": "^1.0.2",
|
|
||||||
"vue-router": "^2.0.0-rc.5",
|
"vue-router": "^2.0.0-rc.5",
|
||||||
"vue-template-compiler": "^2.1.0",
|
"vue-template-compiler": "^2.1.0",
|
||||||
"webpack": "^1.12.2",
|
"webpack": "^1.12.2",
|
||||||
@@ -199,6 +199,7 @@
|
|||||||
"mocha": "^2.3.3",
|
"mocha": "^2.3.3",
|
||||||
"mongodb": "^2.0.46",
|
"mongodb": "^2.0.46",
|
||||||
"mongoskin": "~2.1.0",
|
"mongoskin": "~2.1.0",
|
||||||
|
"monk": "^3.1.3",
|
||||||
"nightwatch": "^0.8.18",
|
"nightwatch": "^0.8.18",
|
||||||
"phantomjs-prebuilt": "^2.1.12",
|
"phantomjs-prebuilt": "^2.1.12",
|
||||||
"protractor": "^3.1.1",
|
"protractor": "^3.1.1",
|
||||||
|
|||||||
@@ -35,6 +35,24 @@ describe('POST /chat', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Returns an error when an empty message is provided', async () => {
|
||||||
|
await expect(user.post(`/groups/${groupWithChat._id}/chat`, { message: ' '}))
|
||||||
|
.to.eventually.be.rejected.and.eql({
|
||||||
|
code: 400,
|
||||||
|
error: 'BadRequest',
|
||||||
|
message: t('invalidReqParams'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Returns an error when an message containing only newlines is provided', async () => {
|
||||||
|
await expect(user.post(`/groups/${groupWithChat._id}/chat`, { message: '\n\n'}))
|
||||||
|
.to.eventually.be.rejected.and.eql({
|
||||||
|
code: 400,
|
||||||
|
error: 'BadRequest',
|
||||||
|
message: t('invalidReqParams'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('Returns an error when group is not found', async () => {
|
it('Returns an error when group is not found', async () => {
|
||||||
await expect(user.post('/groups/invalidID/chat', { message: testMessage})).to.eventually.be.rejected.and.eql({
|
await expect(user.post('/groups/invalidID/chat', { message: testMessage})).to.eventually.be.rejected.and.eql({
|
||||||
code: 404,
|
code: 404,
|
||||||
|
|||||||
@@ -300,6 +300,26 @@ describe('Post /groups/:groupId/invite', () => {
|
|||||||
message: t('userAlreadyInGroup'),
|
message: t('userAlreadyInGroup'),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// @TODO: Add this after we are able to mock the group plan route
|
||||||
|
xit('returns an error when a non-leader invites to a group plan', async () => {
|
||||||
|
let userToInvite = await generateUser();
|
||||||
|
|
||||||
|
let nonGroupLeader = await generateUser();
|
||||||
|
await inviter.post(`/groups/${group._id}/invite`, {
|
||||||
|
uuids: [nonGroupLeader._id],
|
||||||
|
});
|
||||||
|
await nonGroupLeader.post(`/groups/${group._id}/join`);
|
||||||
|
|
||||||
|
await expect(nonGroupLeader.post(`/groups/${group._id}/invite`, {
|
||||||
|
uuids: [userToInvite._id],
|
||||||
|
}))
|
||||||
|
.to.eventually.be.rejected.and.eql({
|
||||||
|
code: 401,
|
||||||
|
error: 'NotAuthorized',
|
||||||
|
message: t('onlyGroupLeaderCanInviteToGroupPlan'),
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('party invites', () => {
|
describe('party invites', () => {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ describe('GET /models/:model/paths', () => {
|
|||||||
user = await generateUser();
|
user = await generateUser();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns an error when model is not accessible or doesn\'t exists', async () => {
|
it('returns an error when model is not accessible or doesn\'t exist', async () => {
|
||||||
await expect(user.get('/models/1234/paths')).to.eventually.be.rejected.and.eql({
|
await expect(user.get('/models/1234/paths')).to.eventually.be.rejected.and.eql({
|
||||||
code: 400,
|
code: 400,
|
||||||
error: 'BadRequest',
|
error: 'BadRequest',
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
import {
|
|
||||||
generateUser,
|
|
||||||
translate as t,
|
|
||||||
} from '../../../../helpers/api-integration/v3';
|
|
||||||
|
|
||||||
describe('payments : amazon #subscribeCancel', () => {
|
|
||||||
let endpoint = '/amazon/subscribe/cancel';
|
|
||||||
let user;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
user = await generateUser();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('verifies subscription', async () => {
|
|
||||||
await expect(user.get(endpoint)).to.eventually.be.rejected.and.eql({
|
|
||||||
code: 401,
|
|
||||||
error: 'NotAuthorized',
|
|
||||||
message: t('missingSubscription'),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import {
|
|
||||||
generateUser,
|
|
||||||
translate as t,
|
|
||||||
} from '../../../../helpers/api-integration/v3';
|
|
||||||
|
|
||||||
xdescribe('payments : paypal #checkout', () => {
|
|
||||||
let endpoint = '/paypal/checkout';
|
|
||||||
let user;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
user = await generateUser();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('verifies subscription', async () => {
|
|
||||||
await expect(user.get(endpoint)).to.eventually.be.rejected.and.eql({
|
|
||||||
code: 401,
|
|
||||||
error: 'NotAuthorized',
|
|
||||||
message: t('missingSubscription'),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import {
|
|
||||||
generateUser,
|
|
||||||
translate as t,
|
|
||||||
} from '../../../../helpers/api-integration/v3';
|
|
||||||
|
|
||||||
xdescribe('payments : paypal #checkoutSuccess', () => {
|
|
||||||
let endpoint = '/paypal/checkout/success';
|
|
||||||
let user;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
user = await generateUser();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('verifies subscription', async () => {
|
|
||||||
await expect(user.get(endpoint)).to.eventually.be.rejected.and.eql({
|
|
||||||
code: 401,
|
|
||||||
error: 'NotAuthorized',
|
|
||||||
message: t('missingSubscription'),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import {
|
|
||||||
generateUser,
|
|
||||||
translate as t,
|
|
||||||
} from '../../../../helpers/api-integration/v3';
|
|
||||||
|
|
||||||
xdescribe('payments : paypal #subscribe', () => {
|
|
||||||
let endpoint = '/paypal/subscribe';
|
|
||||||
let user;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
user = await generateUser();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('verifies credentials', async () => {
|
|
||||||
await expect(user.get(endpoint)).to.eventually.be.rejected.and.eql({
|
|
||||||
code: 401,
|
|
||||||
error: 'NotAuthorized',
|
|
||||||
message: t('missingSubscription'),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import {
|
|
||||||
generateUser,
|
|
||||||
translate as t,
|
|
||||||
} from '../../../../helpers/api-integration/v3';
|
|
||||||
|
|
||||||
describe('payments : paypal #subscribeCancel', () => {
|
|
||||||
let endpoint = '/paypal/subscribe/cancel';
|
|
||||||
let user;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
user = await generateUser();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('verifies credentials', async () => {
|
|
||||||
await expect(user.get(endpoint)).to.eventually.be.rejected.and.eql({
|
|
||||||
code: 401,
|
|
||||||
error: 'NotAuthorized',
|
|
||||||
message: t('missingSubscription'),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import {
|
|
||||||
generateUser,
|
|
||||||
translate as t,
|
|
||||||
} from '../../../../helpers/api-integration/v3';
|
|
||||||
|
|
||||||
xdescribe('payments : paypal #subscribeSuccess', () => {
|
|
||||||
let endpoint = '/paypal/subscribe/success';
|
|
||||||
let user;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
user = await generateUser();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('verifies credentials', async () => {
|
|
||||||
await expect(user.get(endpoint)).to.eventually.be.rejected.and.eql({
|
|
||||||
code: 401,
|
|
||||||
error: 'NotAuthorized',
|
|
||||||
message: t('missingSubscription'),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import {
|
|
||||||
generateUser,
|
|
||||||
translate as t,
|
|
||||||
} from '../../../../helpers/api-integration/v3';
|
|
||||||
|
|
||||||
describe('payments - stripe - #subscribeCancel', () => {
|
|
||||||
let endpoint = '/stripe/subscribe/cancel';
|
|
||||||
let user;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
user = await generateUser();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('verifies credentials', async () => {
|
|
||||||
await expect(user.get(endpoint)).to.eventually.be.rejected.and.eql({
|
|
||||||
code: 401,
|
|
||||||
error: 'NotAuthorized',
|
|
||||||
message: t('missingSubscription'),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import {
|
|
||||||
generateUser,
|
|
||||||
} from '../../../../helpers/api-integration/v3';
|
|
||||||
|
|
||||||
describe('payments - amazon - #checkout', () => {
|
|
||||||
let endpoint = '/amazon/checkout';
|
|
||||||
let user;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
user = await generateUser();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('verifies credentials', async () => {
|
|
||||||
await expect(user.post(endpoint)).to.eventually.be.rejected.and.eql({
|
|
||||||
code: 400,
|
|
||||||
error: 'BadRequest',
|
|
||||||
message: 'Missing req.body.orderReferenceId',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import {
|
|
||||||
generateUser,
|
|
||||||
translate as t,
|
|
||||||
} from '../../../../helpers/api-integration/v3';
|
|
||||||
|
|
||||||
describe('payments - amazon - #subscribe', () => {
|
|
||||||
let endpoint = '/amazon/subscribe';
|
|
||||||
let user;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
user = await generateUser();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('verifies subscription code', async () => {
|
|
||||||
await expect(user.post(endpoint)).to.eventually.be.rejected.and.eql({
|
|
||||||
code: 400,
|
|
||||||
error: 'BadRequest',
|
|
||||||
message: t('missingSubscriptionCode'),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
import {
|
|
||||||
generateUser,
|
|
||||||
} from '../../../../helpers/api-integration/v3';
|
|
||||||
|
|
||||||
describe('payments - paypal - #ipn', () => {
|
|
||||||
let endpoint = '/paypal/ipn';
|
|
||||||
let user;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
user = await generateUser();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('verifies credentials', async () => {
|
|
||||||
let result = await user.post(endpoint);
|
|
||||||
expect(result).to.eql('OK');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import {
|
|
||||||
generateUser,
|
|
||||||
} from '../../../../helpers/api-integration/v3';
|
|
||||||
|
|
||||||
describe('payments - stripe - #checkout', () => {
|
|
||||||
let endpoint = '/stripe/checkout';
|
|
||||||
let user;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
user = await generateUser();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('verifies credentials', async () => {
|
|
||||||
await expect(user.post(endpoint, {id: 123})).to.eventually.be.rejected.and.eql({
|
|
||||||
code: 401,
|
|
||||||
error: 'Error',
|
|
||||||
message: 'Invalid API Key provided: ****************************1111',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import {
|
|
||||||
generateUser,
|
|
||||||
translate as t,
|
|
||||||
} from '../../../../helpers/api-integration/v3';
|
|
||||||
|
|
||||||
describe('payments - stripe - #subscribeEdit', () => {
|
|
||||||
let endpoint = '/stripe/subscribe/edit';
|
|
||||||
let user;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
user = await generateUser();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('verifies credentials', async () => {
|
|
||||||
await expect(user.post(endpoint)).to.eventually.be.rejected.and.eql({
|
|
||||||
code: 401,
|
|
||||||
error: 'NotAuthorized',
|
|
||||||
message: t('missingSubscription'),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
import {
|
||||||
|
generateUser,
|
||||||
|
generateGroup,
|
||||||
|
translate as t,
|
||||||
|
} from '../../../../../helpers/api-integration/v3';
|
||||||
|
import amzLib from '../../../../../../website/server/libs/amazonPayments';
|
||||||
|
|
||||||
|
describe('payments : amazon #subscribeCancel', () => {
|
||||||
|
let endpoint = '/amazon/subscribe/cancel';
|
||||||
|
let user, group, amazonSubscribeCancelStub;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
user = await generateUser();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws error when there users has no subscription', async () => {
|
||||||
|
await expect(user.get(endpoint)).to.eventually.be.rejected.and.eql({
|
||||||
|
code: 401,
|
||||||
|
error: 'NotAuthorized',
|
||||||
|
message: t('missingSubscription'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('success', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
amazonSubscribeCancelStub = sinon.stub(amzLib, 'cancelSubscription').returnsPromise().resolves({});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
amzLib.cancelSubscription.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('cancels a user subscription', async () => {
|
||||||
|
user = await generateUser({
|
||||||
|
'profile.name': 'sender',
|
||||||
|
'purchased.plan.customerId': 'customer-id',
|
||||||
|
'purchased.plan.planId': 'basic_3mo',
|
||||||
|
'purchased.plan.lastBillingDate': new Date(),
|
||||||
|
balance: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
await user.get(endpoint);
|
||||||
|
|
||||||
|
expect(amazonSubscribeCancelStub).to.be.calledOnce;
|
||||||
|
expect(amazonSubscribeCancelStub.args[0][0].user._id).to.eql(user._id);
|
||||||
|
expect(amazonSubscribeCancelStub.args[0][0].groupId).to.eql(undefined);
|
||||||
|
expect(amazonSubscribeCancelStub.args[0][0].headers['x-api-key']).to.eql(user.apiToken);
|
||||||
|
expect(amazonSubscribeCancelStub.args[0][0].headers['x-api-user']).to.eql(user._id);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('cancels a group subscription', async () => {
|
||||||
|
user = await generateUser({
|
||||||
|
'profile.name': 'sender',
|
||||||
|
'purchased.plan.customerId': 'customer-id',
|
||||||
|
'purchased.plan.planId': 'basic_3mo',
|
||||||
|
'purchased.plan.lastBillingDate': new Date(),
|
||||||
|
balance: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
group = await generateGroup(user, {
|
||||||
|
name: 'test group',
|
||||||
|
type: 'guild',
|
||||||
|
privacy: 'public',
|
||||||
|
'purchased.plan.customerId': 'customer-id',
|
||||||
|
'purchased.plan.planId': 'basic_3mo',
|
||||||
|
'purchased.plan.lastBillingDate': new Date(),
|
||||||
|
});
|
||||||
|
|
||||||
|
await user.get(`${endpoint}?groupId=${group._id}`);
|
||||||
|
|
||||||
|
expect(amazonSubscribeCancelStub).to.be.calledOnce;
|
||||||
|
expect(amazonSubscribeCancelStub.args[0][0].user._id).to.eql(user._id);
|
||||||
|
expect(amazonSubscribeCancelStub.args[0][0].groupId).to.eql(group._id);
|
||||||
|
expect(amazonSubscribeCancelStub.args[0][0].headers['x-api-key']).to.eql(user.apiToken);
|
||||||
|
expect(amazonSubscribeCancelStub.args[0][0].headers['x-api-user']).to.eql(user._id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import {
|
||||||
|
generateUser,
|
||||||
|
} from '../../../../../helpers/api-integration/v3';
|
||||||
|
import amzLib from '../../../../../../website/server/libs/amazonPayments';
|
||||||
|
|
||||||
|
describe('payments - amazon - #checkout', () => {
|
||||||
|
let endpoint = '/amazon/checkout';
|
||||||
|
let user, amazonCheckoutStub;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
user = await generateUser();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('verifies credentials', async () => {
|
||||||
|
await expect(user.post(endpoint)).to.eventually.be.rejected.and.eql({
|
||||||
|
code: 400,
|
||||||
|
error: 'BadRequest',
|
||||||
|
message: 'Missing req.body.orderReferenceId',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('success', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
amazonCheckoutStub = sinon.stub(amzLib, 'checkout').returnsPromise().resolves({});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
amzLib.checkout.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('makes a purcahse with amazon checkout', async () => {
|
||||||
|
user = await generateUser({
|
||||||
|
'profile.name': 'sender',
|
||||||
|
'purchased.plan.customerId': 'customer-id',
|
||||||
|
'purchased.plan.planId': 'basic_3mo',
|
||||||
|
'purchased.plan.lastBillingDate': new Date(),
|
||||||
|
balance: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
let gift = {
|
||||||
|
type: 'gems',
|
||||||
|
gems: {
|
||||||
|
amount: 16,
|
||||||
|
uuid: user._id,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let orderReferenceId = 'orderReferenceId-example';
|
||||||
|
|
||||||
|
await user.post(endpoint, {
|
||||||
|
gift,
|
||||||
|
orderReferenceId,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(amazonCheckoutStub).to.be.calledOnce;
|
||||||
|
expect(amazonCheckoutStub.args[0][0].user._id).to.eql(user._id);
|
||||||
|
expect(amazonCheckoutStub.args[0][0].gift).to.eql(gift);
|
||||||
|
expect(amazonCheckoutStub.args[0][0].orderReferenceId).to.eql(orderReferenceId);
|
||||||
|
expect(amazonCheckoutStub.args[0][0].headers['x-api-key']).to.eql(user.apiToken);
|
||||||
|
expect(amazonCheckoutStub.args[0][0].headers['x-api-user']).to.eql(user._id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
generateUser,
|
generateUser,
|
||||||
} from '../../../../helpers/api-integration/v3';
|
} from '../../../../../helpers/api-integration/v3';
|
||||||
|
|
||||||
describe('payments - amazon - #createOrderReferenceId', () => {
|
describe('payments - amazon - #createOrderReferenceId', () => {
|
||||||
let endpoint = '/amazon/createOrderReferenceId';
|
let endpoint = '/amazon/createOrderReferenceId';
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
import {
|
||||||
|
generateUser,
|
||||||
|
generateGroup,
|
||||||
|
translate as t,
|
||||||
|
} from '../../../../../helpers/api-integration/v3';
|
||||||
|
import amzLib from '../../../../../../website/server/libs/amazonPayments';
|
||||||
|
|
||||||
|
describe('payments - amazon - #subscribe', () => {
|
||||||
|
let endpoint = '/amazon/subscribe';
|
||||||
|
let user, group, subscribeWithAmazonStub;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
user = await generateUser();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('verifies subscription code', async () => {
|
||||||
|
await expect(user.post(endpoint)).to.eventually.be.rejected.and.eql({
|
||||||
|
code: 400,
|
||||||
|
error: 'BadRequest',
|
||||||
|
message: t('missingSubscriptionCode'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('success', () => {
|
||||||
|
let billingAgreementId = 'billingAgreementId-example';
|
||||||
|
let subscription = 'basic_3mo';
|
||||||
|
let coupon;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
subscribeWithAmazonStub = sinon.stub(amzLib, 'subscribe').returnsPromise().resolves({});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
amzLib.subscribe.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates a user subscription', async () => {
|
||||||
|
user = await generateUser({
|
||||||
|
'profile.name': 'sender',
|
||||||
|
'purchased.plan.customerId': 'customer-id',
|
||||||
|
'purchased.plan.planId': 'basic_3mo',
|
||||||
|
'purchased.plan.lastBillingDate': new Date(),
|
||||||
|
balance: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
await user.post(endpoint, {
|
||||||
|
billingAgreementId,
|
||||||
|
subscription,
|
||||||
|
coupon,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(subscribeWithAmazonStub).to.be.calledOnce;
|
||||||
|
expect(subscribeWithAmazonStub.args[0][0].billingAgreementId).to.eql(billingAgreementId);
|
||||||
|
expect(subscribeWithAmazonStub.args[0][0].sub).to.exist;
|
||||||
|
expect(subscribeWithAmazonStub.args[0][0].coupon).to.eql(coupon);
|
||||||
|
expect(subscribeWithAmazonStub.args[0][0].groupId).not.exist;
|
||||||
|
expect(subscribeWithAmazonStub.args[0][0].headers['x-api-key']).to.eql(user.apiToken);
|
||||||
|
expect(subscribeWithAmazonStub.args[0][0].headers['x-api-user']).to.eql(user._id);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates a group subscription', async () => {
|
||||||
|
user = await generateUser({
|
||||||
|
'profile.name': 'sender',
|
||||||
|
'purchased.plan.customerId': 'customer-id',
|
||||||
|
'purchased.plan.planId': 'basic_3mo',
|
||||||
|
'purchased.plan.lastBillingDate': new Date(),
|
||||||
|
balance: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
group = await generateGroup(user, {
|
||||||
|
name: 'test group',
|
||||||
|
type: 'guild',
|
||||||
|
privacy: 'public',
|
||||||
|
'purchased.plan.customerId': 'customer-id',
|
||||||
|
'purchased.plan.planId': 'basic_3mo',
|
||||||
|
'purchased.plan.lastBillingDate': new Date(),
|
||||||
|
});
|
||||||
|
|
||||||
|
await user.post(endpoint, {
|
||||||
|
billingAgreementId,
|
||||||
|
subscription,
|
||||||
|
coupon,
|
||||||
|
groupId: group._id,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(subscribeWithAmazonStub).to.be.calledOnce;
|
||||||
|
expect(subscribeWithAmazonStub.args[0][0].billingAgreementId).to.eql(billingAgreementId);
|
||||||
|
expect(subscribeWithAmazonStub.args[0][0].sub).to.exist;
|
||||||
|
expect(subscribeWithAmazonStub.args[0][0].coupon).to.eql(coupon);
|
||||||
|
expect(subscribeWithAmazonStub.args[0][0].user._id).to.eql(user._id);
|
||||||
|
expect(subscribeWithAmazonStub.args[0][0].groupId).to.eql(group._id);
|
||||||
|
expect(subscribeWithAmazonStub.args[0][0].headers['x-api-key']).to.eql(user.apiToken);
|
||||||
|
expect(subscribeWithAmazonStub.args[0][0].headers['x-api-user']).to.eql(user._id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
generateUser,
|
generateUser,
|
||||||
} from '../../../../helpers/api-integration/v3';
|
} from '../../../../../helpers/api-integration/v3';
|
||||||
|
|
||||||
describe('payments : amazon', () => {
|
describe('payments : amazon', () => {
|
||||||
let endpoint = '/amazon/verifyAccessToken';
|
let endpoint = '/amazon/verifyAccessToken';
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import {
|
||||||
|
generateUser,
|
||||||
|
} from '../../../../../helpers/api-integration/v3';
|
||||||
|
import paypalPayments from '../../../../../../website/server/libs/paypalPayments';
|
||||||
|
|
||||||
|
describe('payments : paypal #checkout', () => {
|
||||||
|
let endpoint = '/paypal/checkout';
|
||||||
|
let user;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
user = await generateUser();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('success', () => {
|
||||||
|
let checkoutStub;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
checkoutStub = sinon.stub(paypalPayments, 'checkout').returnsPromise().resolves('/');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
paypalPayments.checkout.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates a purchase link', async () => {
|
||||||
|
user = await generateUser({
|
||||||
|
'profile.name': 'sender',
|
||||||
|
'purchased.plan.customerId': 'customer-id',
|
||||||
|
'purchased.plan.planId': 'basic_3mo',
|
||||||
|
'purchased.plan.lastBillingDate': new Date(),
|
||||||
|
balance: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
await user.get(endpoint);
|
||||||
|
|
||||||
|
expect(checkoutStub).to.be.calledOnce;
|
||||||
|
expect(checkoutStub.args[0][0].gift).to.eql(undefined);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
import {
|
||||||
|
generateUser,
|
||||||
|
translate as t,
|
||||||
|
} from '../../../../../helpers/api-integration/v3';
|
||||||
|
import paypalPayments from '../../../../../../website/server/libs/paypalPayments';
|
||||||
|
|
||||||
|
describe('payments : paypal #checkoutSuccess', () => {
|
||||||
|
let endpoint = '/paypal/checkout/success';
|
||||||
|
let user;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
user = await generateUser();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('verifies paymentId', async () => {
|
||||||
|
await expect(user.get(endpoint))
|
||||||
|
.to.eventually.be.rejected.and.eql({
|
||||||
|
code: 400,
|
||||||
|
error: 'BadRequest',
|
||||||
|
message: t('missingPaymentId'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('verifies customerId', async () => {
|
||||||
|
await expect(user.get(`${endpoint}?paymentId=test-paymentid`))
|
||||||
|
.to.eventually.be.rejected.and.eql({
|
||||||
|
code: 400,
|
||||||
|
error: 'BadRequest',
|
||||||
|
message: t('missingCustomerId'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('success', () => {
|
||||||
|
let checkoutSuccessStub;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
checkoutSuccessStub = sinon.stub(paypalPayments, 'checkoutSuccess').returnsPromise().resolves({});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
paypalPayments.checkoutSuccess.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('makes a purchase', async () => {
|
||||||
|
let paymentId = 'test-paymentid';
|
||||||
|
let customerId = 'test-customerId';
|
||||||
|
|
||||||
|
user = await generateUser({
|
||||||
|
'profile.name': 'sender',
|
||||||
|
'purchased.plan.customerId': 'customer-id',
|
||||||
|
'purchased.plan.planId': 'basic_3mo',
|
||||||
|
'purchased.plan.lastBillingDate': new Date(),
|
||||||
|
balance: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
await user.get(`${endpoint}?PayerID=${customerId}&paymentId=${paymentId}`);
|
||||||
|
|
||||||
|
expect(checkoutSuccessStub).to.be.calledOnce;
|
||||||
|
|
||||||
|
expect(checkoutSuccessStub.args[0][0].user._id).to.eql(user._id);
|
||||||
|
expect(checkoutSuccessStub.args[0][0].gift).to.eql(undefined);
|
||||||
|
expect(checkoutSuccessStub.args[0][0].paymentId).to.eql(paymentId);
|
||||||
|
expect(checkoutSuccessStub.args[0][0].customerId).to.eql(customerId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import {
|
||||||
|
generateUser,
|
||||||
|
translate as t,
|
||||||
|
} from '../../../../../helpers/api-integration/v3';
|
||||||
|
import paypalPayments from '../../../../../../website/server/libs/paypalPayments';
|
||||||
|
import shared from '../../../../../../website/common';
|
||||||
|
|
||||||
|
describe('payments : paypal #subscribe', () => {
|
||||||
|
let endpoint = '/paypal/subscribe';
|
||||||
|
let user;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
user = await generateUser();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('verifies sub key', async () => {
|
||||||
|
await expect(user.get(endpoint)).to.eventually.be.rejected.and.eql({
|
||||||
|
code: 400,
|
||||||
|
error: 'BadRequest',
|
||||||
|
message: t('missingSubKey'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('success', () => {
|
||||||
|
let subscribeStub;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
subscribeStub = sinon.stub(paypalPayments, 'subscribe').returnsPromise().resolves('/');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
paypalPayments.subscribe.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('makes a purchase', async () => {
|
||||||
|
let subKey = 'basic_3mo';
|
||||||
|
let sub = shared.content.subscriptionBlocks[subKey];
|
||||||
|
|
||||||
|
user = await generateUser({
|
||||||
|
'profile.name': 'sender',
|
||||||
|
'purchased.plan.customerId': 'customer-id',
|
||||||
|
'purchased.plan.planId': 'basic_3mo',
|
||||||
|
'purchased.plan.lastBillingDate': new Date(),
|
||||||
|
balance: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
await user.get(`${endpoint}?sub=${subKey}`);
|
||||||
|
|
||||||
|
expect(subscribeStub).to.be.calledOnce;
|
||||||
|
|
||||||
|
expect(subscribeStub.args[0][0].sub).to.eql(sub);
|
||||||
|
expect(subscribeStub.args[0][0].coupon).to.eql(undefined);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import {
|
||||||
|
generateUser,
|
||||||
|
translate as t,
|
||||||
|
} from '../../../../../helpers/api-integration/v3';
|
||||||
|
import paypalPayments from '../../../../../../website/server/libs/paypalPayments';
|
||||||
|
|
||||||
|
describe('payments : paypal #subscribeCancel', () => {
|
||||||
|
let endpoint = '/paypal/subscribe/cancel';
|
||||||
|
let user;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
user = await generateUser();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('verifies credentials', async () => {
|
||||||
|
await expect(user.get(endpoint))
|
||||||
|
.to.eventually.be.rejected.and.eql({
|
||||||
|
code: 401,
|
||||||
|
error: 'NotAuthorized',
|
||||||
|
message: t('missingSubscription'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('success', () => {
|
||||||
|
let subscribeCancelStub;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
subscribeCancelStub = sinon.stub(paypalPayments, 'subscribeCancel').returnsPromise().resolves('/');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
paypalPayments.subscribeCancel.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('cancels a subscription', async () => {
|
||||||
|
user = await generateUser({
|
||||||
|
'profile.name': 'sender',
|
||||||
|
'purchased.plan.customerId': 'customer-id',
|
||||||
|
'purchased.plan.planId': 'basic_3mo',
|
||||||
|
'purchased.plan.lastBillingDate': new Date(),
|
||||||
|
balance: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
await user.get(endpoint);
|
||||||
|
|
||||||
|
expect(subscribeCancelStub).to.be.calledOnce;
|
||||||
|
|
||||||
|
expect(subscribeCancelStub.args[0][0].user._id).to.eql(user._id);
|
||||||
|
expect(subscribeCancelStub.args[0][0].groupId).to.eql(undefined);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import {
|
||||||
|
generateUser,
|
||||||
|
translate as t,
|
||||||
|
} from '../../../../../helpers/api-integration/v3';
|
||||||
|
import paypalPayments from '../../../../../../website/server/libs/paypalPayments';
|
||||||
|
|
||||||
|
describe('payments : paypal #subscribeSuccess', () => {
|
||||||
|
let endpoint = '/paypal/subscribe/success';
|
||||||
|
let user;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
user = await generateUser();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('verifies Paypal Block', async () => {
|
||||||
|
await expect(user.get(endpoint)).to.eventually.be.rejected.and.eql({
|
||||||
|
code: 400,
|
||||||
|
error: 'BadRequest',
|
||||||
|
message: t('missingPaypalBlock'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
xdescribe('success', () => {
|
||||||
|
let subscribeSuccessStub;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
subscribeSuccessStub = sinon.stub(paypalPayments, 'subscribeSuccess').returnsPromise().resolves({});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
paypalPayments.subscribeSuccess.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates a subscription', async () => {
|
||||||
|
let token = 'test-token';
|
||||||
|
|
||||||
|
user = await generateUser({
|
||||||
|
'profile.name': 'sender',
|
||||||
|
'purchased.plan.customerId': 'customer-id',
|
||||||
|
'purchased.plan.planId': 'basic_3mo',
|
||||||
|
'purchased.plan.lastBillingDate': new Date(),
|
||||||
|
balance: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
await user.get(`${endpoint}?token=${token}`);
|
||||||
|
|
||||||
|
expect(subscribeSuccessStub).to.be.calledOnce;
|
||||||
|
|
||||||
|
expect(subscribeSuccessStub.args[0][0].user._id).to.eql(user._id);
|
||||||
|
expect(subscribeSuccessStub.args[0][0].block).to.eql(undefined);
|
||||||
|
expect(subscribeSuccessStub.args[0][0].groupId).to.eql(undefined);
|
||||||
|
expect(subscribeSuccessStub.args[0][0].token).to.eql(token);
|
||||||
|
expect(subscribeSuccessStub.args[0][0].headers).to.exist;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import {
|
||||||
|
generateUser,
|
||||||
|
} from '../../../../../helpers/api-integration/v3';
|
||||||
|
import paypalPayments from '../../../../../../website/server/libs/paypalPayments';
|
||||||
|
|
||||||
|
describe('payments - paypal - #ipn', () => {
|
||||||
|
let endpoint = '/paypal/ipn';
|
||||||
|
let user;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
user = await generateUser();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('verifies credentials', async () => {
|
||||||
|
let result = await user.post(endpoint);
|
||||||
|
expect(result).to.eql('OK');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('success', () => {
|
||||||
|
let ipnStub;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
ipnStub = sinon.stub(paypalPayments, 'ipn').returnsPromise().resolves({});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
paypalPayments.ipn.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('makes a purchase', async () => {
|
||||||
|
user = await generateUser({
|
||||||
|
'profile.name': 'sender',
|
||||||
|
'purchased.plan.customerId': 'customer-id',
|
||||||
|
'purchased.plan.planId': 'basic_3mo',
|
||||||
|
'purchased.plan.lastBillingDate': new Date(),
|
||||||
|
balance: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
await user.post(endpoint);
|
||||||
|
|
||||||
|
expect(ipnStub).to.be.calledOnce;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
import {
|
||||||
|
generateUser,
|
||||||
|
generateGroup,
|
||||||
|
translate as t,
|
||||||
|
} from '../../../../../helpers/api-integration/v3';
|
||||||
|
import stripePayments from '../../../../../../website/server/libs/stripePayments';
|
||||||
|
|
||||||
|
describe('payments - stripe - #subscribeCancel', () => {
|
||||||
|
let endpoint = '/stripe/subscribe/cancel';
|
||||||
|
let user, group, stripeCancelSubscriptionStub;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
user = await generateUser();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('verifies credentials', async () => {
|
||||||
|
await expect(user.get(endpoint)).to.eventually.be.rejected.and.eql({
|
||||||
|
code: 401,
|
||||||
|
error: 'NotAuthorized',
|
||||||
|
message: t('missingSubscription'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('success', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
stripeCancelSubscriptionStub = sinon.stub(stripePayments, 'cancelSubscription').returnsPromise().resolves({});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
stripePayments.cancelSubscription.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('cancels a user subscription', async () => {
|
||||||
|
user = await generateUser({
|
||||||
|
'profile.name': 'sender',
|
||||||
|
'purchased.plan.customerId': 'customer-id',
|
||||||
|
'purchased.plan.planId': 'basic_3mo',
|
||||||
|
'purchased.plan.lastBillingDate': new Date(),
|
||||||
|
balance: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
await user.get(`${endpoint}?redirect=none`);
|
||||||
|
|
||||||
|
expect(stripeCancelSubscriptionStub).to.be.calledOnce;
|
||||||
|
expect(stripeCancelSubscriptionStub.args[0][0].user._id).to.eql(user._id);
|
||||||
|
expect(stripeCancelSubscriptionStub.args[0][0].groupId).to.eql(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('cancels a group subscription', async () => {
|
||||||
|
user = await generateUser({
|
||||||
|
'profile.name': 'sender',
|
||||||
|
'purchased.plan.customerId': 'customer-id',
|
||||||
|
'purchased.plan.planId': 'basic_3mo',
|
||||||
|
'purchased.plan.lastBillingDate': new Date(),
|
||||||
|
balance: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
group = await generateGroup(user, {
|
||||||
|
name: 'test group',
|
||||||
|
type: 'guild',
|
||||||
|
privacy: 'public',
|
||||||
|
'purchased.plan.customerId': 'customer-id',
|
||||||
|
'purchased.plan.planId': 'basic_3mo',
|
||||||
|
'purchased.plan.lastBillingDate': new Date(),
|
||||||
|
});
|
||||||
|
|
||||||
|
await user.get(`${endpoint}?groupId=${group._id}&redirect=none`);
|
||||||
|
|
||||||
|
expect(stripeCancelSubscriptionStub).to.be.calledOnce;
|
||||||
|
expect(stripeCancelSubscriptionStub.args[0][0].user._id).to.eql(user._id);
|
||||||
|
expect(stripeCancelSubscriptionStub.args[0][0].groupId).to.eql(group._id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import {
|
||||||
|
generateUser,
|
||||||
|
generateGroup,
|
||||||
|
} from '../../../../../helpers/api-integration/v3';
|
||||||
|
import stripePayments from '../../../../../../website/server/libs/stripePayments';
|
||||||
|
|
||||||
|
describe('payments - stripe - #checkout', () => {
|
||||||
|
let endpoint = '/stripe/checkout';
|
||||||
|
let user, group;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
user = await generateUser();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('verifies credentials', async () => {
|
||||||
|
await expect(user.post(endpoint, {id: 123})).to.eventually.be.rejected.and.eql({
|
||||||
|
code: 401,
|
||||||
|
error: 'Error',
|
||||||
|
message: 'Invalid API Key provided: ****************************1111',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('success', () => {
|
||||||
|
let stripeCheckoutSubscriptionStub;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
stripeCheckoutSubscriptionStub = sinon.stub(stripePayments, 'checkout').returnsPromise().resolves({});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
stripePayments.checkout.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('cancels a user subscription', async () => {
|
||||||
|
user = await generateUser({
|
||||||
|
'profile.name': 'sender',
|
||||||
|
'purchased.plan.customerId': 'customer-id',
|
||||||
|
'purchased.plan.planId': 'basic_3mo',
|
||||||
|
'purchased.plan.lastBillingDate': new Date(),
|
||||||
|
balance: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
await user.post(endpoint);
|
||||||
|
|
||||||
|
expect(stripeCheckoutSubscriptionStub).to.be.calledOnce;
|
||||||
|
expect(stripeCheckoutSubscriptionStub.args[0][0].user._id).to.eql(user._id);
|
||||||
|
expect(stripeCheckoutSubscriptionStub.args[0][0].groupId).to.eql(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('cancels a group subscription', async () => {
|
||||||
|
user = await generateUser({
|
||||||
|
'profile.name': 'sender',
|
||||||
|
'purchased.plan.customerId': 'customer-id',
|
||||||
|
'purchased.plan.planId': 'basic_3mo',
|
||||||
|
'purchased.plan.lastBillingDate': new Date(),
|
||||||
|
balance: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
group = await generateGroup(user, {
|
||||||
|
name: 'test group',
|
||||||
|
type: 'guild',
|
||||||
|
privacy: 'public',
|
||||||
|
'purchased.plan.customerId': 'customer-id',
|
||||||
|
'purchased.plan.planId': 'basic_3mo',
|
||||||
|
'purchased.plan.lastBillingDate': new Date(),
|
||||||
|
});
|
||||||
|
|
||||||
|
await user.post(`${endpoint}?groupId=${group._id}`);
|
||||||
|
|
||||||
|
expect(stripeCheckoutSubscriptionStub).to.be.calledOnce;
|
||||||
|
expect(stripeCheckoutSubscriptionStub.args[0][0].user._id).to.eql(user._id);
|
||||||
|
expect(stripeCheckoutSubscriptionStub.args[0][0].groupId).to.eql(group._id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
import {
|
||||||
|
generateUser,
|
||||||
|
generateGroup,
|
||||||
|
translate as t,
|
||||||
|
} from '../../../../../helpers/api-integration/v3';
|
||||||
|
import stripePayments from '../../../../../../website/server/libs/stripePayments';
|
||||||
|
|
||||||
|
describe('payments - stripe - #subscribeEdit', () => {
|
||||||
|
let endpoint = '/stripe/subscribe/edit';
|
||||||
|
let user, group;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
user = await generateUser();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('verifies credentials', async () => {
|
||||||
|
await expect(user.post(endpoint)).to.eventually.be.rejected.and.eql({
|
||||||
|
code: 401,
|
||||||
|
error: 'NotAuthorized',
|
||||||
|
message: t('missingSubscription'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('success', () => {
|
||||||
|
let stripeEditSubscriptionStub;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
stripeEditSubscriptionStub = sinon.stub(stripePayments, 'editSubscription').returnsPromise().resolves({});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
stripePayments.editSubscription.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('cancels a user subscription', async () => {
|
||||||
|
user = await generateUser({
|
||||||
|
'profile.name': 'sender',
|
||||||
|
'purchased.plan.customerId': 'customer-id',
|
||||||
|
'purchased.plan.planId': 'basic_3mo',
|
||||||
|
'purchased.plan.lastBillingDate': new Date(),
|
||||||
|
balance: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
await user.post(endpoint);
|
||||||
|
|
||||||
|
expect(stripeEditSubscriptionStub).to.be.calledOnce;
|
||||||
|
expect(stripeEditSubscriptionStub.args[0][0].user._id).to.eql(user._id);
|
||||||
|
expect(stripeEditSubscriptionStub.args[0][0].groupId).to.eql(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('cancels a group subscription', async () => {
|
||||||
|
user = await generateUser({
|
||||||
|
'profile.name': 'sender',
|
||||||
|
'purchased.plan.customerId': 'customer-id',
|
||||||
|
'purchased.plan.planId': 'basic_3mo',
|
||||||
|
'purchased.plan.lastBillingDate': new Date(),
|
||||||
|
balance: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
group = await generateGroup(user, {
|
||||||
|
name: 'test group',
|
||||||
|
type: 'guild',
|
||||||
|
privacy: 'public',
|
||||||
|
'purchased.plan.customerId': 'customer-id',
|
||||||
|
'purchased.plan.planId': 'basic_3mo',
|
||||||
|
'purchased.plan.lastBillingDate': new Date(),
|
||||||
|
});
|
||||||
|
|
||||||
|
await user.post(endpoint, {
|
||||||
|
groupId: group._id,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(stripeEditSubscriptionStub).to.be.calledOnce;
|
||||||
|
expect(stripeEditSubscriptionStub.args[0][0].user._id).to.eql(user._id);
|
||||||
|
expect(stripeEditSubscriptionStub.args[0][0].groupId).to.eql(group._id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -148,5 +148,20 @@ describe('POST /groups/:groupId/quests/accept', () => {
|
|||||||
expect(rejectingMember.party.quest.key).to.not.exist;
|
expect(rejectingMember.party.quest.key).to.not.exist;
|
||||||
expect(rejectingMember.party.quest.completed).to.not.exist;
|
expect(rejectingMember.party.quest.completed).to.not.exist;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('begins the quest if accepting the last pending invite and verifies chat', async () => {
|
||||||
|
await leader.post(`/groups/${questingGroup._id}/quests/invite/${PET_QUEST}`);
|
||||||
|
await partyMembers[0].post(`/groups/${questingGroup._id}/quests/accept`);
|
||||||
|
// quest will start after everyone has accepted
|
||||||
|
await partyMembers[1].post(`/groups/${questingGroup._id}/quests/accept`);
|
||||||
|
|
||||||
|
await questingGroup.sync();
|
||||||
|
expect(questingGroup.chat[0].text).to.exist;
|
||||||
|
expect(questingGroup.chat[0]._meta).to.exist;
|
||||||
|
expect(questingGroup.chat[0]._meta).to.have.all.keys(['participatingMembers']);
|
||||||
|
|
||||||
|
let returnedGroup = await leader.get(`/groups/${questingGroup._id}`);
|
||||||
|
expect(returnedGroup.chat[0]._meta).to.be.undefined;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -231,5 +231,22 @@ describe('POST /groups/:groupId/quests/force-start', () => {
|
|||||||
expect(questingGroup.quest.members[partyMembers[0]._id]).to.exist;
|
expect(questingGroup.quest.members[partyMembers[0]._id]).to.exist;
|
||||||
expect(questingGroup.quest.members[leader._id]).to.exist;
|
expect(questingGroup.quest.members[leader._id]).to.exist;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('allows group leader to force start quest and verifies chat', async () => {
|
||||||
|
let questLeader = partyMembers[0];
|
||||||
|
await questLeader.update({[`items.quests.${PET_QUEST}`]: 1});
|
||||||
|
await questLeader.post(`/groups/${questingGroup._id}/quests/invite/${PET_QUEST}`);
|
||||||
|
|
||||||
|
await leader.post(`/groups/${questingGroup._id}/quests/force-start`);
|
||||||
|
|
||||||
|
await questingGroup.sync();
|
||||||
|
|
||||||
|
expect(questingGroup.chat[0].text).to.exist;
|
||||||
|
expect(questingGroup.chat[0]._meta).to.exist;
|
||||||
|
expect(questingGroup.chat[0]._meta).to.have.all.keys(['participatingMembers']);
|
||||||
|
|
||||||
|
let returnedGroup = await leader.get(`/groups/${questingGroup._id}`);
|
||||||
|
expect(returnedGroup.chat[0]._meta).to.be.undefined;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -188,5 +188,25 @@ describe('POST /groups/:groupId/quests/invite/:questKey', () => {
|
|||||||
|
|
||||||
expect(group.quest.active).to.eql(true);
|
expect(group.quest.active).to.eql(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('starts quest automatically if user is in a solo party and verifies chat', async () => {
|
||||||
|
let leaderDetails = { balance: 10 };
|
||||||
|
leaderDetails[`items.quests.${PET_QUEST}`] = 1;
|
||||||
|
let { group, groupLeader } = await createAndPopulateGroup({
|
||||||
|
groupDetails: { type: 'party', privacy: 'private' },
|
||||||
|
leaderDetails,
|
||||||
|
});
|
||||||
|
|
||||||
|
await groupLeader.post(`/groups/${group._id}/quests/invite/${PET_QUEST}`);
|
||||||
|
|
||||||
|
await group.sync();
|
||||||
|
|
||||||
|
expect(group.chat[0].text).to.exist;
|
||||||
|
expect(group.chat[0]._meta).to.exist;
|
||||||
|
expect(group.chat[0]._meta).to.have.all.keys(['participatingMembers']);
|
||||||
|
|
||||||
|
let returnedGroup = await groupLeader.get(`/groups/${group._id}`);
|
||||||
|
expect(returnedGroup.chat[0]._meta).to.be.undefined;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -86,11 +86,12 @@ describe('POST /groups/:groupId/quests/abort', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('aborts a quest', async () => {
|
it('aborts a quest', async () => {
|
||||||
sandbox.stub(Group.prototype, 'sendChat');
|
|
||||||
await leader.post(`/groups/${questingGroup._id}/quests/invite/${PET_QUEST}`);
|
await leader.post(`/groups/${questingGroup._id}/quests/invite/${PET_QUEST}`);
|
||||||
await partyMembers[0].post(`/groups/${questingGroup._id}/quests/accept`);
|
await partyMembers[0].post(`/groups/${questingGroup._id}/quests/accept`);
|
||||||
await partyMembers[1].post(`/groups/${questingGroup._id}/quests/accept`);
|
await partyMembers[1].post(`/groups/${questingGroup._id}/quests/accept`);
|
||||||
|
|
||||||
|
let stub = sandbox.stub(Group.prototype, 'sendChat');
|
||||||
|
|
||||||
let res = await leader.post(`/groups/${questingGroup._id}/quests/abort`);
|
let res = await leader.post(`/groups/${questingGroup._id}/quests/abort`);
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
leader.sync(),
|
leader.sync(),
|
||||||
@@ -127,6 +128,7 @@ describe('POST /groups/:groupId/quests/abort', () => {
|
|||||||
});
|
});
|
||||||
expect(Group.prototype.sendChat).to.be.calledOnce;
|
expect(Group.prototype.sendChat).to.be.calledOnce;
|
||||||
expect(Group.prototype.sendChat).to.be.calledWithMatch(/aborted the party quest Wail of the Whale.`/);
|
expect(Group.prototype.sendChat).to.be.calledWithMatch(/aborted the party quest Wail of the Whale.`/);
|
||||||
Group.prototype.sendChat.restore();
|
|
||||||
|
stub.restore();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -180,5 +180,19 @@ describe('POST /groups/:groupId/quests/reject', () => {
|
|||||||
expect(rejectingMember.party.quest.key).to.not.exist;
|
expect(rejectingMember.party.quest.key).to.not.exist;
|
||||||
expect(rejectingMember.party.quest.completed).to.not.exist;
|
expect(rejectingMember.party.quest.completed).to.not.exist;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('starts the quest when the last user reject and verifies chat', async () => {
|
||||||
|
await leader.post(`/groups/${questingGroup._id}/quests/invite/${PET_QUEST}`);
|
||||||
|
await partyMembers[0].post(`/groups/${questingGroup._id}/quests/accept`);
|
||||||
|
await partyMembers[1].post(`/groups/${questingGroup._id}/quests/reject`);
|
||||||
|
await questingGroup.sync();
|
||||||
|
|
||||||
|
expect(questingGroup.chat[0].text).to.exist;
|
||||||
|
expect(questingGroup.chat[0]._meta).to.exist;
|
||||||
|
expect(questingGroup.chat[0]._meta).to.have.all.keys(['participatingMembers']);
|
||||||
|
|
||||||
|
let returnedGroup = await leader.get(`/groups/${questingGroup._id}`);
|
||||||
|
expect(returnedGroup.chat[0]._meta).to.be.undefined;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
} from '../../../../helpers/api-integration/v3';
|
} from '../../../../helpers/api-integration/v3';
|
||||||
|
|
||||||
describe('POST /tasks/clearCompletedTodos', () => {
|
describe('POST /tasks/clearCompletedTodos', () => {
|
||||||
it('deletes all completed todos except the ones from a challenge', async () => {
|
it('deletes all completed todos except the ones from a challenge and group', async () => {
|
||||||
let user = await generateUser({balance: 1});
|
let user = await generateUser({balance: 1});
|
||||||
let guild = await generateGroup(user);
|
let guild = await generateGroup(user);
|
||||||
let challenge = await generateChallenge(user, guild);
|
let challenge = await generateChallenge(user, guild);
|
||||||
@@ -24,8 +24,14 @@ describe('POST /tasks/clearCompletedTodos', () => {
|
|||||||
type: 'todo',
|
type: 'todo',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let groupTask = await user.post(`/tasks/group/${guild._id}`, {
|
||||||
|
text: 'todo 7',
|
||||||
|
type: 'todo',
|
||||||
|
});
|
||||||
|
await user.post(`/tasks/${groupTask._id}/assign/${user._id}`);
|
||||||
|
|
||||||
let tasks = await user.get('/tasks/user?type=todos');
|
let tasks = await user.get('/tasks/user?type=todos');
|
||||||
expect(tasks.length).to.equal(initialTodoCount + 6);
|
expect(tasks.length).to.equal(initialTodoCount + 7);
|
||||||
|
|
||||||
for (let task of tasks) {
|
for (let task of tasks) {
|
||||||
if (['todo 2', 'todo 3', 'todo 6'].indexOf(task.text) !== -1) {
|
if (['todo 2', 'todo 3', 'todo 6'].indexOf(task.text) !== -1) {
|
||||||
@@ -38,6 +44,6 @@ describe('POST /tasks/clearCompletedTodos', () => {
|
|||||||
let todos = await user.get('/tasks/user?type=todos');
|
let todos = await user.get('/tasks/user?type=todos');
|
||||||
let allTodos = todos.concat(completedTodos);
|
let allTodos = todos.concat(completedTodos);
|
||||||
expect(allTodos.length).to.equal(initialTodoCount + 4); // + 6 - 3 completed (but one is from challenge)
|
expect(allTodos.length).to.equal(initialTodoCount + 4); // + 6 - 3 completed (but one is from challenge)
|
||||||
expect(allTodos[allTodos.length - 1].text).to.equal('todo 6');
|
expect(allTodos[allTodos.length - 1].text).to.equal('todo 7');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -81,4 +81,36 @@ describe('DELETE /tasks/:id', () => {
|
|||||||
message: t('cantDeleteAssignedGroupTasks'),
|
message: t('cantDeleteAssignedGroupTasks'),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('allows a user to delete a broken task', async () => {
|
||||||
|
let memberTasks = await member.get('/tasks/user');
|
||||||
|
let syncedTask = find(memberTasks, findAssignedTask);
|
||||||
|
|
||||||
|
await user.del(`/tasks/${task._id}`);
|
||||||
|
|
||||||
|
await member.del(`/tasks/${syncedTask._id}`);
|
||||||
|
|
||||||
|
await expect(member.get(`/tasks/${syncedTask._id}`))
|
||||||
|
.to.eventually.be.rejected.and.eql({
|
||||||
|
code: 404,
|
||||||
|
error: 'NotFound',
|
||||||
|
message: 'Task not found.',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('allows a user to delete a task after leaving a group', async () => {
|
||||||
|
let memberTasks = await member.get('/tasks/user');
|
||||||
|
let syncedTask = find(memberTasks, findAssignedTask);
|
||||||
|
|
||||||
|
await member.post(`/groups/${guild._id}/leave`);
|
||||||
|
|
||||||
|
await member.del(`/tasks/${syncedTask._id}`);
|
||||||
|
|
||||||
|
await expect(member.get(`/tasks/${syncedTask._id}`))
|
||||||
|
.to.eventually.be.rejected.and.eql({
|
||||||
|
code: 404,
|
||||||
|
error: 'NotFound',
|
||||||
|
message: 'Task not found.',
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -34,6 +34,10 @@ describe('POST /tasks/:id/score/:direction', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('prevents user from scoring a task that needs to be approved', async () => {
|
it('prevents user from scoring a task that needs to be approved', async () => {
|
||||||
|
await user.update({
|
||||||
|
'preferences.language': 'cs',
|
||||||
|
});
|
||||||
|
|
||||||
let memberTasks = await member.get('/tasks/user');
|
let memberTasks = await member.get('/tasks/user');
|
||||||
let syncedTask = find(memberTasks, findAssignedTask);
|
let syncedTask = find(memberTasks, findAssignedTask);
|
||||||
|
|
||||||
@@ -52,7 +56,7 @@ describe('POST /tasks/:id/score/:direction', () => {
|
|||||||
expect(user.notifications[0].data.message).to.equal(t('userHasRequestedTaskApproval', {
|
expect(user.notifications[0].data.message).to.equal(t('userHasRequestedTaskApproval', {
|
||||||
user: member.auth.local.username,
|
user: member.auth.local.username,
|
||||||
taskName: updatedTask.text,
|
taskName: updatedTask.text,
|
||||||
}));
|
}, 'cs')); // This test only works if we have the notification translated
|
||||||
expect(user.notifications[0].data.groupId).to.equal(guild._id);
|
expect(user.notifications[0].data.groupId).to.equal(guild._id);
|
||||||
|
|
||||||
expect(updatedTask.group.approval.requested).to.equal(true);
|
expect(updatedTask.group.approval.requested).to.equal(true);
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ describe('POST /tasks/:taskId', () => {
|
|||||||
let updateGroup = await user.get(`/groups/${guild._id}`);
|
let updateGroup = await user.get(`/groups/${guild._id}`);
|
||||||
|
|
||||||
expect(updateGroup.chat[0].text).to.equal(t('userIsClamingTask', {username: member.profile.name, task: task.text}));
|
expect(updateGroup.chat[0].text).to.equal(t('userIsClamingTask', {username: member.profile.name, task: task.text}));
|
||||||
|
expect(updateGroup.chat[0].uuid).to.equal('system');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('assigns a task to a user', async () => {
|
it('assigns a task to a user', async () => {
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import {
|
||||||
|
generateUser,
|
||||||
|
generateGroup,
|
||||||
|
} from '../../../../../helpers/api-v3-integration.helper';
|
||||||
|
|
||||||
|
describe('POST group-tasks/:taskId/move/to/:position', () => {
|
||||||
|
let user, guild;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
user = await generateUser({balance: 1});
|
||||||
|
guild = await generateGroup(user, {type: 'guild'});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can move task to new position', async () => {
|
||||||
|
let tasks = await user.post(`/tasks/group/${guild._id}`, [
|
||||||
|
{type: 'habit', text: 'habit 1'},
|
||||||
|
{type: 'habit', text: 'habit 2'},
|
||||||
|
{type: 'daily', text: 'daily 1'},
|
||||||
|
{type: 'habit', text: 'habit 3'},
|
||||||
|
{type: 'habit', text: 'habit 4'},
|
||||||
|
{type: 'todo', text: 'todo 1'},
|
||||||
|
{type: 'habit', text: 'habit 5'},
|
||||||
|
]);
|
||||||
|
|
||||||
|
let taskToMove = tasks[1];
|
||||||
|
expect(taskToMove.text).to.equal('habit 2');
|
||||||
|
let newOrder = await user.post(`/group-tasks/${tasks[1]._id}/move/to/3`);
|
||||||
|
expect(newOrder[3]).to.equal(taskToMove._id);
|
||||||
|
expect(newOrder.length).to.equal(5);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can push to bottom', async () => {
|
||||||
|
let tasks = await user.post(`/tasks/group/${guild._id}`, [
|
||||||
|
{type: 'habit', text: 'habit 1'},
|
||||||
|
{type: 'habit', text: 'habit 2'},
|
||||||
|
{type: 'daily', text: 'daily 1'},
|
||||||
|
{type: 'habit', text: 'habit 3'},
|
||||||
|
{type: 'habit', text: 'habit 4'},
|
||||||
|
{type: 'todo', text: 'todo 1'},
|
||||||
|
{type: 'habit', text: 'habit 5'},
|
||||||
|
]);
|
||||||
|
|
||||||
|
let taskToMove = tasks[1];
|
||||||
|
expect(taskToMove.text).to.equal('habit 2');
|
||||||
|
let newOrder = await user.post(`/group-tasks/${tasks[1]._id}/move/to/-1`);
|
||||||
|
expect(newOrder[4]).to.equal(taskToMove._id);
|
||||||
|
expect(newOrder.length).to.equal(5);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -62,15 +62,6 @@ describe('POST /user/buy/:key', () => {
|
|||||||
await user.post(`/user/buy/${key}`);
|
await user.post(`/user/buy/${key}`);
|
||||||
await user.sync();
|
await user.sync();
|
||||||
|
|
||||||
expect(user.items.gear.owned).to.eql({
|
expect(user.items.gear.owned.armor_warrior_1).to.eql(true);
|
||||||
armor_warrior_1: true,
|
|
||||||
eyewear_special_blackTopFrame: true,
|
|
||||||
eyewear_special_blueTopFrame: true,
|
|
||||||
eyewear_special_greenTopFrame: true,
|
|
||||||
eyewear_special_pinkTopFrame: true,
|
|
||||||
eyewear_special_redTopFrame: true,
|
|
||||||
eyewear_special_whiteTopFrame: true,
|
|
||||||
eyewear_special_yellowTopFrame: true,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -31,15 +31,6 @@ describe('POST /user/buy-gear/:key', () => {
|
|||||||
await user.post(`/user/buy-gear/${key}`);
|
await user.post(`/user/buy-gear/${key}`);
|
||||||
await user.sync();
|
await user.sync();
|
||||||
|
|
||||||
expect(user.items.gear.owned).to.eql({
|
expect(user.items.gear.owned.armor_warrior_1).to.eql(true);
|
||||||
armor_warrior_1: true,
|
|
||||||
eyewear_special_blackTopFrame: true,
|
|
||||||
eyewear_special_blueTopFrame: true,
|
|
||||||
eyewear_special_greenTopFrame: true,
|
|
||||||
eyewear_special_pinkTopFrame: true,
|
|
||||||
eyewear_special_redTopFrame: true,
|
|
||||||
eyewear_special_whiteTopFrame: true,
|
|
||||||
eyewear_special_yellowTopFrame: true,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
} from '../../../../helpers/api-integration/v3';
|
} from '../../../../helpers/api-integration/v3';
|
||||||
|
|
||||||
import { v4 as generateUUID } from 'uuid';
|
import { v4 as generateUUID } from 'uuid';
|
||||||
|
import { find } from 'lodash';
|
||||||
|
|
||||||
describe('POST /user/class/cast/:spellId', () => {
|
describe('POST /user/class/cast/:spellId', () => {
|
||||||
let user;
|
let user;
|
||||||
@@ -120,6 +121,31 @@ describe('POST /user/class/cast/:spellId', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('returns an error if a group task was targeted', async () => {
|
||||||
|
let {group, groupLeader} = await createAndPopulateGroup();
|
||||||
|
|
||||||
|
let groupTask = await groupLeader.post(`/tasks/group/${group._id}`, {
|
||||||
|
text: 'todo group',
|
||||||
|
type: 'todo',
|
||||||
|
});
|
||||||
|
await groupLeader.post(`/tasks/${groupTask._id}/assign/${groupLeader._id}`);
|
||||||
|
let memberTasks = await groupLeader.get('/tasks/user');
|
||||||
|
let syncedGroupTask = find(memberTasks, function findAssignedTask (memberTask) {
|
||||||
|
return memberTask.group.id === group._id;
|
||||||
|
});
|
||||||
|
|
||||||
|
await groupLeader.update({'stats.class': 'rogue', 'stats.lvl': 11});
|
||||||
|
await sleep(0.5);
|
||||||
|
await groupLeader.sync();
|
||||||
|
|
||||||
|
await expect(groupLeader.post(`/user/class/cast/pickPocket?targetId=${syncedGroupTask._id}`))
|
||||||
|
.to.eventually.be.rejected.and.eql({
|
||||||
|
code: 400,
|
||||||
|
error: 'BadRequest',
|
||||||
|
message: t('groupTasksNoCast'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('returns an error if targeted party member doesn\'t exist', async () => {
|
it('returns an error if targeted party member doesn\'t exist', async () => {
|
||||||
let {groupLeader} = await createAndPopulateGroup({
|
let {groupLeader} = await createAndPopulateGroup({
|
||||||
groupDetails: { type: 'party', privacy: 'private' },
|
groupDetails: { type: 'party', privacy: 'private' },
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import {
|
|||||||
generateChallenge,
|
generateChallenge,
|
||||||
translate as t,
|
translate as t,
|
||||||
} from '../../../../helpers/api-integration/v3';
|
} from '../../../../helpers/api-integration/v3';
|
||||||
|
import { find } from 'lodash';
|
||||||
|
|
||||||
describe('POST /user/reset', () => {
|
describe('POST /user/reset', () => {
|
||||||
let user;
|
let user;
|
||||||
@@ -86,19 +87,34 @@ describe('POST /user/reset', () => {
|
|||||||
expect(user.tasksOrder.rewards).to.be.empty;
|
expect(user.tasksOrder.rewards).to.be.empty;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not delete challenge tasks', async () => {
|
it('does not delete challenge or group tasks', async () => {
|
||||||
let guild = await generateGroup(user);
|
let guild = await generateGroup(user);
|
||||||
let challenge = await generateChallenge(user, guild);
|
let challenge = await generateChallenge(user, guild);
|
||||||
let task = await user.post(`/tasks/challenge/${challenge._id}`, {
|
await user.post(`/tasks/challenge/${challenge._id}`, {
|
||||||
text: 'test challenge habit',
|
text: 'test challenge habit',
|
||||||
type: 'habit',
|
type: 'habit',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let groupTask = await user.post(`/tasks/group/${guild._id}`, {
|
||||||
|
text: 'todo group',
|
||||||
|
type: 'todo',
|
||||||
|
});
|
||||||
|
await user.post(`/tasks/${groupTask._id}/assign/${user._id}`);
|
||||||
|
|
||||||
await user.post('/user/reset');
|
await user.post('/user/reset');
|
||||||
await user.sync();
|
await user.sync();
|
||||||
|
|
||||||
let userChallengeTask = await user.get(`/tasks/${task._id}`);
|
let memberTasks = await user.get('/tasks/user');
|
||||||
|
|
||||||
expect(userChallengeTask).to.eql(task);
|
let syncedGroupTask = find(memberTasks, function findAssignedTask (memberTask) {
|
||||||
|
return memberTask.group.id === guild._id;
|
||||||
|
});
|
||||||
|
|
||||||
|
let userChallengeTask = find(memberTasks, function findAssignedTask (memberTask) {
|
||||||
|
return memberTask.challenge.id === challenge._id;
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(userChallengeTask).to.exist;
|
||||||
|
expect(syncedGroupTask).to.exist;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -26,6 +26,32 @@ describe('PUT /user', () => {
|
|||||||
expect(user.preferences.costume).to.eql(true);
|
expect(user.preferences.costume).to.eql(true);
|
||||||
expect(user.stats.hp).to.eql(14);
|
expect(user.stats.hp).to.eql(14);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('profile.name cannot be an empty string or null', async () => {
|
||||||
|
await expect(user.put('/user', {
|
||||||
|
'profile.name': ' ', // string should be trimmed
|
||||||
|
})).to.eventually.be.rejected.and.eql({
|
||||||
|
code: 400,
|
||||||
|
error: 'BadRequest',
|
||||||
|
message: 'User validation failed',
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect(user.put('/user', {
|
||||||
|
'profile.name': '',
|
||||||
|
})).to.eventually.be.rejected.and.eql({
|
||||||
|
code: 400,
|
||||||
|
error: 'BadRequest',
|
||||||
|
message: 'User validation failed',
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect(user.put('/user', {
|
||||||
|
'profile.name': null,
|
||||||
|
})).to.eventually.be.rejected.and.eql({
|
||||||
|
code: 400,
|
||||||
|
error: 'BadRequest',
|
||||||
|
message: 'User validation failed',
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
context('Top Level Protected Operations', () => {
|
context('Top Level Protected Operations', () => {
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ describe('POST /user/auth/local/register', () => {
|
|||||||
expect(user._id).to.exist;
|
expect(user._id).to.exist;
|
||||||
expect(user.apiToken).to.exist;
|
expect(user.apiToken).to.exist;
|
||||||
expect(user.auth.local.username).to.eql(username);
|
expect(user.auth.local.username).to.eql(username);
|
||||||
|
expect(user.profile.name).to.eql(username);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('provides default tags and tasks', async () => {
|
it('provides default tags and tasks', async () => {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ describe('POST /user/auth/social', () => {
|
|||||||
|
|
||||||
describe('facebook', () => {
|
describe('facebook', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
let expectedResult = {id: facebookId};
|
let expectedResult = {id: facebookId, displayName: 'a facebook user'};
|
||||||
sandbox.stub(passport._strategies.facebook, 'userProfile').yields(null, expectedResult);
|
sandbox.stub(passport._strategies.facebook, 'userProfile').yields(null, expectedResult);
|
||||||
network = 'facebook';
|
network = 'facebook';
|
||||||
});
|
});
|
||||||
@@ -47,6 +47,7 @@ describe('POST /user/auth/social', () => {
|
|||||||
expect(response.apiToken).to.exist;
|
expect(response.apiToken).to.exist;
|
||||||
expect(response.id).to.exist;
|
expect(response.id).to.exist;
|
||||||
expect(response.newUser).to.be.true;
|
expect(response.newUser).to.be.true;
|
||||||
|
await expect(getProperty('users', response.id, 'profile.name')).to.eventually.equal('a facebook user');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('logs an existing user in', async () => {
|
it('logs an existing user in', async () => {
|
||||||
@@ -88,7 +89,7 @@ describe('POST /user/auth/social', () => {
|
|||||||
|
|
||||||
describe('google', () => {
|
describe('google', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
let expectedResult = {id: googleId};
|
let expectedResult = {id: googleId, displayName: 'a google user'};
|
||||||
sandbox.stub(passport._strategies.google, 'userProfile').yields(null, expectedResult);
|
sandbox.stub(passport._strategies.google, 'userProfile').yields(null, expectedResult);
|
||||||
network = 'google';
|
network = 'google';
|
||||||
});
|
});
|
||||||
@@ -102,6 +103,7 @@ describe('POST /user/auth/social', () => {
|
|||||||
expect(response.apiToken).to.exist;
|
expect(response.apiToken).to.exist;
|
||||||
expect(response.id).to.exist;
|
expect(response.id).to.exist;
|
||||||
expect(response.newUser).to.be.true;
|
expect(response.newUser).to.be.true;
|
||||||
|
await expect(getProperty('users', response.id, 'profile.name')).to.eventually.equal('a google user');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('logs an existing user in', async () => {
|
it('logs an existing user in', async () => {
|
||||||
|
|||||||
562
test/api/v3/unit/libs/amazonPayments.test.js
Normal file
562
test/api/v3/unit/libs/amazonPayments.test.js
Normal file
@@ -0,0 +1,562 @@
|
|||||||
|
import moment from 'moment';
|
||||||
|
import cc from 'coupon-code';
|
||||||
|
|
||||||
|
import {
|
||||||
|
generateGroup,
|
||||||
|
} from '../../../../helpers/api-unit.helper.js';
|
||||||
|
import { model as User } from '../../../../../website/server/models/user';
|
||||||
|
import { model as Coupon } from '../../../../../website/server/models/coupon';
|
||||||
|
import amzLib from '../../../../../website/server/libs/amazonPayments';
|
||||||
|
import payments from '../../../../../website/server/libs/payments';
|
||||||
|
import common from '../../../../../website/common';
|
||||||
|
|
||||||
|
const i18n = common.i18n;
|
||||||
|
|
||||||
|
describe('Amazon Payments', () => {
|
||||||
|
let subKey = 'basic_3mo';
|
||||||
|
|
||||||
|
describe('checkout', () => {
|
||||||
|
let user, orderReferenceId, headers;
|
||||||
|
let setOrderReferenceDetailsSpy;
|
||||||
|
let confirmOrderReferenceSpy;
|
||||||
|
let authorizeSpy;
|
||||||
|
let closeOrderReferenceSpy;
|
||||||
|
|
||||||
|
let paymentBuyGemsStub;
|
||||||
|
let paymentCreateSubscritionStub;
|
||||||
|
let amount = 5;
|
||||||
|
|
||||||
|
function expectAmazonStubs () {
|
||||||
|
expect(setOrderReferenceDetailsSpy).to.be.calledOnce;
|
||||||
|
expect(setOrderReferenceDetailsSpy).to.be.calledWith({
|
||||||
|
AmazonOrderReferenceId: orderReferenceId,
|
||||||
|
OrderReferenceAttributes: {
|
||||||
|
OrderTotal: {
|
||||||
|
CurrencyCode: amzLib.constants.CURRENCY_CODE,
|
||||||
|
Amount: amount,
|
||||||
|
},
|
||||||
|
SellerNote: amzLib.constants.SELLER_NOTE,
|
||||||
|
SellerOrderAttributes: {
|
||||||
|
SellerOrderId: common.uuid(),
|
||||||
|
StoreName: amzLib.constants.STORE_NAME,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(confirmOrderReferenceSpy).to.be.calledOnce;
|
||||||
|
expect(confirmOrderReferenceSpy).to.be.calledWith({ AmazonOrderReferenceId: orderReferenceId });
|
||||||
|
|
||||||
|
expect(authorizeSpy).to.be.calledOnce;
|
||||||
|
expect(authorizeSpy).to.be.calledWith({
|
||||||
|
AmazonOrderReferenceId: orderReferenceId,
|
||||||
|
AuthorizationReferenceId: common.uuid().substring(0, 32),
|
||||||
|
AuthorizationAmount: {
|
||||||
|
CurrencyCode: amzLib.constants.CURRENCY_CODE,
|
||||||
|
Amount: amount,
|
||||||
|
},
|
||||||
|
SellerAuthorizationNote: amzLib.constants.SELLER_NOTE,
|
||||||
|
TransactionTimeout: 0,
|
||||||
|
CaptureNow: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(closeOrderReferenceSpy).to.be.calledOnce;
|
||||||
|
expect(closeOrderReferenceSpy).to.be.calledWith({ AmazonOrderReferenceId: orderReferenceId });
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
user = new User();
|
||||||
|
headers = {};
|
||||||
|
orderReferenceId = 'orderReferenceId';
|
||||||
|
|
||||||
|
setOrderReferenceDetailsSpy = sinon.stub(amzLib, 'setOrderReferenceDetails');
|
||||||
|
setOrderReferenceDetailsSpy.returnsPromise().resolves({});
|
||||||
|
|
||||||
|
confirmOrderReferenceSpy = sinon.stub(amzLib, 'confirmOrderReference');
|
||||||
|
confirmOrderReferenceSpy.returnsPromise().resolves({});
|
||||||
|
|
||||||
|
authorizeSpy = sinon.stub(amzLib, 'authorize');
|
||||||
|
authorizeSpy.returnsPromise().resolves({});
|
||||||
|
|
||||||
|
closeOrderReferenceSpy = sinon.stub(amzLib, 'closeOrderReference');
|
||||||
|
closeOrderReferenceSpy.returnsPromise().resolves({});
|
||||||
|
|
||||||
|
paymentBuyGemsStub = sinon.stub(payments, 'buyGems');
|
||||||
|
paymentBuyGemsStub.returnsPromise().resolves({});
|
||||||
|
|
||||||
|
paymentCreateSubscritionStub = sinon.stub(payments, 'createSubscription');
|
||||||
|
paymentCreateSubscritionStub.returnsPromise().resolves({});
|
||||||
|
|
||||||
|
sinon.stub(common, 'uuid').returns('uuid-generated');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
amzLib.setOrderReferenceDetails.restore();
|
||||||
|
amzLib.confirmOrderReference.restore();
|
||||||
|
amzLib.authorize.restore();
|
||||||
|
amzLib.closeOrderReference.restore();
|
||||||
|
payments.buyGems.restore();
|
||||||
|
payments.createSubscription.restore();
|
||||||
|
common.uuid.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should purchase gems', async () => {
|
||||||
|
await amzLib.checkout({user, orderReferenceId, headers});
|
||||||
|
|
||||||
|
expect(paymentBuyGemsStub).to.be.calledOnce;
|
||||||
|
expect(paymentBuyGemsStub).to.be.calledWith({
|
||||||
|
user,
|
||||||
|
paymentMethod: amzLib.constants.PAYMENT_METHOD_AMAZON,
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
expectAmazonStubs();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should gift gems', async () => {
|
||||||
|
let receivingUser = new User();
|
||||||
|
receivingUser.save();
|
||||||
|
let gift = {
|
||||||
|
type: 'gems',
|
||||||
|
gems: {
|
||||||
|
amount: 16,
|
||||||
|
uuid: receivingUser._id,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
amount = 16 / 4;
|
||||||
|
await amzLib.checkout({gift, user, orderReferenceId, headers});
|
||||||
|
|
||||||
|
gift.member = receivingUser;
|
||||||
|
expect(paymentBuyGemsStub).to.be.calledOnce;
|
||||||
|
expect(paymentBuyGemsStub).to.be.calledWith({
|
||||||
|
user,
|
||||||
|
paymentMethod: amzLib.constants.PAYMENT_METHOD_AMAZON_GIFT,
|
||||||
|
headers,
|
||||||
|
gift,
|
||||||
|
});
|
||||||
|
expectAmazonStubs();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should gift a subscription', async () => {
|
||||||
|
let receivingUser = new User();
|
||||||
|
receivingUser.save();
|
||||||
|
let gift = {
|
||||||
|
type: 'subscription',
|
||||||
|
subscription: {
|
||||||
|
key: subKey,
|
||||||
|
uuid: receivingUser._id,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
amount = common.content.subscriptionBlocks[subKey].price;
|
||||||
|
|
||||||
|
await amzLib.checkout({user, orderReferenceId, headers, gift});
|
||||||
|
|
||||||
|
gift.member = receivingUser;
|
||||||
|
expect(paymentCreateSubscritionStub).to.be.calledOnce;
|
||||||
|
expect(paymentCreateSubscritionStub).to.be.calledWith({
|
||||||
|
user,
|
||||||
|
paymentMethod: amzLib.constants.PAYMENT_METHOD_AMAZON_GIFT,
|
||||||
|
headers,
|
||||||
|
gift,
|
||||||
|
});
|
||||||
|
expectAmazonStubs();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('subscribe', () => {
|
||||||
|
let user, group, amount, billingAgreementId, sub, coupon, groupId, headers;
|
||||||
|
let amazonSetBillingAgreementDetailsSpy;
|
||||||
|
let amazonConfirmBillingAgreementSpy;
|
||||||
|
let amazongAuthorizeOnBillingAgreementSpy;
|
||||||
|
let createSubSpy;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
user = new User();
|
||||||
|
user.profile.name = 'sender';
|
||||||
|
user.purchased.plan.customerId = 'customer-id';
|
||||||
|
user.purchased.plan.planId = subKey;
|
||||||
|
user.purchased.plan.lastBillingDate = new Date();
|
||||||
|
|
||||||
|
group = generateGroup({
|
||||||
|
name: 'test group',
|
||||||
|
type: 'guild',
|
||||||
|
privacy: 'public',
|
||||||
|
leader: user._id,
|
||||||
|
});
|
||||||
|
group.purchased.plan.customerId = 'customer-id';
|
||||||
|
group.purchased.plan.planId = subKey;
|
||||||
|
await group.save();
|
||||||
|
|
||||||
|
amount = common.content.subscriptionBlocks[subKey].price;
|
||||||
|
billingAgreementId = 'billingAgreementId';
|
||||||
|
sub = {
|
||||||
|
key: subKey,
|
||||||
|
price: amount,
|
||||||
|
};
|
||||||
|
groupId = group._id;
|
||||||
|
headers = {};
|
||||||
|
|
||||||
|
amazonSetBillingAgreementDetailsSpy = sinon.stub(amzLib, 'setBillingAgreementDetails');
|
||||||
|
amazonSetBillingAgreementDetailsSpy.returnsPromise().resolves({});
|
||||||
|
|
||||||
|
amazonConfirmBillingAgreementSpy = sinon.stub(amzLib, 'confirmBillingAgreement');
|
||||||
|
amazonConfirmBillingAgreementSpy.returnsPromise().resolves({});
|
||||||
|
|
||||||
|
amazongAuthorizeOnBillingAgreementSpy = sinon.stub(amzLib, 'authorizeOnBillingAgreement');
|
||||||
|
amazongAuthorizeOnBillingAgreementSpy.returnsPromise().resolves({});
|
||||||
|
|
||||||
|
createSubSpy = sinon.stub(payments, 'createSubscription');
|
||||||
|
createSubSpy.returnsPromise().resolves({});
|
||||||
|
|
||||||
|
sinon.stub(common, 'uuid').returns('uuid-generated');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
amzLib.setBillingAgreementDetails.restore();
|
||||||
|
amzLib.confirmBillingAgreement.restore();
|
||||||
|
amzLib.authorizeOnBillingAgreement.restore();
|
||||||
|
payments.createSubscription.restore();
|
||||||
|
common.uuid.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error if we are missing a subscription', async () => {
|
||||||
|
await expect(amzLib.subscribe({
|
||||||
|
billingAgreementId,
|
||||||
|
coupon,
|
||||||
|
user,
|
||||||
|
groupId,
|
||||||
|
headers,
|
||||||
|
}))
|
||||||
|
.to.eventually.be.rejected.and.to.eql({
|
||||||
|
httpCode: 400,
|
||||||
|
name: 'BadRequest',
|
||||||
|
message: i18n.t('missingSubscriptionCode'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error if we are missing a billingAgreementId', async () => {
|
||||||
|
await expect(amzLib.subscribe({
|
||||||
|
sub,
|
||||||
|
coupon,
|
||||||
|
user,
|
||||||
|
groupId,
|
||||||
|
headers,
|
||||||
|
}))
|
||||||
|
.to.eventually.be.rejected.and.to.eql({
|
||||||
|
httpCode: 400,
|
||||||
|
name: 'BadRequest',
|
||||||
|
message: 'Missing req.body.billingAgreementId',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error when coupon code is missing', async () => {
|
||||||
|
sub.discount = 40;
|
||||||
|
|
||||||
|
await expect(amzLib.subscribe({
|
||||||
|
billingAgreementId,
|
||||||
|
sub,
|
||||||
|
coupon,
|
||||||
|
user,
|
||||||
|
groupId,
|
||||||
|
headers,
|
||||||
|
}))
|
||||||
|
.to.eventually.be.rejected.and.to.eql({
|
||||||
|
httpCode: 400,
|
||||||
|
name: 'BadRequest',
|
||||||
|
message: i18n.t('couponCodeRequired'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error when coupon code is invalid', async () => {
|
||||||
|
sub.discount = 40;
|
||||||
|
sub.key = 'google_6mo';
|
||||||
|
coupon = 'example-coupon';
|
||||||
|
|
||||||
|
let couponModel = new Coupon();
|
||||||
|
couponModel.event = 'google_6mo';
|
||||||
|
await couponModel.save();
|
||||||
|
|
||||||
|
sinon.stub(cc, 'validate').returns('invalid');
|
||||||
|
|
||||||
|
await expect(amzLib.subscribe({
|
||||||
|
billingAgreementId,
|
||||||
|
sub,
|
||||||
|
coupon,
|
||||||
|
user,
|
||||||
|
groupId,
|
||||||
|
headers,
|
||||||
|
}))
|
||||||
|
.to.eventually.be.rejected.and.to.eql({
|
||||||
|
httpCode: 401,
|
||||||
|
name: 'NotAuthorized',
|
||||||
|
message: i18n.t('invalidCoupon'),
|
||||||
|
});
|
||||||
|
cc.validate.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('subscribes with amazon with a coupon', async () => {
|
||||||
|
sub.discount = 40;
|
||||||
|
sub.key = 'google_6mo';
|
||||||
|
coupon = 'example-coupon';
|
||||||
|
|
||||||
|
let couponModel = new Coupon();
|
||||||
|
couponModel.event = 'google_6mo';
|
||||||
|
let updatedCouponModel = await couponModel.save();
|
||||||
|
|
||||||
|
sinon.stub(cc, 'validate').returns(updatedCouponModel._id);
|
||||||
|
|
||||||
|
await amzLib.subscribe({
|
||||||
|
billingAgreementId,
|
||||||
|
sub,
|
||||||
|
coupon,
|
||||||
|
user,
|
||||||
|
groupId,
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(createSubSpy).to.be.calledOnce;
|
||||||
|
expect(createSubSpy).to.be.calledWith({
|
||||||
|
user,
|
||||||
|
customerId: billingAgreementId,
|
||||||
|
paymentMethod: amzLib.constants.PAYMENT_METHOD_AMAZON,
|
||||||
|
sub,
|
||||||
|
headers,
|
||||||
|
groupId,
|
||||||
|
});
|
||||||
|
|
||||||
|
cc.validate.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('subscribes with amazon', async () => {
|
||||||
|
await amzLib.subscribe({
|
||||||
|
billingAgreementId,
|
||||||
|
sub,
|
||||||
|
coupon,
|
||||||
|
user,
|
||||||
|
groupId,
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(amazonSetBillingAgreementDetailsSpy).to.be.calledOnce;
|
||||||
|
expect(amazonSetBillingAgreementDetailsSpy).to.be.calledWith({
|
||||||
|
AmazonBillingAgreementId: billingAgreementId,
|
||||||
|
BillingAgreementAttributes: {
|
||||||
|
SellerNote: amzLib.constants.SELLER_NOTE_SUBSCRIPTION,
|
||||||
|
SellerBillingAgreementAttributes: {
|
||||||
|
SellerBillingAgreementId: common.uuid(),
|
||||||
|
StoreName: amzLib.constants.STORE_NAME,
|
||||||
|
CustomInformation: amzLib.constants.SELLER_NOTE_SUBSCRIPTION,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(amazonConfirmBillingAgreementSpy).to.be.calledOnce;
|
||||||
|
expect(amazonConfirmBillingAgreementSpy).to.be.calledWith({
|
||||||
|
AmazonBillingAgreementId: billingAgreementId,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(amazongAuthorizeOnBillingAgreementSpy).to.be.calledOnce;
|
||||||
|
expect(amazongAuthorizeOnBillingAgreementSpy).to.be.calledWith({
|
||||||
|
AmazonBillingAgreementId: billingAgreementId,
|
||||||
|
AuthorizationReferenceId: common.uuid().substring(0, 32),
|
||||||
|
AuthorizationAmount: {
|
||||||
|
CurrencyCode: amzLib.constants.CURRENCY_CODE,
|
||||||
|
Amount: amount,
|
||||||
|
},
|
||||||
|
SellerAuthorizationNote: amzLib.constants.SELLER_NOTE_ATHORIZATION_SUBSCRIPTION,
|
||||||
|
TransactionTimeout: 0,
|
||||||
|
CaptureNow: true,
|
||||||
|
SellerNote: amzLib.constants.SELLER_NOTE_ATHORIZATION_SUBSCRIPTION,
|
||||||
|
SellerOrderAttributes: {
|
||||||
|
SellerOrderId: common.uuid(),
|
||||||
|
StoreName: amzLib.constants.STORE_NAME,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(createSubSpy).to.be.calledOnce;
|
||||||
|
expect(createSubSpy).to.be.calledWith({
|
||||||
|
user,
|
||||||
|
customerId: billingAgreementId,
|
||||||
|
paymentMethod: amzLib.constants.PAYMENT_METHOD_AMAZON,
|
||||||
|
sub,
|
||||||
|
headers,
|
||||||
|
groupId,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('cancelSubscription', () => {
|
||||||
|
let user, group, headers, billingAgreementId, subscriptionBlock, subscriptionLength;
|
||||||
|
let getBillingAgreementDetailsSpy;
|
||||||
|
let paymentCancelSubscriptionSpy;
|
||||||
|
|
||||||
|
function expectAmazonStubs () {
|
||||||
|
expect(getBillingAgreementDetailsSpy).to.be.calledOnce;
|
||||||
|
expect(getBillingAgreementDetailsSpy).to.be.calledWith({
|
||||||
|
AmazonBillingAgreementId: billingAgreementId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
user = new User();
|
||||||
|
user.profile.name = 'sender';
|
||||||
|
user.purchased.plan.customerId = 'customer-id';
|
||||||
|
user.purchased.plan.planId = subKey;
|
||||||
|
user.purchased.plan.lastBillingDate = new Date();
|
||||||
|
|
||||||
|
group = generateGroup({
|
||||||
|
name: 'test group',
|
||||||
|
type: 'guild',
|
||||||
|
privacy: 'public',
|
||||||
|
leader: user._id,
|
||||||
|
});
|
||||||
|
group.purchased.plan.customerId = 'customer-id';
|
||||||
|
group.purchased.plan.planId = subKey;
|
||||||
|
group.purchased.plan.lastBillingDate = new Date();
|
||||||
|
await group.save();
|
||||||
|
|
||||||
|
subscriptionBlock = common.content.subscriptionBlocks[subKey];
|
||||||
|
subscriptionLength = subscriptionBlock.months * 30;
|
||||||
|
|
||||||
|
headers = {};
|
||||||
|
|
||||||
|
getBillingAgreementDetailsSpy = sinon.stub(amzLib, 'getBillingAgreementDetails');
|
||||||
|
getBillingAgreementDetailsSpy.returnsPromise().resolves({
|
||||||
|
BillingAgreementDetails: {
|
||||||
|
BillingAgreementStatus: {State: 'Closed'},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
paymentCancelSubscriptionSpy = sinon.stub(payments, 'cancelSubscription');
|
||||||
|
paymentCancelSubscriptionSpy.returnsPromise().resolves({});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
amzLib.getBillingAgreementDetails.restore();
|
||||||
|
payments.cancelSubscription.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error if we are missing a subscription', async () => {
|
||||||
|
user.purchased.plan.customerId = undefined;
|
||||||
|
|
||||||
|
await expect(amzLib.cancelSubscription({user}))
|
||||||
|
.to.eventually.be.rejected.and.to.eql({
|
||||||
|
httpCode: 401,
|
||||||
|
name: 'NotAuthorized',
|
||||||
|
message: i18n.t('missingSubscription'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should cancel a user subscription', async () => {
|
||||||
|
billingAgreementId = user.purchased.plan.customerId;
|
||||||
|
|
||||||
|
await amzLib.cancelSubscription({user, headers});
|
||||||
|
|
||||||
|
expect(paymentCancelSubscriptionSpy).to.be.calledOnce;
|
||||||
|
expect(paymentCancelSubscriptionSpy).to.be.calledWith({
|
||||||
|
user,
|
||||||
|
groupId: undefined,
|
||||||
|
nextBill: moment(user.purchased.plan.lastBillingDate).add({ days: subscriptionLength }),
|
||||||
|
paymentMethod: amzLib.constants.PAYMENT_METHOD_AMAZON,
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
expectAmazonStubs();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should close a user subscription if amazon not closed', async () => {
|
||||||
|
amzLib.getBillingAgreementDetails.restore();
|
||||||
|
getBillingAgreementDetailsSpy = sinon.stub(amzLib, 'getBillingAgreementDetails')
|
||||||
|
.returnsPromise()
|
||||||
|
.resolves({
|
||||||
|
BillingAgreementDetails: {
|
||||||
|
BillingAgreementStatus: {State: 'Open'},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
let closeBillingAgreementSpy = sinon.stub(amzLib, 'closeBillingAgreement').returnsPromise().resolves({});
|
||||||
|
billingAgreementId = user.purchased.plan.customerId;
|
||||||
|
|
||||||
|
await amzLib.cancelSubscription({user, headers});
|
||||||
|
|
||||||
|
expectAmazonStubs();
|
||||||
|
expect(closeBillingAgreementSpy).to.be.calledOnce;
|
||||||
|
expect(closeBillingAgreementSpy).to.be.calledWith({
|
||||||
|
AmazonBillingAgreementId: billingAgreementId,
|
||||||
|
});
|
||||||
|
expect(paymentCancelSubscriptionSpy).to.be.calledOnce;
|
||||||
|
expect(paymentCancelSubscriptionSpy).to.be.calledWith({
|
||||||
|
user,
|
||||||
|
groupId: undefined,
|
||||||
|
nextBill: moment(user.purchased.plan.lastBillingDate).add({ days: subscriptionLength }),
|
||||||
|
paymentMethod: amzLib.constants.PAYMENT_METHOD_AMAZON,
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
amzLib.closeBillingAgreement.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error if group is not found', async () => {
|
||||||
|
await expect(amzLib.cancelSubscription({user, groupId: 'fake-id'}))
|
||||||
|
.to.eventually.be.rejected.and.to.eql({
|
||||||
|
httpCode: 404,
|
||||||
|
name: 'NotFound',
|
||||||
|
message: i18n.t('groupNotFound'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error if user is not group leader', async () => {
|
||||||
|
let nonLeader = new User();
|
||||||
|
nonLeader.guilds.push(group._id);
|
||||||
|
await nonLeader.save();
|
||||||
|
|
||||||
|
await expect(amzLib.cancelSubscription({user: nonLeader, groupId: group._id}))
|
||||||
|
.to.eventually.be.rejected.and.to.eql({
|
||||||
|
httpCode: 401,
|
||||||
|
name: 'NotAuthorized',
|
||||||
|
message: i18n.t('onlyGroupLeaderCanManageSubscription'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should cancel a group subscription', async () => {
|
||||||
|
billingAgreementId = group.purchased.plan.customerId;
|
||||||
|
|
||||||
|
await amzLib.cancelSubscription({user, groupId: group._id, headers});
|
||||||
|
|
||||||
|
expect(paymentCancelSubscriptionSpy).to.be.calledOnce;
|
||||||
|
expect(paymentCancelSubscriptionSpy).to.be.calledWith({
|
||||||
|
user,
|
||||||
|
groupId: group._id,
|
||||||
|
nextBill: moment(group.purchased.plan.lastBillingDate).add({ days: subscriptionLength }),
|
||||||
|
paymentMethod: amzLib.constants.PAYMENT_METHOD_AMAZON,
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
expectAmazonStubs();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should close a group subscription if amazon not closed', async () => {
|
||||||
|
amzLib.getBillingAgreementDetails.restore();
|
||||||
|
getBillingAgreementDetailsSpy = sinon.stub(amzLib, 'getBillingAgreementDetails')
|
||||||
|
.returnsPromise()
|
||||||
|
.resolves({
|
||||||
|
BillingAgreementDetails: {
|
||||||
|
BillingAgreementStatus: {State: 'Open'},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
let closeBillingAgreementSpy = sinon.stub(amzLib, 'closeBillingAgreement').returnsPromise().resolves({});
|
||||||
|
billingAgreementId = group.purchased.plan.customerId;
|
||||||
|
|
||||||
|
await amzLib.cancelSubscription({user, groupId: group._id, headers});
|
||||||
|
|
||||||
|
expectAmazonStubs();
|
||||||
|
expect(closeBillingAgreementSpy).to.be.calledOnce;
|
||||||
|
expect(closeBillingAgreementSpy).to.be.calledWith({
|
||||||
|
AmazonBillingAgreementId: billingAgreementId,
|
||||||
|
});
|
||||||
|
expect(paymentCancelSubscriptionSpy).to.be.calledOnce;
|
||||||
|
expect(paymentCancelSubscriptionSpy).to.be.calledWith({
|
||||||
|
user,
|
||||||
|
groupId: group._id,
|
||||||
|
nextBill: moment(group.purchased.plan.lastBillingDate).add({ days: subscriptionLength }),
|
||||||
|
paymentMethod: amzLib.constants.PAYMENT_METHOD_AMAZON,
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
amzLib.closeBillingAgreement.restore();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -303,6 +303,7 @@ describe('analyticsService', () => {
|
|||||||
contributorLevel: 1,
|
contributorLevel: 1,
|
||||||
subscription: 'foo-plan',
|
subscription: 'foo-plan',
|
||||||
balance: 12,
|
balance: 12,
|
||||||
|
balanceGemAmount: 48,
|
||||||
loginIncentives: 1,
|
loginIncentives: 1,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ 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';
|
||||||
import amzLib from '../../../../../website/server/libs/amazonPayments';
|
|
||||||
|
|
||||||
describe('payments/index', () => {
|
describe('payments/index', () => {
|
||||||
let user, group, data, plan;
|
let user, group, data, plan;
|
||||||
@@ -818,109 +817,4 @@ describe('payments/index', () => {
|
|||||||
expect(updatedGroup.purchased.plan.quantity).to.eql(3);
|
expect(updatedGroup.purchased.plan.quantity).to.eql(3);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('payWithStripe', () => {
|
|
||||||
let spy;
|
|
||||||
let stripeCreateCustomerSpy;
|
|
||||||
let createSubSpy;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
spy = sinon.stub(stripe.subscriptions, 'update');
|
|
||||||
spy.returnsPromise().resolves;
|
|
||||||
|
|
||||||
stripeCreateCustomerSpy = sinon.stub(stripe.customers, 'create');
|
|
||||||
let stripCustomerResponse = {
|
|
||||||
subscriptions: {
|
|
||||||
data: [{id: 'test-id'}],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
stripeCreateCustomerSpy.returnsPromise().resolves(stripCustomerResponse);
|
|
||||||
|
|
||||||
createSubSpy = sinon.stub(api, 'createSubscription');
|
|
||||||
createSubSpy.returnsPromise().resolves({});
|
|
||||||
|
|
||||||
data.groupId = group._id;
|
|
||||||
data.sub.quantity = 3;
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(function () {
|
|
||||||
sinon.restore(stripe.subscriptions.update);
|
|
||||||
stripe.customers.create.restore();
|
|
||||||
api.createSubscription.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('subscribes with stripe', async () => {
|
|
||||||
let token = 'test-token';
|
|
||||||
let gift;
|
|
||||||
let sub = data.sub;
|
|
||||||
let groupId = group._id;
|
|
||||||
let email = 'test@test.com';
|
|
||||||
let headers = {};
|
|
||||||
let coupon;
|
|
||||||
|
|
||||||
await api.payWithStripe({
|
|
||||||
token,
|
|
||||||
user,
|
|
||||||
gift,
|
|
||||||
sub,
|
|
||||||
groupId,
|
|
||||||
email,
|
|
||||||
headers,
|
|
||||||
coupon,
|
|
||||||
}, stripe);
|
|
||||||
|
|
||||||
expect(stripeCreateCustomerSpy.calledOnce).to.be.true;
|
|
||||||
expect(createSubSpy.calledOnce).to.be.true;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('subscribeWithAmazon', () => {
|
|
||||||
let amazonSetBillingAgreementDetailsSpy;
|
|
||||||
let amazonConfirmBillingAgreementSpy;
|
|
||||||
let amazongAuthorizeOnBillingAgreementSpy;
|
|
||||||
let createSubSpy;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
amazonSetBillingAgreementDetailsSpy = sinon.stub(amzLib, 'setBillingAgreementDetails');
|
|
||||||
amazonSetBillingAgreementDetailsSpy.returnsPromise().resolves({});
|
|
||||||
|
|
||||||
amazonConfirmBillingAgreementSpy = sinon.stub(amzLib, 'confirmBillingAgreement');
|
|
||||||
amazonConfirmBillingAgreementSpy.returnsPromise().resolves({});
|
|
||||||
|
|
||||||
amazongAuthorizeOnBillingAgreementSpy = sinon.stub(amzLib, 'authorizeOnBillingAgreement');
|
|
||||||
amazongAuthorizeOnBillingAgreementSpy.returnsPromise().resolves({});
|
|
||||||
|
|
||||||
createSubSpy = sinon.stub(api, 'createSubscription');
|
|
||||||
createSubSpy.returnsPromise().resolves({});
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(function () {
|
|
||||||
amzLib.setBillingAgreementDetails.restore();
|
|
||||||
amzLib.confirmBillingAgreement.restore();
|
|
||||||
amzLib.authorizeOnBillingAgreement.restore();
|
|
||||||
api.createSubscription.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('subscribes with amazon', async () => {
|
|
||||||
let billingAgreementId = 'billingAgreementId';
|
|
||||||
let sub = data.sub;
|
|
||||||
let coupon;
|
|
||||||
let groupId = group._id;
|
|
||||||
let headers = {};
|
|
||||||
|
|
||||||
await api.subscribeWithAmazon({
|
|
||||||
billingAgreementId,
|
|
||||||
sub,
|
|
||||||
coupon,
|
|
||||||
user,
|
|
||||||
groupId,
|
|
||||||
headers,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(amazonSetBillingAgreementDetailsSpy.calledOnce).to.be.true;
|
|
||||||
expect(amazonConfirmBillingAgreementSpy.calledOnce).to.be.true;
|
|
||||||
expect(amazongAuthorizeOnBillingAgreementSpy.calledOnce).to.be.true;
|
|
||||||
expect(createSubSpy.calledOnce).to.be.true;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
528
test/api/v3/unit/libs/paypalPayments.test.js
Normal file
528
test/api/v3/unit/libs/paypalPayments.test.js
Normal file
@@ -0,0 +1,528 @@
|
|||||||
|
/* eslint-disable camelcase */
|
||||||
|
import nconf from 'nconf';
|
||||||
|
import moment from 'moment';
|
||||||
|
import cc from 'coupon-code';
|
||||||
|
|
||||||
|
import payments from '../../../../../website/server/libs/payments';
|
||||||
|
import paypalPayments from '../../../../../website/server/libs/paypalPayments';
|
||||||
|
import {
|
||||||
|
generateGroup,
|
||||||
|
} from '../../../../helpers/api-unit.helper.js';
|
||||||
|
import { model as User } from '../../../../../website/server/models/user';
|
||||||
|
import { model as Coupon } from '../../../../../website/server/models/coupon';
|
||||||
|
import common from '../../../../../website/common';
|
||||||
|
|
||||||
|
const BASE_URL = nconf.get('BASE_URL');
|
||||||
|
const i18n = common.i18n;
|
||||||
|
|
||||||
|
describe('Paypal Payments', () => {
|
||||||
|
let subKey = 'basic_3mo';
|
||||||
|
|
||||||
|
describe('checkout', () => {
|
||||||
|
let paypalPaymentCreateStub;
|
||||||
|
let approvalHerf;
|
||||||
|
|
||||||
|
function getPaypalCreateOptions (description, amount) {
|
||||||
|
return {
|
||||||
|
intent: 'sale',
|
||||||
|
payer: { payment_method: 'Paypal' },
|
||||||
|
redirect_urls: {
|
||||||
|
return_url: `${BASE_URL}/paypal/checkout/success`,
|
||||||
|
cancel_url: `${BASE_URL}`,
|
||||||
|
},
|
||||||
|
transactions: [{
|
||||||
|
item_list: {
|
||||||
|
items: [{
|
||||||
|
name: description,
|
||||||
|
price: amount,
|
||||||
|
currency: 'USD',
|
||||||
|
quantity: 1,
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
amount: {
|
||||||
|
currency: 'USD',
|
||||||
|
total: amount,
|
||||||
|
},
|
||||||
|
description,
|
||||||
|
}],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
approvalHerf = 'approval_href';
|
||||||
|
paypalPaymentCreateStub = sinon.stub(paypalPayments, 'paypalPaymentCreate')
|
||||||
|
.returnsPromise().resolves({
|
||||||
|
links: [{ rel: 'approval_url', href: approvalHerf }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
paypalPayments.paypalPaymentCreate.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates a link for gem purchases', async () => {
|
||||||
|
let link = await paypalPayments.checkout();
|
||||||
|
|
||||||
|
expect(paypalPaymentCreateStub).to.be.calledOnce;
|
||||||
|
expect(paypalPaymentCreateStub).to.be.calledWith(getPaypalCreateOptions('Habitica Gems', 5.00));
|
||||||
|
expect(link).to.eql(approvalHerf);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates a link for gifting gems', async () => {
|
||||||
|
let receivingUser = new User();
|
||||||
|
let gift = {
|
||||||
|
type: 'gems',
|
||||||
|
gems: {
|
||||||
|
amount: 16,
|
||||||
|
uuid: receivingUser._id,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let link = await paypalPayments.checkout({gift});
|
||||||
|
|
||||||
|
expect(paypalPaymentCreateStub).to.be.calledOnce;
|
||||||
|
expect(paypalPaymentCreateStub).to.be.calledWith(getPaypalCreateOptions('Habitica Gems (Gift)', '4.00'));
|
||||||
|
expect(link).to.eql(approvalHerf);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates a link for gifting a subscription', async () => {
|
||||||
|
let receivingUser = new User();
|
||||||
|
receivingUser.save();
|
||||||
|
let gift = {
|
||||||
|
type: 'subscription',
|
||||||
|
subscription: {
|
||||||
|
key: subKey,
|
||||||
|
uuid: receivingUser._id,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let link = await paypalPayments.checkout({gift});
|
||||||
|
|
||||||
|
expect(paypalPaymentCreateStub).to.be.calledOnce;
|
||||||
|
expect(paypalPaymentCreateStub).to.be.calledWith(getPaypalCreateOptions('mo. Habitica Subscription (Gift)', '15.00'));
|
||||||
|
expect(link).to.eql(approvalHerf);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('checkout success', () => {
|
||||||
|
let user, gift, customerId, paymentId;
|
||||||
|
let paypalPaymentExecuteStub, paymentBuyGemsStub, paymentsCreateSubscritionStub;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
user = new User();
|
||||||
|
customerId = 'customerId-test';
|
||||||
|
paymentId = 'paymentId-test';
|
||||||
|
|
||||||
|
paypalPaymentExecuteStub = sinon.stub(paypalPayments, 'paypalPaymentExecute').returnsPromise().resolves({});
|
||||||
|
paymentBuyGemsStub = sinon.stub(payments, 'buyGems').returnsPromise().resolves({});
|
||||||
|
paymentsCreateSubscritionStub = sinon.stub(payments, 'createSubscription').returnsPromise().resolves({});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
paypalPayments.paypalPaymentExecute.restore();
|
||||||
|
payments.buyGems.restore();
|
||||||
|
payments.createSubscription.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('purchases gems', async () => {
|
||||||
|
await paypalPayments.checkoutSuccess({user, gift, paymentId, customerId});
|
||||||
|
|
||||||
|
expect(paypalPaymentExecuteStub).to.be.calledOnce;
|
||||||
|
expect(paypalPaymentExecuteStub).to.be.calledWith(paymentId, { payer_id: customerId });
|
||||||
|
expect(paymentBuyGemsStub).to.be.calledOnce;
|
||||||
|
expect(paymentBuyGemsStub).to.be.calledWith({
|
||||||
|
user,
|
||||||
|
customerId,
|
||||||
|
paymentMethod: 'Paypal',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('gifts gems', async () => {
|
||||||
|
let receivingUser = new User();
|
||||||
|
await receivingUser.save();
|
||||||
|
gift = {
|
||||||
|
type: 'gems',
|
||||||
|
gems: {
|
||||||
|
amount: 16,
|
||||||
|
uuid: receivingUser._id,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await paypalPayments.checkoutSuccess({user, gift, paymentId, customerId});
|
||||||
|
|
||||||
|
expect(paypalPaymentExecuteStub).to.be.calledOnce;
|
||||||
|
expect(paypalPaymentExecuteStub).to.be.calledWith(paymentId, { payer_id: customerId });
|
||||||
|
expect(paymentBuyGemsStub).to.be.calledOnce;
|
||||||
|
expect(paymentBuyGemsStub).to.be.calledWith({
|
||||||
|
user,
|
||||||
|
customerId,
|
||||||
|
paymentMethod: 'PayPal (Gift)',
|
||||||
|
gift,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('gifts subscription', async () => {
|
||||||
|
let receivingUser = new User();
|
||||||
|
await receivingUser.save();
|
||||||
|
gift = {
|
||||||
|
type: 'subscription',
|
||||||
|
subscription: {
|
||||||
|
key: subKey,
|
||||||
|
uuid: receivingUser._id,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await paypalPayments.checkoutSuccess({user, gift, paymentId, customerId});
|
||||||
|
|
||||||
|
expect(paypalPaymentExecuteStub).to.be.calledOnce;
|
||||||
|
expect(paypalPaymentExecuteStub).to.be.calledWith(paymentId, { payer_id: customerId });
|
||||||
|
expect(paymentsCreateSubscritionStub).to.be.calledOnce;
|
||||||
|
expect(paymentsCreateSubscritionStub).to.be.calledWith({
|
||||||
|
user,
|
||||||
|
customerId,
|
||||||
|
paymentMethod: 'PayPal (Gift)',
|
||||||
|
gift,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('subscribe', () => {
|
||||||
|
let coupon, sub, approvalHerf;
|
||||||
|
let paypalBillingAgreementCreateStub;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
approvalHerf = 'approvalHerf-test';
|
||||||
|
sub = common.content.subscriptionBlocks[subKey];
|
||||||
|
|
||||||
|
paypalBillingAgreementCreateStub = sinon.stub(paypalPayments, 'paypalBillingAgreementCreate')
|
||||||
|
.returnsPromise().resolves({
|
||||||
|
links: [{ rel: 'approval_url', href: approvalHerf }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
paypalPayments.paypalBillingAgreementCreate.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error when coupon code is missing', async () => {
|
||||||
|
sub.discount = 40;
|
||||||
|
|
||||||
|
await expect(paypalPayments.subscribe({sub, coupon}))
|
||||||
|
.to.eventually.be.rejected.and.to.eql({
|
||||||
|
httpCode: 400,
|
||||||
|
name: 'BadRequest',
|
||||||
|
message: i18n.t('couponCodeRequired'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error when coupon code is invalid', async () => {
|
||||||
|
sub.discount = 40;
|
||||||
|
sub.key = 'google_6mo';
|
||||||
|
coupon = 'example-coupon';
|
||||||
|
|
||||||
|
let couponModel = new Coupon();
|
||||||
|
couponModel.event = 'google_6mo';
|
||||||
|
await couponModel.save();
|
||||||
|
|
||||||
|
sinon.stub(cc, 'validate').returns('invalid');
|
||||||
|
|
||||||
|
await expect(paypalPayments.subscribe({sub, coupon}))
|
||||||
|
.to.eventually.be.rejected.and.to.eql({
|
||||||
|
httpCode: 401,
|
||||||
|
name: 'NotAuthorized',
|
||||||
|
message: i18n.t('invalidCoupon'),
|
||||||
|
});
|
||||||
|
cc.validate.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('subscribes with amazon with a coupon', async () => {
|
||||||
|
sub.discount = 40;
|
||||||
|
sub.key = 'google_6mo';
|
||||||
|
coupon = 'example-coupon';
|
||||||
|
|
||||||
|
let couponModel = new Coupon();
|
||||||
|
couponModel.event = 'google_6mo';
|
||||||
|
let updatedCouponModel = await couponModel.save();
|
||||||
|
|
||||||
|
sinon.stub(cc, 'validate').returns(updatedCouponModel._id);
|
||||||
|
|
||||||
|
let link = await paypalPayments.subscribe({sub, coupon});
|
||||||
|
|
||||||
|
expect(link).to.eql(approvalHerf);
|
||||||
|
expect(paypalBillingAgreementCreateStub).to.be.calledOnce;
|
||||||
|
let billingPlanTitle = `Habitica Subscription ($${sub.price} every ${sub.months} months, recurring)`;
|
||||||
|
expect(paypalBillingAgreementCreateStub).to.be.calledWith({
|
||||||
|
name: billingPlanTitle,
|
||||||
|
description: billingPlanTitle,
|
||||||
|
start_date: moment().add({ minutes: 5 }).format(),
|
||||||
|
plan: {
|
||||||
|
id: sub.paypalKey,
|
||||||
|
},
|
||||||
|
payer: {
|
||||||
|
payment_method: 'Paypal',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
cc.validate.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates a link for a subscription', async () => {
|
||||||
|
delete sub.discount;
|
||||||
|
|
||||||
|
let link = await paypalPayments.subscribe({sub, coupon});
|
||||||
|
|
||||||
|
expect(link).to.eql(approvalHerf);
|
||||||
|
expect(paypalBillingAgreementCreateStub).to.be.calledOnce;
|
||||||
|
let billingPlanTitle = `Habitica Subscription ($${sub.price} every ${sub.months} months, recurring)`;
|
||||||
|
expect(paypalBillingAgreementCreateStub).to.be.calledWith({
|
||||||
|
name: billingPlanTitle,
|
||||||
|
description: billingPlanTitle,
|
||||||
|
start_date: moment().add({ minutes: 5 }).format(),
|
||||||
|
plan: {
|
||||||
|
id: sub.paypalKey,
|
||||||
|
},
|
||||||
|
payer: {
|
||||||
|
payment_method: 'Paypal',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('subscribeSuccess', () => {
|
||||||
|
let user, group, block, groupId, token, headers, customerId;
|
||||||
|
let paypalBillingAgreementExecuteStub, paymentsCreateSubscritionStub;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
user = new User();
|
||||||
|
|
||||||
|
group = generateGroup({
|
||||||
|
name: 'test group',
|
||||||
|
type: 'guild',
|
||||||
|
privacy: 'public',
|
||||||
|
leader: user._id,
|
||||||
|
});
|
||||||
|
|
||||||
|
token = 'test-token';
|
||||||
|
headers = {};
|
||||||
|
block = common.content.subscriptionBlocks[subKey];
|
||||||
|
customerId = 'test-customerId';
|
||||||
|
|
||||||
|
paypalBillingAgreementExecuteStub = sinon.stub(paypalPayments, 'paypalBillingAgreementExecute')
|
||||||
|
.returnsPromise({}).resolves({
|
||||||
|
id: customerId,
|
||||||
|
});
|
||||||
|
paymentsCreateSubscritionStub = sinon.stub(payments, 'createSubscription').returnsPromise().resolves({});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
paypalPayments.paypalBillingAgreementExecute.restore();
|
||||||
|
payments.createSubscription.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates a user subscription', async () => {
|
||||||
|
await paypalPayments.subscribeSuccess({user, block, groupId, token, headers});
|
||||||
|
|
||||||
|
expect(paypalBillingAgreementExecuteStub).to.be.calledOnce;
|
||||||
|
expect(paypalBillingAgreementExecuteStub).to.be.calledWith(token, {});
|
||||||
|
|
||||||
|
expect(paymentsCreateSubscritionStub).to.be.calledOnce;
|
||||||
|
expect(paymentsCreateSubscritionStub).to.be.calledWith({
|
||||||
|
user,
|
||||||
|
groupId,
|
||||||
|
customerId,
|
||||||
|
paymentMethod: 'Paypal',
|
||||||
|
sub: block,
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('create a group subscription', async () => {
|
||||||
|
groupId = group._id;
|
||||||
|
|
||||||
|
await paypalPayments.subscribeSuccess({user, block, groupId, token, headers});
|
||||||
|
|
||||||
|
expect(paypalBillingAgreementExecuteStub).to.be.calledOnce;
|
||||||
|
expect(paypalBillingAgreementExecuteStub).to.be.calledWith(token, {});
|
||||||
|
|
||||||
|
expect(paymentsCreateSubscritionStub).to.be.calledOnce;
|
||||||
|
expect(paymentsCreateSubscritionStub).to.be.calledWith({
|
||||||
|
user,
|
||||||
|
groupId,
|
||||||
|
customerId,
|
||||||
|
paymentMethod: 'Paypal',
|
||||||
|
sub: block,
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('subscribeCancel', () => {
|
||||||
|
let user, group, groupId, customerId, groupCustomerId, nextBillingDate;
|
||||||
|
let paymentCancelSubscriptionSpy, paypalBillingAgreementCancelStub, paypalBillingAgreementGetStub;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
customerId = 'customer-id';
|
||||||
|
groupCustomerId = 'groupCustomerId-test';
|
||||||
|
|
||||||
|
user = new User();
|
||||||
|
user.profile.name = 'sender';
|
||||||
|
user.purchased.plan.customerId = customerId;
|
||||||
|
user.purchased.plan.planId = subKey;
|
||||||
|
user.purchased.plan.lastBillingDate = new Date();
|
||||||
|
|
||||||
|
group = generateGroup({
|
||||||
|
name: 'test group',
|
||||||
|
type: 'guild',
|
||||||
|
privacy: 'public',
|
||||||
|
leader: user._id,
|
||||||
|
});
|
||||||
|
group.purchased.plan.customerId = groupCustomerId;
|
||||||
|
group.purchased.plan.planId = subKey;
|
||||||
|
group.purchased.plan.lastBillingDate = new Date();
|
||||||
|
await group.save();
|
||||||
|
|
||||||
|
nextBillingDate = new Date();
|
||||||
|
|
||||||
|
paypalBillingAgreementCancelStub = sinon.stub(paypalPayments, 'paypalBillingAgreementCancel').returnsPromise().resolves({});
|
||||||
|
paypalBillingAgreementGetStub = sinon.stub(paypalPayments, 'paypalBillingAgreementGet')
|
||||||
|
.returnsPromise().resolves({
|
||||||
|
agreement_details: {
|
||||||
|
next_billing_date: nextBillingDate,
|
||||||
|
cycles_completed: 1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
paymentCancelSubscriptionSpy = sinon.stub(payments, 'cancelSubscription').returnsPromise().resolves({});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
paypalPayments.paypalBillingAgreementGet.restore();
|
||||||
|
paypalPayments.paypalBillingAgreementCancel.restore();
|
||||||
|
payments.cancelSubscription.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error if we are missing a subscription', async () => {
|
||||||
|
user.purchased.plan.customerId = undefined;
|
||||||
|
|
||||||
|
await expect(paypalPayments.subscribeCancel({user}))
|
||||||
|
.to.eventually.be.rejected.and.to.eql({
|
||||||
|
httpCode: 401,
|
||||||
|
name: 'NotAuthorized',
|
||||||
|
message: i18n.t('missingSubscription'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error if group is not found', async () => {
|
||||||
|
await expect(paypalPayments.subscribeCancel({user, groupId: 'fake-id'}))
|
||||||
|
.to.eventually.be.rejected.and.to.eql({
|
||||||
|
httpCode: 404,
|
||||||
|
name: 'NotFound',
|
||||||
|
message: i18n.t('groupNotFound'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error if user is not group leader', async () => {
|
||||||
|
let nonLeader = new User();
|
||||||
|
nonLeader.guilds.push(group._id);
|
||||||
|
await nonLeader.save();
|
||||||
|
|
||||||
|
await expect(paypalPayments.subscribeCancel({user: nonLeader, groupId: group._id}))
|
||||||
|
.to.eventually.be.rejected.and.to.eql({
|
||||||
|
httpCode: 401,
|
||||||
|
name: 'NotAuthorized',
|
||||||
|
message: i18n.t('onlyGroupLeaderCanManageSubscription'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should cancel a user subscription', async () => {
|
||||||
|
await paypalPayments.subscribeCancel({user});
|
||||||
|
|
||||||
|
expect(paypalBillingAgreementGetStub).to.be.calledOnce;
|
||||||
|
expect(paypalBillingAgreementGetStub).to.be.calledWith(customerId);
|
||||||
|
expect(paypalBillingAgreementCancelStub).to.be.calledOnce;
|
||||||
|
expect(paypalBillingAgreementCancelStub).to.be.calledWith(customerId, { note: i18n.t('cancelingSubscription') });
|
||||||
|
|
||||||
|
expect(paymentCancelSubscriptionSpy).to.be.calledOnce;
|
||||||
|
expect(paymentCancelSubscriptionSpy).to.be.calledWith({
|
||||||
|
user,
|
||||||
|
groupId,
|
||||||
|
paymentMethod: 'Paypal',
|
||||||
|
nextBill: nextBillingDate,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should cancel a group subscription', async () => {
|
||||||
|
await paypalPayments.subscribeCancel({user, groupId: group._id});
|
||||||
|
|
||||||
|
expect(paypalBillingAgreementGetStub).to.be.calledOnce;
|
||||||
|
expect(paypalBillingAgreementGetStub).to.be.calledWith(groupCustomerId);
|
||||||
|
expect(paypalBillingAgreementCancelStub).to.be.calledOnce;
|
||||||
|
expect(paypalBillingAgreementCancelStub).to.be.calledWith(groupCustomerId, { note: i18n.t('cancelingSubscription') });
|
||||||
|
|
||||||
|
expect(paymentCancelSubscriptionSpy).to.be.calledOnce;
|
||||||
|
expect(paymentCancelSubscriptionSpy).to.be.calledWith({
|
||||||
|
user,
|
||||||
|
groupId: group._id,
|
||||||
|
paymentMethod: 'Paypal',
|
||||||
|
nextBill: nextBillingDate,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('ipn', () => {
|
||||||
|
let user, group, txn_type, userPaymentId, groupPaymentId;
|
||||||
|
let ipnVerifyAsyncStub, paymentCancelSubscriptionSpy;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
txn_type = 'recurring_payment_profile_cancel';
|
||||||
|
userPaymentId = 'userPaymentId-test';
|
||||||
|
groupPaymentId = 'groupPaymentId-test';
|
||||||
|
|
||||||
|
user = new User();
|
||||||
|
user.profile.name = 'sender';
|
||||||
|
user.purchased.plan.customerId = userPaymentId;
|
||||||
|
user.purchased.plan.planId = subKey;
|
||||||
|
user.purchased.plan.lastBillingDate = new Date();
|
||||||
|
await user.save();
|
||||||
|
|
||||||
|
group = generateGroup({
|
||||||
|
name: 'test group',
|
||||||
|
type: 'guild',
|
||||||
|
privacy: 'public',
|
||||||
|
leader: user._id,
|
||||||
|
});
|
||||||
|
group.purchased.plan.customerId = groupPaymentId;
|
||||||
|
group.purchased.plan.planId = subKey;
|
||||||
|
group.purchased.plan.lastBillingDate = new Date();
|
||||||
|
await group.save();
|
||||||
|
|
||||||
|
ipnVerifyAsyncStub = sinon.stub(paypalPayments, 'ipnVerifyAsync').returnsPromise().resolves({});
|
||||||
|
paymentCancelSubscriptionSpy = sinon.stub(payments, 'cancelSubscription').returnsPromise().resolves({});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
paypalPayments.ipnVerifyAsync.restore();
|
||||||
|
payments.cancelSubscription.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should cancel a user subscription', async () => {
|
||||||
|
await paypalPayments.ipn({txn_type, recurring_payment_id: userPaymentId});
|
||||||
|
|
||||||
|
expect(ipnVerifyAsyncStub).to.be.calledOnce;
|
||||||
|
expect(ipnVerifyAsyncStub).to.be.calledWith({txn_type, recurring_payment_id: userPaymentId});
|
||||||
|
|
||||||
|
expect(paymentCancelSubscriptionSpy).to.be.calledOnce;
|
||||||
|
expect(paymentCancelSubscriptionSpy.args[0][0].user._id).to.eql(user._id);
|
||||||
|
expect(paymentCancelSubscriptionSpy.args[0][0].paymentMethod).to.eql('Paypal');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should cancel a group subscription', async () => {
|
||||||
|
await paypalPayments.ipn({txn_type, recurring_payment_id: groupPaymentId});
|
||||||
|
|
||||||
|
expect(ipnVerifyAsyncStub).to.be.calledOnce;
|
||||||
|
expect(ipnVerifyAsyncStub).to.be.calledWith({txn_type, recurring_payment_id: groupPaymentId});
|
||||||
|
|
||||||
|
expect(paymentCancelSubscriptionSpy).to.be.calledOnce;
|
||||||
|
expect(paymentCancelSubscriptionSpy).to.be.calledWith({ groupId: group._id, paymentMethod: 'Paypal' });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
661
test/api/v3/unit/libs/stripePayments.test.js
Normal file
661
test/api/v3/unit/libs/stripePayments.test.js
Normal file
@@ -0,0 +1,661 @@
|
|||||||
|
import stripeModule from 'stripe';
|
||||||
|
import cc from 'coupon-code';
|
||||||
|
|
||||||
|
import {
|
||||||
|
generateGroup,
|
||||||
|
} from '../../../../helpers/api-unit.helper.js';
|
||||||
|
import { model as User } from '../../../../../website/server/models/user';
|
||||||
|
import { model as Coupon } from '../../../../../website/server/models/coupon';
|
||||||
|
import stripePayments from '../../../../../website/server/libs/stripePayments';
|
||||||
|
import payments from '../../../../../website/server/libs/payments';
|
||||||
|
import common from '../../../../../website/common';
|
||||||
|
|
||||||
|
const i18n = common.i18n;
|
||||||
|
|
||||||
|
describe('Stripe Payments', () => {
|
||||||
|
let subKey = 'basic_3mo';
|
||||||
|
let stripe = stripeModule('test');
|
||||||
|
|
||||||
|
describe('checkout', () => {
|
||||||
|
let stripeChargeStub, paymentBuyGemsStub, paymentCreateSubscritionStub;
|
||||||
|
let user, gift, groupId, email, headers, coupon, customerIdResponse, token;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
user = new User();
|
||||||
|
user.profile.name = 'sender';
|
||||||
|
user.purchased.plan.customerId = 'customer-id';
|
||||||
|
user.purchased.plan.planId = subKey;
|
||||||
|
user.purchased.plan.lastBillingDate = new Date();
|
||||||
|
|
||||||
|
token = 'test-token';
|
||||||
|
|
||||||
|
customerIdResponse = 'example-customerIdResponse';
|
||||||
|
let stripCustomerResponse = {
|
||||||
|
id: customerIdResponse,
|
||||||
|
};
|
||||||
|
stripeChargeStub = sinon.stub(stripe.charges, 'create').returnsPromise().resolves(stripCustomerResponse);
|
||||||
|
paymentBuyGemsStub = sinon.stub(payments, 'buyGems').returnsPromise().resolves({});
|
||||||
|
paymentCreateSubscritionStub = sinon.stub(payments, 'createSubscription').returnsPromise().resolves({});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
stripe.charges.create.restore();
|
||||||
|
payments.buyGems.restore();
|
||||||
|
payments.createSubscription.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should purchase gems', async () => {
|
||||||
|
await stripePayments.checkout({
|
||||||
|
token,
|
||||||
|
user,
|
||||||
|
gift,
|
||||||
|
groupId,
|
||||||
|
email,
|
||||||
|
headers,
|
||||||
|
coupon,
|
||||||
|
}, stripe);
|
||||||
|
|
||||||
|
expect(stripeChargeStub).to.be.calledOnce;
|
||||||
|
expect(stripeChargeStub).to.be.calledWith({
|
||||||
|
amount: 500,
|
||||||
|
currency: 'usd',
|
||||||
|
card: token,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(paymentBuyGemsStub).to.be.calledOnce;
|
||||||
|
expect(paymentBuyGemsStub).to.be.calledWith({
|
||||||
|
user,
|
||||||
|
customerId: customerIdResponse,
|
||||||
|
paymentMethod: 'Stripe',
|
||||||
|
gift,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should gift gems', async () => {
|
||||||
|
let receivingUser = new User();
|
||||||
|
receivingUser.save();
|
||||||
|
gift = {
|
||||||
|
type: 'gems',
|
||||||
|
gems: {
|
||||||
|
amount: 16,
|
||||||
|
uuid: receivingUser._id,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await stripePayments.checkout({
|
||||||
|
token,
|
||||||
|
user,
|
||||||
|
gift,
|
||||||
|
groupId,
|
||||||
|
email,
|
||||||
|
headers,
|
||||||
|
coupon,
|
||||||
|
}, stripe);
|
||||||
|
|
||||||
|
gift.member = receivingUser;
|
||||||
|
expect(stripeChargeStub).to.be.calledOnce;
|
||||||
|
expect(stripeChargeStub).to.be.calledWith({
|
||||||
|
amount: '400',
|
||||||
|
currency: 'usd',
|
||||||
|
card: token,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(paymentBuyGemsStub).to.be.calledOnce;
|
||||||
|
expect(paymentBuyGemsStub).to.be.calledWith({
|
||||||
|
user,
|
||||||
|
customerId: customerIdResponse,
|
||||||
|
paymentMethod: 'Gift',
|
||||||
|
gift,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should gift a subscription', async () => {
|
||||||
|
let receivingUser = new User();
|
||||||
|
receivingUser.save();
|
||||||
|
gift = {
|
||||||
|
type: 'subscription',
|
||||||
|
subscription: {
|
||||||
|
key: subKey,
|
||||||
|
uuid: receivingUser._id,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await stripePayments.checkout({
|
||||||
|
token,
|
||||||
|
user,
|
||||||
|
gift,
|
||||||
|
groupId,
|
||||||
|
email,
|
||||||
|
headers,
|
||||||
|
coupon,
|
||||||
|
}, stripe);
|
||||||
|
|
||||||
|
gift.member = receivingUser;
|
||||||
|
expect(stripeChargeStub).to.be.calledOnce;
|
||||||
|
expect(stripeChargeStub).to.be.calledWith({
|
||||||
|
amount: '1500',
|
||||||
|
currency: 'usd',
|
||||||
|
card: token,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(paymentCreateSubscritionStub).to.be.calledOnce;
|
||||||
|
expect(paymentCreateSubscritionStub).to.be.calledWith({
|
||||||
|
user,
|
||||||
|
customerId: customerIdResponse,
|
||||||
|
paymentMethod: 'Gift',
|
||||||
|
gift,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('checkout with subscription', () => {
|
||||||
|
let user, group, data, gift, sub, groupId, email, headers, coupon, customerIdResponse, subscriptionId, token;
|
||||||
|
let spy;
|
||||||
|
let stripeCreateCustomerSpy;
|
||||||
|
let stripePaymentsCreateSubSpy;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
user = new User();
|
||||||
|
user.profile.name = 'sender';
|
||||||
|
user.purchased.plan.customerId = 'customer-id';
|
||||||
|
user.purchased.plan.planId = subKey;
|
||||||
|
user.purchased.plan.lastBillingDate = new Date();
|
||||||
|
|
||||||
|
group = generateGroup({
|
||||||
|
name: 'test group',
|
||||||
|
type: 'guild',
|
||||||
|
privacy: 'public',
|
||||||
|
leader: user._id,
|
||||||
|
});
|
||||||
|
group.purchased.plan.customerId = 'customer-id';
|
||||||
|
group.purchased.plan.planId = subKey;
|
||||||
|
await group.save();
|
||||||
|
|
||||||
|
sub = {
|
||||||
|
key: 'basic_3mo',
|
||||||
|
};
|
||||||
|
|
||||||
|
data = {
|
||||||
|
user,
|
||||||
|
sub,
|
||||||
|
customerId: 'customer-id',
|
||||||
|
paymentMethod: 'Payment Method',
|
||||||
|
};
|
||||||
|
|
||||||
|
email = 'example@example.com';
|
||||||
|
customerIdResponse = 'test-id';
|
||||||
|
subscriptionId = 'test-sub-id';
|
||||||
|
token = 'test-token';
|
||||||
|
|
||||||
|
spy = sinon.stub(stripe.subscriptions, 'update');
|
||||||
|
spy.returnsPromise().resolves;
|
||||||
|
|
||||||
|
stripeCreateCustomerSpy = sinon.stub(stripe.customers, 'create');
|
||||||
|
let stripCustomerResponse = {
|
||||||
|
id: customerIdResponse,
|
||||||
|
subscriptions: {
|
||||||
|
data: [{id: subscriptionId}],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
stripeCreateCustomerSpy.returnsPromise().resolves(stripCustomerResponse);
|
||||||
|
|
||||||
|
stripePaymentsCreateSubSpy = sinon.stub(payments, 'createSubscription');
|
||||||
|
stripePaymentsCreateSubSpy.returnsPromise().resolves({});
|
||||||
|
|
||||||
|
data.groupId = group._id;
|
||||||
|
data.sub.quantity = 3;
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
sinon.restore(stripe.subscriptions.update);
|
||||||
|
stripe.customers.create.restore();
|
||||||
|
payments.createSubscription.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error if we are missing a token', async () => {
|
||||||
|
await expect(stripePayments.checkout({
|
||||||
|
user,
|
||||||
|
gift,
|
||||||
|
sub,
|
||||||
|
groupId,
|
||||||
|
email,
|
||||||
|
headers,
|
||||||
|
coupon,
|
||||||
|
}))
|
||||||
|
.to.eventually.be.rejected.and.to.eql({
|
||||||
|
httpCode: 400,
|
||||||
|
name: 'BadRequest',
|
||||||
|
message: 'Missing req.body.id',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error when coupon code is missing', async () => {
|
||||||
|
sub.discount = 40;
|
||||||
|
|
||||||
|
await expect(stripePayments.checkout({
|
||||||
|
token,
|
||||||
|
user,
|
||||||
|
gift,
|
||||||
|
sub,
|
||||||
|
groupId,
|
||||||
|
email,
|
||||||
|
headers,
|
||||||
|
coupon,
|
||||||
|
}))
|
||||||
|
.to.eventually.be.rejected.and.to.eql({
|
||||||
|
httpCode: 400,
|
||||||
|
name: 'BadRequest',
|
||||||
|
message: i18n.t('couponCodeRequired'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error when coupon code is invalid', async () => {
|
||||||
|
sub.discount = 40;
|
||||||
|
sub.key = 'google_6mo';
|
||||||
|
coupon = 'example-coupon';
|
||||||
|
|
||||||
|
let couponModel = new Coupon();
|
||||||
|
couponModel.event = 'google_6mo';
|
||||||
|
await couponModel.save();
|
||||||
|
|
||||||
|
sinon.stub(cc, 'validate').returns('invalid');
|
||||||
|
|
||||||
|
await expect(stripePayments.checkout({
|
||||||
|
token,
|
||||||
|
user,
|
||||||
|
gift,
|
||||||
|
sub,
|
||||||
|
groupId,
|
||||||
|
email,
|
||||||
|
headers,
|
||||||
|
coupon,
|
||||||
|
}))
|
||||||
|
.to.eventually.be.rejected.and.to.eql({
|
||||||
|
httpCode: 400,
|
||||||
|
name: 'BadRequest',
|
||||||
|
message: i18n.t('invalidCoupon'),
|
||||||
|
});
|
||||||
|
cc.validate.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('subscribes with amazon with a coupon', async () => {
|
||||||
|
sub.discount = 40;
|
||||||
|
sub.key = 'google_6mo';
|
||||||
|
coupon = 'example-coupon';
|
||||||
|
|
||||||
|
let couponModel = new Coupon();
|
||||||
|
couponModel.event = 'google_6mo';
|
||||||
|
let updatedCouponModel = await couponModel.save();
|
||||||
|
|
||||||
|
sinon.stub(cc, 'validate').returns(updatedCouponModel._id);
|
||||||
|
|
||||||
|
await stripePayments.checkout({
|
||||||
|
token,
|
||||||
|
user,
|
||||||
|
gift,
|
||||||
|
sub,
|
||||||
|
groupId,
|
||||||
|
email,
|
||||||
|
headers,
|
||||||
|
coupon,
|
||||||
|
}, stripe);
|
||||||
|
|
||||||
|
expect(stripeCreateCustomerSpy).to.be.calledOnce;
|
||||||
|
expect(stripeCreateCustomerSpy).to.be.calledWith({
|
||||||
|
email,
|
||||||
|
metadata: { uuid: user._id },
|
||||||
|
card: token,
|
||||||
|
plan: sub.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(stripePaymentsCreateSubSpy).to.be.calledOnce;
|
||||||
|
expect(stripePaymentsCreateSubSpy).to.be.calledWith({
|
||||||
|
user,
|
||||||
|
customerId: customerIdResponse,
|
||||||
|
paymentMethod: 'Stripe',
|
||||||
|
sub,
|
||||||
|
headers,
|
||||||
|
groupId: undefined,
|
||||||
|
subscriptionId: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
cc.validate.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('subscribes a user', async () => {
|
||||||
|
sub = data.sub;
|
||||||
|
|
||||||
|
await stripePayments.checkout({
|
||||||
|
token,
|
||||||
|
user,
|
||||||
|
gift,
|
||||||
|
sub,
|
||||||
|
groupId,
|
||||||
|
email,
|
||||||
|
headers,
|
||||||
|
coupon,
|
||||||
|
}, stripe);
|
||||||
|
|
||||||
|
expect(stripeCreateCustomerSpy).to.be.calledOnce;
|
||||||
|
expect(stripeCreateCustomerSpy).to.be.calledWith({
|
||||||
|
email,
|
||||||
|
metadata: { uuid: user._id },
|
||||||
|
card: token,
|
||||||
|
plan: sub.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(stripePaymentsCreateSubSpy).to.be.calledOnce;
|
||||||
|
expect(stripePaymentsCreateSubSpy).to.be.calledWith({
|
||||||
|
user,
|
||||||
|
customerId: customerIdResponse,
|
||||||
|
paymentMethod: 'Stripe',
|
||||||
|
sub,
|
||||||
|
headers,
|
||||||
|
groupId: undefined,
|
||||||
|
subscriptionId: undefined,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('subscribes a group', async () => {
|
||||||
|
token = 'test-token';
|
||||||
|
sub = data.sub;
|
||||||
|
groupId = group._id;
|
||||||
|
email = 'test@test.com';
|
||||||
|
headers = {};
|
||||||
|
|
||||||
|
await stripePayments.checkout({
|
||||||
|
token,
|
||||||
|
user,
|
||||||
|
gift,
|
||||||
|
sub,
|
||||||
|
groupId,
|
||||||
|
email,
|
||||||
|
headers,
|
||||||
|
coupon,
|
||||||
|
}, stripe);
|
||||||
|
|
||||||
|
expect(stripeCreateCustomerSpy).to.be.calledOnce;
|
||||||
|
expect(stripeCreateCustomerSpy).to.be.calledWith({
|
||||||
|
email,
|
||||||
|
metadata: { uuid: user._id },
|
||||||
|
card: token,
|
||||||
|
plan: sub.key,
|
||||||
|
quantity: 3,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(stripePaymentsCreateSubSpy).to.be.calledOnce;
|
||||||
|
expect(stripePaymentsCreateSubSpy).to.be.calledWith({
|
||||||
|
user,
|
||||||
|
customerId: customerIdResponse,
|
||||||
|
paymentMethod: 'Stripe',
|
||||||
|
sub,
|
||||||
|
headers,
|
||||||
|
groupId,
|
||||||
|
subscriptionId,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('edit subscription', () => {
|
||||||
|
let user, groupId, group, token;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
user = new User();
|
||||||
|
user.profile.name = 'sender';
|
||||||
|
user.purchased.plan.customerId = 'customer-id';
|
||||||
|
user.purchased.plan.planId = subKey;
|
||||||
|
user.purchased.plan.lastBillingDate = new Date();
|
||||||
|
|
||||||
|
group = generateGroup({
|
||||||
|
name: 'test group',
|
||||||
|
type: 'guild',
|
||||||
|
privacy: 'public',
|
||||||
|
leader: user._id,
|
||||||
|
});
|
||||||
|
group.purchased.plan.customerId = 'customer-id';
|
||||||
|
group.purchased.plan.planId = subKey;
|
||||||
|
await group.save();
|
||||||
|
|
||||||
|
groupId = group._id;
|
||||||
|
|
||||||
|
token = 'test-token';
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an error if there is no customer id', async () => {
|
||||||
|
user.purchased.plan.customerId = undefined;
|
||||||
|
|
||||||
|
await expect(stripePayments.editSubscription({
|
||||||
|
user,
|
||||||
|
groupId: undefined,
|
||||||
|
}))
|
||||||
|
.to.eventually.be.rejected.and.to.eql({
|
||||||
|
httpCode: 401,
|
||||||
|
name: 'NotAuthorized',
|
||||||
|
message: i18n.t('missingSubscription'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an error if a token is not provided', async () => {
|
||||||
|
await expect(stripePayments.editSubscription({
|
||||||
|
user,
|
||||||
|
groupId: undefined,
|
||||||
|
}))
|
||||||
|
.to.eventually.be.rejected.and.to.eql({
|
||||||
|
httpCode: 400,
|
||||||
|
name: 'BadRequest',
|
||||||
|
message: 'Missing req.body.id',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an error if the group is not found', async () => {
|
||||||
|
await expect(stripePayments.editSubscription({
|
||||||
|
token,
|
||||||
|
user,
|
||||||
|
groupId: 'fake-group',
|
||||||
|
}))
|
||||||
|
.to.eventually.be.rejected.and.to.eql({
|
||||||
|
httpCode: 404,
|
||||||
|
name: 'NotFound',
|
||||||
|
message: i18n.t('groupNotFound'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an error if user is not the group leader', async () => {
|
||||||
|
let nonLeader = new User();
|
||||||
|
nonLeader.guilds.push(groupId);
|
||||||
|
await nonLeader.save();
|
||||||
|
|
||||||
|
await expect(stripePayments.editSubscription({
|
||||||
|
token,
|
||||||
|
user: nonLeader,
|
||||||
|
groupId,
|
||||||
|
}))
|
||||||
|
.to.eventually.be.rejected.and.to.eql({
|
||||||
|
httpCode: 401,
|
||||||
|
name: 'NotAuthorized',
|
||||||
|
message: i18n.t('onlyGroupLeaderCanManageSubscription'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('success', () => {
|
||||||
|
let stripeListSubscriptionStub, stripeUpdateSubscriptionStub, subscriptionId;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
subscriptionId = 'subId';
|
||||||
|
stripeListSubscriptionStub = sinon.stub(stripe.customers, 'listSubscriptions')
|
||||||
|
.returnsPromise().resolves({
|
||||||
|
data: [{id: subscriptionId}],
|
||||||
|
});
|
||||||
|
|
||||||
|
stripeUpdateSubscriptionStub = sinon.stub(stripe.customers, 'updateSubscription').returnsPromise().resolves({});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
stripe.customers.listSubscriptions.restore();
|
||||||
|
stripe.customers.updateSubscription.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('edits a user subscription', async () => {
|
||||||
|
await stripePayments.editSubscription({
|
||||||
|
token,
|
||||||
|
user,
|
||||||
|
groupId: undefined,
|
||||||
|
}, stripe);
|
||||||
|
|
||||||
|
expect(stripeListSubscriptionStub).to.be.calledOnce;
|
||||||
|
expect(stripeListSubscriptionStub).to.be.calledWith(user.purchased.plan.customerId);
|
||||||
|
expect(stripeUpdateSubscriptionStub).to.be.calledOnce;
|
||||||
|
expect(stripeUpdateSubscriptionStub).to.be.calledWith(
|
||||||
|
user.purchased.plan.customerId,
|
||||||
|
subscriptionId,
|
||||||
|
{ card: token }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('edits a group subscription', async () => {
|
||||||
|
await stripePayments.editSubscription({
|
||||||
|
token,
|
||||||
|
user,
|
||||||
|
groupId,
|
||||||
|
}, stripe);
|
||||||
|
|
||||||
|
expect(stripeListSubscriptionStub).to.be.calledOnce;
|
||||||
|
expect(stripeListSubscriptionStub).to.be.calledWith(group.purchased.plan.customerId);
|
||||||
|
expect(stripeUpdateSubscriptionStub).to.be.calledOnce;
|
||||||
|
expect(stripeUpdateSubscriptionStub).to.be.calledWith(
|
||||||
|
group.purchased.plan.customerId,
|
||||||
|
subscriptionId,
|
||||||
|
{ card: token }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('cancel subscription', () => {
|
||||||
|
let user, groupId, group;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
user = new User();
|
||||||
|
user.profile.name = 'sender';
|
||||||
|
user.purchased.plan.customerId = 'customer-id';
|
||||||
|
user.purchased.plan.planId = subKey;
|
||||||
|
user.purchased.plan.lastBillingDate = new Date();
|
||||||
|
|
||||||
|
group = generateGroup({
|
||||||
|
name: 'test group',
|
||||||
|
type: 'guild',
|
||||||
|
privacy: 'public',
|
||||||
|
leader: user._id,
|
||||||
|
});
|
||||||
|
group.purchased.plan.customerId = 'customer-id';
|
||||||
|
group.purchased.plan.planId = subKey;
|
||||||
|
await group.save();
|
||||||
|
|
||||||
|
groupId = group._id;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an error if there is no customer id', async () => {
|
||||||
|
user.purchased.plan.customerId = undefined;
|
||||||
|
|
||||||
|
await expect(stripePayments.cancelSubscription({
|
||||||
|
user,
|
||||||
|
groupId: undefined,
|
||||||
|
}))
|
||||||
|
.to.eventually.be.rejected.and.to.eql({
|
||||||
|
httpCode: 401,
|
||||||
|
name: 'NotAuthorized',
|
||||||
|
message: i18n.t('missingSubscription'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an error if the group is not found', async () => {
|
||||||
|
await expect(stripePayments.cancelSubscription({
|
||||||
|
user,
|
||||||
|
groupId: 'fake-group',
|
||||||
|
}))
|
||||||
|
.to.eventually.be.rejected.and.to.eql({
|
||||||
|
httpCode: 404,
|
||||||
|
name: 'NotFound',
|
||||||
|
message: i18n.t('groupNotFound'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an error if user is not the group leader', async () => {
|
||||||
|
let nonLeader = new User();
|
||||||
|
nonLeader.guilds.push(groupId);
|
||||||
|
await nonLeader.save();
|
||||||
|
|
||||||
|
await expect(stripePayments.cancelSubscription({
|
||||||
|
user: nonLeader,
|
||||||
|
groupId,
|
||||||
|
}))
|
||||||
|
.to.eventually.be.rejected.and.to.eql({
|
||||||
|
httpCode: 401,
|
||||||
|
name: 'NotAuthorized',
|
||||||
|
message: i18n.t('onlyGroupLeaderCanManageSubscription'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('success', () => {
|
||||||
|
let stripeDeleteCustomerStub, paymentsCancelSubStub, stripeRetrieveStub, subscriptionId, currentPeriodEndTimeStamp;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
subscriptionId = 'subId';
|
||||||
|
stripeDeleteCustomerStub = sinon.stub(stripe.customers, 'del').returnsPromise().resolves({});
|
||||||
|
paymentsCancelSubStub = sinon.stub(payments, 'cancelSubscription').returnsPromise().resolves({});
|
||||||
|
|
||||||
|
currentPeriodEndTimeStamp = (new Date()).getTime();
|
||||||
|
stripeRetrieveStub = sinon.stub(stripe.customers, 'retrieve')
|
||||||
|
.returnsPromise().resolves({
|
||||||
|
subscriptions: {
|
||||||
|
data: [{id: subscriptionId, current_period_end: currentPeriodEndTimeStamp}], // eslint-disable-line camelcase
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
stripe.customers.del.restore();
|
||||||
|
stripe.customers.retrieve.restore();
|
||||||
|
payments.cancelSubscription.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('cancels a user subscription', async () => {
|
||||||
|
await stripePayments.cancelSubscription({
|
||||||
|
user,
|
||||||
|
groupId: undefined,
|
||||||
|
}, stripe);
|
||||||
|
|
||||||
|
expect(stripeDeleteCustomerStub).to.be.calledOnce;
|
||||||
|
expect(stripeDeleteCustomerStub).to.be.calledWith(user.purchased.plan.customerId);
|
||||||
|
expect(stripeRetrieveStub).to.be.calledOnce;
|
||||||
|
expect(stripeRetrieveStub).to.be.calledWith(user.purchased.plan.customerId);
|
||||||
|
expect(paymentsCancelSubStub).to.be.calledOnce;
|
||||||
|
expect(paymentsCancelSubStub).to.be.calledWith({
|
||||||
|
user,
|
||||||
|
groupId: undefined,
|
||||||
|
nextBill: currentPeriodEndTimeStamp * 1000, // timestamp in seconds
|
||||||
|
paymentMethod: 'Stripe',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('cancels a group subscription', async () => {
|
||||||
|
await stripePayments.cancelSubscription({
|
||||||
|
user,
|
||||||
|
groupId,
|
||||||
|
}, stripe);
|
||||||
|
|
||||||
|
expect(stripeDeleteCustomerStub).to.be.calledOnce;
|
||||||
|
expect(stripeDeleteCustomerStub).to.be.calledWith(group.purchased.plan.customerId);
|
||||||
|
expect(stripeRetrieveStub).to.be.calledOnce;
|
||||||
|
expect(stripeRetrieveStub).to.be.calledWith(user.purchased.plan.customerId);
|
||||||
|
expect(paymentsCancelSubStub).to.be.calledOnce;
|
||||||
|
expect(paymentsCancelSubStub).to.be.calledWith({
|
||||||
|
user,
|
||||||
|
groupId,
|
||||||
|
nextBill: currentPeriodEndTimeStamp * 1000, // timestamp in seconds
|
||||||
|
paymentMethod: 'Stripe',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -2,6 +2,7 @@ import {
|
|||||||
createTasks,
|
createTasks,
|
||||||
getTasks,
|
getTasks,
|
||||||
syncableAttrs,
|
syncableAttrs,
|
||||||
|
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 {
|
||||||
@@ -169,4 +170,12 @@ describe('taskManager', () => {
|
|||||||
expect(syncableTask.notes).to.not.exist;
|
expect(syncableTask.notes).to.not.exist;
|
||||||
expect(syncableTask.updatedAt).to.not.exist;
|
expect(syncableTask.updatedAt).to.not.exist;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('moves tasks to a specified position', async() => {
|
||||||
|
let order = ['task-id-1', 'task-id-2'];
|
||||||
|
|
||||||
|
moveTask(order, 'task-id-2', 0);
|
||||||
|
|
||||||
|
expect(order).to.eql(['task-id-2', 'task-id-1']);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -170,15 +170,19 @@ describe('Group Model', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
context('Boss Quests', () => {
|
context('Boss Quests', () => {
|
||||||
|
let sendChatStub;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
party.quest.key = 'whale';
|
party.quest.key = 'whale';
|
||||||
|
|
||||||
await party.startQuest(questLeader);
|
await party.startQuest(questLeader);
|
||||||
await party.save();
|
await party.save();
|
||||||
|
|
||||||
sandbox.stub(Group.prototype, 'sendChat');
|
sendChatStub = sandbox.stub(Group.prototype, 'sendChat');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterEach(() => sendChatStub.restore());
|
||||||
|
|
||||||
it('applies user\'s progress to quest boss hp', async () => {
|
it('applies user\'s progress to quest boss hp', async () => {
|
||||||
await Group.processQuestProgress(participatingMember, progress);
|
await Group.processQuestProgress(participatingMember, progress);
|
||||||
|
|
||||||
@@ -322,15 +326,19 @@ describe('Group Model', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
context('Collection Quests', () => {
|
context('Collection Quests', () => {
|
||||||
|
let sendChatStub;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
party.quest.key = 'atom1';
|
party.quest.key = 'atom1';
|
||||||
|
|
||||||
await party.startQuest(questLeader);
|
await party.startQuest(questLeader);
|
||||||
await party.save();
|
await party.save();
|
||||||
|
|
||||||
sandbox.stub(Group.prototype, 'sendChat');
|
sendChatStub = sandbox.stub(Group.prototype, 'sendChat');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterEach(() => sendChatStub.restore());
|
||||||
|
|
||||||
it('applies user\'s progress to found quest items', async () => {
|
it('applies user\'s progress to found quest items', async () => {
|
||||||
await Group.processQuestProgress(participatingMember, progress);
|
await Group.processQuestProgress(participatingMember, progress);
|
||||||
|
|
||||||
@@ -365,6 +373,7 @@ describe('Group Model', () => {
|
|||||||
party.quest.active = false;
|
party.quest.active = false;
|
||||||
|
|
||||||
await party.startQuest(questLeader);
|
await party.startQuest(questLeader);
|
||||||
|
Group.prototype.sendChat.reset();
|
||||||
await party.save();
|
await party.save();
|
||||||
|
|
||||||
await Group.processQuestProgress(participatingMember, progress);
|
await Group.processQuestProgress(participatingMember, progress);
|
||||||
@@ -383,6 +392,7 @@ describe('Group Model', () => {
|
|||||||
party.quest.active = false;
|
party.quest.active = false;
|
||||||
|
|
||||||
await party.startQuest(questLeader);
|
await party.startQuest(questLeader);
|
||||||
|
Group.prototype.sendChat.reset();
|
||||||
await party.save();
|
await party.save();
|
||||||
|
|
||||||
await Group.processQuestProgress(participatingMember, progress);
|
await Group.processQuestProgress(participatingMember, progress);
|
||||||
@@ -809,6 +819,20 @@ describe('Group Model', () => {
|
|||||||
expect(party.chat).to.have.a.lengthOf(200);
|
expect(party.chat).to.have.a.lengthOf(200);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('cuts down chat to 400 messages when group is subcribed', () => {
|
||||||
|
party.purchased.plan.customerId = 'test-customer-id';
|
||||||
|
|
||||||
|
for (let i = 0; i < 420; i++) {
|
||||||
|
party.chat.push({ text: 'a message' });
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(party.chat).to.have.a.lengthOf(420);
|
||||||
|
|
||||||
|
party.sendChat('message');
|
||||||
|
|
||||||
|
expect(party.chat).to.have.a.lengthOf(400);
|
||||||
|
});
|
||||||
|
|
||||||
it('updates users about new messages in party', () => {
|
it('updates users about new messages in party', () => {
|
||||||
party.sendChat('message');
|
party.sendChat('message');
|
||||||
|
|
||||||
@@ -1259,14 +1283,34 @@ describe('Group Model', () => {
|
|||||||
expect(updatedParticipatingMember.items.hatchingPotions.Shade).to.eql(2);
|
expect(updatedParticipatingMember.items.hatchingPotions.Shade).to.eql(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('awards quests', async () => {
|
it('awards quest scrolls to owner', async () => {
|
||||||
|
let questAwardQuest = questScrolls.vice2;
|
||||||
|
|
||||||
|
await party.finishQuest(questAwardQuest);
|
||||||
|
|
||||||
|
let updatedLeader = await User.findById(questLeader._id);
|
||||||
|
|
||||||
|
expect(updatedLeader.items.quests.vice3).to.eql(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('awards non quest leader rewards to quest leader', async () => {
|
||||||
|
let gearQuest = questScrolls.vice3;
|
||||||
|
|
||||||
|
await party.finishQuest(gearQuest);
|
||||||
|
|
||||||
|
let updatedLeader = await User.findById(questLeader._id);
|
||||||
|
|
||||||
|
expect(updatedLeader.items.gear.owned.weapon_special_2).to.eql(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('doesn\'t award quest owner rewards to all participants', async () => {
|
||||||
let questAwardQuest = questScrolls.vice2;
|
let questAwardQuest = questScrolls.vice2;
|
||||||
|
|
||||||
await party.finishQuest(questAwardQuest);
|
await party.finishQuest(questAwardQuest);
|
||||||
|
|
||||||
let updatedParticipatingMember = await User.findById(participatingMember._id);
|
let updatedParticipatingMember = await User.findById(participatingMember._id);
|
||||||
|
|
||||||
expect(updatedParticipatingMember.items.quests.vice3).to.eql(1);
|
expect(updatedParticipatingMember.items.quests.vice3).to.not.exist;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('awards pets', async () => {
|
it('awards pets', async () => {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
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 Bluebird from 'bluebird';
|
||||||
|
|
||||||
describe('User Model', () => {
|
describe('User Model', () => {
|
||||||
it('keeps user._tmp when calling .toJSON', () => {
|
it('keeps user._tmp when calling .toJSON', () => {
|
||||||
@@ -48,7 +49,7 @@ describe('User Model', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
context('notifications', () => {
|
context('notifications', () => {
|
||||||
it('can add notifications with data', () => {
|
it('can add notifications without data', () => {
|
||||||
let user = new User();
|
let user = new User();
|
||||||
|
|
||||||
user.addNotification('CRON');
|
user.addNotification('CRON');
|
||||||
@@ -60,7 +61,7 @@ describe('User Model', () => {
|
|||||||
expect(userToJSON.notifications[0].data).to.eql({});
|
expect(userToJSON.notifications[0].data).to.eql({});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can add notifications without data', () => {
|
it('can add notifications with data', () => {
|
||||||
let user = new User();
|
let user = new User();
|
||||||
|
|
||||||
user.addNotification('CRON', {field: 1});
|
user.addNotification('CRON', {field: 1});
|
||||||
@@ -71,5 +72,77 @@ describe('User Model', () => {
|
|||||||
expect(userToJSON.notifications[0].type).to.equal('CRON');
|
expect(userToJSON.notifications[0].type).to.equal('CRON');
|
||||||
expect(userToJSON.notifications[0].data).to.eql({field: 1});
|
expect(userToJSON.notifications[0].data).to.eql({field: 1});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
context('static push method', () => {
|
||||||
|
it('adds notifications for a single member via static method', async() => {
|
||||||
|
let user = new User();
|
||||||
|
await user.save();
|
||||||
|
|
||||||
|
await User.pushNotification({_id: user._id}, 'CRON');
|
||||||
|
|
||||||
|
user = await User.findOne({_id: user._id}).exec();
|
||||||
|
|
||||||
|
let userToJSON = user.toJSON();
|
||||||
|
expect(user.notifications.length).to.equal(1);
|
||||||
|
expect(userToJSON.notifications[0]).to.have.all.keys(['data', 'id', 'type']);
|
||||||
|
expect(userToJSON.notifications[0].type).to.equal('CRON');
|
||||||
|
expect(userToJSON.notifications[0].data).to.eql({});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('validates notifications via static method', async() => {
|
||||||
|
let user = new User();
|
||||||
|
await user.save();
|
||||||
|
|
||||||
|
expect(User.pushNotification({_id: user._id}, 'BAD_TYPE')).to.eventually.be.rejected;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('adds notifications without data for all given users via static method', async() => {
|
||||||
|
let user = new User();
|
||||||
|
let otherUser = new User();
|
||||||
|
await Bluebird.all([user.save(), otherUser.save()]);
|
||||||
|
|
||||||
|
await User.pushNotification({_id: {$in: [user._id, otherUser._id]}}, 'CRON');
|
||||||
|
|
||||||
|
user = await User.findOne({_id: user._id}).exec();
|
||||||
|
|
||||||
|
let userToJSON = user.toJSON();
|
||||||
|
expect(user.notifications.length).to.equal(1);
|
||||||
|
expect(userToJSON.notifications[0]).to.have.all.keys(['data', 'id', 'type']);
|
||||||
|
expect(userToJSON.notifications[0].type).to.equal('CRON');
|
||||||
|
expect(userToJSON.notifications[0].data).to.eql({});
|
||||||
|
|
||||||
|
user = await User.findOne({_id: otherUser._id}).exec();
|
||||||
|
|
||||||
|
userToJSON = user.toJSON();
|
||||||
|
expect(user.notifications.length).to.equal(1);
|
||||||
|
expect(userToJSON.notifications[0]).to.have.all.keys(['data', 'id', 'type']);
|
||||||
|
expect(userToJSON.notifications[0].type).to.equal('CRON');
|
||||||
|
expect(userToJSON.notifications[0].data).to.eql({});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('adds notifications with data for all given users via static method', async() => {
|
||||||
|
let user = new User();
|
||||||
|
let otherUser = new User();
|
||||||
|
await Bluebird.all([user.save(), otherUser.save()]);
|
||||||
|
|
||||||
|
await User.pushNotification({_id: {$in: [user._id, otherUser._id]}}, 'CRON', {field: 1});
|
||||||
|
|
||||||
|
user = await User.findOne({_id: user._id}).exec();
|
||||||
|
|
||||||
|
let userToJSON = user.toJSON();
|
||||||
|
expect(user.notifications.length).to.equal(1);
|
||||||
|
expect(userToJSON.notifications[0]).to.have.all.keys(['data', 'id', 'type']);
|
||||||
|
expect(userToJSON.notifications[0].type).to.equal('CRON');
|
||||||
|
expect(userToJSON.notifications[0].data).to.eql({field: 1});
|
||||||
|
|
||||||
|
user = await User.findOne({_id: otherUser._id}).exec();
|
||||||
|
|
||||||
|
userToJSON = user.toJSON();
|
||||||
|
expect(user.notifications.length).to.equal(1);
|
||||||
|
expect(userToJSON.notifications[0]).to.have.all.keys(['data', 'id', 'type']);
|
||||||
|
expect(userToJSON.notifications[0].type).to.equal('CRON');
|
||||||
|
expect(userToJSON.notifications[0].data).to.eql({field: 1});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -240,6 +240,5 @@ describe('Groups Controller', function() {
|
|||||||
describe.skip("clickMember", function() { });
|
describe.skip("clickMember", function() { });
|
||||||
describe.skip("removeMember", function() { });
|
describe.skip("removeMember", function() { });
|
||||||
describe.skip("confirmRemoveMember", function() { });
|
describe.skip("confirmRemoveMember", function() { });
|
||||||
describe.skip("openInviteModal", function() { });
|
|
||||||
describe.skip("quickReply", function() { });
|
describe.skip("quickReply", function() { });
|
||||||
});
|
});
|
||||||
|
|||||||
63
test/client-old/spec/controllers/groupTaskActionsCtrlSpec.js
Normal file
63
test/client-old/spec/controllers/groupTaskActionsCtrlSpec.js
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
describe('Group Tasks Meta Actions Controller', () => {
|
||||||
|
let rootScope, scope, user, userSerivce;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
module(function($provide) {
|
||||||
|
$provide.value('User', {});
|
||||||
|
});
|
||||||
|
|
||||||
|
inject(($rootScope, $controller) => {
|
||||||
|
rootScope = $rootScope;
|
||||||
|
|
||||||
|
user = specHelper.newUser();
|
||||||
|
user._id = "unique-user-id";
|
||||||
|
userSerivce = {user: user};
|
||||||
|
|
||||||
|
scope = $rootScope.$new();
|
||||||
|
|
||||||
|
scope.task = {
|
||||||
|
group: {
|
||||||
|
assignedUsers: [],
|
||||||
|
approval: {
|
||||||
|
required: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
scope.task._edit = angular.copy(scope.task);
|
||||||
|
|
||||||
|
$controller('GroupTaskActionsCtrl', {$scope: scope, User: userSerivce});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('toggleTaskRequiresApproval', function () {
|
||||||
|
it('toggles task approval required field from false to true', function () {
|
||||||
|
scope.toggleTaskRequiresApproval();
|
||||||
|
expect(scope.task._edit.group.approval.required).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('toggles task approval required field from true to false', function () {
|
||||||
|
scope.task._edit.group.approval.required = true;
|
||||||
|
scope.toggleTaskRequiresApproval();
|
||||||
|
expect(scope.task._edit.group.approval.required).to.be.false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('assign events', function () {
|
||||||
|
it('adds a group member to assigned users on "addedGroupMember" event ', () => {
|
||||||
|
var testId = 'test-id';
|
||||||
|
rootScope.$broadcast('addedGroupMember', testId);
|
||||||
|
expect(scope.task.group.assignedUsers).to.contain(testId);
|
||||||
|
expect(scope.task._edit.group.assignedUsers).to.contain(testId);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('removes a group member to assigned users on "addedGroupMember" event ', () => {
|
||||||
|
var testId = 'test-id';
|
||||||
|
scope.task.group.assignedUsers.push(testId);
|
||||||
|
scope.task._edit.group.assignedUsers.push(testId);
|
||||||
|
rootScope.$broadcast('removedGroupMember', testId);
|
||||||
|
expect(scope.task.group.assignedUsers).to.not.contain(testId);
|
||||||
|
expect(scope.task._edit.group.assignedUsers).to.not.contain(testId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
describe('Group Task Actions Controller', () => {
|
||||||
|
let scope, user, userSerivce;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
module(function($provide) {
|
||||||
|
$provide.value('User', {});
|
||||||
|
});
|
||||||
|
|
||||||
|
inject(($rootScope, $controller) => {
|
||||||
|
user = specHelper.newUser();
|
||||||
|
user._id = "unique-user-id";
|
||||||
|
userSerivce = {user: user};
|
||||||
|
userSerivce.sync = sandbox.stub();
|
||||||
|
|
||||||
|
scope = $rootScope.$new();
|
||||||
|
|
||||||
|
$controller('GroupTaskMetaActionsCtrl', {$scope: scope, User: userSerivce});
|
||||||
|
|
||||||
|
scope.task = {
|
||||||
|
group: {
|
||||||
|
assignedUsers: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('claim', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
sandbox.stub(window, 'confirm').returns(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('adds user to assigned users of scope task ', () => {
|
||||||
|
scope.claim();
|
||||||
|
expect(scope.task.group.assignedUsers).to.contain(user._id);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('syncs user tasks ', () => {
|
||||||
|
scope.claim();
|
||||||
|
expect(userSerivce.sync).to.be.calledOnce;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -44,6 +44,7 @@ module.exports = function karmaConfig (config) {
|
|||||||
'../../../website/client-old/js/filters/**/*.js',
|
'../../../website/client-old/js/filters/**/*.js',
|
||||||
'../../../website/client-old/js/directives/**/*.js',
|
'../../../website/client-old/js/directives/**/*.js',
|
||||||
'../../../website/client-old/js/controllers/**/*.js',
|
'../../../website/client-old/js/controllers/**/*.js',
|
||||||
|
'../../../website/client-old/js/components/**/*.js',
|
||||||
|
|
||||||
'../../../test/client-old/spec/specHelper.js',
|
'../../../test/client-old/spec/specHelper.js',
|
||||||
'../../../test/client-old/spec/**/*.js',
|
'../../../test/client-old/spec/**/*.js',
|
||||||
|
|||||||
@@ -194,6 +194,7 @@ describe('Analytics Service', function () {
|
|||||||
rewards: 1
|
rewards: 1
|
||||||
};
|
};
|
||||||
expectedProperties.balance = 12;
|
expectedProperties.balance = 12;
|
||||||
|
expectedProperties.balanceGemAmount = 48;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
user._id = 'unique-user-id';
|
user._id = 'unique-user-id';
|
||||||
@@ -243,7 +244,8 @@ describe('Analytics Service', function () {
|
|||||||
habits: 1,
|
habits: 1,
|
||||||
rewards: 1
|
rewards: 1
|
||||||
},
|
},
|
||||||
balance: 12
|
balance: 12,
|
||||||
|
balanceGemAmount: 48
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
describe('groupServices', function() {
|
describe('groupServices', function() {
|
||||||
var $httpBackend, $http, groups, user;
|
var $httpBackend, $http, groups, user, $rootScope;
|
||||||
var groupApiUrlPrefix = '/api/v3/groups';
|
var groupApiUrlPrefix = '/api/v3/groups';
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
@@ -13,8 +13,10 @@ describe('groupServices', function() {
|
|||||||
$provide.value('User', {user: user});
|
$provide.value('User', {user: user});
|
||||||
});
|
});
|
||||||
|
|
||||||
inject(function(_$httpBackend_, Groups, User) {
|
inject(function(_$httpBackend_, _$rootScope_, Groups, User) {
|
||||||
$httpBackend = _$httpBackend_;
|
$httpBackend = _$httpBackend_;
|
||||||
|
$rootScope = _$rootScope_;
|
||||||
|
$rootScope.openModal = function() {}
|
||||||
groups = Groups;
|
groups = Groups;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -166,4 +168,33 @@ describe('groupServices', function() {
|
|||||||
|
|
||||||
$httpBackend.flush()
|
$httpBackend.flush()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('sets a "sendInviteText" property on a party to "Send Invitations"', function() {
|
||||||
|
var sendInviteText = window.env.t('sendInvitations');
|
||||||
|
var party = {
|
||||||
|
type: 'party',
|
||||||
|
data: {
|
||||||
|
_id: '1234',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
groups.inviteOrStartParty(party);
|
||||||
|
expect(party.sendInviteText).to.eql(sendInviteText);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets a "sendInviteText" proptery on a guild to "Send Invitations +$3.00/month/user"', function() {
|
||||||
|
var sendInviteText = window.env.t('sendInvitations');
|
||||||
|
var guild = {
|
||||||
|
type: 'guild',
|
||||||
|
data: {
|
||||||
|
_id: '12345',
|
||||||
|
},
|
||||||
|
purchased: {
|
||||||
|
plan: {
|
||||||
|
customerId: '123',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
groups.inviteOrStartParty(guild);
|
||||||
|
expect(guild.sendInviteText).to.eql(sendInviteText + window.env.t('groupAdditionalUserCost'));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -17,7 +17,14 @@ describe('Tasks Service', function() {
|
|||||||
tasks = Tasks;
|
tasks = Tasks;
|
||||||
});
|
});
|
||||||
|
|
||||||
rootScope.openModal = function () {};
|
rootScope.openModal = function() {
|
||||||
|
return {
|
||||||
|
result: {
|
||||||
|
then: function() {},
|
||||||
|
catch: function() {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
it('calls get user tasks endpoint', function() {
|
it('calls get user tasks endpoint', function() {
|
||||||
@@ -83,6 +90,14 @@ describe('Tasks Service', function() {
|
|||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('calls group move task endpoint', function() {
|
||||||
|
var taskId = 1;
|
||||||
|
var position = 0;
|
||||||
|
$httpBackend.expectPOST('/api/v3/group-tasks/' + taskId + '/move/to/' + position).respond({});
|
||||||
|
tasks.moveGroupTask(taskId, position);
|
||||||
|
$httpBackend.flush();
|
||||||
|
});
|
||||||
|
|
||||||
it('calls add check list item endpoint', function() {
|
it('calls add check list item endpoint', function() {
|
||||||
var taskId = 1;
|
var taskId = 1;
|
||||||
$httpBackend.expectPOST(apiV3Prefix + '/' + taskId + '/checklist').respond({});
|
$httpBackend.expectPOST(apiV3Prefix + '/' + taskId + '/checklist').respond({});
|
||||||
|
|||||||
6
test/client/.eslintrc
Normal file
6
test/client/.eslintrc
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"env": {
|
||||||
|
"node": true,
|
||||||
|
"browser": true,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
// for how to write custom assertions see
|
// for how to write custom assertions see
|
||||||
// http://nightwatchjs.org/guide#writing-custom-assertions
|
// http://nightwatchjs.org/guide#writing-custom-assertions
|
||||||
exports.assertion = function (selector, count) {
|
exports.assertion = function (selector, count) {
|
||||||
this.message = 'Testing if element <' + selector + '> has count: ' + count;
|
this.message = `Testing if element <${selector}> has count: ${count}`;
|
||||||
this.expected = count;
|
this.expected = count;
|
||||||
this.pass = function (val) {
|
this.pass = function (val) {
|
||||||
return val === this.expected;
|
return val === this.expected;
|
||||||
@@ -16,11 +16,10 @@ exports.assertion = function (selector, count) {
|
|||||||
return res.value;
|
return res.value;
|
||||||
};
|
};
|
||||||
this.command = function (cb) {
|
this.command = function (cb) {
|
||||||
var self = this;
|
return this.api.execute((el) => {
|
||||||
return this.api.execute(function (selector) {
|
return document.querySelectorAll(el).length;
|
||||||
return document.querySelectorAll(selector).length;
|
}, [selector], (res) => {
|
||||||
}, [selector], function (res) {
|
cb.call(this, res);
|
||||||
cb.call(self, res);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,45 +1,48 @@
|
|||||||
|
/* eslint-disable camelcase */
|
||||||
|
|
||||||
require('babel-register');
|
require('babel-register');
|
||||||
var config = require('../../../webpack/config');
|
const config = require('../../../webpack/config');
|
||||||
|
const chromeDriverPath = require('chromedriver').path;
|
||||||
|
|
||||||
// http://nightwatchjs.org/guide#settings-file
|
// http://nightwatchjs.org/guide#settings-file
|
||||||
module.exports = {
|
module.exports = {
|
||||||
'src_folders': ['test/client/e2e/specs'],
|
src_folders: ['test/client/e2e/specs'],
|
||||||
'output_folder': 'test/client/e2e/reports',
|
output_folder: 'test/client/e2e/reports',
|
||||||
'custom_assertions_path': ['test/client/e2e/custom-assertions'],
|
custom_assertions_path: ['test/client/e2e/custom-assertions'],
|
||||||
|
|
||||||
'selenium': {
|
selenium: {
|
||||||
'start_process': true,
|
start_process: true,
|
||||||
'server_path': 'node_modules/selenium-server/lib/runner/selenium-server-standalone-2.53.0.jar',
|
server_path: 'node_modules/selenium-server/lib/runner/selenium-server-standalone-2.53.0.jar',
|
||||||
'host': '127.0.0.1',
|
host: '127.0.0.1',
|
||||||
'port': 4444,
|
port: 4444,
|
||||||
'cli_args': {
|
cli_args: {
|
||||||
'webdriver.chrome.driver': require('chromedriver').path,
|
'webdriver.chrome.driver': chromeDriverPath,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
'test_settings': {
|
test_settings: {
|
||||||
'default': {
|
default: {
|
||||||
'selenium_port': 4444,
|
selenium_port: 4444,
|
||||||
'selenium_host': 'localhost',
|
selenium_host: 'localhost',
|
||||||
'silent': true,
|
silent: true,
|
||||||
'globals': {
|
globals: {
|
||||||
'devServerURL': 'http://localhost:' + (process.env.PORT || config.dev.port),
|
devServerURL: `http://localhost:${process.env.PORT || config.dev.port}`, // eslint-disable-line no-process-env
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
'chrome': {
|
chrome: {
|
||||||
'desiredCapabilities': {
|
desiredCapabilities: {
|
||||||
'browserName': 'chrome',
|
browserName: 'chrome',
|
||||||
'javascriptEnabled': true,
|
javascriptEnabled: true,
|
||||||
'acceptSslCerts': true,
|
acceptSslCerts: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
'firefox': {
|
firefox: {
|
||||||
'desiredCapabilities': {
|
desiredCapabilities: {
|
||||||
'browserName': 'firefox',
|
browserName: 'firefox',
|
||||||
'javascriptEnabled': true,
|
javascriptEnabled: true,
|
||||||
'acceptSslCerts': true,
|
acceptSslCerts: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// 1. start the dev server using production config
|
// 1. start the dev server using production config
|
||||||
process.env.NODE_ENV = 'testing';
|
process.env.NODE_ENV = 'testing'; // eslint-disable-line no-process-env
|
||||||
var server = require('../../../webpack/dev-server.js');
|
const server = require('../../../webpack/dev-server.js');
|
||||||
|
|
||||||
// 2. run the nightwatch test suite against it
|
// 2. run the nightwatch test suite against it
|
||||||
// to run in additional browsers:
|
// to run in additional browsers:
|
||||||
@@ -9,7 +9,7 @@ var server = require('../../../webpack/dev-server.js');
|
|||||||
// or override the environment flag, for example: `npm run e2e -- --env chrome,firefox`
|
// or override the environment flag, for example: `npm run e2e -- --env chrome,firefox`
|
||||||
// For more information on Nightwatch's config file, see
|
// For more information on Nightwatch's config file, see
|
||||||
// http://nightwatchjs.org/guide#settings-file
|
// http://nightwatchjs.org/guide#settings-file
|
||||||
var opts = process.argv.slice(2);
|
let opts = process.argv.slice(2);
|
||||||
if (opts.indexOf('--config') === -1) {
|
if (opts.indexOf('--config') === -1) {
|
||||||
opts = opts.concat(['--config', 'test/client/e2e/nightwatch.conf.js']);
|
opts = opts.concat(['--config', 'test/client/e2e/nightwatch.conf.js']);
|
||||||
}
|
}
|
||||||
@@ -17,8 +17,8 @@ if (opts.indexOf('--env') === -1) {
|
|||||||
opts = opts.concat(['--env', 'chrome']);
|
opts = opts.concat(['--env', 'chrome']);
|
||||||
}
|
}
|
||||||
|
|
||||||
var spawn = require('cross-spawn');
|
const spawn = require('cross-spawn');
|
||||||
var runner = spawn('./node_modules/.bin/nightwatch', opts, { stdio: 'inherit' });
|
const runner = spawn('./node_modules/.bin/nightwatch', opts, { stdio: 'inherit' });
|
||||||
|
|
||||||
runner.on('exit', function (code) {
|
runner.on('exit', function (code) {
|
||||||
server.close();
|
server.close();
|
||||||
|
|||||||
@@ -2,12 +2,11 @@
|
|||||||
// http://nightwatchjs.org/guide#usage
|
// http://nightwatchjs.org/guide#usage
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
'default e2e tests': function (browser) {
|
'default e2e tests' (browser) {
|
||||||
|
|
||||||
// automatically uses dev Server port from /config.index.js
|
// automatically uses dev Server port from /config.index.js
|
||||||
// default: http://localhost:8080
|
// default: http://localhost:8080
|
||||||
// see nightwatch.conf.js
|
// see nightwatch.conf.js
|
||||||
var devServer = browser.globals.devServerURL;
|
const devServer = browser.globals.devServerURL;
|
||||||
|
|
||||||
browser
|
browser
|
||||||
.url(devServer)
|
.url(devServer)
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
// TODO verify if it's needed, added because Vuex require Promise in the global scope
|
// TODO verify if it's needed, added because Axios require Promise in the global scope
|
||||||
// and babel-runtime doesn't affect external libraries
|
// and babel-runtime doesn't affect external libraries
|
||||||
require('babel-polyfill');
|
require('babel-polyfill');
|
||||||
|
|
||||||
// require all test files (files that ends with .spec.js)
|
// require all test files (files that ends with .spec.js)
|
||||||
var testsContext = require.context('./specs', true, /\.spec$/);
|
let testsContext = require.context('./specs', true, /\.spec$/);
|
||||||
testsContext.keys().forEach(testsContext);
|
testsContext.keys().forEach(testsContext);
|
||||||
|
|
||||||
// require all .vue and .js files except main.js for coverage.
|
// require all .vue and .js files except main.js for coverage.
|
||||||
var srcContext = require.context('../../../website/client', true, /^\.\/(?=(?!main(\.js)?$))(?=(.*\.(vue|js)$))/);
|
let srcContext = require.context('../../../website/client', true, /^\.\/(?=(?!main(\.js)?$))(?=(.*\.(vue|js)$))/);
|
||||||
srcContext.keys().forEach(srcContext);
|
srcContext.keys().forEach(srcContext);
|
||||||
@@ -3,14 +3,15 @@
|
|||||||
// we are also using it with karma-webpack
|
// we are also using it with karma-webpack
|
||||||
// https://github.com/webpack/karma-webpack
|
// https://github.com/webpack/karma-webpack
|
||||||
|
|
||||||
var path = require('path');
|
const path = require('path');
|
||||||
var merge = require('webpack-merge');
|
const merge = require('webpack-merge');
|
||||||
var baseConfig = require('../../../webpack/webpack.base.conf');
|
const baseConfig = require('../../../webpack/webpack.base.conf');
|
||||||
var utils = require('../../../webpack/utils');
|
const utils = require('../../../webpack/utils');
|
||||||
var webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
var projectRoot = path.resolve(__dirname, '../../../');
|
const projectRoot = path.resolve(__dirname, '../../../');
|
||||||
|
const testEnv = require('../../../webpack/config/test.env');
|
||||||
|
|
||||||
var webpackConfig = merge(baseConfig, {
|
const webpackConfig = merge(baseConfig, {
|
||||||
// use inline sourcemap for karma-sourcemap-loader
|
// use inline sourcemap for karma-sourcemap-loader
|
||||||
module: {
|
module: {
|
||||||
loaders: utils.styleLoaders(),
|
loaders: utils.styleLoaders(),
|
||||||
@@ -23,7 +24,7 @@ var webpackConfig = merge(baseConfig, {
|
|||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
'process.env': require('../../../webpack/config/test.env'),
|
'process.env': testEnv,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
@@ -43,7 +44,7 @@ webpackConfig.module.preLoaders.unshift({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// only apply babel for test files when using isparta
|
// only apply babel for test files when using isparta
|
||||||
webpackConfig.module.loaders.some(function (loader, i) {
|
webpackConfig.module.loaders.some((loader) => {
|
||||||
if (loader.loader === 'babel') {
|
if (loader.loader === 'babel') {
|
||||||
loader.include = path.resolve(projectRoot, 'test/client/unit');
|
loader.include = path.resolve(projectRoot, 'test/client/unit');
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
19
test/client/unit/specs/plugins/i18n.spec.js
Normal file
19
test/client/unit/specs/plugins/i18n.spec.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import i18n from 'client/plugins/i18n';
|
||||||
|
import commoni18n from 'common/script/i18n';
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
describe('i18n plugin', () => {
|
||||||
|
before(() => {
|
||||||
|
i18n.install(Vue);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('adds $t to Vue.prototype', () => {
|
||||||
|
expect(Vue.prototype.$t).to.be.a.function;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('$t is a proxy for common/i18n.t', () => {
|
||||||
|
const result = (new Vue()).$t('reportBug');
|
||||||
|
expect(result).to.equal(commoni18n.t('reportBug'));
|
||||||
|
expect(result).to.equal('Report a Bug');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -11,7 +11,7 @@ describe('crit', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('computes', () => {
|
it('computes', () => {
|
||||||
let result = crit(user);
|
let result = crit.crit(user);
|
||||||
expect(result).to.eql(1);
|
expect(result).to.eql(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -147,6 +147,15 @@ describe('shared.ops.purchase', () => {
|
|||||||
expect(user.stats.gp).to.equal(goldPoints - planGemLimits.convRate);
|
expect(user.stats.gp).to.equal(goldPoints - planGemLimits.convRate);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('purchases gems with a different language than the default', () => {
|
||||||
|
let [, message] = purchase(user, {params: {type: 'gems', key: 'gem'}, language: 'de'});
|
||||||
|
|
||||||
|
expect(message).to.equal(i18n.t('plusOneGem', 'de'));
|
||||||
|
expect(user.balance).to.equal(userGemAmount + 0.5);
|
||||||
|
expect(user.purchased.plan.gemsBought).to.equal(2);
|
||||||
|
expect(user.stats.gp).to.equal(goldPoints - planGemLimits.convRate * 2);
|
||||||
|
});
|
||||||
|
|
||||||
it('purchases eggs', () => {
|
it('purchases eggs', () => {
|
||||||
let type = 'eggs';
|
let type = 'eggs';
|
||||||
let key = 'Wolf';
|
let key = 'Wolf';
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import scoreTask from '../../../website/common/script/ops/scoreTask';
|
import scoreTask from '../../../website/common/script/ops/scoreTask';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
generateUser,
|
generateUser,
|
||||||
generateDaily,
|
generateDaily,
|
||||||
@@ -11,6 +12,7 @@ import i18n from '../../../website/common/script/i18n';
|
|||||||
import {
|
import {
|
||||||
NotAuthorized,
|
NotAuthorized,
|
||||||
} from '../../../website/common/script/libs/errors';
|
} from '../../../website/common/script/libs/errors';
|
||||||
|
import crit from '../../../website/common/script/fns/crit';
|
||||||
|
|
||||||
let EPSILON = 0.0001; // negligible distance between datapoints
|
let EPSILON = 0.0001; // negligible distance between datapoints
|
||||||
|
|
||||||
@@ -142,6 +144,32 @@ describe('shared.ops.scoreTask', () => {
|
|||||||
expect(ref.beforeUser._id).to.eql(ref.afterUser._id);
|
expect(ref.beforeUser._id).to.eql(ref.afterUser._id);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('critical hits', () => {
|
||||||
|
let normalUser = ref.beforeUser;
|
||||||
|
expect(normalUser.party.quest.progress.up).to.eql(0);
|
||||||
|
normalUser.party.quest.key = 'gryphon';
|
||||||
|
let critUser = ref.afterUser;
|
||||||
|
expect(critUser.party.quest.progress.up).to.eql(0);
|
||||||
|
critUser.party.quest.key = 'gryphon';
|
||||||
|
let normalTask = todo;
|
||||||
|
let critTask = freshTodo;
|
||||||
|
|
||||||
|
scoreTask({ user: normalUser, task: normalTask, direction: 'up', cron: false });
|
||||||
|
let normalTaskDelta = normalUser.party.quest.progress.up;
|
||||||
|
|
||||||
|
sandbox.stub(crit, 'crit').returns(1.5);
|
||||||
|
scoreTask({ user: critUser, task: critTask, direction: 'up', cron: false });
|
||||||
|
let critTaskDelta = critUser.party.quest.progress.up;
|
||||||
|
crit.crit.restore();
|
||||||
|
|
||||||
|
expect(critUser.stats.hp).to.eql(normalUser.stats.hp);
|
||||||
|
expect(critUser.stats.gp).to.be.greaterThan(normalUser.stats.gp);
|
||||||
|
expect(critUser.stats.mp).to.be.greaterThan(normalUser.stats.mp);
|
||||||
|
expect(critUser.stats.exp).to.be.greaterThan(normalUser.stats.exp);
|
||||||
|
expect(critTask.value).to.eql(normalTask.value);
|
||||||
|
expect(critTaskDelta).to.be.greaterThan(normalTaskDelta);
|
||||||
|
});
|
||||||
|
|
||||||
it('and increments quest progress', () => {
|
it('and increments quest progress', () => {
|
||||||
expect(ref.afterUser.party.quest.progress.up).to.eql(0);
|
expect(ref.afterUser.party.quest.progress.up).to.eql(0);
|
||||||
ref.afterUser.party.quest.key = 'gryphon';
|
ref.afterUser.party.quest.key = 'gryphon';
|
||||||
|
|||||||
@@ -1,35 +1,37 @@
|
|||||||
|
/* global env:true, rm:true, mkdir:true, cp:true */
|
||||||
|
|
||||||
// https://github.com/shelljs/shelljs
|
// https://github.com/shelljs/shelljs
|
||||||
require('shelljs/global');
|
require('shelljs/global');
|
||||||
env.NODE_ENV = 'production';
|
env.NODE_ENV = 'production';
|
||||||
|
|
||||||
var path = require('path');
|
const path = require('path');
|
||||||
var config = require('./config');
|
const config = require('./config');
|
||||||
var ora = require('ora');
|
const ora = require('ora');
|
||||||
var webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
var webpackConfig = require('./webpack.prod.conf');
|
const webpackConfig = require('./webpack.prod.conf');
|
||||||
|
|
||||||
console.log(
|
console.log( // eslint-disable-line no-console
|
||||||
' Tip:\n' +
|
' Tip:\n' +
|
||||||
' Built files are meant to be served over an HTTP server.\n' +
|
' Built files are meant to be served over an HTTP server.\n' +
|
||||||
' Opening index.html over file:// won\'t work.\n'
|
' Opening index.html over file:// won\'t work.\n'
|
||||||
);
|
);
|
||||||
|
|
||||||
var spinner = ora('building for production...');
|
const spinner = ora('building for production...');
|
||||||
spinner.start();
|
spinner.start();
|
||||||
|
|
||||||
var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory);
|
const assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory);
|
||||||
rm('-rf', assetsPath);
|
rm('-rf', assetsPath);
|
||||||
mkdir('-p', assetsPath);
|
mkdir('-p', assetsPath);
|
||||||
cp('-R', config.build.staticAssetsDirectory, assetsPath);
|
cp('-R', config.build.staticAssetsDirectory, assetsPath);
|
||||||
|
|
||||||
webpack(webpackConfig, function (err, stats) {
|
webpack(webpackConfig, (err, stats) => {
|
||||||
spinner.stop();
|
spinner.stop();
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
process.stdout.write(stats.toString({
|
process.stdout.write(`${stats.toString({
|
||||||
colors: true,
|
colors: true,
|
||||||
modules: false,
|
modules: false,
|
||||||
children: false,
|
children: false,
|
||||||
chunks: false,
|
chunks: false,
|
||||||
chunkModules: false,
|
chunkModules: false,
|
||||||
}) + '\n');
|
})}\n`);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
var merge = require('webpack-merge');
|
const merge = require('webpack-merge');
|
||||||
var prodEnv = require('./prod.env');
|
const prodEnv = require('./prod.env');
|
||||||
|
|
||||||
module.exports = merge(prodEnv, {
|
module.exports = merge(prodEnv, {
|
||||||
NODE_ENV: '"development"',
|
NODE_ENV: '"development"',
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
// see http://vuejs-templates.github.io/webpack for documentation.
|
// see http://vuejs-templates.github.io/webpack for documentation.
|
||||||
var path = require('path');
|
const path = require('path');
|
||||||
|
const staticAssetsDirectory = './website/static/.'; // The folder where static files (not processed) live
|
||||||
|
const prodEnv = require('./prod.env');
|
||||||
|
const devEnv = require('./dev.env');
|
||||||
|
|
||||||
var staticAssetsDirectory = './website/static/.'; // The folder where static files (not processed) live
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
build: {
|
build: {
|
||||||
env: require('./prod.env'),
|
env: prodEnv,
|
||||||
index: path.resolve(__dirname, '../../dist-client/index.html'),
|
index: path.resolve(__dirname, '../../dist-client/index.html'),
|
||||||
assetsRoot: path.resolve(__dirname, '../../dist-client'),
|
assetsRoot: path.resolve(__dirname, '../../dist-client'),
|
||||||
assetsSubDirectory: 'static',
|
assetsSubDirectory: 'static',
|
||||||
assetsPublicPath: '/new-app',
|
assetsPublicPath: '/new-app',
|
||||||
staticAssetsDirectory: staticAssetsDirectory,
|
staticAssetsDirectory,
|
||||||
productionSourceMap: true,
|
productionSourceMap: true,
|
||||||
// Gzip off by default as many popular static hosts such as
|
// Gzip off by default as many popular static hosts such as
|
||||||
// Surge or Netlify already gzip all static assets for you.
|
// Surge or Netlify already gzip all static assets for you.
|
||||||
@@ -19,11 +21,11 @@ module.exports = {
|
|||||||
productionGzipExtensions: ['js', 'css'],
|
productionGzipExtensions: ['js', 'css'],
|
||||||
},
|
},
|
||||||
dev: {
|
dev: {
|
||||||
env: require('./dev.env'),
|
env: devEnv,
|
||||||
port: 8080,
|
port: 8080,
|
||||||
assetsSubDirectory: 'static',
|
assetsSubDirectory: 'static',
|
||||||
assetsPublicPath: '/',
|
assetsPublicPath: '/',
|
||||||
staticAssetsDirectory: staticAssetsDirectory,
|
staticAssetsDirectory,
|
||||||
proxyTable: {
|
proxyTable: {
|
||||||
// proxy all requests starting with /api/v3 to localhost:3000
|
// proxy all requests starting with /api/v3 to localhost:3000
|
||||||
'/api/v3': {
|
'/api/v3': {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
var merge = require('webpack-merge');
|
const merge = require('webpack-merge');
|
||||||
var devEnv = require('./dev.env');
|
const devEnv = require('./dev.env');
|
||||||
|
|
||||||
module.exports = merge(devEnv, {
|
module.exports = merge(devEnv, {
|
||||||
NODE_ENV: '"testing"',
|
NODE_ENV: '"testing"',
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
/* eslint-disable */
|
/* global window:true */
|
||||||
require('eventsource-polyfill')
|
|
||||||
var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true&overlay=false')
|
|
||||||
|
|
||||||
hotClient.subscribe(function (event) {
|
require('eventsource-polyfill');
|
||||||
|
const hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true&overlay=false');
|
||||||
|
|
||||||
|
hotClient.subscribe(event => {
|
||||||
if (event.action === 'reload') {
|
if (event.action === 'reload') {
|
||||||
window.location.reload()
|
window.location.reload();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|||||||
@@ -1,22 +1,24 @@
|
|||||||
var path = require('path');
|
/* eslint-disable no-process-env, no-console */
|
||||||
var express = require('express');
|
|
||||||
var webpack = require('webpack');
|
const path = require('path');
|
||||||
var config = require('./config');
|
const express = require('express');
|
||||||
var proxyMiddleware = require('http-proxy-middleware');
|
const webpack = require('webpack');
|
||||||
var webpackConfig = process.env.NODE_ENV === 'testing'
|
const config = require('./config');
|
||||||
? require('./webpack.prod.conf')
|
const proxyMiddleware = require('http-proxy-middleware');
|
||||||
: require('./webpack.dev.conf');
|
const webpackConfig = process.env.NODE_ENV === 'testing' ?
|
||||||
|
require('./webpack.prod.conf') :
|
||||||
|
require('./webpack.dev.conf');
|
||||||
|
|
||||||
// default port where dev server listens for incoming traffic
|
// default port where dev server listens for incoming traffic
|
||||||
var port = process.env.PORT || config.dev.port;
|
const port = process.env.PORT || config.dev.port;
|
||||||
// Define HTTP proxies to your custom API backend
|
// Define HTTP proxies to your custom API backend
|
||||||
// https://github.com/chimurai/http-proxy-middleware
|
// https://github.com/chimurai/http-proxy-middleware
|
||||||
var proxyTable = config.dev.proxyTable;
|
const proxyTable = config.dev.proxyTable;
|
||||||
|
|
||||||
var app = express();
|
const app = express();
|
||||||
var compiler = webpack(webpackConfig);
|
const compiler = webpack(webpackConfig);
|
||||||
|
|
||||||
var devMiddleware = require('webpack-dev-middleware')(compiler, {
|
const devMiddleware = require('webpack-dev-middleware')(compiler, {
|
||||||
publicPath: webpackConfig.output.publicPath,
|
publicPath: webpackConfig.output.publicPath,
|
||||||
stats: {
|
stats: {
|
||||||
colors: true,
|
colors: true,
|
||||||
@@ -24,18 +26,18 @@ var devMiddleware = require('webpack-dev-middleware')(compiler, {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
var hotMiddleware = require('webpack-hot-middleware')(compiler);
|
const hotMiddleware = require('webpack-hot-middleware')(compiler);
|
||||||
// force page reload when html-webpack-plugin template changes
|
// force page reload when html-webpack-plugin template changes
|
||||||
compiler.plugin('compilation', function (compilation) {
|
compiler.plugin('compilation', (compilation) => {
|
||||||
compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
|
compilation.plugin('html-webpack-plugin-after-emit', (data, cb) => {
|
||||||
hotMiddleware.publish({ action: 'reload' });
|
hotMiddleware.publish({ action: 'reload' });
|
||||||
cb();
|
cb();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// proxy api requests
|
// proxy api requests
|
||||||
Object.keys(proxyTable).forEach(function (context) {
|
Object.keys(proxyTable).forEach((context) => {
|
||||||
var options = proxyTable[context];
|
let options = proxyTable[context];
|
||||||
if (typeof options === 'string') {
|
if (typeof options === 'string') {
|
||||||
options = { target: options };
|
options = { target: options };
|
||||||
}
|
}
|
||||||
@@ -53,13 +55,13 @@ app.use(devMiddleware);
|
|||||||
app.use(hotMiddleware);
|
app.use(hotMiddleware);
|
||||||
|
|
||||||
// serve pure static assets
|
// serve pure static assets
|
||||||
var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory);
|
const staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory);
|
||||||
app.use(staticPath, express.static(config.dev.staticAssetsDirectory));
|
app.use(staticPath, express.static(config.dev.staticAssetsDirectory));
|
||||||
|
|
||||||
module.exports = app.listen(port, function (err) {
|
module.exports = app.listen(port, (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log('Listening at http://localhost:' + port + '\n');
|
console.log(`Listening at http://localhost:${port}\n`);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,28 +1,30 @@
|
|||||||
var path = require('path');
|
/* eslint-disable no-process-env, no-console */
|
||||||
var config = require('./config');
|
|
||||||
var ExtractTextPlugin = require('extract-text-webpack-plugin');
|
|
||||||
|
|
||||||
exports.assetsPath = function (_path) {
|
const path = require('path');
|
||||||
var assetsSubDirectory = process.env.NODE_ENV === 'production'
|
const config = require('./config');
|
||||||
? config.build.assetsSubDirectory
|
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||||
: config.dev.assetsSubDirectory;
|
|
||||||
|
exports.assetsPath = (_path) => {
|
||||||
|
const assetsSubDirectory = process.env.NODE_ENV === 'production' ?
|
||||||
|
config.build.assetsSubDirectory :
|
||||||
|
config.dev.assetsSubDirectory;
|
||||||
return path.posix.join(assetsSubDirectory, _path);
|
return path.posix.join(assetsSubDirectory, _path);
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.cssLoaders = function (options) {
|
exports.cssLoaders = (options) => {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
// generate loader string to be used with extract text plugin
|
// generate loader string to be used with extract text plugin
|
||||||
function generateLoaders (loaders) {
|
function generateLoaders (loaders) {
|
||||||
var sourceLoader = loaders.map(function (loader) {
|
let sourceLoader = loaders.map((loader) => {
|
||||||
var extraParamChar;
|
let extraParamChar;
|
||||||
if (/\?/.test(loader)) {
|
if (/\?/.test(loader)) {
|
||||||
loader = loader.replace(/\?/, '-loader?');
|
loader = loader.replace(/\?/, '-loader?');
|
||||||
extraParamChar = '&';
|
extraParamChar = '&';
|
||||||
} else {
|
} else {
|
||||||
loader = loader + '-loader';
|
loader = `${loader}-loader`;
|
||||||
extraParamChar = '?';
|
extraParamChar = '?';
|
||||||
}
|
}
|
||||||
return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '');
|
return `${loader}${(options.sourceMap ? extraParamChar + 'sourceMap' : '')}`; // eslint-disable-line prefer-template
|
||||||
}).join('!');
|
}).join('!');
|
||||||
|
|
||||||
if (options.extract) {
|
if (options.extract) {
|
||||||
@@ -45,14 +47,14 @@ exports.cssLoaders = function (options) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Generate loaders for standalone style files (outside of .vue)
|
// Generate loaders for standalone style files (outside of .vue)
|
||||||
exports.styleLoaders = function (options) {
|
exports.styleLoaders = (options) => {
|
||||||
var output = [];
|
const output = [];
|
||||||
var loaders = exports.cssLoaders(options);
|
const loaders = exports.cssLoaders(options);
|
||||||
for (var extension in loaders) {
|
for (let extension in loaders) {
|
||||||
var loader = loaders[extension];
|
const loader = loaders[extension];
|
||||||
output.push({
|
output.push({
|
||||||
test: new RegExp('\\.' + extension + '$'),
|
test: new RegExp(`\\.${extension}$`),
|
||||||
loader: loader,
|
loader,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
var path = require('path');
|
/* eslint-disable no-process-env, no-console */
|
||||||
var config = require('./config');
|
|
||||||
var utils = require('./utils');
|
|
||||||
var projectRoot = path.resolve(__dirname, '../');
|
|
||||||
var webpack = require('webpack');
|
|
||||||
|
|
||||||
var IS_PROD = process.env.NODE_ENV === 'production';
|
const path = require('path');
|
||||||
var baseConfig = {
|
const config = require('./config');
|
||||||
|
const utils = require('./utils');
|
||||||
|
const projectRoot = path.resolve(__dirname, '../');
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const autoprefixer = require('autoprefixer');
|
||||||
|
const postcssEasyImport = require('postcss-easy-import');
|
||||||
|
const IS_PROD = process.env.NODE_ENV === 'production';
|
||||||
|
|
||||||
|
const baseConfig = {
|
||||||
entry: {
|
entry: {
|
||||||
app: './website/client/main.js',
|
app: './website/client/main.js',
|
||||||
},
|
},
|
||||||
@@ -19,6 +23,8 @@ var baseConfig = {
|
|||||||
fallback: [path.join(__dirname, '../node_modules')],
|
fallback: [path.join(__dirname, '../node_modules')],
|
||||||
alias: {
|
alias: {
|
||||||
jquery: 'jquery/src/jquery',
|
jquery: 'jquery/src/jquery',
|
||||||
|
website: path.resolve(__dirname, '../website'),
|
||||||
|
common: path.resolve(__dirname, '../website/common'),
|
||||||
client: path.resolve(__dirname, '../website/client'),
|
client: path.resolve(__dirname, '../website/client'),
|
||||||
assets: path.resolve(__dirname, '../website/client/assets'),
|
assets: path.resolve(__dirname, '../website/client/assets'),
|
||||||
components: path.resolve(__dirname, '../website/client/components'),
|
components: path.resolve(__dirname, '../website/client/components'),
|
||||||
@@ -84,10 +90,10 @@ var baseConfig = {
|
|||||||
vue: {
|
vue: {
|
||||||
loaders: utils.cssLoaders(),
|
loaders: utils.cssLoaders(),
|
||||||
postcss: [
|
postcss: [
|
||||||
require('autoprefixer')({
|
autoprefixer({
|
||||||
browsers: ['last 2 versions'],
|
browsers: ['last 2 versions'],
|
||||||
}),
|
}),
|
||||||
require('postcss-easy-import')({
|
postcssEasyImport({
|
||||||
glob: true,
|
glob: true,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
@@ -95,8 +101,10 @@ var baseConfig = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (!IS_PROD) {
|
if (!IS_PROD) {
|
||||||
|
const eslintFriendlyFormatter = require('eslint-friendly-formatter'); // eslint-disable-line global-require
|
||||||
|
|
||||||
baseConfig.eslint = {
|
baseConfig.eslint = {
|
||||||
formatter: require('eslint-friendly-formatter'),
|
formatter: eslintFriendlyFormatter,
|
||||||
emitWarning: true,
|
emitWarning: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
var config = require('./config');
|
const config = require('./config');
|
||||||
var webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
var merge = require('webpack-merge');
|
const merge = require('webpack-merge');
|
||||||
var utils = require('./utils');
|
const utils = require('./utils');
|
||||||
var baseWebpackConfig = require('./webpack.base.conf');
|
const baseWebpackConfig = require('./webpack.base.conf');
|
||||||
var HtmlWebpackPlugin = require('html-webpack-plugin');
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
|
||||||
// add hot-reload related code to entry chunks
|
// add hot-reload related code to entry chunks
|
||||||
Object.keys(baseWebpackConfig.entry).forEach(function (name) {
|
Object.keys(baseWebpackConfig.entry).forEach((name) => {
|
||||||
baseWebpackConfig.entry[name] = ['./webpack/dev-client'].concat(baseWebpackConfig.entry[name]);
|
baseWebpackConfig.entry[name] = ['./webpack/dev-client'].concat(baseWebpackConfig.entry[name]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
var path = require('path');
|
/* eslint-disable no-process-env, no-console */
|
||||||
var config = require('./config');
|
|
||||||
var utils = require('./utils');
|
|
||||||
var webpack = require('webpack');
|
|
||||||
var merge = require('webpack-merge');
|
|
||||||
var baseWebpackConfig = require('./webpack.base.conf');
|
|
||||||
var ExtractTextPlugin = require('extract-text-webpack-plugin');
|
|
||||||
var HtmlWebpackPlugin = require('html-webpack-plugin');
|
|
||||||
var env = process.env.NODE_ENV === 'testing'
|
|
||||||
? require('./config/test.env')
|
|
||||||
: config.build.env;
|
|
||||||
|
|
||||||
var webpackConfig = merge(baseWebpackConfig, {
|
const path = require('path');
|
||||||
|
const config = require('./config');
|
||||||
|
const utils = require('./utils');
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const merge = require('webpack-merge');
|
||||||
|
const baseWebpackConfig = require('./webpack.base.conf');
|
||||||
|
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
const env = process.env.NODE_ENV === 'testing' ?
|
||||||
|
require('./config/test.env') :
|
||||||
|
config.build.env;
|
||||||
|
|
||||||
|
const webpackConfig = merge(baseWebpackConfig, {
|
||||||
module: {
|
module: {
|
||||||
loaders: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true }),
|
loaders: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true }),
|
||||||
},
|
},
|
||||||
@@ -43,9 +45,9 @@ var webpackConfig = merge(baseWebpackConfig, {
|
|||||||
// you can customize output by editing /index.html
|
// you can customize output by editing /index.html
|
||||||
// see https://github.com/ampedandwired/html-webpack-plugin
|
// see https://github.com/ampedandwired/html-webpack-plugin
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
filename: process.env.NODE_ENV === 'testing'
|
filename: process.env.NODE_ENV === 'testing' ?
|
||||||
? 'index.html'
|
'index.html' :
|
||||||
: config.build.index,
|
config.build.index,
|
||||||
template: './website/client/index.html',
|
template: './website/client/index.html',
|
||||||
inject: true,
|
inject: true,
|
||||||
minify: {
|
minify: {
|
||||||
@@ -61,12 +63,12 @@ var webpackConfig = merge(baseWebpackConfig, {
|
|||||||
// split vendor js into its own file
|
// split vendor js into its own file
|
||||||
new webpack.optimize.CommonsChunkPlugin({
|
new webpack.optimize.CommonsChunkPlugin({
|
||||||
name: 'vendor',
|
name: 'vendor',
|
||||||
minChunks: function (module, count) {
|
minChunks (scriptModule) {
|
||||||
// any required modules inside node_modules are extracted to vendor
|
// any required modules inside node_modules are extracted to vendor
|
||||||
return (
|
return (
|
||||||
module.resource &&
|
scriptModule.resource &&
|
||||||
/\.js$/.test(module.resource) &&
|
/\.js$/.test(scriptModule.resource) &&
|
||||||
module.resource.indexOf(
|
scriptModule.resource.indexOf(
|
||||||
path.join(__dirname, '../node_modules')
|
path.join(__dirname, '../node_modules')
|
||||||
) === 0
|
) === 0
|
||||||
);
|
);
|
||||||
@@ -82,17 +84,13 @@ var webpackConfig = merge(baseWebpackConfig, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (config.build.productionGzip) {
|
if (config.build.productionGzip) {
|
||||||
var CompressionWebpackPlugin = require('compression-webpack-plugin');
|
const CompressionWebpackPlugin = require('compression-webpack-plugin'); // eslint-disable-line global-require
|
||||||
|
|
||||||
webpackConfig.plugins.push(
|
webpackConfig.plugins.push(
|
||||||
new CompressionWebpackPlugin({
|
new CompressionWebpackPlugin({
|
||||||
asset: '[path].gz[query]',
|
asset: '[path].gz[query]',
|
||||||
algorithm: 'gzip',
|
algorithm: 'gzip',
|
||||||
test: new RegExp(
|
test: new RegExp(`\\.(${config.build.productionGzipExtensions.join('|')})$`),
|
||||||
'\\.(' +
|
|
||||||
config.build.productionGzipExtensions.join('|') +
|
|
||||||
')$'
|
|
||||||
),
|
|
||||||
threshold: 10240,
|
threshold: 10240,
|
||||||
minRatio: 0.8,
|
minRatio: 0.8,
|
||||||
})
|
})
|
||||||
|
|||||||
BIN
website/assets/img/project_files/npcs/nye/npc_alex.png
Normal file
BIN
website/assets/img/project_files/npcs/nye/npc_alex.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
BIN
website/assets/img/project_files/npcs/nye/npc_bailey.png
Normal file
BIN
website/assets/img/project_files/npcs/nye/npc_bailey.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
BIN
website/assets/img/project_files/npcs/nye/npc_daniel.png
Normal file
BIN
website/assets/img/project_files/npcs/nye/npc_daniel.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.3 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user