From c916c747752a7db92facb024e47cb1c98ad7ee62 Mon Sep 17 00:00:00 2001 From: Keith Holliday Date: Sun, 3 Apr 2016 14:43:16 -0500 Subject: [PATCH] Ported release both, added unit tests, add release both route with integration tests --- common/locales/en/api-v3.json | 3 +- common/script/index.js | 2 + common/script/ops/releaseBoth.js | 93 ++++++++++-------- .../user/POST-user_release_both.test.js | 48 +++++++++ test/common/ops/releaseBoth.js | 98 +++++++++++++++++++ website/src/controllers/api-v3/user.js | 20 ++++ 6 files changed, 224 insertions(+), 40 deletions(-) create mode 100644 test/api/v3/integration/user/POST-user_release_both.test.js create mode 100644 test/common/ops/releaseBoth.js diff --git a/common/locales/en/api-v3.json b/common/locales/en/api-v3.json index afb7b17f00..940289e7ef 100644 --- a/common/locales/en/api-v3.json +++ b/common/locales/en/api-v3.json @@ -148,5 +148,6 @@ "noSudoAccess": "You don't have sudo access.", "couponCodeRequired": "The coupon code is required.", "eventRequired": "\"req.params.event\" is required.", - "countRequired": "\"req.query.count\" is required." + "countRequired": "\"req.query.count\" is required.", + "mountsAndPetsReleased": "Mounts and pets released" } diff --git a/common/script/index.js b/common/script/index.js index ee7206f3b1..60cd5e120f 100644 --- a/common/script/index.js +++ b/common/script/index.js @@ -118,6 +118,7 @@ import purchase from './ops/purchase'; import purchaseHourglass from './ops/hourglassPurchase'; import readCard from './ops/readCard'; import openMysteryItem from './ops/openMysteryItem'; +import releaseBoth from './ops/releaseBoth'; api.ops = { scoreTask, @@ -137,6 +138,7 @@ api.ops = { purchaseHourglass, readCard, openMysteryItem, + releaseBoth, }; import handleTwoHanded from './fns/handleTwoHanded'; diff --git a/common/script/ops/releaseBoth.js b/common/script/ops/releaseBoth.js index a782581f85..a17d2e5f00 100644 --- a/common/script/ops/releaseBoth.js +++ b/common/script/ops/releaseBoth.js @@ -1,50 +1,65 @@ import content from '../content/index'; import i18n from '../i18n'; +import { + NotAuthorized, +} from '../libs/errors'; +import splitWhitespace from '../libs/splitWhitespace'; + +module.exports = function releaseBoth (user, req = {}, analytics) { + let animal; -module.exports = function(user, req, cb, analytics) { - var analyticsData, animal, giveTriadBingo; if (user.balance < 1.5 && !user.achievements.triadBingo) { - return typeof cb === "function" ? cb({ - code: 401, - message: i18n.t('notEnoughGems', req.language) - }) : void 0; - } else { - giveTriadBingo = true; - if (!user.achievements.triadBingo) { - analyticsData = { + throw new NotAuthorized(i18n.t('notEnoughGems', req.language)); + } + + let giveTriadBingo = true; + + if (!user.achievements.triadBingo) { + if (analytics) { + analytics.track('release pets & mounts', { uuid: user._id, acquireMethod: 'Gems', gemCost: 6, category: 'behavior' - }; - if (typeof analytics !== "undefined" && analytics !== null) { - analytics.track('release pets & mounts', analyticsData); - } - user.balance -= 1.5; - } - user.items.currentMount = ""; - user.items.currentPet = ""; - for (animal in content.pets) { - if (user.items.pets[animal] === -1) { - giveTriadBingo = false; - } - user.items.pets[animal] = 0; - user.items.mounts[animal] = null; - } - if (!user.achievements.beastMasterCount) { - user.achievements.beastMasterCount = 0; - } - user.achievements.beastMasterCount++; - if (!user.achievements.mountMasterCount) { - user.achievements.mountMasterCount = 0; - } - user.achievements.mountMasterCount++; - if (giveTriadBingo) { - if (!user.achievements.triadBingoCount) { - user.achievements.triadBingoCount = 0; - } - user.achievements.triadBingoCount++; + }); } + + user.balance -= 1.5; } - return typeof cb === "function" ? cb(null, user) : void 0; + + user.items.currentMount = ""; + user.items.currentPet = ""; + + for (animal in content.pets) { + if (user.items.pets[animal] === -1) { + giveTriadBingo = false; + } + + user.items.pets[animal] = 0; + user.items.mounts[animal] = null; + } + + if (!user.achievements.beastMasterCount) { + user.achievements.beastMasterCount = 0; + } + user.achievements.beastMasterCount++; + + if (!user.achievements.mountMasterCount) { + user.achievements.mountMasterCount = 0; + } + user.achievements.mountMasterCount++; + + if (giveTriadBingo) { + if (!user.achievements.triadBingoCount) { + user.achievements.triadBingoCount = 0; + } + user.achievements.triadBingoCount++; + } + + let response = { + data: _.pick(user, splitWhitespace('achievements')), + message: i18n.t('mountsAndPetsReleased'), + }; + + return response; }; diff --git a/test/api/v3/integration/user/POST-user_release_both.test.js b/test/api/v3/integration/user/POST-user_release_both.test.js new file mode 100644 index 0000000000..8c47d95dfe --- /dev/null +++ b/test/api/v3/integration/user/POST-user_release_both.test.js @@ -0,0 +1,48 @@ +import { + generateUser, + translate as t, +} from '../../../../helpers/api-integration/v3'; + +describe('POST /user/release-both', () => { + let user; + let animal = 'Wolf-Base'; + + beforeEach(async () => { + user = await generateUser({ + 'items.currentMount': animal, + 'items.currentPet': animal, + 'items.pets': {animal: 5}, + 'items.mounts': {animal: true}, + }); + }); + + it('returns an error when user balance is too low and user does not have triadBingo', async () => { + await expect(user.post('/user/release-both')) + .to.eventually.be.rejected.and.to.eql({ + code: 401, + error: 'NotAuthorized', + message: t('notEnoughGems'), + }); + }); + + // More tests in common code unit tests + + it('grants triad bingo with gems', async () => { + await user.update({ + balance: 1.5, + }); + + let response = await user.post('/user/release-both'); + await user.sync(); + + expect(response.message).to.equal(t('mountsAndPetsReleased')); + expect(user.balance).to.equal(0); + expect(user.items.currentMount).to.be.empty; + expect(user.items.currentPet).to.be.empty; + expect(user.items.pets[animal]).to.be.empty; + expect(user.items.mounts[animal]).to.equal(null); + expect(user.achievements.beastMasterCount).to.equal(1); + expect(user.achievements.mountMasterCount).to.equal(1); + expect(user.achievements.triadBingoCount).to.equal(1); + }); +}); diff --git a/test/common/ops/releaseBoth.js b/test/common/ops/releaseBoth.js new file mode 100644 index 0000000000..309734e7d4 --- /dev/null +++ b/test/common/ops/releaseBoth.js @@ -0,0 +1,98 @@ +import releaseBoth from '../../../common/script/ops/releaseBoth'; +import i18n from '../../../common/script/i18n'; +import { + generateUser, +} from '../../helpers/common.helper'; +import { + NotAuthorized, +} from '../../../common/script/libs/errors'; + +describe('shared.ops.releaseBoth', () => { + let user; + let animal = 'Wolf-Base'; + + beforeEach(() => { + user = generateUser(); + user.items.currentMount = animal; + user.items.currentPet = animal; + user.items.pets[animal] = 5; + user.items.mounts[animal] = true; + user.balance = 1.5; + }); + + it('returns an error when user balance is too low and user does not have triadBingo', (done) => { + user.balance = 0; + + try { + releaseBoth(user); + } catch (err) { + expect(err).to.be.an.instanceof(NotAuthorized); + expect(err.message).to.equal(i18n.t('notEnoughGems')); + done(); + } + }); + + it('grants triad bingo with gems', () => { + let response = releaseBoth(user); + + expect(response.message).to.equal(i18n.t('mountsAndPetsReleased')); + expect(user.achievements.triadBingoCount).to.equal(1); + }); + + it('grants triad bingo without gems', () => { + user.balance = 0; + user.achievements.triadBingo = 1; + user.achievements.triadBingoCount = 1; + + let response = releaseBoth(user); + + expect(response.message).to.equal(i18n.t('mountsAndPetsReleased')); + expect(user.achievements.triadBingoCount).to.equal(2); + }); + + it('releases pets', () => { + let response = releaseBoth(user); + + expect(response.message).to.equal(i18n.t('mountsAndPetsReleased')); + expect(user.items.pets[animal]).to.be.empty; + expect(user.items.mounts[animal]).to.equal(null); + }); + + it('releases mounts', () => { + let response = releaseBoth(user); + + expect(response.message).to.equal(i18n.t('mountsAndPetsReleased')); + expect(user.items.mounts[animal]).to.equal(null); + }); + + it('removes currentPet', () => { + releaseBoth(user); + + expect(user.items.currentMount).to.be.empty; + expect(user.items.currentPet).to.be.empty; + }); + + it('removes currentMount', () => { + releaseBoth(user); + + expect(user.items.currentMount).to.be.empty; + }); + + it('decreases user\'s balance', () => { + releaseBoth(user); + + expect(user.balance).to.equal(0); + }); + + it('incremenets beastMasterCount', () => { + releaseBoth(user); + + expect(user.achievements.beastMasterCount).to.equal(1); + }); + + it('incremenets mountMasterCount', () => { + releaseBoth(user); + + expect(user.achievements.mountMasterCount).to.equal(1); + }); +}); diff --git a/website/src/controllers/api-v3/user.js b/website/src/controllers/api-v3/user.js index 49d2f2f05d..57202e5e62 100644 --- a/website/src/controllers/api-v3/user.js +++ b/website/src/controllers/api-v3/user.js @@ -764,4 +764,24 @@ api.userOpenMysteryItem = { }, }; +/** +* @api {post} /user/release-both Releases Pets and Mounts and grants Triad Bingo. +* @apiVersion 3.0.0 +* @apiName UserReleaseBoth +* @apiGroup User +* +* @apiSuccess {Object} data `user.items.gear.owned` +*/ +api.userReleaseBoth = { + method: 'POST', + middlewares: [authWithHeaders(), cron], + url: '/user/release-both', + async handler (req, res) { + let user = res.locals.user; + let releaseBothResponse = common.ops.releaseBoth(user, req, res.analytics); + await user.save(); + res.respond(200, releaseBothResponse); + }, +}; + module.exports = api;