mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-16 14:17:22 +01:00
Merge branch 'develop' into api-v3
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
/*global module:false*/
|
||||
require('babel-core/register');
|
||||
var _ = require('lodash');
|
||||
module.exports = function(grunt) {
|
||||
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
'use strict';
|
||||
let t = require('./translation.js');
|
||||
|
||||
var t = require('./translation.js');
|
||||
let NUMBER_OF_QUESTIONS = 12;
|
||||
|
||||
var NUMBER_OF_QUESTIONS = 12;
|
||||
|
||||
var faq = {};
|
||||
let faq = {};
|
||||
|
||||
faq.questions = [];
|
||||
|
||||
for (var i = 0; i <= NUMBER_OF_QUESTIONS; i++) {
|
||||
var question = {
|
||||
question: t('faqQuestion' + i),
|
||||
ios: t('iosFaqAnswer' + i),
|
||||
web: t('webFaqAnswer' + i)
|
||||
for (let i = 0; i <= NUMBER_OF_QUESTIONS; i++) {
|
||||
let question = {
|
||||
question: t(`faqQuestion${i}`),
|
||||
ios: t(`iosFaqAnswer${i}`),
|
||||
web: t(`webFaqAnswer${i}`),
|
||||
};
|
||||
|
||||
faq.questions.push(question);
|
||||
@@ -20,7 +18,7 @@ for (var i = 0; i <= NUMBER_OF_QUESTIONS; i++) {
|
||||
|
||||
faq.stillNeedHelp = {
|
||||
ios: t('iosFaqStillNeedHelp'),
|
||||
web: t('webFaqStillNeedHelp')
|
||||
web: t('webFaqStillNeedHelp'),
|
||||
};
|
||||
|
||||
module.exports = faq;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,20 +1,11 @@
|
||||
'use strict';
|
||||
import i18n from '../i18n';
|
||||
|
||||
var i18n = require('../i18n');
|
||||
|
||||
var t = function(string, vars) {
|
||||
var func = function(lang) {
|
||||
if (vars == null) {
|
||||
vars = {
|
||||
a: 'a'
|
||||
};
|
||||
}
|
||||
export default function translator (string, vars = { a: 'a' }) {
|
||||
function func (lang) {
|
||||
return i18n.t(string, vars, lang);
|
||||
};
|
||||
}
|
||||
|
||||
func.i18nLangFunc = true; // Trick to recognize this type of function
|
||||
|
||||
return func;
|
||||
};
|
||||
|
||||
module.exports = t;
|
||||
}
|
||||
|
||||
@@ -1,71 +1,71 @@
|
||||
'use strict';
|
||||
import _ from 'lodash';
|
||||
import content from './content/index';
|
||||
|
||||
var _ = require('lodash');
|
||||
var content = require('./content/index');
|
||||
const DROP_ANIMALS = _.keys(content.pets);
|
||||
|
||||
var DROP_ANIMALS = _.keys(content.pets);
|
||||
function beastMasterProgress (pets) {
|
||||
let count = 0;
|
||||
|
||||
function beastMasterProgress(pets) {
|
||||
var count = 0;
|
||||
_(DROP_ANIMALS).each(function(animal) {
|
||||
if(pets[animal] > 0 || pets[animal] == -1)
|
||||
count++
|
||||
}).value();
|
||||
_(DROP_ANIMALS).each((animal) => {
|
||||
if (pets[animal] > 0 || pets[animal] === -1)
|
||||
count++;
|
||||
});
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
function dropPetsCurrentlyOwned(pets) {
|
||||
var count = 0;
|
||||
function dropPetsCurrentlyOwned (pets) {
|
||||
let count = 0;
|
||||
|
||||
_(DROP_ANIMALS).each(function(animal) {
|
||||
if(pets[animal] > 0)
|
||||
count++
|
||||
}).value();
|
||||
_(DROP_ANIMALS).each((animal) => {
|
||||
if (pets[animal] > 0)
|
||||
count++;
|
||||
});
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
function mountMasterProgress(mounts) {
|
||||
var count = 0;
|
||||
_(DROP_ANIMALS).each(function(animal) {
|
||||
function mountMasterProgress (mounts) {
|
||||
let count = 0;
|
||||
|
||||
_(DROP_ANIMALS).each((animal) => {
|
||||
if (mounts[animal])
|
||||
count++
|
||||
}).value();
|
||||
count++;
|
||||
});
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
function remainingGearInSet(userGear, set) {
|
||||
var gear = _.filter(content.gear.flat, function(item) {
|
||||
var setMatches = item.klass === set;
|
||||
var hasItem = userGear[item.key];
|
||||
function remainingGearInSet (userGear, set) {
|
||||
let gear = _.filter(content.gear.flat, (item) => {
|
||||
let setMatches = item.klass === set;
|
||||
let hasItem = userGear[item.key];
|
||||
|
||||
return setMatches && !hasItem;
|
||||
});
|
||||
|
||||
var count = _.size(gear);
|
||||
let count = _.size(gear);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
function questsOfCategory(userQuests, category) {
|
||||
var quests = _.filter(content.quests, function(quest) {
|
||||
var categoryMatches = quest.category === category;
|
||||
var hasQuest = userQuests[quest.key];
|
||||
function questsOfCategory (userQuests, category) {
|
||||
let quests = _.filter(content.quests, (quest) => {
|
||||
let categoryMatches = quest.category === category;
|
||||
let hasQuest = userQuests[quest.key];
|
||||
|
||||
return categoryMatches && hasQuest;
|
||||
});
|
||||
|
||||
var count = _.size(quests);
|
||||
let count = _.size(quests);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
beastMasterProgress: beastMasterProgress,
|
||||
dropPetsCurrentlyOwned: dropPetsCurrentlyOwned,
|
||||
mountMasterProgress: mountMasterProgress,
|
||||
remainingGearInSet: remainingGearInSet,
|
||||
questsOfCategory: questsOfCategory
|
||||
export default {
|
||||
beastMasterProgress,
|
||||
dropPetsCurrentlyOwned,
|
||||
mountMasterProgress,
|
||||
remainingGearInSet,
|
||||
questsOfCategory,
|
||||
};
|
||||
|
||||
@@ -1,51 +1,63 @@
|
||||
var _;
|
||||
import _ from 'lodash';
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
module.exports = {
|
||||
let i18n = {
|
||||
strings: null,
|
||||
translations: {},
|
||||
t: function(stringName) {
|
||||
var clonedVars, e, error, error1, locale, string, stringNotFound, vars;
|
||||
vars = arguments[1];
|
||||
if (_.isString(arguments[1])) {
|
||||
vars = null;
|
||||
locale = arguments[1];
|
||||
} else if (arguments[2] != null) {
|
||||
vars = arguments[1];
|
||||
locale = arguments[2];
|
||||
t, // eslint-disable-line no-use-before-define
|
||||
};
|
||||
|
||||
function t (stringName) {
|
||||
let vars = arguments[1];
|
||||
let locale;
|
||||
|
||||
if (_.isString(arguments[1])) {
|
||||
vars = null;
|
||||
locale = arguments[1];
|
||||
} else if (arguments[2]) {
|
||||
locale = arguments[2];
|
||||
}
|
||||
|
||||
let i18nNotSetup = !i18n.strings && !i18n.translations[locale];
|
||||
|
||||
if (!locale || i18nNotSetup) {
|
||||
locale = 'en';
|
||||
}
|
||||
|
||||
let string;
|
||||
|
||||
if (i18n.strings) {
|
||||
string = i18n.strings[stringName];
|
||||
} else {
|
||||
string = i18n.translations[locale] && i18n.translations[locale][stringName];
|
||||
}
|
||||
|
||||
let clonedVars = _.clone(vars) || {};
|
||||
|
||||
clonedVars.locale = locale;
|
||||
|
||||
if (string) {
|
||||
try {
|
||||
return _.template(string, clonedVars);
|
||||
} catch (_error) {
|
||||
return 'Error processing the string. Please see Help > Report a Bug.';
|
||||
}
|
||||
if ((locale == null) || (!module.exports.strings && !module.exports.translations[locale])) {
|
||||
locale = 'en';
|
||||
} else {
|
||||
let stringNotFound;
|
||||
|
||||
if (i18n.strings) {
|
||||
stringNotFound = i18n.strings.stringNotFound;
|
||||
} else if (i18n.translations[locale]) {
|
||||
stringNotFound = i18n.translations[locale] && i18n.translations[locale].stringNotFound;
|
||||
}
|
||||
if (module.exports.strings) {
|
||||
string = module.exports.strings[stringName];
|
||||
} else {
|
||||
string = module.exports.translations[locale] && module.exports.translations[locale][stringName];
|
||||
}
|
||||
clonedVars = _.clone(vars) || {};
|
||||
clonedVars.locale = locale;
|
||||
if (string) {
|
||||
try {
|
||||
return _.template(string)(clonedVars);
|
||||
} catch (error) {
|
||||
e = error;
|
||||
return 'Error processing the string. Please see Help > Report a Bug.';
|
||||
}
|
||||
} else {
|
||||
if (module.exports.strings) {
|
||||
stringNotFound = module.exports.strings.stringNotFound;
|
||||
} else if (module.exports.translations[locale]) {
|
||||
stringNotFound = module.exports.translations[locale] && module.exports.translations[locale].stringNotFound;
|
||||
}
|
||||
try {
|
||||
return _.template(stringNotFound)({
|
||||
string: stringName
|
||||
});
|
||||
} catch (error1) {
|
||||
e = error1;
|
||||
return 'Error processing the string. Please see Help > Report a Bug.';
|
||||
}
|
||||
|
||||
try {
|
||||
return _.template(stringNotFound, {
|
||||
string: stringName,
|
||||
});
|
||||
} catch (_error) {
|
||||
return 'Error processing the string. Please see Help > Report a Bug.';
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default i18n;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* directory, and it will automatically be included.
|
||||
*/
|
||||
|
||||
require('babel/register');
|
||||
require('babel-core/register');
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
require('./tasks/gulp-newstuff');
|
||||
|
||||
@@ -6,16 +6,15 @@
|
||||
"dependencies": {
|
||||
"accepts": "^1.3.0",
|
||||
"amazon-payments": "0.0.4",
|
||||
"amplitude": "^2.0.1",
|
||||
"amplitude": "^2.0.3",
|
||||
"async": "^1.5.0",
|
||||
"aws-sdk": "^2.0.25",
|
||||
"babel": "^5.5.4",
|
||||
"babelify": "^7.2.0",
|
||||
"babel-core": "^5.8.34",
|
||||
"babelify": "^6.x.x",
|
||||
"body-parser": "^1.14.1",
|
||||
"compression": "^1.6.0",
|
||||
"bower": "~1.3.12",
|
||||
"browserify": "~12.0.1",
|
||||
"coffee-script": "1.6.x",
|
||||
"connect-ratelimit": "0.0.7",
|
||||
"cookie-parser": "^1.4.0",
|
||||
"cookie-session": "^1.2.0",
|
||||
|
||||
@@ -10,7 +10,7 @@ gulp.task('browserify', function () {
|
||||
let bundler = browserify({
|
||||
entries: './common/index.js',
|
||||
debug: true,
|
||||
transform: [[babel, { compact: false }]]
|
||||
transform: [[babel, { compact: false }]],
|
||||
});
|
||||
|
||||
return bundler.bundle()
|
||||
|
||||
@@ -18,4 +18,19 @@ gulp.task('lint:server', () => {
|
||||
.pipe(eslint.failAfterError());
|
||||
});
|
||||
|
||||
gulp.task('lint', ['lint:server']);
|
||||
gulp.task('lint:common', () => {
|
||||
return gulp
|
||||
.src([
|
||||
'./common/script/**/*.js',
|
||||
// @TODO remove these negations as the files are converted over.
|
||||
'!./common/script/index.js',
|
||||
'!./common/script/content/index.js',
|
||||
'!./common/script/src/**/*.js',
|
||||
'!./common/script/public/**/*.js',
|
||||
])
|
||||
.pipe(eslint())
|
||||
.pipe(eslint.format())
|
||||
.pipe(eslint.failAfterError());
|
||||
});
|
||||
|
||||
gulp.task('lint', ['lint:server', 'lint:common']);
|
||||
|
||||
@@ -18,11 +18,11 @@ let server;
|
||||
|
||||
const TEST_DB_URI = `mongodb://localhost/${TEST_DB}`
|
||||
|
||||
const API_V2_TEST_COMMAND = 'mocha test/api/v2 --recursive --compilers js:babel/register';
|
||||
const API_V3_TEST_COMMAND = 'mocha test/api/v3 --recursive --compilers js:babel/register';
|
||||
const API_V2_TEST_COMMAND = 'mocha test/api/v2 --recursive';
|
||||
const API_V3_TEST_COMMAND = 'mocha test/api/v3 --recursive';
|
||||
const LEGACY_API_TEST_COMMAND = 'mocha test/api-legacy';
|
||||
const COMMON_TEST_COMMAND = 'mocha test/common --compilers coffee:coffee-script';
|
||||
const CONTENT_TEST_COMMAND = 'mocha test/content --compilers js:babel/register';
|
||||
const COMMON_TEST_COMMAND = 'mocha test/common';
|
||||
const CONTENT_TEST_COMMAND = 'mocha test/content';
|
||||
const CONTENT_OPTIONS = {maxBuffer: 1024 * 500};
|
||||
const KARMA_TEST_COMMAND = 'karma start';
|
||||
const SERVER_SIDE_TEST_COMMAND = 'mocha test/server_side';
|
||||
|
||||
@@ -1,346 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
app = require("../../website/src/server")
|
||||
Group = require("../../website/src/models/group").model
|
||||
Challenge = require("../../website/src/models/challenge").model
|
||||
|
||||
describe "Challenges", ->
|
||||
|
||||
challenge = undefined
|
||||
updateTodo = undefined
|
||||
group = undefined
|
||||
|
||||
beforeEach (done) ->
|
||||
async.waterfall [
|
||||
(cb) ->
|
||||
registerNewUser(cb, true)
|
||||
, (user, cb) ->
|
||||
request.post(baseURL + "/groups").send(
|
||||
name: "TestGroup"
|
||||
type: "party"
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
group = res.body
|
||||
expect(group.members.length).to.equal 1
|
||||
expect(group.leader).to.equal user._id
|
||||
cb()
|
||||
, (cb) ->
|
||||
request.post(baseURL + "/challenges").send(
|
||||
group: group._id
|
||||
dailys: [
|
||||
type: "daily"
|
||||
text: "Challenge Daily"
|
||||
]
|
||||
todos: [{
|
||||
type: "todo"
|
||||
text: "Challenge Todo 1"
|
||||
notes: "Challenge Notes"
|
||||
}]
|
||||
rewards: []
|
||||
habits: []
|
||||
).end (err, res) ->
|
||||
challenge = res.body
|
||||
done()
|
||||
]
|
||||
|
||||
describe 'POST /challenge', ->
|
||||
|
||||
it "Creates a challenge", (done) ->
|
||||
request.post(baseURL + "/challenges").send(
|
||||
group: group._id
|
||||
dailys: [
|
||||
type: "daily"
|
||||
text: "Challenge Daily"
|
||||
]
|
||||
todos: [{
|
||||
type: "todo"
|
||||
text: "Challenge Todo 1"
|
||||
notes: "Challenge Notes"
|
||||
}, {
|
||||
type: "todo"
|
||||
text: "Challenge Todo 2"
|
||||
notes: "Challenge Notes"
|
||||
}]
|
||||
rewards: []
|
||||
habits: []
|
||||
official: true
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
async.parallel [
|
||||
(cb) ->
|
||||
User.findById user._id, cb
|
||||
(cb) ->
|
||||
Challenge.findById res.body._id, cb
|
||||
], (err, results) ->
|
||||
user = results[0]
|
||||
challenge = results[1]
|
||||
expect(user.dailys[user.dailys.length - 1].text).to.equal "Challenge Daily"
|
||||
expect(challenge.official).to.equal false
|
||||
done()
|
||||
|
||||
describe 'POST /challenge/:cid', ->
|
||||
it "updates the notes on user's version of a challenge task's note without updating the challenge", (done) ->
|
||||
updateTodo = challenge.todos[0]
|
||||
updateTodo.notes = "User overriden notes"
|
||||
async.waterfall [
|
||||
(cb) ->
|
||||
request.put(baseURL + "/user/tasks/" + updateTodo.id).send(updateTodo).end (err, res) ->
|
||||
cb()
|
||||
, (cb) ->
|
||||
Challenge.findById challenge._id, cb
|
||||
, (chal, cb) ->
|
||||
expect(chal.todos[0].notes).to.eql("Challenge Notes")
|
||||
cb()
|
||||
, (cb) ->
|
||||
request.get(baseURL + "/user/tasks/" + updateTodo.id)
|
||||
.end (err, res) ->
|
||||
expect(res.body.notes).to.eql("User overriden notes")
|
||||
done()
|
||||
]
|
||||
|
||||
it "changes user's copy of challenge tasks when the challenge is updated", (done) ->
|
||||
challenge.dailys[0].text = "Updated Daily"
|
||||
request.post(baseURL + "/challenges/" + challenge._id)
|
||||
.send(challenge)
|
||||
.end (err, res) ->
|
||||
challenge = res.body
|
||||
expect(challenge.dailys[0].text).to.equal "Updated Daily"
|
||||
User.findById user._id, (err, _user) ->
|
||||
expectCode res, 200
|
||||
expect(_user.dailys[_user.dailys.length - 1].text).to.equal "Updated Daily"
|
||||
done()
|
||||
|
||||
it "does not changes user's notes on tasks when challenge task notes are updated", (done) ->
|
||||
challenge.todos[0].notes = "Challenge Updated Todo Notes"
|
||||
request.post(baseURL + "/challenges/" + challenge._id)
|
||||
.send(challenge)
|
||||
.end (err, res) ->
|
||||
challenge = res.body
|
||||
expect(challenge.todos[0].notes).to.equal "Challenge Updated Todo Notes"
|
||||
User.findById user._id, (err, _user) ->
|
||||
expectCode res, 200
|
||||
expect(_user.todos[_user.todos.length - 1].notes).to.equal "Challenge Notes"
|
||||
done()
|
||||
|
||||
|
||||
it "shows user notes on challenge page", (done) ->
|
||||
updateTodo = challenge.todos[0]
|
||||
updateTodo.notes = "User overriden notes"
|
||||
async.waterfall [
|
||||
(cb) ->
|
||||
request.put(baseURL + "/user/tasks/" + updateTodo.id).send(updateTodo).end (err, res) ->
|
||||
cb()
|
||||
, (cb) ->
|
||||
Challenge.findById challenge._id, cb
|
||||
, (chal, cb) ->
|
||||
expect(chal.todos[0].notes).to.eql("Challenge Notes")
|
||||
cb()
|
||||
, (cb) ->
|
||||
request.get(baseURL + "/challenges/" + challenge._id + "/member/" + user._id).end (err, res) ->
|
||||
expect(res.body.todos[res.body.todos.length - 1].notes).to.equal "User overriden notes"
|
||||
done()
|
||||
]
|
||||
|
||||
it "Complete To-Dos", (done) ->
|
||||
User.findById user._id, (err, _user) ->
|
||||
u = _user
|
||||
numTasks = (_.size(u.todos))
|
||||
request.post(baseURL + "/user/tasks/" + u.todos[0].id + "/up").end (err, res) ->
|
||||
request.post(baseURL + "/user/tasks/clear-completed").end (err, res) ->
|
||||
expect(_.size(res.body)).to.equal numTasks - 1
|
||||
done()
|
||||
|
||||
it "Challenge deleted, breaks task link", (done) ->
|
||||
itThis = this
|
||||
request.del(baseURL + "/challenges/" + challenge._id).end (err, res) ->
|
||||
User.findById user._id, (err, user) ->
|
||||
len = user.dailys.length - 1
|
||||
daily = user.dailys[user.dailys.length - 1]
|
||||
expect(daily.challenge.broken).to.equal "CHALLENGE_DELETED"
|
||||
|
||||
# Now let's handle if challenge was deleted, but didn't get to update all the users (an error)
|
||||
unset = $unset: {}
|
||||
unset["$unset"]["dailys." + len + ".challenge.broken"] = 1
|
||||
User.findByIdAndUpdate user._id, unset, {new: true}, (err, user) ->
|
||||
expect(err).to.not.exist
|
||||
expect(user.dailys[len].challenge.broken).to.not.exist
|
||||
request.post(baseURL + "/user/tasks/" + daily.id + "/up").end (err, res) ->
|
||||
setTimeout (->
|
||||
User.findById user._id, (err, user) ->
|
||||
expect(user.dailys[len].challenge.broken).to.equal "CHALLENGE_DELETED"
|
||||
done()
|
||||
), 100 # we need to wait for challenge to update user, it's a background job for perf reasons
|
||||
|
||||
it "admin creates a challenge", (done) ->
|
||||
User.findByIdAndUpdate user._id,
|
||||
$set:
|
||||
"contributor.admin": true
|
||||
, {new: true}
|
||||
, (err, _user) ->
|
||||
expect(err).to.not.exist
|
||||
async.parallel [
|
||||
(cb) ->
|
||||
request.post(baseURL + "/challenges").send(
|
||||
group: group._id
|
||||
dailys: []
|
||||
todos: []
|
||||
rewards: []
|
||||
habits: []
|
||||
official: false
|
||||
).end (err, res) ->
|
||||
expect(res.body.official).to.equal false
|
||||
cb()
|
||||
(cb) ->
|
||||
request.post(baseURL + "/challenges").send(
|
||||
group: group._id
|
||||
dailys: []
|
||||
todos: []
|
||||
rewards: []
|
||||
habits: []
|
||||
official: true
|
||||
).end (err, res) ->
|
||||
expect(res.body.official).to.equal true
|
||||
cb()
|
||||
], done
|
||||
|
||||
it "User creates a non-tavern challenge with prize, deletes it, gets refund", (done) ->
|
||||
User.findByIdAndUpdate user._id,
|
||||
$set:
|
||||
"balance": 8,
|
||||
, {new: true}
|
||||
, (err, user) ->
|
||||
expect(err).to.not.be.ok
|
||||
request.post(baseURL + "/challenges").send(
|
||||
group: group._id
|
||||
dailys: []
|
||||
todos: []
|
||||
rewards: []
|
||||
habits: []
|
||||
prize: 10
|
||||
).end (err, res) ->
|
||||
expect(res.body.prize).to.equal 10
|
||||
async.parallel [
|
||||
(cb) ->
|
||||
User.findById user._id, cb
|
||||
(cb) ->
|
||||
Challenge.findById res.body._id, cb
|
||||
], (err, results) ->
|
||||
user = results[0]
|
||||
challenge = results[1]
|
||||
expect(user.balance).to.equal 5.5
|
||||
request.del(baseURL + "/challenges/" + challenge._id).end (err, res) ->
|
||||
User.findById user._id, (err, _user) ->
|
||||
expect(_user.balance).to.equal 8
|
||||
done()
|
||||
|
||||
it "User creates a tavern challenge with prize, deletes it, and does not get refund", (done) ->
|
||||
User.findByIdAndUpdate user._id,
|
||||
$set:
|
||||
"balance": 8,
|
||||
, {new: true}
|
||||
, (err, user) ->
|
||||
expect(err).to.not.be.ok
|
||||
request.post(baseURL + "/challenges").send(
|
||||
group: 'habitrpg'
|
||||
dailys: []
|
||||
todos: []
|
||||
rewards: []
|
||||
habits: []
|
||||
prize: 10
|
||||
).end (err, res) ->
|
||||
expect(res.body.prize).to.equal 10
|
||||
async.parallel [
|
||||
(cb) ->
|
||||
User.findById user._id, cb
|
||||
(cb) ->
|
||||
Challenge.findById res.body._id, cb
|
||||
], (err, results) ->
|
||||
user = results[0]
|
||||
challenge = results[1]
|
||||
expect(user.balance).to.equal 5.5
|
||||
request.del(baseURL + "/challenges/" + challenge._id).end (err, res) ->
|
||||
User.findById user._id, (err, _user) ->
|
||||
expect(_user.balance).to.equal 5.5
|
||||
done()
|
||||
|
||||
describe "non-owner permissions", () ->
|
||||
challenge = undefined
|
||||
|
||||
beforeEach (done) ->
|
||||
async.waterfall [
|
||||
(cb) ->
|
||||
request.post(baseURL + "/challenges").send(
|
||||
group: group._id
|
||||
name: 'challenge name'
|
||||
dailys: [
|
||||
type: "daily"
|
||||
text: "Challenge Daily"
|
||||
]
|
||||
).end (err, res) ->
|
||||
challenge = res.body
|
||||
cb()
|
||||
|
||||
(cb) ->
|
||||
registerNewUser(done, true)
|
||||
]
|
||||
|
||||
context "non-owner", () ->
|
||||
|
||||
it 'can not edit challenge', (done) ->
|
||||
challenge.name = 'foobar'
|
||||
request.post(baseURL + "/challenges/" + challenge._id)
|
||||
.send(challenge)
|
||||
.end (err, res) ->
|
||||
error = res.body.err
|
||||
|
||||
expect(error).to.eql("You don't have permissions to edit this challenge")
|
||||
done()
|
||||
|
||||
it 'can not close challenge', (done) ->
|
||||
request.post(baseURL + "/challenges/" + challenge._id + "/close?uid=" + user._id)
|
||||
.end (err, res) ->
|
||||
error = res.body.err
|
||||
|
||||
expect(error).to.eql("You don't have permissions to close this challenge")
|
||||
done()
|
||||
|
||||
it 'can not delete challenge', (done) ->
|
||||
request.del(baseURL + "/challenges/" + challenge._id)
|
||||
.end (err, res) ->
|
||||
error = res.body.err
|
||||
|
||||
expect(error).to.eql("You don't have permissions to delete this challenge")
|
||||
done()
|
||||
|
||||
context "non-owner that is an admin", () ->
|
||||
|
||||
beforeEach (done) ->
|
||||
User.findByIdAndUpdate(user._id, { 'contributor.admin': true }, {new: true}, done)
|
||||
|
||||
it 'can edit challenge', (done) ->
|
||||
challenge.name = 'foobar'
|
||||
request.post(baseURL + "/challenges/" + challenge._id)
|
||||
.send(challenge)
|
||||
.end (err, res) ->
|
||||
expect(res.body.err).to.not.exist
|
||||
Challenge.findById challenge._id, (err, chal) ->
|
||||
expect(chal.name).to.eql('foobar')
|
||||
done()
|
||||
|
||||
it 'can close challenge', (done) ->
|
||||
request.post(baseURL + "/challenges/" + challenge._id + "/close?uid=" + user._id)
|
||||
.end (err, res) ->
|
||||
expect(res.body.err).to.not.exist
|
||||
User.findById user._id, (err, usr) ->
|
||||
expect(usr.achievements.challenges[0]).to.eql(challenge.name)
|
||||
done()
|
||||
|
||||
it 'can delete challenge', (done) ->
|
||||
request.del(baseURL + "/challenges/" + challenge._id)
|
||||
.end (err, res) ->
|
||||
expect(res.body.err).to.not.exist
|
||||
request.get(baseURL + "/challenges/" + challenge._id)
|
||||
.end (err, res) ->
|
||||
error = res.body.err
|
||||
expect(error).to.eql("Challenge #{challenge._id} not found")
|
||||
done()
|
||||
412
test/api-legacy/challenges.js
Normal file
412
test/api-legacy/challenges.js
Normal file
@@ -0,0 +1,412 @@
|
||||
var Challenge, Group, app;
|
||||
|
||||
app = require("../../website/src/server");
|
||||
|
||||
Group = require("../../website/src/models/group").model;
|
||||
|
||||
Challenge = require("../../website/src/models/challenge").model;
|
||||
|
||||
describe("Challenges", function() {
|
||||
var challenge, group, updateTodo;
|
||||
challenge = void 0;
|
||||
updateTodo = void 0;
|
||||
group = void 0;
|
||||
beforeEach(function(done) {
|
||||
return async.waterfall([
|
||||
function(cb) {
|
||||
return registerNewUser(cb, true);
|
||||
}, function(user, cb) {
|
||||
return request.post(baseURL + "/groups").send({
|
||||
name: "TestGroup",
|
||||
type: "party"
|
||||
}).end(function(err, res) {
|
||||
expectCode(res, 200);
|
||||
group = res.body;
|
||||
expect(group.members.length).to.equal(1);
|
||||
expect(group.leader).to.equal(user._id);
|
||||
return cb();
|
||||
});
|
||||
}, function(cb) {
|
||||
return request.post(baseURL + "/challenges").send({
|
||||
group: group._id,
|
||||
dailys: [
|
||||
{
|
||||
type: "daily",
|
||||
text: "Challenge Daily"
|
||||
}
|
||||
],
|
||||
todos: [
|
||||
{
|
||||
type: "todo",
|
||||
text: "Challenge Todo 1",
|
||||
notes: "Challenge Notes"
|
||||
}
|
||||
],
|
||||
rewards: [],
|
||||
habits: []
|
||||
}).end(function(err, res) {
|
||||
challenge = res.body;
|
||||
return done();
|
||||
});
|
||||
}
|
||||
]);
|
||||
});
|
||||
describe('POST /challenge', function() {
|
||||
return it("Creates a challenge", function(done) {
|
||||
return request.post(baseURL + "/challenges").send({
|
||||
group: group._id,
|
||||
dailys: [
|
||||
{
|
||||
type: "daily",
|
||||
text: "Challenge Daily"
|
||||
}
|
||||
],
|
||||
todos: [
|
||||
{
|
||||
type: "todo",
|
||||
text: "Challenge Todo 1",
|
||||
notes: "Challenge Notes"
|
||||
}, {
|
||||
type: "todo",
|
||||
text: "Challenge Todo 2",
|
||||
notes: "Challenge Notes"
|
||||
}
|
||||
],
|
||||
rewards: [],
|
||||
habits: [],
|
||||
official: true
|
||||
}).end(function(err, res) {
|
||||
expectCode(res, 200);
|
||||
return async.parallel([
|
||||
function(cb) {
|
||||
return User.findById(user._id, cb);
|
||||
}, function(cb) {
|
||||
return Challenge.findById(res.body._id, cb);
|
||||
}
|
||||
], function(err, results) {
|
||||
var user;
|
||||
user = results[0];
|
||||
challenge = results[1];
|
||||
expect(user.dailys[user.dailys.length - 1].text).to.equal("Challenge Daily");
|
||||
expect(challenge.official).to.equal(false);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('POST /challenge/:cid', function() {
|
||||
it("updates the notes on user's version of a challenge task's note without updating the challenge", function(done) {
|
||||
updateTodo = challenge.todos[0];
|
||||
updateTodo.notes = "User overriden notes";
|
||||
return async.waterfall([
|
||||
function(cb) {
|
||||
return request.put(baseURL + "/user/tasks/" + updateTodo.id).send(updateTodo).end(function(err, res) {
|
||||
return cb();
|
||||
});
|
||||
}, function(cb) {
|
||||
return Challenge.findById(challenge._id, cb);
|
||||
}, function(chal, cb) {
|
||||
expect(chal.todos[0].notes).to.eql("Challenge Notes");
|
||||
return cb();
|
||||
}, function(cb) {
|
||||
return request.get(baseURL + "/user/tasks/" + updateTodo.id).end(function(err, res) {
|
||||
expect(res.body.notes).to.eql("User overriden notes");
|
||||
return done();
|
||||
});
|
||||
}
|
||||
]);
|
||||
});
|
||||
it("changes user's copy of challenge tasks when the challenge is updated", function(done) {
|
||||
challenge.dailys[0].text = "Updated Daily";
|
||||
return request.post(baseURL + "/challenges/" + challenge._id).send(challenge).end(function(err, res) {
|
||||
challenge = res.body;
|
||||
expect(challenge.dailys[0].text).to.equal("Updated Daily");
|
||||
return User.findById(user._id, function(err, _user) {
|
||||
expectCode(res, 200);
|
||||
expect(_user.dailys[_user.dailys.length - 1].text).to.equal("Updated Daily");
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
it("does not changes user's notes on tasks when challenge task notes are updated", function(done) {
|
||||
challenge.todos[0].notes = "Challenge Updated Todo Notes";
|
||||
return request.post(baseURL + "/challenges/" + challenge._id).send(challenge).end(function(err, res) {
|
||||
challenge = res.body;
|
||||
expect(challenge.todos[0].notes).to.equal("Challenge Updated Todo Notes");
|
||||
return User.findById(user._id, function(err, _user) {
|
||||
expectCode(res, 200);
|
||||
expect(_user.todos[_user.todos.length - 1].notes).to.equal("Challenge Notes");
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
return it("shows user notes on challenge page", function(done) {
|
||||
updateTodo = challenge.todos[0];
|
||||
updateTodo.notes = "User overriden notes";
|
||||
return async.waterfall([
|
||||
function(cb) {
|
||||
return request.put(baseURL + "/user/tasks/" + updateTodo.id).send(updateTodo).end(function(err, res) {
|
||||
return cb();
|
||||
});
|
||||
}, function(cb) {
|
||||
return Challenge.findById(challenge._id, cb);
|
||||
}, function(chal, cb) {
|
||||
expect(chal.todos[0].notes).to.eql("Challenge Notes");
|
||||
return cb();
|
||||
}, function(cb) {
|
||||
return request.get(baseURL + "/challenges/" + challenge._id + "/member/" + user._id).end(function(err, res) {
|
||||
expect(res.body.todos[res.body.todos.length - 1].notes).to.equal("User overriden notes");
|
||||
return done();
|
||||
});
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
it("Complete To-Dos", function(done) {
|
||||
return User.findById(user._id, function(err, _user) {
|
||||
var numTasks, u;
|
||||
u = _user;
|
||||
numTasks = _.size(u.todos);
|
||||
return request.post(baseURL + "/user/tasks/" + u.todos[0].id + "/up").end(function(err, res) {
|
||||
return request.post(baseURL + "/user/tasks/clear-completed").end(function(err, res) {
|
||||
expect(_.size(res.body)).to.equal(numTasks - 1);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
it("Challenge deleted, breaks task link", function(done) {
|
||||
var itThis;
|
||||
itThis = this;
|
||||
return request.del(baseURL + "/challenges/" + challenge._id).end(function(err, res) {
|
||||
return User.findById(user._id, function(err, user) {
|
||||
var daily, len, unset;
|
||||
len = user.dailys.length - 1;
|
||||
daily = user.dailys[user.dailys.length - 1];
|
||||
expect(daily.challenge.broken).to.equal("CHALLENGE_DELETED");
|
||||
unset = {
|
||||
$unset: {}
|
||||
};
|
||||
unset["$unset"]["dailys." + len + ".challenge.broken"] = 1;
|
||||
return User.findByIdAndUpdate(user._id, unset, {
|
||||
"new": true
|
||||
}, function(err, user) {
|
||||
expect(err).to.not.exist;
|
||||
expect(user.dailys[len].challenge.broken).to.not.exist;
|
||||
return request.post(baseURL + "/user/tasks/" + daily.id + "/up").end(function(err, res) {
|
||||
return setTimeout((function() {
|
||||
return User.findById(user._id, function(err, user) {
|
||||
expect(user.dailys[len].challenge.broken).to.equal("CHALLENGE_DELETED");
|
||||
return done();
|
||||
});
|
||||
}), 100);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
it("admin creates a challenge", function(done) {
|
||||
return User.findByIdAndUpdate(user._id, {
|
||||
$set: {
|
||||
"contributor.admin": true
|
||||
}
|
||||
}, {
|
||||
"new": true
|
||||
}, function(err, _user) {
|
||||
expect(err).to.not.exist;
|
||||
return async.parallel([
|
||||
function(cb) {
|
||||
return request.post(baseURL + "/challenges").send({
|
||||
group: group._id,
|
||||
dailys: [],
|
||||
todos: [],
|
||||
rewards: [],
|
||||
habits: [],
|
||||
official: false
|
||||
}).end(function(err, res) {
|
||||
expect(res.body.official).to.equal(false);
|
||||
return cb();
|
||||
});
|
||||
}, function(cb) {
|
||||
return request.post(baseURL + "/challenges").send({
|
||||
group: group._id,
|
||||
dailys: [],
|
||||
todos: [],
|
||||
rewards: [],
|
||||
habits: [],
|
||||
official: true
|
||||
}).end(function(err, res) {
|
||||
expect(res.body.official).to.equal(true);
|
||||
return cb();
|
||||
});
|
||||
}
|
||||
], done);
|
||||
});
|
||||
});
|
||||
it("User creates a non-tavern challenge with prize, deletes it, gets refund", function(done) {
|
||||
return User.findByIdAndUpdate(user._id, {
|
||||
$set: {
|
||||
"balance": 8
|
||||
}
|
||||
}, {
|
||||
"new": true
|
||||
}, function(err, user) {
|
||||
expect(err).to.not.be.ok;
|
||||
return request.post(baseURL + "/challenges").send({
|
||||
group: group._id,
|
||||
dailys: [],
|
||||
todos: [],
|
||||
rewards: [],
|
||||
habits: [],
|
||||
prize: 10
|
||||
}).end(function(err, res) {
|
||||
expect(res.body.prize).to.equal(10);
|
||||
return async.parallel([
|
||||
function(cb) {
|
||||
return User.findById(user._id, cb);
|
||||
}, function(cb) {
|
||||
return Challenge.findById(res.body._id, cb);
|
||||
}
|
||||
], function(err, results) {
|
||||
user = results[0];
|
||||
challenge = results[1];
|
||||
expect(user.balance).to.equal(5.5);
|
||||
return request.del(baseURL + "/challenges/" + challenge._id).end(function(err, res) {
|
||||
return User.findById(user._id, function(err, _user) {
|
||||
expect(_user.balance).to.equal(8);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
it("User creates a tavern challenge with prize, deletes it, and does not get refund", function(done) {
|
||||
return User.findByIdAndUpdate(user._id, {
|
||||
$set: {
|
||||
"balance": 8
|
||||
}
|
||||
}, {
|
||||
"new": true
|
||||
}, function(err, user) {
|
||||
expect(err).to.not.be.ok;
|
||||
return request.post(baseURL + "/challenges").send({
|
||||
group: 'habitrpg',
|
||||
dailys: [],
|
||||
todos: [],
|
||||
rewards: [],
|
||||
habits: [],
|
||||
prize: 10
|
||||
}).end(function(err, res) {
|
||||
expect(res.body.prize).to.equal(10);
|
||||
return async.parallel([
|
||||
function(cb) {
|
||||
return User.findById(user._id, cb);
|
||||
}, function(cb) {
|
||||
return Challenge.findById(res.body._id, cb);
|
||||
}
|
||||
], function(err, results) {
|
||||
user = results[0];
|
||||
challenge = results[1];
|
||||
expect(user.balance).to.equal(5.5);
|
||||
return request.del(baseURL + "/challenges/" + challenge._id).end(function(err, res) {
|
||||
return User.findById(user._id, function(err, _user) {
|
||||
expect(_user.balance).to.equal(5.5);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
return describe("non-owner permissions", function() {
|
||||
challenge = void 0;
|
||||
beforeEach(function(done) {
|
||||
return async.waterfall([
|
||||
function(cb) {
|
||||
return request.post(baseURL + "/challenges").send({
|
||||
group: group._id,
|
||||
name: 'challenge name',
|
||||
dailys: [
|
||||
{
|
||||
type: "daily",
|
||||
text: "Challenge Daily"
|
||||
}
|
||||
]
|
||||
}).end(function(err, res) {
|
||||
challenge = res.body;
|
||||
return cb();
|
||||
});
|
||||
}, function(cb) {
|
||||
return registerNewUser(done, true);
|
||||
}
|
||||
]);
|
||||
});
|
||||
context("non-owner", function() {
|
||||
it('can not edit challenge', function(done) {
|
||||
challenge.name = 'foobar';
|
||||
return request.post(baseURL + "/challenges/" + challenge._id).send(challenge).end(function(err, res) {
|
||||
var error;
|
||||
error = res.body.err;
|
||||
expect(error).to.eql("You don't have permissions to edit this challenge");
|
||||
return done();
|
||||
});
|
||||
});
|
||||
it('can not close challenge', function(done) {
|
||||
return request.post(baseURL + "/challenges/" + challenge._id + "/close?uid=" + user._id).end(function(err, res) {
|
||||
var error;
|
||||
error = res.body.err;
|
||||
expect(error).to.eql("You don't have permissions to close this challenge");
|
||||
return done();
|
||||
});
|
||||
});
|
||||
return it('can not delete challenge', function(done) {
|
||||
return request.del(baseURL + "/challenges/" + challenge._id).end(function(err, res) {
|
||||
var error;
|
||||
error = res.body.err;
|
||||
expect(error).to.eql("You don't have permissions to delete this challenge");
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
return context("non-owner that is an admin", function() {
|
||||
beforeEach(function(done) {
|
||||
return User.findByIdAndUpdate(user._id, {
|
||||
'contributor.admin': true
|
||||
}, {
|
||||
"new": true
|
||||
}, done);
|
||||
});
|
||||
it('can edit challenge', function(done) {
|
||||
challenge.name = 'foobar';
|
||||
return request.post(baseURL + "/challenges/" + challenge._id).send(challenge).end(function(err, res) {
|
||||
expect(res.body.err).to.not.exist;
|
||||
return Challenge.findById(challenge._id, function(err, chal) {
|
||||
expect(chal.name).to.eql('foobar');
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
it('can close challenge', function(done) {
|
||||
return request.post(baseURL + "/challenges/" + challenge._id + "/close?uid=" + user._id).end(function(err, res) {
|
||||
expect(res.body.err).to.not.exist;
|
||||
return User.findById(user._id, function(err, usr) {
|
||||
expect(usr.achievements.challenges[0]).to.eql(challenge.name);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
return it('can delete challenge', function(done) {
|
||||
return request.del(baseURL + "/challenges/" + challenge._id).end(function(err, res) {
|
||||
expect(res.body.err).to.not.exist;
|
||||
return request.get(baseURL + "/challenges/" + challenge._id).end(function(err, res) {
|
||||
var error;
|
||||
error = res.body.err;
|
||||
expect(error).to.eql("Challenge " + challenge._id + " not found");
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,73 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
diff = require("deep-diff")
|
||||
|
||||
Group = require("../../website/src/models/group").model
|
||||
app = require("../../website/src/server")
|
||||
|
||||
describe "Chat", ->
|
||||
group = undefined
|
||||
before (done) ->
|
||||
async.waterfall [
|
||||
(cb) ->
|
||||
registerNewUser(cb, true)
|
||||
|
||||
(user, cb) ->
|
||||
request.post(baseURL + "/groups").send(
|
||||
name: "TestGroup"
|
||||
type: "party"
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
group = res.body
|
||||
expect(group.members.length).to.equal 1
|
||||
expect(group.leader).to.equal user._id
|
||||
cb()
|
||||
|
||||
], done
|
||||
|
||||
chat = undefined
|
||||
|
||||
it "removes a user's chat notifications when user is kicked", (done) ->
|
||||
userToRemove = null
|
||||
async.waterfall [
|
||||
(cb) ->
|
||||
registerManyUsers 1, cb
|
||||
|
||||
(members, cb) ->
|
||||
userToRemove = members[0]
|
||||
request.post(baseURL + "/groups/" + group._id + "/invite").send(
|
||||
uuids: [userToRemove._id]
|
||||
)
|
||||
.end -> cb()
|
||||
|
||||
(cb) ->
|
||||
request.post(baseURL + "/groups/" + group._id + "/join")
|
||||
.set("X-API-User", userToRemove._id)
|
||||
.set("X-API-Key", userToRemove.apiToken)
|
||||
.end (err, res) -> cb()
|
||||
|
||||
(cb) ->
|
||||
msg = "TestMsg"
|
||||
request.post(baseURL + "/groups/" + group._id + "/chat?message=" + msg)
|
||||
.end (err, res) -> cb()
|
||||
|
||||
(cb) ->
|
||||
request.get(baseURL + "/user")
|
||||
.set("X-API-User", userToRemove._id)
|
||||
.set("X-API-Key", userToRemove.apiToken)
|
||||
.end (err, res) ->
|
||||
expect(res.body.newMessages[group._id]).to.exist
|
||||
cb()
|
||||
|
||||
(cb) ->
|
||||
request.post(baseURL + "/groups/" + group._id + "/removeMember?uuid=" + userToRemove._id)
|
||||
.end (err, res) -> cb()
|
||||
|
||||
(cb) ->
|
||||
request.get(baseURL + "/user")
|
||||
.set("X-API-User", userToRemove._id)
|
||||
.set("X-API-Key", userToRemove.apiToken)
|
||||
.end (err, res) ->
|
||||
expect(res.body.newMessages[group._id]).to.not.exist
|
||||
cb()
|
||||
], done
|
||||
71
test/api-legacy/chat.js
Normal file
71
test/api-legacy/chat.js
Normal file
@@ -0,0 +1,71 @@
|
||||
var Group, app, diff;
|
||||
|
||||
diff = require("deep-diff");
|
||||
|
||||
Group = require("../../website/src/models/group").model;
|
||||
|
||||
app = require("../../website/src/server");
|
||||
|
||||
describe("Chat", function() {
|
||||
var chat, group;
|
||||
group = void 0;
|
||||
before(function(done) {
|
||||
return async.waterfall([
|
||||
function(cb) {
|
||||
return registerNewUser(cb, true);
|
||||
}, function(user, cb) {
|
||||
return request.post(baseURL + "/groups").send({
|
||||
name: "TestGroup",
|
||||
type: "party"
|
||||
}).end(function(err, res) {
|
||||
expectCode(res, 200);
|
||||
group = res.body;
|
||||
expect(group.members.length).to.equal(1);
|
||||
expect(group.leader).to.equal(user._id);
|
||||
return cb();
|
||||
});
|
||||
}
|
||||
], done);
|
||||
});
|
||||
chat = void 0;
|
||||
return it("removes a user's chat notifications when user is kicked", function(done) {
|
||||
var userToRemove;
|
||||
userToRemove = null;
|
||||
return async.waterfall([
|
||||
function(cb) {
|
||||
return registerManyUsers(1, cb);
|
||||
}, function(members, cb) {
|
||||
userToRemove = members[0];
|
||||
return request.post(baseURL + "/groups/" + group._id + "/invite").send({
|
||||
uuids: [userToRemove._id]
|
||||
}).end(function() {
|
||||
return cb();
|
||||
});
|
||||
}, function(cb) {
|
||||
return request.post(baseURL + "/groups/" + group._id + "/join").set("X-API-User", userToRemove._id).set("X-API-Key", userToRemove.apiToken).end(function(err, res) {
|
||||
return cb();
|
||||
});
|
||||
}, function(cb) {
|
||||
var msg;
|
||||
msg = "TestMsg";
|
||||
return request.post(baseURL + "/groups/" + group._id + "/chat?message=" + msg).end(function(err, res) {
|
||||
return cb();
|
||||
});
|
||||
}, function(cb) {
|
||||
return request.get(baseURL + "/user").set("X-API-User", userToRemove._id).set("X-API-Key", userToRemove.apiToken).end(function(err, res) {
|
||||
expect(res.body.newMessages[group._id]).to.exist;
|
||||
return cb();
|
||||
});
|
||||
}, function(cb) {
|
||||
return request.post(baseURL + "/groups/" + group._id + "/removeMember?uuid=" + userToRemove._id).end(function(err, res) {
|
||||
return cb();
|
||||
});
|
||||
}, function(cb) {
|
||||
return request.get(baseURL + "/user").set("X-API-User", userToRemove._id).set("X-API-Key", userToRemove.apiToken).end(function(err, res) {
|
||||
expect(res.body.newMessages[group._id]).to.not.exist;
|
||||
return cb();
|
||||
});
|
||||
}
|
||||
], done);
|
||||
});
|
||||
});
|
||||
218
test/api-legacy/coupons.js
Normal file
218
test/api-legacy/coupons.js
Normal file
@@ -0,0 +1,218 @@
|
||||
var Coupon, app, makeSudoUser;
|
||||
|
||||
app = require("../../website/src/server");
|
||||
|
||||
Coupon = require("../../website/src/models/coupon").model;
|
||||
|
||||
makeSudoUser = function(usr, cb) {
|
||||
return registerNewUser(function() {
|
||||
var sudoUpdate;
|
||||
sudoUpdate = {
|
||||
"$set": {
|
||||
"contributor.sudo": true
|
||||
}
|
||||
};
|
||||
return User.findByIdAndUpdate(user._id, sudoUpdate, {
|
||||
"new": true
|
||||
}, function(err, _user) {
|
||||
usr = _user;
|
||||
return cb();
|
||||
});
|
||||
}, true);
|
||||
};
|
||||
|
||||
describe("Coupons", function() {
|
||||
var coupons;
|
||||
before(function(done) {
|
||||
return async.parallel([
|
||||
function(cb) {
|
||||
return mongoose.connection.collections['coupons'].drop(function(err) {
|
||||
return cb();
|
||||
});
|
||||
}, function(cb) {
|
||||
return mongoose.connection.collections['users'].drop(function(err) {
|
||||
return cb();
|
||||
});
|
||||
}
|
||||
], done);
|
||||
});
|
||||
coupons = null;
|
||||
describe("POST /api/v2/coupons/generate/:event", function() {
|
||||
context("while sudo user", function() {
|
||||
before(function(done) {
|
||||
return makeSudoUser(user, done);
|
||||
});
|
||||
return it("generates coupons", function(done) {
|
||||
var queries;
|
||||
queries = '?count=10';
|
||||
return request.post(baseURL + '/coupons/generate/wondercon' + queries).end(function(err, res) {
|
||||
expectCode(res, 200);
|
||||
return Coupon.find({
|
||||
event: 'wondercon'
|
||||
}, function(err, _coupons) {
|
||||
coupons = _coupons;
|
||||
expect(coupons.length).to.equal(10);
|
||||
_(coupons).each(function(c) {
|
||||
return expect(c.event).to.equal('wondercon');
|
||||
}).value();
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
return context("while regular user", function() {
|
||||
before(function(done) {
|
||||
return registerNewUser(done, true);
|
||||
});
|
||||
return it("does not generate coupons", function(done) {
|
||||
var queries;
|
||||
queries = '?count=10';
|
||||
return request.post(baseURL + '/coupons/generate/wondercon' + queries).end(function(err, res) {
|
||||
expectCode(res, 401);
|
||||
expect(res.body.err).to.equal('You don\'t have admin access');
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("GET /api/v2/coupons", function() {
|
||||
context("while sudo user", function() {
|
||||
before(function(done) {
|
||||
return makeSudoUser(user, done);
|
||||
});
|
||||
it("gets coupons", function(done) {
|
||||
var queries;
|
||||
queries = '?_id=' + user._id + '&apiToken=' + user.apiToken;
|
||||
return request.get(baseURL + '/coupons' + queries).end(function(err, res) {
|
||||
var codes;
|
||||
expectCode(res, 200);
|
||||
codes = res.text;
|
||||
expect(codes).to.contain('code');
|
||||
_(coupons).each(function(c) {
|
||||
return expect(codes).to.contain(c._id);
|
||||
}).value();
|
||||
return done();
|
||||
});
|
||||
});
|
||||
it("gets first 5 coupons out of 10 when a limit of 5 is set", function(done) {
|
||||
var queries;
|
||||
queries = '?_id=' + user._id + '&apiToken=' + user.apiToken + '&limit=5';
|
||||
return request.get(baseURL + '/coupons' + queries).end(function(err, res) {
|
||||
var codes, firstHalf, secondHalf, sortedCoupons;
|
||||
expectCode(res, 200);
|
||||
codes = res.text;
|
||||
sortedCoupons = _.sortBy(coupons, 'seq');
|
||||
firstHalf = sortedCoupons.slice(0, 5);
|
||||
secondHalf = sortedCoupons.slice(5, 10);
|
||||
_(firstHalf).each(function(c) {
|
||||
return expect(codes).to.contain(c._id);
|
||||
}).value();
|
||||
_(secondHalf).each(function(c) {
|
||||
return expect(codes).to.not.contain(c._id);
|
||||
}).value();
|
||||
return done();
|
||||
});
|
||||
});
|
||||
return it("gets last 5 coupons out of 10 when a limit of 5 is set", function(done) {
|
||||
var queries;
|
||||
queries = '?_id=' + user._id + '&apiToken=' + user.apiToken + '&skip=5';
|
||||
return request.get(baseURL + '/coupons' + queries).end(function(err, res) {
|
||||
var codes, firstHalf, secondHalf, sortedCoupons;
|
||||
expectCode(res, 200);
|
||||
codes = res.text;
|
||||
sortedCoupons = _.sortBy(coupons, 'seq');
|
||||
firstHalf = sortedCoupons.slice(0, 5);
|
||||
secondHalf = sortedCoupons.slice(5, 10);
|
||||
_(firstHalf).each(function(c) {
|
||||
return expect(codes).to.not.contain(c._id);
|
||||
}).value();
|
||||
_(secondHalf).each(function(c) {
|
||||
return expect(codes).to.contain(c._id);
|
||||
}).value();
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
return context("while regular user", function() {
|
||||
before(function(done) {
|
||||
return registerNewUser(done, true);
|
||||
});
|
||||
return it("does not get coupons", function(done) {
|
||||
var queries;
|
||||
queries = '?_id=' + user._id + '&apiToken=' + user.apiToken;
|
||||
return request.get(baseURL + '/coupons' + queries).end(function(err, res) {
|
||||
expectCode(res, 401);
|
||||
expect(res.body.err).to.equal('You don\'t have admin access');
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
return describe("POST /api/v2/user/coupon/:code", function() {
|
||||
var specialGear;
|
||||
specialGear = function(gear, has) {
|
||||
var items;
|
||||
items = ['body_special_wondercon_gold', 'body_special_wondercon_black', 'body_special_wondercon_red', 'back_special_wondercon_red', 'back_special_wondercon_black', 'back_special_wondercon_red', 'eyewear_special_wondercon_black', 'eyewear_special_wondercon_red'];
|
||||
return _(items).each(function(i) {
|
||||
if (has) {
|
||||
return expect(gear[i]).to.exist;
|
||||
} else {
|
||||
return expect(gear[i]).to.not.exist;
|
||||
}
|
||||
}).value();
|
||||
};
|
||||
beforeEach(function(done) {
|
||||
return registerNewUser(function() {
|
||||
var gear;
|
||||
gear = user.items.gear.owned;
|
||||
specialGear(gear, false);
|
||||
return done();
|
||||
}, true);
|
||||
});
|
||||
context("unused coupon", function() {
|
||||
return it("applies coupon and awards equipment", function(done) {
|
||||
var code;
|
||||
code = coupons[0]._id;
|
||||
return request.post(baseURL + '/user/coupon/' + code).end(function(err, res) {
|
||||
var gear;
|
||||
expectCode(res, 200);
|
||||
gear = res.body.items.gear.owned;
|
||||
specialGear(gear, true);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
context("already used coupon", function() {
|
||||
return it("does not apply coupon and does not award equipment", function(done) {
|
||||
var code;
|
||||
code = coupons[0]._id;
|
||||
return request.post(baseURL + '/user/coupon/' + code).end(function(err, res) {
|
||||
expectCode(res, 400);
|
||||
expect(res.body.err).to.equal("Coupon already used");
|
||||
return User.findById(user._id, function(err, _user) {
|
||||
var gear;
|
||||
gear = _user.items.gear.owned;
|
||||
specialGear(gear, false);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
return context("invalid coupon", function() {
|
||||
return it("does not apply coupon and does not award equipment", function(done) {
|
||||
var code;
|
||||
code = "not-a-real-coupon";
|
||||
return request.post(baseURL + '/user/coupon/' + code).end(function(err, res) {
|
||||
expectCode(res, 400);
|
||||
expect(res.body.err).to.equal("Invalid coupon code");
|
||||
return User.findById(user._id, function(err, _user) {
|
||||
var gear;
|
||||
gear = _user.items.gear.owned;
|
||||
specialGear(gear, false);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,281 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
app = require('../../website/src/server')
|
||||
rewire = require('rewire')
|
||||
sinon = require('sinon')
|
||||
inApp = rewire('../../website/src/controllers/payments/iap')
|
||||
iapMock = { }
|
||||
inApp.__set__('iap', iapMock)
|
||||
|
||||
describe 'In-App Purchases', ->
|
||||
describe 'Android', ->
|
||||
req = {
|
||||
body: {
|
||||
transaction: {
|
||||
reciept: 'foo'
|
||||
signature: 'sig'
|
||||
}
|
||||
}
|
||||
}
|
||||
res = {
|
||||
locals: { user: { _id: 'user' } }
|
||||
json: sinon.spy()
|
||||
}
|
||||
next = -> true
|
||||
paymentSpy = sinon.spy()
|
||||
|
||||
before ->
|
||||
inApp.__set__('payments.buyGems', paymentSpy)
|
||||
|
||||
afterEach ->
|
||||
paymentSpy.reset()
|
||||
res.json.reset()
|
||||
|
||||
context 'successful app purchase', ->
|
||||
before ->
|
||||
iapMock.setup = (cb)-> return cb(null)
|
||||
iapMock.validate = (iapGoogle, iapBodyReciept, cb)-> return cb(null, true)
|
||||
iapMock.isValidated = (googleRes)-> return googleRes
|
||||
iapMock.GOOGLE = 'google'
|
||||
|
||||
it 'calls res.json with succesful result object', ->
|
||||
expectedResObj = {
|
||||
ok: true
|
||||
data: true
|
||||
}
|
||||
|
||||
inApp.androidVerify(req, res, next)
|
||||
|
||||
expect(res.json).to.be.calledOnce
|
||||
expect(res.json).to.be.calledWith(expectedResObj)
|
||||
|
||||
it 'calls payments.buyGems function', ->
|
||||
inApp.androidVerify(req, res, next)
|
||||
|
||||
expect(paymentSpy).to.be.calledOnce
|
||||
expect(paymentSpy).to.be.calledWith({user: res.locals.user, paymentMethod:'IAP GooglePlay'})
|
||||
|
||||
context 'error in setup', ->
|
||||
before ->
|
||||
iapMock.setup = (cb)-> return cb("error in setup")
|
||||
|
||||
it 'calls res.json with setup error object', ->
|
||||
expectedResObj = {
|
||||
ok: false
|
||||
data: 'IAP Error'
|
||||
}
|
||||
|
||||
inApp.androidVerify(req, res, next)
|
||||
|
||||
expect(res.json).to.be.calledOnce
|
||||
expect(res.json).to.be.calledWith(expectedResObj)
|
||||
|
||||
it 'does not calls payments.buyGems function', ->
|
||||
inApp.androidVerify(req, res, next)
|
||||
|
||||
expect(paymentSpy).to.not.be.called
|
||||
|
||||
context 'error in validation', ->
|
||||
before ->
|
||||
iapMock.setup = (cb)-> return cb(null)
|
||||
iapMock.validate = (iapGoogle, iapBodyReciept, cb)-> return cb('error in validation', true)
|
||||
|
||||
it 'calls res.json with validation error object', ->
|
||||
expectedResObj = {
|
||||
ok: false
|
||||
data: {
|
||||
code: 6778001
|
||||
message: 'error in validation'
|
||||
}
|
||||
}
|
||||
|
||||
inApp.androidVerify(req, res, next)
|
||||
|
||||
expect(res.json).to.be.calledOnce
|
||||
expect(res.json).to.be.calledWith(expectedResObj)
|
||||
|
||||
it 'does not calls payments.buyGems function', ->
|
||||
inApp.androidVerify(req, res, next)
|
||||
|
||||
expect(paymentSpy).to.not.be.called
|
||||
|
||||
context 'iap is not valid', ->
|
||||
before ->
|
||||
iapMock.setup = (cb)-> return cb(null)
|
||||
iapMock.validate = (iapGoogle, iapBodyReciept, cb)-> return cb(null, false)
|
||||
iapMock.isValidated = (googleRes)-> return googleRes
|
||||
|
||||
it 'does not call res.json', ->
|
||||
inApp.androidVerify(req, res, next)
|
||||
|
||||
expect(res.json).to.not.be.called
|
||||
|
||||
it 'does not calls payments.buyGems function', ->
|
||||
inApp.androidVerify(req, res, next)
|
||||
|
||||
expect(paymentSpy).to.not.be.called
|
||||
|
||||
describe 'iOS', ->
|
||||
req = { body: { transaction: { reciept: 'foo' } } }
|
||||
res = {
|
||||
locals: { user: { _id: 'user' } }
|
||||
json: sinon.spy()
|
||||
}
|
||||
next = -> true
|
||||
paymentSpy = sinon.spy()
|
||||
|
||||
before ->
|
||||
inApp.__set__('payments.buyGems', paymentSpy)
|
||||
|
||||
afterEach ->
|
||||
paymentSpy.reset()
|
||||
res.json.reset()
|
||||
|
||||
context 'successful app purchase', ->
|
||||
before ->
|
||||
iapMock.setup = (cb)-> return cb(null)
|
||||
iapMock.validate = (iapApple, iapBodyReciept, cb)-> return cb(null, true)
|
||||
iapMock.isValidated = (appleRes)-> return appleRes
|
||||
iapMock.getPurchaseData = (appleRes)->
|
||||
return [{ productId: 'com.habitrpg.ios.Habitica.20gems' }]
|
||||
iapMock.APPLE = 'apple'
|
||||
|
||||
it 'calls res.json with succesful result object', ->
|
||||
expectedResObj = {
|
||||
ok: true
|
||||
data: true
|
||||
}
|
||||
|
||||
inApp.iosVerify(req, res, next)
|
||||
|
||||
expect(res.json).to.be.calledOnce
|
||||
expect(res.json).to.be.calledWith(expectedResObj)
|
||||
|
||||
it 'calls payments.buyGems function', ->
|
||||
inApp.iosVerify(req, res, next)
|
||||
|
||||
expect(paymentSpy).to.be.calledOnce
|
||||
expect(paymentSpy).to.be.calledWith({user: res.locals.user, paymentMethod:'IAP AppleStore', amount: 5.25})
|
||||
|
||||
context 'error in setup', ->
|
||||
before ->
|
||||
iapMock.setup = (cb)-> return cb("error in setup")
|
||||
|
||||
it 'calls res.json with setup error object', ->
|
||||
expectedResObj = {
|
||||
ok: false
|
||||
data: 'IAP Error'
|
||||
}
|
||||
|
||||
inApp.iosVerify(req, res, next)
|
||||
|
||||
expect(res.json).to.be.calledOnce
|
||||
expect(res.json).to.be.calledWith(expectedResObj)
|
||||
|
||||
it 'does not calls payments.buyGems function', ->
|
||||
inApp.iosVerify(req, res, next)
|
||||
|
||||
expect(paymentSpy).to.not.be.called
|
||||
|
||||
context 'error in validation', ->
|
||||
before ->
|
||||
iapMock.setup = (cb)-> return cb(null)
|
||||
iapMock.validate = (iapApple, iapBodyReciept, cb)-> return cb('error in validation', true)
|
||||
|
||||
it 'calls res.json with validation error object', ->
|
||||
expectedResObj = {
|
||||
ok: false
|
||||
data: {
|
||||
code: 6778001
|
||||
message: 'error in validation'
|
||||
}
|
||||
}
|
||||
|
||||
inApp.iosVerify(req, res, next)
|
||||
|
||||
expect(res.json).to.be.calledOnce
|
||||
expect(res.json).to.be.calledWith(expectedResObj)
|
||||
|
||||
it 'does not calls payments.buyGems function', ->
|
||||
inApp.iosVerify(req, res, next)
|
||||
|
||||
expect(paymentSpy).to.not.be.called
|
||||
|
||||
context 'iap is not valid', ->
|
||||
before ->
|
||||
iapMock.setup = (cb)-> return cb(null)
|
||||
iapMock.validate = (iapApple, iapBodyReciept, cb)-> return cb(null, false)
|
||||
iapMock.isValidated = (appleRes)-> return appleRes
|
||||
|
||||
it 'does not call res.json', ->
|
||||
inApp.iosVerify(req, res, next)
|
||||
expectedResObj = {
|
||||
ok: false
|
||||
data: {
|
||||
code: 6778001
|
||||
message: 'Invalid receipt'
|
||||
}
|
||||
}
|
||||
expect(res.json).to.be.calledOnce
|
||||
expect(res.json).to.be.calledWith(expectedResObj)
|
||||
|
||||
it 'does not calls payments.buyGems function', ->
|
||||
inApp.iosVerify(req, res, next)
|
||||
|
||||
expect(paymentSpy).to.not.be.called
|
||||
|
||||
context 'iap is valid but has no purchaseDataList', ->
|
||||
before ->
|
||||
iapMock.setup = (cb)-> return cb(null)
|
||||
iapMock.validate = (iapApple, iapBodyReciept, cb)-> return cb(null, true)
|
||||
iapMock.isValidated = (appleRes)-> return appleRes
|
||||
iapMock.getPurchaseData = (appleRes)->
|
||||
return []
|
||||
iapMock.APPLE = 'apple'
|
||||
|
||||
it 'calls res.json with succesful result object', ->
|
||||
expectedResObj = {
|
||||
ok: false
|
||||
data: {
|
||||
code: 6778001
|
||||
message: 'Incorrect receipt content'
|
||||
}
|
||||
}
|
||||
|
||||
inApp.iosVerify(req, res, next)
|
||||
|
||||
expect(res.json).to.be.calledOnce
|
||||
expect(res.json).to.be.calledWith(expectedResObj)
|
||||
|
||||
it 'does not calls payments.buyGems function', ->
|
||||
inApp.iosVerify(req, res, next)
|
||||
|
||||
expect(paymentSpy).to.not.be.called
|
||||
|
||||
context 'iap is valid, has purchaseDataList, but productId does not match', ->
|
||||
before ->
|
||||
iapMock.setup = (cb)-> return cb(null)
|
||||
iapMock.validate = (iapApple, iapBodyReciept, cb)-> return cb(null, true)
|
||||
iapMock.isValidated = (appleRes)-> return appleRes
|
||||
iapMock.getPurchaseData = (appleRes)->
|
||||
return [{ productId: 'com.another.company' }]
|
||||
iapMock.APPLE = 'apple'
|
||||
|
||||
it 'calls res.json with incorrect reciept obj', ->
|
||||
expectedResObj = {
|
||||
ok: false
|
||||
data: {
|
||||
code: 6778001
|
||||
message: 'Incorrect receipt content'
|
||||
}
|
||||
}
|
||||
|
||||
inApp.iosVerify(req, res, next)
|
||||
|
||||
expect(res.json).to.be.calledOnce
|
||||
expect(res.json).to.be.calledWith(expectedResObj)
|
||||
|
||||
it 'does not calls payments.buyGems function', ->
|
||||
inApp.iosVerify(req, res, next)
|
||||
|
||||
expect(paymentSpy).to.not.be.called
|
||||
366
test/api-legacy/inAppPurchases.js
Normal file
366
test/api-legacy/inAppPurchases.js
Normal file
@@ -0,0 +1,366 @@
|
||||
var app, iapMock, inApp, rewire, sinon;
|
||||
|
||||
app = require('../../website/src/server');
|
||||
|
||||
rewire = require('rewire');
|
||||
|
||||
sinon = require('sinon');
|
||||
|
||||
inApp = rewire('../../website/src/controllers/payments/iap');
|
||||
|
||||
iapMock = {};
|
||||
|
||||
inApp.__set__('iap', iapMock);
|
||||
|
||||
describe('In-App Purchases', function() {
|
||||
describe('Android', function() {
|
||||
var next, paymentSpy, req, res;
|
||||
req = {
|
||||
body: {
|
||||
transaction: {
|
||||
reciept: 'foo',
|
||||
signature: 'sig'
|
||||
}
|
||||
}
|
||||
};
|
||||
res = {
|
||||
locals: {
|
||||
user: {
|
||||
_id: 'user'
|
||||
}
|
||||
},
|
||||
json: sinon.spy()
|
||||
};
|
||||
next = function() {
|
||||
return true;
|
||||
};
|
||||
paymentSpy = sinon.spy();
|
||||
before(function() {
|
||||
return inApp.__set__('payments.buyGems', paymentSpy);
|
||||
});
|
||||
afterEach(function() {
|
||||
paymentSpy.reset();
|
||||
return res.json.reset();
|
||||
});
|
||||
context('successful app purchase', function() {
|
||||
before(function() {
|
||||
iapMock.setup = function(cb) {
|
||||
return cb(null);
|
||||
};
|
||||
iapMock.validate = function(iapGoogle, iapBodyReciept, cb) {
|
||||
return cb(null, true);
|
||||
};
|
||||
iapMock.isValidated = function(googleRes) {
|
||||
return googleRes;
|
||||
};
|
||||
return iapMock.GOOGLE = 'google';
|
||||
});
|
||||
it('calls res.json with succesful result object', function() {
|
||||
var expectedResObj;
|
||||
expectedResObj = {
|
||||
ok: true,
|
||||
data: true
|
||||
};
|
||||
inApp.androidVerify(req, res, next);
|
||||
expect(res.json).to.be.calledOnce;
|
||||
return expect(res.json).to.be.calledWith(expectedResObj);
|
||||
});
|
||||
return it('calls payments.buyGems function', function() {
|
||||
inApp.androidVerify(req, res, next);
|
||||
expect(paymentSpy).to.be.calledOnce;
|
||||
return expect(paymentSpy).to.be.calledWith({
|
||||
user: res.locals.user,
|
||||
paymentMethod: 'IAP GooglePlay'
|
||||
});
|
||||
});
|
||||
});
|
||||
context('error in setup', function() {
|
||||
before(function() {
|
||||
return iapMock.setup = function(cb) {
|
||||
return cb("error in setup");
|
||||
};
|
||||
});
|
||||
it('calls res.json with setup error object', function() {
|
||||
var expectedResObj;
|
||||
expectedResObj = {
|
||||
ok: false,
|
||||
data: 'IAP Error'
|
||||
};
|
||||
inApp.androidVerify(req, res, next);
|
||||
expect(res.json).to.be.calledOnce;
|
||||
return expect(res.json).to.be.calledWith(expectedResObj);
|
||||
});
|
||||
return it('does not calls payments.buyGems function', function() {
|
||||
inApp.androidVerify(req, res, next);
|
||||
return expect(paymentSpy).to.not.be.called;
|
||||
});
|
||||
});
|
||||
context('error in validation', function() {
|
||||
before(function() {
|
||||
iapMock.setup = function(cb) {
|
||||
return cb(null);
|
||||
};
|
||||
return iapMock.validate = function(iapGoogle, iapBodyReciept, cb) {
|
||||
return cb('error in validation', true);
|
||||
};
|
||||
});
|
||||
it('calls res.json with validation error object', function() {
|
||||
var expectedResObj;
|
||||
expectedResObj = {
|
||||
ok: false,
|
||||
data: {
|
||||
code: 6778001,
|
||||
message: 'error in validation'
|
||||
}
|
||||
};
|
||||
inApp.androidVerify(req, res, next);
|
||||
expect(res.json).to.be.calledOnce;
|
||||
return expect(res.json).to.be.calledWith(expectedResObj);
|
||||
});
|
||||
return it('does not calls payments.buyGems function', function() {
|
||||
inApp.androidVerify(req, res, next);
|
||||
return expect(paymentSpy).to.not.be.called;
|
||||
});
|
||||
});
|
||||
return context('iap is not valid', function() {
|
||||
before(function() {
|
||||
iapMock.setup = function(cb) {
|
||||
return cb(null);
|
||||
};
|
||||
iapMock.validate = function(iapGoogle, iapBodyReciept, cb) {
|
||||
return cb(null, false);
|
||||
};
|
||||
return iapMock.isValidated = function(googleRes) {
|
||||
return googleRes;
|
||||
};
|
||||
});
|
||||
it('does not call res.json', function() {
|
||||
inApp.androidVerify(req, res, next);
|
||||
return expect(res.json).to.not.be.called;
|
||||
});
|
||||
return it('does not calls payments.buyGems function', function() {
|
||||
inApp.androidVerify(req, res, next);
|
||||
return expect(paymentSpy).to.not.be.called;
|
||||
});
|
||||
});
|
||||
});
|
||||
return describe('iOS', function() {
|
||||
var next, paymentSpy, req, res;
|
||||
req = {
|
||||
body: {
|
||||
transaction: {
|
||||
reciept: 'foo'
|
||||
}
|
||||
}
|
||||
};
|
||||
res = {
|
||||
locals: {
|
||||
user: {
|
||||
_id: 'user'
|
||||
}
|
||||
},
|
||||
json: sinon.spy()
|
||||
};
|
||||
next = function() {
|
||||
return true;
|
||||
};
|
||||
paymentSpy = sinon.spy();
|
||||
before(function() {
|
||||
return inApp.__set__('payments.buyGems', paymentSpy);
|
||||
});
|
||||
afterEach(function() {
|
||||
paymentSpy.reset();
|
||||
return res.json.reset();
|
||||
});
|
||||
context('successful app purchase', function() {
|
||||
before(function() {
|
||||
iapMock.setup = function(cb) {
|
||||
return cb(null);
|
||||
};
|
||||
iapMock.validate = function(iapApple, iapBodyReciept, cb) {
|
||||
return cb(null, true);
|
||||
};
|
||||
iapMock.isValidated = function(appleRes) {
|
||||
return appleRes;
|
||||
};
|
||||
iapMock.getPurchaseData = function(appleRes) {
|
||||
return [
|
||||
{
|
||||
productId: 'com.habitrpg.ios.Habitica.20gems'
|
||||
}
|
||||
];
|
||||
};
|
||||
return iapMock.APPLE = 'apple';
|
||||
});
|
||||
it('calls res.json with succesful result object', function() {
|
||||
var expectedResObj;
|
||||
expectedResObj = {
|
||||
ok: true,
|
||||
data: true
|
||||
};
|
||||
inApp.iosVerify(req, res, next);
|
||||
expect(res.json).to.be.calledOnce;
|
||||
return expect(res.json).to.be.calledWith(expectedResObj);
|
||||
});
|
||||
return it('calls payments.buyGems function', function() {
|
||||
inApp.iosVerify(req, res, next);
|
||||
expect(paymentSpy).to.be.calledOnce;
|
||||
return expect(paymentSpy).to.be.calledWith({
|
||||
user: res.locals.user,
|
||||
paymentMethod: 'IAP AppleStore',
|
||||
amount: 5.25
|
||||
});
|
||||
});
|
||||
});
|
||||
context('error in setup', function() {
|
||||
before(function() {
|
||||
return iapMock.setup = function(cb) {
|
||||
return cb("error in setup");
|
||||
};
|
||||
});
|
||||
it('calls res.json with setup error object', function() {
|
||||
var expectedResObj;
|
||||
expectedResObj = {
|
||||
ok: false,
|
||||
data: 'IAP Error'
|
||||
};
|
||||
inApp.iosVerify(req, res, next);
|
||||
expect(res.json).to.be.calledOnce;
|
||||
return expect(res.json).to.be.calledWith(expectedResObj);
|
||||
});
|
||||
return it('does not calls payments.buyGems function', function() {
|
||||
inApp.iosVerify(req, res, next);
|
||||
return expect(paymentSpy).to.not.be.called;
|
||||
});
|
||||
});
|
||||
context('error in validation', function() {
|
||||
before(function() {
|
||||
iapMock.setup = function(cb) {
|
||||
return cb(null);
|
||||
};
|
||||
return iapMock.validate = function(iapApple, iapBodyReciept, cb) {
|
||||
return cb('error in validation', true);
|
||||
};
|
||||
});
|
||||
it('calls res.json with validation error object', function() {
|
||||
var expectedResObj;
|
||||
expectedResObj = {
|
||||
ok: false,
|
||||
data: {
|
||||
code: 6778001,
|
||||
message: 'error in validation'
|
||||
}
|
||||
};
|
||||
inApp.iosVerify(req, res, next);
|
||||
expect(res.json).to.be.calledOnce;
|
||||
return expect(res.json).to.be.calledWith(expectedResObj);
|
||||
});
|
||||
return it('does not calls payments.buyGems function', function() {
|
||||
inApp.iosVerify(req, res, next);
|
||||
return expect(paymentSpy).to.not.be.called;
|
||||
});
|
||||
});
|
||||
context('iap is not valid', function() {
|
||||
before(function() {
|
||||
iapMock.setup = function(cb) {
|
||||
return cb(null);
|
||||
};
|
||||
iapMock.validate = function(iapApple, iapBodyReciept, cb) {
|
||||
return cb(null, false);
|
||||
};
|
||||
return iapMock.isValidated = function(appleRes) {
|
||||
return appleRes;
|
||||
};
|
||||
});
|
||||
it('does not call res.json', function() {
|
||||
var expectedResObj;
|
||||
inApp.iosVerify(req, res, next);
|
||||
expectedResObj = {
|
||||
ok: false,
|
||||
data: {
|
||||
code: 6778001,
|
||||
message: 'Invalid receipt'
|
||||
}
|
||||
};
|
||||
expect(res.json).to.be.calledOnce;
|
||||
return expect(res.json).to.be.calledWith(expectedResObj);
|
||||
});
|
||||
return it('does not calls payments.buyGems function', function() {
|
||||
inApp.iosVerify(req, res, next);
|
||||
return expect(paymentSpy).to.not.be.called;
|
||||
});
|
||||
});
|
||||
context('iap is valid but has no purchaseDataList', function() {
|
||||
before(function() {
|
||||
iapMock.setup = function(cb) {
|
||||
return cb(null);
|
||||
};
|
||||
iapMock.validate = function(iapApple, iapBodyReciept, cb) {
|
||||
return cb(null, true);
|
||||
};
|
||||
iapMock.isValidated = function(appleRes) {
|
||||
return appleRes;
|
||||
};
|
||||
iapMock.getPurchaseData = function(appleRes) {
|
||||
return [];
|
||||
};
|
||||
return iapMock.APPLE = 'apple';
|
||||
});
|
||||
it('calls res.json with succesful result object', function() {
|
||||
var expectedResObj;
|
||||
expectedResObj = {
|
||||
ok: false,
|
||||
data: {
|
||||
code: 6778001,
|
||||
message: 'Incorrect receipt content'
|
||||
}
|
||||
};
|
||||
inApp.iosVerify(req, res, next);
|
||||
expect(res.json).to.be.calledOnce;
|
||||
return expect(res.json).to.be.calledWith(expectedResObj);
|
||||
});
|
||||
return it('does not calls payments.buyGems function', function() {
|
||||
inApp.iosVerify(req, res, next);
|
||||
return expect(paymentSpy).to.not.be.called;
|
||||
});
|
||||
});
|
||||
return context('iap is valid, has purchaseDataList, but productId does not match', function() {
|
||||
before(function() {
|
||||
iapMock.setup = function(cb) {
|
||||
return cb(null);
|
||||
};
|
||||
iapMock.validate = function(iapApple, iapBodyReciept, cb) {
|
||||
return cb(null, true);
|
||||
};
|
||||
iapMock.isValidated = function(appleRes) {
|
||||
return appleRes;
|
||||
};
|
||||
iapMock.getPurchaseData = function(appleRes) {
|
||||
return [
|
||||
{
|
||||
productId: 'com.another.company'
|
||||
}
|
||||
];
|
||||
};
|
||||
return iapMock.APPLE = 'apple';
|
||||
});
|
||||
it('calls res.json with incorrect reciept obj', function() {
|
||||
var expectedResObj;
|
||||
expectedResObj = {
|
||||
ok: false,
|
||||
data: {
|
||||
code: 6778001,
|
||||
message: 'Incorrect receipt content'
|
||||
}
|
||||
};
|
||||
inApp.iosVerify(req, res, next);
|
||||
expect(res.json).to.be.calledOnce;
|
||||
return expect(res.json).to.be.calledWith(expectedResObj);
|
||||
});
|
||||
return it('does not calls payments.buyGems function', function() {
|
||||
inApp.iosVerify(req, res, next);
|
||||
return expect(paymentSpy).to.not.be.called;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,363 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
diff = require("deep-diff")
|
||||
|
||||
Group = require("../../website/src/models/group").model
|
||||
app = require("../../website/src/server")
|
||||
|
||||
describe "Party", ->
|
||||
context "Quests", ->
|
||||
party = undefined
|
||||
group = undefined
|
||||
participating = []
|
||||
notParticipating = []
|
||||
beforeEach (done) ->
|
||||
# Tavern boss, side-by-side
|
||||
Group.update(
|
||||
_id: "habitrpg"
|
||||
,
|
||||
$set:
|
||||
quest:
|
||||
key: "dilatory"
|
||||
active: true
|
||||
progress:
|
||||
hp: shared.content.quests.dilatory.boss.hp
|
||||
rage: 0
|
||||
).exec()
|
||||
|
||||
# Tally some progress for later. Later we want to test that progress made before the quest began gets
|
||||
# counted after the quest starts
|
||||
async.waterfall [
|
||||
(cb) ->
|
||||
registerNewUser(cb, true)
|
||||
|
||||
(user, cb) ->
|
||||
request.post(baseURL + "/groups").send(
|
||||
name: "TestGroup"
|
||||
type: "party"
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
group = res.body
|
||||
expect(group.members.length).to.equal 1
|
||||
expect(group.leader).to.equal user._id
|
||||
cb()
|
||||
|
||||
(cb) ->
|
||||
request.post(baseURL + '/user/tasks').send({
|
||||
type: 'daily'
|
||||
text: 'daily one'
|
||||
}).end (err, res) ->
|
||||
cb()
|
||||
(cb) ->
|
||||
request.post(baseURL + '/user/tasks').send({
|
||||
type: 'daily'
|
||||
text: 'daily two'
|
||||
}).end (err, res) ->
|
||||
cb()
|
||||
(cb) ->
|
||||
User.findByIdAndUpdate user._id,
|
||||
$set:
|
||||
"stats.lvl": 50
|
||||
, {new: true}
|
||||
, (err, _user) ->
|
||||
cb(null, _user)
|
||||
(_user, cb) ->
|
||||
user = _user
|
||||
request.post(baseURL + "/user/batch-update").send([
|
||||
{
|
||||
op: "score"
|
||||
params:
|
||||
direction: "up"
|
||||
id: user.dailys[0].id
|
||||
}
|
||||
{
|
||||
op: "score"
|
||||
params:
|
||||
direction: "up"
|
||||
id: user.dailys[0].id
|
||||
}
|
||||
{
|
||||
op: "update"
|
||||
body:
|
||||
"stats.lvl": 50
|
||||
}
|
||||
]).end (err, res) ->
|
||||
user = res.body
|
||||
expect(user.party.quest.progress.up).to.be.above 0
|
||||
|
||||
# Invite some members
|
||||
async.waterfall [
|
||||
|
||||
# Register new users
|
||||
(cb) ->
|
||||
registerManyUsers 3, cb
|
||||
|
||||
# Send them invitations
|
||||
(_party, cb) ->
|
||||
party = _party
|
||||
inviteURL = baseURL + "/groups/" + group._id + "/invite"
|
||||
async.parallel [
|
||||
(cb2) ->
|
||||
request.post(inviteURL).send(
|
||||
uuids: [party[0]._id]
|
||||
).end ->
|
||||
cb2()
|
||||
(cb2) ->
|
||||
request.post(inviteURL).send(
|
||||
uuids: [party[1]._id]
|
||||
).end ->
|
||||
cb2()
|
||||
(cb2) ->
|
||||
request.post(inviteURL).send(
|
||||
uuids: [party[2]._id]
|
||||
).end (err, res)->
|
||||
cb2()
|
||||
], cb
|
||||
|
||||
# Accept / Reject
|
||||
(results, cb) ->
|
||||
|
||||
# series since they'll be modifying the same group record
|
||||
series = _.reduce(party, (m, v, i) ->
|
||||
m.push (cb2) ->
|
||||
request.post(baseURL + "/groups/" + group._id + "/join").set("X-API-User", party[i]._id).set("X-API-Key", party[i].apiToken).end ->
|
||||
cb2()
|
||||
m
|
||||
, [])
|
||||
async.series series, cb
|
||||
|
||||
# Make sure the invites stuck
|
||||
(whatever, cb) ->
|
||||
Group.findById group._id, (err, g) ->
|
||||
group = g
|
||||
expect(g.members.length).to.equal 4
|
||||
cb()
|
||||
|
||||
], ->
|
||||
|
||||
# Start the quest
|
||||
async.waterfall [
|
||||
(cb) ->
|
||||
request.post(baseURL + "/groups/" + group._id + "/questAccept?key=vice3").end (err, res) ->
|
||||
expectCode res, 400
|
||||
User.findByIdAndUpdate user._id,
|
||||
$set:
|
||||
"items.quests.vice3": 1
|
||||
, {new: true}
|
||||
, cb
|
||||
|
||||
(_user, cb) ->
|
||||
request.post(baseURL + "/groups/" + group._id + "/questAccept?key=vice3").end (err, res) ->
|
||||
expectCode res, 200
|
||||
Group.findById group._id, cb
|
||||
|
||||
(_group, cb) ->
|
||||
expect(_group.quest.key).to.equal "vice3"
|
||||
expect(_group.quest.active).to.equal false
|
||||
request.post(baseURL + "/groups/" + group._id + "/questAccept").set("X-API-User", party[0]._id).set("X-API-Key", party[0].apiToken).end ->
|
||||
request.post(baseURL + "/groups/" + group._id + "/questAccept").set("X-API-User", party[1]._id).set("X-API-Key", party[1].apiToken).end (err, res) ->
|
||||
request.post(baseURL + "/groups/" + group._id + "/questReject").set("X-API-User", party[2]._id).set("X-API-Key", party[2].apiToken).end (err, res) ->
|
||||
group = res.body
|
||||
expect(group.quest.active).to.equal true
|
||||
cb()
|
||||
|
||||
], done
|
||||
]
|
||||
|
||||
it "Casts a spell", (done) ->
|
||||
mp = user.stats.mp
|
||||
request.get(baseURL + "/members/" + party[0]._id).end (err, res) ->
|
||||
party[0] = res.body
|
||||
request.post(baseURL + "/user/class/cast/snowball?targetType=user&targetId=" + party[0]._id).end (err, res) ->
|
||||
|
||||
#expect(res.body.stats.mp).to.be.below(mp);
|
||||
request.get(baseURL + "/members/" + party[0]._id).end (err, res) ->
|
||||
member = res.body
|
||||
expect(member.achievements.snowball).to.equal 1
|
||||
expect(member.stats.buffs.snowball).to.exist
|
||||
difference = diff(member, party[0])
|
||||
expect(_.size(difference)).to.equal 2
|
||||
|
||||
# level up user so str is > 0
|
||||
request.put(baseURL + "/user").send("stats.lvl": 5).end (err, res) ->
|
||||
|
||||
# Refill mana so user can cast
|
||||
request.put(baseURL + "/user").send("stats.mp": 100).end (err, res) ->
|
||||
request.post(baseURL + "/user/class/cast/valorousPresence?targetType=party").end (err, res) ->
|
||||
request.get(baseURL + "/members/" + member._id).end (err, res) ->
|
||||
expect(res.body.stats.buffs.str).to.be.above 0
|
||||
expect(diff(res.body, member).length).to.equal 1
|
||||
done()
|
||||
|
||||
it "Doesn't include people who aren't participating", (done) ->
|
||||
request.get(baseURL + "/groups/" + group._id).end (err, res) ->
|
||||
expect(_.size(res.body.quest.members)).to.equal 3
|
||||
done()
|
||||
|
||||
it "allows quest participants to leave quest", (done) ->
|
||||
leavingMember = party[1]
|
||||
expect(group.quest.members[leavingMember._id]).to.eql(true)
|
||||
|
||||
request.post(baseURL + "/groups/" + group._id + "/questLeave")
|
||||
.set("X-API-User", leavingMember._id)
|
||||
.set("X-API-Key", leavingMember.apiToken)
|
||||
.end (err, res) ->
|
||||
expectCode res, 204
|
||||
request.get(baseURL + '/groups/party')
|
||||
.end (err, res) ->
|
||||
expect(res.body.quest.members[leavingMember._id]).to.not.be.ok
|
||||
done()
|
||||
|
||||
xit "Hurts the boss", (done) ->
|
||||
request.post(baseURL + "/user/batch-update").end (err, res) ->
|
||||
user = res.body
|
||||
up = user.party.quest.progress.up
|
||||
expect(up).to.be.above 0
|
||||
|
||||
#{op:'score',params:{direction:'up',id:user.dailys[3].id}}, // leave one daily undone so Trapper hurts party
|
||||
# set day to yesterday, cron will then be triggered on next action
|
||||
request.post(baseURL + "/user/batch-update").send([
|
||||
{
|
||||
op: "score"
|
||||
params:
|
||||
direction: "up"
|
||||
id: user.dailys[0].id
|
||||
}
|
||||
{
|
||||
op: "update"
|
||||
body:
|
||||
lastCron: moment().subtract(1, "days")
|
||||
}
|
||||
]).end (err, res) ->
|
||||
expect(res.body.party.quest.progress.up).to.be.above up
|
||||
request.post(baseURL + "/user/batch-update").end ->
|
||||
request.get(baseURL + "/groups/party").end (err, res) ->
|
||||
|
||||
# Check boss damage
|
||||
async.waterfall [
|
||||
(cb) ->
|
||||
async.parallel [
|
||||
|
||||
#tavern boss
|
||||
(cb2) ->
|
||||
Group.findById "habitrpg",
|
||||
quest: 1
|
||||
, (err, tavern) ->
|
||||
expect(tavern.quest.progress.hp).to.be.below shared.content.quests.dilatory.boss.hp
|
||||
expect(tavern.quest.progress.rage).to.be.above 0
|
||||
cb2()
|
||||
|
||||
# party boss
|
||||
(cb2) ->
|
||||
expect(res.body.quest.progress.hp).to.be.below shared.content.quests.vice3.boss.hp
|
||||
_party = res.body.members
|
||||
expect(_.find(_party,
|
||||
_id: party[0]._id
|
||||
).stats.hp).to.be.below 50
|
||||
expect(_.find(_party,
|
||||
_id: party[1]._id
|
||||
).stats.hp).to.be.below 50
|
||||
expect(_.find(_party,
|
||||
_id: party[2]._id
|
||||
).stats.hp).to.be 50
|
||||
cb2()
|
||||
], cb
|
||||
|
||||
# Kill the boss
|
||||
(whatever, cb) ->
|
||||
async.waterfall [
|
||||
|
||||
# tavern boss
|
||||
(cb2) ->
|
||||
expect(user.items.pets["MantisShrimp-Base"]).to.not.be.ok()
|
||||
Group.update
|
||||
_id: "habitrpg"
|
||||
,
|
||||
$set:
|
||||
"quest.progress.hp": 0
|
||||
, cb2
|
||||
|
||||
# party boss
|
||||
(arg1, arg2, cb2) ->
|
||||
expect(user.items.gear.owned.weapon_special_2).to.not.be.ok()
|
||||
Group.findByIdAndUpdate group._id,
|
||||
$set:
|
||||
"quest.progress.hp": 0
|
||||
, {new: true}
|
||||
, cb2
|
||||
], cb
|
||||
(_group, cb) ->
|
||||
# set day to yesterday, cron will then be triggered on next action
|
||||
request.post(baseURL + "/user/batch-update").send([
|
||||
{
|
||||
op: "score"
|
||||
params:
|
||||
direction: "up"
|
||||
id: user.dailys[1].id
|
||||
}
|
||||
{
|
||||
op: "update"
|
||||
body:
|
||||
lastCron: moment().subtract(1, "days")
|
||||
}
|
||||
]).end ->
|
||||
cb()
|
||||
|
||||
(cb) ->
|
||||
request.post(baseURL + "/user/batch-update").end (err, res) ->
|
||||
cb null, res.body
|
||||
|
||||
(_user, cb) ->
|
||||
|
||||
# need to load the user again, since tavern boss does update after user's cron
|
||||
User.findById _user._id, cb
|
||||
(_user, cb) ->
|
||||
user = _user
|
||||
Group.findById group._id, cb
|
||||
(_group, cb) ->
|
||||
cummExp = shared.content.quests.vice3.drop.exp + shared.content.quests.dilatory.drop.exp
|
||||
cummGp = shared.content.quests.vice3.drop.gp + shared.content.quests.dilatory.drop.gp
|
||||
|
||||
#//FIXME check that user got exp, but user is leveling up making the exp check difficult
|
||||
# expect(user.stats.exp).to.be.above(cummExp);
|
||||
# expect(user.stats.gp).to.be.above(cummGp);
|
||||
async.parallel [
|
||||
|
||||
# Tavern Boss
|
||||
(cb2) ->
|
||||
Group.findById "habitrpg", (err, tavern) ->
|
||||
|
||||
#use an explicit get because mongoose wraps the null in an object
|
||||
expect(_.isEmpty(tavern.get("quest"))).to.equal true
|
||||
expect(user.items.pets["MantisShrimp-Base"]).to.equal 5
|
||||
expect(user.items.mounts["MantisShrimp-Base"]).to.equal true
|
||||
expect(user.items.eggs.Dragon).to.equal 2
|
||||
expect(user.items.hatchingPotions.Shade).to.equal 2
|
||||
cb2()
|
||||
|
||||
# Party Boss
|
||||
(cb2) ->
|
||||
|
||||
#use an explicit get because mongoose wraps the null in an object
|
||||
expect(_.isEmpty(_group.get("quest"))).to.equal true
|
||||
expect(user.items.gear.owned.weapon_special_2).to.equal true
|
||||
expect(user.items.eggs.Dragon).to.equal 2
|
||||
expect(user.items.hatchingPotions.Shade).to.equal 2
|
||||
|
||||
# need to fetch users to get updated data
|
||||
async.parallel [
|
||||
(cb3) ->
|
||||
User.findById party[0].id, (err, mbr) ->
|
||||
expect(mbr.items.gear.owned.weapon_special_2).to.equal true
|
||||
cb3()
|
||||
(cb3) ->
|
||||
User.findById party[1].id, (err, mbr) ->
|
||||
expect(mbr.items.gear.owned.weapon_special_2).to.equal true
|
||||
cb3()
|
||||
(cb3) ->
|
||||
User.findById party[2].id, (err, mbr) ->
|
||||
expect(mbr.items.gear.owned.weapon_special_2).to.not.be.ok()
|
||||
cb3()
|
||||
], cb2
|
||||
], cb
|
||||
], done
|
||||
372
test/api-legacy/party.js
Normal file
372
test/api-legacy/party.js
Normal file
@@ -0,0 +1,372 @@
|
||||
var Group, app, diff;
|
||||
|
||||
diff = require("deep-diff");
|
||||
|
||||
Group = require("../../website/src/models/group").model;
|
||||
|
||||
app = require("../../website/src/server");
|
||||
|
||||
describe("Party", function() {
|
||||
return context("Quests", function() {
|
||||
var group, notParticipating, participating, party;
|
||||
party = void 0;
|
||||
group = void 0;
|
||||
participating = [];
|
||||
notParticipating = [];
|
||||
beforeEach(function(done) {
|
||||
Group.update({
|
||||
_id: "habitrpg"
|
||||
}, {
|
||||
$set: {
|
||||
quest: {
|
||||
key: "dilatory",
|
||||
active: true,
|
||||
progress: {
|
||||
hp: shared.content.quests.dilatory.boss.hp,
|
||||
rage: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}).exec();
|
||||
return async.waterfall([
|
||||
function(cb) {
|
||||
return registerNewUser(cb, true);
|
||||
}, function(user, cb) {
|
||||
return request.post(baseURL + "/groups").send({
|
||||
name: "TestGroup",
|
||||
type: "party"
|
||||
}).end(function(err, res) {
|
||||
expectCode(res, 200);
|
||||
group = res.body;
|
||||
expect(group.members.length).to.equal(1);
|
||||
expect(group.leader).to.equal(user._id);
|
||||
return cb();
|
||||
});
|
||||
}, function(cb) {
|
||||
return request.post(baseURL + '/user/tasks').send({
|
||||
type: 'daily',
|
||||
text: 'daily one'
|
||||
}).end(function(err, res) {
|
||||
return cb();
|
||||
});
|
||||
}, function(cb) {
|
||||
return request.post(baseURL + '/user/tasks').send({
|
||||
type: 'daily',
|
||||
text: 'daily two'
|
||||
}).end(function(err, res) {
|
||||
return cb();
|
||||
});
|
||||
}, function(cb) {
|
||||
return User.findByIdAndUpdate(user._id, {
|
||||
$set: {
|
||||
"stats.lvl": 50
|
||||
}
|
||||
}, {
|
||||
"new": true
|
||||
}, function(err, _user) {
|
||||
return cb(null, _user);
|
||||
});
|
||||
}, function(_user, cb) {
|
||||
var user;
|
||||
user = _user;
|
||||
return request.post(baseURL + "/user/batch-update").send([
|
||||
{
|
||||
op: "score",
|
||||
params: {
|
||||
direction: "up",
|
||||
id: user.dailys[0].id
|
||||
}
|
||||
}, {
|
||||
op: "score",
|
||||
params: {
|
||||
direction: "up",
|
||||
id: user.dailys[0].id
|
||||
}
|
||||
}, {
|
||||
op: "update",
|
||||
body: {
|
||||
"stats.lvl": 50
|
||||
}
|
||||
}
|
||||
]).end(function(err, res) {
|
||||
user = res.body;
|
||||
expect(user.party.quest.progress.up).to.be.above(0);
|
||||
return async.waterfall([
|
||||
function(cb) {
|
||||
return registerManyUsers(3, cb);
|
||||
}, function(_party, cb) {
|
||||
var inviteURL;
|
||||
party = _party;
|
||||
inviteURL = baseURL + "/groups/" + group._id + "/invite";
|
||||
return async.parallel([
|
||||
function(cb2) {
|
||||
return request.post(inviteURL).send({
|
||||
uuids: [party[0]._id]
|
||||
}).end(function() {
|
||||
return cb2();
|
||||
});
|
||||
}, function(cb2) {
|
||||
return request.post(inviteURL).send({
|
||||
uuids: [party[1]._id]
|
||||
}).end(function() {
|
||||
return cb2();
|
||||
});
|
||||
}, function(cb2) {
|
||||
return request.post(inviteURL).send({
|
||||
uuids: [party[2]._id]
|
||||
}).end(function(err, res) {
|
||||
return cb2();
|
||||
});
|
||||
}
|
||||
], cb);
|
||||
}, function(results, cb) {
|
||||
var series;
|
||||
series = _.reduce(party, function(m, v, i) {
|
||||
m.push(function(cb2) {
|
||||
return request.post(baseURL + "/groups/" + group._id + "/join").set("X-API-User", party[i]._id).set("X-API-Key", party[i].apiToken).end(function() {
|
||||
return cb2();
|
||||
});
|
||||
});
|
||||
return m;
|
||||
}, []);
|
||||
return async.series(series, cb);
|
||||
}, function(whatever, cb) {
|
||||
return Group.findById(group._id, function(err, g) {
|
||||
group = g;
|
||||
expect(g.members.length).to.equal(4);
|
||||
return cb();
|
||||
});
|
||||
}
|
||||
], function() {
|
||||
return async.waterfall([
|
||||
function(cb) {
|
||||
return request.post(baseURL + "/groups/" + group._id + "/questAccept?key=vice3").end(function(err, res) {
|
||||
expectCode(res, 400);
|
||||
return User.findByIdAndUpdate(user._id, {
|
||||
$set: {
|
||||
"items.quests.vice3": 1
|
||||
}
|
||||
}, {
|
||||
"new": true
|
||||
}, cb);
|
||||
});
|
||||
}, function(_user, cb) {
|
||||
return request.post(baseURL + "/groups/" + group._id + "/questAccept?key=vice3").end(function(err, res) {
|
||||
expectCode(res, 200);
|
||||
return Group.findById(group._id, cb);
|
||||
});
|
||||
}, function(_group, cb) {
|
||||
expect(_group.quest.key).to.equal("vice3");
|
||||
expect(_group.quest.active).to.equal(false);
|
||||
return request.post(baseURL + "/groups/" + group._id + "/questAccept").set("X-API-User", party[0]._id).set("X-API-Key", party[0].apiToken).end(function() {
|
||||
return request.post(baseURL + "/groups/" + group._id + "/questAccept").set("X-API-User", party[1]._id).set("X-API-Key", party[1].apiToken).end(function(err, res) {
|
||||
return request.post(baseURL + "/groups/" + group._id + "/questReject").set("X-API-User", party[2]._id).set("X-API-Key", party[2].apiToken).end(function(err, res) {
|
||||
group = res.body;
|
||||
expect(group.quest.active).to.equal(true);
|
||||
return cb();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
], done);
|
||||
});
|
||||
});
|
||||
}
|
||||
]);
|
||||
});
|
||||
it("Casts a spell", function(done) {
|
||||
var mp;
|
||||
mp = user.stats.mp;
|
||||
return request.get(baseURL + "/members/" + party[0]._id).end(function(err, res) {
|
||||
party[0] = res.body;
|
||||
return request.post(baseURL + "/user/class/cast/snowball?targetType=user&targetId=" + party[0]._id).end(function(err, res) {
|
||||
return request.get(baseURL + "/members/" + party[0]._id).end(function(err, res) {
|
||||
var difference, member;
|
||||
member = res.body;
|
||||
expect(member.achievements.snowball).to.equal(1);
|
||||
expect(member.stats.buffs.snowball).to.exist;
|
||||
difference = diff(member, party[0]);
|
||||
expect(_.size(difference)).to.equal(2);
|
||||
return request.put(baseURL + "/user").send({
|
||||
"stats.lvl": 5
|
||||
}).end(function(err, res) {
|
||||
return request.put(baseURL + "/user").send({
|
||||
"stats.mp": 100
|
||||
}).end(function(err, res) {
|
||||
return request.post(baseURL + "/user/class/cast/valorousPresence?targetType=party").end(function(err, res) {
|
||||
return request.get(baseURL + "/members/" + member._id).end(function(err, res) {
|
||||
expect(res.body.stats.buffs.str).to.be.above(0);
|
||||
expect(diff(res.body, member).length).to.equal(1);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
it("Doesn't include people who aren't participating", function(done) {
|
||||
return request.get(baseURL + "/groups/" + group._id).end(function(err, res) {
|
||||
expect(_.size(res.body.quest.members)).to.equal(3);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
it("allows quest participants to leave quest", function(done) {
|
||||
var leavingMember;
|
||||
leavingMember = party[1];
|
||||
expect(group.quest.members[leavingMember._id]).to.eql(true);
|
||||
return request.post(baseURL + "/groups/" + group._id + "/questLeave").set("X-API-User", leavingMember._id).set("X-API-Key", leavingMember.apiToken).end(function(err, res) {
|
||||
expectCode(res, 204);
|
||||
return request.get(baseURL + '/groups/party').end(function(err, res) {
|
||||
expect(res.body.quest.members[leavingMember._id]).to.not.be.ok;
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
return xit("Hurts the boss", function(done) {
|
||||
return request.post(baseURL + "/user/batch-update").end(function(err, res) {
|
||||
var up, user;
|
||||
user = res.body;
|
||||
up = user.party.quest.progress.up;
|
||||
expect(up).to.be.above(0);
|
||||
return request.post(baseURL + "/user/batch-update").send([
|
||||
{
|
||||
op: "score",
|
||||
params: {
|
||||
direction: "up",
|
||||
id: user.dailys[0].id
|
||||
}
|
||||
}, {
|
||||
op: "update",
|
||||
body: {
|
||||
lastCron: moment().subtract(1, "days")
|
||||
}
|
||||
}
|
||||
]).end(function(err, res) {
|
||||
expect(res.body.party.quest.progress.up).to.be.above(up);
|
||||
return request.post(baseURL + "/user/batch-update").end(function() {
|
||||
return request.get(baseURL + "/groups/party").end(function(err, res) {
|
||||
return async.waterfall([
|
||||
function(cb) {
|
||||
return async.parallel([
|
||||
function(cb2) {
|
||||
return Group.findById("habitrpg", {
|
||||
quest: 1
|
||||
}, function(err, tavern) {
|
||||
expect(tavern.quest.progress.hp).to.be.below(shared.content.quests.dilatory.boss.hp);
|
||||
expect(tavern.quest.progress.rage).to.be.above(0);
|
||||
return cb2();
|
||||
});
|
||||
}, function(cb2) {
|
||||
var _party;
|
||||
expect(res.body.quest.progress.hp).to.be.below(shared.content.quests.vice3.boss.hp);
|
||||
_party = res.body.members;
|
||||
expect(_.find(_party, {
|
||||
_id: party[0]._id
|
||||
}).stats.hp).to.be.below(50);
|
||||
expect(_.find(_party, {
|
||||
_id: party[1]._id
|
||||
}).stats.hp).to.be.below(50);
|
||||
expect(_.find(_party, {
|
||||
_id: party[2]._id
|
||||
}).stats.hp).to.be(50);
|
||||
return cb2();
|
||||
}
|
||||
], cb);
|
||||
}, function(whatever, cb) {
|
||||
return async.waterfall([
|
||||
function(cb2) {
|
||||
expect(user.items.pets["MantisShrimp-Base"]).to.not.be.ok();
|
||||
return Group.update({
|
||||
_id: "habitrpg"
|
||||
}, {
|
||||
$set: {
|
||||
"quest.progress.hp": 0
|
||||
}
|
||||
}, cb2);
|
||||
}, function(arg1, arg2, cb2) {
|
||||
expect(user.items.gear.owned.weapon_special_2).to.not.be.ok();
|
||||
return Group.findByIdAndUpdate(group._id, {
|
||||
$set: {
|
||||
"quest.progress.hp": 0
|
||||
}
|
||||
}, {
|
||||
"new": true
|
||||
}, cb2);
|
||||
}
|
||||
], cb);
|
||||
}, function(_group, cb) {
|
||||
return request.post(baseURL + "/user/batch-update").send([
|
||||
{
|
||||
op: "score",
|
||||
params: {
|
||||
direction: "up",
|
||||
id: user.dailys[1].id
|
||||
}
|
||||
}, {
|
||||
op: "update",
|
||||
body: {
|
||||
lastCron: moment().subtract(1, "days")
|
||||
}
|
||||
}
|
||||
]).end(function() {
|
||||
return cb();
|
||||
});
|
||||
}, function(cb) {
|
||||
return request.post(baseURL + "/user/batch-update").end(function(err, res) {
|
||||
return cb(null, res.body);
|
||||
});
|
||||
}, function(_user, cb) {
|
||||
return User.findById(_user._id, cb);
|
||||
}, function(_user, cb) {
|
||||
user = _user;
|
||||
return Group.findById(group._id, cb);
|
||||
}, function(_group, cb) {
|
||||
var cummExp, cummGp;
|
||||
cummExp = shared.content.quests.vice3.drop.exp + shared.content.quests.dilatory.drop.exp;
|
||||
cummGp = shared.content.quests.vice3.drop.gp + shared.content.quests.dilatory.drop.gp;
|
||||
return async.parallel([
|
||||
function(cb2) {
|
||||
return Group.findById("habitrpg", function(err, tavern) {
|
||||
expect(_.isEmpty(tavern.get("quest"))).to.equal(true);
|
||||
expect(user.items.pets["MantisShrimp-Base"]).to.equal(5);
|
||||
expect(user.items.mounts["MantisShrimp-Base"]).to.equal(true);
|
||||
expect(user.items.eggs.Dragon).to.equal(2);
|
||||
expect(user.items.hatchingPotions.Shade).to.equal(2);
|
||||
return cb2();
|
||||
});
|
||||
}, function(cb2) {
|
||||
expect(_.isEmpty(_group.get("quest"))).to.equal(true);
|
||||
expect(user.items.gear.owned.weapon_special_2).to.equal(true);
|
||||
expect(user.items.eggs.Dragon).to.equal(2);
|
||||
expect(user.items.hatchingPotions.Shade).to.equal(2);
|
||||
return async.parallel([
|
||||
function(cb3) {
|
||||
return User.findById(party[0].id, function(err, mbr) {
|
||||
expect(mbr.items.gear.owned.weapon_special_2).to.equal(true);
|
||||
return cb3();
|
||||
});
|
||||
}, function(cb3) {
|
||||
return User.findById(party[1].id, function(err, mbr) {
|
||||
expect(mbr.items.gear.owned.weapon_special_2).to.equal(true);
|
||||
return cb3();
|
||||
});
|
||||
}, function(cb3) {
|
||||
return User.findById(party[2].id, function(err, mbr) {
|
||||
expect(mbr.items.gear.owned.weapon_special_2).to.not.be.ok();
|
||||
return cb3();
|
||||
});
|
||||
}
|
||||
], cb2);
|
||||
}
|
||||
], cb);
|
||||
}
|
||||
], done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,346 +0,0 @@
|
||||
'use strict'
|
||||
#@TODO: Have to mock most things to get to the parts that
|
||||
#call pushNotify. Consider refactoring group controller
|
||||
#so things are easier to test
|
||||
|
||||
app = require("../../website/src/server")
|
||||
rewire = require('rewire')
|
||||
sinon = require('sinon')
|
||||
|
||||
describe "Push-Notifications", ->
|
||||
before (done) ->
|
||||
registerNewUser(done, true)
|
||||
|
||||
describe "Events that send push notifications", ->
|
||||
pushSpy = { sendNotify: sinon.spy() }
|
||||
|
||||
afterEach (done) ->
|
||||
pushSpy.sendNotify.reset()
|
||||
done()
|
||||
|
||||
context "Challenges", ->
|
||||
challenges = rewire("../../website/src/controllers/api-v2/challenges")
|
||||
challenges.__set__('pushNotify', pushSpy)
|
||||
challengeMock = {
|
||||
findById: (arg, cb) ->
|
||||
cb(null, {leader: user._id, name: 'challenge-name'})
|
||||
}
|
||||
userMock = {
|
||||
findById: (arg, cb) ->
|
||||
cb(null, user)
|
||||
}
|
||||
|
||||
challenges.__set__('Challenge', challengeMock)
|
||||
challenges.__set__('User', userMock)
|
||||
challenges.__set__('closeChal', -> true)
|
||||
|
||||
beforeEach (done) ->
|
||||
registerNewUser ->
|
||||
user.preferences.emailNotifications.wonChallenge = false
|
||||
user.save = (cb) -> cb(null, user)
|
||||
done()
|
||||
, true
|
||||
|
||||
it "sends a push notification when you win a challenge", (done) ->
|
||||
req = {
|
||||
params: { cid: 'challenge-id' }
|
||||
query: {uid: 'user-id'}
|
||||
}
|
||||
res = {
|
||||
locals: { user: user }
|
||||
}
|
||||
challenges.selectWinner req, res
|
||||
|
||||
setTimeout -> # Allow selectWinner to finish
|
||||
expect(pushSpy.sendNotify).to.have.been.calledOnce
|
||||
expect(pushSpy.sendNotify).to.have.been.calledWith(
|
||||
user,
|
||||
'You won a Challenge!',
|
||||
'challenge-name'
|
||||
)
|
||||
done()
|
||||
, 100
|
||||
|
||||
context "Groups", ->
|
||||
|
||||
recipient = null
|
||||
|
||||
groups = rewire("../../website/src/controllers/api-v2/groups")
|
||||
groups.__set__('pushNotify', pushSpy)
|
||||
|
||||
before (done) ->
|
||||
registerNewUser (err,_user)->
|
||||
recipient = _user
|
||||
recipient.invitations.guilds = []
|
||||
recipient.save = (cb) -> cb(null, recipient)
|
||||
recipient.preferences.emailNotifications.invitedGuild = false
|
||||
recipient.preferences.emailNotifications.invitedParty = false
|
||||
recipient.preferences.emailNotifications.invitedQuest = false
|
||||
userMock = {
|
||||
findById: (arg, cb) ->
|
||||
cb(null, recipient)
|
||||
find: (arg, arg2, cb) ->
|
||||
cb(null, [recipient])
|
||||
update: (arg, arg2) ->
|
||||
{ exec: -> true}
|
||||
}
|
||||
groups.__set__('User', userMock)
|
||||
done()
|
||||
|
||||
, false
|
||||
|
||||
it "sends a push notification when invited to a guild", (done) ->
|
||||
group = { _id: 'guild-id', name: 'guild-name', type: 'guild', members: [user._id], invites: [] }
|
||||
group.save = (cb) -> cb(null, group)
|
||||
req = {
|
||||
body: { uuids: [recipient._id] }
|
||||
}
|
||||
res = {
|
||||
locals: { group: group, user: user }
|
||||
json: -> return true
|
||||
}
|
||||
|
||||
groups.invite req, res
|
||||
|
||||
setTimeout -> # Allow invite to finish
|
||||
expect(pushSpy.sendNotify).to.have.been.calledOnce
|
||||
expect(pushSpy.sendNotify).to.have.been.calledWith(
|
||||
recipient,
|
||||
'Invited To Guild',
|
||||
group.name
|
||||
)
|
||||
done()
|
||||
, 100
|
||||
|
||||
it "sends a push notification when invited to a party", (done) ->
|
||||
group = { _id: 'party-id', name: 'party-name', type: 'party', members: [user._id], invites: [] }
|
||||
group.save = (cb) -> cb(null, group)
|
||||
req = {
|
||||
body: { uuids: [recipient._id] }
|
||||
}
|
||||
res = {
|
||||
locals: { group: group, user: user }
|
||||
json: -> return true
|
||||
}
|
||||
|
||||
groups.invite req, res
|
||||
|
||||
setTimeout -> # Allow invite to finish
|
||||
expect(pushSpy.sendNotify).to.have.been.calledOnce
|
||||
expect(pushSpy.sendNotify).to.have.been.calledWith(
|
||||
recipient,
|
||||
'Invited To Party',
|
||||
group.name
|
||||
)
|
||||
done()
|
||||
, 100
|
||||
|
||||
it "sends a push notification when invited to a quest", (done) ->
|
||||
group = { _id: 'party-id', name: 'party-name', type: 'party', members: [user._id, recipient._id], invites: [], quest: {}}
|
||||
user.items.quests.hedgehog = 5
|
||||
group.save = (cb) -> cb(null, group)
|
||||
group.markModified = -> true
|
||||
req = {
|
||||
body: { uuids: [recipient._id] }
|
||||
query: { key: 'hedgehog' }
|
||||
}
|
||||
res = {
|
||||
locals: { group: group, user: user }
|
||||
json: -> return true
|
||||
}
|
||||
|
||||
groups.questAccept req, res
|
||||
|
||||
setTimeout -> # Allow questAccept to finish
|
||||
expect(pushSpy.sendNotify).to.have.been.calledOnce
|
||||
expect(pushSpy.sendNotify).to.have.been.calledWith(
|
||||
recipient,
|
||||
'Quest Invitation',
|
||||
'Invitation for the Quest The Hedgebeast'
|
||||
)
|
||||
done()
|
||||
, 100
|
||||
|
||||
it "sends a push notification to participating members when quest starts", (done) ->
|
||||
group = { _id: 'party-id', name: 'party-name', type: 'party', members: [user._id, recipient._id], invites: []}
|
||||
group.quest = {
|
||||
key: 'hedgehog'
|
||||
progress: { hp: 100 }
|
||||
members: {}
|
||||
}
|
||||
group.quest.members[recipient._id] = true
|
||||
group.save = (cb) -> cb(null, group)
|
||||
group.markModified = -> true
|
||||
req = {
|
||||
body: { uuids: [recipient._id] }
|
||||
query: { }
|
||||
# force: true
|
||||
}
|
||||
res = {
|
||||
locals: { group: group, user: user }
|
||||
json: -> return true
|
||||
}
|
||||
userMock = {
|
||||
findOne: (arg, arg2, cb) ->
|
||||
cb(null, recipient)
|
||||
update: (arg, arg2, cb) ->
|
||||
if (cb)
|
||||
return cb(null, user)
|
||||
else
|
||||
return {
|
||||
exec: -> true
|
||||
}
|
||||
}
|
||||
groups.__set__('User', userMock)
|
||||
groups.__set__('populateQuery',
|
||||
(arg, arg2, arg3) ->
|
||||
return {
|
||||
exec: -> group.members
|
||||
}
|
||||
)
|
||||
|
||||
groups.questAccept req, res
|
||||
|
||||
setTimeout -> # Allow questAccept to finish
|
||||
expect(pushSpy.sendNotify).to.have.been.calledTwice
|
||||
expect(pushSpy.sendNotify).to.have.been.calledWith(
|
||||
recipient,
|
||||
'HabitRPG',
|
||||
'Your Quest has Begun: The Hedgebeast'
|
||||
)
|
||||
done()
|
||||
, 100
|
||||
|
||||
describe "Gifts", ->
|
||||
|
||||
recipient = null
|
||||
|
||||
before (done) ->
|
||||
registerNewUser (err, _user) ->
|
||||
recipient = _user
|
||||
recipient.preferences.emailNotifications.giftedGems = false
|
||||
user.balance = 4
|
||||
user.save = -> return true
|
||||
recipient.save = -> return true
|
||||
done()
|
||||
, false
|
||||
|
||||
context "sending gems from balance", ->
|
||||
members = rewire("../../website/src/controllers/api-v2/members")
|
||||
members.sendMessage = -> true
|
||||
|
||||
members.__set__('pushNotify', pushSpy)
|
||||
members.__set__ 'fetchMember', (id) ->
|
||||
return (cb) -> cb(null, recipient)
|
||||
|
||||
it "sends a push notification", (done) ->
|
||||
req = {
|
||||
params: { uuid: "uuid" },
|
||||
body: {
|
||||
type: 'gems',
|
||||
gems: { amount: 1 }
|
||||
}
|
||||
}
|
||||
res = { locals: { user: user } }
|
||||
|
||||
members.sendGift req, res
|
||||
|
||||
setTimeout -> # Allow sendGift to finish
|
||||
expect(pushSpy.sendNotify).to.have.been.calledOnce
|
||||
expect(pushSpy.sendNotify).to.have.been.calledWith(
|
||||
recipient,
|
||||
'Gifted Gems',
|
||||
'1 Gems - by ' + user.profile.name
|
||||
)
|
||||
done()
|
||||
, 100
|
||||
|
||||
describe "Purchases", ->
|
||||
|
||||
payments = rewire("../../website/src/controllers/payments")
|
||||
|
||||
payments.__set__('pushNotify', pushSpy)
|
||||
membersMock = { sendMessage: -> true }
|
||||
payments.__set__('members', membersMock)
|
||||
|
||||
context "buying gems as a purchased gift", ->
|
||||
|
||||
it "sends a push notification", (done) ->
|
||||
data = {
|
||||
user: user,
|
||||
gift: {
|
||||
member: recipient,
|
||||
gems: { amount: 1 }
|
||||
}
|
||||
}
|
||||
|
||||
payments.buyGems data
|
||||
|
||||
setTimeout -> # Allow buyGems to finish
|
||||
expect(pushSpy.sendNotify).to.have.been.calledOnce
|
||||
expect(pushSpy.sendNotify).to.have.been.calledWith(
|
||||
recipient,
|
||||
'Gifted Gems',
|
||||
'1 Gems - by ' + user.profile.name
|
||||
)
|
||||
|
||||
done()
|
||||
, 100
|
||||
|
||||
it "does not send a push notification if buying gems for self", (done) ->
|
||||
data = {
|
||||
user: user,
|
||||
gift: {
|
||||
member: user
|
||||
gems: { amount: 1 }
|
||||
}
|
||||
}
|
||||
|
||||
payments.buyGems data
|
||||
|
||||
setTimeout -> # Allow buyGems to finish
|
||||
expect(pushSpy.sendNotify).to.not.have.been.called
|
||||
|
||||
done()
|
||||
, 100
|
||||
|
||||
context "sending a subscription as a purchased gift", ->
|
||||
|
||||
it "sends a push notification", (done) ->
|
||||
data = {
|
||||
user: user,
|
||||
gift: {
|
||||
member: recipient
|
||||
subscription: { key: 'basic_6mo' }
|
||||
}
|
||||
}
|
||||
|
||||
payments.createSubscription data
|
||||
|
||||
setTimeout -> # Allow createSubscription to finish
|
||||
expect(pushSpy.sendNotify).to.have.been.calledOnce
|
||||
expect(pushSpy.sendNotify).to.have.been.calledWith(
|
||||
recipient,
|
||||
'Gifted Subscription',
|
||||
'6 months - by ' + user.profile.name
|
||||
)
|
||||
|
||||
done()
|
||||
, 100
|
||||
|
||||
it "does not send a push notification if buying subscription for self", (done) ->
|
||||
data = {
|
||||
user: user,
|
||||
gift: {
|
||||
member: user
|
||||
subscription: { key: 'basic_6mo' }
|
||||
}
|
||||
}
|
||||
|
||||
payments.createSubscription data
|
||||
|
||||
setTimeout -> # Allow buyGems to finish
|
||||
expect(pushSpy.sendNotify).to.not.have.been.called
|
||||
|
||||
done()
|
||||
, 100
|
||||
430
test/api-legacy/pushNotifications.js
Normal file
430
test/api-legacy/pushNotifications.js
Normal file
@@ -0,0 +1,430 @@
|
||||
var app, rewire, sinon;
|
||||
|
||||
app = require("../../website/src/server");
|
||||
|
||||
rewire = require('rewire');
|
||||
|
||||
sinon = require('sinon');
|
||||
|
||||
describe("Push-Notifications", function() {
|
||||
before(function(done) {
|
||||
return registerNewUser(done, true);
|
||||
});
|
||||
return describe("Events that send push notifications", function() {
|
||||
var pushSpy;
|
||||
pushSpy = {
|
||||
sendNotify: sinon.spy()
|
||||
};
|
||||
afterEach(function(done) {
|
||||
pushSpy.sendNotify.reset();
|
||||
return done();
|
||||
});
|
||||
context("Challenges", function() {
|
||||
var challengeMock, challenges, userMock;
|
||||
challenges = rewire("../../website/src/controllers/api-v2/challenges");
|
||||
challenges.__set__('pushNotify', pushSpy);
|
||||
challengeMock = {
|
||||
findById: function(arg, cb) {
|
||||
return cb(null, {
|
||||
leader: user._id,
|
||||
name: 'challenge-name'
|
||||
});
|
||||
}
|
||||
};
|
||||
userMock = {
|
||||
findById: function(arg, cb) {
|
||||
return cb(null, user);
|
||||
}
|
||||
};
|
||||
challenges.__set__('Challenge', challengeMock);
|
||||
challenges.__set__('User', userMock);
|
||||
challenges.__set__('closeChal', function() {
|
||||
return true;
|
||||
});
|
||||
beforeEach(function(done) {
|
||||
return registerNewUser(function() {
|
||||
user.preferences.emailNotifications.wonChallenge = false;
|
||||
user.save = function(cb) {
|
||||
return cb(null, user);
|
||||
};
|
||||
return done();
|
||||
}, true);
|
||||
});
|
||||
return it("sends a push notification when you win a challenge", function(done) {
|
||||
var req, res;
|
||||
req = {
|
||||
params: {
|
||||
cid: 'challenge-id'
|
||||
},
|
||||
query: {
|
||||
uid: 'user-id'
|
||||
}
|
||||
};
|
||||
res = {
|
||||
locals: {
|
||||
user: user
|
||||
}
|
||||
};
|
||||
challenges.selectWinner(req, res);
|
||||
return setTimeout(function() {
|
||||
expect(pushSpy.sendNotify).to.have.been.calledOnce;
|
||||
expect(pushSpy.sendNotify).to.have.been.calledWith(user, 'You won a Challenge!', 'challenge-name');
|
||||
return done();
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
context("Groups", function() {
|
||||
var groups, recipient;
|
||||
recipient = null;
|
||||
groups = rewire("../../website/src/controllers/api-v2/groups");
|
||||
groups.__set__('pushNotify', pushSpy);
|
||||
before(function(done) {
|
||||
return registerNewUser(function(err, _user) {
|
||||
var userMock;
|
||||
recipient = _user;
|
||||
recipient.invitations.guilds = [];
|
||||
recipient.save = function(cb) {
|
||||
return cb(null, recipient);
|
||||
};
|
||||
recipient.preferences.emailNotifications.invitedGuild = false;
|
||||
recipient.preferences.emailNotifications.invitedParty = false;
|
||||
recipient.preferences.emailNotifications.invitedQuest = false;
|
||||
userMock = {
|
||||
findById: function(arg, cb) {
|
||||
return cb(null, recipient);
|
||||
},
|
||||
find: function(arg, arg2, cb) {
|
||||
return cb(null, [recipient]);
|
||||
},
|
||||
update: function(arg, arg2) {
|
||||
return {
|
||||
exec: function() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
groups.__set__('User', userMock);
|
||||
return done();
|
||||
}, false);
|
||||
});
|
||||
it("sends a push notification when invited to a guild", function(done) {
|
||||
var group, req, res;
|
||||
group = {
|
||||
_id: 'guild-id',
|
||||
name: 'guild-name',
|
||||
type: 'guild',
|
||||
members: [user._id],
|
||||
invites: []
|
||||
};
|
||||
group.save = function(cb) {
|
||||
return cb(null, group);
|
||||
};
|
||||
req = {
|
||||
body: {
|
||||
uuids: [recipient._id]
|
||||
}
|
||||
};
|
||||
res = {
|
||||
locals: {
|
||||
group: group,
|
||||
user: user
|
||||
},
|
||||
json: function() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
groups.invite(req, res);
|
||||
return setTimeout(function() {
|
||||
expect(pushSpy.sendNotify).to.have.been.calledOnce;
|
||||
expect(pushSpy.sendNotify).to.have.been.calledWith(recipient, 'Invited To Guild', group.name);
|
||||
return done();
|
||||
}, 100);
|
||||
});
|
||||
it("sends a push notification when invited to a party", function(done) {
|
||||
var group, req, res;
|
||||
group = {
|
||||
_id: 'party-id',
|
||||
name: 'party-name',
|
||||
type: 'party',
|
||||
members: [user._id],
|
||||
invites: []
|
||||
};
|
||||
group.save = function(cb) {
|
||||
return cb(null, group);
|
||||
};
|
||||
req = {
|
||||
body: {
|
||||
uuids: [recipient._id]
|
||||
}
|
||||
};
|
||||
res = {
|
||||
locals: {
|
||||
group: group,
|
||||
user: user
|
||||
},
|
||||
json: function() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
groups.invite(req, res);
|
||||
return setTimeout(function() {
|
||||
expect(pushSpy.sendNotify).to.have.been.calledOnce;
|
||||
expect(pushSpy.sendNotify).to.have.been.calledWith(recipient, 'Invited To Party', group.name);
|
||||
return done();
|
||||
}, 100);
|
||||
});
|
||||
it("sends a push notification when invited to a quest", function(done) {
|
||||
var group, req, res;
|
||||
group = {
|
||||
_id: 'party-id',
|
||||
name: 'party-name',
|
||||
type: 'party',
|
||||
members: [user._id, recipient._id],
|
||||
invites: [],
|
||||
quest: {}
|
||||
};
|
||||
user.items.quests.hedgehog = 5;
|
||||
group.save = function(cb) {
|
||||
return cb(null, group);
|
||||
};
|
||||
group.markModified = function() {
|
||||
return true;
|
||||
};
|
||||
req = {
|
||||
body: {
|
||||
uuids: [recipient._id]
|
||||
},
|
||||
query: {
|
||||
key: 'hedgehog'
|
||||
}
|
||||
};
|
||||
res = {
|
||||
locals: {
|
||||
group: group,
|
||||
user: user
|
||||
},
|
||||
json: function() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
groups.questAccept(req, res);
|
||||
return setTimeout(function() {
|
||||
expect(pushSpy.sendNotify).to.have.been.calledOnce;
|
||||
expect(pushSpy.sendNotify).to.have.been.calledWith(recipient, 'Quest Invitation', 'Invitation for the Quest The Hedgebeast');
|
||||
return done();
|
||||
}, 100);
|
||||
});
|
||||
return it("sends a push notification to participating members when quest starts", function(done) {
|
||||
var group, req, res, userMock;
|
||||
group = {
|
||||
_id: 'party-id',
|
||||
name: 'party-name',
|
||||
type: 'party',
|
||||
members: [user._id, recipient._id],
|
||||
invites: []
|
||||
};
|
||||
group.quest = {
|
||||
key: 'hedgehog',
|
||||
progress: {
|
||||
hp: 100
|
||||
},
|
||||
members: {}
|
||||
};
|
||||
group.quest.members[recipient._id] = true;
|
||||
group.save = function(cb) {
|
||||
return cb(null, group);
|
||||
};
|
||||
group.markModified = function() {
|
||||
return true;
|
||||
};
|
||||
req = {
|
||||
body: {
|
||||
uuids: [recipient._id]
|
||||
},
|
||||
query: {}
|
||||
};
|
||||
res = {
|
||||
locals: {
|
||||
group: group,
|
||||
user: user
|
||||
},
|
||||
json: function() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
userMock = {
|
||||
findOne: function(arg, arg2, cb) {
|
||||
return cb(null, recipient);
|
||||
},
|
||||
update: function(arg, arg2, cb) {
|
||||
if (cb) {
|
||||
return cb(null, user);
|
||||
} else {
|
||||
return {
|
||||
exec: function() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
groups.__set__('User', userMock);
|
||||
groups.__set__('populateQuery', function(arg, arg2, arg3) {
|
||||
return {
|
||||
exec: function() {
|
||||
return group.members;
|
||||
}
|
||||
};
|
||||
});
|
||||
groups.questAccept(req, res);
|
||||
return setTimeout(function() {
|
||||
expect(pushSpy.sendNotify).to.have.been.calledTwice;
|
||||
expect(pushSpy.sendNotify).to.have.been.calledWith(recipient, 'HabitRPG', 'Your Quest has Begun: The Hedgebeast');
|
||||
return done();
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
return describe("Gifts", function() {
|
||||
var recipient;
|
||||
recipient = null;
|
||||
before(function(done) {
|
||||
return registerNewUser(function(err, _user) {
|
||||
recipient = _user;
|
||||
recipient.preferences.emailNotifications.giftedGems = false;
|
||||
user.balance = 4;
|
||||
user.save = function() {
|
||||
return true;
|
||||
};
|
||||
recipient.save = function() {
|
||||
return true;
|
||||
};
|
||||
return done();
|
||||
}, false);
|
||||
});
|
||||
context("sending gems from balance", function() {
|
||||
var members;
|
||||
members = rewire("../../website/src/controllers/api-v2/members");
|
||||
members.sendMessage = function() {
|
||||
return true;
|
||||
};
|
||||
members.__set__('pushNotify', pushSpy);
|
||||
members.__set__('fetchMember', function(id) {
|
||||
return function(cb) {
|
||||
return cb(null, recipient);
|
||||
};
|
||||
});
|
||||
return it("sends a push notification", function(done) {
|
||||
var req, res;
|
||||
req = {
|
||||
params: {
|
||||
uuid: "uuid"
|
||||
},
|
||||
body: {
|
||||
type: 'gems',
|
||||
gems: {
|
||||
amount: 1
|
||||
}
|
||||
}
|
||||
};
|
||||
res = {
|
||||
locals: {
|
||||
user: user
|
||||
}
|
||||
};
|
||||
members.sendGift(req, res);
|
||||
return setTimeout(function() {
|
||||
expect(pushSpy.sendNotify).to.have.been.calledOnce;
|
||||
expect(pushSpy.sendNotify).to.have.been.calledWith(recipient, 'Gifted Gems', '1 Gems - by ' + user.profile.name);
|
||||
return done();
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
return describe("Purchases", function() {
|
||||
var membersMock, payments;
|
||||
payments = rewire("../../website/src/controllers/payments");
|
||||
payments.__set__('pushNotify', pushSpy);
|
||||
membersMock = {
|
||||
sendMessage: function() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
payments.__set__('members', membersMock);
|
||||
context("buying gems as a purchased gift", function() {
|
||||
it("sends a push notification", function(done) {
|
||||
var data;
|
||||
data = {
|
||||
user: user,
|
||||
gift: {
|
||||
member: recipient,
|
||||
gems: {
|
||||
amount: 1
|
||||
}
|
||||
}
|
||||
};
|
||||
payments.buyGems(data);
|
||||
return setTimeout(function() {
|
||||
expect(pushSpy.sendNotify).to.have.been.calledOnce;
|
||||
expect(pushSpy.sendNotify).to.have.been.calledWith(recipient, 'Gifted Gems', '1 Gems - by ' + user.profile.name);
|
||||
return done();
|
||||
}, 100);
|
||||
});
|
||||
return it("does not send a push notification if buying gems for self", function(done) {
|
||||
var data;
|
||||
data = {
|
||||
user: user,
|
||||
gift: {
|
||||
member: user,
|
||||
gems: {
|
||||
amount: 1
|
||||
}
|
||||
}
|
||||
};
|
||||
payments.buyGems(data);
|
||||
return setTimeout(function() {
|
||||
expect(pushSpy.sendNotify).to.not.have.been.called;
|
||||
return done();
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
return context("sending a subscription as a purchased gift", function() {
|
||||
it("sends a push notification", function(done) {
|
||||
var data;
|
||||
data = {
|
||||
user: user,
|
||||
gift: {
|
||||
member: recipient,
|
||||
subscription: {
|
||||
key: 'basic_6mo'
|
||||
}
|
||||
}
|
||||
};
|
||||
payments.createSubscription(data);
|
||||
return setTimeout(function() {
|
||||
expect(pushSpy.sendNotify).to.have.been.calledOnce;
|
||||
expect(pushSpy.sendNotify).to.have.been.calledWith(recipient, 'Gifted Subscription', '6 months - by ' + user.profile.name);
|
||||
return done();
|
||||
}, 100);
|
||||
});
|
||||
return it("does not send a push notification if buying subscription for self", function(done) {
|
||||
var data;
|
||||
data = {
|
||||
user: user,
|
||||
gift: {
|
||||
member: user,
|
||||
subscription: {
|
||||
key: 'basic_6mo'
|
||||
}
|
||||
}
|
||||
};
|
||||
payments.createSubscription(data);
|
||||
return setTimeout(function() {
|
||||
expect(pushSpy.sendNotify).to.not.have.been.called;
|
||||
return done();
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,114 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
require("../../website/src/server")
|
||||
|
||||
describe "Score", ->
|
||||
before (done) ->
|
||||
registerNewUser done, true
|
||||
|
||||
context "Todos that did not previously exist", ->
|
||||
it "creates a completed a todo when using up url", (done) ->
|
||||
request.post(baseURL + "/user/tasks/withUp/up").send(
|
||||
type: "todo"
|
||||
text: "withUp"
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
request.get(baseURL + "/user/tasks/withUp").end (err, res) ->
|
||||
upTodo = res.body
|
||||
expect(upTodo.completed).to.equal true
|
||||
done()
|
||||
|
||||
it "creates an uncompleted todo when using down url", (done) ->
|
||||
request.post(baseURL + "/user/tasks/withDown/down").send(
|
||||
type: "todo"
|
||||
text: "withDown"
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
request.get(baseURL + "/user/tasks/withDown").end (err, res) ->
|
||||
downTodo = res.body
|
||||
expect(downTodo.completed).to.equal false
|
||||
done()
|
||||
|
||||
it "creates a completed a todo overriding the complete parameter when using up url", (done) ->
|
||||
request.post(baseURL + "/user/tasks/withUpWithComplete/up").send(
|
||||
type: "todo"
|
||||
text: "withUpWithComplete"
|
||||
completed: false
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
request.get(baseURL + "/user/tasks/withUpWithComplete").end (err, res) ->
|
||||
upTodo = res.body
|
||||
expect(upTodo.completed).to.equal true
|
||||
done()
|
||||
|
||||
it "Creates an uncompleted todo overriding the completed parameter when using down url", (done) ->
|
||||
request.post(baseURL + "/user/tasks/withDownWithUncomplete/down").send(
|
||||
type: "todo"
|
||||
text: "withDownWithUncomplete"
|
||||
completed: true
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
request.get(baseURL + "/user/tasks/withDownWithUncomplete").end (err, res) ->
|
||||
downTodo = res.body
|
||||
expect(downTodo.completed).to.equal false
|
||||
done()
|
||||
|
||||
context "Todo that already exists", ->
|
||||
it "It completes a todo when using up url", (done) ->
|
||||
request.post(baseURL + "/user/tasks").send(
|
||||
type: "todo"
|
||||
text: "Sample Todo"
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
unCompletedTodo = res.body
|
||||
expect(unCompletedTodo.completed).to.equal false
|
||||
request.post(baseURL + "/user/tasks/"+unCompletedTodo._id+"/up").end (err, res) ->
|
||||
expectCode res, 200
|
||||
request.get(baseURL + "/user/tasks/"+unCompletedTodo._id).end (err, res) ->
|
||||
unCompletedTodo = res.body
|
||||
expect(unCompletedTodo.completed).to.equal true
|
||||
done()
|
||||
|
||||
it "It uncompletes a todo when using down url", (done) ->
|
||||
request.post(baseURL + "/user/tasks").send(
|
||||
type: "todo"
|
||||
text: "Sample Todo"
|
||||
completed: true
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
completedTodo = res.body
|
||||
expect(completedTodo.completed).to.equal true
|
||||
request.post(baseURL + "/user/tasks/"+completedTodo._id+"/down").end (err, res) ->
|
||||
expectCode res, 200
|
||||
request.get(baseURL + "/user/tasks/"+completedTodo._id).end (err, res) ->
|
||||
completedTodo = res.body
|
||||
expect(completedTodo.completed).to.equal false
|
||||
done()
|
||||
|
||||
it "Creates and scores up a habit when using up url", (done) ->
|
||||
upHabit = undefined
|
||||
request.post(baseURL + "/user/tasks/habitWithUp/up").send(
|
||||
type: "habit"
|
||||
text: "testTitle"
|
||||
completed: true
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
request.get(baseURL + "/user/tasks/habitWithUp").end (err, res) ->
|
||||
upHabit = res.body
|
||||
expect(upHabit.value).to.be.at.least(1)
|
||||
expect(upHabit.type).to.equal("habit")
|
||||
done()
|
||||
|
||||
it "Creates and scores down a habit when using down url", (done) ->
|
||||
downHabit = undefined
|
||||
request.post(baseURL + "/user/tasks/habitWithDown/down").send(
|
||||
type: "habit"
|
||||
text: "testTitle"
|
||||
completed: true
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
request.get(baseURL + "/user/tasks/habitWithDown").end (err, res) ->
|
||||
downHabit = res.body
|
||||
expect(downHabit.value).to.have.at.most(-1)
|
||||
expect(downHabit.type).to.equal("habit")
|
||||
done()
|
||||
142
test/api-legacy/score.js
Normal file
142
test/api-legacy/score.js
Normal file
@@ -0,0 +1,142 @@
|
||||
require("../../website/src/server");
|
||||
|
||||
describe("Score", function() {
|
||||
before(function(done) {
|
||||
return registerNewUser(done, true);
|
||||
});
|
||||
context("Todos that did not previously exist", function() {
|
||||
it("creates a completed a todo when using up url", function(done) {
|
||||
return request.post(baseURL + "/user/tasks/withUp/up").send({
|
||||
type: "todo",
|
||||
text: "withUp"
|
||||
}).end(function(err, res) {
|
||||
expectCode(res, 200);
|
||||
request.get(baseURL + "/user/tasks/withUp").end(function(err, res) {
|
||||
var upTodo;
|
||||
upTodo = res.body;
|
||||
return expect(upTodo.completed).to.equal(true);
|
||||
});
|
||||
return done();
|
||||
});
|
||||
});
|
||||
it("creates an uncompleted todo when using down url", function(done) {
|
||||
return request.post(baseURL + "/user/tasks/withDown/down").send({
|
||||
type: "todo",
|
||||
text: "withDown"
|
||||
}).end(function(err, res) {
|
||||
expectCode(res, 200);
|
||||
return request.get(baseURL + "/user/tasks/withDown").end(function(err, res) {
|
||||
var downTodo;
|
||||
downTodo = res.body;
|
||||
expect(downTodo.completed).to.equal(false);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
it("creates a completed a todo overriding the complete parameter when using up url", function(done) {
|
||||
return request.post(baseURL + "/user/tasks/withUpWithComplete/up").send({
|
||||
type: "todo",
|
||||
text: "withUpWithComplete",
|
||||
completed: false
|
||||
}).end(function(err, res) {
|
||||
expectCode(res, 200);
|
||||
return request.get(baseURL + "/user/tasks/withUpWithComplete").end(function(err, res) {
|
||||
var upTodo;
|
||||
upTodo = res.body;
|
||||
expect(upTodo.completed).to.equal(true);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
return it("Creates an uncompleted todo overriding the completed parameter when using down url", function(done) {
|
||||
return request.post(baseURL + "/user/tasks/withDownWithUncomplete/down").send({
|
||||
type: "todo",
|
||||
text: "withDownWithUncomplete",
|
||||
completed: true
|
||||
}).end(function(err, res) {
|
||||
expectCode(res, 200);
|
||||
return request.get(baseURL + "/user/tasks/withDownWithUncomplete").end(function(err, res) {
|
||||
var downTodo;
|
||||
downTodo = res.body;
|
||||
expect(downTodo.completed).to.equal(false);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
context("Todo that already exists", function() {
|
||||
it("It completes a todo when using up url", function(done) {
|
||||
return request.post(baseURL + "/user/tasks").send({
|
||||
type: "todo",
|
||||
text: "Sample Todo"
|
||||
}).end(function(err, res) {
|
||||
var unCompletedTodo;
|
||||
expectCode(res, 200);
|
||||
unCompletedTodo = res.body;
|
||||
expect(unCompletedTodo.completed).to.equal(false);
|
||||
return request.post(baseURL + "/user/tasks/" + unCompletedTodo._id + "/up").end(function(err, res) {
|
||||
expectCode(res, 200);
|
||||
return request.get(baseURL + "/user/tasks/" + unCompletedTodo._id).end(function(err, res) {
|
||||
unCompletedTodo = res.body;
|
||||
expect(unCompletedTodo.completed).to.equal(true);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
return it("It uncompletes a todo when using down url", function(done) {
|
||||
return request.post(baseURL + "/user/tasks").send({
|
||||
type: "todo",
|
||||
text: "Sample Todo",
|
||||
completed: true
|
||||
}).end(function(err, res) {
|
||||
var completedTodo;
|
||||
expectCode(res, 200);
|
||||
completedTodo = res.body;
|
||||
expect(completedTodo.completed).to.equal(true);
|
||||
return request.post(baseURL + "/user/tasks/" + completedTodo._id + "/down").end(function(err, res) {
|
||||
expectCode(res, 200);
|
||||
return request.get(baseURL + "/user/tasks/" + completedTodo._id).end(function(err, res) {
|
||||
completedTodo = res.body;
|
||||
expect(completedTodo.completed).to.equal(false);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
it("Creates and scores up a habit when using up url", function(done) {
|
||||
var upHabit;
|
||||
upHabit = void 0;
|
||||
return request.post(baseURL + "/user/tasks/habitWithUp/up").send({
|
||||
type: "habit",
|
||||
text: "testTitle",
|
||||
completed: true
|
||||
}).end(function(err, res) {
|
||||
expectCode(res, 200);
|
||||
return request.get(baseURL + "/user/tasks/habitWithUp").end(function(err, res) {
|
||||
upHabit = res.body;
|
||||
expect(upHabit.value).to.be.at.least(1);
|
||||
expect(upHabit.type).to.equal("habit");
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
return it("Creates and scores down a habit when using down url", function(done) {
|
||||
var downHabit;
|
||||
downHabit = void 0;
|
||||
return request.post(baseURL + "/user/tasks/habitWithDown/down").send({
|
||||
type: "habit",
|
||||
text: "testTitle",
|
||||
completed: true
|
||||
}).end(function(err, res) {
|
||||
expectCode(res, 200);
|
||||
return request.get(baseURL + "/user/tasks/habitWithDown").end(function(err, res) {
|
||||
downHabit = res.body;
|
||||
expect(downHabit.value).to.have.at.most(-1);
|
||||
expect(downHabit.type).to.equal("habit");
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,41 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
payments = require("../../website/src/controllers/payments")
|
||||
app = require("../../website/src/server")
|
||||
|
||||
describe "Subscriptions", ->
|
||||
|
||||
before (done) ->
|
||||
registerNewUser(done, true)
|
||||
|
||||
it "Handles unsubscription", (done) ->
|
||||
cron = ->
|
||||
user.lastCron = moment().subtract(1, "d")
|
||||
user.fns.cron()
|
||||
|
||||
expect(user.purchased.plan.customerId).to.not.exist
|
||||
payments.createSubscription
|
||||
user: user
|
||||
customerId: "123"
|
||||
paymentMethod: "Stripe"
|
||||
sub: {key: 'basic_6mo'}
|
||||
|
||||
expect(user.purchased.plan.customerId).to.exist
|
||||
shared.wrap user
|
||||
cron()
|
||||
expect(user.purchased.plan.customerId).to.exist
|
||||
payments.cancelSubscription user: user
|
||||
cron()
|
||||
expect(user.purchased.plan.customerId).to.exist
|
||||
expect(user.purchased.plan.dateTerminated).to.exist
|
||||
user.purchased.plan.dateTerminated = moment().subtract(2, "d")
|
||||
cron()
|
||||
expect(user.purchased.plan.customerId).to.not.exist
|
||||
payments.createSubscription
|
||||
user: user
|
||||
customerId: "123"
|
||||
paymentMethod: "Stripe"
|
||||
sub: {key: 'basic_6mo'}
|
||||
|
||||
expect(user.purchased.plan.dateTerminated).to.not.exist
|
||||
done()
|
||||
50
test/api-legacy/subscriptions.js
Normal file
50
test/api-legacy/subscriptions.js
Normal file
@@ -0,0 +1,50 @@
|
||||
var app, payments;
|
||||
|
||||
payments = require("../../website/src/controllers/payments");
|
||||
|
||||
app = require("../../website/src/server");
|
||||
|
||||
describe("Subscriptions", function() {
|
||||
before(function(done) {
|
||||
return registerNewUser(done, true);
|
||||
});
|
||||
return it("Handles unsubscription", function(done) {
|
||||
var cron;
|
||||
cron = function() {
|
||||
user.lastCron = moment().subtract(1, "d");
|
||||
return user.fns.cron();
|
||||
};
|
||||
expect(user.purchased.plan.customerId).to.not.exist;
|
||||
payments.createSubscription({
|
||||
user: user,
|
||||
customerId: "123",
|
||||
paymentMethod: "Stripe",
|
||||
sub: {
|
||||
key: 'basic_6mo'
|
||||
}
|
||||
});
|
||||
expect(user.purchased.plan.customerId).to.exist;
|
||||
shared.wrap(user);
|
||||
cron();
|
||||
expect(user.purchased.plan.customerId).to.exist;
|
||||
payments.cancelSubscription({
|
||||
user: user
|
||||
});
|
||||
cron();
|
||||
expect(user.purchased.plan.customerId).to.exist;
|
||||
expect(user.purchased.plan.dateTerminated).to.exist;
|
||||
user.purchased.plan.dateTerminated = moment().subtract(2, "d");
|
||||
cron();
|
||||
expect(user.purchased.plan.customerId).to.not.exist;
|
||||
payments.createSubscription({
|
||||
user: user,
|
||||
customerId: "123",
|
||||
paymentMethod: "Stripe",
|
||||
sub: {
|
||||
key: 'basic_6mo'
|
||||
}
|
||||
});
|
||||
expect(user.purchased.plan.dateTerminated).to.not.exist;
|
||||
return done();
|
||||
});
|
||||
});
|
||||
@@ -1,82 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
require("../../website/src/server")
|
||||
|
||||
describe "Todos", ->
|
||||
|
||||
before (done) ->
|
||||
registerNewUser done, true
|
||||
|
||||
beforeEach (done) ->
|
||||
User.findById user._id, (err, _user) ->
|
||||
user = _user
|
||||
shared.wrap user
|
||||
done()
|
||||
|
||||
it "Archives old todos", (done) ->
|
||||
numTasks = _.size(user.todos)
|
||||
request.post(baseURL + "/user/batch-update?_v=999").send([
|
||||
{
|
||||
op: "addTask"
|
||||
body:
|
||||
type: "todo"
|
||||
}
|
||||
{
|
||||
op: "addTask"
|
||||
body:
|
||||
type: "todo"
|
||||
}
|
||||
{
|
||||
op: "addTask"
|
||||
body:
|
||||
type: "todo"
|
||||
}
|
||||
]).end (err, res) ->
|
||||
expectCode res, 200
|
||||
# Expect number of todos to be 3 greater than the number the user started with
|
||||
expect(_.size(res.body.todos)).to.equal numTasks + 3
|
||||
# Assign new number to numTasks variable
|
||||
numTasks += 3
|
||||
request.post(baseURL + "/user/batch-update?_v=998").send([
|
||||
{
|
||||
op: "score"
|
||||
params:
|
||||
direction: "up"
|
||||
id: res.body.todos[0].id
|
||||
}
|
||||
{
|
||||
op: "score"
|
||||
params:
|
||||
direction: "up"
|
||||
id: res.body.todos[1].id
|
||||
}
|
||||
{
|
||||
op: "score"
|
||||
params:
|
||||
direction: "up"
|
||||
id: res.body.todos[2].id
|
||||
}
|
||||
]).end (err, res) ->
|
||||
expectCode res, 200
|
||||
expect(_.size(res.body.todos)).to.equal numTasks
|
||||
request.post(baseURL + "/user/batch-update?_v=997").send([
|
||||
{
|
||||
op: "updateTask"
|
||||
params:
|
||||
id: res.body.todos[0].id
|
||||
|
||||
body:
|
||||
dateCompleted: moment().subtract(4, "days")
|
||||
}
|
||||
{
|
||||
op: "updateTask"
|
||||
params:
|
||||
id: res.body.todos[1].id
|
||||
|
||||
body:
|
||||
dateCompleted: moment().subtract(4, "days")
|
||||
}
|
||||
]).end (err, res) ->
|
||||
# Expect todos to be 2 less than the total count
|
||||
expect(_.size(res.body.todos)).to.equal numTasks - 2
|
||||
done()
|
||||
87
test/api-legacy/todos.js
Normal file
87
test/api-legacy/todos.js
Normal file
@@ -0,0 +1,87 @@
|
||||
require("../../website/src/server");
|
||||
|
||||
describe("Todos", function() {
|
||||
before(function(done) {
|
||||
return registerNewUser(done, true);
|
||||
});
|
||||
beforeEach(function(done) {
|
||||
return User.findById(user._id, function(err, _user) {
|
||||
var user;
|
||||
user = _user;
|
||||
shared.wrap(user);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
return it("Archives old todos", function(done) {
|
||||
var numTasks;
|
||||
numTasks = _.size(user.todos);
|
||||
return request.post(baseURL + "/user/batch-update?_v=999").send([
|
||||
{
|
||||
op: "addTask",
|
||||
body: {
|
||||
type: "todo"
|
||||
}
|
||||
}, {
|
||||
op: "addTask",
|
||||
body: {
|
||||
type: "todo"
|
||||
}
|
||||
}, {
|
||||
op: "addTask",
|
||||
body: {
|
||||
type: "todo"
|
||||
}
|
||||
}
|
||||
]).end(function(err, res) {
|
||||
expectCode(res, 200);
|
||||
expect(_.size(res.body.todos)).to.equal(numTasks + 3);
|
||||
numTasks += 3;
|
||||
return request.post(baseURL + "/user/batch-update?_v=998").send([
|
||||
{
|
||||
op: "score",
|
||||
params: {
|
||||
direction: "up",
|
||||
id: res.body.todos[0].id
|
||||
}
|
||||
}, {
|
||||
op: "score",
|
||||
params: {
|
||||
direction: "up",
|
||||
id: res.body.todos[1].id
|
||||
}
|
||||
}, {
|
||||
op: "score",
|
||||
params: {
|
||||
direction: "up",
|
||||
id: res.body.todos[2].id
|
||||
}
|
||||
}
|
||||
]).end(function(err, res) {
|
||||
expectCode(res, 200);
|
||||
expect(_.size(res.body.todos)).to.equal(numTasks);
|
||||
return request.post(baseURL + "/user/batch-update?_v=997").send([
|
||||
{
|
||||
op: "updateTask",
|
||||
params: {
|
||||
id: res.body.todos[0].id
|
||||
},
|
||||
body: {
|
||||
dateCompleted: moment().subtract(4, "days")
|
||||
}
|
||||
}, {
|
||||
op: "updateTask",
|
||||
params: {
|
||||
id: res.body.todos[1].id
|
||||
},
|
||||
body: {
|
||||
dateCompleted: moment().subtract(4, "days")
|
||||
}
|
||||
}
|
||||
]).end(function(err, res) {
|
||||
expect(_.size(res.body.todos)).to.equal(numTasks - 2);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,925 +0,0 @@
|
||||
_ = require 'lodash'
|
||||
expect = require 'expect.js'
|
||||
sinon = require 'sinon'
|
||||
moment = require 'moment'
|
||||
shared = require '../../common/script/index.js'
|
||||
shared.i18n.translations = require('../../website/src/libs/i18n.js').translations
|
||||
test_helper = require './test_helper'
|
||||
test_helper.addCustomMatchers()
|
||||
$w = (s)->s.split(' ')
|
||||
|
||||
### Helper Functions ####
|
||||
newUser = (addTasks=true)->
|
||||
buffs = {per:0, int:0, con:0, str:0, stealth: 0, streaks: false}
|
||||
user =
|
||||
auth:
|
||||
timestamps: {}
|
||||
stats: {str:1, con:1, per:1, int:1, mp: 32, class: 'warrior', buffs: buffs}
|
||||
items:
|
||||
lastDrop:
|
||||
count: 0
|
||||
hatchingPotions: {}
|
||||
eggs: {}
|
||||
food: {}
|
||||
gear:
|
||||
equipped: {}
|
||||
costume: {}
|
||||
owned: {}
|
||||
quests: {}
|
||||
party:
|
||||
quest:
|
||||
progress:
|
||||
down: 0
|
||||
preferences: {
|
||||
autoEquip: true
|
||||
}
|
||||
dailys: []
|
||||
todos: []
|
||||
rewards: []
|
||||
flags: {}
|
||||
achievements:
|
||||
ultimateGearSets: {}
|
||||
contributor:
|
||||
level: 2
|
||||
_tmp: {}
|
||||
|
||||
shared.wrap(user)
|
||||
user.ops.reset(null, ->)
|
||||
if addTasks
|
||||
_.each ['habit', 'todo', 'daily'], (task)->
|
||||
user.ops.addTask {body: {type: task, id: shared.uuid()}}
|
||||
user
|
||||
|
||||
rewrapUser = (user)->
|
||||
user._wrapped = false
|
||||
shared.wrap(user)
|
||||
user
|
||||
|
||||
expectStrings = (obj, paths) ->
|
||||
_.each paths, (path) -> expect(obj[path]).to.be.ok()
|
||||
|
||||
# options.daysAgo: days ago when the last cron was executed
|
||||
# cronAfterStart: moves the lastCron to be after the dayStart.
|
||||
# This way the daysAgo works as expected if the test case
|
||||
# makes the assumption that the lastCron was after dayStart.
|
||||
beforeAfter = (options={}) ->
|
||||
user = newUser()
|
||||
[before, after] = [user, _.cloneDeep(user)]
|
||||
# avoid closure on the original user
|
||||
rewrapUser(after)
|
||||
before.preferences.dayStart = after.preferences.dayStart = options.dayStart if options.dayStart
|
||||
before.preferences.timezoneOffset = after.preferences.timezoneOffset = (options.timezoneOffset or moment().zone())
|
||||
if options.limitOne
|
||||
before["#{options.limitOne}s"] = [before["#{options.limitOne}s"][0]]
|
||||
after["#{options.limitOne}s"] = [after["#{options.limitOne}s"][0]]
|
||||
lastCron = moment(options.now || +new Date).subtract( {days:options.daysAgo} ) if options.daysAgo
|
||||
lastCron.add( {hours:options.dayStart, minutes:1} ) if options.daysAgo and options.cronAfterStart
|
||||
lastCron = +lastCron if options.daysAgo
|
||||
_.each [before,after], (obj) ->
|
||||
obj.lastCron = lastCron if options.daysAgo
|
||||
{before:before, after:after}
|
||||
#TODO calculate actual points
|
||||
|
||||
expectLostPoints = (before, after, taskType) ->
|
||||
if taskType in ['daily','habit']
|
||||
expect(after.stats.hp).to.be.lessThan before.stats.hp
|
||||
expect(after["#{taskType}s"][0].history).to.have.length(1)
|
||||
else expect(after.history.todos).to.have.length(1)
|
||||
expect(after).toHaveExp 0
|
||||
expect(after).toHaveGP 0
|
||||
expect(after["#{taskType}s"][0].value).to.be.lessThan before["#{taskType}s"][0].value
|
||||
|
||||
expectGainedPoints = (before, after, taskType) ->
|
||||
expect(after.stats.hp).to.be 50
|
||||
expect(after.stats.exp).to.be.greaterThan before.stats.exp
|
||||
expect(after.stats.gp).to.be.greaterThan before.stats.gp
|
||||
expect(after["#{taskType}s"][0].value).to.be.greaterThan before["#{taskType}s"][0].value
|
||||
expect(after["#{taskType}s"][0].history).to.have.length(1) if taskType is 'habit'
|
||||
# daily & todo histories handled on cron
|
||||
|
||||
expectNoChange = (before,after) ->
|
||||
_.each $w('stats items gear dailys todos rewards preferences'), (attr)->
|
||||
expect(after[attr]).to.eql before[attr]
|
||||
|
||||
expectClosePoints = (before, after, taskType) ->
|
||||
expect( Math.abs(after.stats.exp - before.stats.exp) ).to.be.lessThan 0.0001
|
||||
expect( Math.abs(after.stats.gp - before.stats.gp) ).to.be.lessThan 0.0001
|
||||
expect( Math.abs(after["#{taskType}s"][0].value - before["#{taskType}s"][0].value) ).to.be.lessThan 0.0001
|
||||
|
||||
expectDayResetNoDamage = (b,a) ->
|
||||
[before,after] = [_.cloneDeep(b), _.cloneDeep(a)]
|
||||
_.each after.dailys, (task,i) ->
|
||||
expect(task.completed).to.be false
|
||||
expect(before.dailys[i].value).to.be task.value
|
||||
expect(before.dailys[i].streak).to.be task.streak
|
||||
expect(task.history).to.have.length(1)
|
||||
_.each after.todos, (task,i) ->
|
||||
expect(task.completed).to.be false
|
||||
expect(before.todos[i].value).to.be.greaterThan task.value
|
||||
expect(after.history.todos).to.have.length(1)
|
||||
# hack so we can compare user before/after obj equality sans effected paths
|
||||
_.each [before,after], (obj) ->
|
||||
delete obj.stats.buffs
|
||||
_.each $w('dailys todos history lastCron'), (path) -> delete obj[path]
|
||||
delete after._tmp
|
||||
expectNoChange(before, after)
|
||||
|
||||
cycle = (array)->
|
||||
n = -1
|
||||
(seed=0)->
|
||||
n++
|
||||
return array[n % array.length]
|
||||
|
||||
repeatWithoutLastWeekday = ()->
|
||||
repeat = {su:true,m:true,t:true,w:true,th:true,f:true,s:true}
|
||||
if shared.startOfWeek(moment().zone(0)).isoWeekday() == 1 # Monday
|
||||
repeat.su = false
|
||||
else
|
||||
repeat.s = false
|
||||
{repeat: repeat}
|
||||
|
||||
###### Specs ######
|
||||
|
||||
describe 'User', ->
|
||||
it 'sets correct user defaults', ->
|
||||
user = newUser()
|
||||
base_gear = { armor: 'armor_base_0', weapon: 'weapon_base_0', head: 'head_base_0', shield: 'shield_base_0' }
|
||||
buffs = {per:0, int:0, con:0, str:0, stealth: 0, streaks: false}
|
||||
expect(user.stats).to.eql { str: 1, con: 1, per: 1, int: 1, hp: 50, mp: 32, lvl: 1, exp: 0, gp: 0, class: 'warrior', buffs: buffs }
|
||||
expect(user.items.gear).to.eql { equipped: base_gear, costume: base_gear, owned: {weapon_warrior_0: true} }
|
||||
expect(user.preferences).to.eql { autoEquip: true, costume: false }
|
||||
|
||||
it 'calculates max MP', ->
|
||||
user = newUser()
|
||||
expect(user).toHaveMaxMP 32
|
||||
user.stats.int = 10
|
||||
expect(user).toHaveMaxMP 50
|
||||
user.stats.lvl = 5
|
||||
expect(user).toHaveMaxMP 54
|
||||
user.stats.class = 'wizard'
|
||||
user.items.gear.equipped.weapon = 'weapon_wizard_1'
|
||||
expect(user).toHaveMaxMP 63
|
||||
|
||||
it 'handles perfect days', ->
|
||||
user = newUser()
|
||||
user.dailys = []
|
||||
_.times 3, ->user.dailys.push shared.taskDefaults({type:'daily', startDate: moment().subtract(7, 'days')})
|
||||
cron = -> user.lastCron = moment().subtract(1,'days');user.fns.cron()
|
||||
|
||||
cron()
|
||||
expect(user.stats.buffs.str).to.be 0
|
||||
expect(user.achievements.perfect).to.not.be.ok()
|
||||
|
||||
user.dailys[0].completed = true
|
||||
cron()
|
||||
expect(user.stats.buffs.str).to.be 0
|
||||
expect(user.achievements.perfect).to.not.be.ok()
|
||||
|
||||
_.each user.dailys, (d)->d.completed = true
|
||||
cron()
|
||||
expect(user.stats.buffs.str).to.be 1
|
||||
expect(user.achievements.perfect).to.be 1
|
||||
|
||||
# Handle greyed-out dailys
|
||||
yesterday = moment().subtract(1,'days')
|
||||
user.dailys[0].repeat[shared.dayMapping[yesterday.day()]] = false
|
||||
_.each user.dailys[1..], (d)->d.completed = true
|
||||
cron()
|
||||
expect(user.stats.buffs.str).to.be 1
|
||||
expect(user.achievements.perfect).to.be 2
|
||||
|
||||
describe 'Resting in the Inn', ->
|
||||
user = null
|
||||
cron = null
|
||||
|
||||
beforeEach ->
|
||||
user = newUser()
|
||||
user.preferences.sleep = true
|
||||
cron = -> user.lastCron = moment().subtract(1, 'days');user.fns.cron()
|
||||
user.dailys = []
|
||||
_.times 2, -> user.dailys.push shared.taskDefaults({type:'daily', startDate: moment().subtract(7, 'days')})
|
||||
|
||||
it 'remains in the inn on cron', ->
|
||||
cron()
|
||||
expect(user.preferences.sleep).to.be true
|
||||
|
||||
it 'resets dailies', ->
|
||||
user.dailys[0].completed = true
|
||||
cron()
|
||||
expect(user.dailys[0].completed).to.be false
|
||||
|
||||
it 'resets checklist on incomplete dailies', ->
|
||||
user.dailys[0].checklist = [
|
||||
{
|
||||
"text" : "1",
|
||||
"id" : "checklist-one",
|
||||
"completed" : true
|
||||
},
|
||||
{
|
||||
"text" : "2",
|
||||
"id" : "checklist-two",
|
||||
"completed" : true
|
||||
},
|
||||
{
|
||||
"text" : "3",
|
||||
"id" : "checklist-three",
|
||||
"completed" : false
|
||||
}
|
||||
]
|
||||
cron()
|
||||
_.each user.dailys[0].checklist, (box)->
|
||||
expect(box.completed).to.be false
|
||||
|
||||
it 'resets checklist on complete dailies', ->
|
||||
user.dailys[0].checklist = [
|
||||
{
|
||||
"text" : "1",
|
||||
"id" : "checklist-one",
|
||||
"completed" : true
|
||||
},
|
||||
{
|
||||
"text" : "2",
|
||||
"id" : "checklist-two",
|
||||
"completed" : true
|
||||
},
|
||||
{
|
||||
"text" : "3",
|
||||
"id" : "checklist-three",
|
||||
"completed" : false
|
||||
}
|
||||
]
|
||||
user.dailys[0].completed = true
|
||||
cron()
|
||||
_.each user.dailys[0].checklist, (box)->
|
||||
expect(box.completed).to.be false
|
||||
|
||||
it 'does not reset checklist on grey incomplete dailies', ->
|
||||
yesterday = moment().subtract(1,'days')
|
||||
user.dailys[0].repeat[shared.dayMapping[yesterday.day()]] = false
|
||||
user.dailys[0].checklist = [
|
||||
{
|
||||
"text" : "1",
|
||||
"id" : "checklist-one",
|
||||
"completed" : true
|
||||
},
|
||||
{
|
||||
"text" : "2",
|
||||
"id" : "checklist-two",
|
||||
"completed" : true
|
||||
},
|
||||
{
|
||||
"text" : "3",
|
||||
"id" : "checklist-three",
|
||||
"completed" : true
|
||||
}
|
||||
]
|
||||
|
||||
cron()
|
||||
_.each user.dailys[0].checklist, (box)->
|
||||
expect(box.completed).to.be true
|
||||
|
||||
it 'resets checklist on complete grey complete dailies', ->
|
||||
yesterday = moment().subtract(1,'days')
|
||||
user.dailys[0].repeat[shared.dayMapping[yesterday.day()]] = false
|
||||
user.dailys[0].checklist = [
|
||||
{
|
||||
"text" : "1",
|
||||
"id" : "checklist-one",
|
||||
"completed" : true
|
||||
},
|
||||
{
|
||||
"text" : "2",
|
||||
"id" : "checklist-two",
|
||||
"completed" : true
|
||||
},
|
||||
{
|
||||
"text" : "3",
|
||||
"id" : "checklist-three",
|
||||
"completed" : true
|
||||
}
|
||||
]
|
||||
user.dailys[0].completed = true
|
||||
|
||||
cron()
|
||||
_.each user.dailys[0].checklist, (box)->
|
||||
expect(box.completed).to.be false
|
||||
|
||||
it 'does not damage user for incomplete dailies', ->
|
||||
expect(user).toHaveHP 50
|
||||
user.dailys[0].completed = true
|
||||
user.dailys[1].completed = false
|
||||
cron()
|
||||
expect(user).toHaveHP 50
|
||||
|
||||
it 'gives credit for complete dailies', ->
|
||||
user.dailys[0].completed = true
|
||||
expect(user.dailys[0].history).to.be.empty
|
||||
cron()
|
||||
expect(user.dailys[0].history).to.not.be.empty
|
||||
|
||||
it 'damages user for incomplete dailies after checkout', ->
|
||||
expect(user).toHaveHP 50
|
||||
user.dailys[0].completed = true
|
||||
user.dailys[1].completed = false
|
||||
user.preferences.sleep = false
|
||||
cron()
|
||||
expect(user.stats.hp).to.be.lessThan 50
|
||||
|
||||
describe 'Death', ->
|
||||
user = undefined
|
||||
it 'revives correctly', ->
|
||||
user = newUser()
|
||||
user.stats = { gp: 10, exp: 100, lvl: 2, hp: 0, class: 'warrior' }
|
||||
user.ops.revive()
|
||||
expect(user).toHaveGP 0
|
||||
expect(user).toHaveExp 0
|
||||
expect(user).toHaveLevel 1
|
||||
expect(user).toHaveHP 50
|
||||
expect(user.items.gear.owned).to.eql { weapon_warrior_0: false }
|
||||
|
||||
it "doesn't break unbreakables", ->
|
||||
ce = shared.countExists
|
||||
user = newUser()
|
||||
# breakables (includes default weapon_warrior_0):
|
||||
user.items.gear.owned['shield_warrior_1'] = true
|
||||
# unbreakables because off-class or 0 value:
|
||||
user.items.gear.owned['shield_rogue_1'] = true
|
||||
user.items.gear.owned['head_special_nye'] = true
|
||||
expect(ce user.items.gear.owned).to.be 4
|
||||
user.stats.hp = 0
|
||||
user.ops.revive()
|
||||
expect(ce(user.items.gear.owned)).to.be 3
|
||||
user.stats.hp = 0
|
||||
user.ops.revive()
|
||||
expect(ce(user.items.gear.owned)).to.be 2
|
||||
user.stats.hp = 0
|
||||
user.ops.revive()
|
||||
expect(ce(user.items.gear.owned)).to.be 2
|
||||
expect(user.items.gear.owned).to.eql { weapon_warrior_0: false, shield_warrior_1: false, shield_rogue_1: true, head_special_nye: true }
|
||||
|
||||
it "handles event items", ->
|
||||
shared.content.gear.flat.head_special_nye.event.start = '2012-01-01'
|
||||
shared.content.gear.flat.head_special_nye.event.end = '2012-02-01'
|
||||
expect(shared.content.gear.flat.head_special_nye.canOwn(user)).to.be true
|
||||
delete user.items.gear.owned['head_special_nye']
|
||||
expect(shared.content.gear.flat.head_special_nye.canOwn(user)).to.be false
|
||||
|
||||
shared.content.gear.flat.head_special_nye.event.start = moment().subtract(5,'days')
|
||||
shared.content.gear.flat.head_special_nye.event.end = moment().add(5,'days')
|
||||
expect(shared.content.gear.flat.head_special_nye.canOwn(user)).to.be true
|
||||
|
||||
describe 'Rebirth', ->
|
||||
user = undefined
|
||||
it 'removes correct gear', ->
|
||||
user = newUser()
|
||||
user.stats.lvl = 100
|
||||
user.items.gear.owned = {
|
||||
"weapon_warrior_0": true,
|
||||
"weapon_warrior_1": true,
|
||||
"armor_warrior_1": false,
|
||||
"armor_mystery_201402": true,
|
||||
"back_mystery_201402": false,
|
||||
"head_mystery_201402": true,
|
||||
"weapon_armoire_basicCrossbow": true,
|
||||
}
|
||||
user.ops.rebirth()
|
||||
expect(user.items.gear.owned).to.eql {
|
||||
"weapon_warrior_0": true,
|
||||
"weapon_warrior_1": false,
|
||||
"armor_warrior_1": false,
|
||||
"armor_mystery_201402": true,
|
||||
"back_mystery_201402": false,
|
||||
"head_mystery_201402": true,
|
||||
"weapon_armoire_basicCrossbow": false,
|
||||
}
|
||||
|
||||
describe 'store', ->
|
||||
it 'buys a Quest scroll', ->
|
||||
user = newUser()
|
||||
user.stats.gp = 205
|
||||
user.ops.buyQuest {params: {key: 'dilatoryDistress1'}}
|
||||
expect(user.items.quests).to.eql {dilatoryDistress1: 1}
|
||||
expect(user).toHaveGP 5
|
||||
|
||||
it 'does not buy Quests without enough Gold', ->
|
||||
user = newUser()
|
||||
user.stats.gp = 1
|
||||
user.ops.buyQuest {params: {key: 'dilatoryDistress1'}}
|
||||
expect(user.items.quests).to.eql {}
|
||||
expect(user).toHaveGP 1
|
||||
|
||||
it 'does not buy nonexistent Quests', ->
|
||||
user = newUser()
|
||||
user.stats.gp = 9999
|
||||
user.ops.buyQuest {params: {key: 'snarfblatter'}}
|
||||
expect(user.items.quests).to.eql {}
|
||||
expect(user).toHaveGP 9999
|
||||
|
||||
it 'does not buy Gem-premium Quests', ->
|
||||
user = newUser()
|
||||
user.stats.gp = 9999
|
||||
user.ops.buyQuest {params: {key: 'kraken'}}
|
||||
expect(user.items.quests).to.eql {}
|
||||
expect(user).toHaveGP 9999
|
||||
|
||||
describe 'Gem purchases', ->
|
||||
it 'does not purchase items without enough Gems', ->
|
||||
user = newUser()
|
||||
user.ops.purchase {params: {type: 'eggs', key: 'Cactus'}}
|
||||
user.ops.purchase {params: {type: 'gear', key: 'headAccessory_special_foxEars'}}
|
||||
user.ops.unlock {query: {path: 'items.gear.owned.headAccessory_special_bearEars,items.gear.owned.headAccessory_special_cactusEars,items.gear.owned.headAccessory_special_foxEars,items.gear.owned.headAccessory_special_lionEars,items.gear.owned.headAccessory_special_pandaEars,items.gear.owned.headAccessory_special_pigEars,items.gear.owned.headAccessory_special_tigerEars,items.gear.owned.headAccessory_special_wolfEars'}}
|
||||
expect(user.items.eggs).to.eql {}
|
||||
expect(user.items.gear.owned).to.eql { weapon_warrior_0: true }
|
||||
|
||||
it 'purchases an egg', ->
|
||||
user = newUser()
|
||||
user.balance = 1
|
||||
user.ops.purchase {params: {type: 'eggs', key: 'Cactus'}}
|
||||
expect(user.items.eggs).to.eql { Cactus: 1}
|
||||
expect(user.balance).to.eql 0.25
|
||||
|
||||
it 'purchases fox ears', ->
|
||||
user = newUser()
|
||||
user.balance = 1
|
||||
user.ops.purchase {params: {type: 'gear', key: 'headAccessory_special_foxEars'}}
|
||||
expect(user.items.gear.owned).to.eql { weapon_warrior_0: true, headAccessory_special_foxEars: true }
|
||||
expect(user.balance).to.eql 0.5
|
||||
|
||||
it 'unlocks all the animal ears at once', ->
|
||||
user = newUser()
|
||||
user.balance = 2
|
||||
user.ops.unlock {query: {path: 'items.gear.owned.headAccessory_special_bearEars,items.gear.owned.headAccessory_special_cactusEars,items.gear.owned.headAccessory_special_foxEars,items.gear.owned.headAccessory_special_lionEars,items.gear.owned.headAccessory_special_pandaEars,items.gear.owned.headAccessory_special_pigEars,items.gear.owned.headAccessory_special_tigerEars,items.gear.owned.headAccessory_special_wolfEars'}}
|
||||
expect(user.items.gear.owned).to.eql { weapon_warrior_0: true, headAccessory_special_bearEars: true, headAccessory_special_cactusEars: true, headAccessory_special_foxEars: true, headAccessory_special_lionEars: true, headAccessory_special_pandaEars: true, headAccessory_special_pigEars: true, headAccessory_special_tigerEars: true, headAccessory_special_wolfEars: true}
|
||||
expect(user.balance).to.eql 0.75
|
||||
|
||||
describe 'spells', ->
|
||||
_.each shared.content.spells, (spellClass)->
|
||||
_.each spellClass, (spell)->
|
||||
it "#{spell.text} has valid values", ->
|
||||
expect(spell.target).to.match(/^(task|self|party|user)$/)
|
||||
expect(spell.mana).to.be.an('number')
|
||||
if spell.lvl
|
||||
expect(spell.lvl).to.be.an('number')
|
||||
expect(spell.lvl).to.be.above(0)
|
||||
expect(spell.cast).to.be.a('function')
|
||||
|
||||
describe 'drop system', ->
|
||||
user = null
|
||||
MIN_RANGE_FOR_POTION = 0
|
||||
MAX_RANGE_FOR_POTION = .3
|
||||
MIN_RANGE_FOR_EGG = .4
|
||||
MAX_RANGE_FOR_EGG = .6
|
||||
MIN_RANGE_FOR_FOOD = .7
|
||||
MAX_RANGE_FOR_FOOD = 1
|
||||
|
||||
beforeEach ->
|
||||
user = newUser()
|
||||
user.flags.dropsEnabled = true
|
||||
@task_id = shared.uuid()
|
||||
user.ops.addTask({body: {type: 'daily', id: @task_id}})
|
||||
|
||||
it 'drops a hatching potion', ->
|
||||
for random in [MIN_RANGE_FOR_POTION..MAX_RANGE_FOR_POTION] by .1
|
||||
sinon.stub(user.fns, 'predictableRandom').returns random
|
||||
user.ops.score {params: { id: @task_id, direction: 'up'}}
|
||||
expect(user.items.eggs).to.be.empty
|
||||
expect(user.items.hatchingPotions).to.not.be.empty
|
||||
expect(user.items.food).to.be.empty
|
||||
user.fns.predictableRandom.restore()
|
||||
|
||||
it 'drops a pet egg', ->
|
||||
for random in [MIN_RANGE_FOR_EGG..MAX_RANGE_FOR_EGG] by .1
|
||||
sinon.stub(user.fns, 'predictableRandom').returns random
|
||||
user.ops.score {params: { id: @task_id, direction: 'up'}}
|
||||
expect(user.items.eggs).to.not.be.empty
|
||||
expect(user.items.hatchingPotions).to.be.empty
|
||||
expect(user.items.food).to.be.empty
|
||||
user.fns.predictableRandom.restore()
|
||||
|
||||
it 'drops food', ->
|
||||
for random in [MIN_RANGE_FOR_FOOD..MAX_RANGE_FOR_FOOD] by .1
|
||||
sinon.stub(user.fns, 'predictableRandom').returns random
|
||||
user.ops.score {params: { id: @task_id, direction: 'up'}}
|
||||
expect(user.items.eggs).to.be.empty
|
||||
expect(user.items.hatchingPotions).to.be.empty
|
||||
expect(user.items.food).to.not.be.empty
|
||||
user.fns.predictableRandom.restore()
|
||||
|
||||
it 'does not get a drop', ->
|
||||
sinon.stub(user.fns, 'predictableRandom').returns 0.5
|
||||
user.ops.score {params: { id: @task_id, direction: 'up'}}
|
||||
expect(user.items.eggs).to.eql {}
|
||||
expect(user.items.hatchingPotions).to.eql {}
|
||||
expect(user.items.food).to.eql {}
|
||||
user.fns.predictableRandom.restore()
|
||||
|
||||
describe 'Quests', ->
|
||||
_.each shared.content.quests, (quest)->
|
||||
it "#{quest.text()} has valid values", ->
|
||||
expect(quest.notes()).to.be.an('string')
|
||||
expect(quest.completion()).to.be.an('string') if quest.completion
|
||||
expect(quest.previous).to.be.an('string') if quest.previous
|
||||
expect(quest.value).to.be.greaterThan 0 if quest.canBuy()
|
||||
expect(quest.drop.gp).to.not.be.lessThan 0
|
||||
expect(quest.drop.exp).to.not.be.lessThan 0
|
||||
expect(quest.category).to.match(/pet|unlockable|gold|world/)
|
||||
if quest.drop.items
|
||||
expect(quest.drop.items).to.be.an(Array)
|
||||
if quest.boss
|
||||
expect(quest.boss.name()).to.be.an('string')
|
||||
expect(quest.boss.hp).to.be.greaterThan 0
|
||||
expect(quest.boss.str).to.be.greaterThan 0
|
||||
else if quest.collect
|
||||
_.each quest.collect, (collect)->
|
||||
expect(collect.text()).to.be.an('string')
|
||||
expect(collect.count).to.be.greaterThan 0
|
||||
|
||||
describe 'Achievements', ->
|
||||
_.each shared.content.classes, (klass) ->
|
||||
user = newUser()
|
||||
user.stats.gp = 10000
|
||||
_.each shared.content.gearTypes, (type) ->
|
||||
_.each [1..5], (i) ->
|
||||
user.ops.buy {params:'#{type}_#{klass}_#{i}'}
|
||||
it 'does not get ultimateGear ' + klass, ->
|
||||
expect(user.achievements.ultimateGearSets[klass]).to.not.be.ok()
|
||||
_.each shared.content.gearTypes, (type) ->
|
||||
user.ops.buy {params:'#{type}_#{klass}_6'}
|
||||
xit 'gets ultimateGear ' + klass, ->
|
||||
expect(user.achievements.ultimateGearSets[klass]).to.be.ok()
|
||||
|
||||
it 'does not remove existing Ultimate Gear achievements', ->
|
||||
user = newUser()
|
||||
user.achievements.ultimateGearSets = {'healer':true,'wizard':true,'rogue':true,'warrior':true}
|
||||
user.items.gear.owned.shield_warrior_5 = false
|
||||
user.items.gear.owned.weapon_rogue_6 = false
|
||||
user.ops.buy {params:'shield_warrior_5'}
|
||||
expect(user.achievements.ultimateGearSets).to.eql {'healer':true,'wizard':true,'rogue':true,'warrior':true}
|
||||
|
||||
describe 'unlocking features', ->
|
||||
it 'unlocks drops at level 3', ->
|
||||
user = newUser()
|
||||
user.stats.lvl = 3
|
||||
user.fns.updateStats(user.stats)
|
||||
expect(user.flags.dropsEnabled).to.be.ok()
|
||||
|
||||
it 'unlocks Rebirth at level 50', ->
|
||||
user = newUser()
|
||||
user.stats.lvl = 50
|
||||
user.fns.updateStats(user.stats)
|
||||
expect(user.flags.rebirthEnabled).to.be.ok()
|
||||
|
||||
describe 'level-awarded Quests', ->
|
||||
it 'gets Attack of the Mundane at level 15', ->
|
||||
user = newUser()
|
||||
user.stats.lvl = 15
|
||||
user.fns.updateStats(user.stats)
|
||||
expect(user.flags.levelDrops.atom1).to.be.ok()
|
||||
expect(user.items.quests.atom1).to.eql 1
|
||||
|
||||
it 'gets Vice at level 30', ->
|
||||
user = newUser()
|
||||
user.stats.lvl = 30
|
||||
user.fns.updateStats(user.stats)
|
||||
expect(user.flags.levelDrops.vice1).to.be.ok()
|
||||
expect(user.items.quests.vice1).to.eql 1
|
||||
|
||||
it 'gets Golden Knight at level 40', ->
|
||||
user = newUser()
|
||||
user.stats.lvl = 40
|
||||
user.fns.updateStats(user.stats)
|
||||
expect(user.flags.levelDrops.goldenknight1).to.be.ok()
|
||||
expect(user.items.quests.goldenknight1).to.eql 1
|
||||
|
||||
it 'gets Moonstone Chain at level 60', ->
|
||||
user = newUser()
|
||||
user.stats.lvl = 60
|
||||
user.fns.updateStats(user.stats)
|
||||
expect(user.flags.levelDrops.moonstone1).to.be.ok()
|
||||
expect(user.items.quests.moonstone1).to.eql 1
|
||||
|
||||
describe 'Simple Scoring', ->
|
||||
beforeEach ->
|
||||
{@before, @after} = beforeAfter()
|
||||
|
||||
it 'Habits : Up', ->
|
||||
@after.ops.score {params: {id: @after.habits[0].id, direction: 'down'}, query: {times: 5}}
|
||||
expectLostPoints(@before, @after,'habit')
|
||||
|
||||
it 'Habits : Down', ->
|
||||
@after.ops.score {params: {id: @after.habits[0].id, direction: 'up'}, query: {times: 5}}
|
||||
expectGainedPoints(@before, @after,'habit')
|
||||
|
||||
it 'Dailys : Up', ->
|
||||
@after.ops.score {params: {id: @after.dailys[0].id, direction: 'up'}}
|
||||
expectGainedPoints(@before, @after,'daily')
|
||||
|
||||
it 'Dailys : Up, Down', ->
|
||||
@after.ops.score {params: {id: @after.dailys[0].id, direction: 'up'}}
|
||||
@after.ops.score {params: {id: @after.dailys[0].id, direction: 'down'}}
|
||||
expectClosePoints(@before, @after, 'daily')
|
||||
|
||||
it 'Todos : Up', ->
|
||||
@after.ops.score {params: {id: @after.todos[0].id, direction: 'up'}}
|
||||
expectGainedPoints(@before, @after,'todo')
|
||||
|
||||
it 'Todos : Up, Down', ->
|
||||
@after.ops.score {params: {id: @after.todos[0].id, direction: 'up'}}
|
||||
@after.ops.score {params: {id: @after.todos[0].id, direction: 'down'}}
|
||||
expectClosePoints(@before, @after, 'todo')
|
||||
|
||||
describe 'Cron', ->
|
||||
|
||||
it 'computes shouldCron', ->
|
||||
user = newUser()
|
||||
|
||||
paths = {};user.fns.cron {paths}
|
||||
expect(user.lastCron).to.not.be.ok # it setup the cron property now
|
||||
|
||||
user.lastCron = +moment().subtract(1,'days')
|
||||
|
||||
paths = {};user.fns.cron {paths}
|
||||
expect(user.lastCron).to.be.greaterThan 0
|
||||
|
||||
# user.lastCron = +moment().add(1,'days')
|
||||
# paths = {};algos.cron user, {paths}
|
||||
# expect(paths.lastCron).to.be true # busted cron (was set to after today's date)
|
||||
|
||||
it 'only dailies & todos are affected', ->
|
||||
{before,after} = beforeAfter({daysAgo:1})
|
||||
before.dailys = before.todos = after.dailys = after.todos = []
|
||||
after.fns.cron()
|
||||
before.stats.mp=after.stats.mp #FIXME
|
||||
expect(after.lastCron).to.not.be before.lastCron # make sure cron was run
|
||||
delete after.stats.buffs;delete before.stats.buffs
|
||||
expect(before.stats).to.eql after.stats
|
||||
beforeTasks = before.habits.concat(before.dailys).concat(before.todos).concat(before.rewards)
|
||||
afterTasks = after.habits.concat(after.dailys).concat(after.todos).concat(after.rewards)
|
||||
expect(beforeTasks).to.eql afterTasks
|
||||
|
||||
describe 'preening', ->
|
||||
beforeEach ->
|
||||
@clock = sinon.useFakeTimers(Date.parse("2013-11-20"), "Date")
|
||||
|
||||
afterEach ->
|
||||
@clock.restore()
|
||||
|
||||
it 'should preen user history', ->
|
||||
{before,after} = beforeAfter({daysAgo:1})
|
||||
history = [
|
||||
# Last year should be condensed to one entry, avg: 1
|
||||
{date:'09/01/2012', value: 0}
|
||||
{date:'10/01/2012', value: 0}
|
||||
{date:'11/01/2012', value: 2}
|
||||
{date:'12/01/2012', value: 2}
|
||||
|
||||
# Each month of this year should be condensed to 1/mo, averages follow
|
||||
{date:'01/01/2013', value: 1} #2
|
||||
{date:'01/15/2013', value: 3}
|
||||
|
||||
{date:'02/01/2013', value: 2} #3
|
||||
{date:'02/15/2013', value: 4}
|
||||
|
||||
{date:'03/01/2013', value: 3} #4
|
||||
{date:'03/15/2013', value: 5}
|
||||
|
||||
{date:'04/01/2013', value: 4} #5
|
||||
{date:'04/15/2013', value: 6}
|
||||
|
||||
{date:'05/01/2013', value: 5} #6
|
||||
{date:'05/15/2013', value: 7}
|
||||
|
||||
{date:'06/01/2013', value: 6} #7
|
||||
{date:'06/15/2013', value: 8}
|
||||
|
||||
{date:'07/01/2013', value: 7} #8
|
||||
{date:'07/15/2013', value: 9}
|
||||
|
||||
{date:'08/01/2013', value: 8} #9
|
||||
{date:'08/15/2013', value: 10}
|
||||
|
||||
{date:'09/01/2013', value: 9} #10
|
||||
{date:'09/15/2013', value: 11}
|
||||
|
||||
{date:'010/01/2013', value: 10} #11
|
||||
{date:'010/15/2013', value: 12}
|
||||
|
||||
# This month should condense each week
|
||||
{date:'011/01/2013', value: 12}
|
||||
{date:'011/02/2013', value: 13}
|
||||
{date:'011/03/2013', value: 14}
|
||||
{date:'011/04/2013', value: 15}
|
||||
]
|
||||
after.history = {exp: _.cloneDeep(history), todos: _.cloneDeep(history)}
|
||||
after.habits[0].history = _.cloneDeep(history)
|
||||
after.fns.cron()
|
||||
|
||||
# remove history entries created by cron
|
||||
after.history.exp.pop()
|
||||
after.history.todos.pop()
|
||||
|
||||
_.each [after.history.exp, after.history.todos, after.habits[0].history], (arr) ->
|
||||
expect(_.map(arr, (x)->x.value)).to.eql [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
|
||||
|
||||
describe 'Todos', ->
|
||||
it '1 day missed', ->
|
||||
{before,after} = beforeAfter({daysAgo:1})
|
||||
before.dailys = after.dailys = []
|
||||
after.fns.cron()
|
||||
|
||||
# todos don't effect stats
|
||||
expect(after).toHaveHP 50
|
||||
expect(after).toHaveExp 0
|
||||
expect(after).toHaveGP 0
|
||||
|
||||
# but they devalue
|
||||
expect(before.todos[0].value).to.be 0 # sanity check for task setup
|
||||
expect(after.todos[0].value).to.be -1 # the actual test
|
||||
expect(after.history.todos).to.have.length 1
|
||||
|
||||
it '2 days missed', ->
|
||||
{before,after} = beforeAfter({daysAgo:2})
|
||||
before.dailys = after.dailys = []
|
||||
after.fns.cron()
|
||||
|
||||
# todos devalue by only one day's worth of devaluation
|
||||
expect(before.todos[0].value).to.be 0 # sanity check for task setup
|
||||
expect(after.todos[0].value).to.be -1 # the actual test
|
||||
|
||||
# I used hard-coded dates here instead of 'now' so the tests don't fail
|
||||
# when you run them between midnight and dayStart. Nothing worse than
|
||||
# intermittent failures.
|
||||
describe 'cron day calculations', ->
|
||||
dayStart = 4
|
||||
fstr = "YYYY-MM-DD HH:mm:ss"
|
||||
|
||||
it 'startOfDay before dayStart', ->
|
||||
# If the time is before dayStart, then we expect the start of the day to be yesterday at dayStart
|
||||
start = shared.startOfDay {now: moment('2014-10-09 02:30:00'), dayStart}
|
||||
expect(start.format(fstr)).to.eql '2014-10-08 04:00:00'
|
||||
|
||||
it 'startOfDay after dayStart', ->
|
||||
# If the time is after dayStart, then we expect the start of the day to be today at dayStart
|
||||
start = shared.startOfDay {now: moment('2014-10-09 05:30:00'), dayStart}
|
||||
expect(start.format(fstr)).to.eql '2014-10-09 04:00:00'
|
||||
|
||||
it 'daysSince cron before, now after', ->
|
||||
# If the lastCron was before dayStart, then a time on the same day after dayStart
|
||||
# should be 1 day later than lastCron
|
||||
lastCron = moment('2014-10-09 02:30:00')
|
||||
days = shared.daysSince(lastCron, {now: moment('2014-10-09 11:30:00'), dayStart})
|
||||
expect(days).to.eql 1
|
||||
|
||||
it 'daysSince cron before, now before', ->
|
||||
# If the lastCron was before dayStart, then a time on the same day also before dayStart
|
||||
# should be 0 days later than lastCron
|
||||
lastCron = moment('2014-10-09 02:30:00')
|
||||
days = shared.daysSince(lastCron, {now: moment('2014-10-09 03:30:00'), dayStart})
|
||||
expect(days).to.eql 0
|
||||
|
||||
it 'daysSince cron after, now after', ->
|
||||
# If the lastCron was after dayStart, then a time on the same day also after dayStart
|
||||
# should be 0 days later than lastCron
|
||||
lastCron = moment('2014-10-09 05:30:00')
|
||||
days = shared.daysSince(lastCron, {now: moment('2014-10-09 06:30:00'), dayStart})
|
||||
expect(days).to.eql 0
|
||||
|
||||
it 'daysSince cron after, now tomorrow before', ->
|
||||
# If the lastCron was after dayStart, then a time on the following day but before dayStart
|
||||
# should be 0 days later than lastCron
|
||||
lastCron = moment('2014-10-09 12:30:00')
|
||||
days = shared.daysSince(lastCron, {now: moment('2014-10-10 01:30:00'), dayStart})
|
||||
expect(days).to.eql 0
|
||||
|
||||
it 'daysSince cron after, now tomorrow after', ->
|
||||
# If the lastCron was after dayStart, then a time on the following day and after dayStart
|
||||
# should be 1 day later than lastCron
|
||||
lastCron = moment('2014-10-09 12:30:00')
|
||||
days = shared.daysSince(lastCron, {now: moment('2014-10-10 10:30:00'), dayStart})
|
||||
expect(days).to.eql 1
|
||||
|
||||
xit 'daysSince, last cron before new dayStart', ->
|
||||
# If lastCron was after dayStart (at 1am) with dayStart set at 0, changing dayStart to 4am
|
||||
# should not trigger another cron the same day
|
||||
|
||||
# dayStart is 0
|
||||
lastCron = moment('2014-10-09 01:00:00')
|
||||
# dayStart is 4
|
||||
days = shared.daysSince(lastCron, {now: moment('2014-10-09 05:00:00'), dayStart})
|
||||
expect(days).to.eql 0
|
||||
|
||||
describe 'dailies', ->
|
||||
|
||||
describe 'new day', ->
|
||||
|
||||
###
|
||||
This section runs through a "cron matrix" of all permutations (that I can easily account for). It sets
|
||||
task due days, user custom day start, timezoneOffset, etc - then runs cron, jumps to tomorrow and runs cron,
|
||||
and so on - testing each possible outcome along the way
|
||||
###
|
||||
|
||||
runCron = (options) ->
|
||||
_.each [480, 240, 0, -120], (timezoneOffset) -> # test different timezones
|
||||
now = shared.startOfWeek({timezoneOffset}).add(options.currentHour||0, 'hours')
|
||||
{before,after} = beforeAfter({now, timezoneOffset, daysAgo:1, cronAfterStart:options.cronAfterStart||true, dayStart:options.dayStart||0, limitOne:'daily'})
|
||||
before.dailys[0].repeat = after.dailys[0].repeat = options.repeat if options.repeat
|
||||
before.dailys[0].streak = after.dailys[0].streak = 10
|
||||
before.dailys[0].completed = after.dailys[0].completed = true if options.checked
|
||||
before.dailys[0].startDate = after.dailys[0].startDate = moment().subtract(30, 'days')
|
||||
if options.shouldDo
|
||||
expect(shared.shouldDo(now.toDate(), after.dailys[0], {timezoneOffset, dayStart:options.dayStart, now})).to.be.ok()
|
||||
after.fns.cron {now}
|
||||
before.stats.mp=after.stats.mp #FIXME
|
||||
switch options.expect
|
||||
when 'losePoints' then expectLostPoints(before,after,'daily')
|
||||
when 'noChange' then expectNoChange(before,after)
|
||||
when 'noDamage' then expectDayResetNoDamage(before,after)
|
||||
{before,after}
|
||||
|
||||
# These test cases were written assuming that lastCron was run after dayStart
|
||||
# even if currentHour < dayStart and lastCron = yesterday at currentHour.
|
||||
# cronAfterStart makes sure that lastCron is moved to be after dayStart.
|
||||
cronMatrix =
|
||||
steps:
|
||||
|
||||
'due yesterday':
|
||||
defaults: {daysAgo:1, cronAfterStart:true, limitOne: 'daily'}
|
||||
steps:
|
||||
|
||||
'(simple)': {expect:'losePoints'}
|
||||
|
||||
'due today':
|
||||
# NOTE: a strange thing here, moment().startOf('week') is Sunday, but moment.zone(myTimeZone).startOf('week') is Monday.
|
||||
defaults: {repeat:{su:true,m:true,t:true,w:true,th:true,f:true,s:true}}
|
||||
steps:
|
||||
'pre-dayStart':
|
||||
defaults: {currentHour:3, dayStart:4, shouldDo:true}
|
||||
steps:
|
||||
'checked': {checked: true, expect:'noChange'}
|
||||
'un-checked': {checked: false, expect:'noChange'}
|
||||
'post-dayStart':
|
||||
defaults: {currentHour:5, dayStart:4, shouldDo:true}
|
||||
steps:
|
||||
'checked': {checked:true, expect:'noDamage'}
|
||||
'unchecked': {checked:false, expect: 'losePoints'}
|
||||
|
||||
'NOT due today':
|
||||
defaults: {repeat:{su:true,m:false,t:true,w:true,th:true,f:true,s:true}}
|
||||
steps:
|
||||
'pre-dayStart':
|
||||
defaults: {currentHour:3, dayStart:4, shouldDo:true}
|
||||
steps:
|
||||
'checked': {checked: true, expect:'noChange'}
|
||||
'un-checked': {checked: false, expect:'noChange'}
|
||||
'post-dayStart':
|
||||
defaults: {currentHour:5, dayStart:4, shouldDo:false}
|
||||
steps:
|
||||
'checked': {checked:true, expect:'noDamage'}
|
||||
'unchecked': {checked:false, expect: 'losePoints'}
|
||||
|
||||
'not due yesterday':
|
||||
defaults: repeatWithoutLastWeekday()
|
||||
steps:
|
||||
'(simple)': {expect:'noDamage'}
|
||||
'post-dayStart': {currentHour:5,dayStart:4, expect:'noDamage'}
|
||||
'pre-dayStart': {currentHour:3, dayStart:4, expect:'noChange'}
|
||||
|
||||
recurseCronMatrix = (obj, options={}) ->
|
||||
if obj.steps
|
||||
_.each obj.steps, (step, text) ->
|
||||
o = _.cloneDeep options
|
||||
o.text ?= ''; o.text += " #{text} "
|
||||
recurseCronMatrix step, _.defaults(o,obj.defaults)
|
||||
else
|
||||
it "#{options.text}", -> runCron(_.defaults(obj,options))
|
||||
recurseCronMatrix(cronMatrix)
|
||||
|
||||
describe 'Helper', ->
|
||||
|
||||
it 'calculates gold coins', ->
|
||||
expect(shared.gold(10)).to.eql 10
|
||||
expect(shared.gold(1.957)).to.eql 1
|
||||
expect(shared.gold()).to.eql 0
|
||||
|
||||
it 'calculates silver coins', ->
|
||||
expect(shared.silver(10)).to.eql 0
|
||||
expect(shared.silver(1.957)).to.eql 95
|
||||
expect(shared.silver(0.01)).to.eql "01"
|
||||
expect(shared.silver()).to.eql "00"
|
||||
|
||||
it 'calculates experience to next level', ->
|
||||
expect(shared.tnl 1).to.eql 150
|
||||
expect(shared.tnl 2).to.eql 160
|
||||
expect(shared.tnl 10).to.eql 260
|
||||
expect(shared.tnl 99).to.eql 3580
|
||||
|
||||
it 'calculates the start of the day', ->
|
||||
fstr = 'YYYY-MM-DD HH:mm:ss'
|
||||
today = '2013-01-01 00:00:00'
|
||||
# get the timezone for the day, so the test case doesn't fail
|
||||
# if you run it during daylight savings time because by default
|
||||
# it uses moment().zone() which is the current minute offset
|
||||
zone = moment(today).zone()
|
||||
expect(shared.startOfDay({now: new Date(2013, 0, 1, 0)}, timezoneOffset:zone).format(fstr)).to.eql today
|
||||
expect(shared.startOfDay({now: new Date(2013, 0, 1, 5)}, timezoneOffset:zone).format(fstr)).to.eql today
|
||||
expect(shared.startOfDay({now: new Date(2013, 0, 1, 23, 59, 59), timezoneOffset:zone}).format(fstr)).to.eql today
|
||||
1507
test/common/algos.mocha.js
Normal file
1507
test/common/algos.mocha.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,418 +0,0 @@
|
||||
_ = require 'lodash'
|
||||
expect = require 'expect.js'
|
||||
sinon = require 'sinon'
|
||||
moment = require 'moment'
|
||||
shared = require '../../common/script/index.js'
|
||||
shared.i18n.translations = require('../../website/src/libs/i18n.js').translations
|
||||
|
||||
repeatWithoutLastWeekday = ()->
|
||||
repeat = {su:true,m:true,t:true,w:true,th:true,f:true,s:true}
|
||||
if shared.startOfWeek(moment().zone(0)).isoWeekday() == 1 # Monday
|
||||
repeat.su = false
|
||||
else
|
||||
repeat.s = false
|
||||
{repeat: repeat}
|
||||
|
||||
### Helper Functions ####
|
||||
# @TODO: Refactor into helper file
|
||||
newUser = (addTasks=true)->
|
||||
buffs = {per:0, int:0, con:0, str:0, stealth: 0, streaks: false}
|
||||
user =
|
||||
auth:
|
||||
timestamps: {}
|
||||
stats: {str:1, con:1, per:1, int:1, mp: 32, class: 'warrior', buffs: buffs}
|
||||
items:
|
||||
lastDrop:
|
||||
count: 0
|
||||
hatchingPotions: {}
|
||||
eggs: {}
|
||||
food: {}
|
||||
gear:
|
||||
equipped: {}
|
||||
costume: {}
|
||||
party:
|
||||
quest:
|
||||
progress:
|
||||
down: 0
|
||||
preferences: {}
|
||||
dailys: []
|
||||
todos: []
|
||||
rewards: []
|
||||
flags: {}
|
||||
achievements: {}
|
||||
contributor:
|
||||
level: 2
|
||||
shared.wrap(user)
|
||||
user.ops.reset(null, ->)
|
||||
if addTasks
|
||||
_.each ['habit', 'todo', 'daily'], (task)->
|
||||
user.ops.addTask {body: {type: task, id: shared.uuid()}}
|
||||
user
|
||||
|
||||
cron = (usr, missedDays=1) ->
|
||||
usr.lastCron = moment().subtract(missedDays,'days')
|
||||
usr.fns.cron()
|
||||
|
||||
describe 'daily/weekly that repeats everyday (default)', ->
|
||||
user = null
|
||||
daily = null
|
||||
weekly = null
|
||||
|
||||
describe 'when startDate is in the future', ->
|
||||
beforeEach ->
|
||||
user = newUser()
|
||||
user.dailys = [
|
||||
shared.taskDefaults({type:'daily', startDate: moment().add(7, 'days'), frequency: 'daily'})
|
||||
shared.taskDefaults({type:'daily', startDate: moment().add(7, 'days'), frequency: 'weekly', repeat: {su:true,m:true,t:true,w:true,th:true,f:true,s:true}})
|
||||
]
|
||||
daily = user.dailys[0]
|
||||
weekly = user.dailys[1]
|
||||
|
||||
it 'does not damage user for not completing it', ->
|
||||
cron(user)
|
||||
expect(user.stats.hp).to.be 50
|
||||
|
||||
it 'does not change value on cron if daily is incomplete', ->
|
||||
cron(user)
|
||||
expect(daily.value).to.be 0
|
||||
expect(weekly.value).to.be 0
|
||||
|
||||
it 'does not reset checklists if daily is not marked as complete', ->
|
||||
checklist = [
|
||||
{
|
||||
'text' : '1',
|
||||
'id' : 'checklist-one',
|
||||
'completed' : true
|
||||
},
|
||||
{
|
||||
'text' : '2',
|
||||
'id' : 'checklist-two',
|
||||
'completed' : true
|
||||
},
|
||||
{
|
||||
'text' : '3',
|
||||
'id' : 'checklist-three',
|
||||
'completed' : false
|
||||
}
|
||||
]
|
||||
daily.checklist = checklist
|
||||
weekly.checklist = checklist
|
||||
cron(user)
|
||||
|
||||
expect(daily.checklist[0].completed).to.be true
|
||||
expect(daily.checklist[1].completed).to.be true
|
||||
expect(daily.checklist[2].completed).to.be false
|
||||
|
||||
expect(weekly.checklist[0].completed).to.be true
|
||||
expect(weekly.checklist[1].completed).to.be true
|
||||
expect(weekly.checklist[2].completed).to.be false
|
||||
|
||||
it 'resets checklists if daily is marked as complete', ->
|
||||
checklist = [
|
||||
{
|
||||
'text' : '1',
|
||||
'id' : 'checklist-one',
|
||||
'completed' : true
|
||||
},
|
||||
{
|
||||
'text' : '2',
|
||||
'id' : 'checklist-two',
|
||||
'completed' : true
|
||||
},
|
||||
{
|
||||
'text' : '3',
|
||||
'id' : 'checklist-three',
|
||||
'completed' : false
|
||||
}
|
||||
]
|
||||
daily.checklist = checklist
|
||||
weekly.checklist = checklist
|
||||
daily.completed = true
|
||||
weekly.completed = true
|
||||
cron(user)
|
||||
|
||||
_.each daily.checklist, (box)->
|
||||
expect(box.completed).to.be false
|
||||
|
||||
_.each weekly.checklist, (box)->
|
||||
expect(box.completed).to.be false
|
||||
|
||||
it 'is due on startDate', ->
|
||||
daily_due_today = shared.shouldDo moment(), daily
|
||||
daily_due_on_start_date = shared.shouldDo moment().add(7, 'days'), daily
|
||||
|
||||
expect(daily_due_today).to.be false
|
||||
expect(daily_due_on_start_date).to.be true
|
||||
|
||||
weekly_due_today = shared.shouldDo moment(), weekly
|
||||
weekly_due_on_start_date = shared.shouldDo moment().add(7, 'days'), weekly
|
||||
|
||||
expect(weekly_due_today).to.be false
|
||||
expect(weekly_due_on_start_date).to.be true
|
||||
|
||||
describe 'when startDate is in the past', ->
|
||||
beforeEach ->
|
||||
user = newUser()
|
||||
user.dailys = [
|
||||
shared.taskDefaults({type:'daily', startDate: moment().subtract(7, 'days'), frequency: 'daily'})
|
||||
shared.taskDefaults({type:'daily', startDate: moment().subtract(7, 'days'), frequency: 'weekly'})
|
||||
]
|
||||
daily = user.dailys[0]
|
||||
weekly = user.dailys[1]
|
||||
|
||||
it 'does damage user for not completing it', ->
|
||||
cron(user)
|
||||
expect(user.stats.hp).to.be.lessThan 50
|
||||
|
||||
it 'decreases value on cron if daily is incomplete', ->
|
||||
cron(user, 1)
|
||||
expect(daily.value).to.be -1
|
||||
expect(weekly.value).to.be -1
|
||||
|
||||
it 'decreases value on cron once only if daily is incomplete and multiple days are missed', ->
|
||||
cron(user, 7)
|
||||
expect(daily.value).to.be -1
|
||||
expect(weekly.value).to.be -1
|
||||
|
||||
it 'resets checklists if daily is not marked as complete', ->
|
||||
checklist = [
|
||||
{
|
||||
'text' : '1',
|
||||
'id' : 'checklist-one',
|
||||
'completed' : true
|
||||
},
|
||||
{
|
||||
'text' : '2',
|
||||
'id' : 'checklist-two',
|
||||
'completed' : true
|
||||
},
|
||||
{
|
||||
'text' : '3',
|
||||
'id' : 'checklist-three',
|
||||
'completed' : false
|
||||
}
|
||||
]
|
||||
daily.checklist = checklist
|
||||
weekly.checklist = checklist
|
||||
cron(user)
|
||||
|
||||
_.each daily.checklist, (box)->
|
||||
expect(box.completed).to.be false
|
||||
|
||||
_.each weekly.checklist, (box)->
|
||||
expect(box.completed).to.be false
|
||||
|
||||
it 'resets checklists if daily is marked as complete', ->
|
||||
checklist = [
|
||||
{
|
||||
'text' : '1',
|
||||
'id' : 'checklist-one',
|
||||
'completed' : true
|
||||
},
|
||||
{
|
||||
'text' : '2',
|
||||
'id' : 'checklist-two',
|
||||
'completed' : true
|
||||
},
|
||||
{
|
||||
'text' : '3',
|
||||
'id' : 'checklist-three',
|
||||
'completed' : false
|
||||
}
|
||||
]
|
||||
daily.checklist = checklist
|
||||
daily.completed = true
|
||||
weekly.checklist = checklist
|
||||
weekly.completed = true
|
||||
cron(user)
|
||||
|
||||
_.each daily.checklist, (box)->
|
||||
expect(box.completed).to.be false
|
||||
|
||||
_.each weekly.checklist, (box)->
|
||||
expect(box.completed).to.be false
|
||||
|
||||
describe 'when startDate is today', ->
|
||||
beforeEach ->
|
||||
user = newUser()
|
||||
user.dailys = [
|
||||
# Must set start date to yesterday, because cron mock sets last cron to yesterday
|
||||
shared.taskDefaults({type:'daily', startDate: moment().subtract(1, 'days'), frequency: 'daily'})
|
||||
shared.taskDefaults({type:'daily', startDate: moment().subtract(1, 'days'), frequency: 'weekly'})
|
||||
]
|
||||
daily = user.dailys[0]
|
||||
weekly = user.dailys[1]
|
||||
|
||||
it 'does damage user for not completing it', ->
|
||||
cron(user)
|
||||
expect(user.stats.hp).to.be.lessThan 50
|
||||
|
||||
it 'decreases value on cron if daily is incomplete', ->
|
||||
cron(user)
|
||||
expect(daily.value).to.be.lessThan 0
|
||||
expect(weekly.value).to.be.lessThan 0
|
||||
|
||||
it 'resets checklists if daily is not marked as complete', ->
|
||||
checklist = [
|
||||
{
|
||||
'text' : '1',
|
||||
'id' : 'checklist-one',
|
||||
'completed' : true
|
||||
},
|
||||
{
|
||||
'text' : '2',
|
||||
'id' : 'checklist-two',
|
||||
'completed' : true
|
||||
},
|
||||
{
|
||||
'text' : '3',
|
||||
'id' : 'checklist-three',
|
||||
'completed' : false
|
||||
}
|
||||
]
|
||||
daily.checklist = checklist
|
||||
weekly.checklist = checklist
|
||||
cron(user)
|
||||
|
||||
_.each daily.checklist, (box)->
|
||||
expect(box.completed).to.be false
|
||||
|
||||
_.each weekly.checklist, (box)->
|
||||
expect(box.completed).to.be false
|
||||
|
||||
it 'resets checklists if daily is marked as complete', ->
|
||||
checklist = [
|
||||
{
|
||||
'text' : '1',
|
||||
'id' : 'checklist-one',
|
||||
'completed' : true
|
||||
},
|
||||
{
|
||||
'text' : '2',
|
||||
'id' : 'checklist-two',
|
||||
'completed' : true
|
||||
},
|
||||
{
|
||||
'text' : '3',
|
||||
'id' : 'checklist-three',
|
||||
'completed' : false
|
||||
}
|
||||
]
|
||||
daily.checklist = checklist
|
||||
daily.completed = true
|
||||
weekly.checklist = checklist
|
||||
weekly.completed = true
|
||||
cron(user)
|
||||
|
||||
_.each daily.checklist, (box)->
|
||||
expect(box.completed).to.be false
|
||||
|
||||
_.each weekly.checklist, (box)->
|
||||
expect(box.completed).to.be false
|
||||
|
||||
describe 'daily that repeats every x days', ->
|
||||
user = null
|
||||
daily = null
|
||||
|
||||
beforeEach ->
|
||||
user = newUser()
|
||||
user.dailys = [ shared.taskDefaults({type:'daily', startDate: moment(), frequency: 'daily'}) ]
|
||||
daily = user.dailys[0]
|
||||
|
||||
_.times 11, (due) ->
|
||||
|
||||
it 'where x equals ' + due, ->
|
||||
daily.everyX = due
|
||||
|
||||
_.times 30, (day) ->
|
||||
isDue = shared.shouldDo moment().add(day, 'days'), daily
|
||||
expect(isDue).to.be true if day % due == 0
|
||||
expect(isDue).to.be false if day % due != 0
|
||||
|
||||
describe 'daily that repeats every X days when multiple days are missed', ->
|
||||
everyX = 3
|
||||
startDateDaysAgo = everyX * 3
|
||||
user = null
|
||||
daily = null
|
||||
|
||||
describe 'including missing a due date', ->
|
||||
missedDays = everyX * 2 + 1
|
||||
|
||||
beforeEach ->
|
||||
user = newUser()
|
||||
user.dailys = [
|
||||
shared.taskDefaults({type:'daily', startDate: moment().subtract(startDateDaysAgo, 'days'), frequency: 'daily', everyX: everyX})
|
||||
]
|
||||
daily = user.dailys[0]
|
||||
|
||||
it 'decreases value on cron once only if daily is incomplete', ->
|
||||
cron(user, missedDays)
|
||||
expect(daily.value).to.be -1
|
||||
|
||||
it 'resets checklists if daily is incomplete', ->
|
||||
checklist = [
|
||||
{
|
||||
'text' : '1',
|
||||
'id' : 'checklist-one',
|
||||
'completed' : true
|
||||
}
|
||||
]
|
||||
daily.checklist = checklist
|
||||
cron(user, missedDays)
|
||||
_.each daily.checklist, (box)->
|
||||
expect(box.completed).to.be false
|
||||
|
||||
it 'resets checklists if daily is marked as complete', ->
|
||||
checklist = [
|
||||
{
|
||||
'text' : '1',
|
||||
'id' : 'checklist-one',
|
||||
'completed' : true
|
||||
}
|
||||
]
|
||||
daily.checklist = checklist
|
||||
daily.completed = true
|
||||
cron(user, missedDays)
|
||||
_.each daily.checklist, (box)->
|
||||
expect(box.completed).to.be false
|
||||
|
||||
describe 'but not missing a due date', ->
|
||||
missedDays = everyX - 1
|
||||
|
||||
beforeEach ->
|
||||
user = newUser()
|
||||
user.dailys = [
|
||||
shared.taskDefaults({type:'daily', startDate: moment().subtract(startDateDaysAgo, 'days'), frequency: 'daily', everyX: everyX})
|
||||
]
|
||||
daily = user.dailys[0]
|
||||
|
||||
it 'does not decrease value on cron', ->
|
||||
cron(user, missedDays)
|
||||
expect(daily.value).to.be 0
|
||||
|
||||
it 'does not reset checklists if daily is incomplete', ->
|
||||
checklist = [
|
||||
{
|
||||
'text' : '1',
|
||||
'id' : 'checklist-one',
|
||||
'completed' : true
|
||||
}
|
||||
]
|
||||
daily.checklist = checklist
|
||||
cron(user, missedDays)
|
||||
_.each daily.checklist, (box)->
|
||||
expect(box.completed).to.be true
|
||||
|
||||
it 'resets checklists if daily is marked as complete', ->
|
||||
checklist = [
|
||||
{
|
||||
'text' : '1',
|
||||
'id' : 'checklist-one',
|
||||
'completed' : true
|
||||
}
|
||||
]
|
||||
daily.checklist = checklist
|
||||
daily.completed = true
|
||||
cron(user, missedDays)
|
||||
_.each daily.checklist, (box)->
|
||||
expect(box.completed).to.be false
|
||||
538
test/common/dailies.js
Normal file
538
test/common/dailies.js
Normal file
@@ -0,0 +1,538 @@
|
||||
var _, cron, expect, moment, newUser, repeatWithoutLastWeekday, shared, sinon;
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
expect = require('expect.js');
|
||||
|
||||
sinon = require('sinon');
|
||||
|
||||
moment = require('moment');
|
||||
|
||||
shared = require('../../common/script/index.js');
|
||||
|
||||
shared.i18n.translations = require('../../website/src/libs/i18n.js').translations;
|
||||
|
||||
repeatWithoutLastWeekday = function() {
|
||||
var repeat;
|
||||
repeat = {
|
||||
su: true,
|
||||
m: true,
|
||||
t: true,
|
||||
w: true,
|
||||
th: true,
|
||||
f: true,
|
||||
s: true
|
||||
};
|
||||
if (shared.startOfWeek(moment().zone(0)).isoWeekday() === 1) {
|
||||
repeat.su = false;
|
||||
} else {
|
||||
repeat.s = false;
|
||||
}
|
||||
return {
|
||||
repeat: repeat
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* Helper Functions */
|
||||
|
||||
newUser = function(addTasks) {
|
||||
var buffs, user;
|
||||
if (addTasks == null) {
|
||||
addTasks = true;
|
||||
}
|
||||
buffs = {
|
||||
per: 0,
|
||||
int: 0,
|
||||
con: 0,
|
||||
str: 0,
|
||||
stealth: 0,
|
||||
streaks: false
|
||||
};
|
||||
user = {
|
||||
auth: {
|
||||
timestamps: {}
|
||||
},
|
||||
stats: {
|
||||
str: 1,
|
||||
con: 1,
|
||||
per: 1,
|
||||
int: 1,
|
||||
mp: 32,
|
||||
"class": 'warrior',
|
||||
buffs: buffs
|
||||
},
|
||||
items: {
|
||||
lastDrop: {
|
||||
count: 0
|
||||
},
|
||||
hatchingPotions: {},
|
||||
eggs: {},
|
||||
food: {},
|
||||
gear: {
|
||||
equipped: {},
|
||||
costume: {}
|
||||
}
|
||||
},
|
||||
party: {
|
||||
quest: {
|
||||
progress: {
|
||||
down: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
preferences: {},
|
||||
dailys: [],
|
||||
todos: [],
|
||||
rewards: [],
|
||||
flags: {},
|
||||
achievements: {},
|
||||
contributor: {
|
||||
level: 2
|
||||
}
|
||||
};
|
||||
shared.wrap(user);
|
||||
user.ops.reset(null, function() {});
|
||||
if (addTasks) {
|
||||
_.each(['habit', 'todo', 'daily'], function(task) {
|
||||
return user.ops.addTask({
|
||||
body: {
|
||||
type: task,
|
||||
id: shared.uuid()
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
return user;
|
||||
};
|
||||
|
||||
cron = function(usr, missedDays) {
|
||||
if (missedDays == null) {
|
||||
missedDays = 1;
|
||||
}
|
||||
usr.lastCron = moment().subtract(missedDays, 'days');
|
||||
return usr.fns.cron();
|
||||
};
|
||||
|
||||
describe('daily/weekly that repeats everyday (default)', function() {
|
||||
var daily, user, weekly;
|
||||
user = null;
|
||||
daily = null;
|
||||
weekly = null;
|
||||
describe('when startDate is in the future', function() {
|
||||
beforeEach(function() {
|
||||
user = newUser();
|
||||
user.dailys = [
|
||||
shared.taskDefaults({
|
||||
type: 'daily',
|
||||
startDate: moment().add(7, 'days'),
|
||||
frequency: 'daily'
|
||||
}), shared.taskDefaults({
|
||||
type: 'daily',
|
||||
startDate: moment().add(7, 'days'),
|
||||
frequency: 'weekly',
|
||||
repeat: {
|
||||
su: true,
|
||||
m: true,
|
||||
t: true,
|
||||
w: true,
|
||||
th: true,
|
||||
f: true,
|
||||
s: true
|
||||
}
|
||||
})
|
||||
];
|
||||
daily = user.dailys[0];
|
||||
return weekly = user.dailys[1];
|
||||
});
|
||||
it('does not damage user for not completing it', function() {
|
||||
cron(user);
|
||||
return expect(user.stats.hp).to.be(50);
|
||||
});
|
||||
it('does not change value on cron if daily is incomplete', function() {
|
||||
cron(user);
|
||||
expect(daily.value).to.be(0);
|
||||
return expect(weekly.value).to.be(0);
|
||||
});
|
||||
it('does not reset checklists if daily is not marked as complete', function() {
|
||||
var checklist;
|
||||
checklist = [
|
||||
{
|
||||
'text': '1',
|
||||
'id': 'checklist-one',
|
||||
'completed': true
|
||||
}, {
|
||||
'text': '2',
|
||||
'id': 'checklist-two',
|
||||
'completed': true
|
||||
}, {
|
||||
'text': '3',
|
||||
'id': 'checklist-three',
|
||||
'completed': false
|
||||
}
|
||||
];
|
||||
daily.checklist = checklist;
|
||||
weekly.checklist = checklist;
|
||||
cron(user);
|
||||
expect(daily.checklist[0].completed).to.be(true);
|
||||
expect(daily.checklist[1].completed).to.be(true);
|
||||
expect(daily.checklist[2].completed).to.be(false);
|
||||
expect(weekly.checklist[0].completed).to.be(true);
|
||||
expect(weekly.checklist[1].completed).to.be(true);
|
||||
return expect(weekly.checklist[2].completed).to.be(false);
|
||||
});
|
||||
it('resets checklists if daily is marked as complete', function() {
|
||||
var checklist;
|
||||
checklist = [
|
||||
{
|
||||
'text': '1',
|
||||
'id': 'checklist-one',
|
||||
'completed': true
|
||||
}, {
|
||||
'text': '2',
|
||||
'id': 'checklist-two',
|
||||
'completed': true
|
||||
}, {
|
||||
'text': '3',
|
||||
'id': 'checklist-three',
|
||||
'completed': false
|
||||
}
|
||||
];
|
||||
daily.checklist = checklist;
|
||||
weekly.checklist = checklist;
|
||||
daily.completed = true;
|
||||
weekly.completed = true;
|
||||
cron(user);
|
||||
_.each(daily.checklist, function(box) {
|
||||
return expect(box.completed).to.be(false);
|
||||
});
|
||||
return _.each(weekly.checklist, function(box) {
|
||||
return expect(box.completed).to.be(false);
|
||||
});
|
||||
});
|
||||
return it('is due on startDate', function() {
|
||||
var daily_due_on_start_date, daily_due_today, weekly_due_on_start_date, weekly_due_today;
|
||||
daily_due_today = shared.shouldDo(moment(), daily);
|
||||
daily_due_on_start_date = shared.shouldDo(moment().add(7, 'days'), daily);
|
||||
expect(daily_due_today).to.be(false);
|
||||
expect(daily_due_on_start_date).to.be(true);
|
||||
weekly_due_today = shared.shouldDo(moment(), weekly);
|
||||
weekly_due_on_start_date = shared.shouldDo(moment().add(7, 'days'), weekly);
|
||||
expect(weekly_due_today).to.be(false);
|
||||
return expect(weekly_due_on_start_date).to.be(true);
|
||||
});
|
||||
});
|
||||
describe('when startDate is in the past', function() {
|
||||
beforeEach(function() {
|
||||
user = newUser();
|
||||
user.dailys = [
|
||||
shared.taskDefaults({
|
||||
type: 'daily',
|
||||
startDate: moment().subtract(7, 'days'),
|
||||
frequency: 'daily'
|
||||
}), shared.taskDefaults({
|
||||
type: 'daily',
|
||||
startDate: moment().subtract(7, 'days'),
|
||||
frequency: 'weekly'
|
||||
})
|
||||
];
|
||||
daily = user.dailys[0];
|
||||
return weekly = user.dailys[1];
|
||||
});
|
||||
it('does damage user for not completing it', function() {
|
||||
cron(user);
|
||||
return expect(user.stats.hp).to.be.lessThan(50);
|
||||
});
|
||||
it('decreases value on cron if daily is incomplete', function() {
|
||||
cron(user, 1);
|
||||
expect(daily.value).to.be(-1);
|
||||
return expect(weekly.value).to.be(-1);
|
||||
});
|
||||
it('decreases value on cron once only if daily is incomplete and multiple days are missed', function() {
|
||||
cron(user, 7);
|
||||
expect(daily.value).to.be(-1);
|
||||
return expect(weekly.value).to.be(-1);
|
||||
});
|
||||
it('resets checklists if daily is not marked as complete', function() {
|
||||
var checklist;
|
||||
checklist = [
|
||||
{
|
||||
'text': '1',
|
||||
'id': 'checklist-one',
|
||||
'completed': true
|
||||
}, {
|
||||
'text': '2',
|
||||
'id': 'checklist-two',
|
||||
'completed': true
|
||||
}, {
|
||||
'text': '3',
|
||||
'id': 'checklist-three',
|
||||
'completed': false
|
||||
}
|
||||
];
|
||||
daily.checklist = checklist;
|
||||
weekly.checklist = checklist;
|
||||
cron(user);
|
||||
_.each(daily.checklist, function(box) {
|
||||
return expect(box.completed).to.be(false);
|
||||
});
|
||||
return _.each(weekly.checklist, function(box) {
|
||||
return expect(box.completed).to.be(false);
|
||||
});
|
||||
});
|
||||
return it('resets checklists if daily is marked as complete', function() {
|
||||
var checklist;
|
||||
checklist = [
|
||||
{
|
||||
'text': '1',
|
||||
'id': 'checklist-one',
|
||||
'completed': true
|
||||
}, {
|
||||
'text': '2',
|
||||
'id': 'checklist-two',
|
||||
'completed': true
|
||||
}, {
|
||||
'text': '3',
|
||||
'id': 'checklist-three',
|
||||
'completed': false
|
||||
}
|
||||
];
|
||||
daily.checklist = checklist;
|
||||
daily.completed = true;
|
||||
weekly.checklist = checklist;
|
||||
weekly.completed = true;
|
||||
cron(user);
|
||||
_.each(daily.checklist, function(box) {
|
||||
return expect(box.completed).to.be(false);
|
||||
});
|
||||
return _.each(weekly.checklist, function(box) {
|
||||
return expect(box.completed).to.be(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
return describe('when startDate is today', function() {
|
||||
beforeEach(function() {
|
||||
user = newUser();
|
||||
user.dailys = [
|
||||
shared.taskDefaults({
|
||||
type: 'daily',
|
||||
startDate: moment().subtract(1, 'days'),
|
||||
frequency: 'daily'
|
||||
}), shared.taskDefaults({
|
||||
type: 'daily',
|
||||
startDate: moment().subtract(1, 'days'),
|
||||
frequency: 'weekly'
|
||||
})
|
||||
];
|
||||
daily = user.dailys[0];
|
||||
return weekly = user.dailys[1];
|
||||
});
|
||||
it('does damage user for not completing it', function() {
|
||||
cron(user);
|
||||
return expect(user.stats.hp).to.be.lessThan(50);
|
||||
});
|
||||
it('decreases value on cron if daily is incomplete', function() {
|
||||
cron(user);
|
||||
expect(daily.value).to.be.lessThan(0);
|
||||
return expect(weekly.value).to.be.lessThan(0);
|
||||
});
|
||||
it('resets checklists if daily is not marked as complete', function() {
|
||||
var checklist;
|
||||
checklist = [
|
||||
{
|
||||
'text': '1',
|
||||
'id': 'checklist-one',
|
||||
'completed': true
|
||||
}, {
|
||||
'text': '2',
|
||||
'id': 'checklist-two',
|
||||
'completed': true
|
||||
}, {
|
||||
'text': '3',
|
||||
'id': 'checklist-three',
|
||||
'completed': false
|
||||
}
|
||||
];
|
||||
daily.checklist = checklist;
|
||||
weekly.checklist = checklist;
|
||||
cron(user);
|
||||
_.each(daily.checklist, function(box) {
|
||||
return expect(box.completed).to.be(false);
|
||||
});
|
||||
return _.each(weekly.checklist, function(box) {
|
||||
return expect(box.completed).to.be(false);
|
||||
});
|
||||
});
|
||||
return it('resets checklists if daily is marked as complete', function() {
|
||||
var checklist;
|
||||
checklist = [
|
||||
{
|
||||
'text': '1',
|
||||
'id': 'checklist-one',
|
||||
'completed': true
|
||||
}, {
|
||||
'text': '2',
|
||||
'id': 'checklist-two',
|
||||
'completed': true
|
||||
}, {
|
||||
'text': '3',
|
||||
'id': 'checklist-three',
|
||||
'completed': false
|
||||
}
|
||||
];
|
||||
daily.checklist = checklist;
|
||||
daily.completed = true;
|
||||
weekly.checklist = checklist;
|
||||
weekly.completed = true;
|
||||
cron(user);
|
||||
_.each(daily.checklist, function(box) {
|
||||
return expect(box.completed).to.be(false);
|
||||
});
|
||||
return _.each(weekly.checklist, function(box) {
|
||||
return expect(box.completed).to.be(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('daily that repeats every x days', function() {
|
||||
var daily, user;
|
||||
user = null;
|
||||
daily = null;
|
||||
beforeEach(function() {
|
||||
user = newUser();
|
||||
user.dailys = [
|
||||
shared.taskDefaults({
|
||||
type: 'daily',
|
||||
startDate: moment(),
|
||||
frequency: 'daily'
|
||||
})
|
||||
];
|
||||
return daily = user.dailys[0];
|
||||
});
|
||||
return _.times(11, function(due) {
|
||||
return it('where x equals ' + due, function() {
|
||||
daily.everyX = due;
|
||||
return _.times(30, function(day) {
|
||||
var isDue;
|
||||
isDue = shared.shouldDo(moment().add(day, 'days'), daily);
|
||||
if (day % due === 0) {
|
||||
expect(isDue).to.be(true);
|
||||
}
|
||||
if (day % due !== 0) {
|
||||
return expect(isDue).to.be(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('daily that repeats every X days when multiple days are missed', function() {
|
||||
var daily, everyX, startDateDaysAgo, user;
|
||||
everyX = 3;
|
||||
startDateDaysAgo = everyX * 3;
|
||||
user = null;
|
||||
daily = null;
|
||||
describe('including missing a due date', function() {
|
||||
var missedDays;
|
||||
missedDays = everyX * 2 + 1;
|
||||
beforeEach(function() {
|
||||
user = newUser();
|
||||
user.dailys = [
|
||||
shared.taskDefaults({
|
||||
type: 'daily',
|
||||
startDate: moment().subtract(startDateDaysAgo, 'days'),
|
||||
frequency: 'daily',
|
||||
everyX: everyX
|
||||
})
|
||||
];
|
||||
return daily = user.dailys[0];
|
||||
});
|
||||
it('decreases value on cron once only if daily is incomplete', function() {
|
||||
cron(user, missedDays);
|
||||
return expect(daily.value).to.be(-1);
|
||||
});
|
||||
it('resets checklists if daily is incomplete', function() {
|
||||
var checklist;
|
||||
checklist = [
|
||||
{
|
||||
'text': '1',
|
||||
'id': 'checklist-one',
|
||||
'completed': true
|
||||
}
|
||||
];
|
||||
daily.checklist = checklist;
|
||||
cron(user, missedDays);
|
||||
return _.each(daily.checklist, function(box) {
|
||||
return expect(box.completed).to.be(false);
|
||||
});
|
||||
});
|
||||
return it('resets checklists if daily is marked as complete', function() {
|
||||
var checklist;
|
||||
checklist = [
|
||||
{
|
||||
'text': '1',
|
||||
'id': 'checklist-one',
|
||||
'completed': true
|
||||
}
|
||||
];
|
||||
daily.checklist = checklist;
|
||||
daily.completed = true;
|
||||
cron(user, missedDays);
|
||||
return _.each(daily.checklist, function(box) {
|
||||
return expect(box.completed).to.be(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
return describe('but not missing a due date', function() {
|
||||
var missedDays;
|
||||
missedDays = everyX - 1;
|
||||
beforeEach(function() {
|
||||
user = newUser();
|
||||
user.dailys = [
|
||||
shared.taskDefaults({
|
||||
type: 'daily',
|
||||
startDate: moment().subtract(startDateDaysAgo, 'days'),
|
||||
frequency: 'daily',
|
||||
everyX: everyX
|
||||
})
|
||||
];
|
||||
return daily = user.dailys[0];
|
||||
});
|
||||
it('does not decrease value on cron', function() {
|
||||
cron(user, missedDays);
|
||||
return expect(daily.value).to.be(0);
|
||||
});
|
||||
it('does not reset checklists if daily is incomplete', function() {
|
||||
var checklist;
|
||||
checklist = [
|
||||
{
|
||||
'text': '1',
|
||||
'id': 'checklist-one',
|
||||
'completed': true
|
||||
}
|
||||
];
|
||||
daily.checklist = checklist;
|
||||
cron(user, missedDays);
|
||||
return _.each(daily.checklist, function(box) {
|
||||
return expect(box.completed).to.be(true);
|
||||
});
|
||||
});
|
||||
return it('resets checklists if daily is marked as complete', function() {
|
||||
var checklist;
|
||||
checklist = [
|
||||
{
|
||||
'text': '1',
|
||||
'id': 'checklist-one',
|
||||
'completed': true
|
||||
}
|
||||
];
|
||||
daily.checklist = checklist;
|
||||
daily.completed = true;
|
||||
cron(user, missedDays);
|
||||
return _.each(daily.checklist, function(box) {
|
||||
return expect(box.completed).to.be(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,8 +0,0 @@
|
||||
--colors
|
||||
--reporter spec
|
||||
--timeout 8000
|
||||
--check-leaks
|
||||
--growl
|
||||
--debug
|
||||
--compilers coffee:coffee-script
|
||||
--globals io
|
||||
@@ -1,82 +0,0 @@
|
||||
###
|
||||
1) clone the repo
|
||||
2) npm install
|
||||
3) coffee ./tests/math_samples.coffee
|
||||
|
||||
Current results at https://gist.github.com/lefnire/8049676
|
||||
###
|
||||
|
||||
shared = require '../../../common/script/index.js'
|
||||
_ = require 'lodash'
|
||||
$w = (s)->s.split(' ')
|
||||
|
||||
id = shared.uuid()
|
||||
user =
|
||||
stats:
|
||||
class: 'warrior'
|
||||
lvl:1, hp:50, gp:0, exp:10
|
||||
per:0, int:0, con:0, str:0
|
||||
buffs: {per:0, int:0, con:0, str:0}
|
||||
training: {int:0,con:0,per:0,str:0}
|
||||
preferences: automaticAllocation: false
|
||||
party: quest: key:'evilsanta', progress: {up:0,down:0}
|
||||
achievements: {}
|
||||
items:
|
||||
eggs: {}
|
||||
hatchingPotions: {}
|
||||
food: {}
|
||||
gear:
|
||||
equipped:
|
||||
weapon: 'weapon_warrior_4'
|
||||
armor: 'armor_warrior_4'
|
||||
shield: 'shield_warrior_4'
|
||||
head: 'head_warrior_4'
|
||||
habits: [
|
||||
# we're gonna change this habit's attribute to mess with taskbased allo. Add the others to make sure our _.reduce is legit
|
||||
{id:'a',value:1,type:'habit',attribute:'str'}
|
||||
]
|
||||
dailys: [
|
||||
{id:'b',value:1,type:'daily',attribute:'str'}
|
||||
]
|
||||
todos: [
|
||||
{id:'c',value:1,type:'todo',attribute:'con'}
|
||||
{id:'d',value:1,type:'todo',attribute:'per'}
|
||||
{id:'e',value:1,type:'todo',attribute:'int'}
|
||||
]
|
||||
rewards: []
|
||||
|
||||
modes =
|
||||
flat: _.cloneDeep user
|
||||
classbased_warrior: _.cloneDeep user
|
||||
classbased_rogue: _.cloneDeep user
|
||||
classbased_wizard: _.cloneDeep user
|
||||
classbased_healer: _.cloneDeep user
|
||||
taskbased: _.cloneDeep user
|
||||
|
||||
modes.classbased_warrior.stats.class = 'warrior'
|
||||
modes.classbased_rogue.stats.class = 'rogue'
|
||||
modes.classbased_wizard.stats.class = 'wizard'
|
||||
modes.classbased_healer.stats.class = 'healer'
|
||||
|
||||
_.each $w('flat classbased_warrior classbased_rogue classbased_wizard classbased_healer taskbased'), (mode) ->
|
||||
_.merge modes[mode].preferences,
|
||||
automaticAllocation: true
|
||||
allocationMode: if mode.indexOf('classbased') is 0 then 'classbased' else mode
|
||||
shared.wrap(modes[mode])
|
||||
|
||||
console.log "\n\n================================================"
|
||||
console.log "New Simulation"
|
||||
console.log "================================================\n\n"
|
||||
|
||||
|
||||
_.times [20], (lvl) ->
|
||||
console.log ("[lvl #{lvl}]\n--------------\n")
|
||||
_.each $w('flat classbased_warrior classbased_rogue classbased_wizard classbased_healer taskbased'), (mode) ->
|
||||
u = modes[mode] #local var
|
||||
u.stats.exp = shared.tnl(lvl)+1 # level up
|
||||
_.merge u.stats, {per:0,con:0,int:0,str:0} if mode is 'taskbased' # if task-based, clear stat so we can see clearly which stat got +1
|
||||
u.habits[0].attribute = u.fns.randomVal({str:'str',int:'int',per:'per',con:'con'})
|
||||
u.ops.score {params:{id:u.habits[0].id},direction:'up'}
|
||||
u.fns.updateStats(u.stats) # trigger stats update
|
||||
str = mode + (if mode is 'taskbased' then " (#{u.habits[0].attribute})" else "")
|
||||
console.log str, _.pick(u.stats, $w 'per int con str')
|
||||
161
test/common/simulations/autoAllocate.js
Normal file
161
test/common/simulations/autoAllocate.js
Normal file
@@ -0,0 +1,161 @@
|
||||
var $w, _, id, modes, shared, user;
|
||||
|
||||
shared = require('../../../common/script/index.js');
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
$w = function(s) {
|
||||
return s.split(' ');
|
||||
};
|
||||
|
||||
id = shared.uuid();
|
||||
|
||||
user = {
|
||||
stats: {
|
||||
"class": 'warrior',
|
||||
lvl: 1,
|
||||
hp: 50,
|
||||
gp: 0,
|
||||
exp: 10,
|
||||
per: 0,
|
||||
int: 0,
|
||||
con: 0,
|
||||
str: 0,
|
||||
buffs: {
|
||||
per: 0,
|
||||
int: 0,
|
||||
con: 0,
|
||||
str: 0
|
||||
},
|
||||
training: {
|
||||
int: 0,
|
||||
con: 0,
|
||||
per: 0,
|
||||
str: 0
|
||||
}
|
||||
},
|
||||
preferences: {
|
||||
automaticAllocation: false
|
||||
},
|
||||
party: {
|
||||
quest: {
|
||||
key: 'evilsanta',
|
||||
progress: {
|
||||
up: 0,
|
||||
down: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
achievements: {},
|
||||
items: {
|
||||
eggs: {},
|
||||
hatchingPotions: {},
|
||||
food: {},
|
||||
gear: {
|
||||
equipped: {
|
||||
weapon: 'weapon_warrior_4',
|
||||
armor: 'armor_warrior_4',
|
||||
shield: 'shield_warrior_4',
|
||||
head: 'head_warrior_4'
|
||||
}
|
||||
}
|
||||
},
|
||||
habits: [
|
||||
{
|
||||
id: 'a',
|
||||
value: 1,
|
||||
type: 'habit',
|
||||
attribute: 'str'
|
||||
}
|
||||
],
|
||||
dailys: [
|
||||
{
|
||||
id: 'b',
|
||||
value: 1,
|
||||
type: 'daily',
|
||||
attribute: 'str'
|
||||
}
|
||||
],
|
||||
todos: [
|
||||
{
|
||||
id: 'c',
|
||||
value: 1,
|
||||
type: 'todo',
|
||||
attribute: 'con'
|
||||
}, {
|
||||
id: 'd',
|
||||
value: 1,
|
||||
type: 'todo',
|
||||
attribute: 'per'
|
||||
}, {
|
||||
id: 'e',
|
||||
value: 1,
|
||||
type: 'todo',
|
||||
attribute: 'int'
|
||||
}
|
||||
],
|
||||
rewards: []
|
||||
};
|
||||
|
||||
modes = {
|
||||
flat: _.cloneDeep(user),
|
||||
classbased_warrior: _.cloneDeep(user),
|
||||
classbased_rogue: _.cloneDeep(user),
|
||||
classbased_wizard: _.cloneDeep(user),
|
||||
classbased_healer: _.cloneDeep(user),
|
||||
taskbased: _.cloneDeep(user)
|
||||
};
|
||||
|
||||
modes.classbased_warrior.stats["class"] = 'warrior';
|
||||
|
||||
modes.classbased_rogue.stats["class"] = 'rogue';
|
||||
|
||||
modes.classbased_wizard.stats["class"] = 'wizard';
|
||||
|
||||
modes.classbased_healer.stats["class"] = 'healer';
|
||||
|
||||
_.each($w('flat classbased_warrior classbased_rogue classbased_wizard classbased_healer taskbased'), function(mode) {
|
||||
_.merge(modes[mode].preferences, {
|
||||
automaticAllocation: true,
|
||||
allocationMode: mode.indexOf('classbased') === 0 ? 'classbased' : mode
|
||||
});
|
||||
return shared.wrap(modes[mode]);
|
||||
});
|
||||
|
||||
console.log("\n\n================================================");
|
||||
|
||||
console.log("New Simulation");
|
||||
|
||||
console.log("================================================\n\n");
|
||||
|
||||
_.times([20], function(lvl) {
|
||||
console.log("[lvl " + lvl + "]\n--------------\n");
|
||||
return _.each($w('flat classbased_warrior classbased_rogue classbased_wizard classbased_healer taskbased'), function(mode) {
|
||||
var str, u;
|
||||
u = modes[mode];
|
||||
u.stats.exp = shared.tnl(lvl) + 1;
|
||||
if (mode === 'taskbased') {
|
||||
_.merge(u.stats, {
|
||||
per: 0,
|
||||
con: 0,
|
||||
int: 0,
|
||||
str: 0
|
||||
});
|
||||
}
|
||||
u.habits[0].attribute = u.fns.randomVal({
|
||||
str: 'str',
|
||||
int: 'int',
|
||||
per: 'per',
|
||||
con: 'con'
|
||||
});
|
||||
u.ops.score({
|
||||
params: {
|
||||
id: u.habits[0].id
|
||||
},
|
||||
direction: 'up'
|
||||
});
|
||||
u.fns.updateStats(u.stats);
|
||||
str = mode + (mode === 'taskbased' ? " (" + u.habits[0].attribute + ")" : "");
|
||||
return console.log(str, _.pick(u.stats, $w('per int con str')));
|
||||
});
|
||||
});
|
||||
@@ -1,180 +0,0 @@
|
||||
###
|
||||
1) clone the repo
|
||||
2) npm install
|
||||
3) coffee ./tests/math_samples.coffee
|
||||
|
||||
Current results at https://gist.github.com/lefnire/8049676
|
||||
###
|
||||
|
||||
shared = require '../../../common/script/index.js'
|
||||
_ = require 'lodash'
|
||||
|
||||
id = shared.uuid()
|
||||
user =
|
||||
stats: {class: 'warrior', buffs: {per:0,int:0,con:0,str:0}}
|
||||
party: quest: key:'evilsanta', progress: {up:0,down:0}
|
||||
preferences: automaticAllocation:false
|
||||
achievements:{}
|
||||
flags: levelDrops: {}
|
||||
items:
|
||||
eggs: {}
|
||||
hatchingPotions: {}
|
||||
food: {}
|
||||
quests:{}
|
||||
gear:
|
||||
equipped:
|
||||
weapon: 'weapon_warrior_4'
|
||||
armor: 'armor_warrior_4'
|
||||
shield: 'shield_warrior_4'
|
||||
head: 'head_warrior_4'
|
||||
habits: [
|
||||
shared.taskDefaults({id, value: 0})
|
||||
]
|
||||
dailys: [{"text" : "1",},{"text" : "1",},{"text" : "1",},{"text" : "1",},{"text" : "1",},{"text" : "1",},{"text" : "1",},{"text" : "1",},{"text" : "1",},{"text" : "1",},{"text" : "1",},{"text" : "1",},{"text" : "1",},{"text" : "1",},{"text" : "1",}],
|
||||
todos: []
|
||||
rewards: []
|
||||
|
||||
shared.wrap(user)
|
||||
s = user.stats
|
||||
task = user.tasks[id]
|
||||
party = [user]
|
||||
|
||||
console.log "\n\n================================================"
|
||||
console.log "New Simulation"
|
||||
console.log "================================================\n\n"
|
||||
|
||||
clearUser = (lvl=1) ->
|
||||
_.merge user.stats, {exp:0, gp:0, hp:50, lvl:lvl, str:lvl*1.5, con:lvl*1.5, per:lvl*1.5, int:lvl*1.5, mp: 100}
|
||||
_.merge s.buffs, {str:0,con:0,int:0,per:0}
|
||||
_.merge user.party.quest.progress, {up:0,down:0}
|
||||
user.items.lastDrop = {count:0}
|
||||
|
||||
_.each [1,25,50,75,100], (lvl) ->
|
||||
console.log "[LEVEL #{lvl}] (#{lvl*2} points total in every attr)\n\n"
|
||||
_.each {red:-25,yellow:0,green:35}, (taskVal, color) ->
|
||||
console.log "[task.value = #{taskVal} (#{color})]"
|
||||
console.log "direction\texpΔ\t\thpΔ\tgpΔ\ttask.valΔ\ttask.valΔ bonus\t\tboss-hit"
|
||||
_.each ['up','down'], (direction) ->
|
||||
clearUser(lvl)
|
||||
b4 = {hp:s.hp, taskVal}
|
||||
task.value = taskVal
|
||||
task.type = 'daily' if direction is 'up'
|
||||
delta = user.ops.score params:{id, direction}
|
||||
console.log "#{if direction is 'up' then '↑' else '↓'}\t\t#{s.exp}/#{shared.tnl(s.lvl)}\t\t#{(b4.hp-s.hp).toFixed(1)}\t#{s.gp.toFixed(1)}\t#{delta.toFixed(1)}\t\t#{(task.value-b4.taskVal-delta).toFixed(1)}\t\t\t#{user.party.quest.progress.up.toFixed(1)}"
|
||||
|
||||
str = '- [Wizard]'
|
||||
|
||||
task.value = taskVal;clearUser(lvl)
|
||||
b4 = {taskVal}
|
||||
shared.content.spells.wizard.fireball.cast(user,task)
|
||||
str += "\tfireball(task.valΔ:#{(task.value-taskVal).toFixed(1)} exp:#{s.exp.toFixed(1)} bossHit:#{user.party.quest.progress.up.toFixed(2)})"
|
||||
|
||||
task.value = taskVal;clearUser(lvl)
|
||||
_party = [user, {stats:{mp:0}}]
|
||||
shared.content.spells.wizard.mpheal.cast(user,_party)
|
||||
str += "\t| mpheal(mp:#{_party[1].stats.mp})"
|
||||
|
||||
task.value = taskVal;clearUser(lvl)
|
||||
shared.content.spells.wizard.earth.cast(user,party)
|
||||
str += "\t\t\t\t| earth(buffs.int:#{s.buffs.int})"
|
||||
s.buffs.int = 0
|
||||
|
||||
task.value = taskVal;clearUser(lvl)
|
||||
shared.content.spells.wizard.frost.cast(user,{})
|
||||
str += "\t\t\t| frost(N/A)"
|
||||
|
||||
console.log str
|
||||
str = '- [Warrior]'
|
||||
|
||||
task.value = taskVal;clearUser(lvl)
|
||||
shared.content.spells.warrior.smash.cast(user,task)
|
||||
b4 = {taskVal}
|
||||
str += "\tsmash(task.valΔ:#{(task.value-taskVal).toFixed(1)})"
|
||||
|
||||
task.value = taskVal;clearUser(lvl)
|
||||
shared.content.spells.warrior.defensiveStance.cast(user,{})
|
||||
str += "\t\t| defensiveStance(buffs.con:#{s.buffs.con})"
|
||||
s.buffs.con = 0
|
||||
|
||||
task.value = taskVal;clearUser(lvl)
|
||||
shared.content.spells.warrior.valorousPresence.cast(user,party)
|
||||
str += "\t\t\t| valorousPresence(buffs.str:#{s.buffs.str})"
|
||||
s.buffs.str = 0
|
||||
|
||||
task.value = taskVal;clearUser(lvl)
|
||||
shared.content.spells.warrior.intimidate.cast(user,party)
|
||||
str += "\t\t| intimidate(buffs.con:#{s.buffs.con})"
|
||||
s.buffs.con = 0
|
||||
|
||||
console.log str
|
||||
str = '- [Rogue]'
|
||||
|
||||
task.value = taskVal;clearUser(lvl)
|
||||
shared.content.spells.rogue.pickPocket.cast(user,task)
|
||||
str += "\tpickPocket(gp:#{s.gp.toFixed(1)})"
|
||||
|
||||
task.value = taskVal;clearUser(lvl)
|
||||
shared.content.spells.rogue.backStab.cast(user,task)
|
||||
b4 = {taskVal}
|
||||
str += "\t\t| backStab(task.valΔ:#{(task.value-b4.taskVal).toFixed(1)} exp:#{s.exp.toFixed(1)} gp:#{s.gp.toFixed(1)})"
|
||||
|
||||
task.value = taskVal;clearUser(lvl)
|
||||
shared.content.spells.rogue.toolsOfTrade.cast(user,party)
|
||||
str += "\t| toolsOfTrade(buffs.per:#{s.buffs.per})"
|
||||
s.buffs.per = 0
|
||||
|
||||
task.value = taskVal;clearUser(lvl)
|
||||
shared.content.spells.rogue.stealth.cast(user,{})
|
||||
str += "\t\t| stealth(avoiding #{user.stats.buffs.stealth} tasks)"
|
||||
user.stats.buffs.stealth = 0
|
||||
|
||||
console.log str
|
||||
str = '- [Healer]'
|
||||
|
||||
task.value = taskVal;clearUser(lvl)
|
||||
s.hp=0
|
||||
shared.content.spells.healer.heal.cast(user,{})
|
||||
str += "\theal(hp:#{s.hp.toFixed(1)})"
|
||||
|
||||
task.value = taskVal;clearUser(lvl)
|
||||
shared.content.spells.healer.brightness.cast(user,{})
|
||||
b4 = {taskVal}
|
||||
str += "\t\t\t| brightness(task.valΔ:#{(task.value-b4.taskVal).toFixed(1)})"
|
||||
|
||||
task.value = taskVal;clearUser(lvl)
|
||||
shared.content.spells.healer.protectAura.cast(user,party)
|
||||
str += "\t\t\t| protectAura(buffs.con:#{s.buffs.con})"
|
||||
s.buffs.con = 0
|
||||
|
||||
task.value = taskVal;clearUser(lvl)
|
||||
s.hp=0
|
||||
shared.content.spells.healer.heallAll.cast(user,party)
|
||||
str += "\t\t| heallAll(hp:#{s.hp.toFixed(1)})"
|
||||
|
||||
console.log str
|
||||
console.log '\n'
|
||||
|
||||
|
||||
console.log '------------------------------------------------------------'
|
||||
|
||||
###
|
||||
_.each [1,25,50,75,100,125], (lvl) ->
|
||||
console.log "[LEVEL #{lvl}] (#{lvl*2} points in every attr)\n\n"
|
||||
_.each {red:-25,yellow:0,green:35}, (taskVal, color) ->
|
||||
console.log "[task.value = #{taskVal} (#{color})]"
|
||||
console.log "direction\texpΔ\t\thpΔ\tgpΔ\ttask.valΔ\ttask.valΔ bonus\t\tboss-hit"
|
||||
_.each ['up','down'], (direction) ->
|
||||
clearUser(lvl)
|
||||
b4 = {hp:s.hp, taskVal}
|
||||
task.value = taskVal
|
||||
task.type = 'daily' if direction is 'up'
|
||||
delta = user.ops.score params:{id, direction}
|
||||
console.log "#{if direction is 'up' then '↑' else '↓'}\t\t#{s.exp}/#{shared.tnl(s.lvl)}\t\t#{(b4.hp-s.hp).toFixed(1)}\t#{s.gp.toFixed(1)}\t#{delta.toFixed(1)}\t\t#{(task.value-b4.taskVal-delta).toFixed(1)}\t\t\t#{user.party.quest.progress.up.toFixed(1)}"
|
||||
|
||||
task.value = taskVal;clearUser(lvl)
|
||||
shared.content.spells.rogue.stealth.cast(user,{})
|
||||
console.log "\t\t| stealth(avoiding #{user.stats.buffs.stealth} tasks)"
|
||||
user.stats.buffs.stealth = 0
|
||||
|
||||
console.log user.dailys.length
|
||||
###
|
||||
291
test/common/simulations/passive_active_attrs.js
Normal file
291
test/common/simulations/passive_active_attrs.js
Normal file
@@ -0,0 +1,291 @@
|
||||
var _, clearUser, id, party, s, shared, task, user;
|
||||
|
||||
shared = require('../../../common/script/index.js');
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
id = shared.uuid();
|
||||
|
||||
user = {
|
||||
stats: {
|
||||
"class": 'warrior',
|
||||
buffs: {
|
||||
per: 0,
|
||||
int: 0,
|
||||
con: 0,
|
||||
str: 0
|
||||
}
|
||||
},
|
||||
party: {
|
||||
quest: {
|
||||
key: 'evilsanta',
|
||||
progress: {
|
||||
up: 0,
|
||||
down: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
preferences: {
|
||||
automaticAllocation: false
|
||||
},
|
||||
achievements: {},
|
||||
flags: {
|
||||
levelDrops: {}
|
||||
},
|
||||
items: {
|
||||
eggs: {},
|
||||
hatchingPotions: {},
|
||||
food: {},
|
||||
quests: {},
|
||||
gear: {
|
||||
equipped: {
|
||||
weapon: 'weapon_warrior_4',
|
||||
armor: 'armor_warrior_4',
|
||||
shield: 'shield_warrior_4',
|
||||
head: 'head_warrior_4'
|
||||
}
|
||||
}
|
||||
},
|
||||
habits: [
|
||||
shared.taskDefaults({
|
||||
id: id,
|
||||
value: 0
|
||||
})
|
||||
],
|
||||
dailys: [
|
||||
{
|
||||
"text": "1"
|
||||
}, {
|
||||
"text": "1"
|
||||
}, {
|
||||
"text": "1"
|
||||
}, {
|
||||
"text": "1"
|
||||
}, {
|
||||
"text": "1"
|
||||
}, {
|
||||
"text": "1"
|
||||
}, {
|
||||
"text": "1"
|
||||
}, {
|
||||
"text": "1"
|
||||
}, {
|
||||
"text": "1"
|
||||
}, {
|
||||
"text": "1"
|
||||
}, {
|
||||
"text": "1"
|
||||
}, {
|
||||
"text": "1"
|
||||
}, {
|
||||
"text": "1"
|
||||
}, {
|
||||
"text": "1"
|
||||
}, {
|
||||
"text": "1"
|
||||
}
|
||||
],
|
||||
todos: [],
|
||||
rewards: []
|
||||
};
|
||||
|
||||
shared.wrap(user);
|
||||
|
||||
s = user.stats;
|
||||
|
||||
task = user.tasks[id];
|
||||
|
||||
party = [user];
|
||||
|
||||
console.log("\n\n================================================");
|
||||
|
||||
console.log("New Simulation");
|
||||
|
||||
console.log("================================================\n\n");
|
||||
|
||||
clearUser = function(lvl) {
|
||||
if (lvl == null) {
|
||||
lvl = 1;
|
||||
}
|
||||
_.merge(user.stats, {
|
||||
exp: 0,
|
||||
gp: 0,
|
||||
hp: 50,
|
||||
lvl: lvl,
|
||||
str: lvl * 1.5,
|
||||
con: lvl * 1.5,
|
||||
per: lvl * 1.5,
|
||||
int: lvl * 1.5,
|
||||
mp: 100
|
||||
});
|
||||
_.merge(s.buffs, {
|
||||
str: 0,
|
||||
con: 0,
|
||||
int: 0,
|
||||
per: 0
|
||||
});
|
||||
_.merge(user.party.quest.progress, {
|
||||
up: 0,
|
||||
down: 0
|
||||
});
|
||||
return user.items.lastDrop = {
|
||||
count: 0
|
||||
};
|
||||
};
|
||||
|
||||
_.each([1, 25, 50, 75, 100], function(lvl) {
|
||||
console.log("[LEVEL " + lvl + "] (" + (lvl * 2) + " points total in every attr)\n\n");
|
||||
_.each({
|
||||
red: -25,
|
||||
yellow: 0,
|
||||
green: 35
|
||||
}, function(taskVal, color) {
|
||||
var _party, b4, str;
|
||||
console.log("[task.value = " + taskVal + " (" + color + ")]");
|
||||
console.log("direction\texpΔ\t\thpΔ\tgpΔ\ttask.valΔ\ttask.valΔ bonus\t\tboss-hit");
|
||||
_.each(['up', 'down'], function(direction) {
|
||||
var b4, delta;
|
||||
clearUser(lvl);
|
||||
b4 = {
|
||||
hp: s.hp,
|
||||
taskVal: taskVal
|
||||
};
|
||||
task.value = taskVal;
|
||||
if (direction === 'up') {
|
||||
task.type = 'daily';
|
||||
}
|
||||
delta = user.ops.score({
|
||||
params: {
|
||||
id: id,
|
||||
direction: direction
|
||||
}
|
||||
});
|
||||
return console.log((direction === 'up' ? '↑' : '↓') + "\t\t" + s.exp + "/" + (shared.tnl(s.lvl)) + "\t\t" + ((b4.hp - s.hp).toFixed(1)) + "\t" + (s.gp.toFixed(1)) + "\t" + (delta.toFixed(1)) + "\t\t" + ((task.value - b4.taskVal - delta).toFixed(1)) + "\t\t\t" + (user.party.quest.progress.up.toFixed(1)));
|
||||
});
|
||||
str = '- [Wizard]';
|
||||
task.value = taskVal;
|
||||
clearUser(lvl);
|
||||
b4 = {
|
||||
taskVal: taskVal
|
||||
};
|
||||
shared.content.spells.wizard.fireball.cast(user, task);
|
||||
str += "\tfireball(task.valΔ:" + ((task.value - taskVal).toFixed(1)) + " exp:" + (s.exp.toFixed(1)) + " bossHit:" + (user.party.quest.progress.up.toFixed(2)) + ")";
|
||||
task.value = taskVal;
|
||||
clearUser(lvl);
|
||||
_party = [
|
||||
user, {
|
||||
stats: {
|
||||
mp: 0
|
||||
}
|
||||
}
|
||||
];
|
||||
shared.content.spells.wizard.mpheal.cast(user, _party);
|
||||
str += "\t| mpheal(mp:" + _party[1].stats.mp + ")";
|
||||
task.value = taskVal;
|
||||
clearUser(lvl);
|
||||
shared.content.spells.wizard.earth.cast(user, party);
|
||||
str += "\t\t\t\t| earth(buffs.int:" + s.buffs.int + ")";
|
||||
s.buffs.int = 0;
|
||||
task.value = taskVal;
|
||||
clearUser(lvl);
|
||||
shared.content.spells.wizard.frost.cast(user, {});
|
||||
str += "\t\t\t| frost(N/A)";
|
||||
console.log(str);
|
||||
str = '- [Warrior]';
|
||||
task.value = taskVal;
|
||||
clearUser(lvl);
|
||||
shared.content.spells.warrior.smash.cast(user, task);
|
||||
b4 = {
|
||||
taskVal: taskVal
|
||||
};
|
||||
str += "\tsmash(task.valΔ:" + ((task.value - taskVal).toFixed(1)) + ")";
|
||||
task.value = taskVal;
|
||||
clearUser(lvl);
|
||||
shared.content.spells.warrior.defensiveStance.cast(user, {});
|
||||
str += "\t\t| defensiveStance(buffs.con:" + s.buffs.con + ")";
|
||||
s.buffs.con = 0;
|
||||
task.value = taskVal;
|
||||
clearUser(lvl);
|
||||
shared.content.spells.warrior.valorousPresence.cast(user, party);
|
||||
str += "\t\t\t| valorousPresence(buffs.str:" + s.buffs.str + ")";
|
||||
s.buffs.str = 0;
|
||||
task.value = taskVal;
|
||||
clearUser(lvl);
|
||||
shared.content.spells.warrior.intimidate.cast(user, party);
|
||||
str += "\t\t| intimidate(buffs.con:" + s.buffs.con + ")";
|
||||
s.buffs.con = 0;
|
||||
console.log(str);
|
||||
str = '- [Rogue]';
|
||||
task.value = taskVal;
|
||||
clearUser(lvl);
|
||||
shared.content.spells.rogue.pickPocket.cast(user, task);
|
||||
str += "\tpickPocket(gp:" + (s.gp.toFixed(1)) + ")";
|
||||
task.value = taskVal;
|
||||
clearUser(lvl);
|
||||
shared.content.spells.rogue.backStab.cast(user, task);
|
||||
b4 = {
|
||||
taskVal: taskVal
|
||||
};
|
||||
str += "\t\t| backStab(task.valΔ:" + ((task.value - b4.taskVal).toFixed(1)) + " exp:" + (s.exp.toFixed(1)) + " gp:" + (s.gp.toFixed(1)) + ")";
|
||||
task.value = taskVal;
|
||||
clearUser(lvl);
|
||||
shared.content.spells.rogue.toolsOfTrade.cast(user, party);
|
||||
str += "\t| toolsOfTrade(buffs.per:" + s.buffs.per + ")";
|
||||
s.buffs.per = 0;
|
||||
task.value = taskVal;
|
||||
clearUser(lvl);
|
||||
shared.content.spells.rogue.stealth.cast(user, {});
|
||||
str += "\t\t| stealth(avoiding " + user.stats.buffs.stealth + " tasks)";
|
||||
user.stats.buffs.stealth = 0;
|
||||
console.log(str);
|
||||
str = '- [Healer]';
|
||||
task.value = taskVal;
|
||||
clearUser(lvl);
|
||||
s.hp = 0;
|
||||
shared.content.spells.healer.heal.cast(user, {});
|
||||
str += "\theal(hp:" + (s.hp.toFixed(1)) + ")";
|
||||
task.value = taskVal;
|
||||
clearUser(lvl);
|
||||
shared.content.spells.healer.brightness.cast(user, {});
|
||||
b4 = {
|
||||
taskVal: taskVal
|
||||
};
|
||||
str += "\t\t\t| brightness(task.valΔ:" + ((task.value - b4.taskVal).toFixed(1)) + ")";
|
||||
task.value = taskVal;
|
||||
clearUser(lvl);
|
||||
shared.content.spells.healer.protectAura.cast(user, party);
|
||||
str += "\t\t\t| protectAura(buffs.con:" + s.buffs.con + ")";
|
||||
s.buffs.con = 0;
|
||||
task.value = taskVal;
|
||||
clearUser(lvl);
|
||||
s.hp = 0;
|
||||
shared.content.spells.healer.heallAll.cast(user, party);
|
||||
str += "\t\t| heallAll(hp:" + (s.hp.toFixed(1)) + ")";
|
||||
console.log(str);
|
||||
return console.log('\n');
|
||||
});
|
||||
return console.log('------------------------------------------------------------');
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
_.each [1,25,50,75,100,125], (lvl) ->
|
||||
console.log "[LEVEL #{lvl}] (#{lvl*2} points in every attr)\n\n"
|
||||
_.each {red:-25,yellow:0,green:35}, (taskVal, color) ->
|
||||
console.log "[task.value = #{taskVal} (#{color})]"
|
||||
console.log "direction\texpΔ\t\thpΔ\tgpΔ\ttask.valΔ\ttask.valΔ bonus\t\tboss-hit"
|
||||
_.each ['up','down'], (direction) ->
|
||||
clearUser(lvl)
|
||||
b4 = {hp:s.hp, taskVal}
|
||||
task.value = taskVal
|
||||
task.type = 'daily' if direction is 'up'
|
||||
delta = user.ops.score params:{id, direction}
|
||||
console.log "#{if direction is 'up' then '↑' else '↓'}\t\t#{s.exp}/#{shared.tnl(s.lvl)}\t\t#{(b4.hp-s.hp).toFixed(1)}\t#{s.gp.toFixed(1)}\t#{delta.toFixed(1)}\t\t#{(task.value-b4.taskVal-delta).toFixed(1)}\t\t\t#{user.party.quest.progress.up.toFixed(1)}"
|
||||
|
||||
task.value = taskVal;clearUser(lvl)
|
||||
shared.content.spells.rogue.stealth.cast(user,{})
|
||||
console.log "\t\t| stealth(avoiding #{user.stats.buffs.stealth} tasks)"
|
||||
user.stats.buffs.stealth = 0
|
||||
|
||||
console.log user.dailys.length
|
||||
*/
|
||||
@@ -1,44 +0,0 @@
|
||||
expect = require 'expect.js'
|
||||
|
||||
module.exports.addCustomMatchers = ->
|
||||
Assertion = expect.Assertion
|
||||
|
||||
Assertion.prototype.toHaveGP = (gp)->
|
||||
actual = @obj.stats.gp
|
||||
@assert(
|
||||
actual == gp,
|
||||
-> "expected user to have #{gp} gp, but got #{actual}",
|
||||
-> "expected user to not have #{gp} gp"
|
||||
)
|
||||
|
||||
Assertion.prototype.toHaveHP = (hp)->
|
||||
actual = @obj.stats.hp
|
||||
@assert(
|
||||
actual == hp,
|
||||
-> "expected user to have #{hp} hp, but got #{actual}",
|
||||
-> "expected user to not have #{hp} hp"
|
||||
)
|
||||
|
||||
Assertion.prototype.toHaveExp = (exp)->
|
||||
actual = @obj.stats.exp
|
||||
@assert(
|
||||
actual == exp,
|
||||
-> "expected user to have #{exp} experience points, but got #{actual}",
|
||||
-> "expected user to not have #{exp} experience points"
|
||||
)
|
||||
|
||||
Assertion.prototype.toHaveLevel = (lvl)->
|
||||
actual = @obj.stats.lvl
|
||||
@assert(
|
||||
actual == lvl,
|
||||
-> "expected user to be level #{lvl}, but got #{actual}",
|
||||
-> "expected user to not be level #{lvl}"
|
||||
)
|
||||
|
||||
Assertion.prototype.toHaveMaxMP = (mp)->
|
||||
actual = @obj._statsComputed.maxMP
|
||||
@assert(
|
||||
actual == mp,
|
||||
-> "expected user to have #{mp} max mp, but got #{actual}",
|
||||
-> "expected user to not have #{mp} max mp"
|
||||
)
|
||||
53
test/common/test_helper.js
Normal file
53
test/common/test_helper.js
Normal file
@@ -0,0 +1,53 @@
|
||||
var expect;
|
||||
|
||||
expect = require('expect.js');
|
||||
|
||||
module.exports.addCustomMatchers = function() {
|
||||
var Assertion;
|
||||
Assertion = expect.Assertion;
|
||||
Assertion.prototype.toHaveGP = function(gp) {
|
||||
var actual;
|
||||
actual = this.obj.stats.gp;
|
||||
return this.assert(actual === gp, function() {
|
||||
return "expected user to have " + gp + " gp, but got " + actual;
|
||||
}, function() {
|
||||
return "expected user to not have " + gp + " gp";
|
||||
});
|
||||
};
|
||||
Assertion.prototype.toHaveHP = function(hp) {
|
||||
var actual;
|
||||
actual = this.obj.stats.hp;
|
||||
return this.assert(actual === hp, function() {
|
||||
return "expected user to have " + hp + " hp, but got " + actual;
|
||||
}, function() {
|
||||
return "expected user to not have " + hp + " hp";
|
||||
});
|
||||
};
|
||||
Assertion.prototype.toHaveExp = function(exp) {
|
||||
var actual;
|
||||
actual = this.obj.stats.exp;
|
||||
return this.assert(actual === exp, function() {
|
||||
return "expected user to have " + exp + " experience points, but got " + actual;
|
||||
}, function() {
|
||||
return "expected user to not have " + exp + " experience points";
|
||||
});
|
||||
};
|
||||
Assertion.prototype.toHaveLevel = function(lvl) {
|
||||
var actual;
|
||||
actual = this.obj.stats.lvl;
|
||||
return this.assert(actual === lvl, function() {
|
||||
return "expected user to be level " + lvl + ", but got " + actual;
|
||||
}, function() {
|
||||
return "expected user to not be level " + lvl;
|
||||
});
|
||||
};
|
||||
return Assertion.prototype.toHaveMaxMP = function(mp) {
|
||||
var actual;
|
||||
actual = this.obj._statsComputed.maxMP;
|
||||
return this.assert(actual === mp, function() {
|
||||
return "expected user to have " + mp + " max mp, but got " + actual;
|
||||
}, function() {
|
||||
return "expected user to not have " + mp + " max mp";
|
||||
});
|
||||
};
|
||||
};
|
||||
@@ -131,7 +131,7 @@ describe('user.fns.buy', function() {
|
||||
|
||||
_(shared.content.gearTypes).each(function(type) {
|
||||
_(shared.content.gear.tree[type].armoire).each(function(gearObject, gearName) {
|
||||
var armoireKey = gearObject.key;
|
||||
let armoireKey = gearObject.key;
|
||||
fullArmoire[armoireKey] = true;
|
||||
}).value();
|
||||
}).value();
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
'use strict';
|
||||
|
||||
var shared = require('../../common/script/index.js');
|
||||
shared.i18n.translations = require('../../website/src/libs/i18n.js').translations
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
--timeout 8000
|
||||
--check-leaks
|
||||
--growl
|
||||
--compilers coffee:coffee-script
|
||||
--compilers js:babel/register
|
||||
--globals io
|
||||
--compilers js:babel-core/register
|
||||
--require test/api-legacy/api-helper
|
||||
--require ./test/helpers/globals.helper
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Register babel hook so we can write the real entry file (server.js) in ES6
|
||||
require('babel/register');
|
||||
require('babel-core/register');
|
||||
|
||||
// Only do the minimal amount of work before forking just in case of a dyno restart
|
||||
var cluster = require('cluster');
|
||||
|
||||
@@ -60,18 +60,38 @@ _.each(langCodes, function(code){
|
||||
}catch (e){}
|
||||
});
|
||||
|
||||
// Remove en_GB from langCodes checked by browser to avaoi it being
|
||||
// Remove en_GB from langCodes checked by browser to avaoi it being
|
||||
// used in place of plain original 'en'
|
||||
var defaultLangCodes = _.without(langCodes, 'en_GB');
|
||||
|
||||
// A list of languages that have different versions
|
||||
var multipleVersionsLanguages = ['es', 'zh'];
|
||||
|
||||
var latinAmericanSpanishes = ['es-419', 'es-mx', 'es-gt', 'es-cr', 'es-pa', 'es-do', 'es-ve', 'es-co', 'es-pe',
|
||||
'es-ar', 'es-ec', 'es-cl', 'es-uy', 'es-py', 'es-bo', 'es-sv', 'es-hn',
|
||||
'es-ni', 'es-pr'];
|
||||
var latinAmericanSpanishes = {
|
||||
'es-419': 'es_419',
|
||||
'es-mx': 'es_419',
|
||||
'es-gt': 'es_419',
|
||||
'es-cr': 'es_419',
|
||||
'es-pa': 'es_419',
|
||||
'es-do': 'es_419',
|
||||
'es-ve': 'es_419',
|
||||
'es-co': 'es_419',
|
||||
'es-pe': 'es_419',
|
||||
'es-ar': 'es_419',
|
||||
'es-ec': 'es_419',
|
||||
'es-cl': 'es_419',
|
||||
'es-uy': 'es_419',
|
||||
'es-py': 'es_419',
|
||||
'es-bo': 'es_419',
|
||||
'es-sv': 'es_419',
|
||||
'es-hn': 'es_419',
|
||||
'es-ni': 'es_419',
|
||||
'es-pr': 'es_419',
|
||||
};
|
||||
|
||||
var chineseVersions = ['zh-tw'];
|
||||
var chineseVersions = {
|
||||
'zh-tw': 'zh_TW',
|
||||
};
|
||||
|
||||
var getUserLanguage = function(req, res, next){
|
||||
var getFromBrowser = function(){
|
||||
@@ -97,10 +117,9 @@ var getUserLanguage = function(req, res, next){
|
||||
}
|
||||
|
||||
if(matches[0] === 'es'){
|
||||
return (latinAmericanSpanishes.indexOf(acceptedCompleteLang) !== -1) ? 'es_419' : 'es';
|
||||
return latinAmericanSpanishes[acceptedCompleteLang] || 'es';
|
||||
}else if(matches[0] === 'zh'){
|
||||
var iChinese = chineseVersions.indexOf(acceptedCompleteLang.toLowerCase());
|
||||
return (iChinese !== -1) ? chineseVersions[iChinese] : 'zh';
|
||||
return chineseVersions[acceptedCompleteLang] || 'zh';
|
||||
}else{
|
||||
return en;
|
||||
}
|
||||
@@ -158,4 +177,4 @@ module.exports.enTranslations = function(){ // stringName and vars are the allow
|
||||
var args = Array.prototype.slice.call(arguments, 0);
|
||||
args.push(language.code);
|
||||
return shared.i18n.t.apply(null, args);
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user