diff --git a/.eslintrc b/.eslintrc index 82c291e8ce..585f456870 100644 --- a/.eslintrc +++ b/.eslintrc @@ -81,9 +81,6 @@ "block-spacing": [2, "always"], "key-spacing": [2, {"beforeColon": false, "afterColon": true}], "max-nested-callbacks": [2, 3], - "mocha/no-exclusive-tests": 2, - "mocha/no-global-tests": 2, - "mocha/handle-done-callback": 2, "new-cap": 2, "new-parens": 2, "newline-after-var": 2, @@ -119,11 +116,5 @@ ecmaFeatures : { modules: true }, - "extends": "eslint:recommended", - "globals": { - "expect": true - }, - "plugins": [ - "mocha" - ] + "extends": "eslint:recommended" } diff --git a/common/script/content/gear/index.js b/common/script/content/gear/index.js index 1ef3088c14..a9fe254e7b 100644 --- a/common/script/content/gear/index.js +++ b/common/script/content/gear/index.js @@ -61,11 +61,11 @@ each(GEAR_TYPES, (type) => { let _canOwn = item.canOwn || canOwnFuncTrue; item.canOwn = (user) => { - let userOwnsItem = Boolean(user.items.gear.owned[key]); + let userHasOwnedItem = ownsItem(key)(user); let eventIsCurrent = moment().isAfter(item.event.start) && moment().isBefore(item.event.end); let compatibleWithUserClass = item.specialClass ? user.stats.class === item.specialClass : true; - return _canOwn(user) && (userOwnsItem || eventIsCurrent) && compatibleWithUserClass; + return _canOwn(user) && (userHasOwnedItem || eventIsCurrent) && compatibleWithUserClass; }; } diff --git a/common/script/content/gear/sets/armoire.js b/common/script/content/gear/sets/armoire.js index 888b2586c4..77c9ff065c 100644 --- a/common/script/content/gear/sets/armoire.js +++ b/common/script/content/gear/sets/armoire.js @@ -18,7 +18,7 @@ let armor = { str: 7, per: 7, set: 'gladiator', - canOwn: ownsItem('armor_armoire_gladiatorArmor '), + canOwn: ownsItem('armor_armoire_gladiatorArmor'), }, rancherRobes: { text: t('armorArmoireRancherRobesText'), @@ -28,7 +28,7 @@ let armor = { per: 5, int: 5, set: 'rancher', - canOwn: ownsItem('armor_armoire_rancherRobes '), + canOwn: ownsItem('armor_armoire_rancherRobes'), }, goldenToga: { text: t('armorArmoireGoldenTogaText'), @@ -37,7 +37,7 @@ let armor = { str: 8, con: 8, set: 'goldenToga', - canOwn: ownsItem('armor_armoire_goldenToga '), + canOwn: ownsItem('armor_armoire_goldenToga'), }, hornedIronArmor: { text: t('armorArmoireHornedIronArmorText'), @@ -46,7 +46,7 @@ let armor = { con: 9, per: 7, set: 'hornedIron', - canOwn: ownsItem('armor_armoire_hornedIronArmor '), + canOwn: ownsItem('armor_armoire_hornedIronArmor'), }, plagueDoctorOvercoat: { text: t('armorArmoirePlagueDoctorOvercoatText'), @@ -56,7 +56,7 @@ let armor = { str: 5, con: 6, set: 'plagueDoctor', - canOwn: ownsItem('armor_armoire_plagueDoctorOvercoat '), + canOwn: ownsItem('armor_armoire_plagueDoctorOvercoat'), }, shepherdRobes: { text: t('armorArmoireShepherdRobesText'), @@ -65,7 +65,7 @@ let armor = { str: 9, per: 9, set: 'shepherd', - canOwn: ownsItem('armor_armoire_shepherdRobes '), + canOwn: ownsItem('armor_armoire_shepherdRobes'), }, royalRobes: { text: t('armorArmoireRoyalRobesText'), @@ -75,7 +75,7 @@ let armor = { per: 5, int: 5, set: 'royal', - canOwn: ownsItem('armor_armoire_royalRobes '), + canOwn: ownsItem('armor_armoire_royalRobes'), }, }; @@ -85,7 +85,7 @@ let eyewear = { notes: t('eyewearArmoirePlagueDoctorMaskNotes'), value: 100, set: 'plagueDoctor', - canOwn: ownsItem('eyewear_armoire_plagueDoctorMask '), + canOwn: ownsItem('eyewear_armoire_plagueDoctorMask'), }, }; @@ -97,7 +97,7 @@ let head = { con: 7, per: 7, set: 'soothing', - canOwn: ownsItem('head_armoire_lunarCrown '), + canOwn: ownsItem('head_armoire_lunarCrown'), }, redHairbow: { text: t('headArmoireRedHairbowText'), @@ -106,7 +106,7 @@ let head = { str: 5, int: 5, con: 5, - canOwn: ownsItem('head_armoire_redHairbow '), + canOwn: ownsItem('head_armoire_redHairbow'), }, violetFloppyHat: { text: t('headArmoireVioletFloppyHatText'), @@ -115,7 +115,7 @@ let head = { per: 5, int: 5, con: 5, - canOwn: ownsItem('head_armoire_violetFloppyHat '), + canOwn: ownsItem('head_armoire_violetFloppyHat'), }, gladiatorHelm: { text: t('headArmoireGladiatorHelmText'), @@ -124,7 +124,7 @@ let head = { per: 7, int: 7, set: 'gladiator', - canOwn: ownsItem('head_armoire_gladiatorHelm '), + canOwn: ownsItem('head_armoire_gladiatorHelm'), }, rancherHat: { text: t('headArmoireRancherHatText'), @@ -134,7 +134,7 @@ let head = { per: 5, int: 5, set: 'rancher', - canOwn: ownsItem('head_armoire_rancherHat '), + canOwn: ownsItem('head_armoire_rancherHat'), }, royalCrown: { text: t('headArmoireRoyalCrownText'), @@ -142,7 +142,7 @@ let head = { value: 100, str: 10, set: 'royal', - canOwn: ownsItem('head_armoire_royalCrown '), + canOwn: ownsItem('head_armoire_royalCrown'), }, blueHairbow: { text: t('headArmoireBlueHairbowText'), @@ -151,7 +151,7 @@ let head = { per: 5, int: 5, con: 5, - canOwn: ownsItem('head_armoire_blueHairbow '), + canOwn: ownsItem('head_armoire_blueHairbow'), }, goldenLaurels: { text: t('headArmoireGoldenLaurelsText'), @@ -160,7 +160,7 @@ let head = { per: 8, con: 8, set: 'goldenToga', - canOwn: ownsItem('head_armoire_goldenLaurels '), + canOwn: ownsItem('head_armoire_goldenLaurels'), }, hornedIronHelm: { text: t('headArmoireHornedIronHelmText'), @@ -169,7 +169,7 @@ let head = { con: 9, str: 7, set: 'hornedIron', - canOwn: ownsItem('head_armoire_hornedIronHelm '), + canOwn: ownsItem('head_armoire_hornedIronHelm'), }, yellowHairbow: { text: t('headArmoireYellowHairbowText'), @@ -178,7 +178,7 @@ let head = { int: 5, per: 5, str: 5, - canOwn: ownsItem('head_armoire_yellowHairbow '), + canOwn: ownsItem('head_armoire_yellowHairbow'), }, redFloppyHat: { text: t('headArmoireRedFloppyHatText'), @@ -187,7 +187,7 @@ let head = { con: 6, int: 6, per: 6, - canOwn: ownsItem('head_armoire_redFloppyHat '), + canOwn: ownsItem('head_armoire_redFloppyHat'), }, plagueDoctorHat: { text: t('headArmoirePlagueDoctorHatText'), @@ -197,7 +197,7 @@ let head = { str: 6, con: 5, set: 'plagueDoctor', - canOwn: ownsItem('head_armoire_plagueDoctorHat '), + canOwn: ownsItem('head_armoire_plagueDoctorHat'), }, blackCat: { text: t('headArmoireBlackCatText'), @@ -205,7 +205,7 @@ let head = { value: 100, int: 9, per: 9, - canOwn: ownsItem('head_armoire_blackCat '), + canOwn: ownsItem('head_armoire_blackCat'), }, orangeCat: { text: t('headArmoireOrangeCatText'), @@ -213,7 +213,7 @@ let head = { value: 100, con: 9, str: 9, - canOwn: ownsItem('head_armoire_orangeCat '), + canOwn: ownsItem('head_armoire_orangeCat'), }, blueFloppyHat: { text: t('headArmoireBlueFloppyHatText'), @@ -222,7 +222,7 @@ let head = { per: 7, int: 7, con: 7, - canOwn: ownsItem('head_armoire_blueFloppyHat '), + canOwn: ownsItem('head_armoire_blueFloppyHat'), }, shepherdHeaddress: { text: t('headArmoireShepherdHeaddressText'), @@ -230,7 +230,7 @@ let head = { value: 100, int: 9, set: 'shepherd', - canOwn: ownsItem('head_armoire_shepherdHeaddress '), + canOwn: ownsItem('head_armoire_shepherdHeaddress'), }, }; @@ -242,7 +242,7 @@ let shield = { con: 5, str: 5, set: 'gladiator', - canOwn: ownsItem('shield_armoire_gladiatorShield '), + canOwn: ownsItem('shield_armoire_gladiatorShield'), }, midnightShield: { text: t('shieldArmoireMidnightShieldText'), @@ -250,7 +250,7 @@ let shield = { value: 100, con: 10, str: 2, - canOwn: ownsItem('shield_armoire_midnightShield '), + canOwn: ownsItem('shield_armoire_midnightShield'), }, royalCane: { text: t('shieldArmoireRoyalCaneText'), @@ -260,7 +260,7 @@ let shield = { int: 5, per: 5, set: 'royal', - canOwn: ownsItem('shield_armoire_royalCane '), + canOwn: ownsItem('shield_armoire_royalCane'), }, }; @@ -272,7 +272,7 @@ let weapon = { str: 5, per: 5, con: 5, - canOwn: ownsItem('weapon_armoire_basicCrossbow '), + canOwn: ownsItem('weapon_armoire_basicCrossbow'), }, lunarSceptre: { text: t('weaponArmoireLunarSceptreText'), @@ -281,7 +281,7 @@ let weapon = { con: 7, int: 7, set: 'soothing', - canOwn: ownsItem('weapon_armoire_lunarSceptre '), + canOwn: ownsItem('weapon_armoire_lunarSceptre'), }, rancherLasso: { twoHanded: true, @@ -292,7 +292,7 @@ let weapon = { per: 5, int: 5, set: 'rancher', - canOwn: ownsItem('weapon_armoire_rancherLasso '), + canOwn: ownsItem('weapon_armoire_rancherLasso'), }, mythmakerSword: { text: t('weaponArmoireMythmakerSwordText'), @@ -301,7 +301,7 @@ let weapon = { str: 6, per: 6, set: 'goldenToga', - canOwn: ownsItem('weapon_armoire_mythmakerSword '), + canOwn: ownsItem('weapon_armoire_mythmakerSword'), }, ironCrook: { text: t('weaponArmoireIronCrookText'), @@ -310,7 +310,7 @@ let weapon = { str: 7, per: 7, set: 'hornedIron', - canOwn: ownsItem('weapon_armoire_ironCrook '), + canOwn: ownsItem('weapon_armoire_ironCrook'), }, goldWingStaff: { text: t('weaponArmoireGoldWingStaffText'), @@ -320,7 +320,7 @@ let weapon = { int: 4, per: 4, str: 4, - canOwn: ownsItem('weapon_armoire_goldWingStaff '), + canOwn: ownsItem('weapon_armoire_goldWingStaff'), }, batWand: { text: t('weaponArmoireBatWandText'), @@ -328,7 +328,7 @@ let weapon = { value: 100, int: 10, per: 2, - canOwn: ownsItem('weapon_armoire_batWand '), + canOwn: ownsItem('weapon_armoire_batWand'), }, shepherdsCrook: { text: t('weaponArmoireShepherdsCrookText'), @@ -336,7 +336,7 @@ let weapon = { value: 100, con: 9, set: 'shepherd', - canOwn: ownsItem('weapon_armoire_shepherdsCrook '), + canOwn: ownsItem('weapon_armoire_shepherdsCrook'), }, }; diff --git a/tasks/gulp-eslint.js b/tasks/gulp-eslint.js index 022445d62d..f85cb9455a 100644 --- a/tasks/gulp-eslint.js +++ b/tasks/gulp-eslint.js @@ -45,7 +45,18 @@ gulp.task('lint:tests', () => { '!./test/server_side/**/*', '!./test/spec/**/*', ]) - .pipe(eslint()) + .pipe(eslint({ + rules: { + 'no-unused-expressions': 0, + 'mocha/no-exclusive-tests': 2, + 'mocha/no-global-tests': 2, + 'mocha/handle-done-callback': 2, + }, + globals: { + 'expect': true, + }, + plugins: [ 'mocha' ], + })) .pipe(eslint.format()) .pipe(eslint.failAfterError()); }); diff --git a/test/helpers/api-integration.helper.js b/test/helpers/api-integration.helper.js index 92e67294df..d10a87096c 100644 --- a/test/helpers/api-integration.helper.js +++ b/test/helpers/api-integration.helper.js @@ -1,11 +1,13 @@ +/* eslint-disable no-use-before-define */ + import { assign, each, isEmpty, times, } from 'lodash'; -import {MongoClient as mongo} from 'mongodb'; -import {v4 as generateUUID} from 'uuid'; +import { MongoClient as mongo } from 'mongodb'; +import { v4 as generateUUID } from 'uuid'; import superagent from 'superagent'; import i18n from '../../common/script/src/i18n'; i18n.translations = require('../../website/src/libs/api-v3/i18n').translations; @@ -15,19 +17,19 @@ const API_TEST_SERVER_PORT = 3003; // Sets up an abject that can make all REST requests // If a user is passed in, the uuid and api token of // the user are used to make the requests -export function requester(user={}, additionalSets) { +export function requester (user = {}, additionalSets) { return { get: _requestMaker(user, 'get', additionalSets), post: _requestMaker(user, 'post', additionalSets), put: _requestMaker(user, 'put', additionalSets), del: _requestMaker(user, 'del', additionalSets), - } -}; + }; +} // Use this to verify error messages returned by the server // That way, if the translated string changes, the test // will not break. NOTE: it checks agains errors with string as well. -export function translate(key, variables) { +export function translate (key, variables) { const STRING_ERROR_MSG = 'Error processing the string. Please see Help > Report a Bug.'; const STRING_DOES_NOT_EXIST_MSG = /^String '.*' not found.$/; @@ -38,18 +40,22 @@ export function translate(key, variables) { expect(translatedString).to.not.match(STRING_DOES_NOT_EXIST_MSG); return translatedString; -}; +} // Useful for checking things that have been deleted, // but you no longer have access to, // like private parties or users -export function checkExistence(collectionName, id) { +export function checkExistence (collectionName, id) { return new Promise((resolve, reject) => { - mongo.connect('mongodb://localhost/habitrpg_test', (err, db) => { - if (err) return reject(err); + mongo.connect('mongodb://localhost/habitrpg_test', (connectionError, db) => { + if (connectionError) return reject(connectionError); let collection = db.collection(collectionName); - collection.find({_id: id}, {_id: 1}).limit(1).toArray((err, docs) => { + + collection.find({_id: id}, {_id: 1}).limit(1).toArray((findError, docs) => { + if (findError) return reject(findError); + let exists = docs.length > 0; + db.close(); resolve(exists); }); @@ -64,41 +70,41 @@ export function checkExistence(collectionName, id) { // paramter, such as the number of wolf eggs the user has, // , you can do so by passing in the full path as a string: // { 'items.eggs.Wolf': 10 } -export function generateUser(update={}) { +export function generateUser (update = {}) { let username = generateUUID(); - let password = 'password' - let email = username + '@example.com'; + let password = 'password'; + let email = `${username}@example.com`; let request = _requestMaker({}, 'post'); return new Promise((resolve, reject) => { request('/register', { - username: username, - email: email, - password: password, + username, + email, + password, confirmPassword: password, }).then((user) => { _updateDocument('users', user, update, () => { resolve(user); }); - }); + }).catch(reject); }); -}; +} // Generates a new group. Requires a user object, which // will will become the groups leader. Takes an update // argument which will update group -export function generateGroup(leader, update={}) { +export function generateGroup (leader, update = {}) { let request = _requestMaker(leader, 'post'); return new Promise((resolve, reject) => { request('/groups').then((group) => { _updateDocument('groups', group, update, () => { resolve(group); - }); + }).catch(reject); }); }); -}; +} // This is generate group + the ability to create // real users to populate it. The settings object @@ -114,8 +120,12 @@ export function generateGroup(leader, update={}) { // invitees: an array of user objects that correspond to the invitees of the group // leader: the leader user object // group: the group object -export function createAndPopulateGroup(settings={}) { - let request, leader, members, invitees, group; +export function createAndPopulateGroup (settings = {}) { + let request; + let leader; + let members; + let invitees; + let group; let numberOfMembers = settings.members || 0; let numberOfInvites = settings.invites || 0; @@ -156,37 +166,39 @@ export function createAndPopulateGroup(settings={}) { }).then((users) => { invitees = users; - let invitePromises = []; + let invitationPromises = []; each(invitees, (invitee) => { let invitePromise = request(`/groups/${group._id}/invite`, { - uuids: [invitee._id] + uuids: [invitee._id], }); - invitePromises.push(invitePromise); + + invitationPromises.push(invitePromise); }); - return Promise.all(invitePromises); - }).then((inviteResults) => { + return Promise.all(invitationPromises); + }).then(() => { resolve({ - leader: leader, - group: group, - members: members, - invitees: invitees, + leader, + group, + members, + invitees, }); }).catch(reject); }); -}; +} // Specifically helpful for the GET /groups tests, // resets the db to an empty state and creates a tavern document -export function resetHabiticaDB() { +export function resetHabiticaDB () { return new Promise((resolve, reject) => { mongo.connect('mongodb://localhost/habitrpg_test', (err, db) => { if (err) return reject(err); - db.dropDatabase((err) => { - if (err) return reject(err); + db.dropDatabase((dbErr) => { + if (dbErr) return reject(dbErr); let groups = db.collection('groups'); + groups.insertOne({ _id: 'habitrpg', chat: [], @@ -195,8 +207,8 @@ export function resetHabiticaDB() { type: 'guild', privacy: 'public', members: [], - }, (err) => { - if (err) return reject(err); + }, (insertErr) => { + if (insertErr) return reject(insertErr); db.close(); resolve(); @@ -208,6 +220,7 @@ export function resetHabiticaDB() { function _requestMaker(user, method, additionalSets) { const API_V = process.env.API_VERSION || 'v2' + return (route, send, query) => { return new Promise((resolve, reject) => { let request = superagent[method](`http://localhost:${API_TEST_SERVER_PORT}/api/${API_V}${route}`) @@ -229,29 +242,31 @@ function _requestMaker(user, method, additionalSets) { .end((err, response) => { if (err) { if (!err.response) return reject(err); - let errorString = JSON.parse(err.response.text).err; + return reject({ - code: err.response.statusCode, - text: errorString, + code: err.response.status, + text: err.response.body.err, }); } resolve(response.body); }); }); - } + }; } -function _updateDocument(collectionName, doc, update, cb) { - if (isEmpty(update)) { return cb(); } +function _updateDocument (collectionName, doc, update, cb) { + if (isEmpty(update)) { + return cb(); + } - mongo.connect('mongodb://localhost/habitrpg_test', (err, db) => { - if (err) throw `Error connecting to database when updating ${collectionName} collection: ${err}`; + mongo.connect('mongodb://localhost/habitrpg_test', (connectErr, db) => { + if (connectErr) throw new Error(`Error connecting to database when updating ${collectionName} collection: ${connectErr}`); let collection = db.collection(collectionName); - collection.update({ _id: doc._id }, { $set: update }, (err, result) => { - if (err) throw `Error updating ${collectionName}: ${err}`; + collection.update({ _id: doc._id }, { $set: update }, (updateErr) => { + if (updateErr) throw new Error(`Error updating ${collectionName}: ${updateErr}`); assign(doc, update); db.close(); cb(); diff --git a/test/helpers/content.helper.js b/test/helpers/content.helper.js index 9c6b3fcdad..f089156157 100644 --- a/test/helpers/content.helper.js +++ b/test/helpers/content.helper.js @@ -15,7 +15,7 @@ export function expectValidTranslationString (attribute) { expect(translatedString).to.not.be.empty; expect(translatedString).to.not.eql(STRING_ERROR_MSG); expect(translatedString).to.not.match(STRING_DOES_NOT_EXIST_MSG); -}; +} export function describeEachItem (testDescription, set, cb, describeFunction) { // describeFunction allows you to pass in 'only' or 'skip' @@ -34,8 +34,8 @@ export function describeEachItem (testDescription, set, cb, describeFunction) { describeEachItem.only = (des, set, cb) => { describeEachItem(des, set, cb, 'only'); -} +}; describeEachItem.skip = (des, set, cb) => { describeEachItem(des, set, cb, 'skip'); -} +}; diff --git a/test/helpers/globals.helper.js b/test/helpers/globals.helper.js index 4da36c7977..19f3ebfc71 100644 --- a/test/helpers/globals.helper.js +++ b/test/helpers/globals.helper.js @@ -1,14 +1,15 @@ +/* eslint-disable no-undef */ require('babel-core/register'); //------------------------------ // Global modules //------------------------------ -global._ = require("lodash") -global.chai = require("chai") -global.sinon = require("sinon"); -chai.use(require("sinon-chai")) -chai.use(require("chai-as-promised")); -global.expect = chai.expect +global._ = require('lodash'); +global.chai = require('chai'); +chai.use(require('sinon-chai')); +chai.use(require('chai-as-promised')); +global.expect = chai.expect; +global.sinon = require('sinon'); global.sandbox = sinon.sandbox.create(); //------------------------------