From 6e43d4dc795dd919b583f2b3b4435398c05c5c42 Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Mon, 31 Jan 2022 22:36:15 +0100 Subject: [PATCH] Add Transaction log for gem and hourglass changes (#13589) * Log all gem transactions to database * Also store hourglass transactions * Fix tests * Display transaction history in hall of heroes for admins * add tests to new API call * hide transaction settings tab for non admins * fix(lint): remove console * fix(lint): various automatic corrections * fix(transactions): use enum expected pluralizations * fix api unit tests * fix lint * fix failing test * Fix minor inconsistencies * Log all gem transactions to database * Also store hourglass transactions * Fix tests * Display transaction history in hall of heroes for admins * add tests to new API call * hide transaction settings tab for non admins * fix(lint): remove console * fix(lint): various automatic corrections * fix(transactions): use enum expected pluralizations * fix api unit tests * fix lint * Fix minor inconsistencies Co-authored-by: Sabe Jones --- test/api/unit/libs/cron.test.js | 620 +++++++++--------- .../v4/members/GET-purchase_history.test.js | 38 ++ test/common/ops/buy/buy.js | 44 +- test/common/ops/buy/buyArmoire.js | 27 +- test/common/ops/buy/buyGem.js | 39 +- test/common/ops/buy/buyHealthPotion.js | 38 +- test/common/ops/buy/buyMarketGear.js | 96 ++- test/common/ops/buy/buyMysterySet.js | 19 +- test/common/ops/buy/buyQuestGems.js | 19 +- test/common/ops/buy/buyQuestGold.js | 51 +- test/common/ops/buy/buySpell.js | 21 +- test/common/ops/buy/hourglassPurchase.js | 55 +- test/common/ops/buy/purchase.js | 79 +-- test/common/ops/changeClass.js | 32 +- test/common/ops/rebirth.js | 97 ++- test/common/ops/releaseMounts.js | 40 +- test/common/ops/releasePets.js | 42 +- test/common/ops/reroll.js | 21 +- test/common/ops/unlock.js | 151 ++--- website/client/src/components/hall/heroes.vue | 446 +++++++------ .../header/notifications/worldBoss.vue | 6 +- .../src/components/inventory/items/index.vue | 5 +- .../client/src/components/settings/index.vue | 9 + .../components/settings/purchaseHistory.vue | 38 ++ .../src/components/snackbars/notification.vue | 33 +- .../components/snackbars/notifications.vue | 6 +- .../components/ui/purchaseHistoryTable.vue | 155 +++++ website/client/src/router/index.js | 6 + website/client/src/store/actions/members.js | 5 + website/client/src/store/actions/user.js | 6 + website/common/locales/en/settings.json | 22 +- .../script/ops/buy/abstractBuyOperation.js | 18 +- website/common/script/ops/buy/buy.js | 26 +- website/common/script/ops/buy/buyGem.js | 3 +- website/common/script/ops/buy/buyMount.js | 4 +- .../common/script/ops/buy/buyMysterySet.js | 5 +- website/common/script/ops/buy/buyQuestGem.js | 4 +- .../script/ops/buy/hourglassPurchase.js | 9 +- website/common/script/ops/buy/purchase.js | 12 +- website/common/script/ops/changeClass.js | 11 +- website/common/script/ops/rebirth.js | 5 +- website/common/script/ops/releaseMounts.js | 5 +- website/common/script/ops/releasePets.js | 3 +- website/common/script/ops/reroll.js | 5 +- website/common/script/ops/unlock.js | 5 +- .../common/script/ops/updateUserBalance.js | 11 + .../script/ops/updateUserHourglasses.js | 15 + website/server/controllers/api-v3/debug.js | 4 +- website/server/controllers/api-v3/groups.js | 2 +- website/server/controllers/api-v3/hall.js | 2 +- website/server/controllers/api-v3/members.js | 4 +- website/server/controllers/api-v3/user.js | 28 +- website/server/controllers/api-v4/members.js | 23 + website/server/controllers/api-v4/user.js | 18 + website/server/libs/challenges/index.js | 30 +- website/server/libs/cron.js | 9 +- website/server/libs/payments/gems.js | 8 +- website/server/libs/payments/subscriptions.js | 2 +- website/server/libs/user/index.js | 4 +- website/server/middlewares/cron.js | 2 +- website/server/models/subscriptionPlan.js | 17 + website/server/models/transaction.js | 31 + website/server/models/user/methods.js | 28 + 63 files changed, 1530 insertions(+), 1089 deletions(-) create mode 100644 test/api/v4/members/GET-purchase_history.test.js create mode 100644 website/client/src/components/settings/purchaseHistory.vue create mode 100644 website/client/src/components/ui/purchaseHistoryTable.vue create mode 100644 website/common/script/ops/updateUserBalance.js create mode 100644 website/common/script/ops/updateUserHourglasses.js create mode 100644 website/server/models/transaction.js diff --git a/test/api/unit/libs/cron.test.js b/test/api/unit/libs/cron.test.js index ee0271d82f..eb15119ee1 100644 --- a/test/api/unit/libs/cron.test.js +++ b/test/api/unit/libs/cron.test.js @@ -12,7 +12,7 @@ import * as analytics from '../../../../website/server/libs/analyticsService'; const pathToCronLib = '../../../../website/server/libs/cron'; -describe('cron', () => { +describe('cron', async () => { let clock = null; let user; const tasksByType = { @@ -20,7 +20,7 @@ describe('cron', () => { }; let daysMissed = 0; - beforeEach(() => { + beforeEach(async () => { user = new User({ auth: { local: { @@ -36,62 +36,62 @@ describe('cron', () => { sinon.spy(analytics, 'track'); }); - afterEach(() => { + afterEach(async () => { if (clock !== null) clock.restore(); analytics.track.restore(); }); - it('updates user.preferences.timezoneOffsetAtLastCron', () => { + it('updates user.preferences.timezoneOffsetAtLastCron', async () => { const timezoneUtcOffsetFromUserPrefs = -1; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, timezoneUtcOffsetFromUserPrefs, }); expect(user.preferences.timezoneOffsetAtLastCron).to.equal(1); }); - it('resets user.items.lastDrop.count', () => { + it('resets user.items.lastDrop.count', async () => { user.items.lastDrop.count = 4; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.items.lastDrop.count).to.equal(0); }); - it('increments user cron count', () => { + it('increments user cron count', async () => { const cronCountBefore = user.flags.cronCount; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.flags.cronCount).to.be.greaterThan(cronCountBefore); }); - it('calls analytics', () => { - cron({ + it('calls analytics', async () => { + await cron({ user, tasksByType, daysMissed, analytics, }); expect(analytics.track.callCount).to.equal(1); }); - it('calls analytics when user is sleeping', () => { + it('calls analytics when user is sleeping', async () => { user.preferences.sleep = true; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(analytics.track.callCount).to.equal(1); }); - describe('end of the month perks', () => { - beforeEach(() => { + describe('end of the month perks', async () => { + beforeEach(async () => { user.purchased.plan.customerId = 'subscribedId'; user.purchased.plan.dateUpdated = moment().subtract(1, 'months').toDate(); }); - it('awards current mystery items to subscriber', () => { + it('awards current mystery items to subscriber', async () => { user.purchased.plan.dateUpdated = new Date('2018-12-11'); clock = sinon.useFakeTimers(new Date('2019-01-29')); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.purchased.plan.mysteryItems.length).to.eql(2); @@ -99,10 +99,10 @@ describe('cron', () => { expect(filteredNotifications.length).to.equal(1); }); - it('awards multiple mystery item sets if user skipped months between logins', () => { + it('awards multiple mystery item sets if user skipped months between logins', async () => { user.purchased.plan.dateUpdated = new Date('2018-11-11'); clock = sinon.useFakeTimers(new Date('2019-01-29')); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.purchased.plan.mysteryItems.length).to.eql(4); @@ -110,104 +110,104 @@ describe('cron', () => { expect(filteredNotifications.length).to.equal(1); }); - it('resets plan.gemsBought on a new month', () => { + it('resets plan.gemsBought on a new month', async () => { user.purchased.plan.gemsBought = 10; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.purchased.plan.gemsBought).to.equal(0); }); - it('resets plan.gemsBought on a new month if user does not have purchased.plan.dateUpdated', () => { + it('resets plan.gemsBought on a new month if user does not have purchased.plan.dateUpdated', async () => { user.purchased.plan.gemsBought = 10; user.purchased.plan.dateUpdated = undefined; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.purchased.plan.gemsBought).to.equal(0); }); - it('does not reset plan.gemsBought within the month', () => { + it('does not reset plan.gemsBought within the month', async () => { clock = sinon.useFakeTimers(moment().startOf('month').add(2, 'days').toDate()); user.purchased.plan.dateUpdated = moment().startOf('month').toDate(); user.purchased.plan.gemsBought = 10; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.purchased.plan.gemsBought).to.equal(10); }); - it('resets plan.dateUpdated on a new month', () => { + it('resets plan.dateUpdated on a new month', async () => { const currentMonth = moment().startOf('month'); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(moment(user.purchased.plan.dateUpdated).startOf('month').isSame(currentMonth)).to.eql(true); }); - it('increments plan.consecutive.count', () => { + it('increments plan.consecutive.count', async () => { user.purchased.plan.consecutive.count = 0; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.purchased.plan.consecutive.count).to.equal(1); }); - it('increments plan.consecutive.count by more than 1 if user skipped months between logins', () => { + it('increments plan.consecutive.count by more than 1 if user skipped months between logins', async () => { user.purchased.plan.dateUpdated = moment().subtract(2, 'months').toDate(); user.purchased.plan.consecutive.count = 0; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.purchased.plan.consecutive.count).to.equal(2); }); - it('decrements plan.consecutive.offset when offset is greater than 0', () => { + it('decrements plan.consecutive.offset when offset is greater than 0', async () => { user.purchased.plan.consecutive.offset = 2; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.purchased.plan.consecutive.offset).to.equal(1); }); - it('does not award unearned plan.consecutive.trinkets if subscription ended during an absence', () => { + it('does not award unearned plan.consecutive.trinkets if subscription ended during an absence', async () => { user.purchased.plan.dateUpdated = moment().subtract(6, 'months').toDate(); user.purchased.plan.dateTerminated = moment().subtract(3, 'months').toDate(); user.purchased.plan.consecutive.count = 5; user.purchased.plan.consecutive.trinkets = 1; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.purchased.plan.consecutive.trinkets).to.equal(1); }); - it('does not increment plan.consecutive.gemCapExtra when user has reached the gemCap limit', () => { + it('does not increment plan.consecutive.gemCapExtra when user has reached the gemCap limit', async () => { user.purchased.plan.consecutive.gemCapExtra = 25; user.purchased.plan.consecutive.count = 5; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.purchased.plan.consecutive.gemCapExtra).to.equal(25); }); - it('does not reset plan stats if we are before the last day of the cancelled month', () => { + it('does not reset plan stats if we are before the last day of the cancelled month', async () => { user.purchased.plan.dateTerminated = moment(new Date()).add({ days: 1 }); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.purchased.plan.customerId).to.exist; }); - it('does reset plan stats if we are after the last day of the cancelled month', () => { + it('does reset plan stats if we are after the last day of the cancelled month', async () => { user.purchased.plan.dateTerminated = moment(new Date()).subtract({ days: 1 }); user.purchased.plan.consecutive.gemCapExtra = 20; user.purchased.plan.consecutive.count = 5; user.purchased.plan.consecutive.offset = 1; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -217,7 +217,7 @@ describe('cron', () => { expect(user.purchased.plan.consecutive.offset).to.equal(0); }); - describe('for a 1-month recurring subscription', () => { + describe('for a 1-month recurring subscription', async () => { // create a user that will be used for all of these tests without a reset before each const user1 = new User({ auth: { @@ -239,14 +239,14 @@ describe('cron', () => { user1.purchased.plan.consecutive.trinkets = 0; user1.purchased.plan.consecutive.gemCapExtra = 0; - it('does not increment consecutive benefits after the first month', () => { + it('does not increment consecutive benefits after the first month', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(1, 'months') .add(2, 'days') .toDate()); // Add 1 month to simulate what happens a month after the subscription was created. // Add 2 days so that we're sure we're not affected by any start-of-month effects // e.g., from time zone oddness. - cron({ + await cron({ user: user1, tasksByType, daysMissed, analytics, }); expect(user1.purchased.plan.consecutive.count).to.equal(1); @@ -255,14 +255,14 @@ describe('cron', () => { expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(0); }); - it('does not increment consecutive benefits after the second month', () => { + it('does not increment consecutive benefits after the second month', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(2, 'months') .add(2, 'days') .toDate()); // Add 1 month to simulate what happens a month after the subscription was created. // Add 2 days so that we're sure we're not affected by any start-of-month effects // e.g., from time zone oddness. - cron({ + await cron({ user: user1, tasksByType, daysMissed, analytics, }); expect(user1.purchased.plan.consecutive.count).to.equal(2); @@ -271,14 +271,14 @@ describe('cron', () => { expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(0); }); - it('increments consecutive benefits after the third month', () => { + it('increments consecutive benefits after the third month', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(3, 'months') .add(2, 'days') .toDate()); // Add 1 month to simulate what happens a month after the subscription was created. // Add 2 days so that we're sure we're not affected by any start-of-month effects // e.g., from time zone oddness. - cron({ + await cron({ user: user1, tasksByType, daysMissed, analytics, }); expect(user1.purchased.plan.consecutive.count).to.equal(3); @@ -287,14 +287,14 @@ describe('cron', () => { expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(5); }); - it('does not increment consecutive benefits after the fourth month', () => { + it('does not increment consecutive benefits after the fourth month', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(4, 'months') .add(2, 'days') .toDate()); // Add 1 month to simulate what happens a month after the subscription was created. // Add 2 days so that we're sure we're not affected by any start-of-month effects // e.g., from time zone oddness. - cron({ + await cron({ user: user1, tasksByType, daysMissed, analytics, }); expect(user1.purchased.plan.consecutive.count).to.equal(4); @@ -303,11 +303,11 @@ describe('cron', () => { expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(5); }); - it('increments consecutive benefits correctly if user has been absent with continuous subscription', () => { + it('increments consecutive benefits correctly if user has been absent with continuous subscription', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(10, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user1, tasksByType, daysMissed, analytics, }); expect(user1.purchased.plan.consecutive.count).to.equal(10); @@ -317,7 +317,7 @@ describe('cron', () => { }); }); - describe('for a 3-month recurring subscription', () => { + describe('for a 3-month recurring subscription', async () => { const user3 = new User({ auth: { local: { @@ -338,11 +338,11 @@ describe('cron', () => { user3.purchased.plan.consecutive.trinkets = 1; user3.purchased.plan.consecutive.gemCapExtra = 5; - it('does not increment consecutive benefits in the first month of the first paid period that they already have benefits for', () => { + it('does not increment consecutive benefits in the first month of the first paid period that they already have benefits for', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(1, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user3, tasksByType, daysMissed, analytics, }); expect(user3.purchased.plan.consecutive.count).to.equal(1); @@ -351,11 +351,11 @@ describe('cron', () => { expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(5); }); - it('does not increment consecutive benefits in the middle of the period that they already have benefits for', () => { + it('does not increment consecutive benefits in the middle of the period that they already have benefits for', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(2, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user3, tasksByType, daysMissed, analytics, }); expect(user3.purchased.plan.consecutive.count).to.equal(2); @@ -364,11 +364,11 @@ describe('cron', () => { expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(5); }); - it('does not increment consecutive benefits in the final month of the period that they already have benefits for', () => { + it('does not increment consecutive benefits in the final month of the period that they already have benefits for', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(3, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user3, tasksByType, daysMissed, analytics, }); expect(user3.purchased.plan.consecutive.count).to.equal(3); @@ -377,11 +377,11 @@ describe('cron', () => { expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(5); }); - it('increments consecutive benefits the month after the second paid period has started', () => { + it('increments consecutive benefits the month after the second paid period has started', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(4, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user3, tasksByType, daysMissed, analytics, }); expect(user3.purchased.plan.consecutive.count).to.equal(4); @@ -390,11 +390,11 @@ describe('cron', () => { expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(10); }); - it('does not increment consecutive benefits in the second month of the second period that they already have benefits for', () => { + it('does not increment consecutive benefits in the second month of the second period that they already have benefits for', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(5, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user3, tasksByType, daysMissed, analytics, }); expect(user3.purchased.plan.consecutive.count).to.equal(5); @@ -403,11 +403,11 @@ describe('cron', () => { expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(10); }); - it('does not increment consecutive benefits in the final month of the second period that they already have benefits for', () => { + it('does not increment consecutive benefits in the final month of the second period that they already have benefits for', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(6, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user3, tasksByType, daysMissed, analytics, }); expect(user3.purchased.plan.consecutive.count).to.equal(6); @@ -416,11 +416,11 @@ describe('cron', () => { expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(10); }); - it('increments consecutive benefits the month after the third paid period has started', () => { + it('increments consecutive benefits the month after the third paid period has started', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(7, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user3, tasksByType, daysMissed, analytics, }); expect(user3.purchased.plan.consecutive.count).to.equal(7); @@ -429,11 +429,11 @@ describe('cron', () => { expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(15); }); - it('increments consecutive benefits correctly if user has been absent with continuous subscription', () => { + it('increments consecutive benefits correctly if user has been absent with continuous subscription', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(10, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user3, tasksByType, daysMissed, analytics, }); expect(user3.purchased.plan.consecutive.count).to.equal(10); @@ -443,7 +443,7 @@ describe('cron', () => { }); }); - describe('for a 6-month recurring subscription', () => { + describe('for a 6-month recurring subscription', async () => { const user6 = new User({ auth: { local: { @@ -464,11 +464,11 @@ describe('cron', () => { user6.purchased.plan.consecutive.trinkets = 2; user6.purchased.plan.consecutive.gemCapExtra = 10; - it('does not increment consecutive benefits in the first month of the first paid period that they already have benefits for', () => { + it('does not increment consecutive benefits in the first month of the first paid period that they already have benefits for', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(1, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user6, tasksByType, daysMissed, analytics, }); expect(user6.purchased.plan.consecutive.count).to.equal(1); @@ -477,11 +477,11 @@ describe('cron', () => { expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(10); }); - it('does not increment consecutive benefits in the final month of the period that they already have benefits for', () => { + it('does not increment consecutive benefits in the final month of the period that they already have benefits for', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(6, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user6, tasksByType, daysMissed, analytics, }); expect(user6.purchased.plan.consecutive.count).to.equal(6); @@ -490,11 +490,11 @@ describe('cron', () => { expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(10); }); - it('increments consecutive benefits the month after the second paid period has started', () => { + it('increments consecutive benefits the month after the second paid period has started', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(7, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user6, tasksByType, daysMissed, analytics, }); expect(user6.purchased.plan.consecutive.count).to.equal(7); @@ -503,11 +503,11 @@ describe('cron', () => { expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(20); }); - it('increments consecutive benefits the month after the third paid period has started', () => { + it('increments consecutive benefits the month after the third paid period has started', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(13, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user6, tasksByType, daysMissed, analytics, }); expect(user6.purchased.plan.consecutive.count).to.equal(13); @@ -516,11 +516,11 @@ describe('cron', () => { expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(25); }); - it('increments consecutive benefits correctly if user has been absent with continuous subscription', () => { + it('increments consecutive benefits correctly if user has been absent with continuous subscription', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(19, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user6, tasksByType, daysMissed, analytics, }); expect(user6.purchased.plan.consecutive.count).to.equal(19); @@ -530,7 +530,7 @@ describe('cron', () => { }); }); - describe('for a 12-month recurring subscription', () => { + describe('for a 12-month recurring subscription', async () => { const user12 = new User({ auth: { local: { @@ -551,11 +551,11 @@ describe('cron', () => { user12.purchased.plan.consecutive.trinkets = 4; user12.purchased.plan.consecutive.gemCapExtra = 20; - it('does not increment consecutive benefits in the first month of the first paid period that they already have benefits for', () => { + it('does not increment consecutive benefits in the first month of the first paid period that they already have benefits for', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(1, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user12, tasksByType, daysMissed, analytics, }); expect(user12.purchased.plan.consecutive.count).to.equal(1); @@ -564,11 +564,11 @@ describe('cron', () => { expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(20); }); - it('does not increment consecutive benefits in the final month of the period that they already have benefits for', () => { + it('does not increment consecutive benefits in the final month of the period that they already have benefits for', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(12, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user12, tasksByType, daysMissed, analytics, }); expect(user12.purchased.plan.consecutive.count).to.equal(12); @@ -577,11 +577,11 @@ describe('cron', () => { expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(20); }); - it('increments consecutive benefits the month after the second paid period has started', () => { + it('increments consecutive benefits the month after the second paid period has started', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(13, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user12, tasksByType, daysMissed, analytics, }); expect(user12.purchased.plan.consecutive.count).to.equal(13); @@ -590,11 +590,11 @@ describe('cron', () => { expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(25); }); - it('increments consecutive benefits the month after the third paid period has started', () => { + it('increments consecutive benefits the month after the third paid period has started', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(25, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user12, tasksByType, daysMissed, analytics, }); expect(user12.purchased.plan.consecutive.count).to.equal(25); @@ -603,11 +603,11 @@ describe('cron', () => { expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(25); }); - it('increments consecutive benefits correctly if user has been absent with continuous subscription', () => { + it('increments consecutive benefits correctly if user has been absent with continuous subscription', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(37, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user12, tasksByType, daysMissed, analytics, }); expect(user12.purchased.plan.consecutive.count).to.equal(37); @@ -617,7 +617,7 @@ describe('cron', () => { }); }); - describe('for a 3-month gift subscription (non-recurring)', () => { + describe('for a 3-month gift subscription (non-recurring)', async () => { const user3g = new User({ auth: { local: { @@ -640,11 +640,11 @@ describe('cron', () => { user3g.purchased.plan.consecutive.trinkets = 1; user3g.purchased.plan.consecutive.gemCapExtra = 5; - it('does not increment consecutive benefits in the first month of the gift subscription', () => { + it('does not increment consecutive benefits in the first month of the gift subscription', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(1, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user3g, tasksByType, daysMissed, analytics, }); expect(user3g.purchased.plan.consecutive.count).to.equal(1); @@ -653,11 +653,11 @@ describe('cron', () => { expect(user3g.purchased.plan.consecutive.gemCapExtra).to.equal(5); }); - it('does not increment consecutive benefits in the second month of the gift subscription', () => { + it('does not increment consecutive benefits in the second month of the gift subscription', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(2, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user3g, tasksByType, daysMissed, analytics, }); expect(user3g.purchased.plan.consecutive.count).to.equal(2); @@ -666,11 +666,11 @@ describe('cron', () => { expect(user3g.purchased.plan.consecutive.gemCapExtra).to.equal(5); }); - it('does not increment consecutive benefits in the third month of the gift subscription', () => { + it('does not increment consecutive benefits in the third month of the gift subscription', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(3, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user3g, tasksByType, daysMissed, analytics, }); expect(user3g.purchased.plan.consecutive.count).to.equal(3); @@ -679,11 +679,11 @@ describe('cron', () => { expect(user3g.purchased.plan.consecutive.gemCapExtra).to.equal(5); }); - it('does not increment consecutive benefits in the month after the gift subscription has ended', () => { + it('does not increment consecutive benefits in the month after the gift subscription has ended', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(4, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user3g, tasksByType, daysMissed, analytics, }); // subscription has been erased by now @@ -694,7 +694,7 @@ describe('cron', () => { }); }); - describe('for a 6-month recurring subscription where the user has incorrect consecutive month data from prior bugs', () => { + describe('for a 6-month recurring subscription where the user has incorrect consecutive month data from prior bugs', async () => { const user6x = new User({ auth: { local: { @@ -716,11 +716,11 @@ describe('cron', () => { user6x.purchased.plan.consecutive.trinkets = 3; user6x.purchased.plan.consecutive.gemCapExtra = 15; - it('increments consecutive benefits in the first month since the fix for #4819 goes live', () => { + it('increments consecutive benefits in the first month since the fix for #4819 goes live', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(1, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user6x, tasksByType, daysMissed, analytics, }); expect(user6x.purchased.plan.consecutive.count).to.equal(9); @@ -729,11 +729,11 @@ describe('cron', () => { expect(user6x.purchased.plan.consecutive.gemCapExtra).to.equal(25); }); - it('does not increment consecutive benefits in the second month after the fix goes live', () => { + it('does not increment consecutive benefits in the second month after the fix goes live', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(2, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user6x, tasksByType, daysMissed, analytics, }); expect(user6x.purchased.plan.consecutive.count).to.equal(10); @@ -742,11 +742,11 @@ describe('cron', () => { expect(user6x.purchased.plan.consecutive.gemCapExtra).to.equal(25); }); - it('does not increment consecutive benefits in the third month after the fix goes live', () => { + it('does not increment consecutive benefits in the third month after the fix goes live', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(3, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user6x, tasksByType, daysMissed, analytics, }); expect(user6x.purchased.plan.consecutive.count).to.equal(11); @@ -755,11 +755,11 @@ describe('cron', () => { expect(user6x.purchased.plan.consecutive.gemCapExtra).to.equal(25); }); - it('increments consecutive benefits in the seventh month after the fix goes live', () => { + it('increments consecutive benefits in the seventh month after the fix goes live', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(7, 'months') .add(2, 'days') .toDate()); - cron({ + await cron({ user: user6x, tasksByType, daysMissed, analytics, }); expect(user6x.purchased.plan.consecutive.count).to.equal(15); @@ -770,93 +770,93 @@ describe('cron', () => { }); }); - describe('end of the month perks when user is not subscribed', () => { - beforeEach(() => { + describe('end of the month perks when user is not subscribed', async () => { + beforeEach(async () => { user.purchased.plan.dateUpdated = moment().subtract(1, 'months').toDate(); }); - it('resets plan.gemsBought on a new month', () => { + it('resets plan.gemsBought on a new month', async () => { user.purchased.plan.gemsBought = 10; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.purchased.plan.gemsBought).to.equal(0); }); - it('does not reset plan.gemsBought within the month', () => { + it('does not reset plan.gemsBought within the month', async () => { clock = sinon.useFakeTimers(moment().startOf('month').add(2, 'days').unix()); user.purchased.plan.dateUpdated = moment().startOf('month').toDate(); user.purchased.plan.gemsBought = 10; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.purchased.plan.gemsBought).to.equal(10); }); - it('does not reset plan.dateUpdated on a new month', () => { - cron({ + it('does not reset plan.dateUpdated on a new month', async () => { + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.purchased.plan.dateUpdated).to.be.empty; }); - it('does not increment plan.consecutive.count', () => { + it('does not increment plan.consecutive.count', async () => { user.purchased.plan.consecutive.count = 0; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.purchased.plan.consecutive.count).to.equal(0); }); - it('does not decrement plan.consecutive.offset when offset is greater than 0', () => { + it('does not decrement plan.consecutive.offset when offset is greater than 0', async () => { user.purchased.plan.consecutive.offset = 1; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.purchased.plan.consecutive.offset).to.equal(1); }); - it('does not increment plan.consecutive.trinkets when user has reached a month that is a multiple of 3', () => { + it('does not increment plan.consecutive.trinkets when user has reached a month that is a multiple of 3', async () => { user.purchased.plan.consecutive.count = 5; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.purchased.plan.consecutive.trinkets).to.equal(0); }); - it('does not increment plan.consecutive.gemCapExtra when user has reached a month that is a multiple of 3', () => { + it('does not increment plan.consecutive.gemCapExtra when user has reached a month that is a multiple of 3', async () => { user.purchased.plan.consecutive.count = 5; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.purchased.plan.consecutive.gemCapExtra).to.equal(0); }); - it('does not increment plan.consecutive.gemCapExtra when user has reached the gemCap limit', () => { + it('does not increment plan.consecutive.gemCapExtra when user has reached the gemCap limit', async () => { user.purchased.plan.consecutive.gemCapExtra = 25; user.purchased.plan.consecutive.count = 5; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.purchased.plan.consecutive.gemCapExtra).to.equal(25); }); - it('does nothing to plan stats if we are before the last day of the cancelled month', () => { + it('does nothing to plan stats if we are before the last day of the cancelled month', async () => { user.purchased.plan.dateTerminated = moment(new Date()).add({ days: 1 }); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.purchased.plan.customerId).to.not.exist; }); - xit('does nothing to plan stats when we are after the last day of the cancelled month', () => { + xit('does nothing to plan stats when we are after the last day of the cancelled month', async () => { user.purchased.plan.dateTerminated = moment(new Date()).subtract({ days: 1 }); user.purchased.plan.consecutive.gemCapExtra = 20; user.purchased.plan.consecutive.count = 5; user.purchased.plan.consecutive.offset = 1; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -867,8 +867,8 @@ describe('cron', () => { }); }); - describe('todos', () => { - beforeEach(() => { + describe('todos', async () => { + beforeEach(async () => { const todo = { text: 'test todo', type: 'todo', @@ -879,39 +879,39 @@ describe('cron', () => { tasksByType.todos.push(task); }); - afterEach(() => { + afterEach(async () => { tasksByType.todos = []; user.tasksOrder.todos = []; }); - it('should make uncompleted todos redder', () => { + it('should make uncompleted todos redder', async () => { const valueBefore = tasksByType.todos[0].value; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(tasksByType.todos[0].value).to.be.lessThan(valueBefore); }); - it('should not make completed todos redder', () => { + it('should not make completed todos redder', async () => { tasksByType.todos[0].completed = true; const valueBefore = tasksByType.todos[0].value; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(tasksByType.todos[0].value).to.equal(valueBefore); }); - it('should add history of completed todos to user history', () => { + it('should add history of completed todos to user history', async () => { tasksByType.todos[0].completed = true; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.history.todos).to.be.lengthOf(1); }); - it('should remove completed todos from users taskOrder list', () => { + it('should remove completed todos from users taskOrder list', async () => { const todo = { text: 'test todo', type: 'todo', @@ -930,7 +930,7 @@ describe('cron', () => { expect(tasksByType.todos).to.be.lengthOf(2); expect(user.tasksOrder.todos).to.be.lengthOf(3); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -939,7 +939,7 @@ describe('cron', () => { expect(user.tasksOrder.todos).to.be.lengthOf(1); }); - it('should preserve todos order in task list', () => { + it('should preserve todos order in task list', async () => { const todo = { text: 'test todo', type: 'todo', @@ -957,7 +957,7 @@ describe('cron', () => { user.tasksOrder.todos = tasksByType.todos.map(todoTask => todoTask._id).reverse(); const original = user.tasksOrder.todos; // Preserve the original order - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -973,8 +973,8 @@ describe('cron', () => { }); }); - describe('dailys', () => { - beforeEach(() => { + describe('dailys', async () => { + beforeEach(async () => { const daily = { text: 'test daily', type: 'daily', @@ -989,116 +989,116 @@ describe('cron', () => { stubbedStatsComputed.returns(Object.assign(statsComputedRes, { con: 1 })); }); - afterEach(() => { + afterEach(async () => { common.statsComputed.restore(); }); - it('computes isDue', () => { + it('computes isDue', async () => { tasksByType.dailys[0].frequency = 'daily'; tasksByType.dailys[0].everyX = 5; tasksByType.dailys[0].startDate = moment().add(1, 'days').toDate(); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(tasksByType.dailys[0].isDue).to.be.false; }); - it('computes isDue when user is sleeping', () => { + it('computes isDue when user is sleeping', async () => { user.preferences.sleep = true; tasksByType.dailys[0].frequency = 'daily'; tasksByType.dailys[0].everyX = 5; tasksByType.dailys[0].startDate = moment().toDate(); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(tasksByType.dailys[0].isDue).to.exist; }); - it('computes nextDue', () => { + it('computes nextDue', async () => { tasksByType.dailys[0].frequency = 'daily'; tasksByType.dailys[0].everyX = 5; tasksByType.dailys[0].startDate = moment().add(1, 'days').toDate(); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(tasksByType.dailys[0].nextDue.length).to.eql(6); }); - it('should add history', () => { - cron({ + it('should add history', async () => { + await cron({ user, tasksByType, daysMissed, analytics, }); expect(tasksByType.dailys[0].history).to.be.lengthOf(1); }); - it('should set tasks completed to false', () => { + it('should set tasks completed to false', async () => { tasksByType.dailys[0].completed = true; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(tasksByType.dailys[0].completed).to.be.false; }); - it('should set tasks completed to false when user is sleeping', () => { + it('should set tasks completed to false when user is sleeping', async () => { user.preferences.sleep = true; tasksByType.dailys[0].completed = true; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(tasksByType.dailys[0].completed).to.be.false; }); - it('should reset task checklist for completed dailys', () => { + it('should reset task checklist for completed dailys', async () => { tasksByType.dailys[0].checklist.push({ title: 'test', completed: false }); tasksByType.dailys[0].completed = true; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(tasksByType.dailys[0].checklist[0].completed).to.be.false; }); - it('should reset task checklist for completed dailys when user is sleeping', () => { + it('should reset task checklist for completed dailys when user is sleeping', async () => { user.preferences.sleep = true; tasksByType.dailys[0].checklist.push({ title: 'test', completed: false }); tasksByType.dailys[0].completed = true; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(tasksByType.dailys[0].checklist[0].completed).to.be.false; }); - it('should reset task checklist for dailys with scheduled misses', () => { + it('should reset task checklist for dailys with scheduled misses', async () => { daysMissed = 10; tasksByType.dailys[0].checklist.push({ title: 'test', completed: false }); tasksByType.dailys[0].startDate = moment(new Date()).subtract({ days: 1 }); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(tasksByType.dailys[0].checklist[0].completed).to.be.false; }); - it('should do damage for missing a daily', () => { + it('should do damage for missing a daily', async () => { daysMissed = 1; const hpBefore = user.stats.hp; tasksByType.dailys[0].startDate = moment(new Date()).subtract({ days: 1 }); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.stats.hp).to.be.lessThan(hpBefore); }); - it('should not do damage for missing a daily when user is sleeping', () => { + it('should not do damage for missing a daily when user is sleeping', async () => { user.preferences.sleep = true; daysMissed = 1; const hpBefore = user.stats.hp; tasksByType.dailys[0].startDate = moment(new Date()).subtract({ days: 1 }); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.stats.hp).to.equal(hpBefore); }); - it('should not do damage for missing a daily when CRON_SAFE_MODE is set', () => { + it('should not do damage for missing a daily when CRON_SAFE_MODE is set', async () => { sandbox.stub(nconf, 'get').withArgs('CRON_SAFE_MODE').returns('true'); const cronOverride = requireAgain(pathToCronLib).cron; @@ -1113,24 +1113,24 @@ describe('cron', () => { expect(user.stats.hp).to.equal(hpBefore); }); - it('should not do damage for missing a daily if user stealth buff is greater than or equal to days missed', () => { + it('should not do damage for missing a daily if user stealth buff is greater than or equal to days missed', async () => { daysMissed = 1; const hpBefore = user.stats.hp; user.stats.buffs.stealth = 2; tasksByType.dailys[0].startDate = moment(new Date()).subtract({ days: 1 }); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.stats.hp).to.equal(hpBefore); }); - it('should do less damage for missing a daily with partial completion', () => { + it('should do less damage for missing a daily with partial completion', async () => { daysMissed = 1; let hpBefore = user.stats.hp; tasksByType.dailys[0].startDate = moment(new Date()).subtract({ days: 1 }); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); const hpDifferenceOfFullyIncompleteDaily = hpBefore - user.stats.hp; @@ -1138,7 +1138,7 @@ describe('cron', () => { hpBefore = user.stats.hp; tasksByType.dailys[0].checklist.push({ title: 'test', completed: true }); tasksByType.dailys[0].checklist.push({ title: 'test2', completed: false }); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); const hpDifferenceOfPartiallyIncompleteDaily = hpBefore - user.stats.hp; @@ -1147,30 +1147,30 @@ describe('cron', () => { .to.be.lessThan(hpDifferenceOfFullyIncompleteDaily); }); - it('should decrement quest.progress.down for missing a daily', () => { + it('should decrement quest.progress.down for missing a daily', async () => { daysMissed = 1; tasksByType.dailys[0].startDate = moment(new Date()).subtract({ days: 1 }); - const progress = cron({ + const progress = await cron({ user, tasksByType, daysMissed, analytics, }); expect(progress.down).to.equal(-1); }); - it('should not decrement quest.progress.down for missing a daily when user is sleeping', () => { + it('should not decrement quest.progress.down for missing a daily when user is sleeping', async () => { user.preferences.sleep = true; daysMissed = 1; tasksByType.dailys[0].startDate = moment(new Date()).subtract({ days: 1 }); - const progress = cron({ + const progress = await cron({ user, tasksByType, daysMissed, analytics, }); expect(progress.down).to.equal(0); }); - it('should do damage for only yesterday\'s dailies', () => { + it('should do damage for only yesterday\'s dailies', async () => { daysMissed = 3; tasksByType.dailys[0].startDate = moment(new Date()).subtract({ days: 1 }); @@ -1184,7 +1184,7 @@ describe('cron', () => { tasksByType.dailys[1].everyX = 2; tasksByType.dailys[1].frequency = 'daily'; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1192,8 +1192,8 @@ describe('cron', () => { }); }); - describe('habits', () => { - beforeEach(() => { + describe('habits', async () => { + beforeEach(async () => { const habit = { text: 'test habit', type: 'habit', @@ -1204,53 +1204,53 @@ describe('cron', () => { tasksByType.habits.push(task); }); - it('should decrement only up value', () => { + it('should decrement only up value', async () => { tasksByType.habits[0].value = 1; tasksByType.habits[0].down = false; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(tasksByType.habits[0].value).to.be.lessThan(1); }); - it('should decrement only down value', () => { + it('should decrement only down value', async () => { tasksByType.habits[0].value = 1; tasksByType.habits[0].up = false; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(tasksByType.habits[0].value).to.be.lessThan(1); }); - it('should do nothing to habits with both up and down', () => { + it('should do nothing to habits with both up and down', async () => { tasksByType.habits[0].value = 1; tasksByType.habits[0].up = true; tasksByType.habits[0].down = true; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(tasksByType.habits[0].value).to.equal(1); }); - describe('counters', () => { + describe('counters', async () => { const notStartOfWeekOrMonth = new Date(2016, 9, 28).getTime(); // a Friday - beforeEach(() => { + beforeEach(async () => { // Replace system clocks so we can get predictable results clock = sinon.useFakeTimers(notStartOfWeekOrMonth); }); - it('should reset a daily habit counter each day', () => { + it('should reset a daily habit counter each day', async () => { tasksByType.habits[0].counterUp = 1; tasksByType.habits[0].counterDown = 1; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1258,12 +1258,12 @@ describe('cron', () => { expect(tasksByType.habits[0].counterDown).to.equal(0); }); - it('should reset habit counters even if user is sleeping', () => { + it('should reset habit counters even if user is sleeping', async () => { user.preferences.sleep = true; tasksByType.habits[0].counterUp = 1; tasksByType.habits[0].counterDown = 1; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1271,13 +1271,13 @@ describe('cron', () => { expect(tasksByType.habits[0].counterDown).to.equal(0); }); - it('should reset a weekly habit counter each Monday', () => { + it('should reset a weekly habit counter each Monday', async () => { tasksByType.habits[0].frequency = 'weekly'; tasksByType.habits[0].counterUp = 1; tasksByType.habits[0].counterDown = 1; // should not reset - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1286,7 +1286,7 @@ describe('cron', () => { // should reset daysMissed = 8; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1294,7 +1294,7 @@ describe('cron', () => { expect(tasksByType.habits[0].counterDown).to.equal(0); }); - it('should reset a weekly habit counter with custom daily start', () => { + it('should reset a weekly habit counter with custom daily start', async () => { clock.restore(); // Server clock: Monday 12am UTC @@ -1310,7 +1310,7 @@ describe('cron', () => { daysMissed = 1; // should not reset - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1324,7 +1324,7 @@ describe('cron', () => { clock = sinon.useFakeTimers(monday); // should reset after user CDS - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1332,7 +1332,7 @@ describe('cron', () => { expect(tasksByType.habits[0].counterDown).to.equal(0); }); - it('should not reset a weekly habit counter when server tz is Monday but user\'s tz is Tuesday', () => { + it('should not reset a weekly habit counter when server tz is Monday but user\'s tz is Tuesday', async () => { clock.restore(); // Server clock: Monday 11pm UTC @@ -1348,7 +1348,7 @@ describe('cron', () => { daysMissed = 1; // should not reset - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1358,7 +1358,7 @@ describe('cron', () => { // User missed one cron, which will subtract User clock back to Monday 1am UTC + 2 // should reset daysMissed = 2; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1366,7 +1366,7 @@ describe('cron', () => { expect(tasksByType.habits[0].counterDown).to.equal(0); }); - it('should reset a weekly habit counter when server tz is Sunday but user\'s tz is Monday', () => { + it('should reset a weekly habit counter when server tz is Sunday but user\'s tz is Monday', async () => { clock.restore(); // Server clock: Sunday 11pm UTC @@ -1382,7 +1382,7 @@ describe('cron', () => { daysMissed = 1; // should reset - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1390,7 +1390,7 @@ describe('cron', () => { expect(tasksByType.habits[0].counterDown).to.equal(0); }); - it('should not reset a weekly habit counter when server tz is Monday but user\'s tz is Sunday', () => { + it('should not reset a weekly habit counter when server tz is Monday but user\'s tz is Sunday', async () => { clock.restore(); // Server clock: Monday 2am UTC @@ -1406,7 +1406,7 @@ describe('cron', () => { daysMissed = 1; // should not reset - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1414,13 +1414,13 @@ describe('cron', () => { expect(tasksByType.habits[0].counterDown).to.equal(1); }); - it('should reset a monthly habit counter the first day of each month', () => { + it('should reset a monthly habit counter the first day of each month', async () => { tasksByType.habits[0].frequency = 'monthly'; tasksByType.habits[0].counterUp = 1; tasksByType.habits[0].counterDown = 1; // should not reset - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1429,7 +1429,7 @@ describe('cron', () => { // should reset daysMissed = 32; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1437,7 +1437,7 @@ describe('cron', () => { expect(tasksByType.habits[0].counterDown).to.equal(0); }); - it('should reset a monthly habit counter when server tz is last day of month but user tz is first day of the month', () => { + it('should reset a monthly habit counter when server tz is last day of month but user tz is first day of the month', async () => { clock.restore(); daysMissed = 0; @@ -1454,7 +1454,7 @@ describe('cron', () => { daysMissed = 1; // should reset - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1462,7 +1462,7 @@ describe('cron', () => { expect(tasksByType.habits[0].counterDown).to.equal(0); }); - it('should not reset a monthly habit counter when server tz is first day of month but user tz is 2nd day of the month', () => { + it('should not reset a monthly habit counter when server tz is first day of month but user tz is 2nd day of the month', async () => { clock.restore(); // Server clock: 5/1/17 11pm UTC @@ -1478,7 +1478,7 @@ describe('cron', () => { daysMissed = 1; // should not reset - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1488,7 +1488,7 @@ describe('cron', () => { // User missed one day, which will subtract User clock back to 5/1/17 2am UTC + 3 // should reset daysMissed = 2; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1498,8 +1498,8 @@ describe('cron', () => { }); }); - describe('perfect day', () => { - beforeEach(() => { + describe('perfect day', async () => { + beforeEach(async () => { const daily = { text: 'test daily', type: 'daily', @@ -1514,14 +1514,14 @@ describe('cron', () => { stubbedStatsComputed.returns(Object.assign(statsComputedRes, { con: 1 })); }); - afterEach(() => { + afterEach(async () => { common.statsComputed.restore(); }); - it('stores a new entry in user.history.exp', () => { + it('stores a new entry in user.history.exp', async () => { user.stats.lvl = 2; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1529,38 +1529,38 @@ describe('cron', () => { expect(user.history.exp[0].value).to.equal(25); }); - it('increments perfect day achievement if all (at least 1) due dailies were completed', () => { + it('increments perfect day achievement if all (at least 1) due dailies were completed', async () => { daysMissed = 1; tasksByType.dailys[0].completed = true; tasksByType.dailys[0].startDate = moment(new Date()).subtract({ days: 1 }); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.achievements.perfect).to.equal(1); }); - it('does not increment perfect day achievement if no due dailies', () => { + it('does not increment perfect day achievement if no due dailies', async () => { daysMissed = 1; tasksByType.dailys[0].completed = true; tasksByType.dailys[0].startDate = moment(new Date()).add({ days: 1 }); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.achievements.perfect).to.equal(0); }); - it('gives perfect day buff if all (at least 1) due dailies were completed', () => { + it('gives perfect day buff if all (at least 1) due dailies were completed', async () => { daysMissed = 1; tasksByType.dailys[0].completed = true; tasksByType.dailys[0].startDate = moment(new Date()).subtract({ days: 1 }); const previousBuffs = user.stats.buffs.toObject(); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1570,7 +1570,7 @@ describe('cron', () => { expect(user.stats.buffs.con).to.be.greaterThan(previousBuffs.con); }); - it('gives perfect day buff if all (at least 1) due dailies were completed when user is sleeping', () => { + it('gives perfect day buff if all (at least 1) due dailies were completed when user is sleeping', async () => { user.preferences.sleep = true; daysMissed = 1; tasksByType.dailys[0].completed = true; @@ -1578,7 +1578,7 @@ describe('cron', () => { const previousBuffs = user.stats.buffs.toObject(); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1588,7 +1588,7 @@ describe('cron', () => { expect(user.stats.buffs.con).to.be.greaterThan(previousBuffs.con); }); - it('clears buffs if user does not have a perfect day (no due dailys)', () => { + it('clears buffs if user does not have a perfect day (no due dailys)', async () => { daysMissed = 1; tasksByType.dailys[0].completed = true; tasksByType.dailys[0].startDate = moment(new Date()).add({ days: 1 }); @@ -1602,7 +1602,7 @@ describe('cron', () => { streaks: true, }; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1614,7 +1614,7 @@ describe('cron', () => { expect(user.stats.buffs.streaks).to.be.false; }); - it('clears buffs if user does not have a perfect day (no due dailys) when user is sleeping', () => { + it('clears buffs if user does not have a perfect day (no due dailys) when user is sleeping', async () => { user.preferences.sleep = true; daysMissed = 1; tasksByType.dailys[0].completed = true; @@ -1629,7 +1629,7 @@ describe('cron', () => { streaks: true, }; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1641,7 +1641,7 @@ describe('cron', () => { expect(user.stats.buffs.streaks).to.be.false; }); - it('clears buffs if user does not have a perfect day (at least one due daily not completed)', () => { + it('clears buffs if user does not have a perfect day (at least one due daily not completed)', async () => { daysMissed = 1; tasksByType.dailys[0].completed = false; tasksByType.dailys[0].startDate = moment(new Date()).subtract({ days: 1 }); @@ -1655,7 +1655,7 @@ describe('cron', () => { streaks: true, }; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1667,7 +1667,7 @@ describe('cron', () => { expect(user.stats.buffs.streaks).to.be.false; }); - it('clears buffs if user does not have a perfect day (at least one due daily not completed) when user is sleeping', () => { + it('clears buffs if user does not have a perfect day (at least one due daily not completed) when user is sleeping', async () => { user.preferences.sleep = true; daysMissed = 1; tasksByType.dailys[0].completed = false; @@ -1682,7 +1682,7 @@ describe('cron', () => { streaks: true, }; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1694,7 +1694,7 @@ describe('cron', () => { expect(user.stats.buffs.streaks).to.be.false; }); - it('always grants a perfect day buff when CRON_SAFE_MODE is set', () => { + it('always grants a perfect day buff when CRON_SAFE_MODE is set', async () => { sandbox.stub(nconf, 'get').withArgs('CRON_SAFE_MODE').returns('true'); const cronOverride = requireAgain(pathToCronLib).cron; daysMissed = 1; @@ -1713,7 +1713,7 @@ describe('cron', () => { expect(user.stats.buffs.con).to.be.greaterThan(previousBuffs.con); }); - it('always grants a perfect day buff when CRON_SAFE_MODE is set when user is sleeping', () => { + it('always grants a perfect day buff when CRON_SAFE_MODE is set when user is sleeping', async () => { user.preferences.sleep = true; sandbox.stub(nconf, 'get').withArgs('CRON_SAFE_MODE').returns('true'); const cronOverride = requireAgain(pathToCronLib).cron; @@ -1734,15 +1734,15 @@ describe('cron', () => { }); }); - describe('adding mp', () => { - it('should add mp to user', () => { + describe('adding mp', async () => { + it('should add mp to user', async () => { const statsComputedRes = common.statsComputed(user); const stubbedStatsComputed = sinon.stub(common, 'statsComputed'); const mpBefore = user.stats.mp; tasksByType.dailys[0].completed = true; stubbedStatsComputed.returns(Object.assign(statsComputedRes, { maxMP: 100 })); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.stats.mp).to.be.greaterThan(mpBefore); @@ -1750,7 +1750,7 @@ describe('cron', () => { common.statsComputed.restore(); }); - it('should not add mp to user when user is sleeping', () => { + it('should not add mp to user when user is sleeping', async () => { const statsComputedRes = common.statsComputed(user); const stubbedStatsComputed = sinon.stub(common, 'statsComputed'); @@ -1758,7 +1758,7 @@ describe('cron', () => { const mpBefore = user.stats.mp; tasksByType.dailys[0].completed = true; stubbedStatsComputed.returns(Object.assign(statsComputedRes, { maxMP: 100 })); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.stats.mp).to.equal(mpBefore); @@ -1766,12 +1766,12 @@ describe('cron', () => { common.statsComputed.restore(); }); - it('set user\'s mp to statsComputed.maxMP when user.stats.mp is greater', () => { + it('set user\'s mp to statsComputed.maxMP when user.stats.mp is greater', async () => { const statsComputedRes = common.statsComputed(user); const stubbedStatsComputed = sinon.stub(common, 'statsComputed'); user.stats.mp = 120; stubbedStatsComputed.returns(Object.assign(statsComputedRes, { maxMP: 100 })); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.stats.mp).to.equal(common.statsComputed(user).maxMP); @@ -1780,8 +1780,8 @@ describe('cron', () => { }); }); - describe('quest progress', () => { - beforeEach(() => { + describe('quest progress', async () => { + beforeEach(async () => { const daily = { text: 'test daily', type: 'daily', @@ -1799,12 +1799,12 @@ describe('cron', () => { tasksByType.dailys[0].startDate = moment(new Date()).subtract({ days: 1 }); }); - afterEach(() => { + afterEach(async () => { common.statsComputed.restore(); }); - it('resets user progress', () => { - cron({ + it('resets user progress', async () => { + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.party.quest.progress.up).to.equal(0); @@ -1812,16 +1812,16 @@ describe('cron', () => { expect(user.party.quest.progress.collectedItems).to.equal(0); }); - it('applies the user progress', () => { - const progress = cron({ + it('applies the user progress', async () => { + const progress = await cron({ user, tasksByType, daysMissed, analytics, }); expect(progress.down).to.equal(-1); }); }); - describe('notifications', () => { - it('adds a user notification', () => { + describe('notifications', async () => { + it('adds a user notification', async () => { const mpBefore = user.stats.mp; tasksByType.dailys[0].completed = true; @@ -1833,7 +1833,7 @@ describe('cron', () => { const hpBefore = user.stats.hp; tasksByType.dailys[0].startDate = moment(new Date()).subtract({ days: 1 }); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1847,7 +1847,7 @@ describe('cron', () => { common.statsComputed.restore(); }); - it('condenses multiple notifications into one', () => { + it('condenses multiple notifications into one', async () => { const mpBefore1 = user.stats.mp; tasksByType.dailys[0].completed = true; @@ -1859,7 +1859,7 @@ describe('cron', () => { const hpBefore1 = user.stats.hp; tasksByType.dailys[0].startDate = moment(new Date()).subtract({ days: 1 }); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1876,7 +1876,7 @@ describe('cron', () => { user.lastCron = moment(new Date()).subtract({ days: 2 }); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1892,10 +1892,10 @@ describe('cron', () => { }); }); - describe('private messages', () => { + describe('private messages', async () => { let lastMessageId; - beforeEach(() => { + beforeEach(async () => { const maxPMs = 200; for (let index = 0; index < maxPMs - 1; index += 1) { const messageId = common.uuid(); @@ -1921,35 +1921,35 @@ describe('cron', () => { }); }); - describe('login incentives', () => { - it('increments incentive counter each cron', () => { - cron({ + describe('login incentives', async () => { + it('increments incentive counter each cron', async () => { + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.loginIncentives).to.eql(1); user.lastCron = moment(new Date()).subtract({ days: 1 }); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.loginIncentives).to.eql(2); }); - it('pushes a notification of the day\'s incentive each cron', () => { - cron({ + it('pushes a notification of the day\'s incentive each cron', async () => { + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.notifications.length).to.be.greaterThan(1); expect(user.notifications[0].type).to.eql('LOGIN_INCENTIVE'); }); - it('replaces previous notifications', () => { - cron({ + it('replaces previous notifications', async () => { + await cron({ user, tasksByType, daysMissed, analytics, }); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); @@ -1958,24 +1958,24 @@ describe('cron', () => { expect(filteredNotifications.length).to.equal(1); }); - it('increments loginIncentives by 1 even if days are skipped in between', () => { + it('increments loginIncentives by 1 even if days are skipped in between', async () => { daysMissed = 3; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.loginIncentives).to.eql(1); }); - it('increments loginIncentives by 1 even if user is sleeping', () => { + it('increments loginIncentives by 1 even if user is sleeping', async () => { user.preferences.sleep = true; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.loginIncentives).to.eql(1); }); - it('awards user bard robes if login incentive is 1', () => { - cron({ + it('awards user bard robes if login incentive is 1', async () => { + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.loginIncentives).to.eql(1); @@ -1983,9 +1983,9 @@ describe('cron', () => { expect(user.notifications[0].type).to.eql('LOGIN_INCENTIVE'); }); - it('awards user incentive backgrounds if login incentive is 2', () => { + it('awards user incentive backgrounds if login incentive is 2', async () => { user.loginIncentives = 1; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.loginIncentives).to.eql(2); @@ -1997,9 +1997,9 @@ describe('cron', () => { expect(user.notifications[0].type).to.eql('LOGIN_INCENTIVE'); }); - it('awards user Bard Hat if login incentive is 3', () => { + it('awards user Bard Hat if login incentive is 3', async () => { user.loginIncentives = 2; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.loginIncentives).to.eql(3); @@ -2007,9 +2007,9 @@ describe('cron', () => { expect(user.notifications[0].type).to.eql('LOGIN_INCENTIVE'); }); - it('awards user RoyalPurple Hatching Potion if login incentive is 4', () => { + it('awards user RoyalPurple Hatching Potion if login incentive is 4', async () => { user.loginIncentives = 3; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.loginIncentives).to.eql(4); @@ -2017,9 +2017,9 @@ describe('cron', () => { expect(user.notifications[0].type).to.eql('LOGIN_INCENTIVE'); }); - it('awards user a Chocolate, Meat and Pink Contton Candy if login incentive is 5', () => { + it('awards user a Chocolate, Meat and Pink Contton Candy if login incentive is 5', async () => { user.loginIncentives = 4; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.loginIncentives).to.eql(5); @@ -2031,9 +2031,9 @@ describe('cron', () => { expect(user.notifications[0].type).to.eql('LOGIN_INCENTIVE'); }); - it('awards user moon quest if login incentive is 7', () => { + it('awards user moon quest if login incentive is 7', async () => { user.loginIncentives = 6; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.loginIncentives).to.eql(7); @@ -2041,9 +2041,9 @@ describe('cron', () => { expect(user.notifications[0].type).to.eql('LOGIN_INCENTIVE'); }); - it('awards user RoyalPurple Hatching Potion if login incentive is 10', () => { + it('awards user RoyalPurple Hatching Potion if login incentive is 10', async () => { user.loginIncentives = 9; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.loginIncentives).to.eql(10); @@ -2051,9 +2051,9 @@ describe('cron', () => { expect(user.notifications[0].type).to.eql('LOGIN_INCENTIVE'); }); - it('awards user a Strawberry, Patato and Blue Contton Candy if login incentive is 14', () => { + it('awards user a Strawberry, Patato and Blue Contton Candy if login incentive is 14', async () => { user.loginIncentives = 13; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.loginIncentives).to.eql(14); @@ -2065,9 +2065,9 @@ describe('cron', () => { expect(user.notifications[0].type).to.eql('LOGIN_INCENTIVE'); }); - it('awards user a bard instrument if login incentive is 18', () => { + it('awards user a bard instrument if login incentive is 18', async () => { user.loginIncentives = 17; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.loginIncentives).to.eql(18); @@ -2075,9 +2075,9 @@ describe('cron', () => { expect(user.notifications[0].type).to.eql('LOGIN_INCENTIVE'); }); - it('awards user second moon quest if login incentive is 22', () => { + it('awards user second moon quest if login incentive is 22', async () => { user.loginIncentives = 21; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.loginIncentives).to.eql(22); @@ -2085,9 +2085,9 @@ describe('cron', () => { expect(user.notifications[0].type).to.eql('LOGIN_INCENTIVE'); }); - it('awards user a RoyalPurple hatching potion if login incentive is 26', () => { + it('awards user a RoyalPurple hatching potion if login incentive is 26', async () => { user.loginIncentives = 25; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.loginIncentives).to.eql(26); @@ -2095,9 +2095,9 @@ describe('cron', () => { expect(user.notifications[0].type).to.eql('LOGIN_INCENTIVE'); }); - it('awards user Fish, Milk, Rotten Meat and Honey if login incentive is 30', () => { + it('awards user Fish, Milk, Rotten Meat and Honey if login incentive is 30', async () => { user.loginIncentives = 29; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.loginIncentives).to.eql(30); @@ -2110,9 +2110,9 @@ describe('cron', () => { expect(user.notifications[0].type).to.eql('LOGIN_INCENTIVE'); }); - it('awards user a RoyalPurple hatching potion if login incentive is 35', () => { + it('awards user a RoyalPurple hatching potion if login incentive is 35', async () => { user.loginIncentives = 34; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.loginIncentives).to.eql(35); @@ -2120,9 +2120,9 @@ describe('cron', () => { expect(user.notifications[0].type).to.eql('LOGIN_INCENTIVE'); }); - it('awards user the third moon quest if login incentive is 40', () => { + it('awards user the third moon quest if login incentive is 40', async () => { user.loginIncentives = 39; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.loginIncentives).to.eql(40); @@ -2130,9 +2130,9 @@ describe('cron', () => { expect(user.notifications[0].type).to.eql('LOGIN_INCENTIVE'); }); - it('awards user a RoyalPurple hatching potion if login incentive is 45', () => { + it('awards user a RoyalPurple hatching potion if login incentive is 45', async () => { user.loginIncentives = 44; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.loginIncentives).to.eql(45); @@ -2140,9 +2140,9 @@ describe('cron', () => { expect(user.notifications[0].type).to.eql('LOGIN_INCENTIVE'); }); - it('awards user a saddle if login incentive is 50', () => { + it('awards user a saddle if login incentive is 50', async () => { user.loginIncentives = 49; - cron({ + await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.loginIncentives).to.eql(50); @@ -2152,11 +2152,11 @@ describe('cron', () => { }); }); -describe('recoverCron', () => { +describe('recoverCron', async () => { let locals; let status; let execStub; - beforeEach(() => { + beforeEach(async () => { execStub = sandbox.stub(); sandbox.stub(User, 'findOne').returns({ exec: execStub }); @@ -2176,7 +2176,7 @@ describe('recoverCron', () => { }; }); - afterEach(() => { + afterEach(async () => { sandbox.restore(); }); diff --git a/test/api/v4/members/GET-purchase_history.test.js b/test/api/v4/members/GET-purchase_history.test.js new file mode 100644 index 0000000000..99623a4561 --- /dev/null +++ b/test/api/v4/members/GET-purchase_history.test.js @@ -0,0 +1,38 @@ +import { + generateUser, + translate as t, +} from '../../../helpers/api-integration/v4'; + +describe('GET /members/:memberId/purchase-history', () => { + let user; + + before(async () => { + user = await generateUser({ + contributor: { admin: true }, + }); + }); + + it('validates req.params.memberId', async () => { + await expect(user.get('/members/invalidUUID/purchase-history')).to.eventually.be.rejected.and.eql({ + code: 400, + error: 'BadRequest', + message: t('invalidReqParams'), + }); + }); + + it('returns error if user is not admin', async () => { + const member = await generateUser(); + const nonAdmin = await generateUser(); + await expect(nonAdmin.get(`/members/${member._id}/purchase-history`)).to.eventually.be.rejected.and.eql({ + code: 401, + error: 'NotAuthorized', + message: t('noAdminAccess'), + }); + }); + + it('returns purchase history based on given user', async () => { + const member = await generateUser(); + const response = await user.get(`/members/${member._id}/purchase-history`); + expect(response.length).to.equal(0); + }); +}); diff --git a/test/common/ops/buy/buy.js b/test/common/ops/buy/buy.js index eed601e10a..739e7d7010 100644 --- a/test/common/ops/buy/buy.js +++ b/test/common/ops/buy/buy.js @@ -40,28 +40,27 @@ describe('shared.ops.buy', () => { analytics.track.restore(); }); - it('returns error when key is not provided', done => { + it('returns error when key is not provided', async () => { try { - buy(user); + await buy(user); } catch (err) { expect(err).to.be.an.instanceof(BadRequest); expect(err.message).to.equal(errorMessage('missingKeyParam')); - done(); } }); - it('recovers 15 hp', () => { + it('recovers 15 hp', async () => { user.stats.hp = 30; - buy(user, { params: { key: 'potion' } }, analytics); + await buy(user, { params: { key: 'potion' } }, analytics); expect(user.stats.hp).to.eql(45); expect(analytics.track).to.be.calledOnce; }); - it('adds equipment to inventory', () => { + it('adds equipment to inventory', async () => { user.stats.gp = 31; - buy(user, { params: { key: 'armor_warrior_1' } }); + await buy(user, { params: { key: 'armor_warrior_1' } }); expect(user.items.gear.owned).to.eql({ weapon_warrior_0: true, @@ -90,10 +89,10 @@ describe('shared.ops.buy', () => { }); }); - it('buys Steampunk Accessories Set', () => { + it('buys Steampunk Accessories Set', async () => { user.purchased.plan.consecutive.trinkets = 1; - buy(user, { + await buy(user, { params: { key: '301404', }, @@ -108,10 +107,10 @@ describe('shared.ops.buy', () => { expect(user.items.gear.owned).to.have.property('eyewear_mystery_301404', true); }); - it('buys a Quest scroll', () => { + it('buys a Quest scroll', async () => { user.stats.gp = 205; - buy(user, { + await buy(user, { params: { key: 'dilatoryDistress1', }, @@ -122,11 +121,11 @@ describe('shared.ops.buy', () => { expect(user.stats.gp).to.equal(5); }); - it('buys a special item', () => { + it('buys a special item', async () => { user.stats.gp = 11; const item = content.special.thankyou; - const [data, message] = buy(user, { + const [data, message] = await buy(user, { params: { key: 'thankyou', }, @@ -144,15 +143,15 @@ describe('shared.ops.buy', () => { })); }); - it('allows for bulk purchases', () => { + it('allows for bulk purchases', async () => { user.stats.hp = 30; - buy(user, { params: { key: 'potion' }, quantity: 2 }); + await buy(user, { params: { key: 'potion' }, quantity: 2 }); expect(user.stats.hp).to.eql(50); }); - it('errors if user supplies a non-numeric quantity', done => { + it('errors if user supplies a non-numeric quantity', async () => { try { - buy(user, { + await buy(user, { params: { key: 'dilatoryDistress1', }, @@ -162,13 +161,12 @@ describe('shared.ops.buy', () => { } catch (err) { expect(err).to.be.an.instanceof(BadRequest); expect(err.message).to.equal(errorMessage('invalidQuantity')); - done(); } }); - it('errors if user supplies a negative quantity', done => { + it('errors if user supplies a negative quantity', async () => { try { - buy(user, { + await buy(user, { params: { key: 'dilatoryDistress1', }, @@ -178,13 +176,12 @@ describe('shared.ops.buy', () => { } catch (err) { expect(err).to.be.an.instanceof(BadRequest); expect(err.message).to.equal(errorMessage('invalidQuantity')); - done(); } }); - it('errors if user supplies a decimal quantity', done => { + it('errors if user supplies a decimal quantity', async () => { try { - buy(user, { + await buy(user, { params: { key: 'dilatoryDistress1', }, @@ -194,7 +191,6 @@ describe('shared.ops.buy', () => { } catch (err) { expect(err).to.be.an.instanceof(BadRequest); expect(err.message).to.equal(errorMessage('invalidQuantity')); - done(); } }); }); diff --git a/test/common/ops/buy/buyArmoire.js b/test/common/ops/buy/buyArmoire.js index a3a79d8341..d9309086fc 100644 --- a/test/common/ops/buy/buyArmoire.js +++ b/test/common/ops/buy/buyArmoire.js @@ -33,7 +33,7 @@ describe('shared.ops.buyArmoire', () => { const YIELD_EXP = 0.9; const analytics = { track () {} }; - function buyArmoire (_user, _req, _analytics) { + async function buyArmoire (_user, _req, _analytics) { const buyOp = new BuyArmoireOperation(_user, _req, _analytics); return buyOp.purchase(); @@ -61,11 +61,11 @@ describe('shared.ops.buyArmoire', () => { }); context('failure conditions', () => { - it('does not open if user does not have enough gold', done => { + it('does not open if user does not have enough gold', async () => { user.stats.gp = 50; try { - buyArmoire(user); + await buyArmoire(user); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('messageNotEnoughGold')); @@ -74,17 +74,16 @@ describe('shared.ops.buyArmoire', () => { }); expect(user.items.food).to.be.empty; expect(user.stats.exp).to.eql(0); - done(); } }); }); context('non-gear awards', () => { - it('gives Experience', () => { + it('gives Experience', async () => { const previousExp = user.stats.exp; randomValFns.trueRandom.returns(YIELD_EXP); - buyArmoire(user); + await buyArmoire(user); expect(user.items.gear.owned).to.eql({ weapon_warrior_0: true }); expect(user.items.food).to.be.empty; @@ -92,12 +91,12 @@ describe('shared.ops.buyArmoire', () => { expect(user.stats.gp).to.equal(100); }); - it('gives food', () => { + it('gives food', async () => { const previousExp = user.stats.exp; randomValFns.trueRandom.returns(YIELD_FOOD); - buyArmoire(user); + await buyArmoire(user); expect(user.items.gear.owned).to.eql({ weapon_warrior_0: true }); expect(user.items.food).to.not.be.empty; @@ -105,12 +104,12 @@ describe('shared.ops.buyArmoire', () => { expect(user.stats.gp).to.equal(100); }); - it('does not give equipment if all equipment has been found', () => { + it('does not give equipment if all equipment has been found', async () => { randomValFns.trueRandom.returns(YIELD_EQUIPMENT); user.items.gear.owned = getFullArmoire(); user.stats.gp = 150; - buyArmoire(user); + await buyArmoire(user); expect(user.items.gear.owned).to.eql(getFullArmoire()); const armoireCount = count.remainingGearInSet(user.items.gear.owned, 'armoire'); @@ -122,13 +121,13 @@ describe('shared.ops.buyArmoire', () => { }); context('gear awards', () => { - it('always drops equipment the first time', () => { + it('always drops equipment the first time', async () => { delete user.flags.armoireOpened; randomValFns.trueRandom.returns(YIELD_EXP); expect(_.size(user.items.gear.owned)).to.equal(1); - buyArmoire(user); + await buyArmoire(user); expect(_.size(user.items.gear.owned)).to.equal(2); @@ -140,7 +139,7 @@ describe('shared.ops.buyArmoire', () => { expect(user.stats.gp).to.equal(100); }); - it('gives more equipment', () => { + it('gives more equipment', async () => { randomValFns.trueRandom.returns(YIELD_EQUIPMENT); user.items.gear.owned = { weapon_warrior_0: true, @@ -150,7 +149,7 @@ describe('shared.ops.buyArmoire', () => { expect(_.size(user.items.gear.owned)).to.equal(2); - buyArmoire(user, {}, analytics); + await buyArmoire(user, {}, analytics); expect(_.size(user.items.gear.owned)).to.equal(3); diff --git a/test/common/ops/buy/buyGem.js b/test/common/ops/buy/buyGem.js index 42741d677b..0ffdb131f7 100644 --- a/test/common/ops/buy/buyGem.js +++ b/test/common/ops/buy/buyGem.js @@ -11,7 +11,7 @@ import i18n from '../../../../website/common/script/i18n'; import { BuyGemOperation } from '../../../../website/common/script/ops/buy/buyGem'; import planGemLimits from '../../../../website/common/script/libs/planGemLimits'; -function buyGem (user, req, analytics) { +async function buyGem (user, req, analytics) { const buyOp = new BuyGemOperation(user, req, analytics); return buyOp.purchase(); @@ -44,8 +44,8 @@ describe('shared.ops.buyGem', () => { }); context('Gems', () => { - it('purchases gems', () => { - const [, message] = buyGem(user, { params: { type: 'gems', key: 'gem' } }, analytics); + it('purchases gems', async () => { + const [, message] = await buyGem(user, { params: { type: 'gems', key: 'gem' } }, analytics); expect(message).to.equal(i18n.t('plusGem', { count: 1 })); expect(user.balance).to.equal(userGemAmount + 0.25); @@ -54,8 +54,8 @@ describe('shared.ops.buyGem', () => { expect(analytics.track).to.be.calledOnce; }); - it('purchases gems with a different language than the default', () => { - const [, message] = buyGem(user, { params: { type: 'gems', key: 'gem' }, language: 'de' }); + it('purchases gems with a different language than the default', async () => { + const [, message] = await buyGem(user, { params: { type: 'gems', key: 'gem' }, language: 'de' }); expect(message).to.equal(i18n.t('plusGem', { count: 1 }, 'de')); expect(user.balance).to.equal(userGemAmount + 0.25); @@ -63,8 +63,8 @@ describe('shared.ops.buyGem', () => { expect(user.stats.gp).to.equal(goldPoints - planGemLimits.convRate); }); - it('makes bulk purchases of gems', () => { - const [, message] = buyGem(user, { + it('makes bulk purchases of gems', async () => { + const [, message] = await buyGem(user, { params: { type: 'gems', key: 'gem' }, quantity: 2, }); @@ -76,63 +76,58 @@ describe('shared.ops.buyGem', () => { }); context('Failure conditions', () => { - it('returns an error when key is not provided', done => { + it('returns an error when key is not provided', async () => { try { - buyGem(user, { params: { type: 'gems' } }); + await buyGem(user, { params: { type: 'gems' } }); } catch (err) { expect(err).to.be.an.instanceof(BadRequest); expect(err.message).to.equal(i18n.t('missingKeyParam')); - done(); } }); - it('prevents unsubscribed user from buying gems', done => { + it('prevents unsubscribed user from buying gems', async () => { delete user.purchased.plan.customerId; try { - buyGem(user, { params: { type: 'gems', key: 'gem' } }); + await buyGem(user, { params: { type: 'gems', key: 'gem' } }); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('mustSubscribeToPurchaseGems')); - done(); } }); - it('prevents user with not enough gold from buying gems', done => { + it('prevents user with not enough gold from buying gems', async () => { user.stats.gp = 15; try { - buyGem(user, { params: { type: 'gems', key: 'gem' } }); + await buyGem(user, { params: { type: 'gems', key: 'gem' } }); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('messageNotEnoughGold')); - done(); } }); - it('prevents user that have reached the conversion cap from buying gems', done => { + it('prevents user that have reached the conversion cap from buying gems', async () => { user.stats.gp = goldPoints; user.purchased.plan.gemsBought = gemsBought; try { - buyGem(user, { params: { type: 'gems', key: 'gem' } }); + await buyGem(user, { params: { type: 'gems', key: 'gem' } }); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('maxBuyGems', { convCap: planGemLimits.convCap })); - done(); } }); - it('prevents user from buying an invalid quantity', done => { + it('prevents user from buying an invalid quantity', async () => { user.stats.gp = goldPoints; user.purchased.plan.gemsBought = gemsBought; try { - buyGem(user, { params: { type: 'gems', key: 'gem' }, quantity: 'a' }); + await buyGem(user, { params: { type: 'gems', key: 'gem' }, quantity: 'a' }); } catch (err) { expect(err).to.be.an.instanceof(BadRequest); expect(err.message).to.equal(i18n.t('invalidQuantity')); - done(); } }); }); diff --git a/test/common/ops/buy/buyHealthPotion.js b/test/common/ops/buy/buyHealthPotion.js index 5ed2df7e19..b7449bb3d6 100644 --- a/test/common/ops/buy/buyHealthPotion.js +++ b/test/common/ops/buy/buyHealthPotion.js @@ -12,7 +12,7 @@ describe('shared.ops.buyHealthPotion', () => { let user; const analytics = { track () {} }; - function buyHealthPotion (_user, _req, _analytics) { + async function buyHealthPotion (_user, _req, _analytics) { const buyOp = new BuyHealthPotionOperation(_user, _req, _analytics); return buyOp.purchase(); @@ -40,83 +40,75 @@ describe('shared.ops.buyHealthPotion', () => { }); context('Potion', () => { - it('recovers 15 hp', () => { + it('recovers 15 hp', async () => { user.stats.hp = 30; - buyHealthPotion(user, {}, analytics); + await buyHealthPotion(user, {}, analytics); expect(user.stats.hp).to.eql(45); expect(analytics.track).to.be.calledOnce; }); - it('does not increase hp above 50', () => { + it('does not increase hp above 50', async () => { user.stats.hp = 45; - buyHealthPotion(user); + await buyHealthPotion(user); expect(user.stats.hp).to.eql(50); }); - it('deducts 25 gp', () => { + it('deducts 25 gp', async () => { user.stats.hp = 45; - buyHealthPotion(user); + await buyHealthPotion(user); expect(user.stats.gp).to.eql(175); }); - it('does not purchase if not enough gp', done => { + it('does not purchase if not enough gp', async () => { user.stats.hp = 45; user.stats.gp = 5; try { - buyHealthPotion(user); + await buyHealthPotion(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(); } }); - it('does not purchase if hp is full', done => { + it('does not purchase if hp is full', async () => { user.stats.hp = 50; user.stats.gp = 40; try { - buyHealthPotion(user); + await buyHealthPotion(user); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('messageHealthAlreadyMax')); expect(user.stats.hp).to.eql(50); expect(user.stats.gp).to.eql(40); - - done(); } }); - it('does not allow potion purchases when hp is zero', done => { + it('does not allow potion purchases when hp is zero', async () => { user.stats.hp = 0; user.stats.gp = 40; try { - buyHealthPotion(user); + await buyHealthPotion(user); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('messageHealthAlreadyMin')); expect(user.stats.hp).to.eql(0); expect(user.stats.gp).to.eql(40); - - done(); } }); - it('does not allow potion purchases when hp is negative', done => { + it('does not allow potion purchases when hp is negative', async () => { user.stats.hp = -8; user.stats.gp = 40; try { - buyHealthPotion(user); + await buyHealthPotion(user); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('messageHealthAlreadyMin')); expect(user.stats.hp).to.eql(-8); expect(user.stats.gp).to.eql(40); - - done(); } }); }); diff --git a/test/common/ops/buy/buyMarketGear.js b/test/common/ops/buy/buyMarketGear.js index 568fc03b3e..9b72bd50cc 100644 --- a/test/common/ops/buy/buyMarketGear.js +++ b/test/common/ops/buy/buyMarketGear.js @@ -13,7 +13,7 @@ import { import i18n from '../../../../website/common/script/i18n'; import errorMessage from '../../../../website/common/script/libs/errorMessage'; -function buyGear (user, req, analytics) { +async function buyGear (user, req, analytics) { const buyOp = new BuyMarketGearOperation(user, req, analytics); return buyOp.purchase(); @@ -57,10 +57,10 @@ describe('shared.ops.buyMarketGear', () => { }); context('Gear', () => { - it('adds equipment to inventory', () => { + it('adds equipment to inventory', async () => { user.stats.gp = 31; - buyGear(user, { params: { key: 'armor_warrior_1' } }, analytics); + await buyGear(user, { params: { key: 'armor_warrior_1' } }, analytics); expect(user.items.gear.owned).to.eql({ weapon_warrior_0: true, @@ -90,10 +90,10 @@ describe('shared.ops.buyMarketGear', () => { expect(analytics.track).to.be.calledOnce; }); - it('adds the onboarding achievement to the user and checks the onboarding status', () => { + it('adds the onboarding achievement to the user and checks the onboarding status', async () => { user.stats.gp = 31; - buyGear(user, { params: { key: 'armor_warrior_1' } }, analytics); + await buyGear(user, { params: { key: 'armor_warrior_1' } }, analytics); expect(user.addAchievement).to.be.calledOnce; expect(user.addAchievement).to.be.calledWith('purchasedEquipment'); @@ -102,36 +102,36 @@ describe('shared.ops.buyMarketGear', () => { expect(shared.onboarding.checkOnboardingStatus).to.be.calledWith(user); }); - it('does not add the onboarding achievement to the user if it\'s already been awarded', () => { + it('does not add the onboarding achievement to the user if it\'s already been awarded', async () => { user.stats.gp = 31; user.achievements.purchasedEquipment = true; - buyGear(user, { params: { key: 'armor_warrior_1' } }, analytics); + await buyGear(user, { params: { key: 'armor_warrior_1' } }, analytics); expect(user.addAchievement).to.not.be.called; }); - it('deducts gold from user', () => { + it('deducts gold from user', async () => { user.stats.gp = 31; - buyGear(user, { params: { key: 'armor_warrior_1' } }); + await 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', () => { + it('auto equips equipment if user has auto-equip preference turned on', async () => { user.stats.gp = 31; user.preferences.autoEquip = true; - buyGear(user, { params: { key: 'armor_warrior_1' } }); + await buyGear(user, { params: { key: 'armor_warrior_1' } }); expect(user.items.gear.equipped).to.have.property('armor', 'armor_warrior_1'); }); - it('updates the pinnedItems to the next item in the set if one exists', () => { + it('updates the pinnedItems to the next item in the set if one exists', async () => { user.stats.gp = 31; - buyGear(user, { params: { key: 'armor_warrior_1' } }); + await buyGear(user, { params: { key: 'armor_warrior_1' } }); expect(user.pinnedItems).to.deep.include({ type: 'marketGear', @@ -139,155 +139,147 @@ describe('shared.ops.buyMarketGear', () => { }); }); - it('buyGears equipment but does not auto-equip', () => { + it('buyGears equipment but does not auto-equip', async () => { user.stats.gp = 31; user.preferences.autoEquip = false; - buyGear(user, { params: { key: 'armor_warrior_1' } }); + await 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 => { + it('does not buyGear equipment twice', async () => { user.stats.gp = 62; - buyGear(user, { params: { key: 'armor_warrior_1' } }); + await buyGear(user, { params: { key: 'armor_warrior_1' } }); try { - buyGear(user, { params: { key: 'armor_warrior_1' } }); + await 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(); } }); - it('does not buy equipment of different class', done => { + it('does not buy equipment of different class', async () => { user.stats.gp = 82; user.stats.class = 'warrior'; try { - buyGear(user, { params: { key: 'weapon_special_winter2018Rogue' } }); + await buyGear(user, { params: { key: 'weapon_special_winter2018Rogue' } }); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('cannotBuyItem')); - done(); } }); - it('does not buy equipment in bulk', done => { + it('does not buy equipment in bulk', async () => { user.stats.gp = 82; try { - buyGear(user, { params: { key: 'armor_warrior_1' }, quantity: 3 }); + await buyGear(user, { params: { key: 'armor_warrior_1' }, quantity: 3 }); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('messageNotAbleToBuyInBulk')); - 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', () => { + xit('removes one-handed weapon and shield if auto-equip is on and a two-hander is bought', async () => { user.stats.gp = 100; user.preferences.autoEquip = true; - buyGear(user, { params: { key: 'shield_warrior_1' } }); + await buyGear(user, { params: { key: 'shield_warrior_1' } }); user.ops.equip({ params: { key: 'shield_warrior_1' } }); - buyGear(user, { params: { key: 'weapon_warrior_1' } }); + await buyGear(user, { params: { key: 'weapon_warrior_1' } }); user.ops.equip({ params: { key: 'weapon_warrior_1' } }); - buyGear(user, { params: { key: 'weapon_wizard_1' } }); + await 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', () => { + xit('buyGears two-handed equipment but does not automatically remove sword or shield', async () => { user.stats.gp = 100; user.preferences.autoEquip = false; - buyGear(user, { params: { key: 'shield_warrior_1' } }); + await buyGear(user, { params: { key: 'shield_warrior_1' } }); user.ops.equip({ params: { key: 'shield_warrior_1' } }); - buyGear(user, { params: { key: 'weapon_warrior_1' } }); + await buyGear(user, { params: { key: 'weapon_warrior_1' } }); user.ops.equip({ params: { key: 'weapon_warrior_1' } }); - buyGear(user, { params: { key: 'weapon_wizard_1' } }); + await 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 => { + it('does not buyGear equipment without enough Gold', async () => { user.stats.gp = 20; try { - buyGear(user, { params: { key: 'armor_warrior_1' } }); + await 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(); } }); - it('returns error when key is not provided', done => { + it('returns error when key is not provided', async () => { try { - buyGear(user); + await buyGear(user); } catch (err) { expect(err).to.be.an.instanceof(BadRequest); expect(err.message).to.equal(errorMessage('missingKeyParam')); - done(); } }); - it('returns error when item is not found', done => { + it('returns error when item is not found', async () => { const params = { key: 'armor_warrior_notExisting' }; try { - buyGear(user, { params }); + await buyGear(user, { params }); } catch (err) { expect(err).to.be.an.instanceof(NotFound); expect(err.message).to.equal(errorMessage('itemNotFound', params)); - done(); } }); - it('does not buyGear equipment without the previous equipment', done => { + it('does not buyGear equipment without the previous equipment', async () => { try { - buyGear(user, { params: { key: 'armor_warrior_2' } }); + await buyGear(user, { params: { key: 'armor_warrior_2' } }); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('previousGearNotOwned')); - done(); } }); - it('does not buyGear equipment if user does not own prior item in sequence', done => { + it('does not buyGear equipment if user does not own prior item in sequence', async () => { user.stats.gp = 200; try { - buyGear(user, { params: { key: 'armor_warrior_2' } }); + await buyGear(user, { params: { key: 'armor_warrior_2' } }); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('previousGearNotOwned')); expect(user.items.gear.owned).to.not.have.property('armor_warrior_2'); - done(); } }); - it('does buyGear equipment if item is a numbered special item user qualifies for', () => { + it('does buyGear equipment if item is a numbered special item user qualifies for', async () => { user.stats.gp = 200; user.items.gear.owned.head_special_2 = false; - buyGear(user, { params: { key: 'head_special_2' } }); + await buyGear(user, { params: { key: 'head_special_2' } }); expect(user.items.gear.owned).to.have.property('head_special_2', true); }); - it('does buyGear equipment if it is an armoire item that an user previously lost', () => { + it('does buyGear equipment if it is an armoire item that an user previously lost', async () => { user.stats.gp = 200; user.items.gear.owned.shield_armoire_ramHornShield = false; - buyGear(user, { params: { key: 'shield_armoire_ramHornShield' } }); + await buyGear(user, { params: { key: 'shield_armoire_ramHornShield' } }); expect(user.items.gear.owned).to.have.property('shield_armoire_ramHornShield', true); }); diff --git a/test/common/ops/buy/buyMysterySet.js b/test/common/ops/buy/buyMysterySet.js index b485f2f164..4363c67e73 100644 --- a/test/common/ops/buy/buyMysterySet.js +++ b/test/common/ops/buy/buyMysterySet.js @@ -35,18 +35,17 @@ describe('shared.ops.buyMysterySet', () => { context('Mystery Sets', () => { context('failure conditions', () => { - it('does not grant mystery sets without Mystic Hourglasses', done => { + it('does not grant mystery sets without Mystic Hourglasses', async () => { try { - buyMysterySet(user, { params: { key: '201501' } }); + await buyMysterySet(user, { params: { key: '201501' } }); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.eql(i18n.t('notEnoughHourglasses')); expect(user.items.gear.owned).to.have.property('weapon_warrior_0', true); - done(); } }); - it('does not grant mystery set that has already been purchased', done => { + it('does not grant mystery set that has already been purchased', async () => { user.purchased.plan.consecutive.trinkets = 1; user.items.gear.owned = { weapon_warrior_0: true, @@ -57,30 +56,28 @@ describe('shared.ops.buyMysterySet', () => { }; try { - buyMysterySet(user, { params: { key: '301404' } }); + await buyMysterySet(user, { params: { key: '301404' } }); } catch (err) { expect(err).to.be.an.instanceof(NotFound); expect(err.message).to.eql(i18n.t('mysterySetNotFound')); expect(user.purchased.plan.consecutive.trinkets).to.eql(1); - done(); } }); - it('returns error when key is not provided', done => { + it('returns error when key is not provided', async () => { try { - buyMysterySet(user); + await buyMysterySet(user); } catch (err) { expect(err).to.be.an.instanceof(BadRequest); expect(err.message).to.equal(errorMessage('missingKeyParam')); - done(); } }); }); context('successful purchases', () => { - it('buys Steampunk Accessories Set', () => { + it('buys Steampunk Accessories Set', async () => { user.purchased.plan.consecutive.trinkets = 1; - buyMysterySet(user, { params: { key: '301404' } }, analytics); + await buyMysterySet(user, { params: { key: '301404' } }, analytics); expect(user.purchased.plan.consecutive.trinkets).to.eql(0); expect(user.items.gear.owned).to.have.property('weapon_warrior_0', true); diff --git a/test/common/ops/buy/buyQuestGems.js b/test/common/ops/buy/buyQuestGems.js index d1c25b0832..17e1c54dde 100644 --- a/test/common/ops/buy/buyQuestGems.js +++ b/test/common/ops/buy/buyQuestGems.js @@ -13,7 +13,7 @@ describe('shared.ops.buyQuestGems', () => { const goldPoints = 40; const analytics = { track () {} }; - function buyQuest (_user, _req, _analytics) { + async function buyQuest (_user, _req, _analytics) { const buyOp = new BuyQuestWithGemOperation(_user, _req, _analytics); return buyOp.purchase(); @@ -44,19 +44,19 @@ describe('shared.ops.buyQuestGems', () => { user.pinnedItems.push({ type: 'quests', key: 'gryphon' }); }); - it('purchases quests', () => { + it('purchases quests', async () => { const key = 'gryphon'; - buyQuest(user, { params: { key } }); + await buyQuest(user, { params: { key } }); expect(user.items.quests[key]).to.equal(1); expect(pinnedGearUtils.removeItemByPath.notCalled).to.equal(true); }); - it('if a user\'s count of a quest scroll is negative, it will be reset to 0 before incrementing when they buy a new one.', () => { + it('if a user\'s count of a quest scroll is negative, it will be reset to 0 before incrementing when they buy a new one.', async () => { const key = 'dustbunnies'; user.items.quests[key] = -1; - buyQuest(user, { params: { key } }); + await buyQuest(user, { params: { key } }); expect(user.items.quests[key]).to.equal(1); expect(pinnedGearUtils.removeItemByPath.notCalled).to.equal(true); @@ -73,26 +73,25 @@ describe('shared.ops.buyQuestGems', () => { user.purchased.plan.customerId = 'customer-id'; }); - it('errors when user does not have enough gems', done => { + it('errors when user does not have enough gems', async () => { user.balance = 1; const key = 'gryphon'; try { - buyQuest(user, { + await buyQuest(user, { params: { key }, quantity: 2, }); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('notEnoughGems')); - done(); } }); - it('makes bulk purchases of quests', () => { + it('makes bulk purchases of quests', async () => { const key = 'gryphon'; - buyQuest(user, { + await buyQuest(user, { params: { key }, quantity: 3, }); diff --git a/test/common/ops/buy/buyQuestGold.js b/test/common/ops/buy/buyQuestGold.js index f50b00f1aa..4a13cda6ca 100644 --- a/test/common/ops/buy/buyQuestGold.js +++ b/test/common/ops/buy/buyQuestGold.js @@ -14,7 +14,7 @@ describe('shared.ops.buyQuest', () => { let user; const analytics = { track () {} }; - function buyQuest (_user, _req, _analytics) { + async function buyQuest (_user, _req, _analytics) { const buyOp = new BuyQuestWithGoldOperation(_user, _req, _analytics); return buyOp.purchase(); @@ -29,9 +29,9 @@ describe('shared.ops.buyQuest', () => { analytics.track.restore(); }); - it('buys a Quest scroll', () => { + it('buys a Quest scroll', async () => { user.stats.gp = 205; - buyQuest(user, { + await buyQuest(user, { params: { key: 'dilatoryDistress1', }, @@ -43,11 +43,11 @@ describe('shared.ops.buyQuest', () => { expect(analytics.track).to.be.calledOnce; }); - it('if a user\'s count of a quest scroll is negative, it will be reset to 0 before incrementing when they buy a new one.', () => { + it('if a user\'s count of a quest scroll is negative, it will be reset to 0 before incrementing when they buy a new one.', async () => { user.stats.gp = 205; const key = 'dilatoryDistress1'; user.items.quests[key] = -1; - buyQuest(user, { + await buyQuest(user, { params: { key }, }, analytics); expect(user.items.quests[key]).to.equal(1); @@ -55,14 +55,14 @@ describe('shared.ops.buyQuest', () => { expect(analytics.track).to.be.calledOnce; }); - it('buys a Quest scroll with the right quantity if a string is passed for quantity', () => { + it('buys a Quest scroll with the right quantity if a string is passed for quantity', async () => { user.stats.gp = 1000; - buyQuest(user, { + await buyQuest(user, { params: { key: 'dilatoryDistress1', }, }, analytics); - buyQuest(user, { + await buyQuest(user, { params: { key: 'dilatoryDistress1', }, @@ -74,10 +74,10 @@ describe('shared.ops.buyQuest', () => { }); }); - it('does not buy a Quest scroll when an invalid quantity is passed', done => { + it('does not buy a Quest scroll when an invalid quantity is passed', async () => { user.stats.gp = 1000; try { - buyQuest(user, { + await buyQuest(user, { params: { key: 'dilatoryDistress1', }, @@ -88,14 +88,13 @@ describe('shared.ops.buyQuest', () => { expect(err.message).to.equal(i18n.t('invalidQuantity')); expect(user.items.quests).to.eql({}); expect(user.stats.gp).to.equal(1000); - done(); } }); - it('does not buy Quests without enough Gold', done => { + it('does not buy Quests without enough Gold', async () => { user.stats.gp = 1; try { - buyQuest(user, { + await buyQuest(user, { params: { key: 'dilatoryDistress1', }, @@ -105,14 +104,13 @@ describe('shared.ops.buyQuest', () => { expect(err.message).to.equal(i18n.t('messageNotEnoughGold')); expect(user.items.quests).to.eql({}); expect(user.stats.gp).to.equal(1); - done(); } }); - it('does not buy nonexistent Quests', done => { + it('does not buy nonexistent Quests', async () => { user.stats.gp = 9999; try { - buyQuest(user, { + await buyQuest(user, { params: { key: 'snarfblatter', }, @@ -122,13 +120,12 @@ describe('shared.ops.buyQuest', () => { expect(err.message).to.equal(errorMessage('questNotFound', { key: 'snarfblatter' })); expect(user.items.quests).to.eql({}); expect(user.stats.gp).to.equal(9999); - done(); } }); - it('does not buy the Mystery of the Masterclassers', done => { + it('does not buy the Mystery of the Masterclassers', async () => { try { - buyQuest(user, { + await buyQuest(user, { params: { key: 'lostMasterclasser1', }, @@ -137,14 +134,13 @@ describe('shared.ops.buyQuest', () => { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('questUnlockLostMasterclasser')); expect(user.items.quests).to.eql({}); - done(); } }); - it('does not buy Gem-premium Quests', done => { + it('does not buy Gem-premium Quests', async () => { user.stats.gp = 9999; try { - buyQuest(user, { + await buyQuest(user, { params: { key: 'kraken', }, @@ -154,23 +150,21 @@ describe('shared.ops.buyQuest', () => { expect(err.message).to.equal(i18n.t('questNotGoldPurchasable', { key: 'kraken' })); expect(user.items.quests).to.eql({}); expect(user.stats.gp).to.equal(9999); - done(); } }); - it('returns error when key is not provided', done => { + it('returns error when key is not provided', async () => { try { - buyQuest(user); + await buyQuest(user); } catch (err) { expect(err).to.be.an.instanceof(BadRequest); expect(err.message).to.equal(errorMessage('missingKeyParam')); - done(); } }); - it('does not buy a quest without completing previous quests', done => { + it('does not buy a quest without completing previous quests', async () => { try { - buyQuest(user, { + await buyQuest(user, { params: { key: 'dilatoryDistress3', }, @@ -179,7 +173,6 @@ describe('shared.ops.buyQuest', () => { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('mustComplete', { quest: 'dilatoryDistress2' })); expect(user.items.quests).to.eql({}); - done(); } }); }); diff --git a/test/common/ops/buy/buySpell.js b/test/common/ops/buy/buySpell.js index 83b8008756..5e49837a2d 100644 --- a/test/common/ops/buy/buySpell.js +++ b/test/common/ops/buy/buySpell.js @@ -15,7 +15,7 @@ describe('shared.ops.buySpecialSpell', () => { let user; const analytics = { track () {} }; - function buySpecialSpell (_user, _req, _analytics) { + async function buySpecialSpell (_user, _req, _analytics) { const buyOp = new BuySpellOperation(_user, _req, _analytics); return buyOp.purchase(); @@ -29,19 +29,18 @@ describe('shared.ops.buySpecialSpell', () => { analytics.track.restore(); }); - it('throws an error if params.key is missing', done => { + it('throws an error if params.key is missing', async () => { try { - buySpecialSpell(user); + await buySpecialSpell(user); } catch (err) { expect(err).to.be.an.instanceof(BadRequest); expect(err.message).to.equal(errorMessage('missingKeyParam')); - done(); } }); - it('throws an error if the spell doesn\'t exists', done => { + it('throws an error if the spell doesn\'t exists', async () => { try { - buySpecialSpell(user, { + await buySpecialSpell(user, { params: { key: 'notExisting', }, @@ -49,14 +48,13 @@ describe('shared.ops.buySpecialSpell', () => { } catch (err) { expect(err).to.be.an.instanceof(NotFound); expect(err.message).to.equal(errorMessage('spellNotFound', { spellId: 'notExisting' })); - done(); } }); - it('throws an error if the user doesn\'t have enough gold', done => { + it('throws an error if the user doesn\'t have enough gold', async () => { user.stats.gp = 1; try { - buySpecialSpell(user, { + await buySpecialSpell(user, { params: { key: 'thankyou', }, @@ -64,15 +62,14 @@ describe('shared.ops.buySpecialSpell', () => { } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('messageNotEnoughGold')); - done(); } }); - it('buys an item', () => { + it('buys an item', async () => { user.stats.gp = 11; const item = content.special.thankyou; - const [data, message] = buySpecialSpell(user, { + const [data, message] = await buySpecialSpell(user, { params: { key: 'thankyou', }, diff --git a/test/common/ops/buy/hourglassPurchase.js b/test/common/ops/buy/hourglassPurchase.js index a04ad429a3..b049e73c6c 100644 --- a/test/common/ops/buy/hourglassPurchase.js +++ b/test/common/ops/buy/hourglassPurchase.js @@ -15,7 +15,7 @@ describe('common.ops.hourglassPurchase', () => { let user; const analytics = { track () {} }; - function buyMount (_user, _req, _analytics) { + async function buyMount (_user, _req, _analytics) { const buyOp = new BuyHourglassMountOperation(_user, _req, _analytics); return buyOp.purchase(); @@ -31,116 +31,107 @@ describe('common.ops.hourglassPurchase', () => { }); context('failure conditions', () => { - it('return error when key is not provided', done => { + it('return error when key is not provided', async () => { try { - hourglassPurchase(user, { params: {} }); + await hourglassPurchase(user, { params: {} }); } catch (err) { expect(err).to.be.an.instanceof(BadRequest); expect(err.message).to.eql(errorMessage('missingKeyParam')); - done(); } }); - it('returns error when type is not provided', done => { + it('returns error when type is not provided', async () => { try { - hourglassPurchase(user, { params: { key: 'Base' } }); + await hourglassPurchase(user, { params: { key: 'Base' } }); } catch (err) { expect(err).to.be.an.instanceof(BadRequest); expect(err.message).to.eql(errorMessage('missingTypeParam')); - done(); } }); - it('returns error when inccorect type is provided', done => { + it('returns error when inccorect type is provided', async () => { try { - hourglassPurchase(user, { params: { type: 'notAType', key: 'MantisShrimp-Base' } }); + await hourglassPurchase(user, { params: { type: 'notAType', key: 'MantisShrimp-Base' } }); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.eql(i18n.t('typeNotAllowedHourglass', { allowedTypes: _.keys(content.timeTravelStable).toString() })); - done(); } }); - it('does not grant to pets without Mystic Hourglasses', done => { + it('does not grant to pets without Mystic Hourglasses', async () => { try { - hourglassPurchase(user, { params: { type: 'pets', key: 'MantisShrimp-Base' } }); + await hourglassPurchase(user, { params: { type: 'pets', key: 'MantisShrimp-Base' } }); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.eql(i18n.t('notEnoughHourglasses')); - done(); } }); - it('does not grant to mounts without Mystic Hourglasses', done => { + it('does not grant to mounts without Mystic Hourglasses', async () => { try { - buyMount(user, { params: { key: 'MantisShrimp-Base' } }); + await buyMount(user, { params: { key: 'MantisShrimp-Base' } }); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.eql(i18n.t('notEnoughHourglasses')); - done(); } }); - it('does not grant pet that is not part of the Time Travel Stable', done => { + it('does not grant pet that is not part of the Time Travel Stable', async () => { user.purchased.plan.consecutive.trinkets = 1; try { - hourglassPurchase(user, { params: { type: 'pets', key: 'Wolf-Veteran' } }); + await hourglassPurchase(user, { params: { type: 'pets', key: 'Wolf-Veteran' } }); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.eql(i18n.t('notAllowedHourglass')); - done(); } }); - it('does not grant mount that is not part of the Time Travel Stable', done => { + it('does not grant mount that is not part of the Time Travel Stable', async () => { user.purchased.plan.consecutive.trinkets = 1; try { - buyMount(user, { params: { key: 'Orca-Base' } }); + await buyMount(user, { params: { key: 'Orca-Base' } }); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.eql(i18n.t('notAllowedHourglass')); - done(); } }); - it('does not grant pet that has already been purchased', done => { + it('does not grant pet that has already been purchased', async () => { user.purchased.plan.consecutive.trinkets = 1; user.items.pets = { 'MantisShrimp-Base': true, }; try { - hourglassPurchase(user, { params: { type: 'pets', key: 'MantisShrimp-Base' } }); + await hourglassPurchase(user, { params: { type: 'pets', key: 'MantisShrimp-Base' } }); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.eql(i18n.t('petsAlreadyOwned')); - done(); } }); - it('does not grant mount that has already been purchased', done => { + it('does not grant mount that has already been purchased', async () => { user.purchased.plan.consecutive.trinkets = 1; user.items.mounts = { 'MantisShrimp-Base': true, }; try { - buyMount(user, { params: { key: 'MantisShrimp-Base' } }); + await buyMount(user, { params: { key: 'MantisShrimp-Base' } }); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.eql(i18n.t('mountsAlreadyOwned')); - done(); } }); }); context('successful purchases', () => { - it('buys a pet', () => { + it('buys a pet', async () => { user.purchased.plan.consecutive.trinkets = 2; - const [, message] = hourglassPurchase(user, { params: { type: 'pets', key: 'MantisShrimp-Base' } }, analytics); + const [, message] = await hourglassPurchase(user, { params: { type: 'pets', key: 'MantisShrimp-Base' } }, analytics); expect(message).to.eql(i18n.t('hourglassPurchase')); expect(user.purchased.plan.consecutive.trinkets).to.eql(1); @@ -148,10 +139,10 @@ describe('common.ops.hourglassPurchase', () => { expect(analytics.track).to.be.calledOnce; }); - it('buys a mount', () => { + it('buys a mount', async () => { user.purchased.plan.consecutive.trinkets = 2; - const [, message] = buyMount(user, { params: { key: 'MantisShrimp-Base' } }); + const [, message] = await buyMount(user, { params: { key: 'MantisShrimp-Base' } }); expect(message).to.eql(i18n.t('hourglassPurchase')); expect(user.purchased.plan.consecutive.trinkets).to.eql(1); expect(user.items.mounts).to.eql({ 'MantisShrimp-Base': true }); diff --git a/test/common/ops/buy/purchase.js b/test/common/ops/buy/purchase.js index a2759deac1..fa5f7c5473 100644 --- a/test/common/ops/buy/purchase.js +++ b/test/common/ops/buy/purchase.js @@ -33,118 +33,108 @@ describe('shared.ops.purchase', () => { }); context('failure conditions', () => { - it('returns an error when type is not provided', done => { + it('returns an error when type is not provided', async () => { try { - purchase(user, { params: {} }); + await purchase(user, { params: {} }); } catch (err) { expect(err).to.be.an.instanceof(BadRequest); expect(err.message).to.equal(i18n.t('typeRequired')); - done(); } }); - it('returns error when unknown type is provided', done => { + it('returns error when unknown type is provided', async () => { try { - purchase(user, { params: { type: 'randomType', key: 'gem' } }); + await purchase(user, { params: { type: 'randomType', key: 'gem' } }); } catch (err) { expect(err).to.be.an.instanceof(NotFound); expect(err.message).to.equal(i18n.t('notAccteptedType')); - done(); } }); - it('returns error when user attempts to purchase a piece of gear they own', done => { + it('returns error when user attempts to purchase a piece of gear they own', async () => { user.items.gear.owned['shield_rogue_1'] = true; // eslint-disable-line dot-notation try { - purchase(user, { params: { type: 'gear', key: 'shield_rogue_1' } }); + await purchase(user, { params: { type: 'gear', key: 'shield_rogue_1' } }); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('alreadyHave')); - done(); } }); - it('returns error when unknown item is requested', done => { + it('returns error when unknown item is requested', async () => { try { - purchase(user, { params: { type: 'gear', key: 'randomKey' } }); + await purchase(user, { params: { type: 'gear', key: 'randomKey' } }); } catch (err) { expect(err).to.be.an.instanceof(NotFound); expect(err.message).to.equal(i18n.t('contentKeyNotFound', { type: 'gear' })); - done(); } }); - it('returns error when user does not have permission to buy an item', done => { + it('returns error when user does not have permission to buy an item', async () => { try { - purchase(user, { params: { type: 'gear', key: 'eyewear_mystery_301405' } }); + await purchase(user, { params: { type: 'gear', key: 'eyewear_mystery_301405' } }); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('messageNotAvailable')); - done(); } }); - it('returns error when user does not have enough gems to buy an item', done => { + it('returns error when user does not have enough gems to buy an item', async () => { try { - purchase(user, { params: { type: 'gear', key: 'headAccessory_special_wolfEars' } }); + await purchase(user, { params: { type: 'gear', key: 'headAccessory_special_wolfEars' } }); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('notEnoughGems')); - done(); } }); - it('returns error when item is not found', done => { + it('returns error when item is not found', async () => { const params = { key: 'notExisting', type: 'food' }; try { - purchase(user, { params }); + await purchase(user, { params }); } catch (err) { expect(err).to.be.an.instanceof(NotFound); expect(err.message).to.equal(i18n.t('contentKeyNotFound', params)); - done(); } }); - it('returns error when user supplies a non-numeric quantity', done => { + it('returns error when user supplies a non-numeric quantity', async () => { const type = 'eggs'; const key = 'Wolf'; try { - purchase(user, { params: { type, key }, quantity: 'jamboree' }, analytics); + await purchase(user, { params: { type, key }, quantity: 'jamboree' }, analytics); } catch (err) { expect(err).to.be.an.instanceof(BadRequest); expect(err.message).to.equal(i18n.t('invalidQuantity')); - done(); } }); - it('returns error when user supplies a negative quantity', done => { + it('returns error when user supplies a negative quantity', async () => { const type = 'eggs'; const key = 'Wolf'; user.balance = 10; try { - purchase(user, { params: { type, key }, quantity: -2 }, analytics); + await purchase(user, { params: { type, key }, quantity: -2 }, analytics); } catch (err) { expect(err).to.be.an.instanceof(BadRequest); expect(err.message).to.equal(i18n.t('invalidQuantity')); - done(); } }); - it('returns error when user supplies a decimal quantity', done => { + it('returns error when user supplies a decimal quantity', async () => { const type = 'eggs'; const key = 'Wolf'; user.balance = 10; try { - purchase(user, { params: { type, key }, quantity: 2.9 }, analytics); + await purchase(user, { params: { type, key }, quantity: 2.9 }, analytics); } catch (err) { expect(err).to.be.an.instanceof(BadRequest); expect(err.message).to.equal(i18n.t('invalidQuantity')); - done(); } }); }); @@ -164,48 +154,48 @@ describe('shared.ops.purchase', () => { user.pinnedItems.push({ type: 'bundles', key: 'featheredFriends' }); }); - it('purchases eggs', () => { + it('purchases eggs', async () => { const type = 'eggs'; const key = 'Wolf'; - purchase(user, { params: { type, key } }, analytics); + await purchase(user, { params: { type, key } }, analytics); expect(user.items[type][key]).to.equal(1); expect(pinnedGearUtils.removeItemByPath.notCalled).to.equal(true); expect(analytics.track).to.be.calledOnce; }); - it('purchases hatchingPotions', () => { + it('purchases hatchingPotions', async () => { const type = 'hatchingPotions'; const key = 'Base'; - purchase(user, { params: { type, key } }); + await purchase(user, { params: { type, key } }); expect(user.items[type][key]).to.equal(1); expect(pinnedGearUtils.removeItemByPath.notCalled).to.equal(true); }); - it('purchases food', () => { + it('purchases food', async () => { const type = 'food'; const key = SEASONAL_FOOD; - purchase(user, { params: { type, key } }); + await purchase(user, { params: { type, key } }); expect(user.items[type][key]).to.equal(1); expect(pinnedGearUtils.removeItemByPath.notCalled).to.equal(true); }); - it('purchases gear', () => { + it('purchases gear', async () => { const type = 'gear'; const key = 'headAccessory_special_tigerEars'; - purchase(user, { params: { type, key } }); + await purchase(user, { params: { type, key } }); expect(user.items.gear.owned[key]).to.be.true; expect(pinnedGearUtils.removeItemByPath.calledOnce).to.equal(true); }); - it('purchases quest bundles', () => { + it('purchases quest bundles', async () => { const startingBalance = user.balance; const clock = sandbox.useFakeTimers(moment('2019-05-20').valueOf()); const type = 'bundles'; @@ -217,7 +207,7 @@ describe('shared.ops.purchase', () => { 'owl', ]; - purchase(user, { params: { type, key } }); + await purchase(user, { params: { type, key } }); forEach(questList, bundledKey => { expect(user.items.quests[bundledKey]).to.equal(1); @@ -240,28 +230,27 @@ describe('shared.ops.purchase', () => { user.purchased.plan.customerId = 'customer-id'; }); - it('errors when user does not have enough gems', done => { + it('errors when user does not have enough gems', async () => { user.balance = 1; const type = 'eggs'; const key = 'TigerCub'; try { - purchase(user, { + await purchase(user, { params: { type, key }, quantity: 2, }); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('notEnoughGems')); - done(); } }); - it('makes bulk purchases of eggs', () => { + it('makes bulk purchases of eggs', async () => { const type = 'eggs'; const key = 'TigerCub'; - purchase(user, { + await purchase(user, { params: { type, key }, quantity: 2, }); diff --git a/test/common/ops/changeClass.js b/test/common/ops/changeClass.js index 4b1d31ffd7..9046d0b895 100644 --- a/test/common/ops/changeClass.js +++ b/test/common/ops/changeClass.js @@ -19,51 +19,48 @@ describe('shared.ops.changeClass', () => { user.stats.flagSelected = false; }); - it('user is not level 10', done => { + it('user is not level 10', async () => { user.stats.lvl = 9; try { - changeClass(user, { query: { class: 'rogue' } }); + await await changeClass(user, { query: { class: 'rogue' } }); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('lvl10ChangeClass')); - done(); } }); - it('req.query.class is an invalid class', done => { + it('req.query.class is an invalid class', async () => { user.flags.classSelected = false; user.preferences.disableClasses = false; try { - changeClass(user, { query: { class: 'cellist' } }); + await changeClass(user, { query: { class: 'cellist' } }); } catch (err) { expect(err).to.be.an.instanceof(BadRequest); expect(err.message).to.equal(i18n.t('invalidClass')); - done(); } }); context('req.query.class is a valid class', () => { - it('errors if user.stats.flagSelected is true and user.balance < 0.75', done => { + it('errors if user.stats.flagSelected is true and user.balance < 0.75', async () => { user.flags.classSelected = true; user.preferences.disableClasses = false; user.balance = 0; try { - changeClass(user, { query: { class: 'rogue' } }); + await changeClass(user, { query: { class: 'rogue' } }); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('notEnoughGems')); - done(); } }); - it('changes class', () => { + it('changes class', async () => { user.stats.class = 'healer'; user.items.gear.owned.weapon_healer_3 = true; user.items.gear.equipped.weapon = 'weapon_healer_3'; - const [data] = changeClass(user, { query: { class: 'rogue' } }); + const [data] = await changeClass(user, { query: { class: 'rogue' } }); expect(data).to.eql({ preferences: user.preferences, stats: user.stats, @@ -81,7 +78,7 @@ describe('shared.ops.changeClass', () => { }); context('req.query.class is missing or user.stats.flagSelected is true', () => { - it('has user.preferences.disableClasses === true', () => { + it('has user.preferences.disableClasses === true', async () => { user.balance = 1; user.preferences.disableClasses = true; user.preferences.autoAllocate = true; @@ -92,7 +89,7 @@ describe('shared.ops.changeClass', () => { user.stats.int = 4; user.flags.classSelected = true; - const [data] = changeClass(user); + const [data] = await changeClass(user); expect(data).to.eql({ preferences: user.preferences, stats: user.stats, @@ -112,18 +109,17 @@ describe('shared.ops.changeClass', () => { }); context('has user.preferences.disableClasses !== true', () => { - it('and less than 3 gems', done => { + it('and less than 3 gems', async () => { user.balance = 0.5; try { - changeClass(user); + await changeClass(user); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('notEnoughGems')); - done(); } }); - it('and at least 3 gems', () => { + it('and at least 3 gems', async () => { user.balance = 1; user.stats.points = 45; user.stats.str = 1; @@ -132,7 +128,7 @@ describe('shared.ops.changeClass', () => { user.stats.int = 4; user.flags.classSelected = true; - const [data] = changeClass(user); + const [data] = await changeClass(user); expect(data).to.eql({ preferences: user.preferences, stats: user.stats, diff --git a/test/common/ops/rebirth.js b/test/common/ops/rebirth.js index 84b34dccc3..5193126c6a 100644 --- a/test/common/ops/rebirth.js +++ b/test/common/ops/rebirth.js @@ -24,60 +24,59 @@ describe('shared.ops.rebirth', () => { tasks = [generateHabit(), generateDaily(), generateTodo(), generateReward()]; }); - it('returns an error when user balance is too low and user is less than max level', done => { + it('returns an error when user balance is too low and user is less than max level', async () => { user.balance = 0; try { - rebirth(user); + await rebirth(user); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('notEnoughGems')); - done(); } }); - it('rebirths a user with enough gems', () => { - const [, message] = rebirth(user); + it('rebirths a user with enough gems', async () => { + const [, message] = await rebirth(user); expect(message).to.equal(i18n.t('rebirthComplete')); }); - it('rebirths a user with not enough gems but max level', () => { + it('rebirths a user with not enough gems but max level', async () => { user.balance = 0; user.stats.lvl = MAX_LEVEL; - const [, message] = rebirth(user); + const [, message] = await rebirth(user); expect(message).to.equal(i18n.t('rebirthComplete')); expect(user.flags.lastFreeRebirth).to.exist; }); - it('rebirths a user with not enough gems but more than max level', () => { + it('rebirths a user with not enough gems but more than max level', async () => { user.balance = 0; user.stats.lvl = MAX_LEVEL + 1; - const [, message] = rebirth(user); + const [, message] = await rebirth(user); expect(message).to.equal(i18n.t('rebirthComplete')); }); - it('rebirths a user using gems if over max level but rebirthed recently', () => { + it('rebirths a user using gems if over max level but rebirthed recently', async () => { user.stats.lvl = MAX_LEVEL + 1; user.flags.lastFreeRebirth = new Date(); - const [, message] = rebirth(user); + const [, message] = await rebirth(user); expect(message).to.equal(i18n.t('rebirthComplete')); expect(user.balance).to.equal(0); }); - it('resets user\'s tasks values except for rewards to 0', () => { + it('resets user\'s tasks values except for rewards to 0', async () => { tasks[0].value = 1; tasks[1].value = 1; tasks[2].value = 1; tasks[3].value = 1; // Reward - rebirth(user, tasks); + await rebirth(user, tasks); expect(tasks[0].value).to.equal(0); expect(tasks[1].value).to.equal(0); @@ -85,99 +84,99 @@ describe('shared.ops.rebirth', () => { expect(tasks[3].value).to.equal(1); // Reward }); - it('resets user\'s daily streaks to 0', () => { + it('resets user\'s daily streaks to 0', async () => { tasks[0].counterDown = 1; // Habit tasks[0].counterUp = 1; // Habit tasks[1].streak = 1; // Daily - rebirth(user, tasks); + await rebirth(user, tasks); expect(tasks[0].counterDown).to.equal(0); expect(tasks[0].counterUp).to.equal(0); expect(tasks[1].streak).to.equal(0); }); - it('resets a user\'s buffs', () => { + it('resets a user\'s buffs', async () => { user.stats.buffs = { test: 'test' }; - rebirth(user); + await rebirth(user); expect(user.stats.buffs).to.be.empty; }); - it('resets a user\'s health points', () => { + it('resets a user\'s health points', async () => { user.stats.hp = 40; - rebirth(user); + await rebirth(user); expect(user.stats.hp).to.equal(50); }); - it('resets a user\'s class', () => { + it('resets a user\'s class', async () => { user.stats.class = 'rouge'; - rebirth(user); + await rebirth(user); expect(user.stats.class).to.equal('warrior'); }); - it('resets a user\'s stats', () => { + it('resets a user\'s stats', async () => { user.stats.class = 'rouge'; _.each(userStats, value => { user.stats[value] = 10; }); - rebirth(user); + await rebirth(user); _.each(userStats, value => { user.stats[value] = 0; }); }); - it('retains a user\'s gear', () => { + it('retains a user\'s gear', async () => { const prevGearEquipped = user.items.gear.equipped; const prevGearCostume = user.items.gear.costume; const prevPrefCostume = user.preferences.costume; - rebirth(user); + await rebirth(user); expect(user.items.gear.equipped).to.deep.equal(prevGearEquipped); expect(user.items.gear.costume).to.deep.equal(prevGearCostume); expect(user.preferences.costume).to.equal(prevPrefCostume); }); - it('retains a user\'s gear owned', () => { + it('retains a user\'s gear owned', async () => { user.items.gear.owned.weapon_warrior_1 = true; // eslint-disable-line camelcase const prevGearOwned = user.items.gear.owned; - rebirth(user); + await rebirth(user); expect(user.items.gear.owned).to.equal(prevGearOwned); }); - it('resets a user\'s current pet', () => { + it('resets a user\'s current pet', async () => { user.items.pets[animal] = true; user.items.currentPet = animal; - rebirth(user); + await rebirth(user); expect(user.items.currentPet).to.be.empty; }); - it('resets a user\'s current mount', () => { + it('resets a user\'s current mount', async () => { user.items.mounts[animal] = true; user.items.currentMount = animal; - rebirth(user); + await rebirth(user); expect(user.items.currentMount).to.be.empty; }); - it('resets a user\'s flags', () => { + it('resets a user\'s flags', async () => { user.flags.itemsEnabled = true; user.flags.classSelected = true; user.flags.rebirthEnabled = true; user.flags.levelDrops = { test: 'test' }; - rebirth(user); + await rebirth(user); expect(user.flags.itemsEnabled).to.be.false; expect(user.flags.classSelected).to.be.false; @@ -185,80 +184,80 @@ describe('shared.ops.rebirth', () => { expect(user.flags.levelDrops).to.be.empty; }); - it('reset rebirthEnabled even if user has beastMaster', () => { + it('reset rebirthEnabled even if user has beastMaster', async () => { user.achievements.beastMaster = 1; user.flags.rebirthEnabled = true; - rebirth(user); + await rebirth(user); expect(user.flags.rebirthEnabled).to.be.false; }); - it('sets rebirth achievement', () => { - rebirth(user); + it('sets rebirth achievement', async () => { + await rebirth(user); expect(user.achievements.rebirths).to.equal(1); expect(user.achievements.rebirthLevel).to.equal(user.stats.lvl); }); - it('increments rebirth achievements', () => { + it('increments rebirth achievements', async () => { user.stats.lvl = 2; user.achievements.rebirths = 1; user.achievements.rebirthLevel = 1; - rebirth(user); + await rebirth(user); expect(user.achievements.rebirths).to.equal(2); expect(user.achievements.rebirthLevel).to.equal(2); }); - it('does not increment rebirth achievements when level is lower than previous', () => { + it('does not increment rebirth achievements when level is lower than previous', async () => { user.stats.lvl = 2; user.achievements.rebirths = 1; user.achievements.rebirthLevel = 3; - rebirth(user); + await rebirth(user); expect(user.achievements.rebirths).to.equal(1); expect(user.achievements.rebirthLevel).to.equal(3); }); - it('always increments rebirth achievements when level is MAX_LEVEL', () => { + it('always increments rebirth achievements when level is MAX_LEVEL', async () => { user.stats.lvl = MAX_LEVEL; user.achievements.rebirths = 1; // this value is not actually possible (actually capped at MAX_LEVEL) but makes a good test user.achievements.rebirthLevel = MAX_LEVEL + 1; - rebirth(user); + await rebirth(user); expect(user.achievements.rebirths).to.equal(2); expect(user.achievements.rebirthLevel).to.equal(MAX_LEVEL); }); - it('always increments rebirth achievements when level is greater than MAX_LEVEL', () => { + it('always increments rebirth achievements when level is greater than MAX_LEVEL', async () => { user.stats.lvl = MAX_LEVEL + 1; user.achievements.rebirths = 1; // this value is not actually possible (actually capped at MAX_LEVEL) but makes a good test user.achievements.rebirthLevel = MAX_LEVEL + 2; - rebirth(user); + await rebirth(user); expect(user.achievements.rebirths).to.equal(2); expect(user.achievements.rebirthLevel).to.equal(MAX_LEVEL); }); - it('keeps automaticAllocation false', () => { + it('keeps automaticAllocation false', async () => { user.preferences.automaticAllocation = false; - rebirth(user); + await rebirth(user); expect(user.preferences.automaticAllocation).to.be.false; }); - it('sets automaticAllocation to false when true', () => { + it('sets automaticAllocation to false when true', async () => { user.preferences.automaticAllocation = true; - rebirth(user); + await rebirth(user); expect(user.preferences.automaticAllocation).to.be.false; }); diff --git a/test/common/ops/releaseMounts.js b/test/common/ops/releaseMounts.js index 10ec71f23b..10469beb7e 100644 --- a/test/common/ops/releaseMounts.js +++ b/test/common/ops/releaseMounts.js @@ -23,87 +23,85 @@ describe('shared.ops.releaseMounts', () => { user.balance = 1; }); - it('returns an error when user balance is too low', done => { + it('returns an error when user balance is too low', async () => { user.balance = 0; try { - releaseMounts(user); + await releaseMounts(user); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('notEnoughGems')); - done(); } }); - it('returns an error when user does not have all pets', done => { + it('returns an error when user does not have all pets', async () => { const mountsKeys = Object.keys(user.items.mounts); delete user.items.mounts[mountsKeys[0]]; try { - releaseMounts(user); + await releaseMounts(user); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('notEnoughMounts')); - done(); } }); - it('releases mounts', () => { - const message = releaseMounts(user)[1]; + it('releases mounts', async () => { + const result = await releaseMounts(user); - expect(message).to.equal(i18n.t('mountsReleased')); + expect(result[1]).to.equal(i18n.t('mountsReleased')); expect(user.items.mounts[animal]).to.equal(null); }); - it('removes drop currentMount', () => { + it('removes drop currentMount', async () => { const mountInfo = content.mountInfo[user.items.currentMount]; expect(mountInfo.type).to.equal('drop'); - releaseMounts(user); + await releaseMounts(user); expect(user.items.currentMount).to.be.empty; }); - it('leaves non-drop mount equipped', () => { + it('leaves non-drop mount equipped', async () => { const questAnimal = 'Gryphon-Base'; user.items.currentMount = questAnimal; user.items.mounts[questAnimal] = true; const mountInfo = content.mountInfo[user.items.currentMount]; expect(mountInfo.type).to.not.equal('drop'); - releaseMounts(user); + await releaseMounts(user); expect(user.items.currentMount).to.equal(questAnimal); }); - it('increases mountMasterCount achievement', () => { - releaseMounts(user); + it('increases mountMasterCount achievement', async () => { + await releaseMounts(user); expect(user.achievements.mountMasterCount).to.equal(1); }); - it('does not increase mountMasterCount achievement if mount is missing (null)', () => { + it('does not increase mountMasterCount achievement if mount is missing (null)', async () => { const mountMasterCountBeforeRelease = user.achievements.mountMasterCount; user.items.mounts[animal] = null; try { - releaseMounts(user); + await releaseMounts(user); } catch (e) { expect(user.achievements.mountMasterCount).to.equal(mountMasterCountBeforeRelease); } }); - it('does not increase mountMasterCount achievement if mount is missing (undefined)', () => { + it('does not increase mountMasterCount achievement if mount is missing (undefined)', async () => { const mountMasterCountBeforeRelease = user.achievements.mountMasterCount; delete user.items.mounts[animal]; try { - releaseMounts(user); + await releaseMounts(user); } catch (e) { expect(user.achievements.mountMasterCount).to.equal(mountMasterCountBeforeRelease); } }); - it('subtracts gems from balance', () => { - releaseMounts(user); + it('subtracts gems from balance', async () => { + await releaseMounts(user); expect(user.balance).to.equal(0); }); diff --git a/test/common/ops/releasePets.js b/test/common/ops/releasePets.js index a333fc41ab..d5bae92545 100644 --- a/test/common/ops/releasePets.js +++ b/test/common/ops/releasePets.js @@ -23,98 +23,96 @@ describe('shared.ops.releasePets', () => { user.balance = 1; }); - it('returns an error when user balance is too low', done => { + it('returns an error when user balance is too low', async () => { user.balance = 0; try { - releasePets(user); + await releasePets(user); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('notEnoughGems')); - done(); } }); - it('returns an error when user does not have all pets', done => { + it('returns an error when user does not have all pets', async () => { const petKeys = Object.keys(user.items.pets); delete user.items.pets[petKeys[0]]; try { - releasePets(user); + await releasePets(user); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('notEnoughPets')); - done(); } }); - it('releases pets', () => { - const message = releasePets(user)[1]; + it('releases pets', async () => { + const message = await releasePets(user)[1]; expect(message).to.equal(i18n.t('petsReleased')); expect(user.items.pets[animal]).to.equal(0); }); - it('removes drop currentPet', () => { + it('removes drop currentPet', async () => { const petInfo = content.petInfo[user.items.currentPet]; expect(petInfo.type).to.equal('drop'); - releasePets(user); + await releasePets(user); expect(user.items.currentPet).to.be.empty; }); - it('leaves non-drop pets equipped', () => { + it('leaves non-drop pets equipped', async () => { const questAnimal = 'Gryphon-Base'; user.items.currentPet = questAnimal; user.items.pets[questAnimal] = 5; const petInfo = content.petInfo[user.items.currentPet]; expect(petInfo.type).to.not.equal('drop'); - releasePets(user); + await releasePets(user); expect(user.items.currentPet).to.equal(questAnimal); }); - it('decreases user\'s balance', () => { - releasePets(user); + it('decreases user\'s balance', async () => { + await releasePets(user); expect(user.balance).to.equal(0); }); - it('incremenets beastMasterCount', () => { - releasePets(user); + it('incremenets beastMasterCount', async () => { + await releasePets(user); expect(user.achievements.beastMasterCount).to.equal(1); }); - it('does not increment beastMasterCount if any pet is level 0 (released)', () => { + it('does not increment beastMasterCount if any pet is level 0 (released)', async () => { const beastMasterCountBeforeRelease = user.achievements.beastMasterCount; user.items.pets[animal] = 0; try { - releasePets(user); + await releasePets(user); } catch (e) { expect(user.achievements.beastMasterCount).to.equal(beastMasterCountBeforeRelease); } }); - it('does not increment beastMasterCount if any pet is missing (null)', () => { + it('does not increment beastMasterCount if any pet is missing (null)', async () => { const beastMasterCountBeforeRelease = user.achievements.beastMasterCount; user.items.pets[animal] = null; try { - releasePets(user); + await releasePets(user); } catch (e) { expect(user.achievements.beastMasterCount).to.equal(beastMasterCountBeforeRelease); } }); - it('does not increment beastMasterCount if any pet is missing (undefined)', () => { + it('does not increment beastMasterCount if any pet is missing (undefined)', async () => { const beastMasterCountBeforeRelease = user.achievements.beastMasterCount; delete user.items.pets[animal]; try { - releasePets(user); + await releasePets(user); } catch (e) { expect(user.achievements.beastMasterCount).to.equal(beastMasterCountBeforeRelease); } diff --git a/test/common/ops/reroll.js b/test/common/ops/reroll.js index 15020c8aa4..a3b33812ed 100644 --- a/test/common/ops/reroll.js +++ b/test/common/ops/reroll.js @@ -19,43 +19,42 @@ describe('shared.ops.reroll', () => { tasks = [generateDaily(), generateReward()]; }); - it('returns an error when user balance is too low', done => { + it('returns an error when user balance is too low', async () => { user.balance = 0; try { - reroll(user); + await reroll(user); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('notEnoughGems')); - done(); } }); - it('rerolls a user with enough gems', () => { - const [, message] = reroll(user); + it('rerolls a user with enough gems', async () => { + const [, message] = await reroll(user); expect(message).to.equal(i18n.t('fortifyComplete')); }); - it('reduces a user\'s balance', () => { - reroll(user); + it('reduces a user\'s balance', async () => { + await reroll(user); expect(user.balance).to.equal(0); }); - it('resets a user\'s health points', () => { + it('resets a user\'s health points', async () => { user.stats.hp = 40; - reroll(user); + await reroll(user); expect(user.stats.hp).to.equal(50); }); - it('resets user\'s taks values except for rewards to 0', () => { + it('resets user\'s taks values except for rewards to 0', async () => { tasks[0].value = 1; tasks[1].value = 1; - reroll(user, tasks); + await reroll(user, tasks); expect(tasks[0].value).to.equal(0); expect(tasks[1].value).to.equal(1); diff --git a/test/common/ops/unlock.js b/test/common/ops/unlock.js index b6307e59c3..f08608e615 100644 --- a/test/common/ops/unlock.js +++ b/test/common/ops/unlock.js @@ -19,184 +19,173 @@ describe('shared.ops.unlock', () => { user.balance = usersStartingGems; }); - it('returns an error when path is not provided', done => { + it('returns an error when path is not provided', async () => { try { - unlock(user); + await unlock(user); } catch (err) { expect(err).to.be.an.instanceof(BadRequest); expect(err.message).to.equal(i18n.t('pathRequired')); - done(); } }); - it('does not unlock lost gear', done => { + it('does not unlock lost gear', async () => { user.items.gear.owned.headAccessory_special_bearEars = false; - unlock(user, { query: { path: 'items.gear.owned.headAccessory_special_bearEars' } }); + await unlock(user, { query: { path: 'items.gear.owned.headAccessory_special_bearEars' } }); expect(user.balance).to.equal(usersStartingGems); - done(); }); - it('returns an error when user balance is too low', done => { + it('returns an error when user balance is too low', async () => { user.balance = 0; try { - unlock(user, { query: { path: unlockPath } }); + await unlock(user, { query: { path: unlockPath } }); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('notEnoughGems')); - done(); } }); - it('returns an error when user already owns a full set', done => { + it('returns an error when user already owns a full set', async () => { let expectedBalance; try { - unlock(user, { query: { path: unlockPath } }); + await unlock(user, { query: { path: unlockPath } }); expectedBalance = user.balance; - unlock(user, { query: { path: unlockPath } }); + await unlock(user, { query: { path: unlockPath } }); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('alreadyUnlocked')); expect(user.balance).to.equal(expectedBalance); - done(); } }); - it('returns an error when user already owns a full set of gear', done => { + it('returns an error when user already owns a full set of gear', async () => { let expectedBalance; try { - unlock(user, { query: { path: unlockGearSetPath } }); + await unlock(user, { query: { path: unlockGearSetPath } }); expectedBalance = user.balance; - unlock(user, { query: { path: unlockGearSetPath } }); + await unlock(user, { query: { path: unlockGearSetPath } }); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('alreadyUnlocked')); expect(user.balance).to.equal(expectedBalance); - done(); } }); - it('returns an error if an item does not exists', done => { + it('returns an error if an item does not exists', async () => { try { - unlock(user, { query: { path: 'background.invalid_background' } }); + await unlock(user, { query: { path: 'background.invalid_background' } }); } catch (err) { expect(err).to.be.an.instanceof(BadRequest); expect(err.message).to.equal(i18n.t('invalidUnlockSet')); - done(); } }); - it('returns an error if there are items from multiple sets', done => { + it('returns an error if there are items from multiple sets', async () => { try { - unlock(user, { query: { path: 'shirt.convict,skin.0ff591' } }); + await unlock(user, { query: { path: 'shirt.convict,skin.0ff591' } }); } catch (err) { expect(err).to.be.an.instanceof(BadRequest); expect(err.message).to.equal(i18n.t('invalidUnlockSet')); - done(); } }); - it('returns an error if gear is not from the animal set', done => { + it('returns an error if gear is not from the animal set', async () => { try { - unlock(user, { query: { path: 'items.gear.owned.back_mystery_202004' } }); + await unlock(user, { query: { path: 'items.gear.owned.back_mystery_202004' } }); } catch (err) { expect(err).to.be.an.instanceof(BadRequest); expect(err.message).to.equal(i18n.t('invalidUnlockSet')); - done(); } }); - it('returns an error if the item is free', done => { + it('returns an error if the item is free', async () => { try { - unlock(user, { query: { path: 'shirt.black' } }); + await unlock(user, { query: { path: 'shirt.black' } }); } catch (err) { expect(err).to.be.an.instanceof(BadRequest); expect(err.message).to.equal(i18n.t('invalidUnlockSet')); - done(); } }); - it('returns an error if an item does not belong to a set (appearances)', done => { + it('returns an error if an item does not belong to a set (appearances)', async () => { try { - unlock(user, { query: { path: 'shirt.pink' } }); + await unlock(user, { query: { path: 'shirt.pink' } }); } catch (err) { expect(err).to.be.an.instanceof(BadRequest); expect(err.message).to.equal(i18n.t('invalidUnlockSet')); - done(); } }); - it('returns an error when user already owns items in a full set and it would be more expensive to buy the entire set', done => { + it('returns an error when user already owns items in a full set and it would be more expensive to buy the entire set', async () => { try { // There are 11 shirts in the set, each cost 2 gems, the full set 5 gems // In order for the full purchase not to be worth, we must own 9 const partialUnlockPaths = unlockPath.split(','); - unlock(user, { query: { path: partialUnlockPaths[0] } }); - unlock(user, { query: { path: partialUnlockPaths[1] } }); - unlock(user, { query: { path: partialUnlockPaths[2] } }); - unlock(user, { query: { path: partialUnlockPaths[3] } }); - unlock(user, { query: { path: partialUnlockPaths[4] } }); - unlock(user, { query: { path: partialUnlockPaths[5] } }); - unlock(user, { query: { path: partialUnlockPaths[6] } }); - unlock(user, { query: { path: partialUnlockPaths[7] } }); - unlock(user, { query: { path: partialUnlockPaths[8] } }); + await unlock(user, { query: { path: partialUnlockPaths[0] } }); + await unlock(user, { query: { path: partialUnlockPaths[1] } }); + await unlock(user, { query: { path: partialUnlockPaths[2] } }); + await unlock(user, { query: { path: partialUnlockPaths[3] } }); + await unlock(user, { query: { path: partialUnlockPaths[4] } }); + await unlock(user, { query: { path: partialUnlockPaths[5] } }); + await unlock(user, { query: { path: partialUnlockPaths[6] } }); + await unlock(user, { query: { path: partialUnlockPaths[7] } }); + await unlock(user, { query: { path: partialUnlockPaths[8] } }); - unlock(user, { query: { path: unlockPath } }); + await unlock(user, { query: { path: unlockPath } }); } catch (err) { expect(err).to.be.an.instanceof(NotAuthorized); expect(err.message).to.equal(i18n.t('alreadyUnlockedPart')); - done(); } }); - it('does not return an error when user already owns items in a full set and it would not be more expensive to buy the entire set', () => { + it('does not return an error when user already owns items in a full set and it would not be more expensive to buy the entire set', async () => { // There are 11 shirts in the set, each cost 2 gems, the full set 5 gems // In order for the full purchase to be worth, we can own already 8 const partialUnlockPaths = unlockPath.split(','); - unlock(user, { query: { path: partialUnlockPaths[0] } }); - unlock(user, { query: { path: partialUnlockPaths[1] } }); - unlock(user, { query: { path: partialUnlockPaths[2] } }); - unlock(user, { query: { path: partialUnlockPaths[3] } }); - unlock(user, { query: { path: partialUnlockPaths[4] } }); - unlock(user, { query: { path: partialUnlockPaths[5] } }); - unlock(user, { query: { path: partialUnlockPaths[6] } }); - unlock(user, { query: { path: partialUnlockPaths[7] } }); + await unlock(user, { query: { path: partialUnlockPaths[0] } }); + await unlock(user, { query: { path: partialUnlockPaths[1] } }); + await unlock(user, { query: { path: partialUnlockPaths[2] } }); + await unlock(user, { query: { path: partialUnlockPaths[3] } }); + await unlock(user, { query: { path: partialUnlockPaths[4] } }); + await unlock(user, { query: { path: partialUnlockPaths[5] } }); + await unlock(user, { query: { path: partialUnlockPaths[6] } }); + await unlock(user, { query: { path: partialUnlockPaths[7] } }); - unlock(user, { query: { path: unlockPath } }); + await unlock(user, { query: { path: unlockPath } }); }); - it('equips an item already owned', () => { + it('equips an item already owned', async () => { expect(user.purchased.background.giant_florals).to.not.exist; - unlock(user, { query: { path: backgroundUnlockPath } }); + await unlock(user, { query: { path: backgroundUnlockPath } }); const afterBalance = user.balance; - const response = unlock(user, { query: { path: backgroundUnlockPath } }); + const response = await unlock(user, { query: { path: backgroundUnlockPath } }); expect(user.balance).to.equal(afterBalance); // do not bill twice expect(response.message).to.not.exist; expect(user.preferences.background).to.equal('giant_florals'); }); - it('un-equips a background already equipped', () => { + it('un-equips a background already equipped', async () => { expect(user.purchased.background.giant_florals).to.not.exist; - unlock(user, { query: { path: backgroundUnlockPath } }); // unlock + await unlock(user, { query: { path: backgroundUnlockPath } }); // unlock const afterBalance = user.balance; - unlock(user, { query: { path: backgroundUnlockPath } }); // equip - const response = unlock(user, { query: { path: backgroundUnlockPath } }); + await unlock(user, { query: { path: backgroundUnlockPath } }); // equip + const response = await unlock(user, { query: { path: backgroundUnlockPath } }); expect(user.balance).to.equal(afterBalance); // do not bill twice expect(response.message).to.not.exist; expect(user.preferences.background).to.equal(''); }); - it('unlocks a full set of appearance items', () => { + it('unlocks a full set of appearance items', async () => { const initialShirts = Object.keys(user.purchased.shirt).length; - const [, message] = unlock(user, { query: { path: unlockPath } }); + const [, message] = await unlock(user, { query: { path: unlockPath } }); expect(message).to.equal(i18n.t('unlocked')); const individualPaths = unlockPath.split(','); @@ -208,11 +197,11 @@ describe('shared.ops.unlock', () => { expect(user.balance).to.equal(usersStartingGems - 1.25); }); - it('unlocks a full set of hair items', () => { + it('unlocks a full set of hair items', async () => { user.purchased.hair.color = {}; const initialHairColors = Object.keys(user.purchased.hair.color).length; - const [, message] = unlock(user, { query: { path: hairUnlockPath } }); + const [, message] = await unlock(user, { query: { path: hairUnlockPath } }); expect(message).to.equal(i18n.t('unlocked')); const individualPaths = hairUnlockPath.split(','); @@ -224,13 +213,13 @@ describe('shared.ops.unlock', () => { expect(user.balance).to.equal(usersStartingGems - 1.25); }); - it('unlocks the facial hair set', () => { + it('unlocks the facial hair set', async () => { user.purchased.hair.mustache = {}; user.purchased.hair.beard = {}; const initialMustache = Object.keys(user.purchased.hair.mustache).length; const initialBeard = Object.keys(user.purchased.hair.mustache).length; - const [, message] = unlock(user, { query: { path: facialHairUnlockPath } }); + const [, message] = await unlock(user, { query: { path: facialHairUnlockPath } }); expect(message).to.equal(i18n.t('unlocked')); const individualPaths = facialHairUnlockPath.split(','); @@ -242,9 +231,9 @@ describe('shared.ops.unlock', () => { expect(user.balance).to.equal(usersStartingGems - 1.25); }); - it('unlocks a full set of gear', () => { + it('unlocks a full set of gear', async () => { const initialGear = Object.keys(user.items.gear.owned).length; - const [, message] = unlock(user, { query: { path: unlockGearSetPath } }); + const [, message] = await unlock(user, { query: { path: unlockGearSetPath } }); expect(message).to.equal(i18n.t('unlocked')); @@ -257,9 +246,9 @@ describe('shared.ops.unlock', () => { expect(user.balance).to.equal(usersStartingGems - 1.25); }); - it('unlocks a full set of backgrounds', () => { + it('unlocks a full set of backgrounds', async () => { const initialBackgrounds = Object.keys(user.purchased.background).length; - const [, message] = unlock(user, { query: { path: backgroundSetUnlockPath } }); + const [, message] = await unlock(user, { query: { path: backgroundSetUnlockPath } }); expect(message).to.equal(i18n.t('unlocked')); const individualPaths = backgroundSetUnlockPath.split(','); @@ -271,10 +260,10 @@ describe('shared.ops.unlock', () => { expect(user.balance).to.equal(usersStartingGems - 3.75); }); - it('unlocks an item (appearance)', () => { + it('unlocks an item (appearance)', async () => { const path = unlockPath.split(',')[0]; const initialShirts = Object.keys(user.purchased.shirt).length; - const [, message] = unlock(user, { query: { path } }); + const [, message] = await unlock(user, { query: { path } }); expect(message).to.equal(i18n.t('unlocked')); expect(Object.keys(user.purchased.shirt).length).to.equal(initialShirts + 1); @@ -282,12 +271,12 @@ describe('shared.ops.unlock', () => { expect(user.balance).to.equal(usersStartingGems - 0.5); }); - it('unlocks an item (hair color)', () => { + it('unlocks an item (hair color)', async () => { user.purchased.hair.color = {}; const path = hairUnlockPath.split(',')[0]; const initialColorHair = Object.keys(user.purchased.hair.color).length; - const [, message] = unlock(user, { query: { path } }); + const [, message] = await unlock(user, { query: { path } }); expect(message).to.equal(i18n.t('unlocked')); expect(Object.keys(user.purchased.hair.color).length).to.equal(initialColorHair + 1); @@ -295,14 +284,14 @@ describe('shared.ops.unlock', () => { expect(user.balance).to.equal(usersStartingGems - 0.5); }); - it('unlocks an item (facial hair)', () => { + it('unlocks an item (facial hair)', async () => { user.purchased.hair.mustache = {}; user.purchased.hair.beard = {}; const path = facialHairUnlockPath.split(',')[0]; const initialMustache = Object.keys(user.purchased.hair.mustache).length; const initialBeard = Object.keys(user.purchased.hair.beard).length; - const [, message] = unlock(user, { query: { path } }); + const [, message] = await unlock(user, { query: { path } }); expect(message).to.equal(i18n.t('unlocked')); @@ -313,10 +302,10 @@ describe('shared.ops.unlock', () => { expect(user.balance).to.equal(usersStartingGems - 0.5); }); - it('unlocks an item (gear)', () => { + it('unlocks an item (gear)', async () => { const path = unlockGearSetPath.split(',')[0]; const initialGear = Object.keys(user.items.gear.owned).length; - const [, message] = unlock(user, { query: { path } }); + const [, message] = await unlock(user, { query: { path } }); expect(message).to.equal(i18n.t('unlocked')); expect(Object.keys(user.items.gear.owned).length).to.equal(initialGear + 1); @@ -324,9 +313,9 @@ describe('shared.ops.unlock', () => { expect(user.balance).to.equal(usersStartingGems - 0.5); }); - it('unlocks an item (background)', () => { + it('unlocks an item (background)', async () => { const initialBackgrounds = Object.keys(user.purchased.background).length; - const [, message] = unlock(user, { query: { path: backgroundUnlockPath } }); + const [, message] = await unlock(user, { query: { path: backgroundUnlockPath } }); expect(message).to.equal(i18n.t('unlocked')); expect(Object.keys(user.purchased.background).length).to.equal(initialBackgrounds + 1); diff --git a/website/client/src/components/hall/heroes.vue b/website/client/src/components/hall/heroes.vue index 485699e691..60c0009029 100644 --- a/website/client/src/components/hall/heroes.vue +++ b/website/client/src/components/hall/heroes.vue @@ -1,205 +1,231 @@