handle error from invalid input
This commit is contained in:
@@ -0,0 +1,357 @@
|
||||
import get from 'lodash/get';
|
||||
import unlock from '../../../website/common/script/ops/unlock';
|
||||
import i18n from '../../../website/common/script/i18n';
|
||||
import { generateUser } from '../../helpers/common.helper';
|
||||
import {
|
||||
NotAuthorized,
|
||||
BadRequest,
|
||||
} from '../../../website/common/script/libs/errors';
|
||||
|
||||
describe('shared.ops.unlock', () => {
|
||||
let user;
|
||||
let clock;
|
||||
const unlockPath = 'shirt.convict,shirt.fire,shirt.horizon,shirt.ocean,shirt.purple,shirt.rainbow,shirt.redblue,shirt.thunder,shirt.tropical,shirt.zombie';
|
||||
const unlockGearSetPath = 'items.gear.owned.headAccessory_special_bearEars,items.gear.owned.headAccessory_special_cactusEars,items.gear.owned.headAccessory_special_foxEars,items.gear.owned.headAccessory_special_lionEars,items.gear.owned.headAccessory_special_pandaEars,items.gear.owned.headAccessory_special_pigEars,items.gear.owned.headAccessory_special_tigerEars,items.gear.owned.headAccessory_special_wolfEars';
|
||||
const backgroundUnlockPath = 'background.giant_florals';
|
||||
const hairUnlockPath = 'hair.color.rainbow,hair.color.yellow,hair.color.green,hair.color.purple,hair.color.blue,hair.color.TRUred';
|
||||
const facialHairUnlockPath = 'hair.mustache.1,hair.mustache.2,hair.beard.1,hair.beard.2,hair.beard.3';
|
||||
const usersStartingGems = 50 / 4;
|
||||
|
||||
beforeEach(() => {
|
||||
user = generateUser();
|
||||
user.balance = usersStartingGems;
|
||||
clock = sandbox.useFakeTimers(new Date('2024-04-10'));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
clock.restore();
|
||||
});
|
||||
|
||||
it('returns an error when path is not provided', async () => {
|
||||
try {
|
||||
await unlock(user);
|
||||
} catch (err) {
|
||||
expect(err).to.be.an.instanceof(BadRequest);
|
||||
expect(err.message).to.equal(i18n.t('pathRequired'));
|
||||
}
|
||||
});
|
||||
|
||||
it('does not unlock lost gear', async () => {
|
||||
user.items.gear.owned.headAccessory_special_bearEars = false;
|
||||
|
||||
await unlock(user, {
|
||||
query: { path: 'items.gear.owned.headAccessory_special_bearEars' },
|
||||
});
|
||||
|
||||
expect(user.balance).to.equal(usersStartingGems);
|
||||
});
|
||||
|
||||
it('returns an error when user balance is too low', async () => {
|
||||
user.balance = 0;
|
||||
|
||||
try {
|
||||
await unlock(user, { query: { path: unlockPath } });
|
||||
} catch (err) {
|
||||
expect(err).to.be.an.instanceof(NotAuthorized);
|
||||
expect(err.message).to.equal(i18n.t('notEnoughGems'));
|
||||
}
|
||||
});
|
||||
|
||||
it('returns an error when user already owns a full set', async () => {
|
||||
let expectedBalance;
|
||||
|
||||
try {
|
||||
await unlock(user, { query: { path: unlockPath } });
|
||||
expectedBalance = user.balance;
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
it('returns an error when user already owns a full set of gear', async () => {
|
||||
let expectedBalance;
|
||||
|
||||
try {
|
||||
await unlock(user, { query: { path: unlockGearSetPath } });
|
||||
expectedBalance = user.balance;
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
it('returns an error if an item does not exists', async () => {
|
||||
try {
|
||||
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'));
|
||||
}
|
||||
});
|
||||
|
||||
it('returns an error if there are items from multiple sets', async () => {
|
||||
try {
|
||||
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'));
|
||||
}
|
||||
});
|
||||
|
||||
it('returns an error if gear is not from the animal set', async () => {
|
||||
try {
|
||||
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'));
|
||||
}
|
||||
});
|
||||
|
||||
it('returns an error if the item is free', async () => {
|
||||
try {
|
||||
await unlock(user, { query: { path: 'shirt.black' } });
|
||||
} catch (err) {
|
||||
expect(err).to.be.an.instanceof(BadRequest);
|
||||
expect(err.message).to.equal(i18n.t('invalidUnlockSet'));
|
||||
}
|
||||
});
|
||||
|
||||
it('returns an error if an item does not belong to a set (appearances)', async () => {
|
||||
try {
|
||||
await unlock(user, { query: { path: 'shirt.pink' } });
|
||||
} catch (err) {
|
||||
expect(err).to.be.an.instanceof(BadRequest);
|
||||
expect(err.message).to.equal(i18n.t('invalidUnlockSet'));
|
||||
}
|
||||
});
|
||||
|
||||
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(',');
|
||||
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] } });
|
||||
|
||||
await unlock(user, { query: { path: unlockPath } });
|
||||
} catch (err) {
|
||||
expect(err).to.be.an.instanceof(NotAuthorized);
|
||||
expect(err.message).to.equal(i18n.t('alreadyUnlockedPart'));
|
||||
}
|
||||
});
|
||||
|
||||
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(',');
|
||||
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: unlockPath } });
|
||||
});
|
||||
|
||||
it('equips an item already owned', async () => {
|
||||
expect(user.purchased.background.giant_florals).to.not.exist;
|
||||
|
||||
await unlock(user, { query: { path: backgroundUnlockPath } });
|
||||
const afterBalance = user.balance;
|
||||
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', async () => {
|
||||
expect(user.purchased.background.giant_florals).to.not.exist;
|
||||
|
||||
await unlock(user, { query: { path: backgroundUnlockPath } }); // unlock
|
||||
const afterBalance = user.balance;
|
||||
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', async () => {
|
||||
const initialShirts = Object.keys(user.purchased.shirt).length;
|
||||
const [, message] = await unlock(user, { query: { path: unlockPath } });
|
||||
|
||||
expect(message).to.equal(i18n.t('unlocked'));
|
||||
const individualPaths = unlockPath.split(',');
|
||||
individualPaths.forEach(path => {
|
||||
expect(get(user.purchased, path)).to.be.true;
|
||||
});
|
||||
expect(Object.keys(user.purchased.shirt).length).to.equal(
|
||||
initialShirts + individualPaths.length,
|
||||
);
|
||||
expect(user.balance).to.equal(usersStartingGems - 1.25);
|
||||
});
|
||||
|
||||
it('unlocks a full set of hair items', async () => {
|
||||
user.purchased.hair.color = {};
|
||||
|
||||
const initialHairColors = Object.keys(user.purchased.hair.color).length;
|
||||
const [, message] = await unlock(user, { query: { path: hairUnlockPath } });
|
||||
|
||||
expect(message).to.equal(i18n.t('unlocked'));
|
||||
const individualPaths = hairUnlockPath.split(',');
|
||||
individualPaths.forEach(path => {
|
||||
expect(get(user.purchased, path)).to.be.true;
|
||||
});
|
||||
expect(Object.keys(user.purchased.hair.color).length).to.equal(
|
||||
initialHairColors + individualPaths.length,
|
||||
);
|
||||
expect(user.balance).to.equal(usersStartingGems - 1.25);
|
||||
});
|
||||
|
||||
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] = await unlock(user, {
|
||||
query: { path: facialHairUnlockPath },
|
||||
});
|
||||
|
||||
expect(message).to.equal(i18n.t('unlocked'));
|
||||
const individualPaths = facialHairUnlockPath.split(',');
|
||||
individualPaths.forEach(path => {
|
||||
expect(get(user.purchased, path)).to.be.true;
|
||||
});
|
||||
expect(
|
||||
Object.keys(user.purchased.hair.mustache).length
|
||||
+ Object.keys(user.purchased.hair.beard).length,
|
||||
) // eslint-disable-line max-len
|
||||
.to.equal(initialMustache + initialBeard + individualPaths.length);
|
||||
expect(user.balance).to.equal(usersStartingGems - 1.25);
|
||||
});
|
||||
|
||||
it('unlocks a full set of gear', async () => {
|
||||
const initialGear = Object.keys(user.items.gear.owned).length;
|
||||
const [, message] = await unlock(user, {
|
||||
query: { path: unlockGearSetPath },
|
||||
});
|
||||
|
||||
expect(message).to.equal(i18n.t('unlocked'));
|
||||
|
||||
const individualPaths = unlockGearSetPath.split(',');
|
||||
individualPaths.forEach(path => {
|
||||
expect(get(user, path)).to.be.true;
|
||||
});
|
||||
expect(Object.keys(user.items.gear.owned).length).to.equal(
|
||||
initialGear + individualPaths.length,
|
||||
);
|
||||
expect(user.balance).to.equal(usersStartingGems - 1.25);
|
||||
});
|
||||
|
||||
it('unlocks an item (appearance)', async () => {
|
||||
const path = unlockPath.split(',')[0];
|
||||
const initialShirts = Object.keys(user.purchased.shirt).length;
|
||||
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,
|
||||
);
|
||||
expect(get(user.purchased, path)).to.be.true;
|
||||
expect(user.balance).to.equal(usersStartingGems - 0.5);
|
||||
});
|
||||
|
||||
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] = await unlock(user, { query: { path } });
|
||||
|
||||
expect(message).to.equal(i18n.t('unlocked'));
|
||||
expect(Object.keys(user.purchased.hair.color).length).to.equal(
|
||||
initialColorHair + 1,
|
||||
);
|
||||
expect(get(user.purchased, path)).to.be.true;
|
||||
expect(user.balance).to.equal(usersStartingGems - 0.5);
|
||||
});
|
||||
|
||||
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] = await unlock(user, { query: { path } });
|
||||
|
||||
expect(message).to.equal(i18n.t('unlocked'));
|
||||
|
||||
expect(Object.keys(user.purchased.hair.mustache).length).to.equal(
|
||||
initialMustache + 1,
|
||||
);
|
||||
expect(Object.keys(user.purchased.hair.beard).length).to.equal(
|
||||
initialBeard,
|
||||
);
|
||||
|
||||
expect(get(user.purchased, path)).to.be.true;
|
||||
expect(user.balance).to.equal(usersStartingGems - 0.5);
|
||||
});
|
||||
|
||||
it('unlocks an item (gear)', async () => {
|
||||
const path = unlockGearSetPath.split(',')[0];
|
||||
const initialGear = Object.keys(user.items.gear.owned).length;
|
||||
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);
|
||||
expect(get(user, path)).to.be.true;
|
||||
expect(user.balance).to.equal(usersStartingGems - 0.5);
|
||||
});
|
||||
|
||||
it('unlocks an item (background)', async () => {
|
||||
const initialBackgrounds = Object.keys(user.purchased.background).length;
|
||||
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,
|
||||
);
|
||||
expect(get(user.purchased, backgroundUnlockPath)).to.be.true;
|
||||
expect(user.balance).to.equal(usersStartingGems - 1.75);
|
||||
});
|
||||
|
||||
it('handles an invalid hair path gracefully', async () => {
|
||||
try {
|
||||
await unlock(user, { query: { path: 'hair.invalid' } });
|
||||
} catch (err) {
|
||||
expect(err).to.be.an.instanceof(BadRequest);
|
||||
expect(err.message).to.equal(i18n.t('invalidUnlockSet'));
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user