Merge branch 'api-v3' into api-v3-unlock-fix

This commit is contained in:
Matteo Pagliazzi
2016-04-22 12:33:39 +02:00
141 changed files with 4016 additions and 3189 deletions

View File

@@ -12,13 +12,13 @@ website/public/
# Temporarilly disabled. These should be removed when the linting errors are fixed # Temporarilly disabled. These should be removed when the linting errors are fixed
common/script/content/index.js common/script/content/index.js
common/script/fns/randomDrop.js
common/script/public/**/*.js common/script/public/**/*.js
website/src/**/api-v2/**/*.js website/src/**/api-v2/**/*.js
website/src/routes/payments.js website/src/routes/payments.js
website/src/routes/pages.js website/src/routes/pages.js
website/src/middlewares/ website/src/middlewares/apiThrottle.js
website/src/middlewares/forceRefresh.js
website/src/controllers/payments/ website/src/controllers/payments/
debug-scripts/* debug-scripts/*

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

After

Width:  |  Height:  |  Size: 143 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

After

Width:  |  Height:  |  Size: 155 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 68 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 KiB

After

Width:  |  Height:  |  Size: 140 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

After

Width:  |  Height:  |  Size: 145 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -113,14 +113,13 @@
"missingKeyParam": "\"req.params.key\" is required.", "missingKeyParam": "\"req.params.key\" is required.",
"mysterySetNotFound": "Mystery set not found, or set already owned.", "mysterySetNotFound": "Mystery set not found, or set already owned.",
"itemNotFound": "Item \"<%= key %>\" not found.", "itemNotFound": "Item \"<%= key %>\" not found.",
"cannoyBuyItem": "You can't buy this item.", "cannotBuyItem": "You can't buy this item.",
"missingTypeKeyEquip": "\"key\" and \"type\" are required parameters.", "missingTypeKeyEquip": "\"key\" and \"type\" are required parameters.",
"missingPetFoodFeed": "\"pet\" and \"food\" are required parameters.", "missingPetFoodFeed": "\"pet\" and \"food\" are required parameters.",
"invalidPetName": "Invalid pet name supplied.", "invalidPetName": "Invalid pet name supplied.",
"missingEggHatchingPotionHatch": "\"egg\" and \"hatchingPotion\" are required parameters.", "missingEggHatchingPotionHatch": "\"egg\" and \"hatchingPotion\" are required parameters.",
"invalidTypeEquip": "\"type\" must be one of 'equipped', 'pet', 'mount', 'costume'.", "invalidTypeEquip": "\"type\" must be one of 'equipped', 'pet', 'mount', 'costume'.",
"cannotDeleteActiveAccount": "You have an active subscription, cancel your plan before deleting your account.", "cannotDeleteActiveAccount": "You have an active subscription, cancel your plan before deleting your account.",
"cannoyBuyItem": "You can't buy this item",
"messageRequired": "A message is required.", "messageRequired": "A message is required.",
"toUserIDRequired": "A toUserId is required", "toUserIDRequired": "A toUserId is required",
"notAuthorizedToSendMessageToThisUser": "Can't send message to this user.", "notAuthorizedToSendMessageToThisUser": "Can't send message to this user.",
@@ -171,5 +170,6 @@
"pushDeviceAdded": "Push device added successfully", "pushDeviceAdded": "Push device added successfully",
"pushDeviceAlreadyAdded": "The user already has the push device", "pushDeviceAlreadyAdded": "The user already has the push device",
"resetComplete": "Reset completed", "resetComplete": "Reset completed",
"lvl10ChangeClass": "To change class you must be at least level 10." "lvl10ChangeClass": "To change class you must be at least level 10.",
"equipmentAlreadyOwned": "You already own that piece of equipment"
} }

View File

@@ -1,4 +1,5 @@
{ {
"communityGuidelinesWarning": "Please keep in mind that your Display Name, profile photo, and blurb must comply with the <a href='https://habitica.com/static/community-guidelines' target='_blank'>Community Guidelines</a> (e.g. no profanity, no adult topics, no insults, etc). If you have any questions about whether or not something is appropriate, feel free to email <a href='mailto:leslie@habitica.com' target='blank'>leslie@habitica.com</a>!",
"statsAch": "Stats & Achievements", "statsAch": "Stats & Achievements",
"profile": "Profile", "profile": "Profile",
"avatar": "Customize Avatar", "avatar": "Customize Avatar",

View File

@@ -19,7 +19,7 @@
"orca": "Orca", "orca": "Orca",
"royalPurpleGryphon": "Royal Purple Gryphon", "royalPurpleGryphon": "Royal Purple Gryphon",
"phoenix": "Phoenix", "phoenix": "Phoenix",
"bumblebee": "Magical Bee", "magicalBee": "Magical Bee",
"rarePetPop1": "Click the gold paw to learn more about how you can obtain this rare pet through contributing to Habitica!", "rarePetPop1": "Click the gold paw to learn more about how you can obtain this rare pet through contributing to Habitica!",
"rarePetPop2": "How to Get this Pet!", "rarePetPop2": "How to Get this Pet!",
"potion": "<%= potionType %> Potion", "potion": "<%= potionType %> Potion",

View File

@@ -66,6 +66,14 @@
"API": "API", "API": "API",
"APIText": "Copy these for use in third party applications. However, think of your API Token like a password, and do not share it publicly. You may occasionally be asked for your User ID, but never post your API Token where others can see it, including on Github.", "APIText": "Copy these for use in third party applications. However, think of your API Token like a password, and do not share it publicly. You may occasionally be asked for your User ID, but never post your API Token where others can see it, including on Github.",
"APIToken": "API Token (this is a password - see warning above!)", "APIToken": "API Token (this is a password - see warning above!)",
"thirdPartyApps": "Third Party Apps",
"dataToolDesc": "A webpage that shows you certain information from your Habitica account, such as statistics about your tasks, equipment, and skills.",
"beeminder": "Beeminder",
"beeminderDesc": "Let Beeminder automatically monitor your Habitica To-Dos. You can commit to maintaining a target number of To-Dos completed per day or per week, or you can commit to gradually reducing your remaining number of uncompleted To-Dos. (By \"commit\" Beeminder means under threat of paying actual money! But you may also just like Beeminder's fancy graphs.)",
"chromeChatExtension": "Chrome Chat Extension",
"chromeChatExtensionDesc": "The Chrome Chat Extension for Habitica adds an intuitive chat box to all of habitica.com. It allows users to chat in the Tavern, their party, and any guilds they are in.",
"otherExtensions": "<a target='blank' href='http://habitica.wikia.com/wiki/App_and_Extension_Integrations'>Other Extensions</a>",
"otherDesc": "Find other apps, extensions, and tools on the Habitica wiki.",
"resetDo": "Do it, reset my account!", "resetDo": "Do it, reset my account!",
"fixValues": "Fix Values", "fixValues": "Fix Values",
"fixValuesText1": "If you've encountered a bug or made a mistake that unfairly changed your character (damage you shouldn't have taken, Gold you didn't really earn, etc.), you can manually correct your numbers here. Yes, this makes it possible to cheat: use this feature wisely, or you'll sabotage your own habit-building!", "fixValuesText1": "If you've encountered a bug or made a mistake that unfairly changed your character (damage you shouldn't have taken, Gold you didn't really earn, etc.), you can manually correct your numbers here. Yes, this makes it possible to cheat: use this feature wisely, or you'll sabotage your own habit-building!",

View File

@@ -418,7 +418,7 @@ api.specialPets = {
'Tiger-Veteran': 'veteranTiger', 'Tiger-Veteran': 'veteranTiger',
'Phoenix-Base': 'phoenix', 'Phoenix-Base': 'phoenix',
'Turkey-Gilded': 'gildedTurkey', 'Turkey-Gilded': 'gildedTurkey',
'Bumblebee-Base': 'bumblebee', 'MagicalBee-Base': 'magicalBee',
}; };
api.specialMounts = { api.specialMounts = {
@@ -431,7 +431,7 @@ api.specialMounts = {
'Gryphon-RoyalPurple': 'royalPurpleGryphon', 'Gryphon-RoyalPurple': 'royalPurpleGryphon',
'Phoenix-Base': 'phoenix', 'Phoenix-Base': 'phoenix',
'JackOLantern-Base': 'jackolantern', 'JackOLantern-Base': 'jackolantern',
'Bumblebee-Base': 'bumblebee', 'MagicalBee-Base': 'magicalBee',
}; };
api.timeTravelStable = { api.timeTravelStable = {

View File

@@ -1,7 +1,8 @@
import predictableRandom from './predictableRandom';
module.exports = function crit (user, stat = 'str', chance = 0.03) { module.exports = function crit (user, stat = 'str', chance = 0.03) {
let s = user._statsComputed[stat]; let s = user._statsComputed[stat];
if (user.fns.predictableRandom() <= chance * (1 + s / 100)) { if (predictableRandom(user) <= chance * (1 + s / 100)) {
return 1.5 + 4 * s / (s + 200); return 1.5 + 4 * s / (s + 200);
} else { } else {
return 1; return 1;

View File

@@ -3,80 +3,118 @@ import content from '../content/index';
import i18n from '../i18n'; import i18n from '../i18n';
import { daysSince } from '../cron'; import { daysSince } from '../cron';
import { diminishingReturns } from '../statHelpers'; import { diminishingReturns } from '../statHelpers';
import { predictableRandom } from './predictableRandom';
import randomVal from './randomVal';
// Clone a drop object maintaining its functions so that we can change it without affecting the original item // Clone a drop object maintaining its functions so that we can change it without affecting the original item
function cloneDropItem (drop) { function cloneDropItem (drop) {
return _.cloneDeep(drop, function (val) { return _.cloneDeep(drop, (val) => {
return _.isFunction(val) ? val : undefined; // undefined will be handled by lodash return _.isFunction(val) ? val : undefined; // undefined will be handled by lodash
}); });
} }
module.exports = function randomDrop (user, modifiers, req) { module.exports = function randomDrop (user, modifiers, req = {}) {
var acceptableDrops, base, base1, base2, chance, drop, dropK, dropMultiplier, name, name1, name2, quest, rarity, ref, ref1, ref2, ref3, task; let acceptableDrops;
let chance;
let drop;
let dropK;
let dropMultiplier;
let quest;
let rarity;
let task;
task = modifiers.task; task = modifiers.task;
chance = _.min([Math.abs(task.value - 21.27), 37.5]) / 150 + .02;
chance *= task.priority * (1 + (task.streak / 100 || 0)) * (1 + (user._statsComputed.per / 100)) * (1 + (user.contributor.level / 40 || 0)) * (1 + (user.achievements.rebirths / 20 || 0)) * (1 + (user.achievements.streak / 200 || 0)) * (user._tmp.crit || 1) * (1 + .5 * (_.reduce(task.checklist, (function(m, i) { chance = _.min([Math.abs(task.value - 21.27), 37.5]) / 150 + 0.02;
return m + (i.completed ? 1 : 0); chance *= task.priority * // Task priority: +50% for Medium, +100% for Hard
}), 0) || 0)); (1 + (task.streak / 100 || 0)) * // Streak bonus: +1% per streak
(1 + user._statsComputed.per / 100) * // PERception: +1% per point
(1 + (user.contributor.level / 40 || 0)) * // Contrib levels: +2.5% per level
(1 + (user.achievements.rebirths / 20 || 0)) * // Rebirths: +5% per achievement
(1 + (user.achievements.streak / 200 || 0)) * // Streak achievements: +0.5% per achievement
(user._tmp.crit || 1) * (1 + 0.5 * (_.reduce(task.checklist, (m, i) => {
return m + (i.completed ? 1 : 0); // +50% per checklist item complete. TODO: make this into X individual drop chances instead
}, 0) || 0));
chance = diminishingReturns(chance, 0.75); chance = diminishingReturns(chance, 0.75);
quest = content.quests[(ref = user.party.quest) != null ? ref.key : void 0];
if ((quest != null ? quest.collect : void 0) && user.fns.predictableRandom(user.stats.gp) < chance) { if (user.party.quest.key)
dropK = user.fns.randomVal(quest.collect, { quest = content.quests[user.party.quest.key];
key: true if (quest && quest.collect && predictableRandom(user, user.stats.gp) < chance) {
dropK = randomVal(user, quest.collect, {
key: true,
}); });
if (!user.party.quest.progress.collect[dropK])
user.party.quest.progress.collect[dropK] = 0;
user.party.quest.progress.collect[dropK]++; user.party.quest.progress.collect[dropK]++;
if (typeof user.markModified === "function") {
user.markModified('party.quest.progress'); user.markModified('party.quest.progress');
} }
if (user.purchased && user.purchased.plan && user.purchased.plan.custsomerId) {
dropMultiplier = 2;
} else {
dropMultiplier = 1;
} }
dropMultiplier = ((ref1 = user.purchased) != null ? (ref2 = ref1.plan) != null ? ref2.customerId : void 0 : void 0) ? 2 : 1;
if ((daysSince(user.items.lastDrop.date, user.preferences) === 0) && (user.items.lastDrop.count >= dropMultiplier * (5 + Math.floor(user._statsComputed.per / 25) + (user.contributor.level || 0)))) { if (daysSince(user.items.lastDrop.date, user.preferences) === 0 &&
user.items.lastDrop.count >= dropMultiplier * (5 + Math.floor(user._statsComputed.per / 25) + (user.contributor.level || 0))) {
return; return;
} }
if (((ref3 = user.flags) != null ? ref3.dropsEnabled : void 0) && user.fns.predictableRandom(user.stats.exp) < chance) {
rarity = user.fns.predictableRandom(user.stats.gp); if (user.flags && user.flags.dropsEnabled && predictableRandom(user, user.stats.exp) < chance) {
if (rarity > .6) { rarity = predictableRandom(user, user.stats.gp);
drop = cloneDropItem(user.fns.randomVal(_.where(content.food, {
canDrop: true if (rarity > 0.6) { // food 40% chance
drop = cloneDropItem(randomVal(user, _.where(content.food, {
canDrop: true,
}))); })));
if ((base = user.items.food)[name = drop.key] == null) {
base[name] = 0; if (!user.items.food[drop.key]) {
user.items.food[drop.key] = 0;
} }
user.items.food[drop.key] += 1; user.items.food[drop.key] += 1;
drop.type = 'Food'; drop.type = 'Food';
drop.dialog = i18n.t('messageDropFood', { drop.dialog = i18n.t('messageDropFood', {
dropArticle: drop.article, dropArticle: drop.article,
dropText: drop.text(req.language), dropText: drop.text(req.language),
dropNotes: drop.notes(req.language) dropNotes: drop.notes(req.language),
}, req.language); }, req.language);
} else if (rarity > .3) { } else if (rarity > 0.3) { // eggs 30% chance
drop = cloneDropItem(user.fns.randomVal(content.dropEggs)); drop = cloneDropItem(randomVal(user, content.dropEggs));
if ((base1 = user.items.eggs)[name1 = drop.key] == null) { if (!user.items.eggs[drop.key]) {
base1[name1] = 0; user.items.eggs[drop.key] = 0;
} }
user.items.eggs[drop.key]++; user.items.eggs[drop.key]++;
drop.type = 'Egg'; drop.type = 'Egg';
drop.dialog = i18n.t('messageDropEgg', { drop.dialog = i18n.t('messageDropEgg', {
dropText: drop.text(req.language), dropText: drop.text(req.language),
dropNotes: drop.notes(req.language) dropNotes: drop.notes(req.language),
}, req.language); }, req.language);
} else { } else { // Hatching Potion, 30% chance - break down by rarity.
acceptableDrops = rarity < .02 ? ['Golden'] : rarity < .09 ? ['Zombie', 'CottonCandyPink', 'CottonCandyBlue'] : rarity < .18 ? ['Red', 'Shade', 'Skeleton'] : ['Base', 'White', 'Desert']; if (rarity < 0.02) { // Very Rare: 10% (of 30%)
drop = cloneDropItem(user.fns.randomVal(_.pick(content.hatchingPotions, (function(v, k) { acceptableDrops = ['Golden'];
} else if (rarity < 0.09) { // Rare: 20% of 30%
acceptableDrops = ['Zombie', 'CottonCandyPink', 'CottonCandyBlue'];
} else if (rarity < 0.18) { // uncommon: 30% of 30%
acceptableDrops = ['Red', 'Shade', 'Skeleton'];
} else { // common, 40% of 30%
acceptableDrops = ['Base', 'White', 'Desert'];
}
drop = cloneDropItem(randomVal(user, _.pick(content.hatchingPotions, (v, k) => {
return acceptableDrops.indexOf(k) >= 0; return acceptableDrops.indexOf(k) >= 0;
})))); })));
if ((base2 = user.items.hatchingPotions)[name2 = drop.key] == null) { if (!user.items.hatchingPotions[drop.key]) {
base2[name2] = 0; user.items.hatchingPotions[drop.key] = 0;
} }
user.items.hatchingPotions[drop.key]++; user.items.hatchingPotions[drop.key]++;
drop.type = 'HatchingPotion'; drop.type = 'HatchingPotion';
drop.dialog = i18n.t('messageDropPotion', { drop.dialog = i18n.t('messageDropPotion', {
dropText: drop.text(req.language), dropText: drop.text(req.language),
dropNotes: drop.notes(req.language) dropNotes: drop.notes(req.language),
}, req.language); }, req.language);
} }
user._tmp.drop = drop; user._tmp.drop = drop;
user.items.lastDrop.date = +(new Date); user.items.lastDrop.date = Number(new Date());
return user.items.lastDrop.count++; user.items.lastDrop.count++;
} }
}; };

View File

@@ -85,12 +85,37 @@ import count from './count';
api.count = count; api.count = count;
import statsComputed from './libs/statsComputed'; import statsComputed from './libs/statsComputed';
api.statsComputed = statsComputed;
import autoAllocate from './fns/autoAllocate';
import crit from './fns/crit';
import handleTwoHanded from './fns/handleTwoHanded';
import predictableRandom from './fns/predictableRandom';
import randomDrop from './fns/randomDrop';
import randomVal from './fns/randomVal';
import resetGear from './fns/resetGear';
import ultimateGear from './fns/ultimateGear';
import updateStats from './fns/updateStats';
api.fns = {
autoAllocate,
crit,
handleTwoHanded,
predictableRandom,
randomDrop,
randomVal,
resetGear,
ultimateGear,
updateStats,
};
// TODO As ops and fns are ported, exported them through the api object
import scoreTask from './ops/scoreTask'; import scoreTask from './ops/scoreTask';
import sleep from './ops/sleep'; import sleep from './ops/sleep';
import allocate from './ops/allocate'; import allocate from './ops/allocate';
import buy from './ops/buy'; import buy from './ops/buy';
import buyGear from './ops/buyGear';
import buyPotion from './ops/buyPotion';
import buyArmoire from './ops/buyArmoire';
import buyMysterySet from './ops/buyMysterySet'; import buyMysterySet from './ops/buyMysterySet';
import buyQuest from './ops/buyQuest'; import buyQuest from './ops/buyQuest';
import buySpecialSpell from './ops/buySpecialSpell'; import buySpecialSpell from './ops/buySpecialSpell';
@@ -128,6 +153,9 @@ api.ops = {
sleep, sleep,
allocate, allocate,
buy, buy,
buyGear,
buyPotion,
buyArmoire,
buyMysterySet, buyMysterySet,
buySpecialSpell, buySpecialSpell,
buyQuest, buyQuest,
@@ -161,28 +189,12 @@ api.ops = {
reset, reset,
}; };
import handleTwoHanded from './fns/handleTwoHanded';
import predictableRandom from './fns/predictableRandom';
import randomVal from './fns/randomVal';
import ultimateGear from './fns/ultimateGear';
import autoAllocate from './fns/autoAllocate';
api.fns = {
handleTwoHanded,
predictableRandom,
randomVal,
ultimateGear,
autoAllocate,
};
/* /*
------------------------------------------------------ ------------------------------------------------------
User (prototype wrapper to give it ops, helper funcs, and virtuals User (prototype wrapper to give it ops, helper funcs, and virtuals
------------------------------------------------------ ------------------------------------------------------
*/ */
/* /*
User is now wrapped (both on client and server), adding a few new properties: User is now wrapped (both on client and server), adding a few new properties:
* getters (_statsComputed, tasks, etc) * getters (_statsComputed, tasks, etc)
@@ -216,7 +228,7 @@ TODO
import importedOps from './ops'; import importedOps from './ops';
import importedFns from './fns'; import importedFns from './fns';
// TODO redo // TODO Kept for the client side
api.wrap = function wrapUser (user, main = true) { api.wrap = function wrapUser (user, main = true) {
if (user._wrapped) return; if (user._wrapped) return;
user._wrapped = true; user._wrapped = true;
@@ -260,6 +272,9 @@ api.wrap = function wrapUser (user, main = true) {
releaseMounts: _.partial(importedOps.releaseMounts, user), releaseMounts: _.partial(importedOps.releaseMounts, user),
releaseBoth: _.partial(importedOps.releaseBoth, user), releaseBoth: _.partial(importedOps.releaseBoth, user),
buy: _.partial(importedOps.buy, user), buy: _.partial(importedOps.buy, user),
buyPotion: _.partial(importedOps.buyPotion, user),
buyArmoire: _.partial(importedOps.buyArmoire, user),
buyGear: _.partial(importedOps.buyGear, user),
buyQuest: _.partial(importedOps.buyQuest, user), buyQuest: _.partial(importedOps.buyQuest, user),
buyMysterySet: _.partial(importedOps.buyMysterySet, user), buyMysterySet: _.partial(importedOps.buyMysterySet, user),
hourglassPurchase: _.partial(importedOps.hourglassPurchase, user), hourglassPurchase: _.partial(importedOps.hourglassPurchase, user),

View File

@@ -1,11 +1,11 @@
import _ from 'lodash'; import _ from 'lodash';
import i18n from '../i18n'; import i18n from '../i18n';
import splitWhitespace from '../libs/splitWhitespace';
import { import {
BadRequest, BadRequest,
NotAuthorized, NotAuthorized,
} from '../libs/errors'; } from '../libs/errors';
// TODO move to server code
module.exports = function addPushDevice (user, req = {}) { module.exports = function addPushDevice (user, req = {}) {
let regId = _.get(req, 'body.regId'); let regId = _.get(req, 'body.regId');
if (!regId) throw new BadRequest(i18n.t('regIdRequired', req.language)); if (!regId) throw new BadRequest(i18n.t('regIdRequired', req.language));
@@ -34,10 +34,8 @@ module.exports = function addPushDevice (user, req = {}) {
pushDevices.push(item); pushDevices.push(item);
let response = { return [
data: _.pick(user, splitWhitespace('pushDevices')), user.pushDevices,
message: i18n.t('pushDeviceAdded', req.language), i18n.t('pushDeviceAdded', req.language),
}; ];
return response;
}; };

View File

@@ -7,8 +7,7 @@ import {
import _ from 'lodash'; import _ from 'lodash';
module.exports = function addWebhook (user, req = {}) { module.exports = function addWebhook (user, req = {}) {
let wh; let wh = user.preferences.webhooks;
wh = user.preferences.webhooks;
if (!validator.isURL(_.get(req, 'body.url'))) throw new BadRequest(i18n.t('invalidUrl', req.language)); if (!validator.isURL(_.get(req, 'body.url'))) throw new BadRequest(i18n.t('invalidUrl', req.language));
if (!validator.isBoolean(_.get(req, 'body.enabled'))) throw new BadRequest(i18n.t('invalidEnabled', req.language)); if (!validator.isBoolean(_.get(req, 'body.enabled'))) throw new BadRequest(i18n.t('invalidEnabled', req.language));
@@ -18,9 +17,11 @@ module.exports = function addWebhook (user, req = {}) {
if (req.v2 === true) { if (req.v2 === true) {
return user.preferences.webhooks; return user.preferences.webhooks;
} else { } else {
return refPush(wh, { return [
refPush(wh, {
url: req.body.url, url: req.body.url,
enabled: req.body.enabled, enabled: req.body.enabled,
}); }),
];
} }
}; };

View File

@@ -1,5 +1,4 @@
import _ from 'lodash'; import _ from 'lodash';
import splitWhitespace from '../libs/splitWhitespace';
import { import {
ATTRIBUTES, ATTRIBUTES,
} from '../constants'; } from '../constants';
@@ -26,5 +25,7 @@ module.exports = function allocate (user, req = {}) {
throw new NotAuthorized(i18n.t('notEnoughAttrPoints', req.language)); throw new NotAuthorized(i18n.t('notEnoughAttrPoints', req.language));
} }
return _.pick(user, splitWhitespace('stats')); return [
user.stats,
];
}; };

View File

@@ -8,8 +8,8 @@ module.exports = function allocateNow (user, req = {}) {
if (req.v2 === true) { if (req.v2 === true) {
return _.pick(user, 'stats'); return _.pick(user, 'stats');
} else { } else {
return { return [
data: _.pick(user, 'stats'), user.stats,
}; ];
} }
}; };

View File

@@ -15,5 +15,7 @@ module.exports = function blockUser (user, req = {}) {
} }
user.markModified('inbox.blocks'); user.markModified('inbox.blocks');
return user.inbox.blocks; return [
user.inbox.blocks,
];
}; };

View File

@@ -1,142 +1,24 @@
import content from '../content/index';
import i18n from '../i18n'; import i18n from '../i18n';
import _ from 'lodash'; import _ from 'lodash';
import count from '../count';
import splitWhitespace from '../libs/splitWhitespace';
import { import {
BadRequest, BadRequest,
NotAuthorized,
NotFound,
} from '../libs/errors'; } from '../libs/errors';
import predictableRandom from '../fns/predictableRandom'; import buyPotion from './buyPotion';
import randomVal from '../fns/randomVal'; import buyArmoire from './buyArmoire';
import handleTwoHanded from '../fns/handleTwoHanded'; import buyGear from './buyGear';
import ultimateGear from '../fns/ultimateGear';
module.exports = function buy (user, req = {}, analytics) { module.exports = function buy (user, req = {}, analytics) {
let key = _.get(req, 'params.key'); let key = _.get(req, 'params.key');
if (!key) throw new BadRequest(i18n.t('missingKeyParam', req.language)); if (!key) throw new BadRequest(i18n.t('missingKeyParam', req.language));
let item; let buyRes;
if (key === 'potion') { if (key === 'potion') {
item = content.potion; buyRes = buyPotion(user, req, analytics);
} else if (key === 'armoire') { } else if (key === 'armoire') {
item = content.armoire; buyRes = buyArmoire(user, req, analytics);
} else { } else {
item = content.gear.flat[key]; buyRes = buyGear(user, req, analytics);
}
if (!item) throw new NotFound(i18n.t('itemNotFound', {key}, req.language));
if (user.stats.gp < item.value) {
throw new NotAuthorized(i18n.t('messageNotEnoughGold', req.language));
} }
if (item.canOwn && !item.canOwn(user)) { return buyRes;
throw new NotAuthorized(i18n.t('cannoyBuyItem', req.language));
}
let armoireResp;
let armoireResult;
let eligibleEquipment;
let drop;
let message;
if (item.key === 'potion') {
user.stats.hp += 15;
if (user.stats.hp > 50) {
user.stats.hp = 50;
}
} else if (item.key === 'armoire') {
armoireResult = predictableRandom(user, user.stats.gp);
eligibleEquipment = _.filter(content.gear.flat, (eligible) => {
return eligible.klass === 'armoire' && !user.items.gear.owned[eligible.key];
});
if (!_.isEmpty(eligibleEquipment) && (armoireResult < 0.6 || !user.flags.armoireOpened)) {
eligibleEquipment.sort();
drop = randomVal(user, eligibleEquipment);
user.items.gear.owned[drop.key] = true;
user.flags.armoireOpened = true;
message = i18n.t('armoireEquipment', {
image: `<span class="shop_${drop.key} pull-left"></span>`,
dropText: drop.text(req.language),
}, req.language);
if (count.remainingGearInSet(user.items.gear.owned, 'armoire') === 0) {
user.flags.armoireEmpty = true;
}
armoireResp = {
type: 'gear',
dropKey: drop.key,
dropText: drop.text(req.language),
};
} else if ((!_.isEmpty(eligibleEquipment) && armoireResult < 0.8) || armoireResult < 0.5) { // eslint-disable-line no-extra-parens
drop = randomVal(user, _.where(content.food, {
canDrop: true,
}));
user.items.food[drop.key] = user.items.food[drop.key] || 0;
user.items.food[drop.key] += 1;
message = i18n.t('armoireFood', {
image: `<span class="Pet_Food_${drop.key} pull-left"></span>`,
dropArticle: drop.article,
dropText: drop.text(req.language),
}, req.language);
armoireResp = {
type: 'food',
dropKey: drop.key,
dropArticle: drop.article,
dropText: drop.text(req.language),
};
} else {
let armoireExp = Math.floor(predictableRandom(user, user.stats.exp) * 40 + 10);
user.stats.exp += armoireExp;
message = i18n.t('armoireExp', req.language);
armoireResp = {
type: 'experience',
value: armoireExp,
};
}
} else {
if (user.preferences.autoEquip) {
user.items.gear.equipped[item.type] = item.key;
message = handleTwoHanded(user, item, undefined, req);
}
user.items.gear.owned[item.key] = true;
if (item.last) ultimateGear(user);
}
user.stats.gp -= item.value;
if (!message) {
message = i18n.t('messageBought', {
itemText: item.text(req.language),
}, req.language);
}
if (analytics) {
analytics.track('acquire item', {
uuid: user._id,
itemKey: key,
acquireMethod: 'Gold',
goldCost: item.value,
category: 'behavior',
});
}
let res = {
data: _.pick(user, splitWhitespace('items achievements stats flags')),
message,
};
if (armoireResp) res.armoire = armoireResp;
if (req.v2 === true) {
return res.data;
} else {
return res;
}
}; };

View File

@@ -0,0 +1,115 @@
import content from '../content/index';
import i18n from '../i18n';
import _ from 'lodash';
import count from '../count';
import splitWhitespace from '../libs/splitWhitespace';
import {
NotAuthorized,
} from '../libs/errors';
import predictableRandom from '../fns/predictableRandom';
import randomVal from '../fns/randomVal';
module.exports = function buyArmoire (user, req = {}, analytics) {
let item = content.armoire;
if (user.stats.gp < item.value) {
throw new NotAuthorized(i18n.t('messageNotEnoughGold', req.language));
}
if (item.canOwn && !item.canOwn(user)) {
throw new NotAuthorized(i18n.t('cannotBuyItem', req.language));
}
let armoireResp;
let armoireResult;
let eligibleEquipment;
let drop;
let message;
armoireResult = predictableRandom(user, user.stats.gp);
eligibleEquipment = _.filter(content.gear.flat, (eligible) => {
return eligible.klass === 'armoire' && !user.items.gear.owned[eligible.key];
});
if (!_.isEmpty(eligibleEquipment) && (armoireResult < 0.6 || !user.flags.armoireOpened)) {
eligibleEquipment.sort();
drop = randomVal(user, eligibleEquipment);
if (user.items.gear.owned[drop.key]) {
throw new NotAuthorized(i18n.t('equipmentAlradyOwned', req.language));
}
user.items.gear.owned[drop.key] = true;
user.flags.armoireOpened = true;
message = i18n.t('armoireEquipment', {
image: `<span class="shop_${drop.key} pull-left"></span>`,
dropText: drop.text(req.language),
}, req.language);
if (count.remainingGearInSet(user.items.gear.owned, 'armoire') === 0) {
user.flags.armoireEmpty = true;
}
armoireResp = {
type: 'gear',
dropKey: drop.key,
dropText: drop.text(req.language),
};
} else if ((!_.isEmpty(eligibleEquipment) && armoireResult < 0.8) || armoireResult < 0.5) { // eslint-disable-line no-extra-parens
drop = randomVal(user, _.where(content.food, {
canDrop: true,
}));
user.items.food[drop.key] = user.items.food[drop.key] || 0;
user.items.food[drop.key] += 1;
message = i18n.t('armoireFood', {
image: `<span class="Pet_Food_${drop.key} pull-left"></span>`,
dropArticle: drop.article,
dropText: drop.text(req.language),
}, req.language);
armoireResp = {
type: 'food',
dropKey: drop.key,
dropArticle: drop.article,
dropText: drop.text(req.language),
};
} else {
let armoireExp = Math.floor(predictableRandom(user, user.stats.exp) * 40 + 10);
user.stats.exp += armoireExp;
message = i18n.t('armoireExp', req.language);
armoireResp = {
type: 'experience',
value: armoireExp,
};
}
user.stats.gp -= item.value;
if (!message) {
message = i18n.t('messageBought', {
itemText: item.text(req.language),
}, req.language);
}
if (analytics) {
analytics.track('acquire item', {
uuid: user._id,
itemKey: 'Armoire',
acquireMethod: 'Gold',
goldCost: item.value,
category: 'behavior',
});
}
let resData = _.pick(user, splitWhitespace('items flags'));
if (armoireResp) resData.armoire = armoireResp;
if (req.v2 === true) {
return resData;
} else {
return [
resData,
message,
];
}
};

View File

@@ -0,0 +1,70 @@
import content from '../content/index';
import i18n from '../i18n';
import _ from 'lodash';
import splitWhitespace from '../libs/splitWhitespace';
import {
BadRequest,
NotAuthorized,
NotFound,
} from '../libs/errors';
import handleTwoHanded from '../fns/handleTwoHanded';
import ultimateGear from '../fns/ultimateGear';
module.exports = function buyGear (user, req = {}, analytics) {
let key = _.get(req, 'params.key');
if (!key) throw new BadRequest(i18n.t('missingKeyParam', req.language));
let item = content.gear.flat[key];
if (!item) throw new NotFound(i18n.t('itemNotFound', {key}, req.language));
if (user.stats.gp < item.value) {
throw new NotAuthorized(i18n.t('messageNotEnoughGold', req.language));
}
if (item.canOwn && !item.canOwn(user)) {
throw new NotAuthorized(i18n.t('cannotBuyItem', req.language));
}
let message;
if (user.items.gear.owned[item.key]) {
throw new NotAuthorized(i18n.t('equipmentAlreadyOwned', req.language));
}
if (user.preferences.autoEquip) {
user.items.gear.equipped[item.type] = item.key;
message = handleTwoHanded(user, item, undefined, req);
}
user.items.gear.owned[item.key] = true;
if (item.last) ultimateGear(user);
user.stats.gp -= item.value;
if (!message) {
message = i18n.t('messageBought', {
itemText: item.text(req.language),
}, req.language);
}
if (analytics) {
analytics.track('acquire item', {
uuid: user._id,
itemKey: key,
acquireMethod: 'Gold',
goldCost: item.value,
category: 'behavior',
});
}
if (req.v2 === true) {
return _.pick(user, splitWhitespace('items achievements stats flags'));
} else {
return [
_.pick(user, splitWhitespace('items achievements stats flags')),
message,
];
}
};

View File

@@ -47,9 +47,9 @@ module.exports = function buyMysterySet (user, req = {}, analytics) {
if (req.v2 === true) { if (req.v2 === true) {
return pickDeep(user, splitWhitespace('items purchased.plan.consecutive')); return pickDeep(user, splitWhitespace('items purchased.plan.consecutive'));
} else { } else {
return { return [
data: pickDeep(user, splitWhitespace('items purchased.plan.consecutive')), { items: user.items, purchasedPlanConsecutive: user.purchased.plan.consecutive },
message: i18n.t('hourglassPurchaseSet', req.language), i18n.t('hourglassPurchaseSet', req.language),
}; ];
} }
}; };

View File

@@ -0,0 +1,48 @@
import content from '../content/index';
import i18n from '../i18n';
import {
NotAuthorized,
} from '../libs/errors';
module.exports = function buyPotion (user, req = {}, analytics) {
let item = content.potion;
if (user.stats.gp < item.value) {
throw new NotAuthorized(i18n.t('messageNotEnoughGold', req.language));
}
if (item.canOwn && !item.canOwn(user)) {
throw new NotAuthorized(i18n.t('cannotBuyItem', req.language));
}
user.stats.hp += 15;
if (user.stats.hp > 50) {
user.stats.hp = 50;
}
user.stats.gp -= item.value;
let message = i18n.t('messageBought', {
itemText: item.text(req.language),
}, req.language);
if (analytics) {
analytics.track('acquire item', {
uuid: user._id,
itemKey: 'Potion',
acquireMethod: 'Gold',
goldCost: item.value,
category: 'behavior',
});
}
if (req.v2 === true) {
return user.stats;
} else {
return [
user.stats,
message,
];
}
};

View File

@@ -40,11 +40,11 @@ module.exports = function buyQuest (user, req = {}, analytics) {
if (req.v2 === true) { if (req.v2 === true) {
return user.items.quests; return user.items.quests;
} else { } else {
return { return [
data: user.items.quests, user.items.quests,
message: i18n.t('messageBought', { i18n.t('messageBought', {
itemText: item.text(req.language), itemText: item.text(req.language),
}, req.language), }, req.language),
}; ];
} }
}; };

View File

@@ -25,11 +25,11 @@ module.exports = function buySpecialSpell (user, req = {}) {
if (req.v2 === true) { if (req.v2 === true) {
return _.pick(user, splitWhitespace('items stats')); return _.pick(user, splitWhitespace('items stats'));
} else { } else {
return { return [
data: _.pick(user, splitWhitespace('items stats')), _.pick(user, splitWhitespace('items stats')),
message: i18n.t('messageBought', { i18n.t('messageBought', {
itemText: item.text(req.language), itemText: item.text(req.language),
}, req.language), }, req.language),
}; ];
} }
}; };

View File

@@ -71,8 +71,8 @@ module.exports = function changeClass (user, req = {}, analytics) {
if (req.v2 === true) { if (req.v2 === true) {
return _.pick(user, splitWhitespace('stats flags items preferences')); return _.pick(user, splitWhitespace('stats flags items preferences'));
} else { } else {
return { return [
data: _.pick(user, splitWhitespace('stats flags items preferences')), _.pick(user, splitWhitespace('stats flags items preferences')),
}; ];
} }
}; };

View File

@@ -1,5 +1,7 @@
module.exports = function clearPMs (user) { module.exports = function clearPMs (user) {
user.inbox.messages = {}; user.inbox.messages = {};
user.markModified('inbox.messages'); user.markModified('inbox.messages');
return user.inbox.messages; return [
user.inbox.messages,
];
}; };

View File

@@ -3,5 +3,7 @@ import _ from 'lodash';
module.exports = function deletePM (user, req = {}) { module.exports = function deletePM (user, req = {}) {
delete user.inbox.messages[_.get(req, 'params.id')]; delete user.inbox.messages[_.get(req, 'params.id')];
user.markModified(`inbox.messages.${req.params.id}`); user.markModified(`inbox.messages.${req.params.id}`);
return user.inbox.messages; return [
user.inbox.messages,
];
}; };

View File

@@ -4,5 +4,7 @@ module.exports = function deleteWebhook (user, req) {
delete user.preferences.webhooks[_.get(req, 'params.id')]; delete user.preferences.webhooks[_.get(req, 'params.id')];
user.markModified('preferences.webhooks'); user.markModified('preferences.webhooks');
return user.preferences.webhooks; return [
user.preferences.webhooks,
];
}; };

View File

@@ -13,8 +13,8 @@ module.exports = function disableClasses (user, req = {}) {
if (req.v2 === true) { if (req.v2 === true) {
return _.pick(user, splitWhitespace('stats flags preferences')); return _.pick(user, splitWhitespace('stats flags preferences'));
} else { } else {
return { return [
data: _.pick(user, splitWhitespace('stats flags preferences')), _.pick(user, splitWhitespace('stats flags preferences')),
}; ];
} }
}; };

View File

@@ -58,14 +58,11 @@ module.exports = function equip (user, req = {}) {
} }
} }
let res = {
data: user.items,
};
if (message) res.message = message;
if (req.v2 === true) { if (req.v2 === true) {
return user.items; return user.items;
} else { } else {
let res = [user.items];
if (message) res.push(message);
return res; return res;
} }
}; };

View File

@@ -94,9 +94,9 @@ module.exports = function feed (user, req = {}) {
value: userPets[pet], value: userPets[pet],
}; };
} else { } else {
return { return [
data: userPets[pet], userPets[pet],
message, message,
}; ];
} }
}; };

View File

@@ -36,9 +36,9 @@ module.exports = function hatch (user, req = {}) {
if (req.v2 === true) { if (req.v2 === true) {
return user.items; return user.items;
} else { } else {
return { return [
message: i18n.t('messageHatched', req.language), user.items,
data: user.items, i18n.t('messageHatched', req.language),
}; ];
} }
}; };

View File

@@ -1,12 +1,11 @@
import content from '../content/index'; import content from '../content/index';
import i18n from '../i18n'; import i18n from '../i18n';
import _ from 'lodash'; import _ from 'lodash';
import splitWhitespace from '../libs/splitWhitespace';
import pickDeep from '../libs/pickDeep';
import { import {
BadRequest, BadRequest,
NotAuthorized, NotAuthorized,
} from '../libs/errors'; } from '../libs/errors';
import splitWhitespace from '../libs/splitWhitespace';
module.exports = function purchaseHourglass (user, req = {}, analytics) { module.exports = function purchaseHourglass (user, req = {}, analytics) {
let key = _.get(req, 'params.key'); let key = _.get(req, 'params.key');
@@ -51,14 +50,12 @@ module.exports = function purchaseHourglass (user, req = {}, analytics) {
}); });
} }
let res = {
data: pickDeep(user, splitWhitespace('items purchased.plan.consecutive')),
message: i18n.t('hourglassPurchase', req.language),
};
if (req.v2 === true) { if (req.v2 === true) {
return res.data; return _.pick(user, splitWhitespace('items purchased.plan.consecutive'));
} else { } else {
return res; return [
{ items: user.items, purchasedPlanConsecutive: user.purchased.plan.consecutive },
i18n.t('hourglassPurchase', req.language),
];
} }
}; };

View File

@@ -30,6 +30,9 @@ import releasePets from './releasePets';
import releaseMounts from './releaseMounts'; import releaseMounts from './releaseMounts';
import releaseBoth from './releaseBoth'; import releaseBoth from './releaseBoth';
import buy from './buy'; import buy from './buy';
import buyGear from './buyGear';
import buyPotion from './buyPotion';
import buyArmoire from './buyArmoire';
import buyQuest from './buyQuest'; import buyQuest from './buyQuest';
import buyMysterySet from './buyMysterySet'; import buyMysterySet from './buyMysterySet';
import hourglassPurchase from './hourglassPurchase'; import hourglassPurchase from './hourglassPurchase';
@@ -77,6 +80,9 @@ module.exports = {
releaseMounts, releaseMounts,
releaseBoth, releaseBoth,
buy, buy,
buyGear,
buyPotion,
buyArmoire,
buyQuest, buyQuest,
buyMysterySet, buyMysterySet,
hourglassPurchase, hourglassPurchase,

View File

@@ -36,9 +36,9 @@ module.exports = function openMysteryItem (user, req = {}, analytics) {
if (req.v2 === true) { if (req.v2 === true) {
return user.items.gear.owned; return user.items.gear.owned;
} else { } else {
return { return [
message: i18n.t('mysteryItemOpened', req.language), user.items.gear.owned,
data: user.items.gear.owned, i18n.t('mysteryItemOpened', req.language),
}; ];
} }
}; };

View File

@@ -54,12 +54,10 @@ module.exports = function purchase (user, req = {}, analytics) {
}); });
} }
let response = { return [
data: _.pick(user, splitWhitespace('stats balance')), _.pick(user, splitWhitespace('stats balance')),
message: i18n.t('plusOneGem'), i18n.t('plusOneGem'),
}; ];
return response;
} }
let acceptedTypes = ['eggs', 'hatchingPotions', 'food', 'quests', 'gear']; let acceptedTypes = ['eggs', 'hatchingPotions', 'food', 'quests', 'gear'];
@@ -119,14 +117,12 @@ module.exports = function purchase (user, req = {}, analytics) {
}); });
} }
let response = {
data: _.pick(user, splitWhitespace('items balance')),
message: i18n.t('purchased', {type, key}),
};
if (req.v2 === true) { if (req.v2 === true) {
return response.data; return _.pick(user, splitWhitespace('items balance'));
} else { } else {
return response; return [
_.pick(user, splitWhitespace('items balance')),
i18n.t('purchased', {type, key}),
];
} }
}; };

View File

@@ -24,9 +24,9 @@ module.exports = function readCard (user, req = {}) {
if (req.v2 === true) { if (req.v2 === true) {
return _.pick(user, splitWhitespace('items.special flags.cardReceived')); return _.pick(user, splitWhitespace('items.special flags.cardReceived'));
} else { } else {
return { return [
message: i18n.t('readCard', {cardType}, req.language), { specialItems: user.items.special, cardReceived: user.flags.cardReceived },
data: _.pick(user, splitWhitespace('items.special flags.cardReceived')), i18n.t('readCard', {cardType}, req.language),
}; ];
} }
}; };

View File

@@ -98,14 +98,12 @@ module.exports = function rebirth (user, tasks = [], req = {}, analytics) {
user.stats.buffs = {}; user.stats.buffs = {};
let response = {
data: user,
message: i18n.t('rebirthComplete'),
};
if (req.v2 === true) { if (req.v2 === true) {
return user; return user;
} else { } else {
return response; return [
{user, tasks},
i18n.t('rebirthComplete'),
];
} }
}; };

View File

@@ -57,14 +57,12 @@ module.exports = function releaseBoth (user, req = {}, analytics) {
user.achievements.triadBingoCount++; user.achievements.triadBingoCount++;
} }
let response = {
data: _.pick(user, splitWhitespace('achievements')),
message: i18n.t('mountsAndPetsReleased'),
};
if (req.v2 === true) { if (req.v2 === true) {
return user; return user;
} else { } else {
return response; return [
_.pick(user, splitWhitespace('achievements items balance')),
i18n.t('mountsAndPetsReleased'),
];
} }
}; };

View File

@@ -3,8 +3,6 @@ import i18n from '../i18n';
import { import {
NotAuthorized, NotAuthorized,
} from '../libs/errors'; } from '../libs/errors';
import splitWhitespace from '../libs/splitWhitespace';
import _ from 'lodash';
module.exports = function releaseMounts (user, req = {}, analytics) { module.exports = function releaseMounts (user, req = {}, analytics) {
let mount; let mount;
@@ -34,14 +32,12 @@ module.exports = function releaseMounts (user, req = {}, analytics) {
}); });
} }
let response = {
data: _.pick(user, splitWhitespace('mounts')),
message: i18n.t('mountsReleased'),
};
if (req.v2 === true) { if (req.v2 === true) {
return user; return user;
} else { } else {
return response; return [
user.items.mounts,
i18n.t('mountsReleased'),
];
} }
}; };

View File

@@ -3,8 +3,6 @@ import i18n from '../i18n';
import { import {
NotAuthorized, NotAuthorized,
} from '../libs/errors'; } from '../libs/errors';
import splitWhitespace from '../libs/splitWhitespace';
import _ from 'lodash';
module.exports = function releasePets (user, req = {}, analytics) { module.exports = function releasePets (user, req = {}, analytics) {
if (user.balance < 1) { if (user.balance < 1) {
@@ -32,14 +30,12 @@ module.exports = function releasePets (user, req = {}, analytics) {
}); });
} }
let response = {
data: _.pick(user, splitWhitespace('user.items.pets')),
message: i18n.t('petsReleased'),
};
if (req.v2 === true) { if (req.v2 === true) {
return user; return user;
} else { } else {
return response; return [
user.items.pets,
i18n.t('petsReleased'),
];
} }
}; };

View File

@@ -27,14 +27,12 @@ module.exports = function reroll (user, tasks = [], req = {}, analytics) {
}); });
} }
let response = {
data: {user, tasks},
message: i18n.t('rerollComplete'),
};
if (req.v2 === true) { if (req.v2 === true) {
return user; return user;
} else { } else {
return response; return [
{user, tasks},
i18n.t('rerollComplete'),
];
} }
}; };

View File

@@ -19,14 +19,12 @@ module.exports = function reset (user, tasks = [], req = {}) {
resetGear(user); resetGear(user);
let response = {
data: {user, tasksToRemove},
message: i18n.t('resetComplete'),
};
if (req.v2 === true) { if (req.v2 === true) {
return user; return user;
} else { } else {
return response; return [
{user, tasksToRemove},
i18n.t('resetComplete'),
];
} }
}; };

View File

@@ -4,7 +4,6 @@ import _ from 'lodash';
import { import {
NotAuthorized, NotAuthorized,
} from '../libs/errors'; } from '../libs/errors';
import splitWhitespace from '../libs/splitWhitespace';
import randomVal from '../fns/randomVal'; import randomVal from '../fns/randomVal';
module.exports = function revive (user, req = {}, analytics) { module.exports = function revive (user, req = {}, analytics) {
@@ -97,14 +96,12 @@ module.exports = function revive (user, req = {}, analytics) {
}); });
} }
let response = {
data: _.pick(user, splitWhitespace('user.items')),
message,
};
if (req.v2 === true) { if (req.v2 === true) {
return user; return user;
} else { } else {
return response; return [
user.items,
message,
];
} }
}; };

View File

@@ -4,6 +4,7 @@ import {
} from '../libs/errors'; } from '../libs/errors';
import i18n from '../i18n'; import i18n from '../i18n';
import updateStats from '../fns/updateStats'; import updateStats from '../fns/updateStats';
import crit from '../fns/crit';
const MAX_TASK_VALUE = 21.27; const MAX_TASK_VALUE = 21.27;
const MIN_TASK_VALUE = -47.27; const MIN_TASK_VALUE = -47.27;
@@ -105,7 +106,7 @@ function _subtractPoints (user, task, stats, delta) {
function _addPoints (user, task, stats, direction, delta) { function _addPoints (user, task, stats, direction, delta) {
// ===== CRITICAL HITS ===== // ===== CRITICAL HITS =====
// allow critical hit only when checking off a task, not when unchecking it: // allow critical hit only when checking off a task, not when unchecking it:
let _crit = delta > 0 ? user.fns.crit() : 1; let _crit = delta > 0 ? crit(user) : 1;
// if there was a crit, alert the user via notification // if there was a crit, alert the user via notification
if (_crit > 1) user._tmp.crit = _crit; if (_crit > 1) user._tmp.crit = _crit;
@@ -256,5 +257,5 @@ module.exports = function scoreTask (options = {}, req = {}) {
} }
updateStats(user, stats, req); updateStats(user, stats, req);
return delta; return [delta];
}; };

View File

@@ -33,14 +33,12 @@ module.exports = function sell (user, req = {}) {
user.items[type][key]--; user.items[type][key]--;
user.stats.gp += content[type][key].value; user.stats.gp += content[type][key].value;
let response = {
data: _.pick(user, splitWhitespace('stats items')),
message: i18n.t('sold', {type, key}),
};
if (req.v2 === true) { if (req.v2 === true) {
return response.data; return _.pick(user, splitWhitespace('stats items'));
} else { } else {
return response; return [
_.pick(user, splitWhitespace('stats items')),
i18n.t('sold', {type, key}),
];
} }
}; };

View File

@@ -4,10 +4,6 @@ module.exports = function sleep (user, req = {}) {
if (req.v2 === true) { if (req.v2 === true) {
return {}; return {};
} else { } else {
return { return [user.preferences.sleep];
preferences: {
sleep: user.preferences.sleep,
},
};
} }
}; };

View File

@@ -64,7 +64,7 @@ module.exports = function unlock (user, req = {}, analytics) {
_.set(user, `purchased.${pathPart}`, true); _.set(user, `purchased.${pathPart}`, true);
}); });
} else { } else {
if (alreadyOwns) { if (alreadyOwns) { // eslint-disable-line no-lonely-if
let split = path.split('.'); let split = path.split('.');
let value = split.pop(); let value = split.pop();
let key = split.join('.'); let key = split.join('.');
@@ -97,14 +97,14 @@ module.exports = function unlock (user, req = {}, analytics) {
} }
} }
let response = { let response = [
data: _.pick(user, splitWhitespace('purchased preferences items')), _.pick(user, splitWhitespace('purchased preferences items')),
}; ];
if (!alreadyOwns) response.message = i18n.t('unlocked', req.language); if (!alreadyOwns) response.push(i18n.t('unlocked', req.language));
if (req.v2 === true) { if (req.v2 === true) {
return response.data; return response[0];
} else { } else {
return response; return response;
} }

View File

@@ -22,5 +22,5 @@ module.exports = function updateTask (task, req = {}) {
_.merge(task, _.omit(req.body, ['_id', 'id', 'type'])); _.merge(task, _.omit(req.body, ['_id', 'id', 'type']));
return task; return [task];
}; };

View File

@@ -15,6 +15,6 @@ module.exports = function updateWebhook (user, req) {
if (req.v2 === true) { if (req.v2 === true) {
return user.preferences.webhooks; return user.preferences.webhooks;
} else { } else {
return user.preferences.webhooks[req.params.id]; return [user.preferences.webhooks[req.params.id]];
} }
}; };

View File

@@ -1,9 +1,9 @@
import { import {
generateUser, generateUser,
translate as t, translate as t,
} from '../../../../../helpers/api-integration/v3'; } from '../../../../helpers/api-integration/v3';
describe('GET /meta/models/:model/paths', () => { describe('GET /models/:model/paths', () => {
let user; let user;
before(async () => { before(async () => {
@@ -11,7 +11,7 @@ describe('GET /meta/models/:model/paths', () => {
}); });
it('returns an error when model is not accessible or doesn\'t exists', async () => { it('returns an error when model is not accessible or doesn\'t exists', async () => {
await expect(user.get('/meta/models/1234/paths')).to.eventually.be.rejected.and.eql({ await expect(user.get('/models/1234/paths')).to.eventually.be.rejected.and.eql({
code: 400, code: 400,
error: 'BadRequest', error: 'BadRequest',
message: t('invalidReqParams'), message: t('invalidReqParams'),
@@ -21,7 +21,7 @@ describe('GET /meta/models/:model/paths', () => {
let models = ['habit', 'daily', 'todo', 'reward', 'user', 'tag', 'challenge', 'group']; let models = ['habit', 'daily', 'todo', 'reward', 'user', 'tag', 'challenge', 'group'];
models.forEach(model => { models.forEach(model => {
it(`returns the model paths for ${model}`, async () => { it(`returns the model paths for ${model}`, async () => {
let res = await user.get(`/meta/models/${model}/paths`); let res = await user.get(`/models/${model}/paths`);
expect(res._id).to.equal('String'); expect(res._id).to.equal('String');
expect(res).to.not.have.keys('__v'); expect(res).to.not.have.keys('__v');

View File

@@ -36,6 +36,6 @@ describe('POST /user/allocate', () => {
await user.sync(); await user.sync();
expect(user.stats.con).to.equal(1); expect(user.stats.con).to.equal(1);
expect(user.stats.points).to.equal(0); expect(user.stats.points).to.equal(0);
expect(res.stats.con).to.equal(1); expect(res.con).to.equal(1);
}); });
}); });

View File

@@ -18,11 +18,7 @@ describe('POST /user/allocate-now', () => {
let res = await user.post('/user/allocate-now'); let res = await user.post('/user/allocate-now');
await user.sync(); await user.sync();
expect(res).to.eql({ expect(res).to.eql(user.stats);
data: {
stats: user.stats,
},
});
expect(user.stats.points).to.equal(0); expect(user.stats.points).to.equal(0);
expect(user.stats.con).to.equal(9); expect(user.stats.con).to.equal(9);
expect(user.stats.int).to.equal(8); expect(user.stats.int).to.equal(8);

View File

@@ -26,17 +26,26 @@ describe('POST /user/buy/:key', () => {
}); });
}); });
it('buys an item', async () => { it('buys a potion', async () => {
await user.update({
'stats.gp': 400,
});
let potion = content.potion; let potion = content.potion;
let res = await user.post('/user/buy/potion'); let res = await user.post('/user/buy/potion');
await user.sync(); await user.sync();
expect(res.data).to.eql({ expect(user.stats.hp).to.equal(50);
items: JSON.parse(JSON.stringify(user.items)), // otherwise dates can't be compared expect(res.data).to.eql(user.stats);
achievements: user.achievements,
stats: user.stats,
flags: JSON.parse(JSON.stringify(user.flags)), // otherwise dates can't be compared
});
expect(res.message).to.equal(t('messageBought', {itemText: potion.text()})); expect(res.message).to.equal(t('messageBought', {itemText: potion.text()}));
}); });
it('buys a piece of gear', async () => {
let key = 'armor_warrior_1';
await user.post(`/user/buy/${key}`);
await user.sync();
expect(user.items.gear.owned).to.eql({ armor_warrior_1: true }); // eslint-disable-line camelcase
});
}); });

View File

@@ -0,0 +1,44 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
import shared from '../../../../../common/script';
let content = shared.content;
describe('POST /user/buy-armoire', () => {
let user;
beforeEach(async () => {
user = await generateUser({
'stats.hp': 40,
});
});
// More tests in common code unit tests
it('returns an error if user does not have enough gold', async () => {
await expect(user.post('/user/buy-potion'))
.to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('messageNotEnoughGold'),
});
});
xit('buys a piece of armoire', async () => {
await user.update({
'stats.gp': 400,
});
let potion = content.potion;
let res = await user.post('/user/buy-potion');
await user.sync();
expect(user.stats.hp).to.equal(50);
expect(res.data).to.eql({
stats: user.stats,
});
expect(res.message).to.equal(t('messageBought', {itemText: potion.text()}));
});
});

View File

@@ -0,0 +1,34 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
describe('POST /user/buy-gear/:key', () => {
let user;
beforeEach(async () => {
user = await generateUser({
'stats.gp': 400,
});
});
// More tests in common code unit tests
it('returns an error if the item is not found', async () => {
await expect(user.post('/user/buy-gear/notExisting'))
.to.eventually.be.rejected.and.eql({
code: 404,
error: 'NotFound',
message: t('itemNotFound', {key: 'notExisting'}),
});
});
it('buys a piece of gear', async () => {
let key = 'armor_warrior_1';
await user.post(`/user/buy-gear/${key}`);
await user.sync();
expect(user.items.gear.owned).to.eql({ armor_warrior_1: true }); // eslint-disable-line camelcase
});
});

View File

@@ -31,11 +31,7 @@ describe('POST /user/buy-mystery-set/:key', () => {
expect(res.data).to.eql({ expect(res.data).to.eql({
items: JSON.parse(JSON.stringify(user.items)), // otherwise dates can't be compared items: JSON.parse(JSON.stringify(user.items)), // otherwise dates can't be compared
purchased: { purchasedPlanConsecutive: user.purchased.plan.consecutive,
plan: {
consecutive: user.purchased.plan.consecutive,
},
},
}); });
expect(res.message).to.equal(t('hourglassPurchaseSet')); expect(res.message).to.equal(t('hourglassPurchaseSet'));
}); });

View File

@@ -0,0 +1,42 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
import shared from '../../../../../common/script';
let content = shared.content;
describe('POST /user/buy-potion', () => {
let user;
beforeEach(async () => {
user = await generateUser({
'stats.hp': 40,
});
});
// More tests in common code unit tests
it('returns an error if user does not have enough gold', async () => {
await expect(user.post('/user/buy-potion'))
.to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('messageNotEnoughGold'),
});
});
it('buys a potion', async () => {
await user.update({
'stats.gp': 400,
});
let potion = content.potion;
let res = await user.post('/user/buy-potion');
await user.sync();
expect(user.stats.hp).to.equal(50);
expect(res.data).to.eql(user.stats);
expect(res.message).to.equal(t('messageBought', {itemText: potion.text()}));
});
});

View File

@@ -18,13 +18,13 @@ describe('POST /user/change-class', () => {
let res = await user.post('/user/change-class?class=rogue'); let res = await user.post('/user/change-class?class=rogue');
await user.sync(); await user.sync();
expect(res).to.eql({ expect(res).to.eql(JSON.parse(
data: JSON.parse(JSON.stringify({ JSON.stringify({
preferences: user.preferences, preferences: user.preferences,
stats: user.stats, stats: user.stats,
flags: user.flags, flags: user.flags,
items: user.items, items: user.items,
})), })
}); ));
}); });
}); });

View File

@@ -15,12 +15,12 @@ describe('POST /user/disable-classes', () => {
let res = await user.post('/user/disable-classes'); let res = await user.post('/user/disable-classes');
await user.sync(); await user.sync();
expect(res).to.eql({ expect(res).to.eql(JSON.parse(
data: JSON.parse(JSON.stringify({ JSON.stringify({
preferences: user.preferences, preferences: user.preferences,
stats: user.stats, stats: user.stats,
flags: user.flags, flags: user.flags,
})), })
}); ));
}); });
}); });

View File

@@ -35,8 +35,6 @@ describe('POST /user/equip/:type/:key', () => {
let res = await user.post('/user/equip/equipped/weapon_warrior_2'); let res = await user.post('/user/equip/equipped/weapon_warrior_2');
await user.sync(); await user.sync();
expect(res).to.eql({ expect(res).to.eql(JSON.parse(JSON.stringify(user.items)));
data: JSON.parse(JSON.stringify(user.items)),
});
}); });
}); });

View File

@@ -13,16 +13,12 @@ describe('POST /user/sleep', () => {
it('toggles sleep status', async () => { it('toggles sleep status', async () => {
let res = await user.post('/user/sleep'); let res = await user.post('/user/sleep');
expect(res).to.eql({ expect(res).to.eql(true);
preferences: {sleep: true},
});
await user.sync(); await user.sync();
expect(user.preferences.sleep).to.be.true; expect(user.preferences.sleep).to.be.true;
let res2 = await user.post('/user/sleep'); let res2 = await user.post('/user/sleep');
expect(res2).to.eql({ expect(res2).to.eql(false);
preferences: {sleep: false},
});
await user.sync(); await user.sync();
expect(user.preferences.sleep).to.be.false; expect(user.preferences.sleep).to.be.false;
}); });

View File

@@ -16,7 +16,7 @@ describe('POST /user/reset-password', async () => {
let response = await user.post(endpoint, { let response = await user.post(endpoint, {
email: user.auth.local.email, email: user.auth.local.email,
}); });
expect(response).to.eql({ message: t('passwordReset') }); expect(response).to.eql({ data: {}, message: t('passwordReset') });
await user.sync(); await user.sync();
expect(user.auth.local.hashed_password).to.not.eql(previousPassword); expect(user.auth.local.hashed_password).to.not.eql(previousPassword);
}); });
@@ -25,7 +25,7 @@ describe('POST /user/reset-password', async () => {
let response = await user.post(endpoint, { let response = await user.post(endpoint, {
email: 'nonExistent@email.com', email: 'nonExistent@email.com',
}); });
expect(response).to.eql({ message: t('passwordReset') }); expect(response).to.eql({ data: {}, message: t('passwordReset') });
}); });
it('errors if email is not provided', async () => { it('errors if email is not provided', async () => {
@@ -36,4 +36,3 @@ describe('POST /user/reset-password', async () => {
}); });
}); });
}); });

View File

@@ -38,6 +38,7 @@ describe('errorHandler', () => {
expect(res.status).to.be.calledWith(500); expect(res.status).to.be.calledWith(500);
expect(res.json).to.be.calledWith({ expect(res.json).to.be.calledWith({
success: false,
error: 'InternalServerError', error: 'InternalServerError',
message: 'An unexpected error occurred.', message: 'An unexpected error occurred.',
}); });
@@ -54,6 +55,7 @@ describe('errorHandler', () => {
expect(res.status).to.be.calledWith(400); expect(res.status).to.be.calledWith(400);
expect(res.json).to.be.calledWith({ expect(res.json).to.be.calledWith({
success: false,
error: 'Error', error: 'Error',
message: 'Error message', message: 'Error message',
}); });
@@ -70,6 +72,7 @@ describe('errorHandler', () => {
expect(res.status).to.be.calledWith(500); expect(res.status).to.be.calledWith(500);
expect(res.json).to.be.calledWith({ expect(res.json).to.be.calledWith({
success: false,
error: 'InternalServerError', error: 'InternalServerError',
message: 'An unexpected error occurred.', message: 'An unexpected error occurred.',
}); });
@@ -85,6 +88,7 @@ describe('errorHandler', () => {
expect(res.status).to.be.calledWith(400); expect(res.status).to.be.calledWith(400);
expect(res.json).to.be.calledWith({ expect(res.json).to.be.calledWith({
success: false,
error: 'BadRequest', error: 'BadRequest',
message: 'Bad request.', message: 'Bad request.',
}); });
@@ -101,6 +105,7 @@ describe('errorHandler', () => {
expect(res.status).to.be.calledWith(error.statusCode); expect(res.status).to.be.calledWith(error.statusCode);
expect(res.json).to.be.calledWith({ expect(res.json).to.be.calledWith({
success: false,
error: error.name, error: error.name,
message: error.message, message: error.message,
}); });
@@ -116,6 +121,7 @@ describe('errorHandler', () => {
expect(res.status).to.be.calledWith(400); expect(res.status).to.be.calledWith(400);
expect(res.json).to.be.calledWith({ expect(res.json).to.be.calledWith({
success: false,
error: 'BadRequest', error: 'BadRequest',
message: 'Invalid request parameters.', message: 'Invalid request parameters.',
errors: [ errors: [
@@ -143,6 +149,7 @@ describe('errorHandler', () => {
expect(res.status).to.be.calledWith(400); expect(res.status).to.be.calledWith(400);
expect(res.json).to.be.calledWith({ expect(res.json).to.be.calledWith({
success: false,
error: 'BadRequest', error: 'BadRequest',
message: 'User validation failed.', message: 'User validation failed.',
errors: [ errors: [

View File

@@ -30,7 +30,23 @@ describe('response middleware', () => {
expect(res.status).to.be.calledWith(200); expect(res.status).to.be.calledWith(200);
expect(res.json).to.be.calledWith({ expect(res.json).to.be.calledWith({
field: 1, success: true,
data: {field: 1},
});
});
it('can be passed a third parameter to be used as optional message', () => {
responseMiddleware(req, res, next);
res.respond(200, {field: 1}, 'hello');
expect(res.status).to.be.calledOnce;
expect(res.json).to.be.calledOnce;
expect(res.status).to.be.calledWith(200);
expect(res.json).to.be.calledWith({
success: true,
data: {field: 1},
message: 'hello',
}); });
}); });
@@ -43,7 +59,8 @@ describe('response middleware', () => {
expect(res.status).to.be.calledWith(403); expect(res.status).to.be.calledWith(403);
expect(res.json).to.be.calledWith({ expect(res.json).to.be.calledWith({
field: 1, success: false,
data: {field: 1},
}); });
}); });
}); });

View File

@@ -110,7 +110,7 @@ describe('Challenge Model', () => {
}; };
Tasks.Task.sanitize(req.body); Tasks.Task.sanitize(req.body);
_.assign(task, common.ops.updateTask(task.toObject(), req)); _.assign(task, common.ops.updateTask(task.toObject(), req)[0]);
await challenge.updateTask(task); await challenge.updateTask(task);

View File

@@ -0,0 +1,165 @@
// TODO disable until we can find a way to stub predictableRandom
/* eslint-disable */
import randomDrop from '../../../common/script/fns/randomDrop';
import {
generateUser,
generateTodo,
generateHabit,
generateDaily,
generateReward,
} from '../../helpers/common.helper';
// import predictableRandom from '../../../common/script/fns/predictableRandom'; // eslint-disable
import content from '../../../common/script/content/index';
xdescribe('common.fns.randomDrop', () => {
let user;
let task;
let predictableRandom;
beforeEach(() => {
user = generateUser();
user._tmp = user._tmp ? user._tmp : {};
task = generateTodo({ userId: user._id });
predictableRandom = () => {
return 0.5;
};
});
/**
* function signature as follows:
* randomDrop(user, modifiers) {}
* modifiers = { task, delta = null }
**/
it('drops an item for the user.party.quest.progress', () => {
expect(user.party.quest.progress.collect).to.eql({});
user.party.quest.key = 'vice2';
let collectWhat = Object.keys(content.quests[user.party.quest.key].collect)[0]; // lightCrystal
predictableRandom = () => {
return 0.0001;
};
randomDrop(user, { task });
expect(user.party.quest.progress.collect[collectWhat]).to.eql(1);
randomDrop(user, { task });
expect(user.party.quest.progress.collect[collectWhat]).to.eql(2);
});
context('drops enabled', () => {
beforeEach(() => {
user.flags.dropsEnabled = true;
task.priority = 100000;
});
it('does nothing if user.items.lastDrop.count is exceeded', () => {
user.items.lastDrop.count = 100;
randomDrop(user, { task });
expect(user._tmp).to.eql({});
});
it('drops something when the task is a todo', () => {
expect(user._tmp).to.eql({});
user.flags.dropsEnabled = true;
predictableRandom = () => {
return 0.1;
};
randomDrop(user, { task });
expect(user._tmp).to.not.eql({});
});
it('drops something when the task is a habit', () => {
task = generateHabit({ userId: user._id });
expect(user._tmp).to.eql({});
user.flags.dropsEnabled = true;
predictableRandom = () => {
return 0.1;
};
randomDrop(user, { task });
expect(user._tmp).to.not.eql({});
});
it('drops something when the task is a daily', () => {
task = generateDaily({ userId: user._id });
expect(user._tmp).to.eql({});
user.flags.dropsEnabled = true;
predictableRandom = () => {
return 0.1;
};
randomDrop(user, { task });
expect(user._tmp).to.not.eql({});
});
it('drops something when the task is a reward', () => {
task = generateReward({ userId: user._id });
expect(user._tmp).to.eql({});
user.flags.dropsEnabled = true;
predictableRandom = () => {
return 0.1;
};
randomDrop(user, { task });
expect(user._tmp).to.not.eql({});
});
it('drops food', () => {
predictableRandom = () => {
return 0.65;
};
randomDrop(user, { task });
expect(user._tmp.drop.type).to.eql('Food');
});
it('drops eggs', () => {
predictableRandom = () => {
return 0.35;
};
randomDrop(user, { task });
expect(user._tmp.drop.type).to.eql('Egg');
});
context('drops hatching potion', () => {
it('drops a very rare potion', () => {
predictableRandom = () => {
return 0.01;
};
randomDrop(user, { task });
expect(user._tmp.drop.type).to.eql('HatchingPotion');
expect(user._tmp.drop.value).to.eql(5);
expect(user._tmp.drop.key).to.eql('Golden');
});
it('drops a rare potion', () => {
predictableRandom = () => {
return 0.08;
};
randomDrop(user, { task });
expect(user._tmp.drop.type).to.eql('HatchingPotion');
expect(user._tmp.drop.value).to.eql(4);
let acceptableDrops = ['Zombie', 'CottonCandyPink', 'CottonCandyBlue'];
expect(acceptableDrops).to.contain(user._tmp.drop.key); // deterministically 'CottonCandyBlue'
});
it('drops an uncommon potion', () => {
predictableRandom = () => {
return 0.17;
};
randomDrop(user, { task });
expect(user._tmp.drop.type).to.eql('HatchingPotion');
expect(user._tmp.drop.value).to.eql(3);
let acceptableDrops = ['Red', 'Shade', 'Skeleton'];
expect(acceptableDrops).to.contain(user._tmp.drop.key); // always skeleton
});
it('drops a common potion', () => {
predictableRandom = () => {
return 0.20;
};
randomDrop(user, { task });
expect(user._tmp.drop.type).to.eql('HatchingPotion');
expect(user._tmp.drop.value).to.eql(2);
let acceptableDrops = ['Base', 'White', 'Desert'];
expect(acceptableDrops).to.contain(user._tmp.drop.key); // always Desert
});
});
});
});

View File

@@ -39,9 +39,9 @@ describe('shared.ops.addPushDevice', () => {
}); });
it('adds a push device', () => { it('adds a push device', () => {
let response = addPushDevice(user, {body: {regId, type}}); let [, message] = addPushDevice(user, {body: {regId, type}});
expect(response.message).to.equal(i18n.t('pushDeviceAdded')); expect(message).to.equal(i18n.t('pushDeviceAdded'));
expect(user.pushDevices[0].type).to.equal(type); expect(user.pushDevices[0].type).to.equal(type);
expect(user.pushDevices[0].regId).to.equal(regId); expect(user.pushDevices[0].regId).to.equal(regId);
}); });

View File

@@ -18,17 +18,13 @@ describe('shared.ops.allocateNow', () => {
user.stats.str = 9; user.stats.str = 9;
user.preferences.allocationMode = 'flat'; user.preferences.allocationMode = 'flat';
let res = allocateNow(user); let [data] = allocateNow(user);
expect(user.stats.points).to.equal(0); expect(user.stats.points).to.equal(0);
expect(user.stats.con).to.equal(9); expect(user.stats.con).to.equal(9);
expect(user.stats.int).to.equal(8); expect(user.stats.int).to.equal(8);
expect(user.stats.per).to.equal(9); expect(user.stats.per).to.equal(9);
expect(user.stats.str).to.equal(9); expect(user.stats.str).to.equal(9);
expect(res).to.eql({ expect(data).to.eql(user.stats);
data: {
stats: user.stats,
},
});
}); });
}); });

View File

@@ -26,10 +26,10 @@ describe('shared.ops.blockUser', () => {
}); });
it('blocks user', () => { it('blocks user', () => {
let result = blockUser(user, { params: { uuid: blockedUser._id } }); let [result] = blockUser(user, { params: { uuid: blockedUser._id } });
expect(user.inbox.blocks).to.eql([blockedUser._id]); expect(user.inbox.blocks).to.eql([blockedUser._id]);
expect(result).to.eql([blockedUser._id]); expect(result).to.eql([blockedUser._id]);
result = blockUser(user, { params: { uuid: blockedUser2._id } }); [result] = blockUser(user, { params: { uuid: blockedUser2._id } });
expect(user.inbox.blocks).to.eql([blockedUser._id, blockedUser2._id]); expect(user.inbox.blocks).to.eql([blockedUser._id, blockedUser2._id]);
expect(result).to.eql([blockedUser._id, blockedUser2._id]); expect(result).to.eql([blockedUser._id, blockedUser2._id]);
}); });
@@ -37,7 +37,7 @@ describe('shared.ops.blockUser', () => {
it('blocks, then unblocks user', () => { it('blocks, then unblocks user', () => {
blockUser(user, { params: { uuid: blockedUser._id } }); blockUser(user, { params: { uuid: blockedUser._id } });
expect(user.inbox.blocks).to.eql([blockedUser._id]); expect(user.inbox.blocks).to.eql([blockedUser._id]);
let result = blockUser(user, { params: { uuid: blockedUser._id } }); let [result] = blockUser(user, { params: { uuid: blockedUser._id } });
expect(user.inbox.blocks).to.eql([]); expect(user.inbox.blocks).to.eql([]);
expect(result).to.eql([]); expect(result).to.eql([]);
}); });

View File

@@ -1,15 +1,10 @@
/* eslint-disable camelcase */ /* eslint-disable camelcase */
import sinon from 'sinon'; // eslint-disable-line no-shadow
import { import {
generateUser, generateUser,
} from '../../helpers/common.helper'; } from '../../helpers/common.helper';
import count from '../../../common/script/count';
import buy from '../../../common/script/ops/buy'; import buy from '../../../common/script/ops/buy';
import shared from '../../../common/script';
import content from '../../../common/script/content/index';
import { import {
NotAuthorized, BadRequest,
} from '../../../common/script/libs/errors'; } from '../../../common/script/libs/errors';
import i18n from '../../../common/script/i18n'; import i18n from '../../../common/script/i18n';
@@ -30,277 +25,27 @@ describe('shared.ops.buy', () => {
}, },
stats: { gp: 200 }, stats: { gp: 200 },
}); });
sinon.stub(shared.fns, 'randomVal');
sinon.stub(shared.fns, 'predictableRandom');
}); });
afterEach(() => { it('returns error when key is not provided', (done) => {
shared.fns.randomVal.restore(); try {
shared.fns.predictableRandom.restore(); buy(user);
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('missingKeyParam'));
done();
}
}); });
context('Potion', () => {
it('recovers 15 hp', () => { it('recovers 15 hp', () => {
user.stats.hp = 30; user.stats.hp = 30;
buy(user, {params: {key: 'potion'}}); buy(user, {params: {key: 'potion'}});
expect(user.stats.hp).to.eql(45); expect(user.stats.hp).to.eql(45);
}); });
it('does not increase hp above 50', () => {
user.stats.hp = 45;
buy(user, {params: {key: 'potion'}});
expect(user.stats.hp).to.eql(50);
});
it('deducts 25 gp', () => {
user.stats.hp = 45;
buy(user, {params: {key: 'potion'}});
expect(user.stats.gp).to.eql(175);
});
it('does not purchase if not enough gp', (done) => {
user.stats.hp = 45;
user.stats.gp = 5;
try {
buy(user, {params: {key: 'potion'}});
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageNotEnoughGold'));
expect(user.stats.hp).to.eql(45);
expect(user.stats.gp).to.eql(5);
done();
}
});
});
context('Gear', () => {
it('adds equipment to inventory', () => { it('adds equipment to inventory', () => {
user.stats.gp = 31; user.stats.gp = 31;
buy(user, {params: {key: 'armor_warrior_1'}}); buy(user, {params: {key: 'armor_warrior_1'}});
expect(user.items.gear.owned).to.eql({ weapon_warrior_0: true, armor_warrior_1: true }); expect(user.items.gear.owned).to.eql({ weapon_warrior_0: true, armor_warrior_1: true });
}); });
it('deducts gold from user', () => {
user.stats.gp = 31;
buy(user, {params: {key: 'armor_warrior_1'}});
expect(user.stats.gp).to.eql(1);
});
it('auto equips equipment if user has auto-equip preference turned on', () => {
user.stats.gp = 31;
user.preferences.autoEquip = true;
buy(user, {params: {key: 'armor_warrior_1'}});
expect(user.items.gear.equipped).to.have.property('armor', 'armor_warrior_1');
});
it('buys equipment but does not auto-equip', () => {
user.stats.gp = 31;
user.preferences.autoEquip = false;
buy(user, {params: {key: 'armor_warrior_1'}});
expect(user.items.gear.equipped.property).to.not.equal('armor_warrior_1');
});
// TODO after user.ops.equip is done
xit('removes one-handed weapon and shield if auto-equip is on and a two-hander is bought', () => {
user.stats.gp = 100;
user.preferences.autoEquip = true;
buy(user, {params: {key: 'shield_warrior_1'}});
user.ops.equip({params: {key: 'shield_warrior_1'}});
buy(user, {params: {key: 'weapon_warrior_1'}});
user.ops.equip({params: {key: 'weapon_warrior_1'}});
buy(user, {params: {key: 'weapon_wizard_1'}});
expect(user.items.gear.equipped).to.have.property('shield', 'shield_base_0');
expect(user.items.gear.equipped).to.have.property('weapon', 'weapon_wizard_1');
});
// TODO after user.ops.equip is done
xit('buys two-handed equipment but does not automatically remove sword or shield', () => {
user.stats.gp = 100;
user.preferences.autoEquip = false;
buy(user, {params: {key: 'shield_warrior_1'}});
user.ops.equip({params: {key: 'shield_warrior_1'}});
buy(user, {params: {key: 'weapon_warrior_1'}});
user.ops.equip({params: {key: 'weapon_warrior_1'}});
buy(user, {params: {key: 'weapon_wizard_1'}});
expect(user.items.gear.equipped).to.have.property('shield', 'shield_warrior_1');
expect(user.items.gear.equipped).to.have.property('weapon', 'weapon_warrior_1');
});
it('does not buy equipment without enough Gold', (done) => {
user.stats.gp = 20;
try {
buy(user, {params: {key: 'armor_warrior_1'}});
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageNotEnoughGold'));
expect(user.items.gear.owned).to.not.have.property('armor_warrior_1');
done();
}
});
});
context('Enchanted Armoire', () => {
let YIELD_EQUIPMENT = 0.5;
let YIELD_FOOD = 0.7;
let YIELD_EXP = 0.9;
let fullArmoire = {};
_(content.gearTypes).each((type) => {
_(content.gear.tree[type].armoire).each((gearObject) => {
let armoireKey = gearObject.key;
fullArmoire[armoireKey] = true;
}).value();
}).value();
beforeEach(() => {
user.achievements.ultimateGearSets = { rogue: true };
user.flags.armoireOpened = true;
user.stats.exp = 0;
user.items.food = {};
});
context('failure conditions', () => {
it('does not open if user does not have enough gold', (done) => {
shared.fns.predictableRandom.returns(YIELD_EQUIPMENT);
user.stats.gp = 50;
try {
buy(user, {params: {key: 'armoire'}});
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageNotEnoughGold'));
expect(user.items.gear.owned).to.eql({weapon_warrior_0: true});
expect(user.items.food).to.be.empty;
expect(user.stats.exp).to.eql(0);
done();
}
});
it('does not open without Ultimate Gear achievement', (done) => {
shared.fns.predictableRandom.returns(YIELD_EQUIPMENT);
user.achievements.ultimateGearSets = {healer: false, wizard: false, rogue: false, warrior: false};
try {
buy(user, {params: {key: 'armoire'}});
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('cannoyBuyItem'));
expect(user.items.gear.owned).to.eql({weapon_warrior_0: true});
expect(user.items.food).to.be.empty;
expect(user.stats.exp).to.eql(0);
done();
}
});
});
context('non-gear awards', () => {
// Skipped because can't stub predictableRandom correctly
xit('gives Experience', () => {
shared.fns.predictableRandom.returns(YIELD_EXP);
buy(user, {params: {key: 'armoire'}});
expect(user.items.gear.owned).to.eql({weapon_warrior_0: true});
expect(user.items.food).to.be.empty;
expect(user.stats.exp).to.eql(46);
expect(user.stats.gp).to.eql(100);
});
// Skipped because can't stub predictableRandom correctly
xit('gives food', () => {
let honey = content.food.Honey;
shared.fns.randomVal.returns(honey);
shared.fns.predictableRandom.returns(YIELD_FOOD);
buy(user, {params: {key: 'armoire'}});
expect(user.items.gear.owned).to.eql({weapon_warrior_0: true});
expect(user.items.food).to.eql({Honey: 1});
expect(user.stats.exp).to.eql(0);
expect(user.stats.gp).to.eql(100);
});
// Skipped because can't stub predictableRandom correctly
xit('does not give equipment if all equipment has been found', () => {
shared.fns.predictableRandom.returns(YIELD_EQUIPMENT);
user.items.gear.owned = fullArmoire;
user.stats.gp = 150;
buy(user, {params: {key: 'armoire'}});
expect(user.items.gear.owned).to.eql(fullArmoire);
let armoireCount = count.remainingGearInSet(user.items.gear.owned, 'armoire');
expect(armoireCount).to.eql(0);
expect(user.stats.exp).to.eql(30);
expect(user.stats.gp).to.eql(50);
});
});
context('gear awards', () => {
beforeEach(() => {
let shield = content.gear.tree.shield.armoire.gladiatorShield;
shared.fns.randomVal.returns(shield);
});
// Skipped because can't stub predictableRandom correctly
xit('always drops equipment the first time', () => {
delete user.flags.armoireOpened;
shared.fns.predictableRandom.returns(YIELD_EXP);
buy(user, {params: {key: 'armoire'}});
expect(user.items.gear.owned).to.eql({
weapon_warrior_0: true,
shield_armoire_gladiatorShield: true,
});
let armoireCount = count.remainingGearInSet(user.items.gear.owned, 'armoire');
expect(armoireCount).to.eql(_.size(fullArmoire) - 1);
expect(user.items.food).to.be.empty;
expect(user.stats.exp).to.eql(0);
expect(user.stats.gp).to.eql(100);
});
// Skipped because can't stub predictableRandom correctly
xit('gives more equipment', () => {
shared.fns.predictableRandom.returns(YIELD_EQUIPMENT);
user.items.gear.owned = {
weapon_warrior_0: true,
head_armoire_hornedIronHelm: true,
};
user.stats.gp = 200;
buy(user, {params: {key: 'armoire'}});
expect(user.items.gear.owned).to.eql({weapon_warrior_0: true, shield_armoire_gladiatorShield: true, head_armoire_hornedIronHelm: true});
let armoireCount = count.remainingGearInSet(user.items.gear.owned, 'armoire');
expect(armoireCount).to.eql(_.size(fullArmoire) - 2);
expect(user.stats.gp).to.eql(100);
});
});
});
}); });

View File

@@ -0,0 +1,187 @@
/* eslint-disable camelcase */
import sinon from 'sinon'; // eslint-disable-line no-shadow
import {
generateUser,
} from '../../helpers/common.helper';
import count from '../../../common/script/count';
import buyArmoire from '../../../common/script/ops/buyArmoire';
import shared from '../../../common/script';
import content from '../../../common/script/content/index';
import {
NotAuthorized,
} from '../../../common/script/libs/errors';
import i18n from '../../../common/script/i18n';
describe('shared.ops.buyArmoire', () => {
let user;
let YIELD_EQUIPMENT = 0.5;
let YIELD_FOOD = 0.7;
let YIELD_EXP = 0.9;
let fullArmoire = {};
_(content.gearTypes).each((type) => {
_(content.gear.tree[type].armoire).each((gearObject) => {
let armoireKey = gearObject.key;
fullArmoire[armoireKey] = true;
}).value();
}).value();
beforeEach(() => {
user = generateUser({
items: {
gear: {
owned: {
weapon_warrior_0: true,
},
equipped: {
weapon_warrior_0: true,
},
},
},
stats: { gp: 200 },
});
user.achievements.ultimateGearSets = { rogue: true };
user.flags.armoireOpened = true;
user.stats.exp = 0;
user.items.food = {};
sinon.stub(shared.fns, 'randomVal');
sinon.stub(shared.fns, 'predictableRandom');
});
afterEach(() => {
shared.fns.randomVal.restore();
shared.fns.predictableRandom.restore();
});
context('failure conditions', () => {
it('does not open if user does not have enough gold', (done) => {
shared.fns.predictableRandom.returns(YIELD_EQUIPMENT);
user.stats.gp = 50;
try {
buyArmoire(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageNotEnoughGold'));
expect(user.items.gear.owned).to.eql({weapon_warrior_0: true});
expect(user.items.food).to.be.empty;
expect(user.stats.exp).to.eql(0);
done();
}
});
it('does not open without Ultimate Gear achievement', (done) => {
shared.fns.predictableRandom.returns(YIELD_EQUIPMENT);
user.achievements.ultimateGearSets = {healer: false, wizard: false, rogue: false, warrior: false};
try {
buyArmoire(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('cannotBuyItem'));
expect(user.items.gear.owned).to.eql({weapon_warrior_0: true});
expect(user.items.food).to.be.empty;
expect(user.stats.exp).to.eql(0);
done();
}
});
});
context('non-gear awards', () => {
// Skipped because can't stub predictableRandom correctly
xit('gives Experience', () => {
shared.fns.predictableRandom.returns(YIELD_EXP);
buyArmoire(user);
expect(user.items.gear.owned).to.eql({weapon_warrior_0: true});
expect(user.items.food).to.be.empty;
expect(user.stats.exp).to.eql(46);
expect(user.stats.gp).to.eql(100);
});
// Skipped because can't stub predictableRandom correctly
xit('gives food', () => {
let honey = content.food.Honey;
shared.fns.randomVal.returns(honey);
shared.fns.predictableRandom.returns(YIELD_FOOD);
buyArmoire(user);
expect(user.items.gear.owned).to.eql({weapon_warrior_0: true});
expect(user.items.food).to.eql({Honey: 1});
expect(user.stats.exp).to.eql(0);
expect(user.stats.gp).to.eql(100);
});
// Skipped because can't stub predictableRandom correctly
xit('does not give equipment if all equipment has been found', () => {
shared.fns.predictableRandom.returns(YIELD_EQUIPMENT);
user.items.gear.owned = fullArmoire;
user.stats.gp = 150;
buyArmoire(user);
expect(user.items.gear.owned).to.eql(fullArmoire);
let armoireCount = count.remainingGearInSet(user.items.gear.owned, 'armoire');
expect(armoireCount).to.eql(0);
expect(user.stats.exp).to.eql(30);
expect(user.stats.gp).to.eql(50);
});
});
context('gear awards', () => {
beforeEach(() => {
let shield = content.gear.tree.shield.armoire.gladiatorShield;
shared.fns.randomVal.returns(shield);
});
// Skipped because can't stub predictableRandom correctly
xit('always drops equipment the first time', () => {
delete user.flags.armoireOpened;
shared.fns.predictableRandom.returns(YIELD_EXP);
buyArmoire(user);
expect(user.items.gear.owned).to.eql({
weapon_warrior_0: true,
shield_armoire_gladiatorShield: true,
});
let armoireCount = count.remainingGearInSet(user.items.gear.owned, 'armoire');
expect(armoireCount).to.eql(_.size(fullArmoire) - 1);
expect(user.items.food).to.be.empty;
expect(user.stats.exp).to.eql(0);
expect(user.stats.gp).to.eql(100);
});
// Skipped because can't stub predictableRandom correctly
xit('gives more equipment', () => {
shared.fns.predictableRandom.returns(YIELD_EQUIPMENT);
user.items.gear.owned = {
weapon_warrior_0: true,
head_armoire_hornedIronHelm: true,
};
user.stats.gp = 200;
buyArmoire(user);
expect(user.items.gear.owned).to.eql({weapon_warrior_0: true, shield_armoire_gladiatorShield: true, head_armoire_hornedIronHelm: true});
let armoireCount = count.remainingGearInSet(user.items.gear.owned, 'armoire');
expect(armoireCount).to.eql(_.size(fullArmoire) - 2);
expect(user.stats.gp).to.eql(100);
});
});
});

132
test/common/ops/buyGear.js Normal file
View File

@@ -0,0 +1,132 @@
/* eslint-disable camelcase */
import sinon from 'sinon'; // eslint-disable-line no-shadow
import {
generateUser,
} from '../../helpers/common.helper';
import buyGear from '../../../common/script/ops/buyGear';
import shared from '../../../common/script';
import {
NotAuthorized,
} from '../../../common/script/libs/errors';
import i18n from '../../../common/script/i18n';
describe('shared.ops.buyGear', () => {
let user;
beforeEach(() => {
user = generateUser({
items: {
gear: {
owned: {
weapon_warrior_0: true,
},
equipped: {
weapon_warrior_0: true,
},
},
},
stats: { gp: 200 },
});
sinon.stub(shared.fns, 'randomVal');
sinon.stub(shared.fns, 'predictableRandom');
});
afterEach(() => {
shared.fns.randomVal.restore();
shared.fns.predictableRandom.restore();
});
context('Gear', () => {
it('adds equipment to inventory', () => {
user.stats.gp = 31;
buyGear(user, {params: {key: 'armor_warrior_1'}});
expect(user.items.gear.owned).to.eql({ weapon_warrior_0: true, armor_warrior_1: true });
});
it('deducts gold from user', () => {
user.stats.gp = 31;
buyGear(user, {params: {key: 'armor_warrior_1'}});
expect(user.stats.gp).to.eql(1);
});
it('auto equips equipment if user has auto-equip preference turned on', () => {
user.stats.gp = 31;
user.preferences.autoEquip = true;
buyGear(user, {params: {key: 'armor_warrior_1'}});
expect(user.items.gear.equipped).to.have.property('armor', 'armor_warrior_1');
});
it('buyGears equipment but does not auto-equip', () => {
user.stats.gp = 31;
user.preferences.autoEquip = false;
buyGear(user, {params: {key: 'armor_warrior_1'}});
expect(user.items.gear.equipped.property).to.not.equal('armor_warrior_1');
});
it('does not buyGear equipment twice', (done) => {
user.stats.gp = 62;
buyGear(user, {params: {key: 'armor_warrior_1'}});
try {
buyGear(user, {params: {key: 'armor_warrior_1'}});
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('equipmentAlreadyOwned'));
done();
}
});
// TODO after user.ops.equip is done
xit('removes one-handed weapon and shield if auto-equip is on and a two-hander is bought', () => {
user.stats.gp = 100;
user.preferences.autoEquip = true;
buyGear(user, {params: {key: 'shield_warrior_1'}});
user.ops.equip({params: {key: 'shield_warrior_1'}});
buyGear(user, {params: {key: 'weapon_warrior_1'}});
user.ops.equip({params: {key: 'weapon_warrior_1'}});
buyGear(user, {params: {key: 'weapon_wizard_1'}});
expect(user.items.gear.equipped).to.have.property('shield', 'shield_base_0');
expect(user.items.gear.equipped).to.have.property('weapon', 'weapon_wizard_1');
});
// TODO after user.ops.equip is done
xit('buyGears two-handed equipment but does not automatically remove sword or shield', () => {
user.stats.gp = 100;
user.preferences.autoEquip = false;
buyGear(user, {params: {key: 'shield_warrior_1'}});
user.ops.equip({params: {key: 'shield_warrior_1'}});
buyGear(user, {params: {key: 'weapon_warrior_1'}});
user.ops.equip({params: {key: 'weapon_warrior_1'}});
buyGear(user, {params: {key: 'weapon_wizard_1'}});
expect(user.items.gear.equipped).to.have.property('shield', 'shield_warrior_1');
expect(user.items.gear.equipped).to.have.property('weapon', 'weapon_warrior_1');
});
it('does not buyGear equipment without enough Gold', (done) => {
user.stats.gp = 20;
try {
buyGear(user, {params: {key: 'armor_warrior_1'}});
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageNotEnoughGold'));
expect(user.items.gear.owned).to.not.have.property('armor_warrior_1');
done();
}
});
});
});

View File

@@ -0,0 +1,65 @@
/* eslint-disable camelcase */
import {
generateUser,
} from '../../helpers/common.helper';
import buyPotion from '../../../common/script/ops/buyPotion';
import {
NotAuthorized,
} from '../../../common/script/libs/errors';
import i18n from '../../../common/script/i18n';
describe('shared.ops.buyPotion', () => {
let user;
beforeEach(() => {
user = generateUser({
items: {
gear: {
owned: {
weapon_warrior_0: true,
},
equipped: {
weapon_warrior_0: true,
},
},
},
stats: { gp: 200 },
});
});
context('Potion', () => {
it('recovers 15 hp', () => {
user.stats.hp = 30;
buyPotion(user);
expect(user.stats.hp).to.eql(45);
});
it('does not increase hp above 50', () => {
user.stats.hp = 45;
buyPotion(user);
expect(user.stats.hp).to.eql(50);
});
it('deducts 25 gp', () => {
user.stats.hp = 45;
buyPotion(user);
expect(user.stats.gp).to.eql(175);
});
it('does not purchase if not enough gp', (done) => {
user.stats.hp = 45;
user.stats.gp = 5;
try {
buyPotion(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageNotEnoughGold'));
expect(user.stats.hp).to.eql(45);
expect(user.stats.gp).to.eql(5);
done();
}
});
});
});

View File

@@ -60,7 +60,7 @@ describe('shared.ops.buySpecialSpell', () => {
user.stats.gp = 11; user.stats.gp = 11;
let item = content.special.thankyou; let item = content.special.thankyou;
let res = buySpecialSpell(user, { let [data, message] = buySpecialSpell(user, {
params: { params: {
key: 'thankyou', key: 'thankyou',
}, },
@@ -68,11 +68,11 @@ describe('shared.ops.buySpecialSpell', () => {
expect(user.stats.gp).to.equal(1); expect(user.stats.gp).to.equal(1);
expect(user.items.special.thankyou).to.equal(1); expect(user.items.special.thankyou).to.equal(1);
expect(res.data).to.eql({ expect(data).to.eql({
items: user.items, items: user.items,
stats: user.stats, stats: user.stats,
}); });
expect(res.message).to.equal(i18n.t('messageBought', { expect(message).to.equal(i18n.t('messageBought', {
itemText: item.text(), itemText: item.text(),
})); }));
}); });

View File

@@ -46,14 +46,12 @@ describe('shared.ops.changeClass', () => {
user.stats.class = 'healer'; user.stats.class = 'healer';
user.items.gear.owned.armor_rogue_1 = true; // eslint-disable-line camelcase user.items.gear.owned.armor_rogue_1 = true; // eslint-disable-line camelcase
let res = changeClass(user, {query: {class: 'rogue'}}); let [data] = changeClass(user, {query: {class: 'rogue'}});
expect(res).to.eql({ expect(data).to.eql({
data: {
preferences: user.preferences, preferences: user.preferences,
stats: user.stats, stats: user.stats,
flags: user.flags, flags: user.flags,
items: user.items, items: user.items,
},
}); });
expect(user.stats.class).to.equal('rogue'); expect(user.stats.class).to.equal('rogue');
@@ -80,14 +78,12 @@ describe('shared.ops.changeClass', () => {
user.stats.int = 4; user.stats.int = 4;
user.flags.classSelected = true; user.flags.classSelected = true;
let res = changeClass(user); let [data] = changeClass(user);
expect(res).to.eql({ expect(data).to.eql({
data: {
preferences: user.preferences, preferences: user.preferences,
stats: user.stats, stats: user.stats,
flags: user.flags, flags: user.flags,
items: user.items, items: user.items,
},
}); });
expect(user.preferences.disableClasses).to.be.false; expect(user.preferences.disableClasses).to.be.false;
@@ -122,14 +118,12 @@ describe('shared.ops.changeClass', () => {
user.stats.int = 4; user.stats.int = 4;
user.flags.classSelected = true; user.flags.classSelected = true;
let res = changeClass(user); let [data] = changeClass(user);
expect(res).to.eql({ expect(data).to.eql({
data: {
preferences: user.preferences, preferences: user.preferences,
stats: user.stats, stats: user.stats,
flags: user.flags, flags: user.flags,
items: user.items, items: user.items,
},
}); });
expect(user.balance).to.equal(0.25); expect(user.balance).to.equal(0.25);

View File

@@ -13,7 +13,7 @@ describe('shared.ops.clearPMs', () => {
it('clears messages', () => { it('clears messages', () => {
expect(user.inbox.messages).to.not.eql({}); expect(user.inbox.messages).to.not.eql({});
let result = clearPMs(user); let [result] = clearPMs(user);
expect(user.inbox.messages).to.eql({}); expect(user.inbox.messages).to.eql({});
expect(result).to.eql({}); expect(result).to.eql({});
}); });

View File

@@ -3,7 +3,7 @@ import {
generateUser, generateUser,
} from '../../helpers/common.helper'; } from '../../helpers/common.helper';
describe('shared.ops.clearPMs', () => { describe('shared.ops.deletePM', () => {
let user; let user;
beforeEach(() => { beforeEach(() => {
@@ -13,7 +13,7 @@ describe('shared.ops.clearPMs', () => {
it('delete message', () => { it('delete message', () => {
expect(user.inbox.messages).to.not.eql({ second: 'message' }); expect(user.inbox.messages).to.not.eql({ second: 'message' });
let response = deletePM(user, { params: { id: 'first' } }); let [response] = deletePM(user, { params: { id: 'first' } });
expect(user.inbox.messages).to.eql({ second: 'message' }); expect(user.inbox.messages).to.eql({ second: 'message' });
expect(response).to.eql({ second: 'message' }); expect(response).to.eql({ second: 'message' });
}); });

View File

@@ -14,8 +14,8 @@ describe('shared.ops.deleteWebhook', () => {
it('succeeds', () => { it('succeeds', () => {
user.preferences.webhooks = { 'some-id': {}, 'another-id': {} }; user.preferences.webhooks = { 'some-id': {}, 'another-id': {} };
let res = deleteWebhook(user, req); let [data] = deleteWebhook(user, req);
expect(user.preferences.webhooks).to.eql({'another-id': {}}); expect(user.preferences.webhooks).to.eql({'another-id': {}});
expect(res).to.equal(user.preferences.webhooks); expect(data).to.equal(user.preferences.webhooks);
}); });
}); });

View File

@@ -18,13 +18,11 @@ describe('shared.ops.disableClasses', () => {
user.preferences.autoAllocate = false; user.preferences.autoAllocate = false;
user.stats.points = 2; user.stats.points = 2;
let res = disableClasses(user); let [data] = disableClasses(user);
expect(res).to.eql({ expect(data).to.eql({
data: {
preferences: user.preferences, preferences: user.preferences,
stats: user.stats, stats: user.stats,
flags: user.flags, flags: user.flags,
},
}); });
expect(user.stats.class).to.equal('warrior'); expect(user.stats.class).to.equal('warrior');

View File

@@ -37,20 +37,20 @@ describe('shared.ops.equip', () => {
equip(user, {params: {key: 'weapon_warrior_1'}}); equip(user, {params: {key: 'weapon_warrior_1'}});
// one-handed to one-handed // one-handed to one-handed
let res = equip(user, {params: {key: 'weapon_warrior_2'}}); let [, message] = equip(user, {params: {key: 'weapon_warrior_2'}});
expect(res.message).to.not.exists; expect(message).to.not.exists;
// one-handed to two-handed // one-handed to two-handed
res = equip(user, {params: {key: 'weapon_wizard_1'}}); [, message] = equip(user, {params: {key: 'weapon_wizard_1'}});
expect(res.message).to.not.exists; expect(message).to.not.exists;
// two-handed to two-handed // two-handed to two-handed
res = equip(user, {params: {key: 'weapon_wizard_2'}}); [, message] = equip(user, {params: {key: 'weapon_wizard_2'}});
expect(res.message).to.not.exists; expect(message).to.not.exists;
// two-handed to one-handed // two-handed to one-handed
res = equip(user, {params: {key: 'weapon_warrior_2'}}); [, message] = equip(user, {params: {key: 'weapon_warrior_2'}});
expect(res.message).to.not.exists; expect(message).to.not.exists;
}); });
it('should send messages if equipping a two-hander causes the off-hander to be unequipped', () => { it('should send messages if equipping a two-hander causes the off-hander to be unequipped', () => {
@@ -58,10 +58,11 @@ describe('shared.ops.equip', () => {
equip(user, {params: {key: 'shield_warrior_1'}}); equip(user, {params: {key: 'shield_warrior_1'}});
// equipping two-hander // equipping two-hander
let res = equip(user, {params: {key: 'weapon_wizard_1'}}); let [data, message] = equip(user, {params: {key: 'weapon_wizard_1'}});
let weapon = content.gear.flat.weapon_wizard_1; let weapon = content.gear.flat.weapon_wizard_1;
let item = content.gear.flat.shield_warrior_1; let item = content.gear.flat.shield_warrior_1;
let res = {data, message};
expect(res).to.eql({ expect(res).to.eql({
message: i18n.t('messageTwoHandedEquip', {twoHandedText: weapon.text(), offHandedText: item.text()}), message: i18n.t('messageTwoHandedEquip', {twoHandedText: weapon.text(), offHandedText: item.text()}),
data: user.items, data: user.items,
@@ -74,8 +75,9 @@ describe('shared.ops.equip', () => {
let weapon = content.gear.flat.weapon_wizard_1; let weapon = content.gear.flat.weapon_wizard_1;
let shield = content.gear.flat.shield_warrior_1; let shield = content.gear.flat.shield_warrior_1;
let res = equip(user, {params: {key: 'shield_warrior_1'}}); let [data, message] = equip(user, {params: {key: 'shield_warrior_1'}});
let res = {data, message};
expect(res).to.eql({ expect(res).to.eql({
message: i18n.t('messageTwoHandedUnequip', {twoHandedText: weapon.text(), offHandedText: shield.text()}), message: i18n.t('messageTwoHandedUnequip', {twoHandedText: weapon.text(), offHandedText: shield.text()}),
data: user.items, data: user.items,

View File

@@ -105,16 +105,14 @@ describe('shared.ops.feed', () => {
let potionText = content.hatchingPotions[potion] ? content.hatchingPotions[potion].text() : potion; let potionText = content.hatchingPotions[potion] ? content.hatchingPotions[potion].text() : potion;
let eggText = content.eggs[egg] ? content.eggs[egg].text() : egg; let eggText = content.eggs[egg] ? content.eggs[egg].text() : egg;
let res = feed(user, {params: {pet: 'Wolf-Base', food: 'Saddle'}}); let [data, message] = feed(user, {params: {pet: 'Wolf-Base', food: 'Saddle'}});
expect(res).to.eql({ expect(data).to.eql(user.items.pets['Wolf-Base']);
data: user.items.pets['Wolf-Base'], expect(message).to.eql(i18n.t('messageEvolve', {
message: i18n.t('messageEvolve', {
egg: i18n.t('petName', { egg: i18n.t('petName', {
potion: potionText, potion: potionText,
egg: eggText, egg: eggText,
}), }),
}), }));
});
expect(user.items.food.Saddle).to.equal(1); expect(user.items.food.Saddle).to.equal(1);
expect(user.items.pets['Wolf-Base']).to.equal(-1); expect(user.items.pets['Wolf-Base']).to.equal(-1);
@@ -131,17 +129,15 @@ describe('shared.ops.feed', () => {
let potionText = content.hatchingPotions[potion] ? content.hatchingPotions[potion].text() : potion; let potionText = content.hatchingPotions[potion] ? content.hatchingPotions[potion].text() : potion;
let eggText = content.eggs[egg] ? content.eggs[egg].text() : egg; let eggText = content.eggs[egg] ? content.eggs[egg].text() : egg;
let res = feed(user, {params: {pet: 'Wolf-Base', food: 'Meat'}}); let [data, message] = feed(user, {params: {pet: 'Wolf-Base', food: 'Meat'}});
expect(res).to.eql({ expect(data).to.eql(user.items.pets['Wolf-Base']);
data: user.items.pets['Wolf-Base'], expect(message).to.eql(i18n.t('messageLikesFood', {
message: i18n.t('messageLikesFood', {
egg: i18n.t('petName', { egg: i18n.t('petName', {
potion: potionText, potion: potionText,
egg: eggText, egg: eggText,
}), }),
foodText: food.text(), foodText: food.text(),
}), }));
});
expect(user.items.food.Meat).to.equal(1); expect(user.items.food.Meat).to.equal(1);
expect(user.items.pets['Wolf-Base']).to.equal(10); expect(user.items.pets['Wolf-Base']).to.equal(10);
@@ -156,17 +152,15 @@ describe('shared.ops.feed', () => {
let potionText = content.hatchingPotions[potion] ? content.hatchingPotions[potion].text() : potion; let potionText = content.hatchingPotions[potion] ? content.hatchingPotions[potion].text() : potion;
let eggText = content.eggs[egg] ? content.eggs[egg].text() : egg; let eggText = content.eggs[egg] ? content.eggs[egg].text() : egg;
let res = feed(user, {params: {pet: 'Wolf-Spooky', food: 'Milk'}}); let [data, message] = feed(user, {params: {pet: 'Wolf-Spooky', food: 'Milk'}});
expect(res).to.eql({ expect(data).to.eql(user.items.pets['Wolf-Spooky']);
data: user.items.pets['Wolf-Spooky'], expect(message).to.eql(i18n.t('messageLikesFood', {
message: i18n.t('messageLikesFood', {
egg: i18n.t('petName', { egg: i18n.t('petName', {
potion: potionText, potion: potionText,
egg: eggText, egg: eggText,
}), }),
foodText: food.text(), foodText: food.text(),
}), }));
});
expect(user.items.food.Milk).to.equal(1); expect(user.items.food.Milk).to.equal(1);
expect(user.items.pets['Wolf-Spooky']).to.equal(10); expect(user.items.pets['Wolf-Spooky']).to.equal(10);
@@ -181,17 +175,15 @@ describe('shared.ops.feed', () => {
let potionText = content.hatchingPotions[potion] ? content.hatchingPotions[potion].text() : potion; let potionText = content.hatchingPotions[potion] ? content.hatchingPotions[potion].text() : potion;
let eggText = content.eggs[egg] ? content.eggs[egg].text() : egg; let eggText = content.eggs[egg] ? content.eggs[egg].text() : egg;
let res = feed(user, {params: {pet: 'Wolf-Base', food: 'Milk'}}); let [data, message] = feed(user, {params: {pet: 'Wolf-Base', food: 'Milk'}});
expect(res).to.eql({ expect(data).to.eql(user.items.pets['Wolf-Base']);
data: user.items.pets['Wolf-Base'], expect(message).to.eql(i18n.t('messageDontEnjoyFood', {
message: i18n.t('messageDontEnjoyFood', {
egg: i18n.t('petName', { egg: i18n.t('petName', {
potion: potionText, potion: potionText,
egg: eggText, egg: eggText,
}), }),
foodText: food.text(), foodText: food.text(),
}), }));
});
expect(user.items.food.Milk).to.equal(1); expect(user.items.food.Milk).to.equal(1);
expect(user.items.pets['Wolf-Base']).to.equal(7); expect(user.items.pets['Wolf-Base']).to.equal(7);
@@ -206,16 +198,14 @@ describe('shared.ops.feed', () => {
let potionText = content.hatchingPotions[potion] ? content.hatchingPotions[potion].text() : potion; let potionText = content.hatchingPotions[potion] ? content.hatchingPotions[potion].text() : potion;
let eggText = content.eggs[egg] ? content.eggs[egg].text() : egg; let eggText = content.eggs[egg] ? content.eggs[egg].text() : egg;
let res = feed(user, {params: {pet: 'Wolf-Base', food: 'Milk'}}); let [data, message] = feed(user, {params: {pet: 'Wolf-Base', food: 'Milk'}});
expect(res).to.eql({ expect(data).to.eql(user.items.pets['Wolf-Base']);
data: user.items.pets['Wolf-Base'], expect(message).to.eql(i18n.t('messageEvolve', {
message: i18n.t('messageEvolve', {
egg: i18n.t('petName', { egg: i18n.t('petName', {
potion: potionText, potion: potionText,
egg: eggText, egg: eggText,
}), }),
}), }));
});
expect(user.items.food.Milk).to.equal(1); expect(user.items.food.Milk).to.equal(1);
expect(user.items.pets['Wolf-Base']).to.equal(-1); expect(user.items.pets['Wolf-Base']).to.equal(-1);

View File

@@ -99,9 +99,9 @@ describe('shared.ops.hatch', () => {
user.items.eggs = {Wolf: 1}; user.items.eggs = {Wolf: 1};
user.items.hatchingPotions = {Base: 1}; user.items.hatchingPotions = {Base: 1};
user.items.pets = {}; user.items.pets = {};
let res = hatch(user, {params: {egg: 'Wolf', hatchingPotion: 'Base'}}); let [data, message] = hatch(user, {params: {egg: 'Wolf', hatchingPotion: 'Base'}});
expect(res.message).to.equal(i18n.t('messageHatched')); expect(message).to.equal(i18n.t('messageHatched'));
expect(res.data).to.eql(user.items); expect(data).to.eql(user.items);
expect(user.items.pets).to.eql({'Wolf-Base': 5}); expect(user.items.pets).to.eql({'Wolf-Base': 5});
expect(user.items.eggs).to.eql({Wolf: 0}); expect(user.items.eggs).to.eql({Wolf: 0});
expect(user.items.hatchingPotions).to.eql({Base: 0}); expect(user.items.hatchingPotions).to.eql({Base: 0});
@@ -111,9 +111,9 @@ describe('shared.ops.hatch', () => {
user.items.eggs = {Cheetah: 1}; user.items.eggs = {Cheetah: 1};
user.items.hatchingPotions = {Base: 1}; user.items.hatchingPotions = {Base: 1};
user.items.pets = {}; user.items.pets = {};
let res = hatch(user, {params: {egg: 'Cheetah', hatchingPotion: 'Base'}}); let [data, message] = hatch(user, {params: {egg: 'Cheetah', hatchingPotion: 'Base'}});
expect(res.message).to.equal(i18n.t('messageHatched')); expect(message).to.equal(i18n.t('messageHatched'));
expect(res.data).to.eql(user.items); expect(data).to.eql(user.items);
expect(user.items.pets).to.eql({'Cheetah-Base': 5}); expect(user.items.pets).to.eql({'Cheetah-Base': 5});
expect(user.items.eggs).to.eql({Cheetah: 0}); expect(user.items.eggs).to.eql({Cheetah: 0});
expect(user.items.hatchingPotions).to.eql({Base: 0}); expect(user.items.hatchingPotions).to.eql({Base: 0});
@@ -123,9 +123,9 @@ describe('shared.ops.hatch', () => {
user.items.eggs = {Wolf: 1}; user.items.eggs = {Wolf: 1};
user.items.hatchingPotions = {Spooky: 1}; user.items.hatchingPotions = {Spooky: 1};
user.items.pets = {}; user.items.pets = {};
let res = hatch(user, {params: {egg: 'Wolf', hatchingPotion: 'Spooky'}}); let [data, message] = hatch(user, {params: {egg: 'Wolf', hatchingPotion: 'Spooky'}});
expect(res.message).to.equal(i18n.t('messageHatched')); expect(message).to.equal(i18n.t('messageHatched'));
expect(res.data).to.eql(user.items); expect(data).to.eql(user.items);
expect(user.items.pets).to.eql({'Wolf-Spooky': 5}); expect(user.items.pets).to.eql({'Wolf-Spooky': 5});
expect(user.items.eggs).to.eql({Wolf: 0}); expect(user.items.eggs).to.eql({Wolf: 0});
expect(user.items.hatchingPotions).to.eql({Spooky: 0}); expect(user.items.hatchingPotions).to.eql({Spooky: 0});
@@ -135,9 +135,9 @@ describe('shared.ops.hatch', () => {
user.items.eggs = {Wolf: 1}; user.items.eggs = {Wolf: 1};
user.items.hatchingPotions = {Base: 1}; user.items.hatchingPotions = {Base: 1};
user.items.pets = {'Wolf-Base': -1}; user.items.pets = {'Wolf-Base': -1};
let res = hatch(user, {params: {egg: 'Wolf', hatchingPotion: 'Base'}}); let [data, message] = hatch(user, {params: {egg: 'Wolf', hatchingPotion: 'Base'}});
expect(res.message).to.eql(i18n.t('messageHatched')); expect(message).to.eql(i18n.t('messageHatched'));
expect(res.data).to.eql(user.items); expect(data).to.eql(user.items);
expect(user.items.pets).to.eql({'Wolf-Base': 5}); expect(user.items.pets).to.eql({'Wolf-Base': 5});
expect(user.items.eggs).to.eql({Wolf: 0}); expect(user.items.eggs).to.eql({Wolf: 0});
expect(user.items.hatchingPotions).to.eql({Base: 0}); expect(user.items.hatchingPotions).to.eql({Base: 0});

View File

@@ -126,9 +126,9 @@ describe('user.ops.hourglassPurchase', () => {
it('buys a pet', () => { it('buys a pet', () => {
user.purchased.plan.consecutive.trinkets = 2; user.purchased.plan.consecutive.trinkets = 2;
let response = hourglassPurchase(user, {params: {type: 'pets', key: 'MantisShrimp-Base'}}); let [, message] = hourglassPurchase(user, {params: {type: 'pets', key: 'MantisShrimp-Base'}});
expect(response.message).to.eql(i18n.t('hourglassPurchase')); expect(message).to.eql(i18n.t('hourglassPurchase'));
expect(user.purchased.plan.consecutive.trinkets).to.eql(1); expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
expect(user.items.pets).to.eql({'MantisShrimp-Base': 5}); expect(user.items.pets).to.eql({'MantisShrimp-Base': 5});
}); });
@@ -136,8 +136,8 @@ describe('user.ops.hourglassPurchase', () => {
it('buys a mount', () => { it('buys a mount', () => {
user.purchased.plan.consecutive.trinkets = 2; user.purchased.plan.consecutive.trinkets = 2;
let response = hourglassPurchase(user, {params: {type: 'mounts', key: 'MantisShrimp-Base'}}); let [, message] = hourglassPurchase(user, {params: {type: 'mounts', key: 'MantisShrimp-Base'}});
expect(response.message).to.eql(i18n.t('hourglassPurchase')); expect(message).to.eql(i18n.t('hourglassPurchase'));
expect(user.purchased.plan.consecutive.trinkets).to.eql(1); expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
expect(user.items.mounts).to.eql({'MantisShrimp-Base': true}); expect(user.items.mounts).to.eql({'MantisShrimp-Base': true});
}); });

View File

@@ -29,10 +29,10 @@ describe('shared.ops.openMysteryItem', () => {
user.purchased.plan.mysteryItems = [mysteryItemKey]; user.purchased.plan.mysteryItems = [mysteryItemKey];
let response = openMysteryItem(user); let [data, message] = openMysteryItem(user);
expect(user.items.gear.owned[mysteryItemKey]).to.be.true; expect(user.items.gear.owned[mysteryItemKey]).to.be.true;
expect(response.message).to.equal(i18n.t('mysteryItemOpened')); expect(message).to.equal(i18n.t('mysteryItemOpened'));
expect(response.data).to.equal(user.items.gear.owned); expect(data).to.equal(user.items.gear.owned);
}); });
}); });

View File

@@ -10,7 +10,7 @@ import {
generateUser, generateUser,
} from '../../helpers/common.helper'; } from '../../helpers/common.helper';
describe('shared.ops.feed', () => { describe('shared.ops.purchase', () => {
let user; let user;
let goldPoints = 40; let goldPoints = 40;
let gemsBought = 40; let gemsBought = 40;
@@ -128,7 +128,7 @@ describe('shared.ops.feed', () => {
}); });
}); });
context('successful feeding', () => { context('successful purchase', () => {
let userGemAmount = 10; let userGemAmount = 10;
before(() => { before(() => {
@@ -138,9 +138,9 @@ describe('shared.ops.feed', () => {
}); });
it('purchases gems', () => { it('purchases gems', () => {
let purchaseResponse = purchase(user, {params: {type: 'gems', key: 'gem'}}); let [, message] = purchase(user, {params: {type: 'gems', key: 'gem'}});
expect(purchaseResponse.message).to.equal(i18n.t('plusOneGem')); expect(message).to.equal(i18n.t('plusOneGem'));
expect(user.balance).to.equal(userGemAmount + 0.25); expect(user.balance).to.equal(userGemAmount + 0.25);
expect(user.purchased.plan.gemsBought).to.equal(1); expect(user.purchased.plan.gemsBought).to.equal(1);
expect(user.stats.gp).to.equal(goldPoints - planGemLimits.convRate); expect(user.stats.gp).to.equal(goldPoints - planGemLimits.convRate);
@@ -150,9 +150,9 @@ describe('shared.ops.feed', () => {
let type = 'eggs'; let type = 'eggs';
let key = 'Wolf'; let key = 'Wolf';
let purchaseResponse = purchase(user, {params: {type, key}}); let [, message] = purchase(user, {params: {type, key}});
expect(purchaseResponse.message).to.equal(i18n.t('purchased', {type, key})); expect(message).to.equal(i18n.t('purchased', {type, key}));
expect(user.items[type][key]).to.equal(1); expect(user.items[type][key]).to.equal(1);
}); });
@@ -160,9 +160,9 @@ describe('shared.ops.feed', () => {
let type = 'hatchingPotions'; let type = 'hatchingPotions';
let key = 'Base'; let key = 'Base';
let purchaseResponse = purchase(user, {params: {type, key}}); let [, message] = purchase(user, {params: {type, key}});
expect(purchaseResponse.message).to.equal(i18n.t('purchased', {type, key})); expect(message).to.equal(i18n.t('purchased', {type, key}));
expect(user.items[type][key]).to.equal(1); expect(user.items[type][key]).to.equal(1);
}); });
@@ -170,9 +170,9 @@ describe('shared.ops.feed', () => {
let type = 'food'; let type = 'food';
let key = 'Meat'; let key = 'Meat';
let purchaseResponse = purchase(user, {params: {type, key}}); let [, message] = purchase(user, {params: {type, key}});
expect(purchaseResponse.message).to.equal(i18n.t('purchased', {type, key})); expect(message).to.equal(i18n.t('purchased', {type, key}));
expect(user.items[type][key]).to.equal(1); expect(user.items[type][key]).to.equal(1);
}); });
@@ -180,9 +180,9 @@ describe('shared.ops.feed', () => {
let type = 'quests'; let type = 'quests';
let key = 'gryphon'; let key = 'gryphon';
let purchaseResponse = purchase(user, {params: {type, key}}); let [, message] = purchase(user, {params: {type, key}});
expect(purchaseResponse.message).to.equal(i18n.t('purchased', {type, key})); expect(message).to.equal(i18n.t('purchased', {type, key}));
expect(user.items[type][key]).to.equal(1); expect(user.items[type][key]).to.equal(1);
}); });
@@ -190,9 +190,9 @@ describe('shared.ops.feed', () => {
let type = 'gear'; let type = 'gear';
let key = 'headAccessory_special_tigerEars'; let key = 'headAccessory_special_tigerEars';
let purchaseResponse = purchase(user, {params: {type, key}}); let [, message] = purchase(user, {params: {type, key}});
expect(purchaseResponse.message).to.equal(i18n.t('purchased', {type, key})); expect(message).to.equal(i18n.t('purchased', {type, key}));
expect(user.items.gear.owned[key]).to.be.true; expect(user.items.gear.owned[key]).to.be.true;
}); });
}); });

View File

@@ -39,9 +39,9 @@ describe('shared.ops.readCard', () => {
}); });
it('reads a card', () => { it('reads a card', () => {
let response = readCard(user, {params: {cardType: 'greeting'}}); let [, message] = readCard(user, {params: {cardType: 'greeting'}});
expect(response.message).to.equal(i18n.t('readCard', {cardType})); expect(message).to.equal(i18n.t('readCard', {cardType}));
expect(user.items.special[`${cardType}Received`]).to.be.empty; expect(user.items.special[`${cardType}Received`]).to.be.empty;
expect(user.flags.cardReceived).to.be.false; expect(user.flags.cardReceived).to.be.false;
}); });

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