From 287014518d450977ad017591d9a7ad5bae08d6f7 Mon Sep 17 00:00:00 2001 From: Sabe Jones Date: Fri, 28 Jun 2024 09:49:08 -0500 Subject: [PATCH] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 28193f86fb7ed6647fb5e1c6469f71a9bb980c38 Author: Phillip Thelen Date: Fri Jun 21 11:12:18 2024 +0200 Fix serving memoized content commit 877fe482252db78b69050b13274da147ede23769 Author: Phillip Thelen Date: Thu Jun 20 12:23:24 2024 +0200 correctly memoize conent api commit e0f6f79c5b49d2b6eae7e5c02dd90ac7ad6ea397 Author: Phillip Thelen Date: Thu Jun 20 10:11:27 2024 +0200 don’t build multiple times on heroku commit f62254d68e2859990a6e80cd5b64d3385a6dea60 Author: Phillip Thelen Date: Wed Jun 19 19:40:20 2024 +0200 fix client command commit d054e6fc1650fbe6df14b62025f0470a15e91883 Author: Phillip Thelen Date: Wed Jun 19 19:36:57 2024 +0200 correct build call commit 7231f699c1e9cc4fc873428863cff0c14a4b6b3f Author: Phillip Thelen Date: Wed Jun 19 19:32:32 2024 +0200 try setting up with heroku buildpack commit 1dae0793fde402e15c9e2eba2b21df999933282f Author: Phillip Thelen Date: Wed Jun 19 18:50:32 2024 +0200 call gulp build:prod commit f18fbe86b61fa282baf38196313fe07837b173cc Author: Phillip Thelen Date: Wed Jun 19 18:40:53 2024 +0200 build client commit 61a61724cae017aaaf912c037796bd2e5064ec87 Author: Phillip Thelen Date: Wed Jun 19 18:33:18 2024 +0200 testing commit 93cf30eb184a74f85751750ab6e5033db3d2fafa Author: Phillip Thelen Date: Wed Jun 19 18:20:25 2024 +0200 integration fix commit cff08adcd0290907281e5db873b9087d7de83e26 Author: Phillip Thelen Date: Wed Jun 19 18:13:20 2024 +0200 specify dev docker file commit 4da2ed4a1f8d017ad3b6ac4e869746e7beaea419 Author: Phillip Thelen Date: Wed Jun 19 18:10:07 2024 +0200 initialize stub commit 11c5b26c594254083fa260a1d0920242d67e23b7 Author: Phillip Thelen Date: Wed Jun 19 18:08:45 2024 +0200 test heroku file commit ac85bb2e2da846b069826a621e975a710038313d Author: Phillip Thelen Date: Wed Jun 19 18:03:15 2024 +0200 fix stub reference commit 74dfb2710ff1b246d788d729149062f6f0b77787 Author: Phillip Thelen Date: Wed Jun 19 18:01:27 2024 +0200 test fixes commit 8dbd3c3db15aac5c3defd294b6c6613cf80136da Author: Phillip Thelen Date: Wed Jun 19 17:37:04 2024 +0200 fix canOwn test commit 74b3b348ff6901e889ef88fd7531d6800d12ab1a Author: Phillip Thelen Date: Wed Jun 19 17:32:31 2024 +0200 fix buy test commit 3386d61fdee32e79a6a53939f22e26d3942eaa7f Author: Phillip Thelen Date: Wed Jun 19 17:30:37 2024 +0200 fix debug tests commit 19da14531ca64a18dd68cefe1ada3f2ed1066622 Author: Phillip Thelen Date: Wed Jun 19 17:05:25 2024 +0200 add chameleon to featured quests commit 254dd80f2479086637c7cafa9522cf6155b3868f Author: Phillip Thelen Date: Wed Jun 19 17:05:14 2024 +0200 fix import commit 0bc3f16b4b03f88cc5c78fad5aa8d38cfdb9324b Author: Phillip Thelen Date: Wed Jun 19 16:33:22 2024 +0200 add new content to new release file commit 5184973bd50fb1f4bf17ab054aa7a5836086a5e1 Author: Phillip Thelen Date: Wed Jun 19 16:33:11 2024 +0200 fix release date tests commit b6accca5cae1bbb33c450e4462095113cfebe480 Author: Phillip Thelen Date: Wed Jun 19 16:33:06 2024 +0200 fix armoire tests commit fec68e621147e31c6ba5370ce0126d7e9b86461c Author: Phillip Thelen Date: Wed Jun 19 16:02:03 2024 +0200 fix tests commit fc63c906ddf4956fbe40543b66cb65cf570de36b Author: Phillip Thelen Date: Mon Jun 10 14:44:21 2024 +0200 Improve test coverage commit 3333f8f0f59d0a69fcd715ee3f690518f7a710b5 Author: Phillip Thelen Date: Mon Jun 10 14:24:59 2024 +0200 allow hatching potions to have a release date commit 89a3ac3ddebf8e949f584c39092e0cc961cde04a Author: Phillip Thelen Date: Mon Jun 10 14:11:38 2024 +0200 allow eggs to have a release date # Conflicts: # test/content/armoire.test.js commit 16551ec83fdcb3e6bb31e4665588c83aa5af42ba Merge: f5f4974a73 2645bf6023 Author: CuriousMagpie Date: Tue Jun 18 15:03:12 2024 -0400 Merge branch '2024-07-content-prebuild' into subs-private commit 2645bf60239a838d5a506f69ca7c8ce38042bf25 Author: CuriousMagpie Date: Tue Jun 18 15:02:47 2024 -0400 update habitica images commit f5f4974a733fc3ebad1dd5da77bb44b48e91b7cc Author: CuriousMagpie Date: Tue Jun 18 14:58:13 2024 -0400 update habitica-images commit 162e337d14a372f523fbf9903bdddd23142e0d79 Merge: f2506c3231 21a7d36b7b Author: CuriousMagpie Date: Tue Jun 18 13:46:03 2024 -0400 Merge branch '2024-07-content-prebuild' into subs-private commit 21a7d36b7ba1d86e30b60e25d778b01062ed11ba Author: CuriousMagpie Date: Tue Jun 18 13:45:09 2024 -0400 update sprites commit f2506c32316df6836ee19489320b289f4dc97a35 Author: CuriousMagpie Date: Tue Jun 18 13:24:21 2024 -0400 updated sprites css commit d47641e25a6dfb9b62f1c10d810e80eb0990ea20 Author: CuriousMagpie Date: Tue Jun 18 12:46:59 2024 -0400 typo fix commit fb8479ad1e887b7f94dd6eec47980d4da593bee9 Author: CuriousMagpie Date: Mon Jun 17 13:44:36 2024 -0400 finish July prebuild commit 3810cf3ef3c492bda8d343596bf1a17f9fc1e36e Author: CuriousMagpie Date: Fri Jun 14 10:42:47 2024 -0400 add chameleon quest commit d05da3722ce1d86a840d6f73b4ef78309c84a2f6 Author: CuriousMagpie Date: Thu Jun 13 17:12:43 2024 -0400 add June background notes commit b8a3440ef2fd0bf26e1305e749bcefab2c446d84 Author: CuriousMagpie Date: Thu Jun 13 16:40:04 2024 -0400 fix mystery item and background description commit 44d63032d81ac58aded8c4c856df7fe5d89f5ef4 Author: CuriousMagpie Date: Thu Jun 13 15:38:23 2024 -0400 add subscriber gear, enchanted armoire, and background commit 9d7da91ec60d84b7ec8f1792f2601bcc863c5a31 Author: CuriousMagpie Date: Thu Jun 13 14:44:59 2024 -0400 add sprites --- Dockerfile-Dev | 7 +- package.json | 4 +- test/api/unit/libs/content.test.js | 2 +- test/common/ops/armoireCanOwn.js | 1 + test/content/armoire.test.js | 41 +- test/content/eggs.test.js | 58 +- test/content/index.test.js | 154 ++++ test/content/releaseDates.test.js | 82 +++ test/content/stable.test.js | 15 +- website/client/src/components/hall/heroes.vue | 4 +- .../inventory/stable/mountRaisedModal.vue | 4 +- .../client/src/components/shops/buyModal.vue | 7 +- website/common/locales/en/backgrounds.json | 4 + website/common/locales/en/content.json | 4 + website/common/locales/en/gear.json | 10 + website/common/locales/en/questsContent.json | 8 +- website/common/locales/en/subscriber.json | 1 + .../script/content/appearance/backgrounds.js | 3 + .../script/content/constants/releaseDates.js | 21 + .../script/content/constants/schedule.js | 1 + website/common/script/content/eggs.js | 31 +- .../script/content/gear/sets/armoire.js | 43 +- .../script/content/gear/sets/mystery.js | 2 + .../common/script/content/hatching-potions.js | 24 +- website/common/script/content/index.js | 658 ++++++++++-------- website/common/script/content/is_released.js | 30 + website/common/script/content/quests/pets.js | 32 + .../script/content/shop-featuredItems.js | 2 +- website/common/script/content/stable.js | 179 ++--- website/common/script/fns/datedMemoize.js | 4 + website/common/script/fns/firstDrops.js | 8 +- 31 files changed, 976 insertions(+), 468 deletions(-) create mode 100644 test/content/index.test.js create mode 100644 test/content/releaseDates.test.js create mode 100644 website/common/script/content/constants/releaseDates.js create mode 100644 website/common/script/content/is_released.js diff --git a/Dockerfile-Dev b/Dockerfile-Dev index a9316937eb..efb8bd074e 100644 --- a/Dockerfile-Dev +++ b/Dockerfile-Dev @@ -3,10 +3,13 @@ FROM node:20 # Install global packages RUN npm install -g gulp-cli mocha -# Copy package.json and package-lock.json into image, then install -# dependencies. +# Copy package.json and package-lock.json into image WORKDIR /usr/src/habitica COPY ["package.json", "package-lock.json", "./"] # Copy the remaining source files in. COPY . /usr/src/habitica +# Install dependencies RUN npm install +RUN npm run postinstall +RUN npm run client:build +RUN gulp build:prod diff --git a/package.json b/package.json index f166b266f1..1afd5c6c61 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,9 @@ "debug": "gulp nodemon --inspect", "mongo:dev": "run-rs -v 5.0.23 -l ubuntu1804 --keep --dbpath mongodb-data --number 1 --quiet", "postinstall": "git config --global url.\"https://\".insteadOf git:// && gulp build && cd website/client && npm install", - "apidoc": "gulp apidoc" + "apidoc": "gulp apidoc", + + "heroku-postbuild": "npm run client:build" }, "devDependencies": { "axios": "^1.4.0", diff --git a/test/api/unit/libs/content.test.js b/test/api/unit/libs/content.test.js index 53c85e4205..2db4e13859 100644 --- a/test/api/unit/libs/content.test.js +++ b/test/api/unit/libs/content.test.js @@ -55,7 +55,7 @@ describe('contentLib', () => { beforeEach(() => { resSpy = generateRes(); if (fs.existsSync(contentLib.CONTENT_CACHE_PATH)) { - fs.rmdirSync(contentLib.CONTENT_CACHE_PATH, { recursive: true }); + fs.rmSync(contentLib.CONTENT_CACHE_PATH, { recursive: true }); } fs.mkdirSync(contentLib.CONTENT_CACHE_PATH); }); diff --git a/test/common/ops/armoireCanOwn.js b/test/common/ops/armoireCanOwn.js index a226c91df2..74b48367ec 100644 --- a/test/common/ops/armoireCanOwn.js +++ b/test/common/ops/armoireCanOwn.js @@ -3,6 +3,7 @@ import armoireSet from '../../../website/common/script/content/gear/sets/armoire describe('armoireSet items', () => { it('checks if canOwn has the same id', () => { Object.keys(armoireSet).forEach(type => { + if (type === 'all') return; Object.keys(armoireSet[type]).forEach(itemKey => { const ownedKey = `${type}_armoire_${itemKey}`; expect(armoireSet[type][itemKey].canOwn({ diff --git a/test/content/armoire.test.js b/test/content/armoire.test.js index cbcb0e253c..02e718eca6 100644 --- a/test/content/armoire.test.js +++ b/test/content/armoire.test.js @@ -3,38 +3,26 @@ import forEach from 'lodash/forEach'; import { expectValidTranslationString, } from '../helpers/content.helper'; - -function makeArmoireIitemList () { - const armoire = require('../../website/common/script/content/gear/sets/armoire').default; - const items = []; - items.push(...Object.values(armoire.armor)); - items.push(...Object.values(armoire.body)); - items.push(...Object.values(armoire.eyewear)); - items.push(...Object.values(armoire.head)); - items.push(...Object.values(armoire.headAccessory)); - items.push(...Object.values(armoire.shield)); - items.push(...Object.values(armoire.weapon)); - return items; -} +import armoire from '../../website/common/script/content/gear/sets/armoire'; describe('armoire', () => { let clock; - beforeEach(() => { - delete require.cache[require.resolve('../../website/common/script/content/gear/sets/armoire')]; - }); afterEach(() => { - clock.restore(); + if (clock) { + clock.restore(); + } }); + it('does not return unreleased gear', async () => { clock = sinon.useFakeTimers(new Date('2024-01-02')); - const items = makeArmoireIitemList(); + const items = armoire.all; expect(items.length).to.equal(377); expect(items.filter(item => item.set === 'pottersSet' || item.set === 'optimistSet' || item.set === 'schoolUniform')).to.be.an('array').that.is.empty; }); it('released gear has all required properties', async () => { clock = sinon.useFakeTimers(new Date('2024-05-08')); - const items = makeArmoireIitemList(); + const items = armoire.all; expect(items.length).to.equal(396); forEach(items, item => { if (item.set !== undefined) { @@ -48,29 +36,30 @@ describe('armoire', () => { it('releases gear when appropriate', async () => { clock = sinon.useFakeTimers(new Date('2024-01-01T00:00:00.000Z')); - const items = makeArmoireIitemList(); + const items = armoire.all; expect(items.length).to.equal(377); clock.restore(); delete require.cache[require.resolve('../../website/common/script/content/gear/sets/armoire')]; clock = sinon.useFakeTimers(new Date('2024-01-08')); - const januaryItems = makeArmoireIitemList(); + const januaryItems = armoire.all; expect(januaryItems.length).to.equal(381); clock.restore(); delete require.cache[require.resolve('../../website/common/script/content/gear/sets/armoire')]; clock = sinon.useFakeTimers(new Date('2024-02-07')); - const januaryItems2 = makeArmoireIitemList(); + const januaryItems2 = armoire.all; expect(januaryItems2.length).to.equal(381); clock.restore(); delete require.cache[require.resolve('../../website/common/script/content/gear/sets/armoire')]; - clock = sinon.useFakeTimers(new Date('2024-02-07T16:00:00.000Z')); - const febuaryItems = makeArmoireIitemList(); + clock = sinon.useFakeTimers(new Date('2024-02-07T09:00:00.000Z')); + const febuaryItems = armoire.all; expect(febuaryItems.length).to.equal(384); }); it('sets have at least 2 items', () => { - const armoire = makeArmoireIitemList(); const setMap = {}; - forEach(armoire, item => { + forEach(armoire.all, item => { + // Gotta have one outlier + if (!item.set || item.set.startsWith('armoire-')) return; if (setMap[item.set] === undefined) { setMap[item.set] = 0; } diff --git a/test/content/eggs.test.js b/test/content/eggs.test.js index cb0e173579..69dcb47798 100644 --- a/test/content/eggs.test.js +++ b/test/content/eggs.test.js @@ -5,29 +5,51 @@ import { expectValidTranslationString, } from '../helpers/content.helper'; -import * as eggs from '../../website/common/script/content/eggs'; +import eggs from '../../website/common/script/content/eggs'; describe('eggs', () => { - describe('all', () => { - it('is a combination of drop and quest eggs', () => { - const dropNumber = Object.keys(eggs.drops).length; - const questNumber = Object.keys(eggs.quests).length; - const allNumber = Object.keys(eggs.all).length; + let clock; - expect(allNumber).to.be.greaterThan(0); - expect(allNumber).to.equal(dropNumber + questNumber); - }); + afterEach(() => { + if (clock) { + clock.restore(); + } + }); - it('contains basic information about each egg', () => { - each(eggs.all, (egg, key) => { - expectValidTranslationString(egg.text); - expectValidTranslationString(egg.adjective); - expectValidTranslationString(egg.mountText); - expectValidTranslationString(egg.notes); - expect(egg.canBuy).to.be.a('function'); - expect(egg.value).to.be.a('number'); - expect(egg.key).to.equal(key); + const eggTypes = [ + 'drops', + 'quests', + ]; + + eggTypes.forEach(eggType => { + describe(eggType, () => { + it('contains basic information about each egg', () => { + each(eggs[eggType], (egg, key) => { + expectValidTranslationString(egg.text); + expectValidTranslationString(egg.adjective); + expectValidTranslationString(egg.mountText); + expectValidTranslationString(egg.notes); + expect(egg.canBuy).to.be.a('function'); + expect(egg.value).to.be.a('number'); + expect(egg.key).to.equal(key); + }); }); }); }); + + it('does not contain unreleased eggs', () => { + clock = sinon.useFakeTimers(new Date('2024-05-20')); + const questEggs = eggs.quests; + expect(questEggs.Giraffe).to.not.exist; + }); + + it('Releases eggs when appropriate without needing restarting', () => { + clock = sinon.useFakeTimers(new Date('2024-05-20')); + const mayEggs = eggs.quests; + clock.restore(); + clock = sinon.useFakeTimers(new Date('2024-06-20')); + const juneEggs = eggs.quests; + expect(juneEggs.Giraffe).to.exist; + expect(Object.keys(mayEggs).length).to.equal(Object.keys(juneEggs).length - 1); + }); }); diff --git a/test/content/index.test.js b/test/content/index.test.js new file mode 100644 index 0000000000..54ea054b64 --- /dev/null +++ b/test/content/index.test.js @@ -0,0 +1,154 @@ +import content from '../../website/common/script/content'; + +describe('content index', () => { + let clock; + + afterEach(() => { + if (clock) { + clock.restore(); + } + }); + + it('Releases eggs when appropriate without needing restarting', () => { + clock = sinon.useFakeTimers(new Date('2024-06-20')); + const mayEggs = content.eggs; + expect(mayEggs.Chameleon).to.not.exist; + clock.restore(); + clock = sinon.useFakeTimers(new Date('2024-07-20')); + const juneEggs = content.eggs; + expect(juneEggs.Chameleon).to.exist; + expect(Object.keys(mayEggs).length, '').to.equal(Object.keys(juneEggs).length - 1); + }); + + it('Releases hatching potions when appropriate without needing restarting', () => { + clock = sinon.useFakeTimers(new Date('2024-05-20')); + const mayHatchingPotions = content.hatchingPotions; + expect(mayHatchingPotions.Koi).to.not.exist; + clock.restore(); + clock = sinon.useFakeTimers(new Date('2024-06-20')); + const juneHatchingPotions = content.hatchingPotions; + expect(juneHatchingPotions.Koi).to.exist; + expect(Object.keys(mayHatchingPotions).length, '').to.equal(Object.keys(juneHatchingPotions).length - 1); + }); + + it('Releases armoire gear when appropriate without needing restarting', () => { + clock = sinon.useFakeTimers(new Date('2024-06-20')); + const juneGear = content.gear.flat; + expect(juneGear.armor_armoire_corsairsCoatAndCape).to.not.exist; + clock.restore(); + clock = sinon.useFakeTimers(new Date('2024-07-10')); + const julyGear = content.gear.flat; + expect(julyGear.armor_armoire_corsairsCoatAndCape).to.exist; + expect(Object.keys(juneGear).length, '').to.equal(Object.keys(julyGear).length - 3); + }); + + it('Releases pets gear when appropriate without needing restarting', () => { + clock = sinon.useFakeTimers(new Date('2024-06-20')); + const junePets = content.petInfo; + expect(junePets['Chameleon-Base']).to.not.exist; + clock.restore(); + clock = sinon.useFakeTimers(new Date('2024-07-10')); + const julyPets = content.petInfo; + expect(julyPets['Chameleon-Base']).to.exist; + expect(Object.keys(junePets).length, '').to.equal(Object.keys(julyPets).length - 10); + }); + + it('Releases mounts gear when appropriate without needing restarting', () => { + clock = sinon.useFakeTimers(new Date('2024-06-20')); + const juneMounts = content.mountInfo; + expect(juneMounts['Chameleon-Base']).to.not.exist; + clock.restore(); + clock = sinon.useFakeTimers(new Date('2024-07-10')); + const julyMounts = content.mountInfo; + expect(julyMounts['Chameleon-Base']).to.exist; + expect(Object.keys(juneMounts).length, '').to.equal(Object.keys(julyMounts).length - 10); + }); + + it('marks regular food as buyable and droppable without any events', () => { + clock = sinon.useFakeTimers(new Date('2024-06-20')); + const { food } = content; + Object.keys(food).forEach(key => { + if (key === 'Saddle') { + expect(food[key].canBuy(), `${key} canBuy`).to.be.true; + expect(food[key].canDrop, `${key} canDrop`).to.be.false; + return; + } + let expected = true; + if (key.startsWith('Cake_')) { + expected = false; + } else if (key.startsWith('Candy_')) { + expected = false; + } else if (key.startsWith('Pie_')) { + expected = false; + } + expect(food[key].canBuy(), `${key} canBuy`).to.equal(expected); + expect(food[key].canDrop, `${key} canDrop`).to.equal(expected); + }); + }); + + it('marks candy as buyable and droppable during habitoween', () => { + clock = sinon.useFakeTimers(new Date('2024-10-31')); + const { food } = content; + Object.keys(food).forEach(key => { + if (key === 'Saddle') { + expect(food[key].canBuy(), `${key} canBuy`).to.be.true; + expect(food[key].canDrop, `${key} canDrop`).to.be.false; + return; + } + let expected = false; + if (key.startsWith('Cake_')) { + expected = false; + } else if (key.startsWith('Candy_')) { + expected = true; + } else if (key.startsWith('Pie_')) { + expected = false; + } + expect(food[key].canBuy(), `${key} canBuy`).to.equal(expected); + expect(food[key].canDrop, `${key} canDrop`).to.equal(expected); + }); + }); + + it('marks cake as buyable and droppable during birthday', () => { + clock = sinon.useFakeTimers(new Date('2024-01-31')); + const { food } = content; + Object.keys(food).forEach(key => { + if (key === 'Saddle') { + expect(food[key].canBuy(), `${key} canBuy`).to.be.true; + expect(food[key].canDrop, `${key} canDrop`).to.be.false; + return; + } + let expected = false; + if (key.startsWith('Cake_')) { + expected = true; + } else if (key.startsWith('Candy_')) { + expected = false; + } else if (key.startsWith('Pie_')) { + expected = false; + } + expect(food[key].canBuy(), `${key} canBuy`).to.equal(expected); + expect(food[key].canDrop, `${key} canDrop`).to.equal(expected); + }); + }); + + it('marks pie as buyable and droppable during pi day', () => { + clock = sinon.useFakeTimers(new Date('2024-03-14')); + const { food } = content; + Object.keys(food).forEach(key => { + if (key === 'Saddle') { + expect(food[key].canBuy(), `${key} canBuy`).to.be.true; + expect(food[key].canDrop, `${key} canDrop`).to.be.false; + return; + } + let expected = false; + if (key.startsWith('Cake_')) { + expected = false; + } else if (key.startsWith('Candy_')) { + expected = false; + } else if (key.startsWith('Pie_')) { + expected = true; + } + expect(food[key].canBuy(), `${key} canBuy`).to.equal(expected); + expect(food[key].canDrop, `${key} canDrop`).to.equal(expected); + }); + }); +}); diff --git a/test/content/releaseDates.test.js b/test/content/releaseDates.test.js new file mode 100644 index 0000000000..1c5fad92b3 --- /dev/null +++ b/test/content/releaseDates.test.js @@ -0,0 +1,82 @@ +import find from 'lodash/find'; +import maxBy from 'lodash/maxBy'; +import { + ARMOIRE_RELEASE_DATES, + EGGS_RELEASE_DATES, + HATCHING_POTIONS_RELEASE_DATES, +} from '../../website/common/script/content/constants/releaseDates'; +import armoire from '../../website/common/script/content/gear/sets/armoire'; +import eggs from '../../website/common/script/content/eggs'; +import hatchingPotions from '../../website/common/script/content/hatching-potions'; + +describe('releaseDates', () => { + let clock; + + afterEach(() => { + if (clock) { + clock.restore(); + } + }); + describe('armoire', () => { + it('should only contain valid armoire names', () => { + const lastReleaseDate = maxBy(Object.values(ARMOIRE_RELEASE_DATES), value => new Date(`${value.year}-${value.month + 1}-20`)); + clock = sinon.useFakeTimers(new Date(`${lastReleaseDate.year}-${lastReleaseDate.month + 1}-20`)); + Object.keys(ARMOIRE_RELEASE_DATES).forEach(key => { + expect(find(armoire.all, { set: key }), `${key} is not a valid armoire set`).to.exist; + }); + }); + + it('should contain a valid year and month', () => { + Object.keys(ARMOIRE_RELEASE_DATES).forEach(key => { + const date = ARMOIRE_RELEASE_DATES[key]; + expect(date.year, `${key} year is not a valid year`).to.be.a('number'); + expect(date.year).to.be.at.least(2023); + expect(date.month, `${key} month is not a valid month`).to.be.a('number'); + expect(date.month).to.be.within(1, 12); + expect(date.day).to.not.exist; + }); + }); + }); + + describe('eggs', () => { + it('should only contain valid egg names', () => { + const lastReleaseDate = maxBy(Object.values(EGGS_RELEASE_DATES), value => new Date(`${value.year}-${value.month + 1}-${value.day}`)); + clock = sinon.useFakeTimers(new Date(`${lastReleaseDate.year}-${lastReleaseDate.month + 1}-${lastReleaseDate.day}`)); + Object.keys(EGGS_RELEASE_DATES).forEach(key => { + expect(eggs.all[key], `${key} is not a valid egg name`).to.exist; + }); + }); + + it('should contain a valid year, month and date', () => { + Object.keys(EGGS_RELEASE_DATES).forEach(key => { + const date = EGGS_RELEASE_DATES[key]; + expect(date.year, `${key} year is not a valid year`).to.be.a('number'); + expect(date.year).to.be.at.least(2024); + expect(date.month, `${key} month is not a valid month`).to.be.a('number'); + expect(date.month).to.be.within(1, 12); + expect(date.day, `${key} day is not a valid day`).to.be.a('number'); + }); + }); + }); + + describe('hatchingPotions', () => { + it('should only contain valid potion names', () => { + const lastReleaseDate = maxBy(Object.values(HATCHING_POTIONS_RELEASE_DATES), value => new Date(`${value.year}-${value.month + 1}-${value.day}`)); + clock = sinon.useFakeTimers(new Date(`${lastReleaseDate.year}-${lastReleaseDate.month + 1}-${lastReleaseDate.day}`)); + Object.keys(HATCHING_POTIONS_RELEASE_DATES).forEach(key => { + expect(hatchingPotions.all[key], `${key} is not a valid potion name`).to.exist; + }); + }); + + it('should contain a valid year, month and date', () => { + Object.keys(HATCHING_POTIONS_RELEASE_DATES).forEach(key => { + const date = HATCHING_POTIONS_RELEASE_DATES[key]; + expect(date.year, `${key} year is not a valid year`).to.be.a('number'); + expect(date.year).to.be.at.least(2024); + expect(date.month, `${key} month is not a valid month`).to.be.a('number'); + expect(date.month).to.be.within(1, 12); + expect(date.day, `${key} day is not a valid day`).to.be.a('number'); + }); + }); + }); +}); diff --git a/test/content/stable.test.js b/test/content/stable.test.js index 3266cb7f47..b5950dbf12 100644 --- a/test/content/stable.test.js +++ b/test/content/stable.test.js @@ -6,12 +6,21 @@ import { } from '../helpers/content.helper'; import t from '../../website/common/script/content/translation'; -import * as stable from '../../website/common/script/content/stable'; -import * as eggs from '../../website/common/script/content/eggs'; -import * as potions from '../../website/common/script/content/hatching-potions'; +import stable from '../../website/common/script/content/stable'; +import eggs from '../../website/common/script/content/eggs'; +import potions from '../../website/common/script/content/hatching-potions'; describe('stable', () => { describe('dropPets', () => { + let clock; + beforeEach(() => { + clock = sinon.useFakeTimers(new Date('2020-05-20')); + }); + + afterEach(() => { + clock.restore(); + }); + it('contains a pet for each drop potion * each drop egg', () => { const numberOfDropPotions = Object.keys(potions.drops).length; const numberOfDropEggs = Object.keys(eggs.drops).length; diff --git a/website/client/src/components/hall/heroes.vue b/website/client/src/components/hall/heroes.vue index 06a12b0384..25721640e9 100644 --- a/website/client/src/components/hall/heroes.vue +++ b/website/client/src/components/hall/heroes.vue @@ -320,7 +320,7 @@