Merge remote-tracking branch 'upstream/develop' into quest-refactors

This commit is contained in:
CuriousMagpie
2022-02-02 16:24:42 -05:00
238 changed files with 57856 additions and 67580 deletions
+12 -73
View File
@@ -1,15 +1,8 @@
import gulp from 'gulp';
import imagemin from 'gulp-imagemin';
import spritesmith from 'gulp.spritesmith';
import clean from 'rimraf';
import sizeOf from 'image-size';
import mergeStream from 'merge-stream';
import { sync } from 'glob';
import { each } from 'lodash';
import vinylBuffer from 'vinyl-buffer';
// https://github.com/Ensighten/grunt-spritesmith/issues/67#issuecomment-34786248
const MAX_SPRITESHEET_SIZE = 1024 * 1024 * 3;
const IMG_DIST_PATH = 'website/client/src/assets/images/sprites/';
const CSS_DIST_PATH = 'website/client/src/assets/css/sprites/';
@@ -19,49 +12,6 @@ function checkForSpecialTreatment (name) {
return name.match(regex) || name === 'head_0';
}
function calculateImgDimensions (img, addPadding) {
let dims = sizeOf(img);
const requiresSpecialTreatment = checkForSpecialTreatment(img);
if (requiresSpecialTreatment) {
const newWidth = dims.width < 90 ? 90 : dims.width;
const newHeight = dims.height < 90 ? 90 : dims.height;
dims = {
width: newWidth,
height: newHeight,
};
}
let padding = 0;
if (addPadding) {
padding = dims.width * 8 + dims.height * 8;
}
if (!dims.width || !dims.height) console.error('MISSING DIMENSIONS:', dims); // eslint-disable-line no-console
const totalPixelSize = dims.width * dims.height + padding;
return totalPixelSize;
}
function calculateSpritesheetsSrcIndicies (src) {
let totalPixels = 0;
const slices = [0];
each(src, (img, index) => {
const imageSize = calculateImgDimensions(img, true);
totalPixels += imageSize;
if (totalPixels > MAX_SPRITESHEET_SIZE) {
slices.push(index - 1);
totalPixels = imageSize;
}
});
return slices;
}
function cssVarMap (sprite) {
// For hair, skins, beards, etc. we want to output a '.customize-options.WHATEVER' class,
// which works as a 60x60 image pointing at the proper part of the 90x90 sprite.
@@ -85,33 +35,22 @@ function cssVarMap (sprite) {
}
function createSpritesStream (name, src) {
const spritesheetSliceIndicies = calculateSpritesheetsSrcIndicies(src);
const stream = mergeStream();
each(spritesheetSliceIndicies, (start, index) => {
const slicedSrc = src.slice(start, spritesheetSliceIndicies[index + 1]);
const spriteData = gulp.src(src)
.pipe(spritesmith({
imgName: `spritesmith-${name}.png`,
cssName: `spritesmith-${name}.css`,
algorithm: 'binary-tree',
padding: 1,
cssTemplate: 'website/raw_sprites/css/css.template.handlebars',
cssVarMap,
}));
const spriteData = gulp.src(slicedSrc)
.pipe(spritesmith({
imgName: `spritesmith-${name}-${index}.png`,
cssName: `spritesmith-${name}-${index}.css`,
algorithm: 'binary-tree',
padding: 1,
cssTemplate: 'website/raw_sprites/css/css.template.handlebars',
cssVarMap,
}));
const cssStream = spriteData.css
.pipe(gulp.dest(CSS_DIST_PATH));
const imgStream = spriteData.img
.pipe(vinylBuffer())
.pipe(imagemin())
.pipe(gulp.dest(IMG_DIST_PATH));
const cssStream = spriteData.css
.pipe(gulp.dest(CSS_DIST_PATH));
stream.add(imgStream);
stream.add(cssStream);
});
stream.add(cssStream);
return stream;
}
@@ -0,0 +1,97 @@
/* eslint-disable no-console */
const MIGRATION_NAME = '20220131_habit_birthday';
import { v4 as uuid } from 'uuid';
import { model as User } from '../../../website/server/models/user';
const progressCount = 1000;
let count = 0;
async function updateUser (user) {
count++;
const inc = {
'items.food.Cake_Skeleton': 1,
'items.food.Cake_Base': 1,
'items.food.Cake_CottonCandyBlue': 1,
'items.food.Cake_CottonCandyPink': 1,
'items.food.Cake_Shade': 1,
'items.food.Cake_White': 1,
'items.food.Cake_Golden': 1,
'items.food.Cake_Zombie': 1,
'items.food.Cake_Desert': 1,
'items.food.Cake_Red': 1,
'achievements.habitBirthdays': 1,
};
const set = {};
let push;
set.migration = MIGRATION_NAME;
if (typeof user.items.gear.owned.armor_special_birthday2021 !== 'undefined') {
set['items.gear.owned.armor_special_birthday2022'] = false;
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.armor_special_birthday2022', _id: uuid()}};
} else if (typeof user.items.gear.owned.armor_special_birthday2020 !== 'undefined') {
set['items.gear.owned.armor_special_birthday2021'] = false;
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.armor_special_birthday2021', _id: uuid()}};
} else if (typeof user.items.gear.owned.armor_special_birthday2019 !== 'undefined') {
set['items.gear.owned.armor_special_birthday2020'] = false;
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.armor_special_birthday2020', _id: uuid()}};
} else if (typeof user.items.gear.owned.armor_special_birthday2018 !== 'undefined') {
set['items.gear.owned.armor_special_birthday2019'] = false;
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.armor_special_birthday2019', _id: uuid()}};
} else if (typeof user.items.gear.owned.armor_special_birthday2017 !== 'undefined') {
set['items.gear.owned.armor_special_birthday2018'] = false;
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.armor_special_birthday2018', _id: uuid()}};
} else if (typeof user.items.gear.owned.armor_special_birthday2016 !== 'undefined') {
set['items.gear.owned.armor_special_birthday2017'] = false;
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.armor_special_birthday2017', _id: uuid()}};
} else if (typeof user.items.gear.owned.armor_special_birthday2015 !== 'undefined') {
set['items.gear.owned.armor_special_birthday2016'] = false;
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.armor_special_birthday2016', _id: uuid()}};
} else if (typeof user.items.gear.owned.armor_special_birthday !== 'undefined') {
set['items.gear.owned.armor_special_birthday2015'] = false;
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.armor_special_birthday2015', _id: uuid()}};
} else {
set['items.gear.owned.armor_special_birthday'] = false;
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.armor_special_birthday', _id: uuid()}};
}
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
return await User.update({_id: user._id}, {$inc: inc, $set: set, $push: push}).exec();
}
export default async function processUsers () {
let query = {
migration: {$ne: MIGRATION_NAME},
'auth.timestamps.loggedin': {$gt: new Date('2022-01-01')},
};
const fields = {
_id: 1,
items: 1,
};
while (true) { // eslint-disable-line no-constant-condition
const users = await User // eslint-disable-line no-await-in-loop
.find(query)
.limit(250)
.sort({_id: 1})
.select(fields)
.lean()
.exec();
if (users.length === 0) {
console.warn('All appropriate users found and modified.');
console.warn(`\n${count} users processed\n`);
break;
} else {
query._id = {
$gt: users[users.length - 1],
};
}
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
}
};
@@ -0,0 +1,178 @@
/* eslint-disable no-console */
const MIGRATION_NAME = '20220201_pet_group_achievements';
import { model as User } from '../../../website/server/models/user';
const progressCount = 1000;
let count = 0;
async function updateUser (user) {
count++;
const set = {
migration: MIGRATION_NAME,
};
if (user && user.items && user.items.pets) {
const pets = user.items.pets;
if (pets['FlyingPig-Base']
&& pets['FlyingPig-CottonCandyBlue']
&& pets['FlyingPig-CottonCandyPink']
&& pets['FlyingPig-Desert']
&& pets['FlyingPig-Golden']
&& pets['FlyingPig-Red']
&& pets['FlyingPig-Shade']
&& pets['FlyingPig-Skeleton']
&& pets['FlyingPig-White']
&& pets['FlyingPig-Zombie']
&& pets['Snake-Base']
&& pets['Snake-CottonCandyBlue']
&& pets['Snake-CottonCandyPink']
&& pets['Snake-Desert']
&& pets['Snake-Golden']
&& pets['Snake-Red']
&& pets['Snake-Shade']
&& pets['Snake-Skeleton']
&& pets['Snake-White']
&& pets['Snake-Zombie']
&& pets['Sheep-Base']
&& pets['Sheep-CottonCandyBlue']
&& pets['Sheep-CottonCandyPink']
&& pets['Sheep-Desert']
&& pets['Sheep-Golden']
&& pets['Sheep-Red']
&& pets['Sheep-Shade']
&& pets['Sheep-Skeleton']
&& pets['Sheep-White']
&& pets['Sheep-Zombie']
&& pets['Rooster-Base']
&& pets['Rooster-CottonCandyBlue']
&& pets['Rooster-CottonCandyPink']
&& pets['Rooster-Desert']
&& pets['Rooster-Golden']
&& pets['Rooster-Red']
&& pets['Rooster-Shade']
&& pets['Rooster-Skeleton']
&& pets['Rooster-White']
&& pets['Rooster-Zombie']
&& pets['Rat-Base']
&& pets['Rat-CottonCandyBlue']
&& pets['Rat-CottonCandyPink']
&& pets['Rat-Desert']
&& pets['Rat-Golden']
&& pets['Rat-Red']
&& pets['Rat-Shade']
&& pets['Rat-Skeleton']
&& pets['Rat-White']
&& pets['Rat-Zombie']
&& pets['Bunny-Base']
&& pets['Bunny-CottonCandyBlue']
&& pets['Bunny-CottonCandyPink']
&& pets['Bunny-Desert']
&& pets['Bunny-Golden']
&& pets['Bunny-Red']
&& pets['Bunny-Shade']
&& pets['Bunny-Skeleton']
&& pets['Bunny-White']
&& pets['Bunny-Zombie']
&& pets['Horse-Base']
&& pets['Horse-CottonCandyBlue']
&& pets['Horse-CottonCandyPink']
&& pets['Horse-Desert']
&& pets['Horse-Golden']
&& pets['Horse-Red']
&& pets['Horse-Shade']
&& pets['Horse-Skeleton']
&& pets['Horse-White']
&& pets['Horse-Zombie']
&& pets['Cow-Base']
&& pets['Cow-CottonCandyBlue']
&& pets['Cow-CottonCandyPink']
&& pets['Cow-Desert']
&& pets['Cow-Golden']
&& pets['Cow-Red']
&& pets['Cow-Shade']
&& pets['Cow-Skeleton']
&& pets['Cow-White']
&& pets['Cow-Zombie']
&& pets['Monkey-Base']
&& pets['Monkey-CottonCandyBlue']
&& pets['Monkey-CottonCandyPink']
&& pets['Monkey-Desert']
&& pets['Monkey-Golden']
&& pets['Monkey-Red']
&& pets['Monkey-Shade']
&& pets['Monkey-Skeleton']
&& pets['Monkey-White']
&& pets['Monkey-Zombie']
&& pets['Wolf-Base']
&& pets['Wolf-CottonCandyBlue']
&& pets['Wolf-CottonCandyPink']
&& pets['Wolf-Desert']
&& pets['Wolf-Golden']
&& pets['Wolf-Red']
&& pets['Wolf-Shade']
&& pets['Wolf-Skeleton']
&& pets['Wolf-White']
&& pets['Wolf-Zombie']
&& pets['Tiger-Base']
&& pets['Tiger-CottonCandyBlue']
&& pets['Tiger-CottonCandyPink']
&& pets['Tiger-Desert']
&& pets['Tiger-Golden']
&& pets['Tiger-Red']
&& pets['Tiger-Shade']
&& pets['Tiger-Skeleton']
&& pets['Tiger-White']
&& pets['Tiger-Zombie']
&& pets['Dragon-Base']
&& pets['Dragon-CottonCandyBlue']
&& pets['Dragon-CottonCandyPink']
&& pets['Dragon-Desert']
&& pets['Dragon-Golden']
&& pets['Dragon-Red']
&& pets['Dragon-Shade']
&& pets['Dragon-Skeleton']
&& pets['Dragon-White']
&& pets['Dragon-Zombie']) {
set['achievements.zodiacZookeeper'] = true;
}
}
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
return await User.update({ _id: user._id }, { $set: set }).exec();
}
export default async function processUsers () {
let query = {
// migration: { $ne: MIGRATION_NAME },
'auth.timestamps.loggedin': { $gt: new Date('2021-08-01') },
};
const fields = {
_id: 1,
items: 1,
};
while (true) { // eslint-disable-line no-constant-condition
const users = await User // eslint-disable-line no-await-in-loop
.find(query)
.limit(250)
.sort({_id: 1})
.select(fields)
.lean()
.exec();
if (users.length === 0) {
console.warn('All appropriate users found and modified.');
console.warn(`\n${count} users processed\n`);
break;
} else {
query._id = {
$gt: users[users.length - 1]._id,
};
}
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
}
};
+32 -15
View File
@@ -1,6 +1,6 @@
{
"name": "habitica",
"version": "4.218.0",
"version": "4.220.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -3781,15 +3781,16 @@
"integrity": "sha512-z0R4cT5357OEAVkP1CEFTHz1egpu2gYiWm2WJOY/sQDhojEXUYL4m3v2kYi5wER3PkMRL+GgfDhed2kGzrHSZA=="
},
"chai": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/chai/-/chai-4.3.4.tgz",
"integrity": "sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==",
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz",
"integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==",
"dev": true,
"requires": {
"assertion-error": "^1.1.0",
"check-error": "^1.0.2",
"deep-eql": "^3.0.1",
"get-func-name": "^2.0.0",
"loupe": "^2.3.1",
"pathval": "^1.1.1",
"type-detect": "^4.0.5"
}
@@ -8119,8 +8120,7 @@
"ieee754": {
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
"integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==",
"optional": true
"integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="
},
"ignore": {
"version": "4.0.6",
@@ -9514,6 +9514,13 @@
"ms": "^2.1.1",
"safe-stable-stringify": "^1.1.0",
"triple-beam": "^1.3.0"
},
"dependencies": {
"safe-stable-stringify": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-1.1.1.tgz",
"integrity": "sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw=="
}
}
},
"longest": {
@@ -9541,6 +9548,15 @@
"signal-exit": "^3.0.0"
}
},
"loupe": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.1.tgz",
"integrity": "sha512-EN1D3jyVmaX4tnajVlfbREU4axL647hLec1h/PXAb8CPDMJiYitcWF2UeLVNttRqaIqQs4x+mRvXf+d+TlDrCA==",
"dev": true,
"requires": {
"get-func-name": "^2.0.0"
}
},
"lowercase-keys": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
@@ -12526,9 +12542,9 @@
}
},
"safe-stable-stringify": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-1.1.1.tgz",
"integrity": "sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw=="
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.3.1.tgz",
"integrity": "sha512-kYBSfT+troD9cDA85VDnHZ1rpHC50O0g1e6WlGHVCz/g+JS+9WKLj+XwFYyR8UbrZN8ll9HUpDAAddY58MGisg=="
},
"safer-buffer": {
"version": "2.1.2",
@@ -13521,9 +13537,9 @@
}
},
"stripe": {
"version": "8.199.0",
"resolved": "https://registry.npmjs.org/stripe/-/stripe-8.199.0.tgz",
"integrity": "sha512-Bc5Zfp6eOOCdde9x5NPrAczeGSKuNwemzjsfGJXWtpbUfQXgJujzTGgkhx2YuzamqakDYJkTgf9w7Ry2uY8QNA==",
"version": "8.201.0",
"resolved": "https://registry.npmjs.org/stripe/-/stripe-8.201.0.tgz",
"integrity": "sha512-pF0F1DdE9zt0U6Cb0XN+REpdFkUmaqp6C7OEVOCeUpTAafjjJqrdV/WmZd7Y5MwT8XvDAxB5/v3CAXwxAp0XNg==",
"requires": {
"@types/node": ">=8.1.0",
"qs": "^6.6.0"
@@ -15221,9 +15237,9 @@
"integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw=="
},
"winston": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/winston/-/winston-3.4.0.tgz",
"integrity": "sha512-FqilVj+5HKwCfIHQzMxrrd5tBIH10JTS3koFGbLVWBODjiIYq7zir08rFyBT4rrTYG/eaTqDcfSIbcjSM78YSw==",
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/winston/-/winston-3.5.0.tgz",
"integrity": "sha512-OQMbmLsIdVHvm2hSurrYZs+iZNIImXneYJ6pX7LseSMEq20HdTETXiNnNX3FDwN4LB/xDRZLF6JYOY+AI112Kw==",
"requires": {
"@dabh/diagnostics": "^2.0.2",
"async": "^3.2.3",
@@ -15231,6 +15247,7 @@
"logform": "^2.3.2",
"one-time": "^1.0.0",
"readable-stream": "^3.4.0",
"safe-stable-stringify": "^2.3.1",
"stack-trace": "0.0.x",
"triple-beam": "^1.3.0",
"winston-transport": "^4.4.2"
+4 -4
View File
@@ -1,7 +1,7 @@
{
"name": "habitica",
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
"version": "4.218.0",
"version": "4.220.0",
"main": "./website/server/index.js",
"dependencies": {
"@babel/core": "^7.16.12",
@@ -67,14 +67,14 @@
"remove-markdown": "^0.3.0",
"rimraf": "^3.0.2",
"short-uuid": "^4.2.0",
"stripe": "^8.199.0",
"stripe": "^8.201.0",
"superagent": "^7.1.1",
"universal-analytics": "^0.5.3",
"useragent": "^2.1.9",
"uuid": "^8.3.2",
"validator": "^13.7.0",
"vinyl-buffer": "^1.0.1",
"winston": "^3.4.0",
"winston": "^3.5.0",
"winston-loggly-bulk": "^3.2.1",
"xml2js": "^0.4.23"
},
@@ -111,7 +111,7 @@
},
"devDependencies": {
"axios": "^0.25.0",
"chai": "^4.3.4",
"chai": "^4.3.6",
"chai-as-promised": "^7.1.1",
"chai-moment": "^0.1.0",
"chalk": "^4.1.2",
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,38 @@
import {
generateUser,
translate as t,
} from '../../../helpers/api-integration/v4';
describe('GET /members/:memberId/purchase-history', () => {
let user;
before(async () => {
user = await generateUser({
contributor: { admin: true },
});
});
it('validates req.params.memberId', async () => {
await expect(user.get('/members/invalidUUID/purchase-history')).to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: t('invalidReqParams'),
});
});
it('returns error if user is not admin', async () => {
const member = await generateUser();
const nonAdmin = await generateUser();
await expect(nonAdmin.get(`/members/${member._id}/purchase-history`)).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('noAdminAccess'),
});
});
it('returns purchase history based on given user', async () => {
const member = await generateUser();
const response = await user.get(`/members/${member._id}/purchase-history`);
expect(response.length).to.equal(0);
});
});
+20 -24
View File
@@ -40,28 +40,27 @@ describe('shared.ops.buy', () => {
analytics.track.restore();
});
it('returns error when key is not provided', done => {
it('returns error when key is not provided', async () => {
try {
buy(user);
await buy(user);
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(errorMessage('missingKeyParam'));
done();
}
});
it('recovers 15 hp', () => {
it('recovers 15 hp', async () => {
user.stats.hp = 30;
buy(user, { params: { key: 'potion' } }, analytics);
await buy(user, { params: { key: 'potion' } }, analytics);
expect(user.stats.hp).to.eql(45);
expect(analytics.track).to.be.calledOnce;
});
it('adds equipment to inventory', () => {
it('adds equipment to inventory', async () => {
user.stats.gp = 31;
buy(user, { params: { key: 'armor_warrior_1' } });
await buy(user, { params: { key: 'armor_warrior_1' } });
expect(user.items.gear.owned).to.eql({
weapon_warrior_0: true,
@@ -90,10 +89,10 @@ describe('shared.ops.buy', () => {
});
});
it('buys Steampunk Accessories Set', () => {
it('buys Steampunk Accessories Set', async () => {
user.purchased.plan.consecutive.trinkets = 1;
buy(user, {
await buy(user, {
params: {
key: '301404',
},
@@ -108,10 +107,10 @@ describe('shared.ops.buy', () => {
expect(user.items.gear.owned).to.have.property('eyewear_mystery_301404', true);
});
it('buys a Quest scroll', () => {
it('buys a Quest scroll', async () => {
user.stats.gp = 205;
buy(user, {
await buy(user, {
params: {
key: 'dilatoryDistress1',
},
@@ -122,11 +121,11 @@ describe('shared.ops.buy', () => {
expect(user.stats.gp).to.equal(5);
});
it('buys a special item', () => {
it('buys a special item', async () => {
user.stats.gp = 11;
const item = content.special.thankyou;
const [data, message] = buy(user, {
const [data, message] = await buy(user, {
params: {
key: 'thankyou',
},
@@ -144,15 +143,15 @@ describe('shared.ops.buy', () => {
}));
});
it('allows for bulk purchases', () => {
it('allows for bulk purchases', async () => {
user.stats.hp = 30;
buy(user, { params: { key: 'potion' }, quantity: 2 });
await buy(user, { params: { key: 'potion' }, quantity: 2 });
expect(user.stats.hp).to.eql(50);
});
it('errors if user supplies a non-numeric quantity', done => {
it('errors if user supplies a non-numeric quantity', async () => {
try {
buy(user, {
await buy(user, {
params: {
key: 'dilatoryDistress1',
},
@@ -162,13 +161,12 @@ describe('shared.ops.buy', () => {
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(errorMessage('invalidQuantity'));
done();
}
});
it('errors if user supplies a negative quantity', done => {
it('errors if user supplies a negative quantity', async () => {
try {
buy(user, {
await buy(user, {
params: {
key: 'dilatoryDistress1',
},
@@ -178,13 +176,12 @@ describe('shared.ops.buy', () => {
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(errorMessage('invalidQuantity'));
done();
}
});
it('errors if user supplies a decimal quantity', done => {
it('errors if user supplies a decimal quantity', async () => {
try {
buy(user, {
await buy(user, {
params: {
key: 'dilatoryDistress1',
},
@@ -194,7 +191,6 @@ describe('shared.ops.buy', () => {
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(errorMessage('invalidQuantity'));
done();
}
});
});
+13 -14
View File
@@ -33,7 +33,7 @@ describe('shared.ops.buyArmoire', () => {
const YIELD_EXP = 0.9;
const analytics = { track () {} };
function buyArmoire (_user, _req, _analytics) {
async function buyArmoire (_user, _req, _analytics) {
const buyOp = new BuyArmoireOperation(_user, _req, _analytics);
return buyOp.purchase();
@@ -61,11 +61,11 @@ describe('shared.ops.buyArmoire', () => {
});
context('failure conditions', () => {
it('does not open if user does not have enough gold', done => {
it('does not open if user does not have enough gold', async () => {
user.stats.gp = 50;
try {
buyArmoire(user);
await buyArmoire(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageNotEnoughGold'));
@@ -74,17 +74,16 @@ describe('shared.ops.buyArmoire', () => {
});
expect(user.items.food).to.be.empty;
expect(user.stats.exp).to.eql(0);
done();
}
});
});
context('non-gear awards', () => {
it('gives Experience', () => {
it('gives Experience', async () => {
const previousExp = user.stats.exp;
randomValFns.trueRandom.returns(YIELD_EXP);
buyArmoire(user);
await buyArmoire(user);
expect(user.items.gear.owned).to.eql({ weapon_warrior_0: true });
expect(user.items.food).to.be.empty;
@@ -92,12 +91,12 @@ describe('shared.ops.buyArmoire', () => {
expect(user.stats.gp).to.equal(100);
});
it('gives food', () => {
it('gives food', async () => {
const previousExp = user.stats.exp;
randomValFns.trueRandom.returns(YIELD_FOOD);
buyArmoire(user);
await buyArmoire(user);
expect(user.items.gear.owned).to.eql({ weapon_warrior_0: true });
expect(user.items.food).to.not.be.empty;
@@ -105,12 +104,12 @@ describe('shared.ops.buyArmoire', () => {
expect(user.stats.gp).to.equal(100);
});
it('does not give equipment if all equipment has been found', () => {
it('does not give equipment if all equipment has been found', async () => {
randomValFns.trueRandom.returns(YIELD_EQUIPMENT);
user.items.gear.owned = getFullArmoire();
user.stats.gp = 150;
buyArmoire(user);
await buyArmoire(user);
expect(user.items.gear.owned).to.eql(getFullArmoire());
const armoireCount = count.remainingGearInSet(user.items.gear.owned, 'armoire');
@@ -122,13 +121,13 @@ describe('shared.ops.buyArmoire', () => {
});
context('gear awards', () => {
it('always drops equipment the first time', () => {
it('always drops equipment the first time', async () => {
delete user.flags.armoireOpened;
randomValFns.trueRandom.returns(YIELD_EXP);
expect(_.size(user.items.gear.owned)).to.equal(1);
buyArmoire(user);
await buyArmoire(user);
expect(_.size(user.items.gear.owned)).to.equal(2);
@@ -140,7 +139,7 @@ describe('shared.ops.buyArmoire', () => {
expect(user.stats.gp).to.equal(100);
});
it('gives more equipment', () => {
it('gives more equipment', async () => {
randomValFns.trueRandom.returns(YIELD_EQUIPMENT);
user.items.gear.owned = {
weapon_warrior_0: true,
@@ -150,7 +149,7 @@ describe('shared.ops.buyArmoire', () => {
expect(_.size(user.items.gear.owned)).to.equal(2);
buyArmoire(user, {}, analytics);
await buyArmoire(user, {}, analytics);
expect(_.size(user.items.gear.owned)).to.equal(3);
+17 -22
View File
@@ -11,7 +11,7 @@ import i18n from '../../../../website/common/script/i18n';
import { BuyGemOperation } from '../../../../website/common/script/ops/buy/buyGem';
import planGemLimits from '../../../../website/common/script/libs/planGemLimits';
function buyGem (user, req, analytics) {
async function buyGem (user, req, analytics) {
const buyOp = new BuyGemOperation(user, req, analytics);
return buyOp.purchase();
@@ -44,8 +44,8 @@ describe('shared.ops.buyGem', () => {
});
context('Gems', () => {
it('purchases gems', () => {
const [, message] = buyGem(user, { params: { type: 'gems', key: 'gem' } }, analytics);
it('purchases gems', async () => {
const [, message] = await buyGem(user, { params: { type: 'gems', key: 'gem' } }, analytics);
expect(message).to.equal(i18n.t('plusGem', { count: 1 }));
expect(user.balance).to.equal(userGemAmount + 0.25);
@@ -54,8 +54,8 @@ describe('shared.ops.buyGem', () => {
expect(analytics.track).to.be.calledOnce;
});
it('purchases gems with a different language than the default', () => {
const [, message] = buyGem(user, { params: { type: 'gems', key: 'gem' }, language: 'de' });
it('purchases gems with a different language than the default', async () => {
const [, message] = await buyGem(user, { params: { type: 'gems', key: 'gem' }, language: 'de' });
expect(message).to.equal(i18n.t('plusGem', { count: 1 }, 'de'));
expect(user.balance).to.equal(userGemAmount + 0.25);
@@ -63,8 +63,8 @@ describe('shared.ops.buyGem', () => {
expect(user.stats.gp).to.equal(goldPoints - planGemLimits.convRate);
});
it('makes bulk purchases of gems', () => {
const [, message] = buyGem(user, {
it('makes bulk purchases of gems', async () => {
const [, message] = await buyGem(user, {
params: { type: 'gems', key: 'gem' },
quantity: 2,
});
@@ -76,63 +76,58 @@ describe('shared.ops.buyGem', () => {
});
context('Failure conditions', () => {
it('returns an error when key is not provided', done => {
it('returns an error when key is not provided', async () => {
try {
buyGem(user, { params: { type: 'gems' } });
await buyGem(user, { params: { type: 'gems' } });
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('missingKeyParam'));
done();
}
});
it('prevents unsubscribed user from buying gems', done => {
it('prevents unsubscribed user from buying gems', async () => {
delete user.purchased.plan.customerId;
try {
buyGem(user, { params: { type: 'gems', key: 'gem' } });
await buyGem(user, { params: { type: 'gems', key: 'gem' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('mustSubscribeToPurchaseGems'));
done();
}
});
it('prevents user with not enough gold from buying gems', done => {
it('prevents user with not enough gold from buying gems', async () => {
user.stats.gp = 15;
try {
buyGem(user, { params: { type: 'gems', key: 'gem' } });
await buyGem(user, { params: { type: 'gems', key: 'gem' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageNotEnoughGold'));
done();
}
});
it('prevents user that have reached the conversion cap from buying gems', done => {
it('prevents user that have reached the conversion cap from buying gems', async () => {
user.stats.gp = goldPoints;
user.purchased.plan.gemsBought = gemsBought;
try {
buyGem(user, { params: { type: 'gems', key: 'gem' } });
await buyGem(user, { params: { type: 'gems', key: 'gem' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('maxBuyGems', { convCap: planGemLimits.convCap }));
done();
}
});
it('prevents user from buying an invalid quantity', done => {
it('prevents user from buying an invalid quantity', async () => {
user.stats.gp = goldPoints;
user.purchased.plan.gemsBought = gemsBought;
try {
buyGem(user, { params: { type: 'gems', key: 'gem' }, quantity: 'a' });
await buyGem(user, { params: { type: 'gems', key: 'gem' }, quantity: 'a' });
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('invalidQuantity'));
done();
}
});
});
+15 -23
View File
@@ -12,7 +12,7 @@ describe('shared.ops.buyHealthPotion', () => {
let user;
const analytics = { track () {} };
function buyHealthPotion (_user, _req, _analytics) {
async function buyHealthPotion (_user, _req, _analytics) {
const buyOp = new BuyHealthPotionOperation(_user, _req, _analytics);
return buyOp.purchase();
@@ -40,83 +40,75 @@ describe('shared.ops.buyHealthPotion', () => {
});
context('Potion', () => {
it('recovers 15 hp', () => {
it('recovers 15 hp', async () => {
user.stats.hp = 30;
buyHealthPotion(user, {}, analytics);
await buyHealthPotion(user, {}, analytics);
expect(user.stats.hp).to.eql(45);
expect(analytics.track).to.be.calledOnce;
});
it('does not increase hp above 50', () => {
it('does not increase hp above 50', async () => {
user.stats.hp = 45;
buyHealthPotion(user);
await buyHealthPotion(user);
expect(user.stats.hp).to.eql(50);
});
it('deducts 25 gp', () => {
it('deducts 25 gp', async () => {
user.stats.hp = 45;
buyHealthPotion(user);
await buyHealthPotion(user);
expect(user.stats.gp).to.eql(175);
});
it('does not purchase if not enough gp', done => {
it('does not purchase if not enough gp', async () => {
user.stats.hp = 45;
user.stats.gp = 5;
try {
buyHealthPotion(user);
await buyHealthPotion(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageNotEnoughGold'));
expect(user.stats.hp).to.eql(45);
expect(user.stats.gp).to.eql(5);
done();
}
});
it('does not purchase if hp is full', done => {
it('does not purchase if hp is full', async () => {
user.stats.hp = 50;
user.stats.gp = 40;
try {
buyHealthPotion(user);
await buyHealthPotion(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageHealthAlreadyMax'));
expect(user.stats.hp).to.eql(50);
expect(user.stats.gp).to.eql(40);
done();
}
});
it('does not allow potion purchases when hp is zero', done => {
it('does not allow potion purchases when hp is zero', async () => {
user.stats.hp = 0;
user.stats.gp = 40;
try {
buyHealthPotion(user);
await buyHealthPotion(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageHealthAlreadyMin'));
expect(user.stats.hp).to.eql(0);
expect(user.stats.gp).to.eql(40);
done();
}
});
it('does not allow potion purchases when hp is negative', done => {
it('does not allow potion purchases when hp is negative', async () => {
user.stats.hp = -8;
user.stats.gp = 40;
try {
buyHealthPotion(user);
await buyHealthPotion(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageHealthAlreadyMin'));
expect(user.stats.hp).to.eql(-8);
expect(user.stats.gp).to.eql(40);
done();
}
});
});
+44 -52
View File
@@ -13,7 +13,7 @@ import {
import i18n from '../../../../website/common/script/i18n';
import errorMessage from '../../../../website/common/script/libs/errorMessage';
function buyGear (user, req, analytics) {
async function buyGear (user, req, analytics) {
const buyOp = new BuyMarketGearOperation(user, req, analytics);
return buyOp.purchase();
@@ -57,10 +57,10 @@ describe('shared.ops.buyMarketGear', () => {
});
context('Gear', () => {
it('adds equipment to inventory', () => {
it('adds equipment to inventory', async () => {
user.stats.gp = 31;
buyGear(user, { params: { key: 'armor_warrior_1' } }, analytics);
await buyGear(user, { params: { key: 'armor_warrior_1' } }, analytics);
expect(user.items.gear.owned).to.eql({
weapon_warrior_0: true,
@@ -90,10 +90,10 @@ describe('shared.ops.buyMarketGear', () => {
expect(analytics.track).to.be.calledOnce;
});
it('adds the onboarding achievement to the user and checks the onboarding status', () => {
it('adds the onboarding achievement to the user and checks the onboarding status', async () => {
user.stats.gp = 31;
buyGear(user, { params: { key: 'armor_warrior_1' } }, analytics);
await buyGear(user, { params: { key: 'armor_warrior_1' } }, analytics);
expect(user.addAchievement).to.be.calledOnce;
expect(user.addAchievement).to.be.calledWith('purchasedEquipment');
@@ -102,36 +102,36 @@ describe('shared.ops.buyMarketGear', () => {
expect(shared.onboarding.checkOnboardingStatus).to.be.calledWith(user);
});
it('does not add the onboarding achievement to the user if it\'s already been awarded', () => {
it('does not add the onboarding achievement to the user if it\'s already been awarded', async () => {
user.stats.gp = 31;
user.achievements.purchasedEquipment = true;
buyGear(user, { params: { key: 'armor_warrior_1' } }, analytics);
await buyGear(user, { params: { key: 'armor_warrior_1' } }, analytics);
expect(user.addAchievement).to.not.be.called;
});
it('deducts gold from user', () => {
it('deducts gold from user', async () => {
user.stats.gp = 31;
buyGear(user, { params: { key: 'armor_warrior_1' } });
await buyGear(user, { params: { key: 'armor_warrior_1' } });
expect(user.stats.gp).to.eql(1);
});
it('auto equips equipment if user has auto-equip preference turned on', () => {
it('auto equips equipment if user has auto-equip preference turned on', async () => {
user.stats.gp = 31;
user.preferences.autoEquip = true;
buyGear(user, { params: { key: 'armor_warrior_1' } });
await buyGear(user, { params: { key: 'armor_warrior_1' } });
expect(user.items.gear.equipped).to.have.property('armor', 'armor_warrior_1');
});
it('updates the pinnedItems to the next item in the set if one exists', () => {
it('updates the pinnedItems to the next item in the set if one exists', async () => {
user.stats.gp = 31;
buyGear(user, { params: { key: 'armor_warrior_1' } });
await buyGear(user, { params: { key: 'armor_warrior_1' } });
expect(user.pinnedItems).to.deep.include({
type: 'marketGear',
@@ -139,155 +139,147 @@ describe('shared.ops.buyMarketGear', () => {
});
});
it('buyGears equipment but does not auto-equip', () => {
it('buyGears equipment but does not auto-equip', async () => {
user.stats.gp = 31;
user.preferences.autoEquip = false;
buyGear(user, { params: { key: 'armor_warrior_1' } });
await buyGear(user, { params: { key: 'armor_warrior_1' } });
expect(user.items.gear.equipped.property).to.not.equal('armor_warrior_1');
});
it('does not buyGear equipment twice', done => {
it('does not buyGear equipment twice', async () => {
user.stats.gp = 62;
buyGear(user, { params: { key: 'armor_warrior_1' } });
await buyGear(user, { params: { key: 'armor_warrior_1' } });
try {
buyGear(user, { params: { key: 'armor_warrior_1' } });
await buyGear(user, { params: { key: 'armor_warrior_1' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('equipmentAlreadyOwned'));
done();
}
});
it('does not buy equipment of different class', done => {
it('does not buy equipment of different class', async () => {
user.stats.gp = 82;
user.stats.class = 'warrior';
try {
buyGear(user, { params: { key: 'weapon_special_winter2018Rogue' } });
await buyGear(user, { params: { key: 'weapon_special_winter2018Rogue' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('cannotBuyItem'));
done();
}
});
it('does not buy equipment in bulk', done => {
it('does not buy equipment in bulk', async () => {
user.stats.gp = 82;
try {
buyGear(user, { params: { key: 'armor_warrior_1' }, quantity: 3 });
await buyGear(user, { params: { key: 'armor_warrior_1' }, quantity: 3 });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageNotAbleToBuyInBulk'));
done();
}
});
// TODO after user.ops.equip is done
xit('removes one-handed weapon and shield if auto-equip is on and a two-hander is bought', () => {
xit('removes one-handed weapon and shield if auto-equip is on and a two-hander is bought', async () => {
user.stats.gp = 100;
user.preferences.autoEquip = true;
buyGear(user, { params: { key: 'shield_warrior_1' } });
await buyGear(user, { params: { key: 'shield_warrior_1' } });
user.ops.equip({ params: { key: 'shield_warrior_1' } });
buyGear(user, { params: { key: 'weapon_warrior_1' } });
await buyGear(user, { params: { key: 'weapon_warrior_1' } });
user.ops.equip({ params: { key: 'weapon_warrior_1' } });
buyGear(user, { params: { key: 'weapon_wizard_1' } });
await buyGear(user, { params: { key: 'weapon_wizard_1' } });
expect(user.items.gear.equipped).to.have.property('shield', 'shield_base_0');
expect(user.items.gear.equipped).to.have.property('weapon', 'weapon_wizard_1');
});
// TODO after user.ops.equip is done
xit('buyGears two-handed equipment but does not automatically remove sword or shield', () => {
xit('buyGears two-handed equipment but does not automatically remove sword or shield', async () => {
user.stats.gp = 100;
user.preferences.autoEquip = false;
buyGear(user, { params: { key: 'shield_warrior_1' } });
await buyGear(user, { params: { key: 'shield_warrior_1' } });
user.ops.equip({ params: { key: 'shield_warrior_1' } });
buyGear(user, { params: { key: 'weapon_warrior_1' } });
await buyGear(user, { params: { key: 'weapon_warrior_1' } });
user.ops.equip({ params: { key: 'weapon_warrior_1' } });
buyGear(user, { params: { key: 'weapon_wizard_1' } });
await buyGear(user, { params: { key: 'weapon_wizard_1' } });
expect(user.items.gear.equipped).to.have.property('shield', 'shield_warrior_1');
expect(user.items.gear.equipped).to.have.property('weapon', 'weapon_warrior_1');
});
it('does not buyGear equipment without enough Gold', done => {
it('does not buyGear equipment without enough Gold', async () => {
user.stats.gp = 20;
try {
buyGear(user, { params: { key: 'armor_warrior_1' } });
await buyGear(user, { params: { key: 'armor_warrior_1' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageNotEnoughGold'));
expect(user.items.gear.owned).to.not.have.property('armor_warrior_1');
done();
}
});
it('returns error when key is not provided', done => {
it('returns error when key is not provided', async () => {
try {
buyGear(user);
await buyGear(user);
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(errorMessage('missingKeyParam'));
done();
}
});
it('returns error when item is not found', done => {
it('returns error when item is not found', async () => {
const params = { key: 'armor_warrior_notExisting' };
try {
buyGear(user, { params });
await buyGear(user, { params });
} catch (err) {
expect(err).to.be.an.instanceof(NotFound);
expect(err.message).to.equal(errorMessage('itemNotFound', params));
done();
}
});
it('does not buyGear equipment without the previous equipment', done => {
it('does not buyGear equipment without the previous equipment', async () => {
try {
buyGear(user, { params: { key: 'armor_warrior_2' } });
await buyGear(user, { params: { key: 'armor_warrior_2' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('previousGearNotOwned'));
done();
}
});
it('does not buyGear equipment if user does not own prior item in sequence', done => {
it('does not buyGear equipment if user does not own prior item in sequence', async () => {
user.stats.gp = 200;
try {
buyGear(user, { params: { key: 'armor_warrior_2' } });
await buyGear(user, { params: { key: 'armor_warrior_2' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('previousGearNotOwned'));
expect(user.items.gear.owned).to.not.have.property('armor_warrior_2');
done();
}
});
it('does buyGear equipment if item is a numbered special item user qualifies for', () => {
it('does buyGear equipment if item is a numbered special item user qualifies for', async () => {
user.stats.gp = 200;
user.items.gear.owned.head_special_2 = false;
buyGear(user, { params: { key: 'head_special_2' } });
await buyGear(user, { params: { key: 'head_special_2' } });
expect(user.items.gear.owned).to.have.property('head_special_2', true);
});
it('does buyGear equipment if it is an armoire item that an user previously lost', () => {
it('does buyGear equipment if it is an armoire item that an user previously lost', async () => {
user.stats.gp = 200;
user.items.gear.owned.shield_armoire_ramHornShield = false;
buyGear(user, { params: { key: 'shield_armoire_ramHornShield' } });
await buyGear(user, { params: { key: 'shield_armoire_ramHornShield' } });
expect(user.items.gear.owned).to.have.property('shield_armoire_ramHornShield', true);
});
+8 -11
View File
@@ -35,18 +35,17 @@ describe('shared.ops.buyMysterySet', () => {
context('Mystery Sets', () => {
context('failure conditions', () => {
it('does not grant mystery sets without Mystic Hourglasses', done => {
it('does not grant mystery sets without Mystic Hourglasses', async () => {
try {
buyMysterySet(user, { params: { key: '201501' } });
await buyMysterySet(user, { params: { key: '201501' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.eql(i18n.t('notEnoughHourglasses'));
expect(user.items.gear.owned).to.have.property('weapon_warrior_0', true);
done();
}
});
it('does not grant mystery set that has already been purchased', done => {
it('does not grant mystery set that has already been purchased', async () => {
user.purchased.plan.consecutive.trinkets = 1;
user.items.gear.owned = {
weapon_warrior_0: true,
@@ -57,30 +56,28 @@ describe('shared.ops.buyMysterySet', () => {
};
try {
buyMysterySet(user, { params: { key: '301404' } });
await buyMysterySet(user, { params: { key: '301404' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotFound);
expect(err.message).to.eql(i18n.t('mysterySetNotFound'));
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
done();
}
});
it('returns error when key is not provided', done => {
it('returns error when key is not provided', async () => {
try {
buyMysterySet(user);
await buyMysterySet(user);
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(errorMessage('missingKeyParam'));
done();
}
});
});
context('successful purchases', () => {
it('buys Steampunk Accessories Set', () => {
it('buys Steampunk Accessories Set', async () => {
user.purchased.plan.consecutive.trinkets = 1;
buyMysterySet(user, { params: { key: '301404' } }, analytics);
await buyMysterySet(user, { params: { key: '301404' } }, analytics);
expect(user.purchased.plan.consecutive.trinkets).to.eql(0);
expect(user.items.gear.owned).to.have.property('weapon_warrior_0', true);
+9 -10
View File
@@ -13,7 +13,7 @@ describe('shared.ops.buyQuestGems', () => {
const goldPoints = 40;
const analytics = { track () {} };
function buyQuest (_user, _req, _analytics) {
async function buyQuest (_user, _req, _analytics) {
const buyOp = new BuyQuestWithGemOperation(_user, _req, _analytics);
return buyOp.purchase();
@@ -44,19 +44,19 @@ describe('shared.ops.buyQuestGems', () => {
user.pinnedItems.push({ type: 'quests', key: 'gryphon' });
});
it('purchases quests', () => {
it('purchases quests', async () => {
const key = 'gryphon';
buyQuest(user, { params: { key } });
await buyQuest(user, { params: { key } });
expect(user.items.quests[key]).to.equal(1);
expect(pinnedGearUtils.removeItemByPath.notCalled).to.equal(true);
});
it('if a user\'s count of a quest scroll is negative, it will be reset to 0 before incrementing when they buy a new one.', () => {
it('if a user\'s count of a quest scroll is negative, it will be reset to 0 before incrementing when they buy a new one.', async () => {
const key = 'dustbunnies';
user.items.quests[key] = -1;
buyQuest(user, { params: { key } });
await buyQuest(user, { params: { key } });
expect(user.items.quests[key]).to.equal(1);
expect(pinnedGearUtils.removeItemByPath.notCalled).to.equal(true);
@@ -73,26 +73,25 @@ describe('shared.ops.buyQuestGems', () => {
user.purchased.plan.customerId = 'customer-id';
});
it('errors when user does not have enough gems', done => {
it('errors when user does not have enough gems', async () => {
user.balance = 1;
const key = 'gryphon';
try {
buyQuest(user, {
await buyQuest(user, {
params: { key },
quantity: 2,
});
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('notEnoughGems'));
done();
}
});
it('makes bulk purchases of quests', () => {
it('makes bulk purchases of quests', async () => {
const key = 'gryphon';
buyQuest(user, {
await buyQuest(user, {
params: { key },
quantity: 3,
});
+22 -29
View File
@@ -14,7 +14,7 @@ describe('shared.ops.buyQuest', () => {
let user;
const analytics = { track () {} };
function buyQuest (_user, _req, _analytics) {
async function buyQuest (_user, _req, _analytics) {
const buyOp = new BuyQuestWithGoldOperation(_user, _req, _analytics);
return buyOp.purchase();
@@ -29,9 +29,9 @@ describe('shared.ops.buyQuest', () => {
analytics.track.restore();
});
it('buys a Quest scroll', () => {
it('buys a Quest scroll', async () => {
user.stats.gp = 205;
buyQuest(user, {
await buyQuest(user, {
params: {
key: 'dilatoryDistress1',
},
@@ -43,11 +43,11 @@ describe('shared.ops.buyQuest', () => {
expect(analytics.track).to.be.calledOnce;
});
it('if a user\'s count of a quest scroll is negative, it will be reset to 0 before incrementing when they buy a new one.', () => {
it('if a user\'s count of a quest scroll is negative, it will be reset to 0 before incrementing when they buy a new one.', async () => {
user.stats.gp = 205;
const key = 'dilatoryDistress1';
user.items.quests[key] = -1;
buyQuest(user, {
await buyQuest(user, {
params: { key },
}, analytics);
expect(user.items.quests[key]).to.equal(1);
@@ -55,14 +55,14 @@ describe('shared.ops.buyQuest', () => {
expect(analytics.track).to.be.calledOnce;
});
it('buys a Quest scroll with the right quantity if a string is passed for quantity', () => {
it('buys a Quest scroll with the right quantity if a string is passed for quantity', async () => {
user.stats.gp = 1000;
buyQuest(user, {
await buyQuest(user, {
params: {
key: 'dilatoryDistress1',
},
}, analytics);
buyQuest(user, {
await buyQuest(user, {
params: {
key: 'dilatoryDistress1',
},
@@ -74,10 +74,10 @@ describe('shared.ops.buyQuest', () => {
});
});
it('does not buy a Quest scroll when an invalid quantity is passed', done => {
it('does not buy a Quest scroll when an invalid quantity is passed', async () => {
user.stats.gp = 1000;
try {
buyQuest(user, {
await buyQuest(user, {
params: {
key: 'dilatoryDistress1',
},
@@ -88,14 +88,13 @@ describe('shared.ops.buyQuest', () => {
expect(err.message).to.equal(i18n.t('invalidQuantity'));
expect(user.items.quests).to.eql({});
expect(user.stats.gp).to.equal(1000);
done();
}
});
it('does not buy Quests without enough Gold', done => {
it('does not buy Quests without enough Gold', async () => {
user.stats.gp = 1;
try {
buyQuest(user, {
await buyQuest(user, {
params: {
key: 'dilatoryDistress1',
},
@@ -105,14 +104,13 @@ describe('shared.ops.buyQuest', () => {
expect(err.message).to.equal(i18n.t('messageNotEnoughGold'));
expect(user.items.quests).to.eql({});
expect(user.stats.gp).to.equal(1);
done();
}
});
it('does not buy nonexistent Quests', done => {
it('does not buy nonexistent Quests', async () => {
user.stats.gp = 9999;
try {
buyQuest(user, {
await buyQuest(user, {
params: {
key: 'snarfblatter',
},
@@ -122,13 +120,12 @@ describe('shared.ops.buyQuest', () => {
expect(err.message).to.equal(errorMessage('questNotFound', { key: 'snarfblatter' }));
expect(user.items.quests).to.eql({});
expect(user.stats.gp).to.equal(9999);
done();
}
});
it('does not buy the Mystery of the Masterclassers', done => {
it('does not buy the Mystery of the Masterclassers', async () => {
try {
buyQuest(user, {
await buyQuest(user, {
params: {
key: 'lostMasterclasser1',
},
@@ -137,14 +134,13 @@ describe('shared.ops.buyQuest', () => {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('questUnlockLostMasterclasser'));
expect(user.items.quests).to.eql({});
done();
}
});
it('does not buy Gem-premium Quests', done => {
it('does not buy Gem-premium Quests', async () => {
user.stats.gp = 9999;
try {
buyQuest(user, {
await buyQuest(user, {
params: {
key: 'kraken',
},
@@ -154,23 +150,21 @@ describe('shared.ops.buyQuest', () => {
expect(err.message).to.equal(i18n.t('questNotGoldPurchasable', { key: 'kraken' }));
expect(user.items.quests).to.eql({});
expect(user.stats.gp).to.equal(9999);
done();
}
});
it('returns error when key is not provided', done => {
it('returns error when key is not provided', async () => {
try {
buyQuest(user);
await buyQuest(user);
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(errorMessage('missingKeyParam'));
done();
}
});
it('does not buy a quest without completing previous quests', done => {
it('does not buy a quest without completing previous quests', async () => {
try {
buyQuest(user, {
await buyQuest(user, {
params: {
key: 'dilatoryDistress3',
},
@@ -179,7 +173,6 @@ describe('shared.ops.buyQuest', () => {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('mustComplete', { quest: 'dilatoryDistress2' }));
expect(user.items.quests).to.eql({});
done();
}
});
});
+9 -12
View File
@@ -15,7 +15,7 @@ describe('shared.ops.buySpecialSpell', () => {
let user;
const analytics = { track () {} };
function buySpecialSpell (_user, _req, _analytics) {
async function buySpecialSpell (_user, _req, _analytics) {
const buyOp = new BuySpellOperation(_user, _req, _analytics);
return buyOp.purchase();
@@ -29,19 +29,18 @@ describe('shared.ops.buySpecialSpell', () => {
analytics.track.restore();
});
it('throws an error if params.key is missing', done => {
it('throws an error if params.key is missing', async () => {
try {
buySpecialSpell(user);
await buySpecialSpell(user);
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(errorMessage('missingKeyParam'));
done();
}
});
it('throws an error if the spell doesn\'t exists', done => {
it('throws an error if the spell doesn\'t exists', async () => {
try {
buySpecialSpell(user, {
await buySpecialSpell(user, {
params: {
key: 'notExisting',
},
@@ -49,14 +48,13 @@ describe('shared.ops.buySpecialSpell', () => {
} catch (err) {
expect(err).to.be.an.instanceof(NotFound);
expect(err.message).to.equal(errorMessage('spellNotFound', { spellId: 'notExisting' }));
done();
}
});
it('throws an error if the user doesn\'t have enough gold', done => {
it('throws an error if the user doesn\'t have enough gold', async () => {
user.stats.gp = 1;
try {
buySpecialSpell(user, {
await buySpecialSpell(user, {
params: {
key: 'thankyou',
},
@@ -64,15 +62,14 @@ describe('shared.ops.buySpecialSpell', () => {
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageNotEnoughGold'));
done();
}
});
it('buys an item', () => {
it('buys an item', async () => {
user.stats.gp = 11;
const item = content.special.thankyou;
const [data, message] = buySpecialSpell(user, {
const [data, message] = await buySpecialSpell(user, {
params: {
key: 'thankyou',
},
+23 -32
View File
@@ -15,7 +15,7 @@ describe('common.ops.hourglassPurchase', () => {
let user;
const analytics = { track () {} };
function buyMount (_user, _req, _analytics) {
async function buyMount (_user, _req, _analytics) {
const buyOp = new BuyHourglassMountOperation(_user, _req, _analytics);
return buyOp.purchase();
@@ -31,116 +31,107 @@ describe('common.ops.hourglassPurchase', () => {
});
context('failure conditions', () => {
it('return error when key is not provided', done => {
it('return error when key is not provided', async () => {
try {
hourglassPurchase(user, { params: {} });
await hourglassPurchase(user, { params: {} });
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.eql(errorMessage('missingKeyParam'));
done();
}
});
it('returns error when type is not provided', done => {
it('returns error when type is not provided', async () => {
try {
hourglassPurchase(user, { params: { key: 'Base' } });
await hourglassPurchase(user, { params: { key: 'Base' } });
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.eql(errorMessage('missingTypeParam'));
done();
}
});
it('returns error when inccorect type is provided', done => {
it('returns error when inccorect type is provided', async () => {
try {
hourglassPurchase(user, { params: { type: 'notAType', key: 'MantisShrimp-Base' } });
await hourglassPurchase(user, { params: { type: 'notAType', key: 'MantisShrimp-Base' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.eql(i18n.t('typeNotAllowedHourglass', { allowedTypes: _.keys(content.timeTravelStable).toString() }));
done();
}
});
it('does not grant to pets without Mystic Hourglasses', done => {
it('does not grant to pets without Mystic Hourglasses', async () => {
try {
hourglassPurchase(user, { params: { type: 'pets', key: 'MantisShrimp-Base' } });
await hourglassPurchase(user, { params: { type: 'pets', key: 'MantisShrimp-Base' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.eql(i18n.t('notEnoughHourglasses'));
done();
}
});
it('does not grant to mounts without Mystic Hourglasses', done => {
it('does not grant to mounts without Mystic Hourglasses', async () => {
try {
buyMount(user, { params: { key: 'MantisShrimp-Base' } });
await buyMount(user, { params: { key: 'MantisShrimp-Base' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.eql(i18n.t('notEnoughHourglasses'));
done();
}
});
it('does not grant pet that is not part of the Time Travel Stable', done => {
it('does not grant pet that is not part of the Time Travel Stable', async () => {
user.purchased.plan.consecutive.trinkets = 1;
try {
hourglassPurchase(user, { params: { type: 'pets', key: 'Wolf-Veteran' } });
await hourglassPurchase(user, { params: { type: 'pets', key: 'Wolf-Veteran' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.eql(i18n.t('notAllowedHourglass'));
done();
}
});
it('does not grant mount that is not part of the Time Travel Stable', done => {
it('does not grant mount that is not part of the Time Travel Stable', async () => {
user.purchased.plan.consecutive.trinkets = 1;
try {
buyMount(user, { params: { key: 'Orca-Base' } });
await buyMount(user, { params: { key: 'Orca-Base' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.eql(i18n.t('notAllowedHourglass'));
done();
}
});
it('does not grant pet that has already been purchased', done => {
it('does not grant pet that has already been purchased', async () => {
user.purchased.plan.consecutive.trinkets = 1;
user.items.pets = {
'MantisShrimp-Base': true,
};
try {
hourglassPurchase(user, { params: { type: 'pets', key: 'MantisShrimp-Base' } });
await hourglassPurchase(user, { params: { type: 'pets', key: 'MantisShrimp-Base' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.eql(i18n.t('petsAlreadyOwned'));
done();
}
});
it('does not grant mount that has already been purchased', done => {
it('does not grant mount that has already been purchased', async () => {
user.purchased.plan.consecutive.trinkets = 1;
user.items.mounts = {
'MantisShrimp-Base': true,
};
try {
buyMount(user, { params: { key: 'MantisShrimp-Base' } });
await buyMount(user, { params: { key: 'MantisShrimp-Base' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.eql(i18n.t('mountsAlreadyOwned'));
done();
}
});
});
context('successful purchases', () => {
it('buys a pet', () => {
it('buys a pet', async () => {
user.purchased.plan.consecutive.trinkets = 2;
const [, message] = hourglassPurchase(user, { params: { type: 'pets', key: 'MantisShrimp-Base' } }, analytics);
const [, message] = await hourglassPurchase(user, { params: { type: 'pets', key: 'MantisShrimp-Base' } }, analytics);
expect(message).to.eql(i18n.t('hourglassPurchase'));
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
@@ -148,10 +139,10 @@ describe('common.ops.hourglassPurchase', () => {
expect(analytics.track).to.be.calledOnce;
});
it('buys a mount', () => {
it('buys a mount', async () => {
user.purchased.plan.consecutive.trinkets = 2;
const [, message] = buyMount(user, { params: { key: 'MantisShrimp-Base' } });
const [, message] = await buyMount(user, { params: { key: 'MantisShrimp-Base' } });
expect(message).to.eql(i18n.t('hourglassPurchase'));
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
expect(user.items.mounts).to.eql({ 'MantisShrimp-Base': true });
+34 -45
View File
@@ -33,118 +33,108 @@ describe('shared.ops.purchase', () => {
});
context('failure conditions', () => {
it('returns an error when type is not provided', done => {
it('returns an error when type is not provided', async () => {
try {
purchase(user, { params: {} });
await purchase(user, { params: {} });
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('typeRequired'));
done();
}
});
it('returns error when unknown type is provided', done => {
it('returns error when unknown type is provided', async () => {
try {
purchase(user, { params: { type: 'randomType', key: 'gem' } });
await purchase(user, { params: { type: 'randomType', key: 'gem' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotFound);
expect(err.message).to.equal(i18n.t('notAccteptedType'));
done();
}
});
it('returns error when user attempts to purchase a piece of gear they own', done => {
it('returns error when user attempts to purchase a piece of gear they own', async () => {
user.items.gear.owned['shield_rogue_1'] = true; // eslint-disable-line dot-notation
try {
purchase(user, { params: { type: 'gear', key: 'shield_rogue_1' } });
await purchase(user, { params: { type: 'gear', key: 'shield_rogue_1' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('alreadyHave'));
done();
}
});
it('returns error when unknown item is requested', done => {
it('returns error when unknown item is requested', async () => {
try {
purchase(user, { params: { type: 'gear', key: 'randomKey' } });
await purchase(user, { params: { type: 'gear', key: 'randomKey' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotFound);
expect(err.message).to.equal(i18n.t('contentKeyNotFound', { type: 'gear' }));
done();
}
});
it('returns error when user does not have permission to buy an item', done => {
it('returns error when user does not have permission to buy an item', async () => {
try {
purchase(user, { params: { type: 'gear', key: 'eyewear_mystery_301405' } });
await purchase(user, { params: { type: 'gear', key: 'eyewear_mystery_301405' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageNotAvailable'));
done();
}
});
it('returns error when user does not have enough gems to buy an item', done => {
it('returns error when user does not have enough gems to buy an item', async () => {
try {
purchase(user, { params: { type: 'gear', key: 'headAccessory_special_wolfEars' } });
await purchase(user, { params: { type: 'gear', key: 'headAccessory_special_wolfEars' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('notEnoughGems'));
done();
}
});
it('returns error when item is not found', done => {
it('returns error when item is not found', async () => {
const params = { key: 'notExisting', type: 'food' };
try {
purchase(user, { params });
await purchase(user, { params });
} catch (err) {
expect(err).to.be.an.instanceof(NotFound);
expect(err.message).to.equal(i18n.t('contentKeyNotFound', params));
done();
}
});
it('returns error when user supplies a non-numeric quantity', done => {
it('returns error when user supplies a non-numeric quantity', async () => {
const type = 'eggs';
const key = 'Wolf';
try {
purchase(user, { params: { type, key }, quantity: 'jamboree' }, analytics);
await purchase(user, { params: { type, key }, quantity: 'jamboree' }, analytics);
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('invalidQuantity'));
done();
}
});
it('returns error when user supplies a negative quantity', done => {
it('returns error when user supplies a negative quantity', async () => {
const type = 'eggs';
const key = 'Wolf';
user.balance = 10;
try {
purchase(user, { params: { type, key }, quantity: -2 }, analytics);
await purchase(user, { params: { type, key }, quantity: -2 }, analytics);
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('invalidQuantity'));
done();
}
});
it('returns error when user supplies a decimal quantity', done => {
it('returns error when user supplies a decimal quantity', async () => {
const type = 'eggs';
const key = 'Wolf';
user.balance = 10;
try {
purchase(user, { params: { type, key }, quantity: 2.9 }, analytics);
await purchase(user, { params: { type, key }, quantity: 2.9 }, analytics);
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('invalidQuantity'));
done();
}
});
});
@@ -164,48 +154,48 @@ describe('shared.ops.purchase', () => {
user.pinnedItems.push({ type: 'bundles', key: 'featheredFriends' });
});
it('purchases eggs', () => {
it('purchases eggs', async () => {
const type = 'eggs';
const key = 'Wolf';
purchase(user, { params: { type, key } }, analytics);
await purchase(user, { params: { type, key } }, analytics);
expect(user.items[type][key]).to.equal(1);
expect(pinnedGearUtils.removeItemByPath.notCalled).to.equal(true);
expect(analytics.track).to.be.calledOnce;
});
it('purchases hatchingPotions', () => {
it('purchases hatchingPotions', async () => {
const type = 'hatchingPotions';
const key = 'Base';
purchase(user, { params: { type, key } });
await purchase(user, { params: { type, key } });
expect(user.items[type][key]).to.equal(1);
expect(pinnedGearUtils.removeItemByPath.notCalled).to.equal(true);
});
it('purchases food', () => {
it('purchases food', async () => {
const type = 'food';
const key = SEASONAL_FOOD;
purchase(user, { params: { type, key } });
await purchase(user, { params: { type, key } });
expect(user.items[type][key]).to.equal(1);
expect(pinnedGearUtils.removeItemByPath.notCalled).to.equal(true);
});
it('purchases gear', () => {
it('purchases gear', async () => {
const type = 'gear';
const key = 'headAccessory_special_tigerEars';
purchase(user, { params: { type, key } });
await purchase(user, { params: { type, key } });
expect(user.items.gear.owned[key]).to.be.true;
expect(pinnedGearUtils.removeItemByPath.calledOnce).to.equal(true);
});
it('purchases quest bundles', () => {
it('purchases quest bundles', async () => {
const startingBalance = user.balance;
const clock = sandbox.useFakeTimers(moment('2019-05-20').valueOf());
const type = 'bundles';
@@ -217,7 +207,7 @@ describe('shared.ops.purchase', () => {
'owl',
];
purchase(user, { params: { type, key } });
await purchase(user, { params: { type, key } });
forEach(questList, bundledKey => {
expect(user.items.quests[bundledKey]).to.equal(1);
@@ -240,28 +230,27 @@ describe('shared.ops.purchase', () => {
user.purchased.plan.customerId = 'customer-id';
});
it('errors when user does not have enough gems', done => {
it('errors when user does not have enough gems', async () => {
user.balance = 1;
const type = 'eggs';
const key = 'TigerCub';
try {
purchase(user, {
await purchase(user, {
params: { type, key },
quantity: 2,
});
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('notEnoughGems'));
done();
}
});
it('makes bulk purchases of eggs', () => {
it('makes bulk purchases of eggs', async () => {
const type = 'eggs';
const key = 'TigerCub';
purchase(user, {
await purchase(user, {
params: { type, key },
quantity: 2,
});
+14 -18
View File
@@ -19,51 +19,48 @@ describe('shared.ops.changeClass', () => {
user.stats.flagSelected = false;
});
it('user is not level 10', done => {
it('user is not level 10', async () => {
user.stats.lvl = 9;
try {
changeClass(user, { query: { class: 'rogue' } });
await await changeClass(user, { query: { class: 'rogue' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('lvl10ChangeClass'));
done();
}
});
it('req.query.class is an invalid class', done => {
it('req.query.class is an invalid class', async () => {
user.flags.classSelected = false;
user.preferences.disableClasses = false;
try {
changeClass(user, { query: { class: 'cellist' } });
await changeClass(user, { query: { class: 'cellist' } });
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('invalidClass'));
done();
}
});
context('req.query.class is a valid class', () => {
it('errors if user.stats.flagSelected is true and user.balance < 0.75', done => {
it('errors if user.stats.flagSelected is true and user.balance < 0.75', async () => {
user.flags.classSelected = true;
user.preferences.disableClasses = false;
user.balance = 0;
try {
changeClass(user, { query: { class: 'rogue' } });
await changeClass(user, { query: { class: 'rogue' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('notEnoughGems'));
done();
}
});
it('changes class', () => {
it('changes class', async () => {
user.stats.class = 'healer';
user.items.gear.owned.weapon_healer_3 = true;
user.items.gear.equipped.weapon = 'weapon_healer_3';
const [data] = changeClass(user, { query: { class: 'rogue' } });
const [data] = await changeClass(user, { query: { class: 'rogue' } });
expect(data).to.eql({
preferences: user.preferences,
stats: user.stats,
@@ -81,7 +78,7 @@ describe('shared.ops.changeClass', () => {
});
context('req.query.class is missing or user.stats.flagSelected is true', () => {
it('has user.preferences.disableClasses === true', () => {
it('has user.preferences.disableClasses === true', async () => {
user.balance = 1;
user.preferences.disableClasses = true;
user.preferences.autoAllocate = true;
@@ -92,7 +89,7 @@ describe('shared.ops.changeClass', () => {
user.stats.int = 4;
user.flags.classSelected = true;
const [data] = changeClass(user);
const [data] = await changeClass(user);
expect(data).to.eql({
preferences: user.preferences,
stats: user.stats,
@@ -112,18 +109,17 @@ describe('shared.ops.changeClass', () => {
});
context('has user.preferences.disableClasses !== true', () => {
it('and less than 3 gems', done => {
it('and less than 3 gems', async () => {
user.balance = 0.5;
try {
changeClass(user);
await changeClass(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('notEnoughGems'));
done();
}
});
it('and at least 3 gems', () => {
it('and at least 3 gems', async () => {
user.balance = 1;
user.stats.points = 45;
user.stats.str = 1;
@@ -132,7 +128,7 @@ describe('shared.ops.changeClass', () => {
user.stats.int = 4;
user.flags.classSelected = true;
const [data] = changeClass(user);
const [data] = await changeClass(user);
expect(data).to.eql({
preferences: user.preferences,
stats: user.stats,
+48 -49
View File
@@ -24,60 +24,59 @@ describe('shared.ops.rebirth', () => {
tasks = [generateHabit(), generateDaily(), generateTodo(), generateReward()];
});
it('returns an error when user balance is too low and user is less than max level', done => {
it('returns an error when user balance is too low and user is less than max level', async () => {
user.balance = 0;
try {
rebirth(user);
await rebirth(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('notEnoughGems'));
done();
}
});
it('rebirths a user with enough gems', () => {
const [, message] = rebirth(user);
it('rebirths a user with enough gems', async () => {
const [, message] = await rebirth(user);
expect(message).to.equal(i18n.t('rebirthComplete'));
});
it('rebirths a user with not enough gems but max level', () => {
it('rebirths a user with not enough gems but max level', async () => {
user.balance = 0;
user.stats.lvl = MAX_LEVEL;
const [, message] = rebirth(user);
const [, message] = await rebirth(user);
expect(message).to.equal(i18n.t('rebirthComplete'));
expect(user.flags.lastFreeRebirth).to.exist;
});
it('rebirths a user with not enough gems but more than max level', () => {
it('rebirths a user with not enough gems but more than max level', async () => {
user.balance = 0;
user.stats.lvl = MAX_LEVEL + 1;
const [, message] = rebirth(user);
const [, message] = await rebirth(user);
expect(message).to.equal(i18n.t('rebirthComplete'));
});
it('rebirths a user using gems if over max level but rebirthed recently', () => {
it('rebirths a user using gems if over max level but rebirthed recently', async () => {
user.stats.lvl = MAX_LEVEL + 1;
user.flags.lastFreeRebirth = new Date();
const [, message] = rebirth(user);
const [, message] = await rebirth(user);
expect(message).to.equal(i18n.t('rebirthComplete'));
expect(user.balance).to.equal(0);
});
it('resets user\'s tasks values except for rewards to 0', () => {
it('resets user\'s tasks values except for rewards to 0', async () => {
tasks[0].value = 1;
tasks[1].value = 1;
tasks[2].value = 1;
tasks[3].value = 1; // Reward
rebirth(user, tasks);
await rebirth(user, tasks);
expect(tasks[0].value).to.equal(0);
expect(tasks[1].value).to.equal(0);
@@ -85,99 +84,99 @@ describe('shared.ops.rebirth', () => {
expect(tasks[3].value).to.equal(1); // Reward
});
it('resets user\'s daily streaks to 0', () => {
it('resets user\'s daily streaks to 0', async () => {
tasks[0].counterDown = 1; // Habit
tasks[0].counterUp = 1; // Habit
tasks[1].streak = 1; // Daily
rebirth(user, tasks);
await rebirth(user, tasks);
expect(tasks[0].counterDown).to.equal(0);
expect(tasks[0].counterUp).to.equal(0);
expect(tasks[1].streak).to.equal(0);
});
it('resets a user\'s buffs', () => {
it('resets a user\'s buffs', async () => {
user.stats.buffs = { test: 'test' };
rebirth(user);
await rebirth(user);
expect(user.stats.buffs).to.be.empty;
});
it('resets a user\'s health points', () => {
it('resets a user\'s health points', async () => {
user.stats.hp = 40;
rebirth(user);
await rebirth(user);
expect(user.stats.hp).to.equal(50);
});
it('resets a user\'s class', () => {
it('resets a user\'s class', async () => {
user.stats.class = 'rouge';
rebirth(user);
await rebirth(user);
expect(user.stats.class).to.equal('warrior');
});
it('resets a user\'s stats', () => {
it('resets a user\'s stats', async () => {
user.stats.class = 'rouge';
_.each(userStats, value => {
user.stats[value] = 10;
});
rebirth(user);
await rebirth(user);
_.each(userStats, value => {
user.stats[value] = 0;
});
});
it('retains a user\'s gear', () => {
it('retains a user\'s gear', async () => {
const prevGearEquipped = user.items.gear.equipped;
const prevGearCostume = user.items.gear.costume;
const prevPrefCostume = user.preferences.costume;
rebirth(user);
await rebirth(user);
expect(user.items.gear.equipped).to.deep.equal(prevGearEquipped);
expect(user.items.gear.costume).to.deep.equal(prevGearCostume);
expect(user.preferences.costume).to.equal(prevPrefCostume);
});
it('retains a user\'s gear owned', () => {
it('retains a user\'s gear owned', async () => {
user.items.gear.owned.weapon_warrior_1 = true; // eslint-disable-line camelcase
const prevGearOwned = user.items.gear.owned;
rebirth(user);
await rebirth(user);
expect(user.items.gear.owned).to.equal(prevGearOwned);
});
it('resets a user\'s current pet', () => {
it('resets a user\'s current pet', async () => {
user.items.pets[animal] = true;
user.items.currentPet = animal;
rebirth(user);
await rebirth(user);
expect(user.items.currentPet).to.be.empty;
});
it('resets a user\'s current mount', () => {
it('resets a user\'s current mount', async () => {
user.items.mounts[animal] = true;
user.items.currentMount = animal;
rebirth(user);
await rebirth(user);
expect(user.items.currentMount).to.be.empty;
});
it('resets a user\'s flags', () => {
it('resets a user\'s flags', async () => {
user.flags.itemsEnabled = true;
user.flags.classSelected = true;
user.flags.rebirthEnabled = true;
user.flags.levelDrops = { test: 'test' };
rebirth(user);
await rebirth(user);
expect(user.flags.itemsEnabled).to.be.false;
expect(user.flags.classSelected).to.be.false;
@@ -185,80 +184,80 @@ describe('shared.ops.rebirth', () => {
expect(user.flags.levelDrops).to.be.empty;
});
it('reset rebirthEnabled even if user has beastMaster', () => {
it('reset rebirthEnabled even if user has beastMaster', async () => {
user.achievements.beastMaster = 1;
user.flags.rebirthEnabled = true;
rebirth(user);
await rebirth(user);
expect(user.flags.rebirthEnabled).to.be.false;
});
it('sets rebirth achievement', () => {
rebirth(user);
it('sets rebirth achievement', async () => {
await rebirth(user);
expect(user.achievements.rebirths).to.equal(1);
expect(user.achievements.rebirthLevel).to.equal(user.stats.lvl);
});
it('increments rebirth achievements', () => {
it('increments rebirth achievements', async () => {
user.stats.lvl = 2;
user.achievements.rebirths = 1;
user.achievements.rebirthLevel = 1;
rebirth(user);
await rebirth(user);
expect(user.achievements.rebirths).to.equal(2);
expect(user.achievements.rebirthLevel).to.equal(2);
});
it('does not increment rebirth achievements when level is lower than previous', () => {
it('does not increment rebirth achievements when level is lower than previous', async () => {
user.stats.lvl = 2;
user.achievements.rebirths = 1;
user.achievements.rebirthLevel = 3;
rebirth(user);
await rebirth(user);
expect(user.achievements.rebirths).to.equal(1);
expect(user.achievements.rebirthLevel).to.equal(3);
});
it('always increments rebirth achievements when level is MAX_LEVEL', () => {
it('always increments rebirth achievements when level is MAX_LEVEL', async () => {
user.stats.lvl = MAX_LEVEL;
user.achievements.rebirths = 1;
// this value is not actually possible (actually capped at MAX_LEVEL) but makes a good test
user.achievements.rebirthLevel = MAX_LEVEL + 1;
rebirth(user);
await rebirth(user);
expect(user.achievements.rebirths).to.equal(2);
expect(user.achievements.rebirthLevel).to.equal(MAX_LEVEL);
});
it('always increments rebirth achievements when level is greater than MAX_LEVEL', () => {
it('always increments rebirth achievements when level is greater than MAX_LEVEL', async () => {
user.stats.lvl = MAX_LEVEL + 1;
user.achievements.rebirths = 1;
// this value is not actually possible (actually capped at MAX_LEVEL) but makes a good test
user.achievements.rebirthLevel = MAX_LEVEL + 2;
rebirth(user);
await rebirth(user);
expect(user.achievements.rebirths).to.equal(2);
expect(user.achievements.rebirthLevel).to.equal(MAX_LEVEL);
});
it('keeps automaticAllocation false', () => {
it('keeps automaticAllocation false', async () => {
user.preferences.automaticAllocation = false;
rebirth(user);
await rebirth(user);
expect(user.preferences.automaticAllocation).to.be.false;
});
it('sets automaticAllocation to false when true', () => {
it('sets automaticAllocation to false when true', async () => {
user.preferences.automaticAllocation = true;
rebirth(user);
await rebirth(user);
expect(user.preferences.automaticAllocation).to.be.false;
});
+19 -21
View File
@@ -23,87 +23,85 @@ describe('shared.ops.releaseMounts', () => {
user.balance = 1;
});
it('returns an error when user balance is too low', done => {
it('returns an error when user balance is too low', async () => {
user.balance = 0;
try {
releaseMounts(user);
await releaseMounts(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('notEnoughGems'));
done();
}
});
it('returns an error when user does not have all pets', done => {
it('returns an error when user does not have all pets', async () => {
const mountsKeys = Object.keys(user.items.mounts);
delete user.items.mounts[mountsKeys[0]];
try {
releaseMounts(user);
await releaseMounts(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('notEnoughMounts'));
done();
}
});
it('releases mounts', () => {
const message = releaseMounts(user)[1];
it('releases mounts', async () => {
const result = await releaseMounts(user);
expect(message).to.equal(i18n.t('mountsReleased'));
expect(result[1]).to.equal(i18n.t('mountsReleased'));
expect(user.items.mounts[animal]).to.equal(null);
});
it('removes drop currentMount', () => {
it('removes drop currentMount', async () => {
const mountInfo = content.mountInfo[user.items.currentMount];
expect(mountInfo.type).to.equal('drop');
releaseMounts(user);
await releaseMounts(user);
expect(user.items.currentMount).to.be.empty;
});
it('leaves non-drop mount equipped', () => {
it('leaves non-drop mount equipped', async () => {
const questAnimal = 'Gryphon-Base';
user.items.currentMount = questAnimal;
user.items.mounts[questAnimal] = true;
const mountInfo = content.mountInfo[user.items.currentMount];
expect(mountInfo.type).to.not.equal('drop');
releaseMounts(user);
await releaseMounts(user);
expect(user.items.currentMount).to.equal(questAnimal);
});
it('increases mountMasterCount achievement', () => {
releaseMounts(user);
it('increases mountMasterCount achievement', async () => {
await releaseMounts(user);
expect(user.achievements.mountMasterCount).to.equal(1);
});
it('does not increase mountMasterCount achievement if mount is missing (null)', () => {
it('does not increase mountMasterCount achievement if mount is missing (null)', async () => {
const mountMasterCountBeforeRelease = user.achievements.mountMasterCount;
user.items.mounts[animal] = null;
try {
releaseMounts(user);
await releaseMounts(user);
} catch (e) {
expect(user.achievements.mountMasterCount).to.equal(mountMasterCountBeforeRelease);
}
});
it('does not increase mountMasterCount achievement if mount is missing (undefined)', () => {
it('does not increase mountMasterCount achievement if mount is missing (undefined)', async () => {
const mountMasterCountBeforeRelease = user.achievements.mountMasterCount;
delete user.items.mounts[animal];
try {
releaseMounts(user);
await releaseMounts(user);
} catch (e) {
expect(user.achievements.mountMasterCount).to.equal(mountMasterCountBeforeRelease);
}
});
it('subtracts gems from balance', () => {
releaseMounts(user);
it('subtracts gems from balance', async () => {
await releaseMounts(user);
expect(user.balance).to.equal(0);
});
+20 -22
View File
@@ -23,98 +23,96 @@ describe('shared.ops.releasePets', () => {
user.balance = 1;
});
it('returns an error when user balance is too low', done => {
it('returns an error when user balance is too low', async () => {
user.balance = 0;
try {
releasePets(user);
await releasePets(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('notEnoughGems'));
done();
}
});
it('returns an error when user does not have all pets', done => {
it('returns an error when user does not have all pets', async () => {
const petKeys = Object.keys(user.items.pets);
delete user.items.pets[petKeys[0]];
try {
releasePets(user);
await releasePets(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('notEnoughPets'));
done();
}
});
it('releases pets', () => {
const message = releasePets(user)[1];
it('releases pets', async () => {
const message = await releasePets(user)[1];
expect(message).to.equal(i18n.t('petsReleased'));
expect(user.items.pets[animal]).to.equal(0);
});
it('removes drop currentPet', () => {
it('removes drop currentPet', async () => {
const petInfo = content.petInfo[user.items.currentPet];
expect(petInfo.type).to.equal('drop');
releasePets(user);
await releasePets(user);
expect(user.items.currentPet).to.be.empty;
});
it('leaves non-drop pets equipped', () => {
it('leaves non-drop pets equipped', async () => {
const questAnimal = 'Gryphon-Base';
user.items.currentPet = questAnimal;
user.items.pets[questAnimal] = 5;
const petInfo = content.petInfo[user.items.currentPet];
expect(petInfo.type).to.not.equal('drop');
releasePets(user);
await releasePets(user);
expect(user.items.currentPet).to.equal(questAnimal);
});
it('decreases user\'s balance', () => {
releasePets(user);
it('decreases user\'s balance', async () => {
await releasePets(user);
expect(user.balance).to.equal(0);
});
it('incremenets beastMasterCount', () => {
releasePets(user);
it('incremenets beastMasterCount', async () => {
await releasePets(user);
expect(user.achievements.beastMasterCount).to.equal(1);
});
it('does not increment beastMasterCount if any pet is level 0 (released)', () => {
it('does not increment beastMasterCount if any pet is level 0 (released)', async () => {
const beastMasterCountBeforeRelease = user.achievements.beastMasterCount;
user.items.pets[animal] = 0;
try {
releasePets(user);
await releasePets(user);
} catch (e) {
expect(user.achievements.beastMasterCount).to.equal(beastMasterCountBeforeRelease);
}
});
it('does not increment beastMasterCount if any pet is missing (null)', () => {
it('does not increment beastMasterCount if any pet is missing (null)', async () => {
const beastMasterCountBeforeRelease = user.achievements.beastMasterCount;
user.items.pets[animal] = null;
try {
releasePets(user);
await releasePets(user);
} catch (e) {
expect(user.achievements.beastMasterCount).to.equal(beastMasterCountBeforeRelease);
}
});
it('does not increment beastMasterCount if any pet is missing (undefined)', () => {
it('does not increment beastMasterCount if any pet is missing (undefined)', async () => {
const beastMasterCountBeforeRelease = user.achievements.beastMasterCount;
delete user.items.pets[animal];
try {
releasePets(user);
await releasePets(user);
} catch (e) {
expect(user.achievements.beastMasterCount).to.equal(beastMasterCountBeforeRelease);
}
+10 -11
View File
@@ -19,43 +19,42 @@ describe('shared.ops.reroll', () => {
tasks = [generateDaily(), generateReward()];
});
it('returns an error when user balance is too low', done => {
it('returns an error when user balance is too low', async () => {
user.balance = 0;
try {
reroll(user);
await reroll(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('notEnoughGems'));
done();
}
});
it('rerolls a user with enough gems', () => {
const [, message] = reroll(user);
it('rerolls a user with enough gems', async () => {
const [, message] = await reroll(user);
expect(message).to.equal(i18n.t('fortifyComplete'));
});
it('reduces a user\'s balance', () => {
reroll(user);
it('reduces a user\'s balance', async () => {
await reroll(user);
expect(user.balance).to.equal(0);
});
it('resets a user\'s health points', () => {
it('resets a user\'s health points', async () => {
user.stats.hp = 40;
reroll(user);
await reroll(user);
expect(user.stats.hp).to.equal(50);
});
it('resets user\'s taks values except for rewards to 0', () => {
it('resets user\'s taks values except for rewards to 0', async () => {
tasks[0].value = 1;
tasks[1].value = 1;
reroll(user, tasks);
await reroll(user, tasks);
expect(tasks[0].value).to.equal(0);
expect(tasks[1].value).to.equal(1);
+70 -81
View File
@@ -19,184 +19,173 @@ describe('shared.ops.unlock', () => {
user.balance = usersStartingGems;
});
it('returns an error when path is not provided', done => {
it('returns an error when path is not provided', async () => {
try {
unlock(user);
await unlock(user);
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('pathRequired'));
done();
}
});
it('does not unlock lost gear', done => {
it('does not unlock lost gear', async () => {
user.items.gear.owned.headAccessory_special_bearEars = false;
unlock(user, { query: { path: 'items.gear.owned.headAccessory_special_bearEars' } });
await unlock(user, { query: { path: 'items.gear.owned.headAccessory_special_bearEars' } });
expect(user.balance).to.equal(usersStartingGems);
done();
});
it('returns an error when user balance is too low', done => {
it('returns an error when user balance is too low', async () => {
user.balance = 0;
try {
unlock(user, { query: { path: unlockPath } });
await unlock(user, { query: { path: unlockPath } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('notEnoughGems'));
done();
}
});
it('returns an error when user already owns a full set', done => {
it('returns an error when user already owns a full set', async () => {
let expectedBalance;
try {
unlock(user, { query: { path: unlockPath } });
await unlock(user, { query: { path: unlockPath } });
expectedBalance = user.balance;
unlock(user, { query: { path: unlockPath } });
await unlock(user, { query: { path: unlockPath } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('alreadyUnlocked'));
expect(user.balance).to.equal(expectedBalance);
done();
}
});
it('returns an error when user already owns a full set of gear', done => {
it('returns an error when user already owns a full set of gear', async () => {
let expectedBalance;
try {
unlock(user, { query: { path: unlockGearSetPath } });
await unlock(user, { query: { path: unlockGearSetPath } });
expectedBalance = user.balance;
unlock(user, { query: { path: unlockGearSetPath } });
await unlock(user, { query: { path: unlockGearSetPath } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('alreadyUnlocked'));
expect(user.balance).to.equal(expectedBalance);
done();
}
});
it('returns an error if an item does not exists', done => {
it('returns an error if an item does not exists', async () => {
try {
unlock(user, { query: { path: 'background.invalid_background' } });
await unlock(user, { query: { path: 'background.invalid_background' } });
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('invalidUnlockSet'));
done();
}
});
it('returns an error if there are items from multiple sets', done => {
it('returns an error if there are items from multiple sets', async () => {
try {
unlock(user, { query: { path: 'shirt.convict,skin.0ff591' } });
await unlock(user, { query: { path: 'shirt.convict,skin.0ff591' } });
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('invalidUnlockSet'));
done();
}
});
it('returns an error if gear is not from the animal set', done => {
it('returns an error if gear is not from the animal set', async () => {
try {
unlock(user, { query: { path: 'items.gear.owned.back_mystery_202004' } });
await unlock(user, { query: { path: 'items.gear.owned.back_mystery_202004' } });
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('invalidUnlockSet'));
done();
}
});
it('returns an error if the item is free', done => {
it('returns an error if the item is free', async () => {
try {
unlock(user, { query: { path: 'shirt.black' } });
await unlock(user, { query: { path: 'shirt.black' } });
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('invalidUnlockSet'));
done();
}
});
it('returns an error if an item does not belong to a set (appearances)', done => {
it('returns an error if an item does not belong to a set (appearances)', async () => {
try {
unlock(user, { query: { path: 'shirt.pink' } });
await unlock(user, { query: { path: 'shirt.pink' } });
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('invalidUnlockSet'));
done();
}
});
it('returns an error when user already owns items in a full set and it would be more expensive to buy the entire set', done => {
it('returns an error when user already owns items in a full set and it would be more expensive to buy the entire set', async () => {
try {
// There are 11 shirts in the set, each cost 2 gems, the full set 5 gems
// In order for the full purchase not to be worth, we must own 9
const partialUnlockPaths = unlockPath.split(',');
unlock(user, { query: { path: partialUnlockPaths[0] } });
unlock(user, { query: { path: partialUnlockPaths[1] } });
unlock(user, { query: { path: partialUnlockPaths[2] } });
unlock(user, { query: { path: partialUnlockPaths[3] } });
unlock(user, { query: { path: partialUnlockPaths[4] } });
unlock(user, { query: { path: partialUnlockPaths[5] } });
unlock(user, { query: { path: partialUnlockPaths[6] } });
unlock(user, { query: { path: partialUnlockPaths[7] } });
unlock(user, { query: { path: partialUnlockPaths[8] } });
await unlock(user, { query: { path: partialUnlockPaths[0] } });
await unlock(user, { query: { path: partialUnlockPaths[1] } });
await unlock(user, { query: { path: partialUnlockPaths[2] } });
await unlock(user, { query: { path: partialUnlockPaths[3] } });
await unlock(user, { query: { path: partialUnlockPaths[4] } });
await unlock(user, { query: { path: partialUnlockPaths[5] } });
await unlock(user, { query: { path: partialUnlockPaths[6] } });
await unlock(user, { query: { path: partialUnlockPaths[7] } });
await unlock(user, { query: { path: partialUnlockPaths[8] } });
unlock(user, { query: { path: unlockPath } });
await unlock(user, { query: { path: unlockPath } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('alreadyUnlockedPart'));
done();
}
});
it('does not return an error when user already owns items in a full set and it would not be more expensive to buy the entire set', () => {
it('does not return an error when user already owns items in a full set and it would not be more expensive to buy the entire set', async () => {
// There are 11 shirts in the set, each cost 2 gems, the full set 5 gems
// In order for the full purchase to be worth, we can own already 8
const partialUnlockPaths = unlockPath.split(',');
unlock(user, { query: { path: partialUnlockPaths[0] } });
unlock(user, { query: { path: partialUnlockPaths[1] } });
unlock(user, { query: { path: partialUnlockPaths[2] } });
unlock(user, { query: { path: partialUnlockPaths[3] } });
unlock(user, { query: { path: partialUnlockPaths[4] } });
unlock(user, { query: { path: partialUnlockPaths[5] } });
unlock(user, { query: { path: partialUnlockPaths[6] } });
unlock(user, { query: { path: partialUnlockPaths[7] } });
await unlock(user, { query: { path: partialUnlockPaths[0] } });
await unlock(user, { query: { path: partialUnlockPaths[1] } });
await unlock(user, { query: { path: partialUnlockPaths[2] } });
await unlock(user, { query: { path: partialUnlockPaths[3] } });
await unlock(user, { query: { path: partialUnlockPaths[4] } });
await unlock(user, { query: { path: partialUnlockPaths[5] } });
await unlock(user, { query: { path: partialUnlockPaths[6] } });
await unlock(user, { query: { path: partialUnlockPaths[7] } });
unlock(user, { query: { path: unlockPath } });
await unlock(user, { query: { path: unlockPath } });
});
it('equips an item already owned', () => {
it('equips an item already owned', async () => {
expect(user.purchased.background.giant_florals).to.not.exist;
unlock(user, { query: { path: backgroundUnlockPath } });
await unlock(user, { query: { path: backgroundUnlockPath } });
const afterBalance = user.balance;
const response = unlock(user, { query: { path: backgroundUnlockPath } });
const response = await unlock(user, { query: { path: backgroundUnlockPath } });
expect(user.balance).to.equal(afterBalance); // do not bill twice
expect(response.message).to.not.exist;
expect(user.preferences.background).to.equal('giant_florals');
});
it('un-equips a background already equipped', () => {
it('un-equips a background already equipped', async () => {
expect(user.purchased.background.giant_florals).to.not.exist;
unlock(user, { query: { path: backgroundUnlockPath } }); // unlock
await unlock(user, { query: { path: backgroundUnlockPath } }); // unlock
const afterBalance = user.balance;
unlock(user, { query: { path: backgroundUnlockPath } }); // equip
const response = unlock(user, { query: { path: backgroundUnlockPath } });
await unlock(user, { query: { path: backgroundUnlockPath } }); // equip
const response = await unlock(user, { query: { path: backgroundUnlockPath } });
expect(user.balance).to.equal(afterBalance); // do not bill twice
expect(response.message).to.not.exist;
expect(user.preferences.background).to.equal('');
});
it('unlocks a full set of appearance items', () => {
it('unlocks a full set of appearance items', async () => {
const initialShirts = Object.keys(user.purchased.shirt).length;
const [, message] = unlock(user, { query: { path: unlockPath } });
const [, message] = await unlock(user, { query: { path: unlockPath } });
expect(message).to.equal(i18n.t('unlocked'));
const individualPaths = unlockPath.split(',');
@@ -208,11 +197,11 @@ describe('shared.ops.unlock', () => {
expect(user.balance).to.equal(usersStartingGems - 1.25);
});
it('unlocks a full set of hair items', () => {
it('unlocks a full set of hair items', async () => {
user.purchased.hair.color = {};
const initialHairColors = Object.keys(user.purchased.hair.color).length;
const [, message] = unlock(user, { query: { path: hairUnlockPath } });
const [, message] = await unlock(user, { query: { path: hairUnlockPath } });
expect(message).to.equal(i18n.t('unlocked'));
const individualPaths = hairUnlockPath.split(',');
@@ -224,13 +213,13 @@ describe('shared.ops.unlock', () => {
expect(user.balance).to.equal(usersStartingGems - 1.25);
});
it('unlocks the facial hair set', () => {
it('unlocks the facial hair set', async () => {
user.purchased.hair.mustache = {};
user.purchased.hair.beard = {};
const initialMustache = Object.keys(user.purchased.hair.mustache).length;
const initialBeard = Object.keys(user.purchased.hair.mustache).length;
const [, message] = unlock(user, { query: { path: facialHairUnlockPath } });
const [, message] = await unlock(user, { query: { path: facialHairUnlockPath } });
expect(message).to.equal(i18n.t('unlocked'));
const individualPaths = facialHairUnlockPath.split(',');
@@ -242,9 +231,9 @@ describe('shared.ops.unlock', () => {
expect(user.balance).to.equal(usersStartingGems - 1.25);
});
it('unlocks a full set of gear', () => {
it('unlocks a full set of gear', async () => {
const initialGear = Object.keys(user.items.gear.owned).length;
const [, message] = unlock(user, { query: { path: unlockGearSetPath } });
const [, message] = await unlock(user, { query: { path: unlockGearSetPath } });
expect(message).to.equal(i18n.t('unlocked'));
@@ -257,9 +246,9 @@ describe('shared.ops.unlock', () => {
expect(user.balance).to.equal(usersStartingGems - 1.25);
});
it('unlocks a full set of backgrounds', () => {
it('unlocks a full set of backgrounds', async () => {
const initialBackgrounds = Object.keys(user.purchased.background).length;
const [, message] = unlock(user, { query: { path: backgroundSetUnlockPath } });
const [, message] = await unlock(user, { query: { path: backgroundSetUnlockPath } });
expect(message).to.equal(i18n.t('unlocked'));
const individualPaths = backgroundSetUnlockPath.split(',');
@@ -271,10 +260,10 @@ describe('shared.ops.unlock', () => {
expect(user.balance).to.equal(usersStartingGems - 3.75);
});
it('unlocks an item (appearance)', () => {
it('unlocks an item (appearance)', async () => {
const path = unlockPath.split(',')[0];
const initialShirts = Object.keys(user.purchased.shirt).length;
const [, message] = unlock(user, { query: { path } });
const [, message] = await unlock(user, { query: { path } });
expect(message).to.equal(i18n.t('unlocked'));
expect(Object.keys(user.purchased.shirt).length).to.equal(initialShirts + 1);
@@ -282,12 +271,12 @@ describe('shared.ops.unlock', () => {
expect(user.balance).to.equal(usersStartingGems - 0.5);
});
it('unlocks an item (hair color)', () => {
it('unlocks an item (hair color)', async () => {
user.purchased.hair.color = {};
const path = hairUnlockPath.split(',')[0];
const initialColorHair = Object.keys(user.purchased.hair.color).length;
const [, message] = unlock(user, { query: { path } });
const [, message] = await unlock(user, { query: { path } });
expect(message).to.equal(i18n.t('unlocked'));
expect(Object.keys(user.purchased.hair.color).length).to.equal(initialColorHair + 1);
@@ -295,14 +284,14 @@ describe('shared.ops.unlock', () => {
expect(user.balance).to.equal(usersStartingGems - 0.5);
});
it('unlocks an item (facial hair)', () => {
it('unlocks an item (facial hair)', async () => {
user.purchased.hair.mustache = {};
user.purchased.hair.beard = {};
const path = facialHairUnlockPath.split(',')[0];
const initialMustache = Object.keys(user.purchased.hair.mustache).length;
const initialBeard = Object.keys(user.purchased.hair.beard).length;
const [, message] = unlock(user, { query: { path } });
const [, message] = await unlock(user, { query: { path } });
expect(message).to.equal(i18n.t('unlocked'));
@@ -313,10 +302,10 @@ describe('shared.ops.unlock', () => {
expect(user.balance).to.equal(usersStartingGems - 0.5);
});
it('unlocks an item (gear)', () => {
it('unlocks an item (gear)', async () => {
const path = unlockGearSetPath.split(',')[0];
const initialGear = Object.keys(user.items.gear.owned).length;
const [, message] = unlock(user, { query: { path } });
const [, message] = await unlock(user, { query: { path } });
expect(message).to.equal(i18n.t('unlocked'));
expect(Object.keys(user.items.gear.owned).length).to.equal(initialGear + 1);
@@ -324,9 +313,9 @@ describe('shared.ops.unlock', () => {
expect(user.balance).to.equal(usersStartingGems - 0.5);
});
it('unlocks an item (background)', () => {
it('unlocks an item (background)', async () => {
const initialBackgrounds = Object.keys(user.purchased.background).length;
const [, message] = unlock(user, { query: { path: backgroundUnlockPath } });
const [, message] = await unlock(user, { query: { path: backgroundUnlockPath } });
expect(message).to.equal(i18n.t('unlocked'));
expect(Object.keys(user.purchased.background).length).to.equal(initialBackgrounds + 1);
+200 -198
View File
@@ -4723,16 +4723,16 @@
"integrity": "sha512-T7VNNlYVM1SgQ+VsMYhnDkcGmWhQdL0bDyGm5TlQ3GBXnJscEClUUOKduWTmm2zCnvNLC1hc3JpuXjs/nFOc5w=="
},
"@storybook/addon-actions": {
"version": "6.4.14",
"resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-6.4.14.tgz",
"integrity": "sha512-EBraATDCKCbb1IpT+bTIV+noFIoK5ykXj8Nt0qmQGD2OC1cZovIyH3DigyD0/3D55znGzxqRruTK8lm0nc1jbg==",
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-6.4.17.tgz",
"integrity": "sha512-8TYdgzJMMKvfHvSp8N3Bsj78xGw9lNHTYkh0IE0TGGwRVOEU6xNBkao6ktXzM3gTB+6U6OZn8Y//NCzLsoTUHg==",
"requires": {
"@storybook/addons": "6.4.14",
"@storybook/api": "6.4.14",
"@storybook/components": "6.4.14",
"@storybook/core-events": "6.4.14",
"@storybook/addons": "6.4.17",
"@storybook/api": "6.4.17",
"@storybook/components": "6.4.17",
"@storybook/core-events": "6.4.17",
"@storybook/csf": "0.0.2--canary.87bc651.0",
"@storybook/theming": "6.4.14",
"@storybook/theming": "6.4.17",
"core-js": "^3.8.2",
"fast-deep-equal": "^3.1.3",
"global": "^4.4.0",
@@ -4857,17 +4857,17 @@
"integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA=="
},
"@storybook/addons": {
"version": "6.4.14",
"resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-6.4.14.tgz",
"integrity": "sha512-Snu42ejLyBAh6PWdlrdI72HKN1oKY7q0R9qEID2wk953WrqgGu4URakp14YLxghJCyKTSfGPs6LNZRRI6H5xgA==",
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-6.4.17.tgz",
"integrity": "sha512-C/hji0Bc7+tssGqaD0JYd/Pz0GM46xbRpdgHSVLInYdhJrb5a9IG6INCbcB8CXeReDKWJCLAaj2+z79Wa96bFQ==",
"requires": {
"@storybook/api": "6.4.14",
"@storybook/channels": "6.4.14",
"@storybook/client-logger": "6.4.14",
"@storybook/core-events": "6.4.14",
"@storybook/api": "6.4.17",
"@storybook/channels": "6.4.17",
"@storybook/client-logger": "6.4.17",
"@storybook/core-events": "6.4.17",
"@storybook/csf": "0.0.2--canary.87bc651.0",
"@storybook/router": "6.4.14",
"@storybook/theming": "6.4.14",
"@storybook/router": "6.4.17",
"@storybook/theming": "6.4.17",
"@types/webpack-env": "^1.16.0",
"core-js": "^3.8.2",
"global": "^4.4.0",
@@ -4875,17 +4875,17 @@
}
},
"@storybook/api": {
"version": "6.4.14",
"resolved": "https://registry.npmjs.org/@storybook/api/-/api-6.4.14.tgz",
"integrity": "sha512-GGGwB5+EquoausTXYx4dnLBBk2sOiS1Z58mDj0swBXCZdjfyUfLyxjxvvb/hl65ltufWP3IdmlKKaLiuARXNtw==",
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/api/-/api-6.4.17.tgz",
"integrity": "sha512-O0ssHVy40t4QD5CNdNESbJo7uZd86UWYrHCFjgeC2gmxrMgBD+ajO34N4HoQFC/F+/84om2/z8RYAGKu/WpoTA==",
"requires": {
"@storybook/channels": "6.4.14",
"@storybook/client-logger": "6.4.14",
"@storybook/core-events": "6.4.14",
"@storybook/channels": "6.4.17",
"@storybook/client-logger": "6.4.17",
"@storybook/core-events": "6.4.17",
"@storybook/csf": "0.0.2--canary.87bc651.0",
"@storybook/router": "6.4.14",
"@storybook/router": "6.4.17",
"@storybook/semver": "^7.3.2",
"@storybook/theming": "6.4.14",
"@storybook/theming": "6.4.17",
"core-js": "^3.8.2",
"fast-deep-equal": "^3.1.3",
"global": "^4.4.0",
@@ -4899,9 +4899,9 @@
}
},
"@storybook/channels": {
"version": "6.4.14",
"resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-6.4.14.tgz",
"integrity": "sha512-3QOVxFG6ZAxDXCta1ie4SUPQ3s50yHeuZzVg6uPp+DcC1FrXeDFYBcU9t0j/jrSgbeKcnFHWxmRHNy1BRyWv/A==",
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-6.4.17.tgz",
"integrity": "sha512-C6ON1olkkHc+FaDerkwL1yYGDL1xtFP+eMlm42ZaO06sIT9qv9EkJZ3GU/PNLTeXYMX4OsZl9kjz2whD4rN7gg==",
"requires": {
"core-js": "^3.8.2",
"ts-dedent": "^2.0.0",
@@ -4909,23 +4909,23 @@
}
},
"@storybook/client-logger": {
"version": "6.4.14",
"resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.4.14.tgz",
"integrity": "sha512-4VmFWZxhpeiG5fDhfqAyQbCfXZSBKS4fNKf35ABWiHStZRDndxml8K5WFtmOmMvVzjrGQx8HesenYMawK6xo/Q==",
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.4.17.tgz",
"integrity": "sha512-awKBTOWHXHBxAIl8a/Zy/BitIw49A+0RnhPGuf8aFAw2Ym/vKR4bI8lRHVPtlR6RIHFp5rC1g32HmCQfKE22Fw==",
"requires": {
"core-js": "^3.8.2",
"global": "^4.4.0"
}
},
"@storybook/components": {
"version": "6.4.14",
"resolved": "https://registry.npmjs.org/@storybook/components/-/components-6.4.14.tgz",
"integrity": "sha512-M7unerbOnvg+UN7qPxBCBWzK/boVdSSQxRiPAr1OL3M4OyEU8+TNPdQeAG0aF4zqtU0BrsDf4E85EznoMXUiFQ==",
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/components/-/components-6.4.17.tgz",
"integrity": "sha512-R6imELCWlHWQiprYMeeXLKgUQK4m698G/jvkc1xUxAThpTxwgROTcpw5qnJA0k+wltjGn4t6MBWKHhheGZc6Hg==",
"requires": {
"@popperjs/core": "^2.6.0",
"@storybook/client-logger": "6.4.14",
"@storybook/client-logger": "6.4.17",
"@storybook/csf": "0.0.2--canary.87bc651.0",
"@storybook/theming": "6.4.14",
"@storybook/theming": "6.4.17",
"@types/color-convert": "^2.0.0",
"@types/overlayscrollbars": "^1.12.0",
"@types/react-syntax-highlighter": "11.0.5",
@@ -4949,9 +4949,9 @@
}
},
"@storybook/core-events": {
"version": "6.4.14",
"resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.4.14.tgz",
"integrity": "sha512-9QFltg2mxTDjMBfmVtFHtrAEPY/i0oVp2kVdTWo6g05cPffYKAjNUnUVjUl7yiqcQmdEcdqUUQ0ut3xgmcYi/A==",
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.4.17.tgz",
"integrity": "sha512-k6wNjQLZZ8A/rt4gLz0M4ebTORKYYz2B9hZ3LvPJftNVqv+bTFAV4KVks6bBlvbJWpJ+eCPEyfeSP9Np2QIFMQ==",
"requires": {
"core-js": "^3.8.2"
}
@@ -4965,11 +4965,11 @@
}
},
"@storybook/router": {
"version": "6.4.14",
"resolved": "https://registry.npmjs.org/@storybook/router/-/router-6.4.14.tgz",
"integrity": "sha512-5+tePyINtwPYm4izgOBZ2sX2ViWtfmmO2vwOAPlWWEGzsRosVQsGMdZv1R8rk4Jl/TotMjlTmd8I1/BufEeIeQ==",
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/router/-/router-6.4.17.tgz",
"integrity": "sha512-GLhzth83BB2BbUkM/+ld2JITIbDQtzFLs/CnZZQKq6aR93Kou6VK2epHnIwrPyWbP6rsGavR/8L/UWeBdwwTrQ==",
"requires": {
"@storybook/client-logger": "6.4.14",
"@storybook/client-logger": "6.4.17",
"core-js": "^3.8.2",
"fast-deep-equal": "^3.1.3",
"global": "^4.4.0",
@@ -4983,14 +4983,14 @@
}
},
"@storybook/theming": {
"version": "6.4.14",
"resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-6.4.14.tgz",
"integrity": "sha512-kqmXNnIoOSAS4cgr9PitMgVrOps725O99eTsJNxB6J1Ide0CsA5v2tV6AmQn/scnpCQNr8uSjZerNlEcl/ensg==",
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-6.4.17.tgz",
"integrity": "sha512-7+U72/VdhoMb00q1URMzdTW3OYHJogro2i2hScgKR+ndL4/dtSmetJ/1z9PuoFxLxHgdLKcwMAV0fZAjEYlhCA==",
"requires": {
"@emotion/core": "^10.1.1",
"@emotion/is-prop-valid": "^0.8.6",
"@emotion/styled": "^10.0.27",
"@storybook/client-logger": "6.4.14",
"@storybook/client-logger": "6.4.17",
"core-js": "^3.8.2",
"deep-object-diff": "^1.1.0",
"emotion-theming": "^10.0.27",
@@ -5347,15 +5347,15 @@
}
},
"@storybook/addon-links": {
"version": "6.4.14",
"resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-6.4.14.tgz",
"integrity": "sha512-Y+5tdmAdkFzk0OC9wJnHdpVfhq3uqqlrAUFE3QYeof4uL6wLNSr2pl0BzCGQtnTfLs0i0bExXaTP5pZhwSnQoA==",
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-6.4.17.tgz",
"integrity": "sha512-ytGEe7sfOW10wwc0NIWSGtNgGM8ql8EOg7ZhrgXiRgQE0vD5NXRJi8FWzBdb06/G3cURYwveKR4Ea9mABZEaUw==",
"requires": {
"@storybook/addons": "6.4.14",
"@storybook/client-logger": "6.4.14",
"@storybook/core-events": "6.4.14",
"@storybook/addons": "6.4.17",
"@storybook/client-logger": "6.4.17",
"@storybook/core-events": "6.4.17",
"@storybook/csf": "0.0.2--canary.87bc651.0",
"@storybook/router": "6.4.14",
"@storybook/router": "6.4.17",
"@types/qs": "^6.9.5",
"core-js": "^3.8.2",
"global": "^4.4.0",
@@ -5475,17 +5475,17 @@
"integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA=="
},
"@storybook/addons": {
"version": "6.4.14",
"resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-6.4.14.tgz",
"integrity": "sha512-Snu42ejLyBAh6PWdlrdI72HKN1oKY7q0R9qEID2wk953WrqgGu4URakp14YLxghJCyKTSfGPs6LNZRRI6H5xgA==",
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-6.4.17.tgz",
"integrity": "sha512-C/hji0Bc7+tssGqaD0JYd/Pz0GM46xbRpdgHSVLInYdhJrb5a9IG6INCbcB8CXeReDKWJCLAaj2+z79Wa96bFQ==",
"requires": {
"@storybook/api": "6.4.14",
"@storybook/channels": "6.4.14",
"@storybook/client-logger": "6.4.14",
"@storybook/core-events": "6.4.14",
"@storybook/api": "6.4.17",
"@storybook/channels": "6.4.17",
"@storybook/client-logger": "6.4.17",
"@storybook/core-events": "6.4.17",
"@storybook/csf": "0.0.2--canary.87bc651.0",
"@storybook/router": "6.4.14",
"@storybook/theming": "6.4.14",
"@storybook/router": "6.4.17",
"@storybook/theming": "6.4.17",
"@types/webpack-env": "^1.16.0",
"core-js": "^3.8.2",
"global": "^4.4.0",
@@ -5493,17 +5493,17 @@
}
},
"@storybook/api": {
"version": "6.4.14",
"resolved": "https://registry.npmjs.org/@storybook/api/-/api-6.4.14.tgz",
"integrity": "sha512-GGGwB5+EquoausTXYx4dnLBBk2sOiS1Z58mDj0swBXCZdjfyUfLyxjxvvb/hl65ltufWP3IdmlKKaLiuARXNtw==",
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/api/-/api-6.4.17.tgz",
"integrity": "sha512-O0ssHVy40t4QD5CNdNESbJo7uZd86UWYrHCFjgeC2gmxrMgBD+ajO34N4HoQFC/F+/84om2/z8RYAGKu/WpoTA==",
"requires": {
"@storybook/channels": "6.4.14",
"@storybook/client-logger": "6.4.14",
"@storybook/core-events": "6.4.14",
"@storybook/channels": "6.4.17",
"@storybook/client-logger": "6.4.17",
"@storybook/core-events": "6.4.17",
"@storybook/csf": "0.0.2--canary.87bc651.0",
"@storybook/router": "6.4.14",
"@storybook/router": "6.4.17",
"@storybook/semver": "^7.3.2",
"@storybook/theming": "6.4.14",
"@storybook/theming": "6.4.17",
"core-js": "^3.8.2",
"fast-deep-equal": "^3.1.3",
"global": "^4.4.0",
@@ -5517,9 +5517,9 @@
}
},
"@storybook/channels": {
"version": "6.4.14",
"resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-6.4.14.tgz",
"integrity": "sha512-3QOVxFG6ZAxDXCta1ie4SUPQ3s50yHeuZzVg6uPp+DcC1FrXeDFYBcU9t0j/jrSgbeKcnFHWxmRHNy1BRyWv/A==",
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-6.4.17.tgz",
"integrity": "sha512-C6ON1olkkHc+FaDerkwL1yYGDL1xtFP+eMlm42ZaO06sIT9qv9EkJZ3GU/PNLTeXYMX4OsZl9kjz2whD4rN7gg==",
"requires": {
"core-js": "^3.8.2",
"ts-dedent": "^2.0.0",
@@ -5527,18 +5527,18 @@
}
},
"@storybook/client-logger": {
"version": "6.4.14",
"resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.4.14.tgz",
"integrity": "sha512-4VmFWZxhpeiG5fDhfqAyQbCfXZSBKS4fNKf35ABWiHStZRDndxml8K5WFtmOmMvVzjrGQx8HesenYMawK6xo/Q==",
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.4.17.tgz",
"integrity": "sha512-awKBTOWHXHBxAIl8a/Zy/BitIw49A+0RnhPGuf8aFAw2Ym/vKR4bI8lRHVPtlR6RIHFp5rC1g32HmCQfKE22Fw==",
"requires": {
"core-js": "^3.8.2",
"global": "^4.4.0"
}
},
"@storybook/core-events": {
"version": "6.4.14",
"resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.4.14.tgz",
"integrity": "sha512-9QFltg2mxTDjMBfmVtFHtrAEPY/i0oVp2kVdTWo6g05cPffYKAjNUnUVjUl7yiqcQmdEcdqUUQ0ut3xgmcYi/A==",
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.4.17.tgz",
"integrity": "sha512-k6wNjQLZZ8A/rt4gLz0M4ebTORKYYz2B9hZ3LvPJftNVqv+bTFAV4KVks6bBlvbJWpJ+eCPEyfeSP9Np2QIFMQ==",
"requires": {
"core-js": "^3.8.2"
}
@@ -5552,11 +5552,11 @@
}
},
"@storybook/router": {
"version": "6.4.14",
"resolved": "https://registry.npmjs.org/@storybook/router/-/router-6.4.14.tgz",
"integrity": "sha512-5+tePyINtwPYm4izgOBZ2sX2ViWtfmmO2vwOAPlWWEGzsRosVQsGMdZv1R8rk4Jl/TotMjlTmd8I1/BufEeIeQ==",
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/router/-/router-6.4.17.tgz",
"integrity": "sha512-GLhzth83BB2BbUkM/+ld2JITIbDQtzFLs/CnZZQKq6aR93Kou6VK2epHnIwrPyWbP6rsGavR/8L/UWeBdwwTrQ==",
"requires": {
"@storybook/client-logger": "6.4.14",
"@storybook/client-logger": "6.4.17",
"core-js": "^3.8.2",
"fast-deep-equal": "^3.1.3",
"global": "^4.4.0",
@@ -5570,14 +5570,14 @@
}
},
"@storybook/theming": {
"version": "6.4.14",
"resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-6.4.14.tgz",
"integrity": "sha512-kqmXNnIoOSAS4cgr9PitMgVrOps725O99eTsJNxB6J1Ide0CsA5v2tV6AmQn/scnpCQNr8uSjZerNlEcl/ensg==",
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-6.4.17.tgz",
"integrity": "sha512-7+U72/VdhoMb00q1URMzdTW3OYHJogro2i2hScgKR+ndL4/dtSmetJ/1z9PuoFxLxHgdLKcwMAV0fZAjEYlhCA==",
"requires": {
"@emotion/core": "^10.1.1",
"@emotion/is-prop-valid": "^0.8.6",
"@emotion/styled": "^10.0.27",
"@storybook/client-logger": "6.4.14",
"@storybook/client-logger": "6.4.17",
"core-js": "^3.8.2",
"deep-object-diff": "^1.1.0",
"emotion-theming": "^10.0.27",
@@ -5881,17 +5881,17 @@
}
},
"@storybook/addons": {
"version": "6.4.14",
"resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-6.4.14.tgz",
"integrity": "sha512-Snu42ejLyBAh6PWdlrdI72HKN1oKY7q0R9qEID2wk953WrqgGu4URakp14YLxghJCyKTSfGPs6LNZRRI6H5xgA==",
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-6.4.17.tgz",
"integrity": "sha512-C/hji0Bc7+tssGqaD0JYd/Pz0GM46xbRpdgHSVLInYdhJrb5a9IG6INCbcB8CXeReDKWJCLAaj2+z79Wa96bFQ==",
"requires": {
"@storybook/api": "6.4.14",
"@storybook/channels": "6.4.14",
"@storybook/client-logger": "6.4.14",
"@storybook/core-events": "6.4.14",
"@storybook/api": "6.4.17",
"@storybook/channels": "6.4.17",
"@storybook/client-logger": "6.4.17",
"@storybook/core-events": "6.4.17",
"@storybook/csf": "0.0.2--canary.87bc651.0",
"@storybook/router": "6.4.14",
"@storybook/theming": "6.4.14",
"@storybook/router": "6.4.17",
"@storybook/theming": "6.4.17",
"@types/webpack-env": "^1.16.0",
"core-js": "^3.8.2",
"global": "^4.4.0",
@@ -6008,17 +6008,17 @@
"integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA=="
},
"@storybook/api": {
"version": "6.4.14",
"resolved": "https://registry.npmjs.org/@storybook/api/-/api-6.4.14.tgz",
"integrity": "sha512-GGGwB5+EquoausTXYx4dnLBBk2sOiS1Z58mDj0swBXCZdjfyUfLyxjxvvb/hl65ltufWP3IdmlKKaLiuARXNtw==",
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/api/-/api-6.4.17.tgz",
"integrity": "sha512-O0ssHVy40t4QD5CNdNESbJo7uZd86UWYrHCFjgeC2gmxrMgBD+ajO34N4HoQFC/F+/84om2/z8RYAGKu/WpoTA==",
"requires": {
"@storybook/channels": "6.4.14",
"@storybook/client-logger": "6.4.14",
"@storybook/core-events": "6.4.14",
"@storybook/channels": "6.4.17",
"@storybook/client-logger": "6.4.17",
"@storybook/core-events": "6.4.17",
"@storybook/csf": "0.0.2--canary.87bc651.0",
"@storybook/router": "6.4.14",
"@storybook/router": "6.4.17",
"@storybook/semver": "^7.3.2",
"@storybook/theming": "6.4.14",
"@storybook/theming": "6.4.17",
"core-js": "^3.8.2",
"fast-deep-equal": "^3.1.3",
"global": "^4.4.0",
@@ -6032,9 +6032,9 @@
}
},
"@storybook/channels": {
"version": "6.4.14",
"resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-6.4.14.tgz",
"integrity": "sha512-3QOVxFG6ZAxDXCta1ie4SUPQ3s50yHeuZzVg6uPp+DcC1FrXeDFYBcU9t0j/jrSgbeKcnFHWxmRHNy1BRyWv/A==",
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-6.4.17.tgz",
"integrity": "sha512-C6ON1olkkHc+FaDerkwL1yYGDL1xtFP+eMlm42ZaO06sIT9qv9EkJZ3GU/PNLTeXYMX4OsZl9kjz2whD4rN7gg==",
"requires": {
"core-js": "^3.8.2",
"ts-dedent": "^2.0.0",
@@ -6042,18 +6042,18 @@
}
},
"@storybook/client-logger": {
"version": "6.4.14",
"resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.4.14.tgz",
"integrity": "sha512-4VmFWZxhpeiG5fDhfqAyQbCfXZSBKS4fNKf35ABWiHStZRDndxml8K5WFtmOmMvVzjrGQx8HesenYMawK6xo/Q==",
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.4.17.tgz",
"integrity": "sha512-awKBTOWHXHBxAIl8a/Zy/BitIw49A+0RnhPGuf8aFAw2Ym/vKR4bI8lRHVPtlR6RIHFp5rC1g32HmCQfKE22Fw==",
"requires": {
"core-js": "^3.8.2",
"global": "^4.4.0"
}
},
"@storybook/core-events": {
"version": "6.4.14",
"resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.4.14.tgz",
"integrity": "sha512-9QFltg2mxTDjMBfmVtFHtrAEPY/i0oVp2kVdTWo6g05cPffYKAjNUnUVjUl7yiqcQmdEcdqUUQ0ut3xgmcYi/A==",
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.4.17.tgz",
"integrity": "sha512-k6wNjQLZZ8A/rt4gLz0M4ebTORKYYz2B9hZ3LvPJftNVqv+bTFAV4KVks6bBlvbJWpJ+eCPEyfeSP9Np2QIFMQ==",
"requires": {
"core-js": "^3.8.2"
}
@@ -6067,11 +6067,11 @@
}
},
"@storybook/router": {
"version": "6.4.14",
"resolved": "https://registry.npmjs.org/@storybook/router/-/router-6.4.14.tgz",
"integrity": "sha512-5+tePyINtwPYm4izgOBZ2sX2ViWtfmmO2vwOAPlWWEGzsRosVQsGMdZv1R8rk4Jl/TotMjlTmd8I1/BufEeIeQ==",
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/router/-/router-6.4.17.tgz",
"integrity": "sha512-GLhzth83BB2BbUkM/+ld2JITIbDQtzFLs/CnZZQKq6aR93Kou6VK2epHnIwrPyWbP6rsGavR/8L/UWeBdwwTrQ==",
"requires": {
"@storybook/client-logger": "6.4.14",
"@storybook/client-logger": "6.4.17",
"core-js": "^3.8.2",
"fast-deep-equal": "^3.1.3",
"global": "^4.4.0",
@@ -6085,14 +6085,14 @@
}
},
"@storybook/theming": {
"version": "6.4.14",
"resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-6.4.14.tgz",
"integrity": "sha512-kqmXNnIoOSAS4cgr9PitMgVrOps725O99eTsJNxB6J1Ide0CsA5v2tV6AmQn/scnpCQNr8uSjZerNlEcl/ensg==",
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-6.4.17.tgz",
"integrity": "sha512-7+U72/VdhoMb00q1URMzdTW3OYHJogro2i2hScgKR+ndL4/dtSmetJ/1z9PuoFxLxHgdLKcwMAV0fZAjEYlhCA==",
"requires": {
"@emotion/core": "^10.1.1",
"@emotion/is-prop-valid": "^0.8.6",
"@emotion/styled": "^10.0.27",
"@storybook/client-logger": "6.4.14",
"@storybook/client-logger": "6.4.17",
"core-js": "^3.8.2",
"deep-object-diff": "^1.1.0",
"emotion-theming": "^10.0.27",
@@ -13072,11 +13072,34 @@
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"emojis-list": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
"integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
"optional": true
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"optional": true
},
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
},
"loader-utils": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
"integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
"optional": true,
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^2.1.2"
}
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
@@ -13113,6 +13136,38 @@
"ansi-regex": "^5.0.1"
}
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"optional": true,
"requires": {
"has-flag": "^4.0.0"
}
},
"vue-loader-v16": {
"version": "npm:vue-loader@16.8.3",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.8.3.tgz",
"integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
"optional": true,
"requires": {
"chalk": "^4.1.0",
"hash-sum": "^2.0.0",
"loader-utils": "^2.0.0"
},
"dependencies": {
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"optional": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
}
}
},
"wrap-ansi": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
@@ -13599,9 +13654,9 @@
"integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM="
},
"amplitude-js": {
"version": "8.16.0",
"resolved": "https://registry.npmjs.org/amplitude-js/-/amplitude-js-8.16.0.tgz",
"integrity": "sha512-PtHuYphktZsCf2BRSbb0EMuClQjHP2kSTDz2QBy6cv18yRvqVs3I2MB386BfeOxgxR16J/OlfFVBWhv9CX2rYw==",
"version": "8.16.1",
"resolved": "https://registry.npmjs.org/amplitude-js/-/amplitude-js-8.16.1.tgz",
"integrity": "sha512-1X9xvxmWIK1DlVluuk2QXziYcgSiZE4d4DLhMzY9yUP+KauCbFy37lW4m3dixp6Y8AIGU+WUAfAsCLqXYlF0rw==",
"requires": {
"@amplitude/ua-parser-js": "0.7.26",
"@amplitude/utils": "^1.0.5",
@@ -15588,14 +15643,15 @@
"integrity": "sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg=="
},
"chai": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/chai/-/chai-4.3.4.tgz",
"integrity": "sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==",
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz",
"integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==",
"requires": {
"assertion-error": "^1.1.0",
"check-error": "^1.0.2",
"deep-eql": "^3.0.1",
"get-func-name": "^2.0.0",
"loupe": "^2.3.1",
"pathval": "^1.1.1",
"type-detect": "^4.0.5"
}
@@ -21729,6 +21785,14 @@
"js-tokens": "^3.0.0 || ^4.0.0"
}
},
"loupe": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.1.tgz",
"integrity": "sha512-EN1D3jyVmaX4tnajVlfbREU4axL647hLec1h/PXAb8CPDMJiYitcWF2UeLVNttRqaIqQs4x+mRvXf+d+TlDrCA==",
"requires": {
"get-func-name": "^2.0.0"
}
},
"lower-case": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz",
@@ -22537,6 +22601,14 @@
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
},
"moment-timezone": {
"version": "0.5.34",
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.34.tgz",
"integrity": "sha512-3zAEHh2hKUs3EXLESx/wsgw6IQdusOT8Bxm3D9UrHPQR7zlMmzwybC8zHEM1tQ4LJwP7fcxrWr8tuBg05fFCbg==",
"requires": {
"moment": ">= 2.9.0"
}
},
"move-concurrently": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
@@ -29183,76 +29255,6 @@
}
}
},
"vue-loader-v16": {
"version": "npm:vue-loader@16.8.3",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.8.3.tgz",
"integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
"requires": {
"chalk": "^4.1.0",
"hash-sum": "^2.0.0",
"loader-utils": "^2.0.0"
},
"dependencies": {
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"requires": {
"color-convert": "^2.0.1"
}
},
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"emojis-list": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
"integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q=="
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
},
"loader-utils": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
"integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^2.1.2"
}
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"requires": {
"has-flag": "^4.0.0"
}
}
}
},
"vue-mugen-scroll": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/vue-mugen-scroll/-/vue-mugen-scroll-0.2.6.tgz",
+6 -5
View File
@@ -13,11 +13,11 @@
"storybook:serve": "vue-cli-service storybook:serve -p 6006 -c config/storybook"
},
"dependencies": {
"@storybook/addons": "6.4.14",
"@storybook/addon-actions": "6.4.14",
"@storybook/addon-actions": "6.4.17",
"@storybook/addon-knobs": "6.2.9",
"@storybook/addon-links": "6.4.14",
"@storybook/addon-links": "6.4.17",
"@storybook/addon-notes": "5.3.21",
"@storybook/addons": "6.4.17",
"@storybook/vue": "6.3.13",
"@vue/cli-plugin-babel": "^4.5.15",
"@vue/cli-plugin-eslint": "^4.5.15",
@@ -25,13 +25,13 @@
"@vue/cli-plugin-unit-mocha": "^4.5.15",
"@vue/cli-service": "^4.5.15",
"@vue/test-utils": "1.0.0-beta.29",
"amplitude-js": "^8.16.0",
"amplitude-js": "^8.16.1",
"axios": "^0.25.0",
"axios-progress-bar": "^1.2.0",
"babel-eslint": "^10.1.0",
"bootstrap": "^4.6.0",
"bootstrap-vue": "^2.21.2",
"chai": "^4.3.4",
"chai": "^4.3.6",
"core-js": "^3.20.3",
"eslint": "^6.8.0",
"eslint-config-habitrpg": "^6.2.0",
@@ -44,6 +44,7 @@
"jquery": "^3.6.0",
"lodash": "^4.17.21",
"moment": "^2.29.1",
"moment-timezone": "^0.5.34",
"nconf": "^0.11.3",
"sass": "^1.34.0",
"sass-loader": "^8.0.2",
-1
View File
@@ -530,6 +530,5 @@ export default {
<style src="intro.js/minified/introjs.min.css"></style>
<style src="axios-progress-bar/dist/nprogress.css"></style>
<style src="@/assets/scss/index.scss" lang="scss"></style>
<style src="@/assets/css/sprites/spritesmith-largeSprites-0.css"></style>
<style src="@/assets/scss/sprites.scss" lang="scss"></style>
<style src="smartbanner.js/dist/smartbanner.min.css"></style>
@@ -1,84 +0,0 @@
.promo_armoire_backgrounds_202010 {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -639px;
width: 423px;
height: 147px;
}
.promo_fall_customizations {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -532px 0px;
width: 336px;
height: 207px;
}
.promo_fall_festival_2019 {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -449px;
width: 360px;
height: 189px;
}
.promo_fall_festival_2020 {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -361px -449px;
width: 360px;
height: 174px;
}
.promo_mystery_202009 {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -869px -296px;
width: 282px;
height: 147px;
}
.promo_mystery_202010 {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -869px -444px;
width: 282px;
height: 147px;
}
.promo_sandy_sidekicks_bundle {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -869px -148px;
width: 420px;
height: 147px;
}
.promo_skeleton_achievements {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -244px;
width: 366px;
height: 204px;
}
.promo_spooky_sparkles {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -424px -639px;
width: 423px;
height: 147px;
}
.promo_take_this {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -1152px -296px;
width: 96px;
height: 69px;
}
.promo_vampire_potions {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -869px 0px;
width: 423px;
height: 147px;
}
.scene_positivity {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px 0px;
width: 531px;
height: 243px;
}
.scene_squall {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -532px -208px;
width: 141px;
height: 169px;
}
.scene_strength {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -869px -592px;
width: 192px;
height: 129px;
}
File diff suppressed because it is too large Load Diff
@@ -1,816 +0,0 @@
.background_halflings_house {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: 0px 0px;
width: 141px;
height: 147px;
}
.background_hall_of_heroes {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -142px 0px;
width: 141px;
height: 147px;
}
.background_harvest_feast {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -284px 0px;
width: 141px;
height: 147px;
}
.background_harvest_fields {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: 0px -148px;
width: 141px;
height: 147px;
}
.background_harvest_moon {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -142px -148px;
width: 141px;
height: 147px;
}
.background_haunted_forest {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -284px -148px;
width: 141px;
height: 147px;
}
.background_haunted_house {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -426px 0px;
width: 141px;
height: 147px;
}
.background_haunted_photo {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -426px -148px;
width: 141px;
height: 147px;
}
.background_heart_shaped_bubbles {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: 0px -296px;
width: 141px;
height: 147px;
}
.background_heather_field {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -142px -296px;
width: 141px;
height: 147px;
}
.background_herding_sheep_in_autumn {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -284px -296px;
width: 141px;
height: 147px;
}
.background_holiday_hearth {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -426px -296px;
width: 141px;
height: 147px;
}
.background_holiday_market {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -568px 0px;
width: 141px;
height: 147px;
}
.background_holiday_wreath {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -568px -148px;
width: 141px;
height: 147px;
}
.background_hot_air_balloon {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -568px -296px;
width: 141px;
height: 147px;
}
.background_hot_spring {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: 0px -444px;
width: 141px;
height: 147px;
}
.background_ice_cave {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -142px -444px;
width: 141px;
height: 147px;
}
.background_ice_palace {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -284px -444px;
width: 141px;
height: 147px;
}
.background_iceberg {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -426px -444px;
width: 141px;
height: 147px;
}
.background_icicle_bridge {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -568px -444px;
width: 141px;
height: 147px;
}
.background_idyllic_cabin {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -710px 0px;
width: 141px;
height: 147px;
}
.background_in_a_classroom {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -710px -148px;
width: 141px;
height: 147px;
}
.background_in_an_ancient_tomb {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -710px -296px;
width: 141px;
height: 147px;
}
.background_in_the_armory {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -710px -444px;
width: 141px;
height: 147px;
}
.background_inside_a_potion_bottle {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: 0px -592px;
width: 141px;
height: 147px;
}
.background_inside_an_ornament {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -142px -592px;
width: 141px;
height: 147px;
}
.background_island_waterfalls {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -284px -592px;
width: 141px;
height: 147px;
}
.background_jungle_canopy {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -426px -592px;
width: 141px;
height: 147px;
}
.background_kelp_forest {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -568px -592px;
width: 141px;
height: 147px;
}
.background_lake_with_floating_lanterns {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -710px -592px;
width: 141px;
height: 147px;
}
.background_lighthouse_shore {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -852px 0px;
width: 141px;
height: 147px;
}
.background_lilypad {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -852px -148px;
width: 141px;
height: 147px;
}
.background_magic_beanstalk {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -852px -296px;
width: 141px;
height: 147px;
}
.background_magical_candles {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -852px -444px;
width: 141px;
height: 147px;
}
.background_magical_museum {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -852px -592px;
width: 141px;
height: 147px;
}
.background_marble_temple {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: 0px -740px;
width: 141px;
height: 147px;
}
.background_market {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -142px -740px;
width: 141px;
height: 147px;
}
.background_meandering_cave {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -284px -740px;
width: 141px;
height: 147px;
}
.background_medieval_kitchen {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -426px -740px;
width: 141px;
height: 147px;
}
.background_meteor_shower {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -568px -740px;
width: 141px;
height: 147px;
}
.background_midnight_castle {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -710px -740px;
width: 141px;
height: 147px;
}
.background_midnight_clouds {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -852px -740px;
width: 141px;
height: 147px;
}
.background_midnight_lake {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -994px 0px;
width: 141px;
height: 147px;
}
.background_mist_shrouded_mountain {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -994px -148px;
width: 141px;
height: 147px;
}
.background_mistiflying_circus {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -994px -296px;
width: 141px;
height: 147px;
}
.background_monster_makers_workshop {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -994px -444px;
width: 141px;
height: 147px;
}
.background_mountain_lake {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -994px -592px;
width: 141px;
height: 147px;
}
.background_mountain_pyramid {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -994px -740px;
width: 141px;
height: 147px;
}
.background_mystical_observatory {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: 0px -888px;
width: 141px;
height: 147px;
}
.background_night_dunes {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -142px -888px;
width: 141px;
height: 147px;
}
.background_ocean_sunrise {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -284px -888px;
width: 141px;
height: 147px;
}
.background_old_fashioned_bakery {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -426px -888px;
width: 141px;
height: 147px;
}
.background_on_tree_branch {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -568px -888px;
width: 141px;
height: 147px;
}
.background_open_waters {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -710px -888px;
width: 141px;
height: 147px;
}
.background_orchard {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -852px -888px;
width: 141px;
height: 147px;
}
.background_pagodas {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -994px -888px;
width: 141px;
height: 147px;
}
.background_palm_tree_with_fairy_lights {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1136px 0px;
width: 141px;
height: 147px;
}
.background_park_with_statue {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1136px -148px;
width: 141px;
height: 147px;
}
.background_pirate_flag {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1136px -296px;
width: 141px;
height: 147px;
}
.background_pixelists_workshop {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1136px -444px;
width: 141px;
height: 147px;
}
.background_potion_shop {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1136px -592px;
width: 141px;
height: 147px;
}
.background_productivity_plaza {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1136px -740px;
width: 141px;
height: 147px;
}
.background_pumpkin_carriage {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1136px -888px;
width: 141px;
height: 147px;
}
.background_pumpkin_patch {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: 0px -1036px;
width: 141px;
height: 147px;
}
.background_purple {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -142px -1036px;
width: 141px;
height: 147px;
}
.background_pyramids {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -284px -1036px;
width: 141px;
height: 147px;
}
.background_raging_river {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -426px -1036px;
width: 141px;
height: 147px;
}
.background_rainbow_meadow {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -568px -1036px;
width: 141px;
height: 147px;
}
.background_rainbows_end {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -710px -1036px;
width: 141px;
height: 147px;
}
.background_rainforest {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -852px -1036px;
width: 141px;
height: 147px;
}
.background_rainy_barnyard {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -994px -1036px;
width: 141px;
height: 147px;
}
.background_rainy_city {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1136px -1036px;
width: 141px;
height: 147px;
}
.background_red {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1278px 0px;
width: 141px;
height: 147px;
}
.background_relaxation_river {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1278px -148px;
width: 141px;
height: 147px;
}
.background_resting_in_the_inn {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1278px -296px;
width: 141px;
height: 147px;
}
.background_river_of_lava {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1278px -444px;
width: 141px;
height: 147px;
}
.background_rolling_hills {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1278px -592px;
width: 141px;
height: 147px;
}
.background_rope_bridge {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1278px -740px;
width: 141px;
height: 147px;
}
.background_rose_garden {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1278px -888px;
width: 141px;
height: 147px;
}
.background_rowboat {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1278px -1036px;
width: 141px;
height: 147px;
}
.background_salt_lake {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: 0px -1184px;
width: 141px;
height: 147px;
}
.background_sandcastle {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -142px -1184px;
width: 141px;
height: 147px;
}
.background_school_of_fish {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -284px -1184px;
width: 141px;
height: 147px;
}
.background_scribes_workshop {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -426px -1184px;
width: 141px;
height: 147px;
}
.background_seafarer_ship {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -568px -1184px;
width: 141px;
height: 147px;
}
.background_seaside_cliffs {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -710px -1184px;
width: 141px;
height: 147px;
}
.background_shimmering_ice_prism {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -852px -1184px;
width: 141px;
height: 147px;
}
.background_shimmery_bubbles {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -994px -1184px;
width: 141px;
height: 147px;
}
.background_slimy_swamp {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1136px -1184px;
width: 141px;
height: 147px;
}
.background_snowglobe {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1278px -1184px;
width: 141px;
height: 147px;
}
.background_snowman_army {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1420px 0px;
width: 141px;
height: 147px;
}
.background_snowy_day_fireplace {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1420px -148px;
width: 141px;
height: 147px;
}
.background_snowy_farm {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1420px -296px;
width: 141px;
height: 147px;
}
.background_snowy_pines {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1420px -444px;
width: 141px;
height: 147px;
}
.background_snowy_sunrise {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1420px -592px;
width: 141px;
height: 147px;
}
.background_south_pole {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1420px -740px;
width: 141px;
height: 147px;
}
.background_sparkling_snowflake {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1420px -888px;
width: 141px;
height: 147px;
}
.background_spider_web {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1420px -1036px;
width: 141px;
height: 147px;
}
.background_spiral_staircase {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1420px -1184px;
width: 141px;
height: 147px;
}
.background_splash_in_a_puddle {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: 0px -1332px;
width: 141px;
height: 147px;
}
.background_spooky_hotel {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -142px -1332px;
width: 141px;
height: 147px;
}
.background_spooky_scarecrow_field {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -284px -1332px;
width: 141px;
height: 147px;
}
.background_spring_rain {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -426px -1332px;
width: 141px;
height: 147px;
}
.background_spring_thaw {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -568px -1332px;
width: 141px;
height: 147px;
}
.background_stable {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -710px -1332px;
width: 141px;
height: 147px;
}
.background_stained_glass {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -852px -1332px;
width: 141px;
height: 147px;
}
.background_starry_skies {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -994px -1332px;
width: 141px;
height: 147px;
}
.background_starry_winter_night {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1136px -1332px;
width: 141px;
height: 147px;
}
.background_stoikalm_volcanoes {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1278px -1332px;
width: 141px;
height: 147px;
}
.background_stone_circle {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1420px -1332px;
width: 141px;
height: 147px;
}
.background_stone_tower {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1562px 0px;
width: 141px;
height: 147px;
}
.background_stormy_rooftops {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1562px -148px;
width: 141px;
height: 147px;
}
.background_stormy_ship {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1562px -296px;
width: 141px;
height: 147px;
}
.background_strange_sewers {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1562px -444px;
width: 141px;
height: 147px;
}
.background_strawberry_patch {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1562px -592px;
width: 141px;
height: 147px;
}
.background_succulent_garden {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1562px -740px;
width: 141px;
height: 147px;
}
.background_summer_fireworks {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1562px -888px;
width: 141px;
height: 147px;
}
.background_sunken_ship {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1562px -1036px;
width: 141px;
height: 147px;
}
.background_sunset_meadow {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1562px -1184px;
width: 141px;
height: 147px;
}
.background_sunset_oasis {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1562px -1332px;
width: 141px;
height: 147px;
}
.background_sunset_savannah {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: 0px -1480px;
width: 141px;
height: 147px;
}
.background_swarming_darkness {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -142px -1480px;
width: 141px;
height: 147px;
}
.background_swimming_among_jellyfish {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -284px -1480px;
width: 141px;
height: 147px;
}
.background_tar_pits {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -426px -1480px;
width: 141px;
height: 147px;
}
.background_tavern {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -568px -1480px;
width: 141px;
height: 147px;
}
.background_tea_party {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -710px -1480px;
width: 141px;
height: 147px;
}
.background_terraced_rice_field {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -852px -1480px;
width: 141px;
height: 147px;
}
.background_throne_room {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -994px -1480px;
width: 141px;
height: 147px;
}
.background_thunderstorm {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1136px -1480px;
width: 141px;
height: 147px;
}
.background_tide_pool {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1278px -1480px;
width: 141px;
height: 147px;
}
.background_tornado {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1420px -1480px;
width: 141px;
height: 147px;
}
.background_toymakers_workshop {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1562px -1480px;
width: 141px;
height: 147px;
}
.background_training_grounds {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1704px 0px;
width: 141px;
height: 147px;
}
.background_treasure_room {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1704px -148px;
width: 141px;
height: 147px;
}
.background_tree_roots {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1704px -296px;
width: 141px;
height: 147px;
}
.background_treehouse {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1704px -444px;
width: 141px;
height: 147px;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,396 +0,0 @@
.quest_alligator {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1322px -1112px;
width: 201px;
height: 213px;
}
.quest_amber {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -220px 0px;
width: 219px;
height: 219px;
}
.quest_armadillo {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -440px 0px;
width: 219px;
height: 219px;
}
.quest_atom1 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1082px -1332px;
width: 250px;
height: 150px;
}
.quest_atom2 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -642px -1534px;
width: 207px;
height: 138px;
}
.quest_atom3 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -211px -1534px;
width: 216px;
height: 180px;
}
.quest_axolotl {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: 0px -232px;
width: 219px;
height: 219px;
}
.quest_badger {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -220px -232px;
width: 219px;
height: 219px;
}
.quest_basilist {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -191px -1721px;
width: 189px;
height: 141px;
}
.quest_beetle {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: 0px -1332px;
width: 204px;
height: 201px;
}
.quest_blackPearl {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1540px 0px;
width: 216px;
height: 216px;
}
.quest_bronze {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -440px -232px;
width: 219px;
height: 219px;
}
.quest_bunny {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: 0px -1534px;
width: 210px;
height: 186px;
}
.quest_butterfly {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -660px 0px;
width: 219px;
height: 219px;
}
.quest_cheetah {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -660px -220px;
width: 219px;
height: 219px;
}
.quest_cow {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1757px 0px;
width: 174px;
height: 213px;
}
.quest_dilatory {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -220px -452px;
width: 219px;
height: 219px;
}
.quest_dilatoryDistress1 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1540px -1085px;
width: 210px;
height: 210px;
}
.quest_dilatoryDistress2 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1757px -422px;
width: 150px;
height: 150px;
}
.quest_dilatoryDistress3 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -440px -452px;
width: 219px;
height: 219px;
}
.quest_dilatory_derby {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: 0px -452px;
width: 219px;
height: 219px;
}
.quest_dolphin {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -660px -452px;
width: 219px;
height: 219px;
}
.quest_dustbunnies {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -880px 0px;
width: 219px;
height: 219px;
}
.quest_egg {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1757px -214px;
width: 165px;
height: 207px;
}
.quest_evilsanta {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1757px -724px;
width: 118px;
height: 131px;
}
.quest_evilsanta2 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -880px -220px;
width: 219px;
height: 219px;
}
.quest_falcon {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -880px -440px;
width: 219px;
height: 219px;
}
.quest_ferret {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: 0px -672px;
width: 219px;
height: 219px;
}
.quest_fluorite {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -220px -672px;
width: 219px;
height: 219px;
}
.quest_frog {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1100px -1112px;
width: 221px;
height: 213px;
}
.quest_ghost_stag {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -440px -672px;
width: 219px;
height: 219px;
}
.quest_goldenknight1 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -660px -672px;
width: 219px;
height: 219px;
}
.quest_goldenknight2 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1333px -1332px;
width: 250px;
height: 150px;
}
.quest_goldenknight3 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: 0px 0px;
width: 219px;
height: 231px;
}
.quest_gryphon {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -648px -1332px;
width: 216px;
height: 177px;
}
.quest_guineapig {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -880px -672px;
width: 219px;
height: 219px;
}
.quest_harpy {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1100px 0px;
width: 219px;
height: 219px;
}
.quest_hedgehog {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -205px -1332px;
width: 219px;
height: 186px;
}
.quest_hippo {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1100px -220px;
width: 219px;
height: 219px;
}
.quest_horse {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1100px -440px;
width: 219px;
height: 219px;
}
.quest_kangaroo {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1100px -660px;
width: 219px;
height: 219px;
}
.quest_kraken {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -865px -1332px;
width: 216px;
height: 177px;
}
.quest_lostMasterclasser1 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: 0px -892px;
width: 219px;
height: 219px;
}
.quest_lostMasterclasser2 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -220px -892px;
width: 219px;
height: 219px;
}
.quest_lostMasterclasser3 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -440px -892px;
width: 219px;
height: 219px;
}
.quest_mayhemMistiflying1 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1757px -573px;
width: 150px;
height: 150px;
}
.quest_mayhemMistiflying2 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -660px -892px;
width: 219px;
height: 219px;
}
.quest_mayhemMistiflying3 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -880px -892px;
width: 219px;
height: 219px;
}
.quest_monkey {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1100px -892px;
width: 219px;
height: 219px;
}
.quest_moon1 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1540px -217px;
width: 216px;
height: 216px;
}
.quest_moon2 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1320px 0px;
width: 219px;
height: 219px;
}
.quest_moon3 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1320px -220px;
width: 219px;
height: 219px;
}
.quest_moonstone1 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1320px -440px;
width: 219px;
height: 219px;
}
.quest_moonstone2 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1320px -660px;
width: 219px;
height: 219px;
}
.quest_moonstone3 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1320px -880px;
width: 219px;
height: 219px;
}
.quest_nudibranch {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1540px -434px;
width: 216px;
height: 216px;
}
.quest_octopus {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -425px -1332px;
width: 222px;
height: 177px;
}
.quest_onyx {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: 0px -1112px;
width: 219px;
height: 219px;
}
.quest_owl {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -220px -1112px;
width: 219px;
height: 219px;
}
.quest_peacock {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1540px -651px;
width: 216px;
height: 216px;
}
.quest_penguin {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: 0px -1721px;
width: 190px;
height: 183px;
}
.quest_pterodactyl {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -440px -1112px;
width: 219px;
height: 219px;
}
.quest_rat {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -660px -1112px;
width: 219px;
height: 219px;
}
.quest_robot {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -880px -1112px;
width: 219px;
height: 219px;
}
.quest_rock {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1540px -868px;
width: 216px;
height: 216px;
}
.quest_rooster {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -428px -1534px;
width: 213px;
height: 174px;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 465 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 464 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 390 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 331 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 597 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

+1 -3
View File
@@ -1,5 +1,3 @@
@import url("../css/sprites.css");
@import url("../css/sprites/spritesmith-main.css");
@for $i from 0 through 31 {
@import url("../css/sprites/spritesmith-main-#{$i}.css");
}
@@ -26,7 +26,7 @@
<!-- eslint-enable vue/no-use-v-if-with-v-for -->
<customize-options
:items="set.options"
:current-value="user.preferences.skin"
:current-value="user.preferences.hair.color"
:full-set="!hideSet(set) && !userOwnsSet('hair', set.keys, 'color')"
@unlock="unlock(`hair.color.${set.keys.join(',hair.color.')}`)"
/>
+257 -189
View File
@@ -1,205 +1,231 @@
<template>
<div class="row standard-page">
<small
class="muted"
v-html="$t('blurbHallContributors')"
></small>
<div class="well">
<div v-if="user.contributor.admin">
<h2>Reward User</h2>
<div class="row">
<div>
<div class="row standard-page">
<small
class="muted"
v-html="$t('blurbHallContributors')"
></small>
</div>
<div class="row standard-page">
<div>
<div v-if="user.contributor.admin">
<h2>Reward User</h2>
<div
v-if="!hero.profile"
class="form col-6"
class="row"
>
<div class="form-group">
<input
v-model="heroID"
class="form-control"
type="text"
:placeholder="'User ID or Username'"
>
</div>
<div class="form-group">
<button
class="btn btn-secondary"
@click="loadHero(heroID)"
>
Load User
</button>
<div class="form col-6">
<div class="form-group">
<input
v-model="heroID"
class="form-control"
type="text"
:placeholder="'User ID or Username'"
>
</div>
<div class="form-group">
<button
class="btn btn-secondary"
@click="loadHero(heroID)"
>
Load User
</button>
</div>
</div>
</div>
</div>
<div class="row">
<div
v-if="hero && hero.profile"
class="form col-6"
submit="saveHero(hero)"
class="row"
>
<router-link :to="{'name': 'userProfile', 'params': {'userId': hero._id}}">
<h3>@{{ hero.auth.local.username }} &nbsp; / &nbsp; {{ hero.profile.name }}</h3>
</router-link>
<div class="form-group">
<label>Contributor Title</label>
<input
v-model="hero.contributor.text"
class="form-control"
type="text"
>
<small>
Common titles:
<strong>Ambassador, Artisan, Bard, Blacksmith, Challenger, Comrade, Fletcher, Linguist, Linguistic Scribe, Scribe, Socialite, Storyteller</strong>. Rare titles: Advisor, Chamberlain, Designer, Mathematician, Shirtster, Spokesperson, Statistician, Tinker, Transcriber, Troubadour. <!-- eslint-disable-line max-len -->
</small>
</div>
<div class="form-group">
<label>Contributor Tier</label>
<input
v-model="hero.contributor.level"
class="form-control"
type="number"
>
<small>
1-7 for normal contributors, 8 for moderators, 9 for staff. This determines which items, pets, and mounts are available, and name-tag coloring. Tiers 8 and 9 are automatically given admin status.&nbsp; <!-- eslint-disable-line max-len -->
<a
href="https://habitica.fandom.com/wiki/Contributor_Rewards"
target="_blank"
>More details</a>
</small>
</div>
<div class="form-group">
<label>Contributions</label>
<textarea
v-model="hero.contributor.contributions"
class="form-control"
cols="5"
></textarea>
</div>
<div class="form-group">
<label>Balance</label>
<input
v-model="hero.balance"
class="form-control"
type="number"
step="any"
>
<small>
<span>
'{{ hero.balance }}' is in USD,
<em>not</em> in Gems. E.g., if this number is 1, it means 4 Gems. Only use this option when manually granting Gems to players, don't use it when granting contributor tiers. Contrib tiers will automatically add Gems. <!-- eslint-disable-line max-len -->
</span>
</small>
</div>
<div class="accordion">
<div
class="accordion-group"
heading="Items"
>
<h4
class="expand-toggle"
:class="{'open': expandItems}"
@click="expandItems = !expandItems"
<div
class="form col-4"
submit="saveHero(hero)"
>
<router-link :to="{'name': 'userProfile', 'params': {'userId': hero._id}}">
<h3>@{{ hero.auth.local.username }} &nbsp; / &nbsp; {{ hero.profile.name }}</h3>
</router-link>
<div class="form-group">
<label>Contributor Title</label>
<input
v-model="hero.contributor.text"
class="form-control"
type="text"
>
Update Item
</h4>
<small>
Common titles:
<strong>Ambassador, Artisan, Bard, Blacksmith, Challenger, Comrade, Fletcher, Linguist, Linguistic Scribe, Scribe, Socialite, Storyteller</strong>. Rare titles: Advisor, Chamberlain, Designer, Mathematician, Shirtster, Spokesperson, Statistician, Tinker, Transcriber, Troubadour. <!-- eslint-disable-line max-len -->
</small>
</div>
<div class="form-group">
<label>Contributor Tier</label>
<input
v-model="hero.contributor.level"
class="form-control"
type="number"
>
<small>
1-7 for normal contributors, 8 for moderators, 9 for staff. This determines which items, pets, and mounts are available, and name-tag coloring. Tiers 8 and 9 are automatically given admin status.&nbsp; <!-- eslint-disable-line max-len -->
<a
href="https://habitica.fandom.com/wiki/Contributor_Rewards"
target="_blank"
>More details</a>
</small>
</div>
<div class="form-group">
<label>Contributions</label>
<textarea
v-model="hero.contributor.contributions"
class="form-control"
cols="5"
></textarea>
</div>
<div class="form-group">
<label>Balance</label>
<input
v-model="hero.balance"
class="form-control"
type="number"
step="any"
>
<small>
<span>
'{{ hero.balance }}' is in USD,
<em>not</em> in Gems. E.g., if this number is 1, it means 4 Gems. Only use this option when manually granting Gems to players, don't use it when granting contributor tiers. Contrib tiers will automatically add Gems. <!-- eslint-disable-line max-len -->
</span>
</small>
</div>
</div>
<div class="col-8">
<div class="accordion">
<div
v-if="expandItems"
class="form-group well"
class="accordion-group"
heading="Items"
>
<input
v-model="hero.itemPath"
class="form-control"
type="text"
placeholder="Path (eg, items.pets.BearCub-Base)"
<h4
class="expand-toggle"
:class="{'open': expandItems}"
@click="expandItems = !expandItems"
>
<small class="muted">
Enter the
<strong>item path</strong>. E.g.,
<code>items.pets.BearCub-Zombie</code> or
<code>items.gear.owned.head_special_0</code> or
<code>items.gear.equipped.head</code>. You can find all the item paths below.
</small>
<br>
<input
v-model="hero.itemVal"
class="form-control"
type="text"
placeholder="Value (eg, 5)"
Update Item
</h4>
<div
v-if="expandItems"
class="form-group well"
>
<small class="muted">
Enter the
<strong>item value</strong>. E.g.,
<code>5</code> or
<code>false</code> or
<code>head_warrior_3</code>. All values are listed in the All Item Paths section below. <!-- eslint-disable-line max-len -->
</small>
<div class="accordion">
<div
class="accordion-group"
heading="All Item Paths"
<input
v-model="hero.itemPath"
class="form-control"
type="text"
placeholder="Path (eg, items.pets.BearCub-Base)"
>
<pre>{{ allItemPaths }}</pre>
</div>
<div
class="accordion-group"
heading="Current Items"
<small class="muted">
Enter the
<strong>item path</strong>. E.g.,
<code>items.pets.BearCub-Zombie</code> or
<code>items.gear.owned.head_special_0</code> or
<code>items.gear.equipped.head</code>. You can find all the item paths below.
</small>
<br>
<input
v-model="hero.itemVal"
class="form-control"
type="text"
placeholder="Value (eg, 5)"
>
<pre>{{ hero.items }}</pre>
<small class="muted">
Enter the
<strong>item value</strong>. E.g.,
<code>5</code> or
<code>false</code> or
<code>head_warrior_3</code>. All values are listed in the All Item Paths section below. <!-- eslint-disable-line max-len -->
</small>
<div class="accordion">
<div
class="accordion-group"
heading="All Item Paths"
>
<pre>{{ allItemPaths }}</pre>
</div>
<div
class="accordion-group"
heading="Current Items"
>
<pre>{{ hero.items }}</pre>
</div>
</div>
</div>
</div>
</div>
<div
class="accordion-group"
heading="Auth"
>
<h4
class="expand-toggle"
:class="{'open': expandAuth}"
@click="expandAuth = !expandAuth"
<div
class="accordion-group"
heading="Auth"
>
Auth
</h4>
<div v-if="expandAuth">
<pre>{{ hero.auth }}</pre>
<div class="form-group">
<div class="checkbox">
<label>
<input
v-if="hero.flags"
v-model="hero.flags.chatShadowMuted"
type="checkbox"
>
<strong>Chat Shadow Muting On</strong>
</label>
<h4
class="expand-toggle"
:class="{'open': expandAuth}"
@click="expandAuth = !expandAuth"
>
Auth
</h4>
<div v-if="expandAuth">
<pre>{{ hero.auth }}</pre>
<div class="form-group">
<div class="checkbox">
<label>
<input
v-if="hero.flags"
v-model="hero.flags.chatShadowMuted"
type="checkbox"
>
<strong>Chat Shadow Muting On</strong>
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="checkbox">
<label>
<input
v-if="hero.flags"
v-model="hero.flags.chatRevoked"
type="checkbox"
>
<strong>Chat Privileges Revoked</strong>
</label>
<div class="form-group">
<div class="checkbox">
<label>
<input
v-if="hero.flags"
v-model="hero.flags.chatRevoked"
type="checkbox"
>
<strong>Chat Privileges Revoked</strong>
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="checkbox">
<label>
<input
v-model="hero.auth.blocked"
type="checkbox"
>Blocked
</label>
<div class="form-group">
<div class="checkbox">
<label>
<input
v-model="hero.auth.blocked"
type="checkbox"
>Blocked
</label>
</div>
</div>
</div>
</div>
<div
class="accordion-group"
heading="Transactions"
>
<h4
class="expand-toggle"
:class="{'open': expandTransactions}"
@click="toggleTransactionsOpen"
>
Transactions
</h4>
<div v-if="expandTransactions">
<purchase-history-table
:gem-transactions="gemTransactions"
:hourglass-transactions="hourglassTransactions"
/>
</div>
</div>
</div>
</div>
<!-- h4 Backer Status-->
<!-- Add backer stuff like tier, disable adds, etcs-->
</div>
<div class="form-group">
<button
class="form-control btn btn-primary"
@@ -207,10 +233,15 @@
>
Save
</button>
<button
class="form-control btn btn-secondary float-right"
@click="clearHero()"
>
Cancel
</button>
</div>
</div>
</div>
</div>
<div class="table-responsive">
<table class="table table-striped">
<thead>
@@ -245,21 +276,40 @@
<td
v-if="user.contributor.admin"
class="btn-link"
@click="populateContributorInput(hero._id, index)"
:key="hero._id"
>
{{ hero._id }}
</td>
<td>{{ hero.contributor.level }}</td>
<td>{{ hero.contributor.text }}</td>
<td>
<div
v-markdown="hero.contributor.contributions"
target="_blank"
></div>
</td>
</tr>
</tbody>
</table>
<td>
<user-link
v-if="hero.contributor && hero.contributor.admin"
:user="hero"
:popover="$t('gamemaster')"
popover-trigger="mouseenter"
popover-placement="right"
/>
<user-link
v-if="!hero.contributor || !hero.contributor.admin"
:user="hero"
/>
</td>
<td
v-if="user.contributor.admin"
class="btn-link"
@click="populateContributorInput(hero._id, index)"
>
{{ hero._id }}
</td>
<td>{{ hero.contributor.level }}</td>
<td>{{ hero.contributor.text }}</td>
<td>
<div
v-markdown="hero.contributor.contributions"
target="_blank"
></div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
@@ -283,10 +333,12 @@ import content from '@/../../common/script/content';
import gear from '@/../../common/script/content/gear';
import notifications from '@/mixins/notifications';
import userLink from '../userLink';
import PurchaseHistoryTable from '../ui/purchaseHistoryTable.vue';
export default {
components: {
userLink,
PurchaseHistoryTable,
},
directives: {
markdown: markdownDirective,
@@ -297,6 +349,8 @@ export default {
heroes: [],
hero: {},
heroID: '',
gemTransactions: [],
hourglassTransactions: [],
currentHeroIndex: -1,
allItemPaths: this.getAllItemPaths(),
quests,
@@ -308,6 +362,7 @@ export default {
gear,
expandItems: false,
expandAuth: false,
expandTransactions: false,
};
},
computed: {
@@ -384,11 +439,24 @@ export default {
this.heroes[this.currentHeroIndex] = heroUpdated;
this.currentHeroIndex = -1;
},
clearHero () {
this.hero = {};
this.heroID = -1;
this.currentHeroIndex = -1;
},
populateContributorInput (id, index) {
this.heroID = id;
window.scrollTo(0, 200);
this.loadHero(id, index);
},
async toggleTransactionsOpen () {
this.expandTransactions = !this.expandTransactions;
if (this.expandTransactions) {
const transactions = await this.$store.dispatch('members:getPurchaseHistory', { memberId: this.hero._id });
this.gemTransactions = transactions.filter(transaction => transaction.currency === 'gems');
this.hourglassTransactions = transactions.filter(transaction => transaction.currency === 'hourglasses');
}
},
},
};
</script>
@@ -178,12 +178,12 @@ import sword from '@/assets/svg/sword.svg';
import { worldStateMixin } from '@/mixins/worldState';
export default {
mixins: [
worldStateMixin,
],
components: {
BaseNotification,
},
mixins: [
worldStateMixin,
],
data () {
const questData = quests.quests.dysheartener;
@@ -194,7 +194,10 @@
<h4 class="popover-content-title">
{{ context.item.text }}
</h4>
<questInfo :quest="context.item" :purchased="true" />
<questInfo
:quest="context.item"
:purchased="true"
/>
</div>
<div v-else>
<h4 class="popover-content-title">

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