From 9d7da91ec60d84b7ec8f1792f2601bcc863c5a31 Mon Sep 17 00:00:00 2001 From: CuriousMagpie Date: Thu, 13 Jun 2024 14:44:59 -0400 Subject: [PATCH 01/39] add sprites --- .../assets/css/sprites/spritesmith-main.css | 299 +++++++++++++++++- 1 file changed, 292 insertions(+), 7 deletions(-) diff --git a/website/client/src/assets/css/sprites/spritesmith-main.css b/website/client/src/assets/css/sprites/spritesmith-main.css index 64894a875f..d8e8e0c4b6 100644 --- a/website/client/src/assets/css/sprites/spritesmith-main.css +++ b/website/client/src/assets/css/sprites/spritesmith-main.css @@ -1875,6 +1875,11 @@ width: 141px; height: 147px; } +.background_river_bottom { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_river_bottom.png'); + width: 141px; + height: 147px; +} .background_river_of_lava { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_river_of_lava.png'); width: 141px; @@ -3773,6 +3778,11 @@ width: 68px; height: 68px; } +.icon_background_river_bottom { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_river_bottom.png'); + width: 68px; + height: 68px; +} .icon_background_river_of_lava { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_river_of_lava.png'); width: 68px; @@ -31442,6 +31452,11 @@ width: 90px; height: 90px; } +.broad_armor_armoire_corsairsCoatAndCape { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_armoire_corsairsCoatAndCape.png'); + width: 114px; + height: 90px; +} .broad_armor_armoire_coverallsOfBookbinding { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_armoire_coverallsOfBookbinding.png'); width: 114px; @@ -32007,6 +32022,11 @@ width: 114px; height: 90px; } +.head_armoire_corsairsBandana { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_armoire_corsairsBandana.png'); + width: 114px; + height: 90px; +} .head_armoire_crownOfDiamonds { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_armoire_crownOfDiamonds.png'); width: 114px; @@ -32827,8 +32847,8 @@ width: 68px; height: 68px; } -.shop_armor_armoire_bluestripedSwimsuit { - background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_armor_armoire_bluestripedSwimsuit.png'); +.shop_armor_armoire_blueStripedSwimsuit { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_armor_armoire_blueStripedSwimsuit.png'); width: 68px; height: 68px; } @@ -32872,6 +32892,11 @@ width: 68px; height: 68px; } +.shop_armor_armoire_corsairsCoatAndCape { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_armor_armoire_corsairsCoatAndCape.png'); + width: 68px; + height: 68px; +} .shop_armor_armoire_coverallsOfBookbinding { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_armor_armoire_coverallsOfBookbinding.png'); width: 68px; @@ -33497,6 +33522,11 @@ width: 68px; height: 68px; } +.shop_head_armoire_corsairsBandana { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_head_armoire_corsairsBandana.png'); + width: 68px; + height: 68px; +} .shop_head_armoire_crownOfDiamonds { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_head_armoire_crownOfDiamonds.png'); width: 68px; @@ -34357,6 +34387,11 @@ width: 68px; height: 68px; } +.shop_weapon_armoire_corsairsBlade { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_weapon_armoire_corsairsBlade.png'); + width: 68px; + height: 68px; +} .shop_weapon_armoire_crystalCrescentStaff { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_weapon_armoire_crystalCrescentStaff.png'); width: 68px; @@ -34872,6 +34907,11 @@ width: 90px; height: 90px; } +.slim_armor_armoire_corsairsCoatAndCape { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_armoire_corsairsCoatAndCape.png'); + width: 114px; + height: 90px; +} .slim_armor_armoire_coverallsOfBookbinding { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_armoire_coverallsOfBookbinding.png'); width: 114px; @@ -35387,6 +35427,11 @@ width: 90px; height: 90px; } +.weapon_armoire_corsairsBlade { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_armoire_corsairsBlade.png'); + width: 114px; + height: 90px; +} .weapon_armoire_crystalCrescentStaff { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_armoire_crystalCrescentStaff.png'); width: 90px; @@ -42032,6 +42077,36 @@ width: 114px; height: 90px; } +.broad_armor_mystery_202407 { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_mystery_202407.png'); + width: 117px; + height: 120px; +} +.head_mystery_202407 { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_mystery_202407.png'); + width: 117px; + height: 120px; +} +.shop_armor_mystery_202407 { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_armor_mystery_202407.png'); + width: 68px; + height: 68px; +} +.shop_head_mystery_202407 { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_head_mystery_202407.png'); + width: 68px; + height: 68px; +} +.shop_set_mystery_202407 { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_set_mystery_202407.png'); + width: 68px; + height: 68px; +} +.slim_armor_mystery_202407 { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_mystery_202407.png'); + width: 117px; + height: 120px; +} .broad_armor_mystery_301404 { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_mystery_301404.png'); width: 90px; @@ -50475,6 +50550,11 @@ width: 219px; height: 219px; } +.quest_chameleon { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/quest_chameleon.png'); + width: 216px; + height: 216px; +} .quest_cheetah { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/quest_cheetah.png'); width: 219px; @@ -51185,6 +51265,11 @@ width: 68px; height: 68px; } +.inventory_quest_scroll_chameleon { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/inventory_quest_scroll_chameleon.png'); + width: 60px; + height: 60px; +} .inventory_quest_scroll_cheetah { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/inventory_quest_scroll_cheetah.png'); width: 68px; @@ -52060,6 +52145,11 @@ width: 68px; height: 68px; } +.Pet_Egg_Chameleon { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet_Egg_Chameleon.png'); + width: 68px; + height: 68px; +} .Pet_Egg_Cheetah { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet_Egg_Cheetah.png'); width: 68px; @@ -53460,6 +53550,56 @@ width: 105px; height: 105px; } +.Mount_Body_Chameleon-Base { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Chameleon-Base.png'); + width: 105px; + height: 105px; +} +.Mount_Body_Chameleon-CottonCandyBlue { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Chameleon-CottonCandyBlue.png'); + width: 105px; + height: 105px; +} +.Mount_Body_Chameleon-CottonCandyPink { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Chameleon-CottonCandyPink.png'); + width: 105px; + height: 105px; +} +.Mount_Body_Chameleon-Desert { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Chameleon-Desert.png'); + width: 105px; + height: 105px; +} +.Mount_Body_Chameleon-Golden { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Chameleon-Golden.png'); + width: 105px; + height: 105px; +} +.Mount_Body_Chameleon-Red { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Chameleon-Red.png'); + width: 105px; + height: 105px; +} +.Mount_Body_Chameleon-Shade { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Chameleon-Shade.png'); + width: 105px; + height: 105px; +} +.Mount_Body_Chameleon-Skeleton { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Chameleon-Skeleton.png'); + width: 105px; + height: 105px; +} +.Mount_Body_Chameleon-White { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Chameleon-White.png'); + width: 105px; + height: 105px; +} +.Mount_Body_Chameleon-Zombie { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Chameleon-Zombie.png'); + width: 105px; + height: 105px; +} .Mount_Body_Cheetah-Base { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Cheetah-Base.png'); width: 105px; @@ -58755,6 +58895,56 @@ width: 105px; height: 105px; } +.Mount_Head_Chameleon-Base { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Chameleon-Base.png'); + width: 105px; + height: 105px; +} +.Mount_Head_Chameleon-CottonCandyBlue { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Chameleon-CottonCandyBlue.png'); + width: 105px; + height: 105px; +} +.Mount_Head_Chameleon-CottonCandyPink { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Chameleon-CottonCandyPink.png'); + width: 105px; + height: 105px; +} +.Mount_Head_Chameleon-Desert { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Chameleon-Desert.png'); + width: 105px; + height: 105px; +} +.Mount_Head_Chameleon-Golden { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Chameleon-Golden.png'); + width: 105px; + height: 105px; +} +.Mount_Head_Chameleon-Red { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Chameleon-Red.png'); + width: 105px; + height: 105px; +} +.Mount_Head_Chameleon-Shade { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Chameleon-Shade.png'); + width: 105px; + height: 105px; +} +.Mount_Head_Chameleon-Skeleton { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Chameleon-Skeleton.png'); + width: 105px; + height: 105px; +} +.Mount_Head_Chameleon-White { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Chameleon-White.png'); + width: 105px; + height: 105px; +} +.Mount_Head_Chameleon-Zombie { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Chameleon-Zombie.png'); + width: 105px; + height: 105px; +} .Mount_Head_Cheetah-Base { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Cheetah-Base.png'); width: 105px; @@ -64055,6 +64245,56 @@ width: 81px; height: 99px; } +.Mount_Icon_Chameleon-Base { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_Chameleon-Base.png'); + width: 81px; + height: 99px; +} +.Mount_Icon_Chameleon-CottonCandyBlue { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_Chameleon-CottonCandyBlue.png'); + width: 81px; + height: 99px; +} +.Mount_Icon_Chameleon-CottonCandyPink { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_Chameleon-CottonCandyPink.png'); + width: 81px; + height: 99px; +} +.Mount_Icon_Chameleon-Desert { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_Chameleon-Desert.png'); + width: 81px; + height: 99px; +} +.Mount_Icon_Chameleon-Golden { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_Chameleon-Golden.png'); + width: 81px; + height: 99px; +} +.Mount_Icon_Chameleon-Red { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_Chameleon-Red.png'); + width: 81px; + height: 99px; +} +.Mount_Icon_Chameleon-Shade { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_Chameleon-Shade.png'); + width: 81px; + height: 99px; +} +.Mount_Icon_Chameleon-Skeleton { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_Chameleon-Skeleton.png'); + width: 81px; + height: 99px; +} +.Mount_Icon_Chameleon-White { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_Chameleon-White.png'); + width: 81px; + height: 99px; +} +.Mount_Icon_Chameleon-Zombie { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_Chameleon-Zombie.png'); + width: 81px; + height: 99px; +} .Mount_Icon_Cheetah-Base { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_Cheetah-Base.png'); width: 81px; @@ -69415,6 +69655,56 @@ width: 81px; height: 99px; } +.Pet-Chameleon-Base { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Chameleon-Base.png'); + width: 81px; + height: 99px; +} +.Pet-Chameleon-CottonCandyBlue { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Chameleon-CottonCandyBlue.png'); + width: 81px; + height: 99px; +} +.Pet-Chameleon-CottonCandyPink { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Chameleon-CottonCandyPink.png'); + width: 81px; + height: 99px; +} +.Pet-Chameleon-Desert { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Chameleon-Desert.png'); + width: 81px; + height: 99px; +} +.Pet-Chameleon-Golden { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Chameleon-Golden.png'); + width: 81px; + height: 99px; +} +.Pet-Chameleon-Red { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Chameleon-Red.png'); + width: 81px; + height: 99px; +} +.Pet-Chameleon-Shade { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Chameleon-Shade.png'); + width: 81px; + height: 99px; +} +.Pet-Chameleon-Skeleton { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Chameleon-Skeleton.png'); + width: 81px; + height: 99px; +} +.Pet-Chameleon-White { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Chameleon-White.png'); + width: 81px; + height: 99px; +} +.Pet-Chameleon-Zombie { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Chameleon-Zombie.png'); + width: 81px; + height: 99px; +} .Pet-Cheetah-Base { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Cheetah-Base.png'); width: 81px; @@ -73985,11 +74275,6 @@ width: 81px; height: 99px; } -.Pet_HatchingPotion_Koi { - background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet_HatchingPotion_Koi.png'); - width: 68px; - height: 68px; -} .Pet_HatchingPotion_Amber { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet_HatchingPotion_Amber.png'); width: 68px; From 44d63032d81ac58aded8c4c856df7fe5d89f5ef4 Mon Sep 17 00:00:00 2001 From: CuriousMagpie Date: Thu, 13 Jun 2024 15:38:23 -0400 Subject: [PATCH 02/39] add subscriber gear, enchanted armoire, and background --- website/common/locales/en/backgrounds.json | 4 ++++ website/common/locales/en/gear.json | 12 +++++++++++- website/common/locales/en/subscriber.json | 1 + .../common/script/content/appearance/backgrounds.js | 3 +++ website/common/script/content/gear/sets/armoire.js | 12 ++++++++++++ website/common/script/content/gear/sets/mystery.js | 1 + 6 files changed, 32 insertions(+), 1 deletion(-) diff --git a/website/common/locales/en/backgrounds.json b/website/common/locales/en/backgrounds.json index f40eabfddd..e43155c11f 100644 --- a/website/common/locales/en/backgrounds.json +++ b/website/common/locales/en/backgrounds.json @@ -983,6 +983,10 @@ "backgroundShellGateText": "Shell Gate", "backgroundShellGateNotes": "", + "backgrounds072024": "SET 122: Released July 2024", + "backgroundRiverBottomText": "River Bottom", + "backgroundRiverBottomNotes": "", + "timeTravelBackgrounds": "Steampunk Backgrounds", "backgroundAirshipText": "Airship", "backgroundAirshipNotes": "Become a sky sailor on board your very own Airship.", diff --git a/website/common/locales/en/gear.json b/website/common/locales/en/gear.json index 8fca1db0d2..7b8b412efb 100644 --- a/website/common/locales/en/gear.json +++ b/website/common/locales/en/gear.json @@ -770,6 +770,8 @@ "weaponArmoirePottersWheelNotes": "Throw some clay on this wheel and make a bowl or a mug or a vase or a slightly different bowl. If you're lucky, a ghost might visit while you create! Increases Perception by <%= per %>. Enchanted Armoire: Potter Set (Item 4 of 4).", "weaponArmoireBeachUmbrellaText": "Beach Umbrella", "weaponArmoireBeachUmbrellaNotes": "The shade of this rainbow-colored umbrella conceals you briefly from the day star and any unwanted bothers. Increases Perception by <%= per %>. Enchanted Armoire: Beachside Set (Item 3 of 4).", + "weaponArmoireCorsairsBladeText": "Corsair’s Blade", + "weaponArmoireCorsairsBladeNotes": "Whether you wield it to plunder or to protect, you can be glad you brought this fierce blade to sea with you. Just be sure to stow it safely when not in use. Increases Strength by <%= str %>. Enchanted Armoire: Corsair Set (Item 3 of 3)", "armor": "armor", "armorCapitalized": "Armor", @@ -1399,7 +1401,9 @@ "armorMystery202401Text": "Snowy Spellbinder Robes", "armorMystery202401Notes": "These robes appear as delicate as crystal snowflakes, but will keep you plenty warm as you work your wintry magic. Confers no benefit. January 2024 Subscriber Item.", "armorMystery202406Text": "Phantom Buccaneer’s Attire", - "armorMystery202406Notes": "Haunt your enemies with style and flair! Confers no benefit. June 2024 Subscriber Item.", + "armorMystery202406Notes": "Haunt your enemies with style and flair! Confers no benefit. June 2024 Subscriber Item.", + "armorMystery202407Text": "Amiable Axolotl Suit", + "armorMystery202407Notes": "Glide through lakes and canals with your sweeping pink tail!", "armorMystery301404Text": "Steampunk Suit", "armorMystery301404Notes": "Dapper and dashing, wot! Confers no benefit. February 3015 Subscriber Item.", @@ -1616,6 +1620,8 @@ "armorArmoireYellowStripedSwimsuitNotes": "What could be more delightful than battling sea monsters on the beach? Increases Constitution by <%= con %>. Enchanted Armoire: Beachside Set (Item 1 of 4).", "armorArmoireBlueStripedSwimsuitText": "Blue Striped Swimsuit", "armorArmoireBlueStripedSwimsuitNotes": "What could be more exciting than battling sea monsters on the beach? Increases Constitution by <%= con %>. Enchanted Armoire: Beachside Set (Item 2 of 4).", + "armorArmoireCorsairsCoatAndCapeText": "Corsair’s Coat and Cape:", + "armorArmoireCorsairsCoatAndCapeNotes": "Whether you’re biding your time on the docks or watching for danger on the open seas, these will surely keep you feeling dry and looking dramatic. Just keep your balance on deck. Increases Constitution by <%= con %>. Enchanted Armoire: Corsair Set (Item 1 of 3)", "headgear": "helm", "headgearCapitalized": "Headgear", @@ -2279,6 +2285,8 @@ "headMystery202404Notes": "This hat will connect you with the earth and allow you to hear secret wishes from many creatures. Confers no benefit. April 2024 Subscriber Item.", "headMystery202406Text": "Phantom Buccaneer’s Hat", "headMystery202406Notes": "The ghostly feathers that adorn this hat glow faintly, like the waves of a spectral sea. Confers no benefit. June 2024 Subscriber Item.", + "headMystery202407Text": "Amiable Axolotl Hood", + "headMystery202407Notes": "These magical gills will let you breathe underwater!", "headMystery301404Text": "Fancy Top Hat", "headMystery301404Notes": "A fancy top hat for the finest of gentlefolk! January 3015 Subscriber Item. Confers no benefit.", @@ -2475,6 +2483,8 @@ "headArmoireHattersTopHatNotes": "Our hats are off to you, and yours is on! What’s hidden in your hat is anybody’s guess (but we’re hoping it’s a bunny). Increases Perception by <%= per %>. Enchanted Armoire: Hatter Set (Item 1 of 4).", "headArmoirePottersBandanaText": "Bandana", "headArmoirePottersBandanaNotes": "Look the part and keep your hair out of your face while you work. It’s a win-win! Increases Intelligence by <%= int %>. Enchanted Armoire: Potter Set (Item 2 of 4).", + "headArmoireCorsairsBandanaText": "Corsair’s Bandana", + "headArmoireCorsairsBandanaNotes": "Whether you’re keeping your head covered in case a seagull flies overhead or making sure your foes never see you sweat, this bandana is essential. Just add a decorative bead for every adventure you complete. Increases Intelligence by <%= int %>. Enchanted Armoire: Corsair Set (Item 2 of 3)", "offhand": "off-hand item", "offHandCapitalized": "Off-Hand Item", diff --git a/website/common/locales/en/subscriber.json b/website/common/locales/en/subscriber.json index baee718d17..e8f885d01f 100644 --- a/website/common/locales/en/subscriber.json +++ b/website/common/locales/en/subscriber.json @@ -163,6 +163,7 @@ "mysterySet202404": "Mycelial Magus Set", "mysterySet202405": "Gilded Dragon Set", "mysterySet202406": "Phantom Buccaneer Set", + "mysterySet202407": "Amiable Axolotl Set", "mysterySet301404": "Steampunk Standard Set", "mysterySet301405": "Steampunk Accessories Set", "mysterySet301703": "Peacock Steampunk Set", diff --git a/website/common/script/content/appearance/backgrounds.js b/website/common/script/content/appearance/backgrounds.js index 6f96769f2a..deb2931211 100644 --- a/website/common/script/content/appearance/backgrounds.js +++ b/website/common/script/content/appearance/backgrounds.js @@ -625,6 +625,9 @@ const plannedBackgrounds = { backgrounds062024: { shell_gate: { }, }, + backgrounds072024: { + river_bottom: { }, + }, eventBackgrounds: { birthday_bash: { price: 0, diff --git a/website/common/script/content/gear/sets/armoire.js b/website/common/script/content/gear/sets/armoire.js index 8c4084ed9d..6f91894126 100644 --- a/website/common/script/content/gear/sets/armoire.js +++ b/website/common/script/content/gear/sets/armoire.js @@ -485,6 +485,10 @@ const armor = { con: 13, set: 'beachsideSet', }, + corsairsCoatAndCape: { + con: 14, + set: 'corsairSet', + }, }; const body = { @@ -994,6 +998,10 @@ const head = { int: 8, set: 'pottersSet', }, + corsairsBandana: { + int: 7, + set: 'corsairSet', + }, }; const shield = { @@ -1831,6 +1839,10 @@ const weapon = { str: 12, set: 'beachsideSet', }, + corsairsBlade: { + str: 7, + set: 'corsairSet', + }, }; const SWITCHOVER_TIME = nconf.get('CONTENT_SWITCHOVER_TIME_OFFSET') || 0; diff --git a/website/common/script/content/gear/sets/mystery.js b/website/common/script/content/gear/sets/mystery.js index 9d673fc4f4..787bd0b39f 100644 --- a/website/common/script/content/gear/sets/mystery.js +++ b/website/common/script/content/gear/sets/mystery.js @@ -66,6 +66,7 @@ const armor = { 202310: { }, 202401: { }, 202406: { }, + 202407: { }, 301404: { }, 301703: { }, 301704: { }, From b8a3440ef2fd0bf26e1305e749bcefab2c446d84 Mon Sep 17 00:00:00 2001 From: CuriousMagpie Date: Thu, 13 Jun 2024 16:40:04 -0400 Subject: [PATCH 03/39] fix mystery item and background description --- website/common/locales/en/backgrounds.json | 2 +- website/common/script/content/gear/sets/mystery.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/website/common/locales/en/backgrounds.json b/website/common/locales/en/backgrounds.json index e43155c11f..97c1a40b5a 100644 --- a/website/common/locales/en/backgrounds.json +++ b/website/common/locales/en/backgrounds.json @@ -985,7 +985,7 @@ "backgrounds072024": "SET 122: Released July 2024", "backgroundRiverBottomText": "River Bottom", - "backgroundRiverBottomNotes": "", + "backgroundRiverBottomNotes": "Explore a River Bottom.", "timeTravelBackgrounds": "Steampunk Backgrounds", "backgroundAirshipText": "Airship", diff --git a/website/common/script/content/gear/sets/mystery.js b/website/common/script/content/gear/sets/mystery.js index 787bd0b39f..d886b97e87 100644 --- a/website/common/script/content/gear/sets/mystery.js +++ b/website/common/script/content/gear/sets/mystery.js @@ -227,6 +227,7 @@ const head = { 202403: { }, 202404: { }, 202406: { }, + 202407: { }, 301404: { }, 301405: { }, 301703: { }, From d05da3722ce1d86a840d6f73b4ef78309c84a2f6 Mon Sep 17 00:00:00 2001 From: CuriousMagpie Date: Thu, 13 Jun 2024 17:12:43 -0400 Subject: [PATCH 04/39] add June background notes --- website/common/locales/en/backgrounds.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/common/locales/en/backgrounds.json b/website/common/locales/en/backgrounds.json index 97c1a40b5a..1e0ca8bd46 100644 --- a/website/common/locales/en/backgrounds.json +++ b/website/common/locales/en/backgrounds.json @@ -981,7 +981,7 @@ "backgrounds062024": "SET 121: Released June 2024", "backgroundShellGateText": "Shell Gate", - "backgroundShellGateNotes": "", + "backgroundShellGateNotes": "Swim beneath a shimmering Shell Gate.", "backgrounds072024": "SET 122: Released July 2024", "backgroundRiverBottomText": "River Bottom", From 3810cf3ef3c492bda8d343596bf1a17f9fc1e36e Mon Sep 17 00:00:00 2001 From: CuriousMagpie Date: Fri, 14 Jun 2024 10:42:47 -0400 Subject: [PATCH 05/39] add chameleon quest --- website/common/locales/en/content.json | 4 +++ website/common/locales/en/questsContent.json | 8 ++++- website/common/script/content/eggs.js | 6 ++++ website/common/script/content/quests/pets.js | 32 ++++++++++++++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/website/common/locales/en/content.json b/website/common/locales/en/content.json index a96f154512..41f6903ba9 100644 --- a/website/common/locales/en/content.json +++ b/website/common/locales/en/content.json @@ -255,6 +255,10 @@ "questEggGiraffeMountText": "Giraffe", "questEggGiraffeAdjective": "a towering", + "questEggChameleonText": "Chameleon", + "questEggChameleonMountText": "Chameleon", + "questEggChameleonAdjective": "a chaotic", + "eggNotes": "Find a hatching potion to pour on this egg, and it will hatch into <%= eggAdjective(locale) %> <%= eggText(locale) %>.", "hatchingPotionBase": "Base", diff --git a/website/common/locales/en/questsContent.json b/website/common/locales/en/questsContent.json index 3b36ec6de1..56815e6eaf 100644 --- a/website/common/locales/en/questsContent.json +++ b/website/common/locales/en/questsContent.json @@ -895,7 +895,13 @@ "questGiraffeBoss": "Gear-affe", "questGiraffeDropGiraffeEgg": "Giraffe (Egg)", "QuestGiraffeUnlockText": "Unlocks Giraffe Eggs for purchase in the Market.", - "questPinkMarbleUnlockText": "Unlocks Pink Marble Hatching Potions for purchase in the Market.", + + "questChameleonText": "The Chaotic Chameleon", + "questChameleonNotes": "It’s a beautiful day in a warm, rainy corner of the Taskwoods. You’re on the hunt for new additions to your leaf collection when a branch in front of you changes color without warning! Then it moves!

Stumbling backwards, you realize this is not a branch at all, but a huge chameleon! Each part of his body keeps changing colors as his eyes dart in different directions.

“Are you all right?” you ask the chameleon.

“Ahhh, well,” he says, looking a little flustered. “I’ve been trying to blend in… but it’s so overwhelming… the colors keep coming and going! It’s hard to focus on just one....”

“Aha,” you say, “I think I can help. We’ll sharpen your focus with a little challenge! Get your colors ready!”

“You’re on!” replied the chameleon.", + "questChameleonCompletion": "After a few lively turns the Chameleon went through every color of the rainbow, perfectly matching each color you requested.

“Wow,” he says, “working together and making it into a game really helped me concentrate! Please take these as a reward, you’re earned them! Teach these little guys how to change all the colors of the rainbow when they hatch.”", + "questChameleonBoss": "Chaotic Chameleon", + "questChameleonDropChameleonEgg": "Chameleon (Egg)", + "QuestChameleonUnlockText": "Unlocks Chameleon Eggs for purchase in the Market", "questFungiText": "The Moody Mushroom", "questFungiNotes": "It’s been a rainy spring in Habitica and the ground around the stables is spongy and damp. You notice quite a few mushrooms have appeared along the wooden stable walls and fences. There’s a fog hanging about, not quite letting the sun peek through, and it’s a bit dispiriting.

Out of the mist you see the outline of the April Fool, not at all his usual bouncy self.

”I’d hoped to bring you all some delightful Fungi Magic Hatching Potions so that you can keep your mushroom friends from my special day forever,” he says, his expression alarmingly unsmiling. “But this cold fog is really getting to me, it’s making me feel too tired and dismal to work my usual magic.”

“Oh no, sorry to hear that,” you say, noticing your own increasingly somber mood. “This fog is really making the day gloomy. I wonder where it came from…”

A low rumble sounds across the fields, and you see an outline emerging from the mist. You’re alarmed to see a gigantic and unhappy looking mushroom creature, and the mist appears to be emanating from it.

“Aha,” says the Fool, “I think this fungal fellow may be the source of our blues. Let’s see if we can summon a little cheer for our friend here and ourselves.”", diff --git a/website/common/script/content/eggs.js b/website/common/script/content/eggs.js index 0a6e438e5b..43967437b6 100644 --- a/website/common/script/content/eggs.js +++ b/website/common/script/content/eggs.js @@ -396,6 +396,12 @@ const quests = { adjective: t('questEggGiraffeAdjective'), canBuy: hasQuestAchievementFunction('giraffe'), }, + Chameleon: { + text: t('questEggChameleonText'), + mountText: t('questEggChameleonMountText'), + adjective: t('questEggChameleonAdjective'), + canBuy: hasQuestAchievementFunction('chameleon'), + }, }; applyEggDefaults(drops, { diff --git a/website/common/script/content/quests/pets.js b/website/common/script/content/quests/pets.js index 7d0f6f6e3a..0c7bfabdac 100644 --- a/website/common/script/content/quests/pets.js +++ b/website/common/script/content/quests/pets.js @@ -232,6 +232,38 @@ const QUEST_PETS = { unlock: t('questButterflyUnlockText'), }, }, + chameleon: { + text: t('questChameleonText'), + notes: t('questChameleonNotes'), + completion: t('questChameleonCompletion'), + value: 4, + category: 'pet', + boss: { + name: t('questChameleonBoss'), + hp: 400, + str: 1.5, + }, + drop: { + items: [ + { + type: 'eggs', + key: 'Chameleon', + text: t('questChameleonDropChameleonEgg'), + }, { + type: 'eggs', + key: 'Chameleon', + text: t('questChameleonDropChameleonEgg'), + }, { + type: 'eggs', + key: 'Chameleon', + text: t('questChameleonDropChameleonEgg'), + }, + ], + }, + gp: 35, + xp: 250, + unlock: t('questChameleonUnlockText'), + }, cheetah: { text: t('questCheetahText'), notes: t('questCheetahNotes'), From fb8479ad1e887b7f94dd6eec47980d4da593bee9 Mon Sep 17 00:00:00 2001 From: CuriousMagpie Date: Mon, 17 Jun 2024 13:44:36 -0400 Subject: [PATCH 06/39] finish July prebuild --- website/common/locales/en/backgrounds.json | 2 +- website/common/script/content/constants/schedule.js | 1 + website/common/script/content/quests/pets.js | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/website/common/locales/en/backgrounds.json b/website/common/locales/en/backgrounds.json index 1e0ca8bd46..97c1a40b5a 100644 --- a/website/common/locales/en/backgrounds.json +++ b/website/common/locales/en/backgrounds.json @@ -981,7 +981,7 @@ "backgrounds062024": "SET 121: Released June 2024", "backgroundShellGateText": "Shell Gate", - "backgroundShellGateNotes": "Swim beneath a shimmering Shell Gate.", + "backgroundShellGateNotes": "", "backgrounds072024": "SET 122: Released July 2024", "backgroundRiverBottomText": "River Bottom", diff --git a/website/common/script/content/constants/schedule.js b/website/common/script/content/constants/schedule.js index 089eb2486b..d62b909228 100644 --- a/website/common/script/content/constants/schedule.js +++ b/website/common/script/content/constants/schedule.js @@ -376,6 +376,7 @@ export const MONTHLY_SCHEDULE = { 'dilatory_derby', 'armadillo', 'guineapig', + 'chameleon', ], }, { diff --git a/website/common/script/content/quests/pets.js b/website/common/script/content/quests/pets.js index 0c7bfabdac..f0ced0ba06 100644 --- a/website/common/script/content/quests/pets.js +++ b/website/common/script/content/quests/pets.js @@ -259,10 +259,10 @@ const QUEST_PETS = { text: t('questChameleonDropChameleonEgg'), }, ], + gp: 35, + exp: 250, + unlock: t('questChameleonUnlockText'), }, - gp: 35, - xp: 250, - unlock: t('questChameleonUnlockText'), }, cheetah: { text: t('questCheetahText'), From d47641e25a6dfb9b62f1c10d810e80eb0990ea20 Mon Sep 17 00:00:00 2001 From: CuriousMagpie Date: Tue, 18 Jun 2024 12:46:59 -0400 Subject: [PATCH 07/39] typo fix --- website/common/locales/en/gear.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/common/locales/en/gear.json b/website/common/locales/en/gear.json index 7b8b412efb..0e1b1798a7 100644 --- a/website/common/locales/en/gear.json +++ b/website/common/locales/en/gear.json @@ -1620,7 +1620,7 @@ "armorArmoireYellowStripedSwimsuitNotes": "What could be more delightful than battling sea monsters on the beach? Increases Constitution by <%= con %>. Enchanted Armoire: Beachside Set (Item 1 of 4).", "armorArmoireBlueStripedSwimsuitText": "Blue Striped Swimsuit", "armorArmoireBlueStripedSwimsuitNotes": "What could be more exciting than battling sea monsters on the beach? Increases Constitution by <%= con %>. Enchanted Armoire: Beachside Set (Item 2 of 4).", - "armorArmoireCorsairsCoatAndCapeText": "Corsair’s Coat and Cape:", + "armorArmoireCorsairsCoatAndCapeText": "Corsair’s Coat and Cape", "armorArmoireCorsairsCoatAndCapeNotes": "Whether you’re biding your time on the docks or watching for danger on the open seas, these will surely keep you feeling dry and looking dramatic. Just keep your balance on deck. Increases Constitution by <%= con %>. Enchanted Armoire: Corsair Set (Item 1 of 3)", "headgear": "helm", From f2506c32316df6836ee19489320b289f4dc97a35 Mon Sep 17 00:00:00 2001 From: CuriousMagpie Date: Tue, 18 Jun 2024 13:24:21 -0400 Subject: [PATCH 08/39] updated sprites css --- .../client/src/assets/css/sprites/spritesmith-main.css | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/website/client/src/assets/css/sprites/spritesmith-main.css b/website/client/src/assets/css/sprites/spritesmith-main.css index d8e8e0c4b6..54b5f96238 100644 --- a/website/client/src/assets/css/sprites/spritesmith-main.css +++ b/website/client/src/assets/css/sprites/spritesmith-main.css @@ -50210,6 +50210,11 @@ width: 28px; height: 28px; } +.icon_pet_veteran_cactus { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_pet_veteran_cactus.png'); + width: 28px; + height: 28px; +} .icon_pet_veteran_dragon { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_pet_veteran_dragon.png'); width: 28px; @@ -51267,8 +51272,8 @@ } .inventory_quest_scroll_chameleon { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/inventory_quest_scroll_chameleon.png'); - width: 60px; - height: 60px; + width: 68px; + height: 68px; } .inventory_quest_scroll_cheetah { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/inventory_quest_scroll_cheetah.png'); From 21a7d36b7ba1d86e30b60e25d778b01062ed11ba Mon Sep 17 00:00:00 2001 From: CuriousMagpie Date: Tue, 18 Jun 2024 13:45:09 -0400 Subject: [PATCH 09/39] update sprites --- .../client/src/assets/css/sprites/spritesmith-main.css | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/website/client/src/assets/css/sprites/spritesmith-main.css b/website/client/src/assets/css/sprites/spritesmith-main.css index d8e8e0c4b6..54b5f96238 100644 --- a/website/client/src/assets/css/sprites/spritesmith-main.css +++ b/website/client/src/assets/css/sprites/spritesmith-main.css @@ -50210,6 +50210,11 @@ width: 28px; height: 28px; } +.icon_pet_veteran_cactus { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_pet_veteran_cactus.png'); + width: 28px; + height: 28px; +} .icon_pet_veteran_dragon { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_pet_veteran_dragon.png'); width: 28px; @@ -51267,8 +51272,8 @@ } .inventory_quest_scroll_chameleon { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/inventory_quest_scroll_chameleon.png'); - width: 60px; - height: 60px; + width: 68px; + height: 68px; } .inventory_quest_scroll_cheetah { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/inventory_quest_scroll_cheetah.png'); From f5f4974a733fc3ebad1dd5da77bb44b48e91b7cc Mon Sep 17 00:00:00 2001 From: CuriousMagpie Date: Tue, 18 Jun 2024 14:58:13 -0400 Subject: [PATCH 10/39] update habitica-images --- habitica-images | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/habitica-images b/habitica-images index aa72332019..e21c292a6c 160000 --- a/habitica-images +++ b/habitica-images @@ -1 +1 @@ -Subproject commit aa723320199d7f03ce749d431b46e8d7f95cc8de +Subproject commit e21c292a6cc2a57c13094c0a94192aff6458c9bb From 2645bf60239a838d5a506f69ca7c8ce38042bf25 Mon Sep 17 00:00:00 2001 From: CuriousMagpie Date: Tue, 18 Jun 2024 15:02:47 -0400 Subject: [PATCH 11/39] update habitica images --- habitica-images | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/habitica-images b/habitica-images index aa72332019..e21c292a6c 160000 --- a/habitica-images +++ b/habitica-images @@ -1 +1 @@ -Subproject commit aa723320199d7f03ce749d431b46e8d7f95cc8de +Subproject commit e21c292a6cc2a57c13094c0a94192aff6458c9bb From 89a3ac3ddebf8e949f584c39092e0cc961cde04a Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Mon, 10 Jun 2024 14:11:38 +0200 Subject: [PATCH 12/39] allow eggs to have a release date # Conflicts: # test/content/armoire.test.js --- test/content/eggs.test.js | 58 +++++++++++------ test/content/stable.test.js | 11 +++- .../script/content/constants/release_dates.js | 15 +++++ website/common/script/content/eggs.js | 21 +++++-- .../script/content/gear/sets/armoire.js | 19 ++---- website/common/script/content/index.js | 5 +- website/common/script/content/is_released.js | 30 +++++++++ website/common/script/content/stable.js | 62 ++++++------------- website/common/script/fns/datedMemoize.js | 4 ++ website/common/script/fns/firstDrops.js | 4 +- 10 files changed, 143 insertions(+), 86 deletions(-) create mode 100644 website/common/script/content/constants/release_dates.js create mode 100644 website/common/script/content/is_released.js 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/stable.test.js b/test/content/stable.test.js index 3266cb7f47..ca1475d631 100644 --- a/test/content/stable.test.js +++ b/test/content/stable.test.js @@ -7,11 +7,20 @@ import { 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 eggs from '../../website/common/script/content/eggs'; import * as 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/common/script/content/constants/release_dates.js b/website/common/script/content/constants/release_dates.js new file mode 100644 index 0000000000..e7edd2b9c8 --- /dev/null +++ b/website/common/script/content/constants/release_dates.js @@ -0,0 +1,15 @@ +export const ARMOIRE_RELEASE_DATES = { + somethingSpooky: { year: 2023, month: 10 }, + cookingImplementsTwo: { year: 2023, month: 11 }, + greenTrapper: { year: 2023, month: 12 }, + schoolUniform: { year: 2024, month: 1 }, + whiteLoungeWear: { year: 2024, month: 2 }, + hatterSet: { year: 2024, month: 3 }, + optimistSet: { year: 2024, month: 4 }, + pottersSet: { year: 2024, month: 5 }, + beachsideSet: { year: 2024, month: 6 }, +}; + +export const EGGS_RELEASE_DATES = { + Giraffe: { year: 2024, month: 6, day: 1 }, +}; diff --git a/website/common/script/content/eggs.js b/website/common/script/content/eggs.js index 43967437b6..cfb9e74569 100644 --- a/website/common/script/content/eggs.js +++ b/website/common/script/content/eggs.js @@ -1,7 +1,9 @@ -import assign from 'lodash/assign'; import defaults from 'lodash/defaults'; import each from 'lodash/each'; import t from './translation'; +import { filterReleased } from './is_released'; +import { EGGS_RELEASE_DATES } from './constants/release_dates'; +import datedMemoize from '../fns/datedMemoize'; function applyEggDefaults (set, config) { each(set, (egg, key) => { @@ -416,10 +418,17 @@ applyEggDefaults(quests, { }, }); -const all = assign({}, drops, quests); +function filterEggs (eggs) { + return filterReleased(eggs, 'key', EGGS_RELEASE_DATES); +} -export { - drops, - quests, - all, +const memoizedFilter = datedMemoize(filterEggs); + +export default { + get drops () { + return memoizedFilter({ memoizeConfig: true, identifier: 'drops' }, drops); + }, + get quests () { + return memoizedFilter({ memoizeConfig: true, identifier: 'quests' }, quests); + }, }; diff --git a/website/common/script/content/gear/sets/armoire.js b/website/common/script/content/gear/sets/armoire.js index 6f91894126..1671c39360 100644 --- a/website/common/script/content/gear/sets/armoire.js +++ b/website/common/script/content/gear/sets/armoire.js @@ -2,12 +2,13 @@ import defaults from 'lodash/defaults'; import find from 'lodash/find'; import forEach from 'lodash/forEach'; import moment from 'moment'; -import nconf from 'nconf'; import upperFirst from 'lodash/upperFirst'; import { ownsItem } from '../gear-helper'; import { ATTRIBUTES } from '../../../constants'; import t from '../../translation'; import memoize from '../../../fns/datedMemoize'; +import { ARMOIRE_RELEASE_DATES as releaseDates } from '../../constants/release_dates'; +import { buildReleaseDate } from '../../is_released'; const armor = { lunarArmor: { @@ -1845,19 +1846,7 @@ const weapon = { }, }; -const SWITCHOVER_TIME = nconf.get('CONTENT_SWITCHOVER_TIME_OFFSET') || 0; const releaseDay = 7; -const releaseDates = { - somethingSpooky: { year: 2023, month: 10 }, - cookingImplementsTwo: { year: 2023, month: 11 }, - greenTrapper: { year: 2023, month: 12 }, - schoolUniform: { year: 2024, month: 1 }, - whiteLoungeWear: { year: 2024, month: 2 }, - hatterSet: { year: 2024, month: 3 }, - optimistSet: { year: 2024, month: 4 }, - pottersSet: { year: 2024, month: 5 }, - beachsideSet: { year: 2024, month: 6 }, -}; forEach({ armor, @@ -1902,12 +1891,12 @@ forEach({ function updateReleased (type) { const today = moment(); - const releaseDateEndPart = `${String(releaseDay).padStart(2, '0')}T${String(SWITCHOVER_TIME).padStart(2, '0')}:00-0500`; const returnType = {}; forEach(type, (gearItem, gearKey) => { let released; if (releaseDates[gearItem.set]) { - const releaseDateString = `${releaseDates[gearItem.set].year}-${String(releaseDates[gearItem.set].month).padStart(2, '0')}-${releaseDateEndPart}`; + const components = releaseDates[gearItem.set]; + const releaseDateString = buildReleaseDate(components.year, components.month, releaseDay); released = today.isAfter(releaseDateString); } else { released = true; diff --git a/website/common/script/content/index.js b/website/common/script/content/index.js index 0de5f5d5f0..f6ba549919 100644 --- a/website/common/script/content/index.js +++ b/website/common/script/content/index.js @@ -1,5 +1,6 @@ import defaults from 'lodash/defaults'; import each from 'lodash/each'; +import assign from 'lodash/assign'; import moment from 'moment'; import t from './translation'; import { tasksByCategory } from './tasks'; @@ -18,7 +19,7 @@ import { import achievements from './achievements'; -import * as eggs from './eggs'; +import eggs from './eggs'; import * as hatchingPotions from './hatching-potions'; import * as stable from './stable'; import gear from './gear'; @@ -167,7 +168,7 @@ api.special = api.spells.special; api.dropEggs = eggs.drops; api.questEggs = eggs.quests; -api.eggs = eggs.all; +api.eggs = assign({}, eggs.drops, eggs.quests); api.timeTravelStable = { pets: { diff --git a/website/common/script/content/is_released.js b/website/common/script/content/is_released.js new file mode 100644 index 0000000000..e1b4f69cef --- /dev/null +++ b/website/common/script/content/is_released.js @@ -0,0 +1,30 @@ +import moment from 'moment'; +import filter from 'lodash/filter'; +import { pickBy } from 'lodash'; +import nconf from 'nconf'; + +const SWITCHOVER_TIME = nconf.get('CONTENT_SWITCHOVER_TIME_OFFSET') || 0; + +const releaseDateEndPart = `T${String(SWITCHOVER_TIME).padStart(2, '0')}:00-0000`; + +export function buildReleaseDate (year, month, day = 1) { + return `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}${releaseDateEndPart}`; +} + +function isReleased (item, fieldName, releaseDateMap, releaseByDefault) { + if (releaseDateMap[item[fieldName]]) { + const release = releaseDateMap[item[fieldName]]; + if (release.day) { + return moment().isAfter(moment(buildReleaseDate(release.year, release.month, release.day))); + } + return moment().isAfter(releaseDateMap[item[fieldName]]); + } + return releaseByDefault; +} + +export function filterReleased (items, fieldName, releaseDateMap, releaseByDefault = true) { + if (typeof items === 'object') { + return pickBy(items, item => isReleased(item, fieldName, releaseDateMap, releaseByDefault)); + } + return filter(items, item => isReleased(item, fieldName, releaseDateMap, releaseByDefault)); +} diff --git a/website/common/script/content/stable.js b/website/common/script/content/stable.js index e6015f6e77..93d72d482f 100644 --- a/website/common/script/content/stable.js +++ b/website/common/script/content/stable.js @@ -1,10 +1,7 @@ import each from 'lodash/each'; import moment from 'moment'; import { EVENTS } from './constants/events'; -import { - drops as dropEggs, - quests as questEggs, -} from './eggs'; +import allEggs from './eggs'; import { drops as dropPotions, premium as premiumPotions, @@ -12,10 +9,14 @@ import { } from './hatching-potions'; import t from './translation'; +const STABLE_RELEASE_DATES = { + +}; + const petInfo = {}; const mountInfo = {}; -function constructSet (type, eggs, potions) { +function constructSet (type, eggs, potions, hasMounts = true) { const pets = {}; const mounts = {}; @@ -37,52 +38,24 @@ function constructSet (type, eggs, potions) { potion: potion.text, egg: egg.text, })); - mountInfo[key] = getAnimalData(t('mountName', { - potion: potion.text, - mount: egg.mountText, - })); - pets[key] = true; - mounts[key] = true; - }); - }); - return [pets, mounts]; -} - -function constructPetOnlySet (type, eggs, potions) { - const pets = {}; - - each(eggs, egg => { - each(potions, potion => { - const key = `${egg.key}-${potion.key}`; - - function getAnimalData (text) { - return { - key, - type, - potion: potion.key, - egg: egg.key, - text, - }; + if (hasMounts) { + mountInfo[key] = getAnimalData(t('mountName', { + potion: potion.text, + mount: egg.mountText, + })); + mounts[key] = true; } - - petInfo[key] = getAnimalData(t('petName', { - potion: potion.text, - egg: egg.text, - })); - pets[key] = true; }); }); + if (hasMounts) { + return [pets, mounts]; + } return pets; } -const [dropPets, dropMounts] = constructSet('drop', dropEggs, dropPotions); -const [premiumPets, premiumMounts] = constructSet('premium', dropEggs, premiumPotions); -const [questPets, questMounts] = constructSet('quest', questEggs, dropPotions); -const wackyPets = constructPetOnlySet('wacky', dropEggs, wackyPotions); - const canFindSpecial = { pets: { // Veteran Pet Ladder - awarded on major updates @@ -158,6 +131,11 @@ const canFindSpecial = { }, }; +const [dropPets, dropMounts] = constructSet('drop', allEggs.drops, dropPotions); +const [premiumPets, premiumMounts] = constructSet('premium', allEggs.drops, premiumPotions); +const [questPets, questMounts] = constructSet('quest', allEggs.quests, dropPotions); +const wackyPets = constructSet('wacky', allEggs.drops, wackyPotions, false); + const specialPets = { 'Wolf-Veteran': 'veteranWolf', 'Wolf-Cerberus': 'cerberusPup', diff --git a/website/common/script/fns/datedMemoize.js b/website/common/script/fns/datedMemoize.js index 6e91fbc52c..c71ab59248 100644 --- a/website/common/script/fns/datedMemoize.js +++ b/website/common/script/fns/datedMemoize.js @@ -33,6 +33,10 @@ const memoize = fn => { identifier = config.identifier; } } + + if (identifier.length === 0) { + identifier = args.filter(arg => typeof arg === 'string').join('-'); + } } if (!checkedDate) { checkedDate = new Date(); diff --git a/website/common/script/fns/firstDrops.js b/website/common/script/fns/firstDrops.js index cfcd5c933a..7a2413cb97 100644 --- a/website/common/script/fns/firstDrops.js +++ b/website/common/script/fns/firstDrops.js @@ -1,9 +1,9 @@ -import { drops as eggs } from '../content/eggs'; +import allEggs from '../content/eggs'; import { drops as hatchingPotions } from '../content/hatching-potions'; import randomVal from '../libs/randomVal'; export default function firstDrops (user) { - const eggDrop = randomVal(eggs); + const eggDrop = randomVal(allEggs.drops); const potionDrop = randomVal(hatchingPotions); user.items.eggs = { From 3333f8f0f59d0a69fcd715ee3f690518f7a710b5 Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Mon, 10 Jun 2024 14:24:59 +0200 Subject: [PATCH 13/39] allow hatching potions to have a release date --- test/content/stable.test.js | 2 +- .../script/content/constants/release_dates.js | 4 ++++ website/common/script/content/eggs.js | 4 ++++ .../common/script/content/hatching-potions.js | 24 ++++++++++++++++--- website/common/script/content/index.js | 5 ++-- website/common/script/content/stable.js | 18 ++++---------- website/common/script/fns/firstDrops.js | 4 ++-- 7 files changed, 39 insertions(+), 22 deletions(-) diff --git a/test/content/stable.test.js b/test/content/stable.test.js index ca1475d631..218e340e78 100644 --- a/test/content/stable.test.js +++ b/test/content/stable.test.js @@ -8,7 +8,7 @@ import t from '../../website/common/script/content/translation'; import * as stable from '../../website/common/script/content/stable'; import eggs from '../../website/common/script/content/eggs'; -import * as potions from '../../website/common/script/content/hatching-potions'; +import potions from '../../website/common/script/content/hatching-potions'; describe('stable', () => { describe('dropPets', () => { diff --git a/website/common/script/content/constants/release_dates.js b/website/common/script/content/constants/release_dates.js index e7edd2b9c8..46fd821d55 100644 --- a/website/common/script/content/constants/release_dates.js +++ b/website/common/script/content/constants/release_dates.js @@ -13,3 +13,7 @@ export const ARMOIRE_RELEASE_DATES = { export const EGGS_RELEASE_DATES = { Giraffe: { year: 2024, month: 6, day: 1 }, }; + +export const HATCHING_POTIONS_RELEASE_DATES = { + Koi: { year: 2024, month: 6, day: 1 }, +}; diff --git a/website/common/script/content/eggs.js b/website/common/script/content/eggs.js index cfb9e74569..9bd2098641 100644 --- a/website/common/script/content/eggs.js +++ b/website/common/script/content/eggs.js @@ -1,5 +1,6 @@ import defaults from 'lodash/defaults'; import each from 'lodash/each'; +import assign from 'lodash/assign'; import t from './translation'; import { filterReleased } from './is_released'; import { EGGS_RELEASE_DATES } from './constants/release_dates'; @@ -431,4 +432,7 @@ export default { get quests () { return memoizedFilter({ memoizeConfig: true, identifier: 'quests' }, quests); }, + get all () { + return assign({}, this.drops, this.quests); + }, }; diff --git a/website/common/script/content/hatching-potions.js b/website/common/script/content/hatching-potions.js index e392f9f666..ed7498c007 100644 --- a/website/common/script/content/hatching-potions.js +++ b/website/common/script/content/hatching-potions.js @@ -2,6 +2,9 @@ import defaults from 'lodash/defaults'; import each from 'lodash/each'; import { assign } from 'lodash'; import t from './translation'; +import datedMemoize from '../fns/datedMemoize'; +import { filterReleased } from './is_released'; +import { HATCHING_POTIONS_RELEASE_DATES } from './constants/release_dates'; function hasQuestAchievementFunction (key) { return user => user.achievements.quests && user.achievements.quests[key] > 0; @@ -193,8 +196,23 @@ each(wacky, (pot, key) => { }); }); -const all = assign({}, drops, premium, wacky); +function filterEggs (eggs) { + return filterReleased(eggs, 'key', HATCHING_POTIONS_RELEASE_DATES); +} -export { - drops, premium, wacky, all, +const memoizedFilter = datedMemoize(filterEggs); + +export default { + get drops () { + return memoizedFilter({ memoizeConfig: true, identifier: 'drops' }, drops); + }, + get premium () { + return memoizedFilter({ memoizeConfig: true, identifier: 'premium' }, premium); + }, + get wacky () { + return memoizedFilter({ memoizeConfig: true, identifier: 'wacky' }, wacky); + }, + get all () { + return assign({}, this.drops, this.premium, this.wacky); + }, }; diff --git a/website/common/script/content/index.js b/website/common/script/content/index.js index f6ba549919..af344f4264 100644 --- a/website/common/script/content/index.js +++ b/website/common/script/content/index.js @@ -1,6 +1,5 @@ import defaults from 'lodash/defaults'; import each from 'lodash/each'; -import assign from 'lodash/assign'; import moment from 'moment'; import t from './translation'; import { tasksByCategory } from './tasks'; @@ -20,7 +19,7 @@ import { import achievements from './achievements'; import eggs from './eggs'; -import * as hatchingPotions from './hatching-potions'; +import hatchingPotions from './hatching-potions'; import * as stable from './stable'; import gear from './gear'; import { quests, questsByLevel, userCanOwnQuestCategories } from './quests'; @@ -168,7 +167,7 @@ api.special = api.spells.special; api.dropEggs = eggs.drops; api.questEggs = eggs.quests; -api.eggs = assign({}, eggs.drops, eggs.quests); +api.eggs = eggs.all; api.timeTravelStable = { pets: { diff --git a/website/common/script/content/stable.js b/website/common/script/content/stable.js index 93d72d482f..1f08886df3 100644 --- a/website/common/script/content/stable.js +++ b/website/common/script/content/stable.js @@ -2,17 +2,9 @@ import each from 'lodash/each'; import moment from 'moment'; import { EVENTS } from './constants/events'; import allEggs from './eggs'; -import { - drops as dropPotions, - premium as premiumPotions, - wacky as wackyPotions, -} from './hatching-potions'; +import allPotions from './hatching-potions'; import t from './translation'; -const STABLE_RELEASE_DATES = { - -}; - const petInfo = {}; const mountInfo = {}; @@ -131,10 +123,10 @@ const canFindSpecial = { }, }; -const [dropPets, dropMounts] = constructSet('drop', allEggs.drops, dropPotions); -const [premiumPets, premiumMounts] = constructSet('premium', allEggs.drops, premiumPotions); -const [questPets, questMounts] = constructSet('quest', allEggs.quests, dropPotions); -const wackyPets = constructSet('wacky', allEggs.drops, wackyPotions, false); +const [dropPets, dropMounts] = constructSet('drop', allEggs.drops, allPotions.drops); +const [premiumPets, premiumMounts] = constructSet('premium', allEggs.drops, allPotions.premium); +const [questPets, questMounts] = constructSet('quest', allEggs.quests, allPotions.drops); +const wackyPets = constructSet('wacky', allEggs.drops, allPotions.wacky, false); const specialPets = { 'Wolf-Veteran': 'veteranWolf', diff --git a/website/common/script/fns/firstDrops.js b/website/common/script/fns/firstDrops.js index 7a2413cb97..5272dcc72e 100644 --- a/website/common/script/fns/firstDrops.js +++ b/website/common/script/fns/firstDrops.js @@ -1,10 +1,10 @@ import allEggs from '../content/eggs'; -import { drops as hatchingPotions } from '../content/hatching-potions'; +import allPotions from '../content/hatching-potions'; import randomVal from '../libs/randomVal'; export default function firstDrops (user) { const eggDrop = randomVal(allEggs.drops); - const potionDrop = randomVal(hatchingPotions); + const potionDrop = randomVal(allPotions.drops); user.items.eggs = { ...user.items.eggs, From fc63c906ddf4956fbe40543b66cb65cf570de36b Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Mon, 10 Jun 2024 14:44:21 +0200 Subject: [PATCH 14/39] Improve test coverage --- test/content/releaseDates.test.js | 66 +++++++++++++++++++ .../{release_dates.js => releaseDates.js} | 0 website/common/script/content/eggs.js | 2 +- .../script/content/gear/sets/armoire.js | 2 +- .../common/script/content/hatching-potions.js | 2 +- 5 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 test/content/releaseDates.test.js rename website/common/script/content/constants/{release_dates.js => releaseDates.js} (100%) diff --git a/test/content/releaseDates.test.js b/test/content/releaseDates.test.js new file mode 100644 index 0000000000..e481146ccb --- /dev/null +++ b/test/content/releaseDates.test.js @@ -0,0 +1,66 @@ +import find from 'lodash/find'; +import { + ARMOIRE_RELEASE_DATES, + EGGS_RELEASE_DATES, + HATCHING_POTIONS_RELEASE_DATES, +} from '../../website/common/script/content/constants/releaseDates'; +import content from '../../website/common/script/content'; + +describe('releaseDates', () => { + describe('armoire', () => { + it('should only contain valid armoire names', () => { + Object.keys(ARMOIRE_RELEASE_DATES).forEach(key => { + expect(find(content.gear.flat, { 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', () => { + Object.keys(EGGS_RELEASE_DATES).forEach(key => { + expect(content.eggs[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', () => { + Object.keys(HATCHING_POTIONS_RELEASE_DATES).forEach(key => { + expect(content.hatchingPotions[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/website/common/script/content/constants/release_dates.js b/website/common/script/content/constants/releaseDates.js similarity index 100% rename from website/common/script/content/constants/release_dates.js rename to website/common/script/content/constants/releaseDates.js diff --git a/website/common/script/content/eggs.js b/website/common/script/content/eggs.js index 9bd2098641..dea7ba21ef 100644 --- a/website/common/script/content/eggs.js +++ b/website/common/script/content/eggs.js @@ -3,7 +3,7 @@ import each from 'lodash/each'; import assign from 'lodash/assign'; import t from './translation'; import { filterReleased } from './is_released'; -import { EGGS_RELEASE_DATES } from './constants/release_dates'; +import { EGGS_RELEASE_DATES } from './constants/releaseDates'; import datedMemoize from '../fns/datedMemoize'; function applyEggDefaults (set, config) { diff --git a/website/common/script/content/gear/sets/armoire.js b/website/common/script/content/gear/sets/armoire.js index 1671c39360..1173ce3c49 100644 --- a/website/common/script/content/gear/sets/armoire.js +++ b/website/common/script/content/gear/sets/armoire.js @@ -7,7 +7,7 @@ import { ownsItem } from '../gear-helper'; import { ATTRIBUTES } from '../../../constants'; import t from '../../translation'; import memoize from '../../../fns/datedMemoize'; -import { ARMOIRE_RELEASE_DATES as releaseDates } from '../../constants/release_dates'; +import { ARMOIRE_RELEASE_DATES as releaseDates } from '../../constants/releaseDates'; import { buildReleaseDate } from '../../is_released'; const armor = { diff --git a/website/common/script/content/hatching-potions.js b/website/common/script/content/hatching-potions.js index ed7498c007..c293b1b99c 100644 --- a/website/common/script/content/hatching-potions.js +++ b/website/common/script/content/hatching-potions.js @@ -4,7 +4,7 @@ import { assign } from 'lodash'; import t from './translation'; import datedMemoize from '../fns/datedMemoize'; import { filterReleased } from './is_released'; -import { HATCHING_POTIONS_RELEASE_DATES } from './constants/release_dates'; +import { HATCHING_POTIONS_RELEASE_DATES } from './constants/releaseDates'; function hasQuestAchievementFunction (key) { return user => user.achievements.quests && user.achievements.quests[key] > 0; From fec68e621147e31c6ba5370ce0126d7e9b86461c Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Wed, 19 Jun 2024 16:02:03 +0200 Subject: [PATCH 15/39] fix tests --- test/api/unit/libs/items/utils.test.js | 2 +- .../unit/middlewares/ensureDevelopmentMode.js | 17 +++++++++-------- .../unit/middlewares/ensureTimeTravelMode.js | 17 +++++++++-------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/test/api/unit/libs/items/utils.test.js b/test/api/unit/libs/items/utils.test.js index d1bf1f126e..9ff116ef95 100644 --- a/test/api/unit/libs/items/utils.test.js +++ b/test/api/unit/libs/items/utils.test.js @@ -117,7 +117,7 @@ describe('Items Utils', () => { it('converts values for owned gear to true/false', () => { expect(castItemVal('items.gear.owned.shield_warrior_0', 'true')).to.equal(true); expect(castItemVal('items.gear.owned.invalid', 'false')).to.equal(false); - expect(castItemVal('items.gear.owned.invalid', 'null')).to.equal(false); + expect(castItemVal('items.gear.owned.invalid', 'null')).to.equal(undefined); expect(castItemVal('items.gear.owned.invalid', 'truthy')).to.equal(true); expect(castItemVal('items.gear.owned.invalid', 0)).to.equal(false); }); diff --git a/test/api/unit/middlewares/ensureDevelopmentMode.js b/test/api/unit/middlewares/ensureDevelopmentMode.js index b3911f9ecd..da5d2cffc0 100644 --- a/test/api/unit/middlewares/ensureDevelopmentMode.js +++ b/test/api/unit/middlewares/ensureDevelopmentMode.js @@ -9,18 +9,19 @@ import ensureDevelopmentMode from '../../../../website/server/middlewares/ensure import { NotFound } from '../../../../website/server/libs/errors'; describe('developmentMode middleware', () => { - let res; let req; let - next; + let res; let req; let next; + let nconfStub; beforeEach(() => { res = generateRes(); req = generateReq(); next = generateNext(); + nconfStub = sandbox.stub(nconf, 'get'); }); it('returns not found when on production URL', () => { - sandbox.stub(nconf, 'get').withArgs('DEBUG_ENABLED').returns(true); - sandbox.stub(nconf, 'get').withArgs('BASE_URL').returns('https://habitica.com'); + nconfStub.withArgs('DEBUG_ENABLED').returns(true); + nconfStub.withArgs('BASE_URL').returns('https://habitica.com'); ensureDevelopmentMode(req, res, next); @@ -29,8 +30,8 @@ describe('developmentMode middleware', () => { }); it('returns not found when intentionally disabled', () => { - sandbox.stub(nconf, 'get').withArgs('DEBUG_ENABLED').returns(false); - sandbox.stub(nconf, 'get').withArgs('BASE_URL').returns('http://localhost:3000'); + nconfStub.withArgs('DEBUG_ENABLED').returns(false); + nconfStub.withArgs('BASE_URL').returns('http://localhost:3000'); ensureDevelopmentMode(req, res, next); @@ -39,8 +40,8 @@ describe('developmentMode middleware', () => { }); it('passes when enabled and on non-production URL', () => { - sandbox.stub(nconf, 'get').withArgs('DEBUG_ENABLED').returns(true); - sandbox.stub(nconf, 'get').withArgs('BASE_URL').returns('http://localhost:3000'); + nconfStub.withArgs('DEBUG_ENABLED').returns(true); + nconfStub.withArgs('BASE_URL').returns('http://localhost:3000'); ensureDevelopmentMode(req, res, next); diff --git a/test/api/unit/middlewares/ensureTimeTravelMode.js b/test/api/unit/middlewares/ensureTimeTravelMode.js index 4a9fa6f56b..6be7d5f4eb 100644 --- a/test/api/unit/middlewares/ensureTimeTravelMode.js +++ b/test/api/unit/middlewares/ensureTimeTravelMode.js @@ -9,18 +9,19 @@ import { NotFound } from '../../../../website/server/libs/errors'; import ensureTimeTravelMode from '../../../../website/server/middlewares/ensureTimeTravelMode'; describe('timetravelMode middleware', () => { - let res; let req; let - next; + let res; let req; let next; + let nconfStub; beforeEach(() => { res = generateRes(); req = generateReq(); next = generateNext(); + nconfStub = sandbox.stub(nconf, 'get'); }); it('returns not found when using production URL', () => { - sandbox.stub(nconf, 'get').withArgs('TIME_TRAVEL_ENABLED').returns(false); - sandbox.stub(nconf, 'get').withArgs('BASE_URL').returns('https://habitica.com'); + nconfStub.withArgs('TIME_TRAVEL_ENABLED').returns(false); + nconfStub.withArgs('BASE_URL').returns('https://habitica.com'); ensureTimeTravelMode(req, res, next); @@ -29,8 +30,8 @@ describe('timetravelMode middleware', () => { }); it('returns not found when not in time travel mode', () => { - sandbox.stub(nconf, 'get').withArgs('TIME_TRAVEL_ENABLED').returns(false); - sandbox.stub(nconf, 'get').withArgs('BASE_URL').returns('http://localhost:3000'); + nconfStub.withArgs('TIME_TRAVEL_ENABLED').returns(false); + nconfStub.withArgs('BASE_URL').returns('http://localhost:3000'); ensureTimeTravelMode(req, res, next); @@ -39,8 +40,8 @@ describe('timetravelMode middleware', () => { }); it('passes when in time travel mode', () => { - sandbox.stub(nconf, 'get').withArgs('TIME_TRAVEL_ENABLED').returns(true); - sandbox.stub(nconf, 'get').withArgs('BASE_URL').returns('http://localhost:3000'); + nconfStub.withArgs('TIME_TRAVEL_ENABLED').returns(true); + nconfStub.withArgs('BASE_URL').returns('http://localhost:3000'); ensureTimeTravelMode(req, res, next); From b6accca5cae1bbb33c450e4462095113cfebe480 Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Wed, 19 Jun 2024 16:33:06 +0200 Subject: [PATCH 16/39] fix armoire tests --- test/content/armoire.test.js | 38 +++++++------------ .../script/content/gear/sets/armoire.js | 12 ++++++ 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/test/content/armoire.test.js b/test/content/armoire.test.js index 5ed052d7a9..7caac823e0 100644 --- a/test/content/armoire.test.js +++ b/test/content/armoire.test.js @@ -3,38 +3,25 @@ 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 +35,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-07T09:00:00.000Z')); - const febuaryItems = makeArmoireIitemList(); + 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/website/common/script/content/gear/sets/armoire.js b/website/common/script/content/gear/sets/armoire.js index 1173ce3c49..244b4d6f1b 100644 --- a/website/common/script/content/gear/sets/armoire.js +++ b/website/common/script/content/gear/sets/armoire.js @@ -1932,4 +1932,16 @@ export default { get weapon () { return memoizedUpdatReleased({ identifier: 'weapon', memoizeConfig: true }, weapon); }, + // convenience method for tests mostly. Not used in the app + get all () { + const items = []; + items.push(...Object.values(this.armor)); + items.push(...Object.values(this.body)); + items.push(...Object.values(this.eyewear)); + items.push(...Object.values(this.head)); + items.push(...Object.values(this.headAccessory)); + items.push(...Object.values(this.shield)); + items.push(...Object.values(this.weapon)); + return items; + }, }; From 5184973bd50fb1f4bf17ab054aa7a5836086a5e1 Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Wed, 19 Jun 2024 16:33:11 +0200 Subject: [PATCH 17/39] fix release date tests --- test/content/releaseDates.test.js | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/test/content/releaseDates.test.js b/test/content/releaseDates.test.js index e481146ccb..1c5fad92b3 100644 --- a/test/content/releaseDates.test.js +++ b/test/content/releaseDates.test.js @@ -1,16 +1,28 @@ 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 content from '../../website/common/script/content'; +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(content.gear.flat, { set: key }), `${key} is not a valid armoire set`).to.exist; + expect(find(armoire.all, { set: key }), `${key} is not a valid armoire set`).to.exist; }); }); @@ -28,8 +40,10 @@ describe('releaseDates', () => { 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(content.eggs[key], `${key} is not a valid egg name`).to.exist; + expect(eggs.all[key], `${key} is not a valid egg name`).to.exist; }); }); @@ -47,8 +61,10 @@ describe('releaseDates', () => { 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(content.hatchingPotions[key], `${key} is not a valid potion name`).to.exist; + expect(hatchingPotions.all[key], `${key} is not a valid potion name`).to.exist; }); }); From 0bc3f16b4b03f88cc5c78fad5aa8d38cfdb9324b Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Wed, 19 Jun 2024 16:33:22 +0200 Subject: [PATCH 18/39] add new content to new release file --- website/common/script/content/constants/releaseDates.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/common/script/content/constants/releaseDates.js b/website/common/script/content/constants/releaseDates.js index 46fd821d55..a639c3f57a 100644 --- a/website/common/script/content/constants/releaseDates.js +++ b/website/common/script/content/constants/releaseDates.js @@ -8,10 +8,12 @@ export const ARMOIRE_RELEASE_DATES = { optimistSet: { year: 2024, month: 4 }, pottersSet: { year: 2024, month: 5 }, beachsideSet: { year: 2024, month: 6 }, + corsairSet: { year: 2024, month: 7 }, }; export const EGGS_RELEASE_DATES = { Giraffe: { year: 2024, month: 6, day: 1 }, + Chameleon: { year: 2024, month: 7, day: 1 }, }; export const HATCHING_POTIONS_RELEASE_DATES = { From 254dd80f2479086637c7cafa9522cf6155b3868f Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Wed, 19 Jun 2024 17:05:14 +0200 Subject: [PATCH 19/39] fix import --- test/content/armoire.test.js | 1 + website/client/src/components/shops/buyModal.vue | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/test/content/armoire.test.js b/test/content/armoire.test.js index 7caac823e0..02e718eca6 100644 --- a/test/content/armoire.test.js +++ b/test/content/armoire.test.js @@ -12,6 +12,7 @@ describe('armoire', () => { clock.restore(); } }); + it('does not return unreleased gear', async () => { clock = sinon.useFakeTimers(new Date('2024-01-02')); const items = armoire.all; diff --git a/website/client/src/components/shops/buyModal.vue b/website/client/src/components/shops/buyModal.vue index 9aeece119e..0f26fd51ae 100644 --- a/website/client/src/components/shops/buyModal.vue +++ b/website/client/src/components/shops/buyModal.vue @@ -586,8 +586,8 @@ import reduce from 'lodash/reduce'; import moment from 'moment'; import planGemLimits from '@/../../common/script/libs/planGemLimits'; -import { drops as dropEggs } from '@/../../common/script/content/eggs'; -import { drops as dropPotions } from '@/../../common/script/content/hatching-potions'; +import eggs from '@/../../common/script/content/eggs'; +import hatchingPotions from '@/../../common/script/content/hatching-potions'; import { avatarEditorUtilities } from '@/mixins/avatarEditUtilities'; import numberInvalid from '@/mixins/numberInvalid'; import spellsMixin from '@/mixins/spells'; @@ -617,6 +617,9 @@ import EquipmentAttributesGrid from '../inventory/equipment/attributesGrid.vue'; import Item from '@/components/inventory/item'; import Avatar from '@/components/avatar'; +const dropEggs = eggs.drops; +const dropPotions = hatchingPotions.drops; + const dropEggKeys = keys(dropEggs); const amountOfDropEggs = size(dropEggs); From 19da14531ca64a18dd68cefe1ada3f2ed1066622 Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Wed, 19 Jun 2024 17:05:25 +0200 Subject: [PATCH 20/39] add chameleon to featured quests --- website/common/script/content/shop-featuredItems.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/common/script/content/shop-featuredItems.js b/website/common/script/content/shop-featuredItems.js index 9712a5b40f..1538683527 100644 --- a/website/common/script/content/shop-featuredItems.js +++ b/website/common/script/content/shop-featuredItems.js @@ -20,6 +20,7 @@ const potentialFeaturedPetQuests = [ 'giraffe', 'guineapig', + 'chameleon', 'cheetah', @@ -34,7 +35,6 @@ const potentialFeaturedPetQuests = [ 'sabretooth', ]; -// hatching potions and food names should be capitalized lest you break the market const featuredItems = { market () { const featured = [{ From 3386d61fdee32e79a6a53939f22e26d3942eaa7f Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Wed, 19 Jun 2024 17:30:37 +0200 Subject: [PATCH 21/39] fix debug tests --- test/api/v3/integration/debug/GET-debug-timeTravelTime.test.js | 2 +- test/api/v3/integration/debug/POST-debug_addHourglass.test.js | 2 +- test/api/v3/integration/debug/POST-debug_addTenGems.test.js | 2 +- test/api/v3/integration/debug/POST-debug_jumpTime.test.js | 2 +- test/api/v3/integration/debug/POST-debug_make-admin.test.js | 2 +- .../v3/integration/debug/POST-debug_modify-inventory.test.js | 2 +- test/api/v3/integration/debug/POST-debug_quest-progress.test.js | 2 +- test/api/v3/integration/debug/POST-debug_set-cron.test.js | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/api/v3/integration/debug/GET-debug-timeTravelTime.test.js b/test/api/v3/integration/debug/GET-debug-timeTravelTime.test.js index b3be755329..329bf7cc9f 100644 --- a/test/api/v3/integration/debug/GET-debug-timeTravelTime.test.js +++ b/test/api/v3/integration/debug/GET-debug-timeTravelTime.test.js @@ -28,7 +28,7 @@ describe('GET /debug/time-travel-time', () => { }); it('returns error when not in time travel mode', async () => { - nconf.set('TIME_TRAVEL_ENABLED', false); + sandbox.stub(nconf, 'get').withArgs('TIME_TRAVEL_ENABLED').returns(false); await expect(user.get('/debug/time-travel-time')) .eventually.be.rejected.and.to.deep.equal({ diff --git a/test/api/v3/integration/debug/POST-debug_addHourglass.test.js b/test/api/v3/integration/debug/POST-debug_addHourglass.test.js index b0ad288348..17520a4e75 100644 --- a/test/api/v3/integration/debug/POST-debug_addHourglass.test.js +++ b/test/api/v3/integration/debug/POST-debug_addHourglass.test.js @@ -23,7 +23,7 @@ describe('POST /debug/add-hourglass', () => { }); it('returns error when not in production mode', async () => { - nconf.set('IS_PROD', true); + sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true); await expect(userToGetHourGlass.post('/debug/add-hourglass')) .eventually.be.rejected.and.to.deep.equal({ diff --git a/test/api/v3/integration/debug/POST-debug_addTenGems.test.js b/test/api/v3/integration/debug/POST-debug_addTenGems.test.js index 74c39a153f..2ac2834cf2 100644 --- a/test/api/v3/integration/debug/POST-debug_addTenGems.test.js +++ b/test/api/v3/integration/debug/POST-debug_addTenGems.test.js @@ -23,7 +23,7 @@ describe('POST /debug/add-ten-gems', () => { }); it('returns error when not in production mode', async () => { - nconf.set('IS_PROD', true); + sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true); await expect(userToGainTenGems.post('/debug/add-ten-gems')) .eventually.be.rejected.and.to.deep.equal({ diff --git a/test/api/v3/integration/debug/POST-debug_jumpTime.test.js b/test/api/v3/integration/debug/POST-debug_jumpTime.test.js index 6580fb9b9f..978b4fe05e 100644 --- a/test/api/v3/integration/debug/POST-debug_jumpTime.test.js +++ b/test/api/v3/integration/debug/POST-debug_jumpTime.test.js @@ -63,7 +63,7 @@ describe('POST /debug/jump-time', () => { }); it('returns error when not in time travel mode', async () => { - nconf.set('TIME_TRAVEL_ENABLED', false); + sandbox.stub(nconf, 'get').withArgs('TIME_TRAVEL_ENABLED').returns(false); await expect(user.post('/debug/jump-time', { offsetDays: 1 })) .eventually.be.rejected.and.to.deep.equal({ diff --git a/test/api/v3/integration/debug/POST-debug_make-admin.test.js b/test/api/v3/integration/debug/POST-debug_make-admin.test.js index c03fa4627f..f0303496a8 100644 --- a/test/api/v3/integration/debug/POST-debug_make-admin.test.js +++ b/test/api/v3/integration/debug/POST-debug_make-admin.test.js @@ -23,7 +23,7 @@ describe('POST /debug/make-admin', () => { }); it('returns error when not in production mode', async () => { - nconf.set('IS_PROD', true); + sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true); await expect(user.post('/debug/make-admin')) .eventually.be.rejected.and.to.deep.equal({ diff --git a/test/api/v3/integration/debug/POST-debug_modify-inventory.test.js b/test/api/v3/integration/debug/POST-debug_modify-inventory.test.js index 8b9f6ac10d..5efec38a6b 100644 --- a/test/api/v3/integration/debug/POST-debug_modify-inventory.test.js +++ b/test/api/v3/integration/debug/POST-debug_modify-inventory.test.js @@ -149,7 +149,7 @@ describe('POST /debug/modify-inventory', () => { }); it('returns error when not in production mode', async () => { - nconf.set('IS_PROD', true); + sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true); await expect(user.post('/debug/modify-inventory')) .eventually.be.rejected.and.to.deep.equal({ diff --git a/test/api/v3/integration/debug/POST-debug_quest-progress.test.js b/test/api/v3/integration/debug/POST-debug_quest-progress.test.js index c74f3bf6af..8d17b68063 100644 --- a/test/api/v3/integration/debug/POST-debug_quest-progress.test.js +++ b/test/api/v3/integration/debug/POST-debug_quest-progress.test.js @@ -48,7 +48,7 @@ describe('POST /debug/quest-progress', () => { }); it('returns error when not in production mode', async () => { - nconf.set('IS_PROD', true); + sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true); await expect(user.post('/debug/quest-progress')) .eventually.be.rejected.and.to.deep.equal({ diff --git a/test/api/v3/integration/debug/POST-debug_set-cron.test.js b/test/api/v3/integration/debug/POST-debug_set-cron.test.js index dfcd99c625..331f19f5fa 100644 --- a/test/api/v3/integration/debug/POST-debug_set-cron.test.js +++ b/test/api/v3/integration/debug/POST-debug_set-cron.test.js @@ -27,7 +27,7 @@ describe('POST /debug/set-cron', () => { }); it('returns error when not in production mode', async () => { - nconf.set('IS_PROD', true); + sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true); await expect(user.post('/debug/set-cron')) .eventually.be.rejected.and.to.deep.equal({ From 74b3b348ff6901e889ef88fd7531d6800d12ab1a Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Wed, 19 Jun 2024 17:32:31 +0200 Subject: [PATCH 22/39] fix buy test --- test/api/v3/integration/user/buy/POST-user_buy.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/api/v3/integration/user/buy/POST-user_buy.test.js b/test/api/v3/integration/user/buy/POST-user_buy.test.js index f91831d37a..7539676c14 100644 --- a/test/api/v3/integration/user/buy/POST-user_buy.test.js +++ b/test/api/v3/integration/user/buy/POST-user_buy.test.js @@ -70,7 +70,6 @@ describe('POST /user/buy/:key', () => { it('buys a special spell', async () => { const key = 'spookySparkles'; const item = content.special[key]; - const stub = sinon.stub(item, 'canOwn').returns(true); await user.updateOne({ 'stats.gp': 250 }); const res = await user.post(`/user/buy/${key}`); From 8dbd3c3db15aac5c3defd294b6c6613cf80136da Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Wed, 19 Jun 2024 17:37:04 +0200 Subject: [PATCH 23/39] fix canOwn test --- test/common/ops/armoireCanOwn.js | 1 + 1 file changed, 1 insertion(+) 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({ From 74dfb2710ff1b246d788d729149062f6f0b77787 Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Wed, 19 Jun 2024 18:01:27 +0200 Subject: [PATCH 24/39] test fixes --- gulp/gulp-tests.js | 2 +- .../debug/GET-debug-timeTravelTime.test.js | 16 +++++++++++----- .../debug/POST-debug_addHourglass.test.js | 13 ++++++++++--- .../debug/POST-debug_addTenGems.test.js | 13 ++++++++++--- .../debug/POST-debug_jumpTime.test.js | 4 +++- .../debug/POST-debug_make-admin.test.js | 11 +++++++++-- .../debug/POST-debug_modify-inventory.test.js | 11 +++++++++-- .../debug/POST-debug_quest-progress.test.js | 11 +++++++++-- .../debug/POST-debug_set-cron.test.js | 11 +++++++++-- .../server/middlewares/ensureDevelopmentMode.js | 1 + 10 files changed, 72 insertions(+), 21 deletions(-) diff --git a/gulp/gulp-tests.js b/gulp/gulp-tests.js index beb1e43132..64ac63902f 100644 --- a/gulp/gulp-tests.js +++ b/gulp/gulp-tests.js @@ -45,7 +45,7 @@ function runInChildProcess (command, options = {}, envVariables = '') { } function integrationTestCommand (testDir) { - return `nyc --no-clean mocha ${testDir} --recursive --require ./test/helpers/start-server`; + return `nyc --silent --no-clean mocha ${testDir} --recursive --require ./test/helpers/start-server`; } /* Test task definitions */ diff --git a/test/api/v3/integration/debug/GET-debug-timeTravelTime.test.js b/test/api/v3/integration/debug/GET-debug-timeTravelTime.test.js index 329bf7cc9f..c2bcc3b87b 100644 --- a/test/api/v3/integration/debug/GET-debug-timeTravelTime.test.js +++ b/test/api/v3/integration/debug/GET-debug-timeTravelTime.test.js @@ -5,30 +5,36 @@ import { describe('GET /debug/time-travel-time', () => { let user; + let nconfStub; + before(async () => { user = await generateUser({ permissions: { fullAccess: true } }); }); - after(() => { - nconf.set('TIME_TRAVEL_ENABLED', false); + beforeEach(() => { + nconfStub = sandbox.stub(nconf, 'get'); + }); + + afterEach(() => { + nconfStub.restore(); }); it('returns the shifted time', async () => { - nconf.set('TIME_TRAVEL_ENABLED', true); + nconfStub.withArgs('TIME_TRAVEL_ENABLED').returns(true); const result = await user.get('/debug/time-travel-time'); expect(result.time).to.exist; await user.post('/debug/jump-time', { disable: true }); }); it('returns shifted when the user is not an admin', async () => { - nconf.set('TIME_TRAVEL_ENABLED', true); + nconfStub.withArgs('TIME_TRAVEL_ENABLED').returns(true); const regularUser = await generateUser(); const result = await regularUser.get('/debug/time-travel-time'); expect(result.time).to.exist; }); it('returns error when not in time travel mode', async () => { - sandbox.stub(nconf, 'get').withArgs('TIME_TRAVEL_ENABLED').returns(false); + nconfStub.withArgs('TIME_TRAVEL_ENABLED').returns(false); await expect(user.get('/debug/time-travel-time')) .eventually.be.rejected.and.to.deep.equal({ diff --git a/test/api/v3/integration/debug/POST-debug_addHourglass.test.js b/test/api/v3/integration/debug/POST-debug_addHourglass.test.js index 17520a4e75..6d7650e07a 100644 --- a/test/api/v3/integration/debug/POST-debug_addHourglass.test.js +++ b/test/api/v3/integration/debug/POST-debug_addHourglass.test.js @@ -5,16 +5,23 @@ import { describe('POST /debug/add-hourglass', () => { let userToGetHourGlass; + let nconfStub; before(async () => { userToGetHourGlass = await generateUser(); }); - after(() => { - nconf.set('IS_PROD', false); + beforeEach(() => { + nconfStub = sandbox.stub(nconf, 'get'); + nconfStub.withArgs('BASE_URL').returns('https://example.com'); + }); + + afterEach(() => { + nconfStub.restore(); }); it('adds Hourglass to the current user', async () => { + nconfStub.withArgs('DEBUG_ENABLED').returns(true); await userToGetHourGlass.post('/debug/add-hourglass'); const userWithHourGlass = await userToGetHourGlass.get('/user'); @@ -23,7 +30,7 @@ describe('POST /debug/add-hourglass', () => { }); it('returns error when not in production mode', async () => { - sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true); + nconfStub.withArgs('DEBUG_ENABLED').returns(false); await expect(userToGetHourGlass.post('/debug/add-hourglass')) .eventually.be.rejected.and.to.deep.equal({ diff --git a/test/api/v3/integration/debug/POST-debug_addTenGems.test.js b/test/api/v3/integration/debug/POST-debug_addTenGems.test.js index 2ac2834cf2..560381b4b0 100644 --- a/test/api/v3/integration/debug/POST-debug_addTenGems.test.js +++ b/test/api/v3/integration/debug/POST-debug_addTenGems.test.js @@ -5,16 +5,23 @@ import { describe('POST /debug/add-ten-gems', () => { let userToGainTenGems; + let nconfStub; before(async () => { userToGainTenGems = await generateUser(); }); - after(() => { - nconf.set('IS_PROD', false); + beforeEach(() => { + nconfStub = sandbox.stub(nconf, 'get'); + nconfStub.withArgs('BASE_URL').returns('https://example.com'); + }); + + afterEach(() => { + nconfStub.restore(); }); it('adds ten gems to the current user', async () => { + nconfStub.withArgs('DEBUG_ENABLED').returns(true); await userToGainTenGems.post('/debug/add-ten-gems'); const userWithTenGems = await userToGainTenGems.get('/user'); @@ -23,7 +30,7 @@ describe('POST /debug/add-ten-gems', () => { }); it('returns error when not in production mode', async () => { - sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true); + nconfStub.withArgs('DEBUG_ENABLED').returns(false); await expect(userToGainTenGems.post('/debug/add-ten-gems')) .eventually.be.rejected.and.to.deep.equal({ diff --git a/test/api/v3/integration/debug/POST-debug_jumpTime.test.js b/test/api/v3/integration/debug/POST-debug_jumpTime.test.js index 978b4fe05e..191badad03 100644 --- a/test/api/v3/integration/debug/POST-debug_jumpTime.test.js +++ b/test/api/v3/integration/debug/POST-debug_jumpTime.test.js @@ -6,6 +6,8 @@ import { describe('POST /debug/jump-time', () => { let user; let today; + let nconfStub; + before(async () => { user = await generateUser({ permissions: { fullAccess: true } }); today = new Date(); @@ -63,7 +65,7 @@ describe('POST /debug/jump-time', () => { }); it('returns error when not in time travel mode', async () => { - sandbox.stub(nconf, 'get').withArgs('TIME_TRAVEL_ENABLED').returns(false); + nconfStub.withArgs('TIME_TRAVEL_ENABLED').returns(false); await expect(user.post('/debug/jump-time', { offsetDays: 1 })) .eventually.be.rejected.and.to.deep.equal({ diff --git a/test/api/v3/integration/debug/POST-debug_make-admin.test.js b/test/api/v3/integration/debug/POST-debug_make-admin.test.js index f0303496a8..dcbcc2685b 100644 --- a/test/api/v3/integration/debug/POST-debug_make-admin.test.js +++ b/test/api/v3/integration/debug/POST-debug_make-admin.test.js @@ -5,16 +5,23 @@ import { describe('POST /debug/make-admin', () => { let user; + let nconfStub; before(async () => { user = await generateUser(); }); + beforeEach(() => { + nconfStub = sandbox.stub(nconf, 'get'); + nconfStub.withArgs('BASE_URL').returns('https://example.com'); + }); + afterEach(() => { - nconf.set('IS_PROD', false); + nconfStub.restore(); }); it('makes user an admin', async () => { + nconfStub.withArgs('DEBUG_ENABLED').returns(true); await user.post('/debug/make-admin'); await user.sync(); @@ -23,7 +30,7 @@ describe('POST /debug/make-admin', () => { }); it('returns error when not in production mode', async () => { - sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true); + nconfStub.withArgs('DEBUG_ENABLED').returns(false); await expect(user.post('/debug/make-admin')) .eventually.be.rejected.and.to.deep.equal({ diff --git a/test/api/v3/integration/debug/POST-debug_modify-inventory.test.js b/test/api/v3/integration/debug/POST-debug_modify-inventory.test.js index 5efec38a6b..1cd8e368b1 100644 --- a/test/api/v3/integration/debug/POST-debug_modify-inventory.test.js +++ b/test/api/v3/integration/debug/POST-debug_modify-inventory.test.js @@ -8,6 +8,7 @@ import { describe('POST /debug/modify-inventory', () => { let user; let originalItems; + let nconfStub; before(async () => { originalItems = { @@ -39,8 +40,14 @@ describe('POST /debug/modify-inventory', () => { }); }); + beforeEach(() => { + nconfStub = sandbox.stub(nconf, 'get'); + nconfStub.withArgs('DEBUG_ENABLED').returns(true); + nconfStub.withArgs('BASE_URL').returns('https://example.com'); + }); + afterEach(() => { - nconf.set('IS_PROD', false); + nconfStub.restore(); }); it('sets equipment', async () => { @@ -149,7 +156,7 @@ describe('POST /debug/modify-inventory', () => { }); it('returns error when not in production mode', async () => { - sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true); + nconfStub.withArgs('DEBUG_ENABLED').returns(false); await expect(user.post('/debug/modify-inventory')) .eventually.be.rejected.and.to.deep.equal({ diff --git a/test/api/v3/integration/debug/POST-debug_quest-progress.test.js b/test/api/v3/integration/debug/POST-debug_quest-progress.test.js index 8d17b68063..a0bc27f379 100644 --- a/test/api/v3/integration/debug/POST-debug_quest-progress.test.js +++ b/test/api/v3/integration/debug/POST-debug_quest-progress.test.js @@ -5,13 +5,20 @@ import { describe('POST /debug/quest-progress', () => { let user; + let nconfStub; beforeEach(async () => { user = await generateUser(); }); + beforeEach(() => { + nconfStub = sandbox.stub(nconf, 'get'); + nconfStub.withArgs('DEBUG_ENABLED').returns(true); + nconfStub.withArgs('BASE_URL').returns('https://example.com'); + }); + afterEach(() => { - nconf.set('IS_PROD', false); + nconfStub.restore(); }); it('errors if user is not on a quest', async () => { @@ -48,7 +55,7 @@ describe('POST /debug/quest-progress', () => { }); it('returns error when not in production mode', async () => { - sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true); + nconfStub.withArgs('DEBUG_ENABLED').returns(false); await expect(user.post('/debug/quest-progress')) .eventually.be.rejected.and.to.deep.equal({ diff --git a/test/api/v3/integration/debug/POST-debug_set-cron.test.js b/test/api/v3/integration/debug/POST-debug_set-cron.test.js index 331f19f5fa..671160e552 100644 --- a/test/api/v3/integration/debug/POST-debug_set-cron.test.js +++ b/test/api/v3/integration/debug/POST-debug_set-cron.test.js @@ -5,13 +5,20 @@ import { describe('POST /debug/set-cron', () => { let user; + let nconfStub; before(async () => { user = await generateUser(); }); + beforeEach(() => { + nconfStub = sandbox.stub(nconf, 'get'); + nconfStub.withArgs('DEBUG_ENABLED').returns(true); + nconfStub.withArgs('BASE_URL').returns('https://example.com'); + }); + afterEach(() => { - nconf.set('IS_PROD', false); + nconfStub.restore(); }); it('sets last cron', async () => { @@ -27,7 +34,7 @@ describe('POST /debug/set-cron', () => { }); it('returns error when not in production mode', async () => { - sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true); + nconfStub.withArgs('DEBUG_ENABLED').returns(false); await expect(user.post('/debug/set-cron')) .eventually.be.rejected.and.to.deep.equal({ diff --git a/website/server/middlewares/ensureDevelopmentMode.js b/website/server/middlewares/ensureDevelopmentMode.js index e31996b534..79dbd04bdf 100644 --- a/website/server/middlewares/ensureDevelopmentMode.js +++ b/website/server/middlewares/ensureDevelopmentMode.js @@ -4,6 +4,7 @@ import { } from '../libs/errors'; export default function ensureDevelopmentMode (req, res, next) { + console.log(nconf.get('DEBUG_ENABLED'), nconf.get('BASE_URL')); if (nconf.get('DEBUG_ENABLED') && nconf.get('BASE_URL') !== 'https://habitica.com') { next(); } else { From ac85bb2e2da846b069826a621e975a710038313d Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Wed, 19 Jun 2024 18:03:15 +0200 Subject: [PATCH 25/39] fix stub reference --- test/api/v3/integration/user/buy/POST-user_buy.test.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/api/v3/integration/user/buy/POST-user_buy.test.js b/test/api/v3/integration/user/buy/POST-user_buy.test.js index 7539676c14..cf96e38182 100644 --- a/test/api/v3/integration/user/buy/POST-user_buy.test.js +++ b/test/api/v3/integration/user/buy/POST-user_buy.test.js @@ -82,8 +82,6 @@ describe('POST /user/buy/:key', () => { expect(res.message).to.equal(t('messageBought', { itemText: item.text(), })); - - stub.restore(); }); it('allows for bulk purchases', async () => { From 11c5b26c594254083fa260a1d0920242d67e23b7 Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Wed, 19 Jun 2024 18:08:45 +0200 Subject: [PATCH 26/39] test heroku file --- heroku.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 heroku.yml diff --git a/heroku.yml b/heroku.yml new file mode 100644 index 0000000000..f3781ab8cc --- /dev/null +++ b/heroku.yml @@ -0,0 +1,5 @@ +build: + docker: + web: Dockerfile +run: + web: node ./website/transpiled-babel/index.js \ No newline at end of file From 4da2ed4a1f8d017ad3b6ac4e869746e7beaea419 Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Wed, 19 Jun 2024 18:10:07 +0200 Subject: [PATCH 27/39] initialize stub --- test/api/v3/integration/debug/POST-debug_jumpTime.test.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/api/v3/integration/debug/POST-debug_jumpTime.test.js b/test/api/v3/integration/debug/POST-debug_jumpTime.test.js index 191badad03..0bc6a3299a 100644 --- a/test/api/v3/integration/debug/POST-debug_jumpTime.test.js +++ b/test/api/v3/integration/debug/POST-debug_jumpTime.test.js @@ -13,6 +13,14 @@ describe('POST /debug/jump-time', () => { today = new Date(); }); + beforeEach(() => { + nconfStub = sandbox.stub(nconf, 'get'); + }); + + afterEach(() => { + nconfStub.restore(); + }); + after(async () => { nconf.set('TIME_TRAVEL_ENABLED', true); await user.post('/debug/jump-time', { disable: true }); From cff08adcd0290907281e5db873b9087d7de83e26 Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Wed, 19 Jun 2024 18:13:20 +0200 Subject: [PATCH 28/39] specify dev docker file --- heroku.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/heroku.yml b/heroku.yml index f3781ab8cc..5c006c6991 100644 --- a/heroku.yml +++ b/heroku.yml @@ -1,5 +1,5 @@ build: docker: - web: Dockerfile + web: Dockerfile-Dev run: web: node ./website/transpiled-babel/index.js \ No newline at end of file From 93cf30eb184a74f85751750ab6e5033db3d2fafa Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Wed, 19 Jun 2024 18:20:25 +0200 Subject: [PATCH 29/39] integration fix --- test/api/v3/integration/debug/POST-debug_jumpTime.test.js | 5 +---- test/api/v3/integration/user/buy/POST-user_buy.test.js | 8 ++++++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/test/api/v3/integration/debug/POST-debug_jumpTime.test.js b/test/api/v3/integration/debug/POST-debug_jumpTime.test.js index 0bc6a3299a..68988f682d 100644 --- a/test/api/v3/integration/debug/POST-debug_jumpTime.test.js +++ b/test/api/v3/integration/debug/POST-debug_jumpTime.test.js @@ -15,6 +15,7 @@ describe('POST /debug/jump-time', () => { beforeEach(() => { nconfStub = sandbox.stub(nconf, 'get'); + nconfStub.withArgs('TIME_TRAVEL_ENABLED').returns(true); }); afterEach(() => { @@ -28,7 +29,6 @@ describe('POST /debug/jump-time', () => { }); it('Jumps forward', async () => { - nconf.set('TIME_TRAVEL_ENABLED', true); const resultDate = new Date((await user.post('/debug/jump-time', { reset: true })).time); expect(resultDate.getDate()).to.eql(today.getDate()); expect(resultDate.getMonth()).to.eql(today.getMonth()); @@ -40,7 +40,6 @@ describe('POST /debug/jump-time', () => { }); it('jumps back', async () => { - nconf.set('TIME_TRAVEL_ENABLED', true); const resultDate = new Date((await user.post('/debug/jump-time', { reset: true })).time); expect(resultDate.getDate()).to.eql(today.getDate()); expect(resultDate.getMonth()).to.eql(today.getMonth()); @@ -52,7 +51,6 @@ describe('POST /debug/jump-time', () => { }); it('can jump a lot', async () => { - nconf.set('TIME_TRAVEL_ENABLED', true); const resultDate = new Date((await user.post('/debug/jump-time', { reset: true })).time); expect(resultDate.getDate()).to.eql(today.getDate()); expect(resultDate.getMonth()).to.eql(today.getMonth()); @@ -62,7 +60,6 @@ describe('POST /debug/jump-time', () => { }); it('returns error when the user is not an admin', async () => { - nconf.set('TIME_TRAVEL_ENABLED', true); const regularUser = await generateUser(); await expect(regularUser.post('/debug/jump-time', { offsetDays: 1 })) .eventually.be.rejected.and.to.deep.equal({ diff --git a/test/api/v3/integration/user/buy/POST-user_buy.test.js b/test/api/v3/integration/user/buy/POST-user_buy.test.js index cf96e38182..4590d7bc62 100644 --- a/test/api/v3/integration/user/buy/POST-user_buy.test.js +++ b/test/api/v3/integration/user/buy/POST-user_buy.test.js @@ -11,6 +11,7 @@ const { content } = shared; describe('POST /user/buy/:key', () => { let user; + let clock; beforeEach(async () => { user = await generateUser({ @@ -18,6 +19,12 @@ describe('POST /user/buy/:key', () => { }); }); + afterEach(() => { + if (clock) { + clock.restore(); + } + }); + // More tests in common code unit tests it('returns an error if the item is not found', async () => { @@ -68,6 +75,7 @@ describe('POST /user/buy/:key', () => { }); it('buys a special spell', async () => { + clock = sinon.useFakeTimers(new Date('2024-10-31T00:00:00Z')); const key = 'spookySparkles'; const item = content.special[key]; From 61a61724cae017aaaf912c037796bd2e5064ec87 Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Wed, 19 Jun 2024 18:33:18 +0200 Subject: [PATCH 30/39] testing --- Dockerfile-Dev | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Dockerfile-Dev b/Dockerfile-Dev index b24336cf3e..3aa613c960 100644 --- a/Dockerfile-Dev +++ b/Dockerfile-Dev @@ -5,10 +5,7 @@ RUN npm install -g gulp-cli mocha # Copy package.json and package-lock.json into image, then install # dependencies. -WORKDIR /usr/src/habitica -COPY ["package.json", "package-lock.json", "./"] -RUN npm install - -# Copy the remaining source files in. COPY . /usr/src/habitica +WORKDIR /usr/src/habitica +RUN npm install RUN npm run postinstall From f18fbe86b61fa282baf38196313fe07837b173cc Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Wed, 19 Jun 2024 18:40:53 +0200 Subject: [PATCH 31/39] build client --- Dockerfile-Dev | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile-Dev b/Dockerfile-Dev index 3aa613c960..9b7e069703 100644 --- a/Dockerfile-Dev +++ b/Dockerfile-Dev @@ -9,3 +9,4 @@ COPY . /usr/src/habitica WORKDIR /usr/src/habitica RUN npm install RUN npm run postinstall +RUN npm run client:build \ No newline at end of file From 1dae0793fde402e15c9e2eba2b21df999933282f Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Wed, 19 Jun 2024 18:50:32 +0200 Subject: [PATCH 32/39] call gulp build:prod --- Dockerfile-Dev | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile-Dev b/Dockerfile-Dev index 9b7e069703..73bcf7bfce 100644 --- a/Dockerfile-Dev +++ b/Dockerfile-Dev @@ -9,4 +9,5 @@ COPY . /usr/src/habitica WORKDIR /usr/src/habitica RUN npm install RUN npm run postinstall -RUN npm run client:build \ No newline at end of file +RUN npm run client:build +RUN gulp build:prod \ No newline at end of file From 7231f699c1e9cc4fc873428863cff0c14a4b6b3f Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Wed, 19 Jun 2024 19:32:32 +0200 Subject: [PATCH 33/39] try setting up with heroku buildpack --- heroku.yml | 5 ----- package.json | 4 +++- 2 files changed, 3 insertions(+), 6 deletions(-) delete mode 100644 heroku.yml diff --git a/heroku.yml b/heroku.yml deleted file mode 100644 index 5c006c6991..0000000000 --- a/heroku.yml +++ /dev/null @@ -1,5 +0,0 @@ -build: - docker: - web: Dockerfile-Dev -run: - web: node ./website/transpiled-babel/index.js \ No newline at end of file diff --git a/package.json b/package.json index cf8979704d..9854a67dd8 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,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 postinstall && npm run build:prod && npm run build:client" }, "devDependencies": { "axios": "^1.4.0", From d054e6fc1650fbe6df14b62025f0470a15e91883 Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Wed, 19 Jun 2024 19:36:57 +0200 Subject: [PATCH 34/39] correct build call --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9854a67dd8..b1c14e3030 100644 --- a/package.json +++ b/package.json @@ -108,7 +108,7 @@ "postinstall": "git config --global url.\"https://\".insteadOf git:// && gulp build && cd website/client && npm install", "apidoc": "gulp apidoc", - "heroku-postbuild": "npm run postinstall && npm run build:prod && npm run build:client" + "heroku-postbuild": "npm run postinstall && gulp build:prod && npm run build:client" }, "devDependencies": { "axios": "^1.4.0", From f62254d68e2859990a6e80cd5b64d3385a6dea60 Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Wed, 19 Jun 2024 19:40:20 +0200 Subject: [PATCH 35/39] fix client command --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b1c14e3030..fe919257dd 100644 --- a/package.json +++ b/package.json @@ -108,7 +108,7 @@ "postinstall": "git config --global url.\"https://\".insteadOf git:// && gulp build && cd website/client && npm install", "apidoc": "gulp apidoc", - "heroku-postbuild": "npm run postinstall && gulp build:prod && npm run build:client" + "heroku-postbuild": "npm run postinstall && gulp build:prod && npm run client:build" }, "devDependencies": { "axios": "^1.4.0", From e0f6f79c5b49d2b6eae7e5c02dd90ac7ad6ea397 Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Thu, 20 Jun 2024 10:11:27 +0200 Subject: [PATCH 36/39] =?UTF-8?q?don=E2=80=99t=20build=20multiple=20times?= =?UTF-8?q?=20on=20heroku?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fe919257dd..e80b981ce6 100644 --- a/package.json +++ b/package.json @@ -108,7 +108,7 @@ "postinstall": "git config --global url.\"https://\".insteadOf git:// && gulp build && cd website/client && npm install", "apidoc": "gulp apidoc", - "heroku-postbuild": "npm run postinstall && gulp build:prod && npm run client:build" + "heroku-postbuild": "npm run client:build" }, "devDependencies": { "axios": "^1.4.0", From 877fe482252db78b69050b13274da147ede23769 Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Thu, 20 Jun 2024 12:23:24 +0200 Subject: [PATCH 37/39] correctly memoize conent api --- test/content/index.test.js | 154 +++++ test/content/stable.test.js | 2 +- website/client/src/components/hall/heroes.vue | 4 +- .../inventory/stable/mountRaisedModal.vue | 4 +- website/common/script/content/index.js | 636 ++++++++++-------- website/common/script/content/stable.js | 127 ++-- 6 files changed, 584 insertions(+), 343 deletions(-) create mode 100644 test/content/index.test.js 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/stable.test.js b/test/content/stable.test.js index 218e340e78..b5950dbf12 100644 --- a/test/content/stable.test.js +++ b/test/content/stable.test.js @@ -6,7 +6,7 @@ import { } from '../helpers/content.helper'; import t from '../../website/common/script/content/translation'; -import * as stable from '../../website/common/script/content/stable'; +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'; 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 @@