Merge branch 'develop' into ksami-develop
@@ -1,6 +1,6 @@
|
||||
.2014_Fall_HealerPROMO2 {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: -472px -950px;
|
||||
background-position: -475px -950px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
@@ -18,7 +18,7 @@
|
||||
}
|
||||
.2014_Fall_Warrior_PROMO {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: -563px -950px;
|
||||
background-position: -566px -950px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
@@ -48,7 +48,7 @@
|
||||
}
|
||||
.promo_dilatoryDistress {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: -836px -950px;
|
||||
background-position: -839px -950px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
@@ -60,7 +60,7 @@
|
||||
}
|
||||
.promo_enchanted_armoire_201507 {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: -289px -859px;
|
||||
background-position: -507px -859px;
|
||||
width: 217px;
|
||||
height: 90px;
|
||||
}
|
||||
@@ -72,7 +72,7 @@
|
||||
}
|
||||
.promo_enchanted_armoire_201509 {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: -290px -950px;
|
||||
background-position: -293px -950px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
@@ -102,7 +102,7 @@
|
||||
}
|
||||
.promo_mystery_201405 {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: -199px -950px;
|
||||
background-position: -1111px -91px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
@@ -114,73 +114,73 @@
|
||||
}
|
||||
.promo_mystery_201407 {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: -1111px -431px;
|
||||
background-position: -1111px -613px;
|
||||
width: 42px;
|
||||
height: 62px;
|
||||
}
|
||||
.promo_mystery_201408 {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: -1111px -155px;
|
||||
background-position: -1111px -337px;
|
||||
width: 60px;
|
||||
height: 71px;
|
||||
}
|
||||
.promo_mystery_201409 {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: -745px -950px;
|
||||
background-position: -748px -950px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_mystery_201410 {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: -1111px -91px;
|
||||
background-position: -1111px -273px;
|
||||
width: 72px;
|
||||
height: 63px;
|
||||
}
|
||||
.promo_mystery_201411 {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: -927px -950px;
|
||||
background-position: -930px -950px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_mystery_201412 {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: -1154px -361px;
|
||||
background-position: -1154px -543px;
|
||||
width: 42px;
|
||||
height: 66px;
|
||||
}
|
||||
.promo_mystery_201501 {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: -1111px -297px;
|
||||
background-position: -1111px -479px;
|
||||
width: 48px;
|
||||
height: 63px;
|
||||
}
|
||||
.promo_mystery_201502 {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: -381px -950px;
|
||||
background-position: -384px -950px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_mystery_201503 {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: -1111px 0px;
|
||||
background-position: -1111px -182px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_mystery_201504 {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: -1111px -227px;
|
||||
background-position: -1111px -409px;
|
||||
width: 60px;
|
||||
height: 69px;
|
||||
}
|
||||
.promo_mystery_201505 {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: -654px -950px;
|
||||
background-position: -657px -950px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_mystery_201506 {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: -1111px -361px;
|
||||
background-position: -1111px -543px;
|
||||
width: 42px;
|
||||
height: 69px;
|
||||
}
|
||||
@@ -192,19 +192,25 @@
|
||||
}
|
||||
.promo_mystery_201508 {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: -970px -777px;
|
||||
background-position: -199px -950px;
|
||||
width: 93px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_mystery_201509 {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: -1018px -950px;
|
||||
background-position: -1111px 0px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_mystery_201510 {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: -970px -777px;
|
||||
width: 93px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_mystery_3014 {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: -507px -859px;
|
||||
background-position: -289px -859px;
|
||||
width: 217px;
|
||||
height: 90px;
|
||||
}
|
||||
@@ -222,13 +228,13 @@
|
||||
}
|
||||
.promo_pastel_skin {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: 0px -775px;
|
||||
background-position: -331px -775px;
|
||||
width: 330px;
|
||||
height: 83px;
|
||||
}
|
||||
.customize-option.promo_pastel_skin {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: -25px -790px;
|
||||
background-position: -356px -790px;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
@@ -246,13 +252,13 @@
|
||||
}
|
||||
.promo_shimmer_hair {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: -331px -775px;
|
||||
background-position: 0px -775px;
|
||||
width: 330px;
|
||||
height: 83px;
|
||||
}
|
||||
.customize-option.promo_shimmer_hair {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: -356px -790px;
|
||||
background-position: -25px -790px;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
@@ -270,13 +276,13 @@
|
||||
}
|
||||
.promo_springclasses2014 {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: -430px -461px;
|
||||
background-position: 0px -859px;
|
||||
width: 288px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_springclasses2015 {
|
||||
background-image: url(spritesmith-largeSprites-0.png);
|
||||
background-position: 0px -859px;
|
||||
background-position: -430px -461px;
|
||||
width: 288px;
|
||||
height: 90px;
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 153 KiB After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 127 KiB |
|
Before Width: | Height: | Size: 390 KiB After Width: | Height: | Size: 387 KiB |
|
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 152 KiB |
|
Before Width: | Height: | Size: 148 KiB After Width: | Height: | Size: 146 KiB |
|
Before Width: | Height: | Size: 143 KiB After Width: | Height: | Size: 143 KiB |
|
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 106 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
@@ -662,6 +662,8 @@
|
||||
"backMystery201504Notes": "Buzz buzz buzz! Flit from task to task. Confers no benefit. April 2015 Subscriber Item.",
|
||||
"backMystery201507Text": "Rad Surfboard",
|
||||
"backMystery201507Notes": "Surf off the Diligent Docks and ride the waves in Inkomplete Bay! Confers no benefit. July 2015 Subscriber Item.",
|
||||
"backMystery201510Text": "Goblin Tail",
|
||||
"backMystery201510Notes": "Prehensile and powerful! Confers no benefit. October 2015 Subscriber Item.",
|
||||
|
||||
"backSpecialWonderconRedText": "Mighty Cape",
|
||||
"backSpecialWonderconRedNotes": "Swishes with strength and beauty. Confers no benefit. Special Edition Convention Item.",
|
||||
@@ -743,6 +745,8 @@
|
||||
"headAccessoryMystery201409Notes": "These powerful antlers change colors with the leaves. Confers no benefit. September 2014 Subscriber Item.",
|
||||
"headAccessoryMystery201502Text": "Wings of Thought",
|
||||
"headAccessoryMystery201502Notes": "Let your imagination take flight! Confers no benefit. February 2015 Subscriber Item.",
|
||||
"headAccessoryMystery201510Text": "Goblin Horns",
|
||||
"headAccessoryMystery201510Notes": "These fearsome horns are slightly slimy. Confers no benefit. October 2015 Subscriber Item.",
|
||||
"headAccessoryMystery301405Text": "Headwear Goggles",
|
||||
"headAccessoryMystery301405Notes": "\"Goggles are for your eyes,\" they said. \"Nobody wants goggles that you can only wear on your head,\" they said. Hah! You sure showed them! Confers no benefit. August 3015 Subscriber Item.",
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ api.mystery =
|
||||
201507: {start:'2015-07-24',end:'2015-08-02', text:'Rad Surfer Set'}
|
||||
201508: {start:'2015-08-23',end:'2015-09-02', text:'Cheetah Costume Set'}
|
||||
201509: {start:'2015-09-24',end:'2015-10-02', text:'Werewolf Set'}
|
||||
201510: {start:'2015-10-26',end:'2015-11-02', text:'Horned Goblin Set'}
|
||||
301404: {start:'3014-03-24',end:'3014-04-02', text:'Steampunk Standard Set'}
|
||||
301405: {start:'3014-04-24',end:'3014-05-02', text:'Steampunk Accessories Set'}
|
||||
wondercon: {start:'2014-03-24',end:'2014-04-01'} # not really, but the mechanic works
|
||||
@@ -459,6 +460,7 @@ gear =
|
||||
201410: text: t('backMystery201410Text'), notes: t('backMystery201410Notes'), mystery:'201410', value: 0
|
||||
201504: text: t('backMystery201504Text'), notes: t('backMystery201504Notes'), mystery:'201504', value: 0
|
||||
201507: text: t('backMystery201507Text'), notes: t('backMystery201507Notes'), mystery:'201507', value: 0
|
||||
201510: text: t('backMystery201510Text'), notes: t('backMystery201510Notes'), mystery:'201510', value: 0
|
||||
special:
|
||||
wondercon_red: text: t('backSpecialWonderconRedText'), notes: t('backSpecialWonderconRedNotes'), value: 0, mystery:'wondercon'
|
||||
wondercon_black: text: t('backSpecialWonderconBlackText'), notes: t('backSpecialWonderconBlackNotes'), value: 0, mystery:'wondercon'
|
||||
@@ -507,6 +509,7 @@ gear =
|
||||
201404: text: t('headAccessoryMystery201404Text'), notes: t('headAccessoryMystery201404Notes'), mystery:'201404', value: 0
|
||||
201409: text: t('headAccessoryMystery201409Text'), notes: t('headAccessoryMystery201409Notes'), mystery:'201409', value: 0
|
||||
201502: text: t('headAccessoryMystery201502Text'), notes: t('headAccessoryMystery201502Notes'), mystery:'201502', value: 0
|
||||
201510: text: t('headAccessoryMystery201510Text'), notes: t('headAccessoryMystery201510Notes'), mystery:'201510', value: 0
|
||||
301405: text: t('headAccessoryMystery301405Text'), notes: t('headAccessoryMystery301405Notes'), mystery:'301405', value: 0
|
||||
|
||||
eyewear:
|
||||
|
||||
@@ -25,6 +25,7 @@ let back = {
|
||||
201410: { mystery: '201410', value: 0 },
|
||||
201504: { mystery: '201504', value: 0 },
|
||||
201507: { mystery: '201507', value: 0 },
|
||||
201510: { mystery: '201510', value: 0 },
|
||||
};
|
||||
|
||||
let eyewear = {
|
||||
@@ -46,7 +47,7 @@ let head = {
|
||||
201501: { mystery: '201501', value: 0 },
|
||||
201505: { mystery: '201505', value: 0 },
|
||||
201508: { mystery: '201508', value: 0 },
|
||||
201509: { mystery:'201509', value: 0 },
|
||||
201509: { mystery: '201509', value: 0 },
|
||||
301404: { mystery: '301404', value: 0 },
|
||||
301405: { mystery: '301405', value: 0 },
|
||||
};
|
||||
@@ -56,6 +57,7 @@ let headAccessory = {
|
||||
201404: { mystery: '201404', value: 0 },
|
||||
201409: { mystery: '201409', value: 0 },
|
||||
201502: { mystery: '201502', value: 0 },
|
||||
201510: { mystery: '201510', value: 0 },
|
||||
301405: { mystery: '301405', value: 0 },
|
||||
};
|
||||
|
||||
|
||||
@@ -102,6 +102,11 @@ let mysterySets = {
|
||||
end:'2015-10-02',
|
||||
text:'Werewolf Set'
|
||||
},
|
||||
201510: {
|
||||
start:'2015-10-26',
|
||||
end:'2015-11-02',
|
||||
text:'Horned Goblin Set'
|
||||
},
|
||||
301404: {
|
||||
start: '3014-03-24',
|
||||
end: '3014-04-02',
|
||||
|
||||
@@ -2,7 +2,7 @@ var _id = '';
|
||||
var update = {
|
||||
$addToSet: {
|
||||
'purchased.plan.mysteryItems':{
|
||||
$each:['head_mystery_201509','armor_mystery_201509']
|
||||
$each:['headAccessory_mystery_201510','back_mystery_201510']
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
"request": "~2.44.0",
|
||||
"s3-upload-stream": "^1.0.6",
|
||||
"stripe": "*",
|
||||
"superagent": "~0.15.7",
|
||||
"superagent": "~1.4.0",
|
||||
"swagger-node-express": "lefnire/swagger-node-express#habitrpg",
|
||||
"universal-analytics": "~0.3.2",
|
||||
"validator": "~3.19.0",
|
||||
@@ -97,7 +97,8 @@
|
||||
"coverage": "COVERAGE=true mocha --require register-handlers.js --reporter html-cov > coverage.html; open coverage.html"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chai": "^2.3.0",
|
||||
"chai": "^3.4.0",
|
||||
"chai-as-promised": "^5.1.0",
|
||||
"coffee-coverage": "~0.4.2",
|
||||
"coveralls": "^2.11.2",
|
||||
"csv": "~0.3.6",
|
||||
@@ -113,21 +114,23 @@
|
||||
"karma-firefox-launcher": "~0.1.0",
|
||||
"karma-html2js-preprocessor": "~0.1.0",
|
||||
"karma-jasmine": "~0.1.3",
|
||||
"karma-mocha": "0.1.3",
|
||||
"karma-mocha-reporter": "^1.0.2",
|
||||
"karma-mocha": "^0.2.0",
|
||||
"karma-mocha-reporter": "^1.1.1",
|
||||
"karma-ng-html2js-preprocessor": "~0.1.0",
|
||||
"karma-phantomjs-launcher": "~0.1.0",
|
||||
"karma-requirejs": "~0.2.0",
|
||||
"karma-script-launcher": "~0.1.0",
|
||||
"lcov-result-merger": "^1.0.2",
|
||||
"mocha": "~1.12.1",
|
||||
"mocha": "^2.3.3",
|
||||
"mongodb": "^2.0.46",
|
||||
"mongoskin": "~0.6.1",
|
||||
"protractor": "~2.0.0",
|
||||
"rewire": "^2.3.3",
|
||||
"shelljs": "^0.4.0",
|
||||
"sinon": "1.15.4",
|
||||
"sinon-chai": "^2.7.0",
|
||||
"superagent-defaults": "~0.1.5",
|
||||
"sinon": "^1.17.2",
|
||||
"sinon-chai": "^2.8.0",
|
||||
"superagent-defaults": "^0.1.13",
|
||||
"uuid": "^2.0.1",
|
||||
"vinyl-source-stream": "^1.0.0",
|
||||
"vinyl-transform": "^1.0.0"
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ exports.config = {
|
||||
|
||||
// A base URL for your application under test. Calls to protractor.get()
|
||||
// with relative paths will be prepended with this.
|
||||
baseUrl: 'http://localhost:3001',
|
||||
baseUrl: 'http://localhost:3003',
|
||||
|
||||
// Options to be passed to Jasmine-node.
|
||||
jasmineNodeOpts: {
|
||||
|
||||
@@ -4,21 +4,26 @@ import mongoose from 'mongoose';
|
||||
import { exec } from 'child_process';
|
||||
import psTree from 'ps-tree';
|
||||
import gulp from 'gulp';
|
||||
import { sync as glob } from 'glob';
|
||||
import Q from 'q';
|
||||
import Mocha from 'mocha';
|
||||
import { resolve } from 'path';
|
||||
|
||||
const TEST_SERVER_PORT = 3001
|
||||
const TEST_SERVER_PORT = 3003
|
||||
const TEST_DB = 'habitrpg_test'
|
||||
let server;
|
||||
|
||||
const TEST_DB_URI = `mongodb://localhost/${TEST_DB}`
|
||||
|
||||
const API_TEST_COMMAND = 'mocha test/api';
|
||||
const COMMON_TEST_COMMAND = 'mocha test/common';
|
||||
const CONTENT_TEST_COMMAND = 'mocha test/content --opts test/content/mocha.content.opts';
|
||||
const API_TEST_COMMAND = 'mocha test/api --recursive --compilers js:babel/register';
|
||||
const LEGACY_API_TEST_COMMAND = 'mocha test/api-legacy';
|
||||
const COMMON_TEST_COMMAND = 'mocha test/common --compilers coffee:coffee-script';
|
||||
const CONTENT_TEST_COMMAND = 'mocha test/content --compilers js:babel/register';
|
||||
const CONTENT_OPTIONS = {maxBuffer: 1024 * 500};
|
||||
const KARMA_TEST_COMMAND = 'karma start';
|
||||
const SERVER_SIDE_TEST_COMMAND = 'mocha test/server_side';
|
||||
|
||||
const INSTANBUL_TEST_COMMAND = `istanbul cover -i "website/src/**" --dir coverage/api $(npm bin)/${API_TEST_COMMAND}`;
|
||||
const ISTANBUL_TEST_COMMAND = `istanbul cover -i "website/src/**" --dir coverage/api ./node_modules/.bin/${LEGACY_API_TEST_COMMAND}`;
|
||||
|
||||
/* Helper methods for reporting test summary */
|
||||
let testResults = [];
|
||||
@@ -32,13 +37,23 @@ let testBin = (string) => {
|
||||
};
|
||||
|
||||
gulp.task('test:prepare:mongo', (cb) => {
|
||||
mongoose.connect(TEST_DB_URI, () => {
|
||||
mongoose.connect(TEST_DB_URI, (err) => {
|
||||
if (err) return cb(`Unable to connect to mongo database. Are you sure it's running? \n\n${err}`);
|
||||
mongoose.connection.db.dropDatabase();
|
||||
mongoose.connection.close();
|
||||
cb();
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('test:prepare:server', ['test:prepare:mongo'], () => {
|
||||
if (!server) {
|
||||
server = exec(`NODE_DB_URI="${TEST_DB_URI}" PORT="${TEST_SERVER_PORT}" node ./website/src/server.js`, (error, stdout, stderr) => {
|
||||
if (error) { throw `Problem with the server: ${error}`; }
|
||||
if (stderr) { console.error(stderr); }
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
gulp.task('test:prepare:build', (cb) => {
|
||||
exec(testBin('grunt build:test'), cb);
|
||||
});
|
||||
@@ -149,9 +164,9 @@ gulp.task('test:server_side:safe', ['test:prepare:build'], (cb) => {
|
||||
pipe(runner);
|
||||
});
|
||||
|
||||
gulp.task('test:api', ['test:prepare:mongo'], (cb) => {
|
||||
gulp.task('test:api-legacy', ['test:prepare:mongo'], (cb) => {
|
||||
let runner = exec(
|
||||
testBin(INSTANBUL_TEST_COMMAND),
|
||||
testBin(ISTANBUL_TEST_COMMAND),
|
||||
(err, stdout, stderr) => {
|
||||
cb(err);
|
||||
}
|
||||
@@ -159,12 +174,12 @@ gulp.task('test:api', ['test:prepare:mongo'], (cb) => {
|
||||
pipe(runner);
|
||||
});
|
||||
|
||||
gulp.task('test:api:safe', ['test:prepare:mongo'], (cb) => {
|
||||
gulp.task('test:api-legacy:safe', ['test:prepare:mongo'], (cb) => {
|
||||
let runner = exec(
|
||||
testBin(INSTANBUL_TEST_COMMAND),
|
||||
testBin(ISTANBUL_TEST_COMMAND),
|
||||
(err, stdout, stderr) => {
|
||||
testResults.push({
|
||||
suite: 'API Specs\t',
|
||||
suite: 'API (legacy) Specs',
|
||||
pass: testCount(stdout, /(\d+) passing/),
|
||||
fail: testCount(stderr, /(\d+) failing/),
|
||||
pend: testCount(stdout, /(\d+) pending/)
|
||||
@@ -175,15 +190,15 @@ gulp.task('test:api:safe', ['test:prepare:mongo'], (cb) => {
|
||||
pipe(runner);
|
||||
});
|
||||
|
||||
gulp.task('test:api:clean', (cb) => {
|
||||
pipe(exec(testBin(API_TEST_COMMAND), () => cb()));
|
||||
gulp.task('test:api-legacy:clean', (cb) => {
|
||||
pipe(exec(testBin(LEGACY_API_TEST_COMMAND), () => cb()));
|
||||
});
|
||||
|
||||
gulp.task('test:api:watch', [
|
||||
gulp.task('test:api-legacy:watch', [
|
||||
'test:prepare:mongo',
|
||||
'test:api:clean'
|
||||
'test:api-legacy:clean'
|
||||
], () => {
|
||||
gulp.watch(['website/src/**', 'test/api/**'], ['test:api:clean']);
|
||||
gulp.watch(['website/src/**', 'test/api-legacy/**'], ['test:api-legacy:clean']);
|
||||
});
|
||||
|
||||
gulp.task('test:karma', ['test:prepare:build'], (cb) => {
|
||||
@@ -222,15 +237,15 @@ gulp.task('test:karma:safe', ['test:prepare:build'], (cb) => {
|
||||
pipe(runner);
|
||||
});
|
||||
|
||||
gulp.task('test:e2e', ['test:prepare'], (cb) => {
|
||||
gulp.task('test:e2e', ['test:prepare', 'test:prepare:server'], (cb) => {
|
||||
let support = [
|
||||
'Xvfb :99 -screen 0 1024x768x24 -extension RANDR',
|
||||
`NODE_DB_URI="${TEST_DB_URI}" PORT="${TEST_SERVER_PORT}" node ./website/src/server.js`,
|
||||
'./node_modules/protractor/bin/webdriver-manager start',
|
||||
].map(exec);
|
||||
support.push(server);
|
||||
|
||||
Q.all([
|
||||
awaitPort(3001),
|
||||
awaitPort(TEST_SERVER_PORT),
|
||||
awaitPort(4444)
|
||||
]).then(() => {
|
||||
let runner = exec(
|
||||
@@ -247,15 +262,14 @@ gulp.task('test:e2e', ['test:prepare'], (cb) => {
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('test:e2e:safe', ['test:prepare'], (cb) => {
|
||||
gulp.task('test:e2e:safe', ['test:prepare', 'test:prepare:server'], (cb) => {
|
||||
let support = [
|
||||
'Xvfb :99 -screen 0 1024x768x24 -extension RANDR',
|
||||
`NODE_DB_URI="${TEST_DB_URI}" PORT="${TEST_SERVER_PORT}" node ./website/src/server.js`,
|
||||
'./node_modules/protractor/bin/webdriver-manager start',
|
||||
].map(exec);
|
||||
|
||||
Q.all([
|
||||
awaitPort(3001),
|
||||
awaitPort(TEST_SERVER_PORT),
|
||||
awaitPort(4444)
|
||||
]).then(() => {
|
||||
let runner = exec(
|
||||
@@ -279,13 +293,59 @@ gulp.task('test:e2e:safe', ['test:prepare'], (cb) => {
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('test:api', ['test:prepare:server'], (done) => {
|
||||
require('../test/helpers/globals.helper');
|
||||
|
||||
awaitPort(TEST_SERVER_PORT).then(() => {
|
||||
let mocha = new Mocha({reporter: 'spec'});
|
||||
let tests = glob('./test/api/**/*.js');
|
||||
|
||||
tests.forEach((test) => {
|
||||
delete require.cache[resolve(test)];
|
||||
mocha.addFile(test);
|
||||
});
|
||||
|
||||
mocha.run((numberOfFailures) => {
|
||||
if (!process.env.RUN_INTEGRATION_TEST_FOREVER) {
|
||||
kill(server);
|
||||
process.exit(numberOfFailures);
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('test:api:watch', ['test:prepare:server'], () => {
|
||||
process.env.RUN_INTEGRATION_TEST_FOREVER = true;
|
||||
gulp.watch(['website/src/**', 'test/api/**'], ['test:api']);
|
||||
});
|
||||
|
||||
gulp.task('test:api:safe', ['test:prepare:server'], (done) => {
|
||||
awaitPort(TEST_SERVER_PORT).then(() => {
|
||||
let runner = exec(
|
||||
testBin(API_TEST_COMMAND),
|
||||
(err, stdout, stderr) => {
|
||||
testResults.push({
|
||||
suite: 'API Specs\t',
|
||||
pass: testCount(stdout, /(\d+) passing/),
|
||||
fail: testCount(stderr, /(\d+) failing/),
|
||||
pend: testCount(stdout, /(\d+) pending/)
|
||||
});
|
||||
done();
|
||||
}
|
||||
);
|
||||
pipe(runner);
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('test', [
|
||||
'test:e2e:safe',
|
||||
'test:common:safe',
|
||||
'test:content:safe',
|
||||
// 'test:content:safe',
|
||||
'test:server_side:safe',
|
||||
'test:karma:safe',
|
||||
'test:api-legacy:safe',
|
||||
'test:api:safe',
|
||||
'test:e2e:safe'
|
||||
], () => {
|
||||
let totals = [0,0,0];
|
||||
|
||||
@@ -311,6 +371,8 @@ gulp.task('test', [
|
||||
|
||||
if (totals[1] > 0) throw "ERROR: There are failing tests!"
|
||||
else {
|
||||
kill(server);
|
||||
console.log('\n\x1b[36mThanks for helping keep Habitica clean!\x1b[0m');
|
||||
process.exit();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# Legacy API Tests
|
||||
|
||||
These tests have been deprecated. Any tests that you see in this folder should be converted to ES2015 and ported to the `/test/api` directory.
|
||||
|
||||
Once all tests have been ported, this directory will be removed.
|
||||
@@ -10,7 +10,7 @@ describe "GET /api/v2/user/anonymized", ->
|
||||
# TODO: Seed user with messages, rewards, dailys, checklists, webhooks, etc
|
||||
registerNewUser ->
|
||||
request.get(baseURL + "/user/anonymized")
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
anon = res.body
|
||||
done()
|
||||
, true
|
||||
@@ -0,0 +1,90 @@
|
||||
require('coffee-script');
|
||||
var path, superagentDefaults;
|
||||
|
||||
superagentDefaults = require("superagent-defaults");
|
||||
|
||||
global.request = superagentDefaults();
|
||||
|
||||
global.mongoose = require("mongoose");
|
||||
|
||||
global.moment = require("moment");
|
||||
|
||||
global.async = require("async");
|
||||
|
||||
global._ = require("lodash");
|
||||
|
||||
global.shared = require("../../common");
|
||||
|
||||
global.User = require("../../website/src/models/user").model;
|
||||
|
||||
global.chai = require("chai");
|
||||
|
||||
chai.use(require("sinon-chai"));
|
||||
|
||||
global.expect = chai.expect;
|
||||
|
||||
path = require("path");
|
||||
|
||||
global.conf = require("nconf");
|
||||
|
||||
conf.argv().env().file({
|
||||
file: path.join(__dirname, "../config.json")
|
||||
}).defaults();
|
||||
|
||||
conf.set("PORT", "1337");
|
||||
|
||||
process.env.NODE_DB_URI = "mongodb://localhost/habitrpg_test_api_legacy";
|
||||
|
||||
global.baseURL = "http://localhost:" + conf.get("PORT") + "/api/v2";
|
||||
|
||||
global.user = void 0;
|
||||
|
||||
global.expectCode = function(res, code) {
|
||||
if (code === 200) {
|
||||
expect(res.body.err).to.not.exist;
|
||||
}
|
||||
return expect(res.statusCode).to.equal(code);
|
||||
};
|
||||
|
||||
global.registerNewUser = function(cb, main) {
|
||||
var password, randomID, username;
|
||||
if (main == null) {
|
||||
main = true;
|
||||
}
|
||||
randomID = shared.uuid();
|
||||
if (main) {
|
||||
username = password = randomID;
|
||||
}
|
||||
return request.post(baseURL + "/register").set("Accept", "application/json").set("X-API-User", null).set("X-API-Key", null).send({
|
||||
username: randomID,
|
||||
password: randomID,
|
||||
confirmPassword: randomID,
|
||||
email: randomID + "@gmail.com"
|
||||
}).end(function(err, res) {
|
||||
var _id, apiToken;
|
||||
if (!main) {
|
||||
return cb(null, res.body);
|
||||
}
|
||||
_id = res.body._id;
|
||||
apiToken = res.body.apiToken;
|
||||
return User.findOne({
|
||||
_id: _id,
|
||||
apiToken: apiToken
|
||||
}, function(err, _user) {
|
||||
expect(err).to.not.be.ok;
|
||||
global.user = _user;
|
||||
request.set("Accept", "application/json").set("X-API-User", _id).set("X-API-Key", apiToken);
|
||||
return cb(null, res.body);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
global.registerManyUsers = function(number, callback) {
|
||||
return async.times(number, function(n, next) {
|
||||
return registerNewUser(function(err, user) {
|
||||
return next(err, user);
|
||||
}, false);
|
||||
}, function(err, users) {
|
||||
return callback(err, users);
|
||||
});
|
||||
};
|
||||
@@ -18,7 +18,7 @@ describe "Challenges", ->
|
||||
request.post(baseURL + "/groups").send(
|
||||
name: "TestGroup"
|
||||
type: "party"
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
group = res.body
|
||||
expect(group.members.length).to.equal 1
|
||||
@@ -38,7 +38,7 @@ describe "Challenges", ->
|
||||
}]
|
||||
rewards: []
|
||||
habits: []
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
challenge = res.body
|
||||
done()
|
||||
]
|
||||
@@ -64,7 +64,7 @@ describe "Challenges", ->
|
||||
rewards: []
|
||||
habits: []
|
||||
official: true
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
async.parallel [
|
||||
(cb) ->
|
||||
@@ -84,7 +84,7 @@ describe "Challenges", ->
|
||||
updateTodo.notes = "User overriden notes"
|
||||
async.waterfall [
|
||||
(cb) ->
|
||||
request.put(baseURL + "/user/tasks/" + updateTodo.id).send(updateTodo).end (res) ->
|
||||
request.put(baseURL + "/user/tasks/" + updateTodo.id).send(updateTodo).end (err, res) ->
|
||||
cb()
|
||||
, (cb) ->
|
||||
Challenge.findById challenge._id, cb
|
||||
@@ -93,7 +93,7 @@ describe "Challenges", ->
|
||||
cb()
|
||||
, (cb) ->
|
||||
request.get(baseURL + "/user/tasks/" + updateTodo.id)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expect(res.body.notes).to.eql("User overriden notes")
|
||||
done()
|
||||
]
|
||||
@@ -102,7 +102,7 @@ describe "Challenges", ->
|
||||
challenge.dailys[0].text = "Updated Daily"
|
||||
request.post(baseURL + "/challenges/" + challenge._id)
|
||||
.send(challenge)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
challenge = res.body
|
||||
expect(challenge.dailys[0].text).to.equal "Updated Daily"
|
||||
User.findById user._id, (err, _user) ->
|
||||
@@ -114,7 +114,7 @@ describe "Challenges", ->
|
||||
challenge.todos[0].notes = "Challenge Updated Todo Notes"
|
||||
request.post(baseURL + "/challenges/" + challenge._id)
|
||||
.send(challenge)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
challenge = res.body
|
||||
expect(challenge.todos[0].notes).to.equal "Challenge Updated Todo Notes"
|
||||
User.findById user._id, (err, _user) ->
|
||||
@@ -128,7 +128,7 @@ describe "Challenges", ->
|
||||
updateTodo.notes = "User overriden notes"
|
||||
async.waterfall [
|
||||
(cb) ->
|
||||
request.put(baseURL + "/user/tasks/" + updateTodo.id).send(updateTodo).end (res) ->
|
||||
request.put(baseURL + "/user/tasks/" + updateTodo.id).send(updateTodo).end (err, res) ->
|
||||
cb()
|
||||
, (cb) ->
|
||||
Challenge.findById challenge._id, cb
|
||||
@@ -136,7 +136,7 @@ describe "Challenges", ->
|
||||
expect(chal.todos[0].notes).to.eql("Challenge Notes")
|
||||
cb()
|
||||
, (cb) ->
|
||||
request.get(baseURL + "/challenges/" + challenge._id + "/member/" + user._id).end (res) ->
|
||||
request.get(baseURL + "/challenges/" + challenge._id + "/member/" + user._id).end (err, res) ->
|
||||
expect(res.body.todos[res.body.todos.length - 1].notes).to.equal "User overriden notes"
|
||||
done()
|
||||
]
|
||||
@@ -145,14 +145,14 @@ describe "Challenges", ->
|
||||
User.findById user._id, (err, _user) ->
|
||||
u = _user
|
||||
numTasks = (_.size(u.todos))
|
||||
request.post(baseURL + "/user/tasks/" + u.todos[0].id + "/up").end (res) ->
|
||||
request.post(baseURL + "/user/tasks/clear-completed").end (res) ->
|
||||
request.post(baseURL + "/user/tasks/" + u.todos[0].id + "/up").end (err, res) ->
|
||||
request.post(baseURL + "/user/tasks/clear-completed").end (err, res) ->
|
||||
expect(_.size(res.body)).to.equal numTasks - 1
|
||||
done()
|
||||
|
||||
it "Challenge deleted, breaks task link", (done) ->
|
||||
itThis = this
|
||||
request.del(baseURL + "/challenges/" + challenge._id).end (res) ->
|
||||
request.del(baseURL + "/challenges/" + challenge._id).end (err, res) ->
|
||||
User.findById user._id, (err, user) ->
|
||||
len = user.dailys.length - 1
|
||||
daily = user.dailys[user.dailys.length - 1]
|
||||
@@ -164,7 +164,7 @@ describe "Challenges", ->
|
||||
User.findByIdAndUpdate user._id, unset, (err, user) ->
|
||||
expect(err).to.not.exist
|
||||
expect(user.dailys[len].challenge.broken).to.not.exist
|
||||
request.post(baseURL + "/user/tasks/" + daily.id + "/up").end (res) ->
|
||||
request.post(baseURL + "/user/tasks/" + daily.id + "/up").end (err, res) ->
|
||||
setTimeout (->
|
||||
User.findById user._id, (err, user) ->
|
||||
expect(user.dailys[len].challenge.broken).to.equal "CHALLENGE_DELETED"
|
||||
@@ -186,7 +186,7 @@ describe "Challenges", ->
|
||||
rewards: []
|
||||
habits: []
|
||||
official: false
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expect(res.body.official).to.equal false
|
||||
cb()
|
||||
(cb) ->
|
||||
@@ -197,7 +197,7 @@ describe "Challenges", ->
|
||||
rewards: []
|
||||
habits: []
|
||||
official: true
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expect(res.body.official).to.equal true
|
||||
cb()
|
||||
], done
|
||||
@@ -215,7 +215,7 @@ describe "Challenges", ->
|
||||
rewards: []
|
||||
habits: []
|
||||
prize: 10
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expect(res.body.prize).to.equal 10
|
||||
async.parallel [
|
||||
(cb) ->
|
||||
@@ -226,7 +226,7 @@ describe "Challenges", ->
|
||||
user = results[0]
|
||||
challenge = results[1]
|
||||
expect(user.balance).to.equal 5.5
|
||||
request.del(baseURL + "/challenges/" + challenge._id).end (res) ->
|
||||
request.del(baseURL + "/challenges/" + challenge._id).end (err, res) ->
|
||||
User.findById user._id, (err, _user) ->
|
||||
expect(_user.balance).to.equal 8
|
||||
done()
|
||||
@@ -244,7 +244,7 @@ describe "Challenges", ->
|
||||
rewards: []
|
||||
habits: []
|
||||
prize: 10
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expect(res.body.prize).to.equal 10
|
||||
async.parallel [
|
||||
(cb) ->
|
||||
@@ -255,7 +255,7 @@ describe "Challenges", ->
|
||||
user = results[0]
|
||||
challenge = results[1]
|
||||
expect(user.balance).to.equal 5.5
|
||||
request.del(baseURL + "/challenges/" + challenge._id).end (res) ->
|
||||
request.del(baseURL + "/challenges/" + challenge._id).end (err, res) ->
|
||||
User.findById user._id, (err, _user) ->
|
||||
expect(_user.balance).to.equal 5.5
|
||||
done()
|
||||
@@ -273,7 +273,7 @@ describe "Challenges", ->
|
||||
type: "daily"
|
||||
text: "Challenge Daily"
|
||||
]
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
challenge = res.body
|
||||
cb()
|
||||
|
||||
@@ -287,7 +287,7 @@ describe "Challenges", ->
|
||||
challenge.name = 'foobar'
|
||||
request.post(baseURL + "/challenges/" + challenge._id)
|
||||
.send(challenge)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
error = res.body.err
|
||||
|
||||
expect(error).to.eql("You don't have permissions to edit this challenge")
|
||||
@@ -295,7 +295,7 @@ describe "Challenges", ->
|
||||
|
||||
it 'can not close challenge', (done) ->
|
||||
request.post(baseURL + "/challenges/" + challenge._id + "/close?uid=" + user._id)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
error = res.body.err
|
||||
|
||||
expect(error).to.eql("You don't have permissions to close this challenge")
|
||||
@@ -303,7 +303,7 @@ describe "Challenges", ->
|
||||
|
||||
it 'can not delete challenge', (done) ->
|
||||
request.del(baseURL + "/challenges/" + challenge._id)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
error = res.body.err
|
||||
|
||||
expect(error).to.eql("You don't have permissions to delete this challenge")
|
||||
@@ -318,7 +318,7 @@ describe "Challenges", ->
|
||||
challenge.name = 'foobar'
|
||||
request.post(baseURL + "/challenges/" + challenge._id)
|
||||
.send(challenge)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expect(res.body.err).to.not.exist
|
||||
Challenge.findById challenge._id, (err, chal) ->
|
||||
expect(chal.name).to.eql('foobar')
|
||||
@@ -326,7 +326,7 @@ describe "Challenges", ->
|
||||
|
||||
it 'can close challenge', (done) ->
|
||||
request.post(baseURL + "/challenges/" + challenge._id + "/close?uid=" + user._id)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expect(res.body.err).to.not.exist
|
||||
User.findById user._id, (err, usr) ->
|
||||
expect(usr.achievements.challenges[0]).to.eql(challenge.name)
|
||||
@@ -334,10 +334,10 @@ describe "Challenges", ->
|
||||
|
||||
it 'can delete challenge', (done) ->
|
||||
request.del(baseURL + "/challenges/" + challenge._id)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expect(res.body.err).to.not.exist
|
||||
request.get(baseURL + "/challenges/" + challenge._id)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
error = res.body.err
|
||||
expect(error).to.eql("Challenge #{challenge._id} not found")
|
||||
done()
|
||||
@@ -16,7 +16,7 @@ describe "Chat", ->
|
||||
request.post(baseURL + "/groups").send(
|
||||
name: "TestGroup"
|
||||
type: "party"
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
group = res.body
|
||||
expect(group.members.length).to.equal 1
|
||||
@@ -28,7 +28,7 @@ describe "Chat", ->
|
||||
chat = undefined
|
||||
it "posts a message to party chat", (done) ->
|
||||
msg = "TestMsg"
|
||||
request.post(baseURL + "/groups/" + group._id + "/chat?message=" + msg).end (res) ->
|
||||
request.post(baseURL + "/groups/" + group._id + "/chat?message=" + msg).end (err, res) ->
|
||||
expectCode res, 200
|
||||
chat = res.body.message
|
||||
expect(chat.id).to.be.ok
|
||||
@@ -47,14 +47,14 @@ describe "Chat", ->
|
||||
it "does not post an empty message", (done) ->
|
||||
msg = ""
|
||||
request.post(baseURL + "/groups/" + group._id + "/chat?message=" + msg).send(
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 400
|
||||
expect(res.body.err).to.equal 'You cannot send a blank message'
|
||||
done()
|
||||
|
||||
it "can not like own chat message", (done) ->
|
||||
request.post(baseURL + "/groups/" + group._id + "/chat/" + chat.id + "/like").send(
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 401
|
||||
body = res.body
|
||||
expect(body.err).to.equal "Can't like your own message. Don't be that person."
|
||||
@@ -62,7 +62,7 @@ describe "Chat", ->
|
||||
|
||||
it "can not flag own message", (done) ->
|
||||
request.post(baseURL + "/groups/" + group._id + "/chat/" + chat.id + "/flag").send(
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 401
|
||||
body = res.body
|
||||
expect(body.err).to.equal "Can't report your own message."
|
||||
@@ -70,7 +70,7 @@ describe "Chat", ->
|
||||
|
||||
it "gets chat messages from party chat", (done) ->
|
||||
request.get(baseURL + "/groups/" + group._id + "/chat").send(
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
message = res.body[0]
|
||||
expect(message.id).to.equal chat.id
|
||||
@@ -86,14 +86,14 @@ describe "Chat", ->
|
||||
|
||||
it "deletes a chat messages from party chat", (done) ->
|
||||
request.del(baseURL + "/groups/" + group._id + "/chat/" + chat.id).send(
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 204
|
||||
expect(res.body).to.be.empty
|
||||
done()
|
||||
|
||||
it "can not delete already deleted message", (done) ->
|
||||
request.del(baseURL + "/groups/" + group._id + "/chat/" + chat.id).send(
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 404
|
||||
body = res.body
|
||||
expect(body.err).to.equal "Message not found!"
|
||||
@@ -116,30 +116,30 @@ describe "Chat", ->
|
||||
request.post(baseURL + "/groups/" + group._id + "/join")
|
||||
.set("X-API-User", userToRemove._id)
|
||||
.set("X-API-Key", userToRemove.apiToken)
|
||||
.end (res) -> cb()
|
||||
.end (err, res) -> cb()
|
||||
|
||||
(cb) ->
|
||||
msg = "TestMsg"
|
||||
request.post(baseURL + "/groups/" + group._id + "/chat?message=" + msg)
|
||||
.end (res) -> cb()
|
||||
.end (err, res) -> cb()
|
||||
|
||||
(cb) ->
|
||||
request.get(baseURL + "/user")
|
||||
.set("X-API-User", userToRemove._id)
|
||||
.set("X-API-Key", userToRemove.apiToken)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expect(res.body.newMessages[group._id]).to.exist
|
||||
cb()
|
||||
|
||||
(cb) ->
|
||||
request.post(baseURL + "/groups/" + group._id + "/removeMember?uuid=" + userToRemove._id)
|
||||
.end (res) -> cb()
|
||||
.end (err, res) -> cb()
|
||||
|
||||
(cb) ->
|
||||
request.get(baseURL + "/user")
|
||||
.set("X-API-User", userToRemove._id)
|
||||
.set("X-API-Key", userToRemove.apiToken)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expect(res.body.newMessages[group._id]).to.not.exist
|
||||
cb()
|
||||
], done
|
||||
@@ -34,7 +34,7 @@ describe "Coupons", ->
|
||||
queries = '?count=10'
|
||||
request
|
||||
.post(baseURL + '/coupons/generate/wondercon' + queries)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
Coupon.find { event: 'wondercon' }, (err, _coupons) ->
|
||||
coupons = _coupons
|
||||
@@ -52,7 +52,7 @@ describe "Coupons", ->
|
||||
queries = '?count=10'
|
||||
request
|
||||
.post(baseURL + '/coupons/generate/wondercon' + queries)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 401
|
||||
expect(res.body.err).to.equal 'You don\'t have admin access'
|
||||
done()
|
||||
@@ -68,7 +68,7 @@ describe "Coupons", ->
|
||||
queries = '?_id=' + user._id + '&apiToken=' + user.apiToken
|
||||
request
|
||||
.get(baseURL + '/coupons' + queries)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
codes = res.text
|
||||
expect(codes).to.contain('code')
|
||||
@@ -81,7 +81,7 @@ describe "Coupons", ->
|
||||
queries = '?_id=' + user._id + '&apiToken=' + user.apiToken + '&limit=5'
|
||||
request
|
||||
.get(baseURL + '/coupons' + queries)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
codes = res.text
|
||||
sortedCoupons = _.sortBy(coupons, 'seq')
|
||||
@@ -98,7 +98,7 @@ describe "Coupons", ->
|
||||
queries = '?_id=' + user._id + '&apiToken=' + user.apiToken + '&skip=5'
|
||||
request
|
||||
.get(baseURL + '/coupons' + queries)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
codes = res.text
|
||||
sortedCoupons = _.sortBy(coupons, 'seq')
|
||||
@@ -121,7 +121,7 @@ describe "Coupons", ->
|
||||
queries = '?_id=' + user._id + '&apiToken=' + user.apiToken
|
||||
request
|
||||
.get(baseURL + '/coupons' + queries)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 401
|
||||
expect(res.body.err).to.equal 'You don\'t have admin access'
|
||||
done()
|
||||
@@ -156,7 +156,7 @@ describe "Coupons", ->
|
||||
code = coupons[0]._id
|
||||
request
|
||||
.post(baseURL + '/user/coupon/' + code)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
gear = res.body.items.gear.owned
|
||||
specialGear(gear, true)
|
||||
@@ -168,7 +168,7 @@ describe "Coupons", ->
|
||||
code = coupons[0]._id
|
||||
request
|
||||
.post(baseURL + '/user/coupon/' + code)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 400
|
||||
expect(res.body.err).to.equal "Coupon already used"
|
||||
User.findById user._id, (err, _user) ->
|
||||
@@ -182,7 +182,7 @@ describe "Coupons", ->
|
||||
code = "not-a-real-coupon"
|
||||
request
|
||||
.post(baseURL + '/user/coupon/' + code)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 400
|
||||
expect(res.body.err).to.equal "Invalid coupon code"
|
||||
User.findById user._id, (err, _user) ->
|
||||
@@ -16,7 +16,7 @@ describe "Party", ->
|
||||
request.post(baseURL + "/groups").send(
|
||||
name: "TestGroup"
|
||||
type: "party"
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
group = res.body
|
||||
expect(group.members.length).to.equal 1
|
||||
@@ -28,7 +28,7 @@ describe "Party", ->
|
||||
request.post(baseURL + "/groups").send(
|
||||
name: "TestGroup"
|
||||
type: "party"
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 400
|
||||
expect(res.body.err).to.equal "Already in a party, try refreshing."
|
||||
done()
|
||||
@@ -44,7 +44,7 @@ describe "Party", ->
|
||||
request.post(baseURL + "/groups").send(
|
||||
name: "TestGroup"
|
||||
type: "party"
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
group = res.body
|
||||
expect(group.members.length).to.equal 1
|
||||
@@ -55,7 +55,7 @@ describe "Party", ->
|
||||
it "can be found by querying for group type party", (done) ->
|
||||
request.get(baseURL + "/groups/").send(
|
||||
type: "party"
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
party = _.find res.body, (g) -> return g._id == group._id
|
||||
expect(party._id).to.equal group._id
|
||||
@@ -76,7 +76,7 @@ describe "Party", ->
|
||||
request.post(baseURL + "/groups").send(
|
||||
name: "TestGroup"
|
||||
type: "party"
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
group = res.body
|
||||
expect(group.members.length).to.equal 1
|
||||
@@ -89,7 +89,7 @@ describe "Party", ->
|
||||
request.post(baseURL + "/groups/" + group._id + "/join").send()
|
||||
.set("X-API-User", user._id)
|
||||
.set("X-API-Key", user.apiToken)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 401
|
||||
expect(res.body.err).to.equal "Can't join a group you're not invited to."
|
||||
done()
|
||||
@@ -114,7 +114,7 @@ describe "Party", ->
|
||||
request.post(baseURL + "/groups/" + group._id + "/join")
|
||||
.set("X-API-User", tmpUser._id)
|
||||
.set("X-API-Key", tmpUser.apiToken)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
cb()
|
||||
|
||||
@@ -153,7 +153,7 @@ describe "Party", ->
|
||||
request.post(baseURL + "/groups").send(
|
||||
name: "TestGroup"
|
||||
type: "party"
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
group = res.body
|
||||
expect(group.members.length).to.equal 1
|
||||
@@ -164,13 +164,13 @@ describe "Party", ->
|
||||
request.post(baseURL + '/user/tasks').send({
|
||||
type: 'daily'
|
||||
text: 'daily one'
|
||||
}).end (res) ->
|
||||
}).end (err, res) ->
|
||||
cb()
|
||||
(cb) ->
|
||||
request.post(baseURL + '/user/tasks').send({
|
||||
type: 'daily'
|
||||
text: 'daily two'
|
||||
}).end (res) ->
|
||||
}).end (err, res) ->
|
||||
cb()
|
||||
(cb) ->
|
||||
User.findByIdAndUpdate user._id,
|
||||
@@ -198,7 +198,7 @@ describe "Party", ->
|
||||
body:
|
||||
"stats.lvl": 50
|
||||
}
|
||||
]).end (res) ->
|
||||
]).end (err, res) ->
|
||||
user = res.body
|
||||
expect(user.party.quest.progress.up).to.be.above 0
|
||||
|
||||
@@ -227,7 +227,7 @@ describe "Party", ->
|
||||
(cb2) ->
|
||||
request.post(inviteURL).send(
|
||||
uuids: [party[2]._id]
|
||||
).end (res)->
|
||||
).end (err, res)->
|
||||
cb2()
|
||||
], cb
|
||||
|
||||
@@ -255,7 +255,7 @@ describe "Party", ->
|
||||
# Start the quest
|
||||
async.waterfall [
|
||||
(cb) ->
|
||||
request.post(baseURL + "/groups/" + group._id + "/questAccept?key=vice3").end (res) ->
|
||||
request.post(baseURL + "/groups/" + group._id + "/questAccept?key=vice3").end (err, res) ->
|
||||
expectCode res, 400
|
||||
User.findByIdAndUpdate user._id,
|
||||
$set:
|
||||
@@ -263,7 +263,7 @@ describe "Party", ->
|
||||
, cb
|
||||
|
||||
(_user, cb) ->
|
||||
request.post(baseURL + "/groups/" + group._id + "/questAccept?key=vice3").end (res) ->
|
||||
request.post(baseURL + "/groups/" + group._id + "/questAccept?key=vice3").end (err, res) ->
|
||||
expectCode res, 200
|
||||
Group.findById group._id, cb
|
||||
|
||||
@@ -271,8 +271,8 @@ describe "Party", ->
|
||||
expect(_group.quest.key).to.equal "vice3"
|
||||
expect(_group.quest.active).to.equal false
|
||||
request.post(baseURL + "/groups/" + group._id + "/questAccept").set("X-API-User", party[0]._id).set("X-API-Key", party[0].apiToken).end ->
|
||||
request.post(baseURL + "/groups/" + group._id + "/questAccept").set("X-API-User", party[1]._id).set("X-API-Key", party[1].apiToken).end (res) ->
|
||||
request.post(baseURL + "/groups/" + group._id + "/questReject").set("X-API-User", party[2]._id).set("X-API-Key", party[2].apiToken).end (res) ->
|
||||
request.post(baseURL + "/groups/" + group._id + "/questAccept").set("X-API-User", party[1]._id).set("X-API-Key", party[1].apiToken).end (err, res) ->
|
||||
request.post(baseURL + "/groups/" + group._id + "/questReject").set("X-API-User", party[2]._id).set("X-API-Key", party[2].apiToken).end (err, res) ->
|
||||
group = res.body
|
||||
expect(group.quest.active).to.equal true
|
||||
cb()
|
||||
@@ -282,12 +282,12 @@ describe "Party", ->
|
||||
|
||||
it "Casts a spell", (done) ->
|
||||
mp = user.stats.mp
|
||||
request.get(baseURL + "/members/" + party[0]._id).end (res) ->
|
||||
request.get(baseURL + "/members/" + party[0]._id).end (err, res) ->
|
||||
party[0] = res.body
|
||||
request.post(baseURL + "/user/class/cast/snowball?targetType=user&targetId=" + party[0]._id).end (res) ->
|
||||
request.post(baseURL + "/user/class/cast/snowball?targetType=user&targetId=" + party[0]._id).end (err, res) ->
|
||||
|
||||
#expect(res.body.stats.mp).to.be.below(mp);
|
||||
request.get(baseURL + "/members/" + party[0]._id).end (res) ->
|
||||
request.get(baseURL + "/members/" + party[0]._id).end (err, res) ->
|
||||
member = res.body
|
||||
expect(member.achievements.snowball).to.equal 1
|
||||
expect(member.stats.buffs.snowball).to.exist
|
||||
@@ -295,18 +295,18 @@ describe "Party", ->
|
||||
expect(_.size(difference)).to.equal 2
|
||||
|
||||
# level up user so str is > 0
|
||||
request.put(baseURL + "/user").send("stats.lvl": 5).end (res) ->
|
||||
request.put(baseURL + "/user").send("stats.lvl": 5).end (err, res) ->
|
||||
|
||||
# Refill mana so user can cast
|
||||
request.put(baseURL + "/user").send("stats.mp": 100).end (res) ->
|
||||
request.post(baseURL + "/user/class/cast/valorousPresence?targetType=party").end (res) ->
|
||||
request.get(baseURL + "/members/" + member._id).end (res) ->
|
||||
request.put(baseURL + "/user").send("stats.mp": 100).end (err, res) ->
|
||||
request.post(baseURL + "/user/class/cast/valorousPresence?targetType=party").end (err, res) ->
|
||||
request.get(baseURL + "/members/" + member._id).end (err, res) ->
|
||||
expect(res.body.stats.buffs.str).to.be.above 0
|
||||
expect(diff(res.body, member).length).to.equal 1
|
||||
done()
|
||||
|
||||
it "Doesn't include people who aren't participating", (done) ->
|
||||
request.get(baseURL + "/groups/" + group._id).end (res) ->
|
||||
request.get(baseURL + "/groups/" + group._id).end (err, res) ->
|
||||
expect(_.size(res.body.quest.members)).to.equal 3
|
||||
done()
|
||||
|
||||
@@ -325,7 +325,7 @@ describe "Party", ->
|
||||
done()
|
||||
|
||||
xit "Hurts the boss", (done) ->
|
||||
request.post(baseURL + "/user/batch-update").end (res) ->
|
||||
request.post(baseURL + "/user/batch-update").end (err, res) ->
|
||||
user = res.body
|
||||
up = user.party.quest.progress.up
|
||||
expect(up).to.be.above 0
|
||||
@@ -344,10 +344,10 @@ describe "Party", ->
|
||||
body:
|
||||
lastCron: moment().subtract(1, "days")
|
||||
}
|
||||
]).end (res) ->
|
||||
]).end (err, res) ->
|
||||
expect(res.body.party.quest.progress.up).to.be.above up
|
||||
request.post(baseURL + "/user/batch-update").end ->
|
||||
request.get(baseURL + "/groups/party").end (res) ->
|
||||
request.get(baseURL + "/groups/party").end (err, res) ->
|
||||
|
||||
# Check boss damage
|
||||
async.waterfall [
|
||||
@@ -419,7 +419,7 @@ describe "Party", ->
|
||||
cb()
|
||||
|
||||
(cb) ->
|
||||
request.post(baseURL + "/user/batch-update").end (res) ->
|
||||
request.post(baseURL + "/user/batch-update").end (err, res) ->
|
||||
cb null, res.body
|
||||
|
||||
(_user, cb) ->
|
||||
@@ -15,7 +15,7 @@ describe "Push-Notifications", ->
|
||||
it "Registers a DeviceID", (done) ->
|
||||
request.post(baseURL + "/user/pushDevice").send(
|
||||
{ regId: "123123", type: "android"}
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
|
||||
User.findOne
|
||||
@@ -11,9 +11,9 @@ describe "Score", ->
|
||||
request.post(baseURL + "/user/tasks/withUp/up").send(
|
||||
type: "todo"
|
||||
text: "withUp"
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
request.get(baseURL + "/user/tasks/withUp").end (res) ->
|
||||
request.get(baseURL + "/user/tasks/withUp").end (err, res) ->
|
||||
upTodo = res.body
|
||||
expect(upTodo.completed).to.equal true
|
||||
done()
|
||||
@@ -22,9 +22,9 @@ describe "Score", ->
|
||||
request.post(baseURL + "/user/tasks/withDown/down").send(
|
||||
type: "todo"
|
||||
text: "withDown"
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
request.get(baseURL + "/user/tasks/withDown").end (res) ->
|
||||
request.get(baseURL + "/user/tasks/withDown").end (err, res) ->
|
||||
downTodo = res.body
|
||||
expect(downTodo.completed).to.equal false
|
||||
done()
|
||||
@@ -34,9 +34,9 @@ describe "Score", ->
|
||||
type: "todo"
|
||||
text: "withUpWithComplete"
|
||||
completed: false
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
request.get(baseURL + "/user/tasks/withUpWithComplete").end (res) ->
|
||||
request.get(baseURL + "/user/tasks/withUpWithComplete").end (err, res) ->
|
||||
upTodo = res.body
|
||||
expect(upTodo.completed).to.equal true
|
||||
done()
|
||||
@@ -46,9 +46,9 @@ describe "Score", ->
|
||||
type: "todo"
|
||||
text: "withDownWithUncomplete"
|
||||
completed: true
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
request.get(baseURL + "/user/tasks/withDownWithUncomplete").end (res) ->
|
||||
request.get(baseURL + "/user/tasks/withDownWithUncomplete").end (err, res) ->
|
||||
downTodo = res.body
|
||||
expect(downTodo.completed).to.equal false
|
||||
done()
|
||||
@@ -58,13 +58,13 @@ describe "Score", ->
|
||||
request.post(baseURL + "/user/tasks").send(
|
||||
type: "todo"
|
||||
text: "Sample Todo"
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
unCompletedTodo = res.body
|
||||
expect(unCompletedTodo.completed).to.equal false
|
||||
request.post(baseURL + "/user/tasks/"+unCompletedTodo._id+"/up").end (res) ->
|
||||
request.post(baseURL + "/user/tasks/"+unCompletedTodo._id+"/up").end (err, res) ->
|
||||
expectCode res, 200
|
||||
request.get(baseURL + "/user/tasks/"+unCompletedTodo._id).end (res) ->
|
||||
request.get(baseURL + "/user/tasks/"+unCompletedTodo._id).end (err, res) ->
|
||||
unCompletedTodo = res.body
|
||||
expect(unCompletedTodo.completed).to.equal true
|
||||
done()
|
||||
@@ -74,13 +74,13 @@ describe "Score", ->
|
||||
type: "todo"
|
||||
text: "Sample Todo"
|
||||
completed: true
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
completedTodo = res.body
|
||||
expect(completedTodo.completed).to.equal true
|
||||
request.post(baseURL + "/user/tasks/"+completedTodo._id+"/down").end (res) ->
|
||||
request.post(baseURL + "/user/tasks/"+completedTodo._id+"/down").end (err, res) ->
|
||||
expectCode res, 200
|
||||
request.get(baseURL + "/user/tasks/"+completedTodo._id).end (res) ->
|
||||
request.get(baseURL + "/user/tasks/"+completedTodo._id).end (err, res) ->
|
||||
completedTodo = res.body
|
||||
expect(completedTodo.completed).to.equal false
|
||||
done()
|
||||
@@ -91,9 +91,9 @@ describe "Score", ->
|
||||
type: "habit"
|
||||
text: "testTitle"
|
||||
completed: true
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
request.get(baseURL + "/user/tasks/habitWithUp").end (res) ->
|
||||
request.get(baseURL + "/user/tasks/habitWithUp").end (err, res) ->
|
||||
upHabit = res.body
|
||||
expect(upHabit.value).to.be.at.least(1)
|
||||
expect(upHabit.type).to.equal("habit")
|
||||
@@ -105,9 +105,9 @@ describe "Score", ->
|
||||
type: "habit"
|
||||
text: "testTitle"
|
||||
completed: true
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
request.get(baseURL + "/user/tasks/habitWithDown").end (res) ->
|
||||
request.get(baseURL + "/user/tasks/habitWithDown").end (err, res) ->
|
||||
downHabit = res.body
|
||||
expect(downHabit.value).to.have.at.most(-1)
|
||||
expect(downHabit.type).to.equal("habit")
|
||||
@@ -31,7 +31,7 @@ describe "Todos", ->
|
||||
body:
|
||||
type: "todo"
|
||||
}
|
||||
]).end (res) ->
|
||||
]).end (err, res) ->
|
||||
expectCode res, 200
|
||||
# Expect number of todos to be 3 greater than the number the user started with
|
||||
expect(_.size(res.body.todos)).to.equal numTasks + 3
|
||||
@@ -56,7 +56,7 @@ describe "Todos", ->
|
||||
direction: "up"
|
||||
id: res.body.todos[2].id
|
||||
}
|
||||
]).end (res) ->
|
||||
]).end (err, res) ->
|
||||
expectCode res, 200
|
||||
expect(_.size(res.body.todos)).to.equal numTasks
|
||||
request.post(baseURL + "/user/batch-update?_v=997").send([
|
||||
@@ -76,7 +76,7 @@ describe "Todos", ->
|
||||
body:
|
||||
dateCompleted: moment().subtract(4, "days")
|
||||
}
|
||||
]).end (res) ->
|
||||
]).end (err, res) ->
|
||||
# Expect todos to be 2 less than the total count
|
||||
expect(_.size(res.body.todos)).to.equal numTasks - 2
|
||||
done()
|
||||
@@ -89,7 +89,7 @@ describe "Todos", ->
|
||||
request.post(baseURL + "/user/tasks").send(
|
||||
type: "todo"
|
||||
text: "Sample Todo"
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
todo = res.body
|
||||
expect(todo.text).to.equal "Sample Todo"
|
||||
@@ -110,10 +110,10 @@ describe "Todos", ->
|
||||
}
|
||||
request.post(baseURL + "/user/tasks").send(
|
||||
original_todo
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
request.post(baseURL + "/user/tasks").send(
|
||||
duplicate_id_todo
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 409
|
||||
expect(res.body.err).to.eql('A task with that ID already exists.')
|
||||
done()
|
||||
@@ -122,7 +122,7 @@ describe "Todos", ->
|
||||
it "Does not update id of todo", (done) ->
|
||||
request.put(baseURL + "/user/tasks/" + todo.id).send(
|
||||
id: "a-new-id"
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
updateTodo = res.body
|
||||
expect(updateTodo.id).to.equal todo.id
|
||||
@@ -131,7 +131,7 @@ describe "Todos", ->
|
||||
it "Does not update type of todo", (done) ->
|
||||
request.put(baseURL + "/user/tasks/" + todo.id).send(
|
||||
type: "habit"
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
updateTodo = res.body
|
||||
expect(updateTodo.type).to.equal todo.type
|
||||
@@ -144,7 +144,7 @@ describe "Todos", ->
|
||||
priority: 1.5
|
||||
value: 5
|
||||
notes: "Some notes"
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
todo = res.body
|
||||
expect(todo.text).to.equal "Changed Title"
|
||||
@@ -157,7 +157,7 @@ describe "Todos", ->
|
||||
describe "Deleting todos", ->
|
||||
it "Does delete todo", (done) ->
|
||||
request.del(baseURL + "/user/tasks/" + todo.id).send(
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 200
|
||||
body = res.body
|
||||
expect(body).to.be.empty
|
||||
@@ -165,7 +165,7 @@ describe "Todos", ->
|
||||
|
||||
it "Does not delete already deleted todo", (done) ->
|
||||
request.del(baseURL + "/user/tasks/" + todo.id).send(
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 404
|
||||
body = res.body
|
||||
expect(body.err).to.equal "Task not found."
|
||||
@@ -178,7 +178,7 @@ describe "Todos", ->
|
||||
priority: 1
|
||||
value: 4
|
||||
notes: "Other notes"
|
||||
).end (res) ->
|
||||
).end (err, res) ->
|
||||
expectCode res, 404
|
||||
body = res.body
|
||||
expect(body.err).to.equal "Task not found."
|
||||
@@ -5,30 +5,6 @@ app = require("../../website/src/server")
|
||||
|
||||
describe "Users", ->
|
||||
|
||||
describe "GET /user without token or user id", ->
|
||||
|
||||
it "/api/v2/user", (done) ->
|
||||
request
|
||||
.get(baseURL + "/user")
|
||||
.set("Accept", "application/json")
|
||||
.set("X-API-User", '')
|
||||
.set("X-API-Key", '')
|
||||
.end (res) ->
|
||||
expect(res.statusCode).to.equal 401
|
||||
expect(res.body.err).to.equal "You must include a token and uid (user id) in your request"
|
||||
done()
|
||||
|
||||
describe "GET /user with token or user id", ->
|
||||
|
||||
before (done) ->
|
||||
registerNewUser(done, true)
|
||||
|
||||
it "/api/v2/user", (done) ->
|
||||
request.get(baseURL + "/user").set("Accept", "application/json").end (res) ->
|
||||
expect(res.statusCode).to.equal 200
|
||||
expect(res.body._id).to.equal user._id
|
||||
done()
|
||||
|
||||
describe "Deleting Users", ->
|
||||
|
||||
before (done) ->
|
||||
@@ -46,10 +22,10 @@ describe "Users", ->
|
||||
request.del(baseURL + "/user")
|
||||
.set("X-API-User", userToDelete._id)
|
||||
.set("X-API-Key", userToDelete.apiToken)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
request.get(baseURL + "/user/" + userToDelete._id)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 404
|
||||
cb()
|
||||
|
||||
@@ -80,7 +56,7 @@ describe "Users", ->
|
||||
)
|
||||
.set("X-API-User", userToDelete._id)
|
||||
.set("X-API-Key", userToDelete.apiToken)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
guildToHaveNewLeader = res.body
|
||||
expect(guildToHaveNewLeader.leader).to.eql(userToDelete._id)
|
||||
@@ -90,7 +66,7 @@ describe "Users", ->
|
||||
inviteURL = baseURL + "/groups/" + guildToHaveNewLeader._id + "/invite"
|
||||
request.post(inviteURL)
|
||||
.send( uuids: [userToBecomeLeader._id])
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
cb()
|
||||
|
||||
@@ -98,7 +74,7 @@ describe "Users", ->
|
||||
request.post(baseURL + "/groups/" + guildToHaveNewLeader._id + "/join")
|
||||
.set("X-API-User", userToBecomeLeader._id)
|
||||
.set("X-API-Key", userToBecomeLeader.apiToken)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
cb()
|
||||
|
||||
@@ -106,7 +82,7 @@ describe "Users", ->
|
||||
request.del(baseURL + "/user")
|
||||
.set("X-API-User", userToDelete._id)
|
||||
.set("X-API-Key", userToDelete.apiToken)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
cb()
|
||||
|
||||
@@ -114,7 +90,7 @@ describe "Users", ->
|
||||
request.get(baseURL + "/groups/" + guildToHaveNewLeader._id)
|
||||
.set("X-API-User", userToBecomeLeader._id)
|
||||
.set("X-API-Key", userToBecomeLeader.apiToken)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
g = res.body
|
||||
userInGroup = _.find(g.members, (member) -> return member._id == userToDelete._id; )
|
||||
@@ -138,7 +114,7 @@ describe "Users", ->
|
||||
name: "TestPrivateGroup"
|
||||
type: "party"
|
||||
)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
party = res.body
|
||||
cb()
|
||||
@@ -148,7 +124,7 @@ describe "Users", ->
|
||||
name: "TestPrivateGroup"
|
||||
type: "guild"
|
||||
)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
guild = res.body
|
||||
cb()
|
||||
@@ -167,7 +143,7 @@ describe "Users", ->
|
||||
inviteURL = baseURL + "/groups/" + party._id + "/invite"
|
||||
request.post(inviteURL)
|
||||
.send( uuids: [userToDelete._id])
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
cb()
|
||||
|
||||
@@ -175,7 +151,7 @@ describe "Users", ->
|
||||
inviteURL = baseURL + "/groups/" + guild._id + "/invite"
|
||||
request.post(inviteURL)
|
||||
.send( uuids: [userToDelete._id])
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
cb()
|
||||
|
||||
@@ -183,7 +159,7 @@ describe "Users", ->
|
||||
request.post(baseURL + "/groups/" + party._id + "/join")
|
||||
.set("X-API-User", userToDelete._id)
|
||||
.set("X-API-Key", userToDelete.apiToken)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
cb()
|
||||
|
||||
@@ -191,7 +167,7 @@ describe "Users", ->
|
||||
request.post(baseURL + "/groups/" + guild._id + "/join")
|
||||
.set("X-API-User", userToDelete._id)
|
||||
.set("X-API-Key", userToDelete.apiToken)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
cb()
|
||||
|
||||
@@ -199,13 +175,13 @@ describe "Users", ->
|
||||
request.del(baseURL + "/user")
|
||||
.set("X-API-User", userToDelete._id)
|
||||
.set("X-API-Key", userToDelete.apiToken)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
cb()
|
||||
|
||||
(cb) ->
|
||||
request.get(baseURL + "/groups/" + party._id)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
g = res.body
|
||||
userInGroup = _.find(g.members, (member) -> return member._id == userToDelete._id; )
|
||||
@@ -214,7 +190,7 @@ describe "Users", ->
|
||||
|
||||
(cb) ->
|
||||
request.get(baseURL + "/groups/" + guild._id)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
g = res.body
|
||||
userInGroup = _.find(g.members, (member) -> return member._id == userToDelete._id; );
|
||||
@@ -235,7 +211,7 @@ describe "Users", ->
|
||||
inviteURL = baseURL + "/groups/" + party._id + "/invite"
|
||||
request.post(inviteURL)
|
||||
.send( uuids: [userToDeleteInvites._id])
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
cb()
|
||||
|
||||
@@ -243,7 +219,7 @@ describe "Users", ->
|
||||
inviteURL = baseURL + "/groups/" + guild._id + "/invite"
|
||||
request.post(inviteURL)
|
||||
.send( uuids: [userToDeleteInvites._id])
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
cb()
|
||||
|
||||
@@ -251,13 +227,13 @@ describe "Users", ->
|
||||
request.del(baseURL + "/user")
|
||||
.set("X-API-User", userToDeleteInvites._id)
|
||||
.set("X-API-Key", userToDeleteInvites.apiToken)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
cb()
|
||||
|
||||
(cb) ->
|
||||
request.get(baseURL + "/groups/" + party._id)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
g = res.body
|
||||
userInviteForGroup = _.find(g.invites, (invite) -> return invite._id == userToDeleteInvites._id; )
|
||||
@@ -266,7 +242,7 @@ describe "Users", ->
|
||||
|
||||
(cb) ->
|
||||
request.get(baseURL + "/groups/" + guild._id)
|
||||
.end (res) ->
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
g = res.body
|
||||
userInviteForGroup = _.find(g.invites, (invite) -> return invite._id == userToDeleteInvites._id; )
|
||||
@@ -1,32 +1,103 @@
|
||||
# API Tests
|
||||
# So you want to write API integration tests?
|
||||
|
||||
Our API tests are written in [coffeescript](http://coffeescript.org/) using the [Mocha testing framework](http://mochajs.org/).
|
||||
That's great! This README will serve as a quick primer for style conventions and practices for these tests.
|
||||
|
||||
There's a variety of ways to run the tests:
|
||||
## What is this?
|
||||
|
||||
These are integration tests for the Habitica API. They are performed by making REST requests to the API's endpoints and asserting on the data that is returned.
|
||||
|
||||
If the javascript looks weird to you, that's because it's written in [ES2015](http://www.ecma-international.org/ecma-262/6.0/) and transpiled by [Babel](https://babeljs.io/docs/learn-es2015/).
|
||||
|
||||
## How to run the tests
|
||||
|
||||
First, install gulp.
|
||||
|
||||
```bash
|
||||
# Individually
|
||||
mocha test/api/name_of_test.coffee
|
||||
# The entire collection of api tests
|
||||
mocha test/api
|
||||
# As part of the whole test suite
|
||||
npm test
|
||||
$ npm install -g gulp
|
||||
```
|
||||
|
||||
### Modules
|
||||
To run the api tests, make sure the mongo db is up and running and then type this on the command line:
|
||||
|
||||
Some modules are declared in the [api-helper.coffee](api-helper.coffee) file for use in any of the api tests:
|
||||
```bash
|
||||
$ gulp test:api
|
||||
```
|
||||
|
||||
* `moment` - time manipulation
|
||||
* `async` - run async processes, good for before blocks
|
||||
* `lodash (_)` - many utilities
|
||||
* `shared` - generate uuids
|
||||
* `expect` - making assertions
|
||||
* `User` - look up a User in the db
|
||||
It may take a little while to get going, since it requires the web server to start up before the tests can run.
|
||||
|
||||
### Helper Methods
|
||||
You can also run a watch command for the api tests. This will allow the tests to re-run automatically when you make changes in the `/test/api/` or `/website/src/` directories.
|
||||
|
||||
There are helper methods declared in the [api-helper.coffee](api-helper.coffee) file. Some useful methods contained there:
|
||||
```bash
|
||||
$ gulp test:api:watch
|
||||
```
|
||||
|
||||
* `registerNewUser(callback, main)` - Theres a global user variable that gets overwritten with the new user whenever you call `registerNewUser` unless you pass false in as the second argument.
|
||||
* `registerManyUsers(number, callback)` - Good for testing things that require many users. The callback function returns new users as and array in the second argument.
|
||||
One caveat. If you have a severe syntax error in your files, the tests may fail to run, but they won't alert you that they are not running. If you ever find your test hanging for a while, run this to get the stackstrace. Once you've fixed the problem, you can resume running the watch comand.
|
||||
|
||||
```bash
|
||||
$ gulp test:api:safe
|
||||
```
|
||||
|
||||
## Structure
|
||||
|
||||
Each top level route has it's own directory. So, all the routes that begin with `/groups/` live in `/test/api/groups/`.
|
||||
|
||||
Each test should:
|
||||
|
||||
* encompase a single route
|
||||
* begin with the REST parameter for the route
|
||||
* display the full name of the route, swapping out `/` for `_`
|
||||
* end with test.js
|
||||
|
||||
So, for the `POST` route `/groups/:id/leave`, it would be
|
||||
|
||||
```bash
|
||||
POST-groups_id_leave.test.js
|
||||
```
|
||||
|
||||
## Promises
|
||||
|
||||
To mitigate [callback hell](http://callbackhell.com/) :imp:, we've written helper methods that [return promises](https://babeljs.io/docs/learn-es2015/#promises). This makes it very easy to chain together commands. All you need to do to make a subsequent request is return another promise and then call `.then((result) => {})` on the surrounding block, like so:
|
||||
|
||||
```js
|
||||
it('does something', () => {
|
||||
let request;
|
||||
return generateUser().then((user) => { // We return the initial promise so this test can be run asyncronously
|
||||
request = requester(user);
|
||||
return request.post('/groups', {
|
||||
type: 'party',
|
||||
});
|
||||
}).then((party) => { // the result of the promise above is the argument of the function
|
||||
return request.put(`/groups/${party._id}`, {
|
||||
name: 'My party',
|
||||
});
|
||||
}).then((result) => {
|
||||
return request.get('/groups/party');
|
||||
}).then((party) => {
|
||||
expect(party.name).to.eql('My party');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
If the test is simple, you can use the [chai-as-promised](http://chaijs.com/plugins/chai-as-promised) `return expect(somePromise).to.eventually` syntax to make your assertion.
|
||||
|
||||
```js
|
||||
it('makes the party creator the leader automatically', () => {
|
||||
let api = requester(user);
|
||||
return expect(request.post('/groups', {
|
||||
type: 'party',
|
||||
})).to.eventually.have.deep.property('leader._id', user._id);
|
||||
});
|
||||
```
|
||||
|
||||
If the test is checking that the request returns an error, use the `rejectedWith` syntax.
|
||||
|
||||
```js
|
||||
it('returns an error', () => {
|
||||
let api = requester(user);
|
||||
return expect(request.get('/groups/id-of-a-party-that-user-does-not-belong-to'))
|
||||
.to.be.rejectedWith('Group not found or you don\'t have access.');
|
||||
});
|
||||
```
|
||||
|
||||
## Questions?
|
||||
|
||||
Ask in the [Aspiring Coder's Guild](https://habitica.com/#/options/groups/guilds/68d4a01e-db97-4786-8ee3-05d612c5af6f)!
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
##############################
|
||||
# Global modules
|
||||
##############################
|
||||
superagentDefaults = require("superagent-defaults")
|
||||
global.request = superagentDefaults()
|
||||
|
||||
global.mongoose = require("mongoose")
|
||||
global.moment = require("moment")
|
||||
global.async = require("async")
|
||||
global._ = require("lodash")
|
||||
global.shared = require("../../common")
|
||||
global.User = require("../../website/src/models/user").model
|
||||
|
||||
global.chai = require("chai")
|
||||
chai.use(require("sinon-chai"))
|
||||
global.expect = chai.expect
|
||||
|
||||
##############################
|
||||
# Nconf config
|
||||
##############################
|
||||
path = require("path")
|
||||
global.conf = require("nconf")
|
||||
conf.argv().env().file(file: path.join(__dirname, "../config.json")).defaults()
|
||||
conf.set "PORT", "1337"
|
||||
|
||||
##############################
|
||||
# Node ENV and global variables
|
||||
##############################
|
||||
process.env.NODE_DB_URI = "mongodb://localhost/habitrpg_test"
|
||||
global.baseURL = "http://localhost:" + conf.get("PORT") + "/api/v2"
|
||||
global.user = undefined
|
||||
|
||||
##############################
|
||||
# Helper Methods
|
||||
##############################
|
||||
global.expectCode = (res, code) ->
|
||||
expect(res.body.err).to.not.exist if code is 200
|
||||
expect(res.statusCode).to.equal code
|
||||
|
||||
global.registerNewUser = (cb, main) ->
|
||||
main = true unless main?
|
||||
randomID = shared.uuid()
|
||||
username = password = randomID if main
|
||||
request
|
||||
.post(baseURL + "/register")
|
||||
.set("Accept", "application/json")
|
||||
.set("X-API-User", null)
|
||||
.set("X-API-Key", null)
|
||||
.send
|
||||
username: randomID
|
||||
password: randomID
|
||||
confirmPassword: randomID
|
||||
email: randomID + "@gmail.com"
|
||||
.end (res) ->
|
||||
return cb(null, res.body) unless main
|
||||
_id = res.body._id
|
||||
apiToken = res.body.apiToken
|
||||
User.findOne
|
||||
_id: _id
|
||||
apiToken: apiToken
|
||||
, (err, _user) ->
|
||||
expect(err).to.not.be.ok
|
||||
global.user = _user
|
||||
request
|
||||
.set("Accept", "application/json")
|
||||
.set("X-API-User", _id)
|
||||
.set("X-API-Key", apiToken)
|
||||
cb null, res.body
|
||||
|
||||
global.registerManyUsers = (number, callback) ->
|
||||
async.times number, (n, next) ->
|
||||
registerNewUser (err, user) ->
|
||||
next(err, user)
|
||||
, false
|
||||
, (err, users) ->
|
||||
callback(err, users)
|
||||
@@ -1,500 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
diff = require("deep-diff")
|
||||
|
||||
Group = require("../../website/src/models/group").model
|
||||
app = require("../../website/src/server")
|
||||
|
||||
describe "Guilds", ->
|
||||
context "creating groups", ->
|
||||
before (done) ->
|
||||
registerNewUser ->
|
||||
User.findByIdAndUpdate user._id,
|
||||
$set:
|
||||
"balance": 40
|
||||
, (err, _user) ->
|
||||
done()
|
||||
, true
|
||||
|
||||
it "can create a public guild", (done) ->
|
||||
request.post(baseURL + "/groups").send(
|
||||
name: "TestGroup"
|
||||
type: "guild",
|
||||
privacy: "public"
|
||||
).end (res) ->
|
||||
expectCode res, 200
|
||||
guild = res.body
|
||||
expect(guild.members.length).to.equal 1
|
||||
expect(guild.leader).to.equal user._id
|
||||
done()
|
||||
|
||||
it "can create a private guild", (done) ->
|
||||
request.post(baseURL + "/groups").send(
|
||||
name: "TestGroup"
|
||||
type: "guild",
|
||||
privacy: "private"
|
||||
).end (res) ->
|
||||
expectCode res, 200
|
||||
guild = res.body
|
||||
expect(guild.members.length).to.equal 1
|
||||
expect(guild.leader).to.equal user._id
|
||||
done()
|
||||
|
||||
it "prevents user from creating a guild when the user has 0 gems", (done) ->
|
||||
registerNewUser (err, user_with_0_gems) ->
|
||||
request.post(baseURL + "/groups").send(
|
||||
name: "TestGroup"
|
||||
type: "guild",
|
||||
)
|
||||
.set("X-API-User", user_with_0_gems._id)
|
||||
.set("X-API-Key", user_with_0_gems.apiToken)
|
||||
.end (res) ->
|
||||
expectCode res, 401
|
||||
done()
|
||||
, false
|
||||
|
||||
context "get guilds", ->
|
||||
guild = undefined
|
||||
|
||||
beforeEach (done)->
|
||||
request.post(baseURL + "/groups").send(
|
||||
name: "TestGroup2"
|
||||
type: "guild"
|
||||
).end (res) ->
|
||||
guild = res.body
|
||||
done()
|
||||
|
||||
it "can find a guild", (done) ->
|
||||
request.get(baseURL + "/groups/" + guild._id)
|
||||
.end (res) ->
|
||||
expectCode res, 200
|
||||
expect(res.body._id).to.equal res.body._id
|
||||
done()
|
||||
|
||||
it "transforms members array to an arrray of user objects", (done) ->
|
||||
request.get(baseURL + "/groups/" + guild._id)
|
||||
.end (res) ->
|
||||
expectCode res, 200
|
||||
members = res.body.members
|
||||
# @TODO: would be more instructive if it had more members in guild :(
|
||||
_(members).each (member) ->
|
||||
expect(member).to.be.an 'object'
|
||||
expect(member.profile.name).to.exist
|
||||
done()
|
||||
|
||||
it "transforms leader id to a user object", (done) ->
|
||||
request.get(baseURL + "/groups/" + guild._id)
|
||||
.end (res) ->
|
||||
expectCode res, 200
|
||||
leader = res.body.leader
|
||||
expect(leader).to.be.an 'object'
|
||||
expect(leader.profile.name).to.exist
|
||||
done()
|
||||
|
||||
it "can list guilds", (done) ->
|
||||
request.get(baseURL + "/groups").send()
|
||||
.end (res) ->
|
||||
expectCode res, 200
|
||||
guild = res.body[0]
|
||||
expect(guild).to.exist
|
||||
done()
|
||||
|
||||
context "updating groups", ->
|
||||
groupToUpdate = undefined
|
||||
before (done) ->
|
||||
request.post(baseURL + "/groups").send(
|
||||
name: "TestGroup"
|
||||
type: "guild"
|
||||
description: "notUpdatedDesc"
|
||||
).end (res) ->
|
||||
groupToUpdate = res.body
|
||||
done()
|
||||
|
||||
it "prevents user from updating a party when they aren't the leader", (done) ->
|
||||
registerNewUser (err, tmpUser) ->
|
||||
request.post(baseURL + "/groups/" + groupToUpdate._id).send(
|
||||
name: "TestGroupName"
|
||||
description: "updatedDesc"
|
||||
)
|
||||
.set("X-API-User", tmpUser._id)
|
||||
.set("X-API-Key", tmpUser.apiToken)
|
||||
.end (res) ->
|
||||
expectCode res, 401
|
||||
expect(res.body.err).to.equal "Only the group leader can update the group!"
|
||||
done()
|
||||
, false
|
||||
|
||||
it "allows user to update a group", (done) ->
|
||||
request.post(baseURL + "/groups/" + groupToUpdate._id).send(
|
||||
description: "updatedDesc"
|
||||
)
|
||||
.end (res) ->
|
||||
expectCode res, 204
|
||||
request.get(baseURL + "/groups/" + groupToUpdate._id).send()
|
||||
.end (res) ->
|
||||
updatedGroup = res.body
|
||||
expect(updatedGroup.description).to.equal "updatedDesc"
|
||||
done()
|
||||
|
||||
context "leaving groups", ->
|
||||
it "can leave a guild", (done) ->
|
||||
guildToLeave = undefined
|
||||
request.post(baseURL + "/groups").send(
|
||||
name: "TestGroupToLeave"
|
||||
type: "guild"
|
||||
).end (res) ->
|
||||
guildToLeave = res.body
|
||||
request.post(baseURL + "/groups/" + guildToLeave._id + "/leave")
|
||||
.send()
|
||||
.end (res) ->
|
||||
expectCode res, 204
|
||||
done()
|
||||
|
||||
it "deletes a group when the last member leaves", (done) ->
|
||||
groupToDeleteAfterLeave = undefined
|
||||
request.post(baseURL + "/groups").send(
|
||||
name: "TestGroupToDeleteAfteLeave"
|
||||
type: "guild"
|
||||
privacy: "private"
|
||||
).end (res) ->
|
||||
groupToDeleteAfterLeave = res.body
|
||||
async.waterfall [
|
||||
(cb) ->
|
||||
request.post(baseURL + "/groups/" + groupToDeleteAfterLeave._id + "/leave")
|
||||
.end (res) ->
|
||||
expectCode res, 204
|
||||
cb()
|
||||
|
||||
(cb) ->
|
||||
request.post(baseURL + "/groups/" + groupToDeleteAfterLeave._id)
|
||||
.end (res) ->
|
||||
expectCode res, 404
|
||||
cb()
|
||||
], done
|
||||
|
||||
it "deletes all invites to a group (guild) when the last member leaves", (done) ->
|
||||
groupToDeleteAfterLeave = undefined
|
||||
userToRemoveInvite = undefined
|
||||
request.post(baseURL + "/groups").send(
|
||||
name: "TestGroupToDeleteAfterLeave"
|
||||
type: "guild"
|
||||
privacy: "private"
|
||||
).end (res) ->
|
||||
groupToDeleteAfterLeave = res.body
|
||||
async.waterfall [
|
||||
(cb) ->
|
||||
registerManyUsers 1, cb
|
||||
|
||||
(_members, cb) ->
|
||||
userToRemoveInvite = _members[0]
|
||||
inviteURL = baseURL + "/groups/" + groupToDeleteAfterLeave._id + "/invite"
|
||||
request.post(inviteURL).send(
|
||||
uuids: [userToRemoveInvite._id]
|
||||
)
|
||||
.end ->
|
||||
cb()
|
||||
|
||||
(cb) ->
|
||||
request.post(baseURL + "/groups/" + groupToDeleteAfterLeave._id + "/leave")
|
||||
.end (res) ->
|
||||
expectCode res, 204
|
||||
cb()
|
||||
|
||||
(cb) ->
|
||||
request.get(baseURL + '/user')
|
||||
.set("X-API-User", userToRemoveInvite._id)
|
||||
.set("X-API-Key", userToRemoveInvite.apiToken)
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
groupInvitation = _.find(res.body.invitations.guilds, {id: groupToDeleteAfterLeave._id})
|
||||
expect(groupInvitation).to.not.exist
|
||||
cb()
|
||||
|
||||
(cb) ->
|
||||
request.post(baseURL + "/groups/" + groupToDeleteAfterLeave._id)
|
||||
.end (res) ->
|
||||
expectCode res, 404
|
||||
cb()
|
||||
], done
|
||||
|
||||
it "deletes all invites to a group (party) when the last member leaves", (done) ->
|
||||
partyToDeleteAfterLeave = undefined
|
||||
userToRemovePartyInvite = undefined
|
||||
request.post(baseURL + "/groups").send(
|
||||
name: "TestPartyToDeleteAfterLeave"
|
||||
type: "party"
|
||||
).end (res) ->
|
||||
partyToDeleteAfterLeave = res.body
|
||||
async.waterfall [
|
||||
(cb) ->
|
||||
registerManyUsers 1, cb
|
||||
|
||||
(_members, cb) ->
|
||||
userToRemovePartyInvite = _members[0]
|
||||
inviteURL = baseURL + "/groups/" + partyToDeleteAfterLeave._id + "/invite"
|
||||
request.post(inviteURL).send(
|
||||
uuids: [userToRemovePartyInvite._id]
|
||||
)
|
||||
.end ->
|
||||
cb()
|
||||
|
||||
(cb) ->
|
||||
request.post(baseURL + "/groups/" + partyToDeleteAfterLeave._id + "/leave")
|
||||
.end (res) ->
|
||||
expectCode res, 204
|
||||
cb()
|
||||
|
||||
(cb) ->
|
||||
request.get(baseURL + '/user')
|
||||
.set("X-API-User", userToRemovePartyInvite._id)
|
||||
.set("X-API-Key", userToRemovePartyInvite.apiToken)
|
||||
.end (err, res) ->
|
||||
expectCode res, 200
|
||||
party = partyToDeleteAfterLeave
|
||||
partyInvitation = _.find(res.body.invitations.party, (invite) ->
|
||||
return invite == party._id
|
||||
)
|
||||
expect(partyInvitation).to.not.exist
|
||||
cb()
|
||||
|
||||
(cb) ->
|
||||
request.post(baseURL + "/groups/" + partyToDeleteAfterLeave._id)
|
||||
.end (res) ->
|
||||
expectCode res, 404
|
||||
cb()
|
||||
], done
|
||||
|
||||
context "removing users groups", ->
|
||||
it "allows guild leaders to remove a member (but not themselves)", (done) ->
|
||||
guildToRemoveMember = undefined
|
||||
members = undefined
|
||||
userToRemove = undefined
|
||||
request.post(baseURL + "/groups").send(
|
||||
name: "TestGuildToRemoveMember"
|
||||
type: "guild"
|
||||
).end (res) ->
|
||||
guildToRemoveMember = res.body
|
||||
#Add members to guild
|
||||
async.waterfall [
|
||||
(cb) ->
|
||||
registerManyUsers 1, cb
|
||||
|
||||
(_members, cb) ->
|
||||
userToRemove = _members[0]
|
||||
members = _members
|
||||
inviteURL = baseURL + "/groups/" + guildToRemoveMember._id + "/invite"
|
||||
request.post(inviteURL).send(
|
||||
uuids: [userToRemove._id]
|
||||
)
|
||||
.end ->
|
||||
cb()
|
||||
|
||||
(cb) ->
|
||||
request.post(baseURL + "/groups/" + guildToRemoveMember._id + "/join")
|
||||
.set("X-API-User", userToRemove._id)
|
||||
.set("X-API-Key", userToRemove.apiToken)
|
||||
.end (res) ->
|
||||
cb()
|
||||
(cb) ->
|
||||
request.post(baseURL + "/groups/" + guildToRemoveMember._id + "/removeMember?uuid=" + guildToRemoveMember.leader)
|
||||
.send().end (res) ->
|
||||
expectCode res, 401
|
||||
cb()
|
||||
|
||||
(cb) ->
|
||||
request.post(baseURL + "/groups/" + guildToRemoveMember._id + "/removeMember?uuid=" + userToRemove._id)
|
||||
.send().end (res) ->
|
||||
expectCode res, 204
|
||||
cb()
|
||||
|
||||
(cb) ->
|
||||
request.get(baseURL + "/groups/" + guildToRemoveMember._id)
|
||||
.send()
|
||||
.end (res) ->
|
||||
g = res.body
|
||||
userInGroup = _.find g.members, (member) -> return member._id == userToRemove._id
|
||||
expect(userInGroup).to.not.exist
|
||||
cb()
|
||||
|
||||
], done
|
||||
|
||||
describe "Private Guilds", ->
|
||||
guild = undefined
|
||||
before (done) ->
|
||||
request.post(baseURL + "/groups").send(
|
||||
name: "TestPrivateGroup"
|
||||
type: "guild"
|
||||
privacy: "private"
|
||||
).end (res) ->
|
||||
expectCode res, 200
|
||||
guild = res.body
|
||||
expect(guild.members.length).to.equal 1
|
||||
expect(guild.leader).to.equal user._id
|
||||
#Add members to guild
|
||||
async.waterfall [
|
||||
(cb) ->
|
||||
registerManyUsers 15, cb
|
||||
|
||||
(_members, cb) ->
|
||||
members = _members
|
||||
|
||||
joinGuild = (member, callback) ->
|
||||
request.post(baseURL + "/groups/" + guild._id + "/join")
|
||||
.set("X-API-User", member._id)
|
||||
.set("X-API-Key", member.apiToken)
|
||||
.end ->
|
||||
callback(null, null)
|
||||
|
||||
async.map members, joinGuild, (err, results) -> cb()
|
||||
|
||||
], done
|
||||
|
||||
it "includes user in private group member list when user is a member", (done) ->
|
||||
|
||||
request.get(baseURL + "/groups/" + guild._id)
|
||||
.end (res) ->
|
||||
g = res.body
|
||||
userInGroup = _.find g.members, (member) -> return member._id == user._id
|
||||
expect(userInGroup).to.exist
|
||||
done()
|
||||
|
||||
it "excludes user from viewing private group member list when user is not a member", (done) ->
|
||||
|
||||
request.post(baseURL + "/groups/" + guild._id + "/leave")
|
||||
.end (res) ->
|
||||
request.get(baseURL + "/groups/" + guild._id)
|
||||
.end (res) ->
|
||||
expect res, 404
|
||||
done()
|
||||
|
||||
describe "Public Guilds", ->
|
||||
before (done) ->
|
||||
async.waterfall [
|
||||
(cb) ->
|
||||
registerNewUser ->
|
||||
User.findByIdAndUpdate user._id, {$set: { "balance": 10 } }, (err, _user) ->
|
||||
cb()
|
||||
, true
|
||||
], done
|
||||
|
||||
context "joining groups", ->
|
||||
it "makes user a group leader when group is empty", (done) ->
|
||||
guildToEmptyAndAssignLeader = undefined
|
||||
members = undefined
|
||||
userToBecomeLeader = undefined
|
||||
request.post(baseURL + "/groups").send(
|
||||
name: "TestGuildToEmptyAndAssignLeader"
|
||||
type: "guild",
|
||||
privacy: "public"
|
||||
).end (res) ->
|
||||
guildToEmptyAndAssignLeader = res.body
|
||||
#Add members to guild
|
||||
async.waterfall [
|
||||
(cb) ->
|
||||
registerManyUsers 1, cb
|
||||
|
||||
(_members, cb) ->
|
||||
userToBecomeLeader = _members[0]
|
||||
members = _members
|
||||
inviteURL = baseURL + "/groups/" + guildToEmptyAndAssignLeader._id + "/invite"
|
||||
request.post(inviteURL).send(
|
||||
uuids: [userToBecomeLeader._id]
|
||||
)
|
||||
.end ->
|
||||
cb()
|
||||
|
||||
(cb) ->
|
||||
request.post(baseURL + "/groups/" + guildToEmptyAndAssignLeader._id + "/leave")
|
||||
.send()
|
||||
.end (res) ->
|
||||
expectCode res, 204
|
||||
cb()
|
||||
|
||||
(cb) ->
|
||||
request.post(baseURL + "/groups/" + guildToEmptyAndAssignLeader._id + "/join")
|
||||
.set("X-API-User", userToBecomeLeader._id)
|
||||
.set("X-API-Key", userToBecomeLeader.apiToken)
|
||||
.end (res) ->
|
||||
expectCode res, 200
|
||||
cb()
|
||||
|
||||
(cb) ->
|
||||
request.get(baseURL + "/groups/" + guildToEmptyAndAssignLeader._id)
|
||||
.set("X-API-User", userToBecomeLeader._id)
|
||||
.set("X-API-Key", userToBecomeLeader.apiToken)
|
||||
.send()
|
||||
.end (res) ->
|
||||
expectCode res, 200
|
||||
g = res.body
|
||||
expect(g.leader._id).to.equal(userToBecomeLeader._id)
|
||||
cb()
|
||||
|
||||
], done
|
||||
|
||||
context "viewing", ->
|
||||
guild = undefined
|
||||
before (done) ->
|
||||
async.waterfall [
|
||||
(cb) ->
|
||||
registerNewUser ->
|
||||
User.findByIdAndUpdate user._id, {$set: { "balance": 10 } }, (err, _user) ->
|
||||
cb()
|
||||
, true
|
||||
(cb) ->
|
||||
request.post(baseURL + "/groups").send(
|
||||
name: "TestPublicGroup"
|
||||
type: "guild"
|
||||
privacy: "public"
|
||||
).end (res) ->
|
||||
guild = res.body
|
||||
expect(guild.members.length).to.equal 1
|
||||
expect(guild.leader).to.equal user._id
|
||||
#Add members to guild
|
||||
cb()
|
||||
|
||||
(cb) ->
|
||||
registerManyUsers 15, cb
|
||||
|
||||
(_members, cb) ->
|
||||
members = _members
|
||||
|
||||
joinGuild = (member, callback) ->
|
||||
request.post(baseURL + "/groups/" + guild._id + "/join")
|
||||
.set("X-API-User", member._id)
|
||||
.set("X-API-Key", member.apiToken)
|
||||
.end ->
|
||||
callback(null, null)
|
||||
|
||||
async.map members, joinGuild, (err, results) -> cb()
|
||||
|
||||
], done
|
||||
|
||||
context "is a member", ->
|
||||
before (done) ->
|
||||
registerNewUser ->
|
||||
request.post(baseURL + "/groups/" + guild._id + "/join")
|
||||
.end (res)->
|
||||
done()
|
||||
, true
|
||||
|
||||
it "includes user in public group member list", (done) ->
|
||||
request.get(baseURL + "/groups/" + guild._id)
|
||||
.end (res) ->
|
||||
g = res.body
|
||||
expect(g.members.length).to.equal 15
|
||||
userInGroup = _.find g.members, (member) -> return member._id == user._id
|
||||
expect(userInGroup).to.exist
|
||||
done()
|
||||
|
||||
context "is not a member", ->
|
||||
before (done) ->
|
||||
registerNewUser done, true
|
||||
|
||||
it "excludes user in public group member list", (done) ->
|
||||
request.get(baseURL + "/groups/" + guild._id)
|
||||
.end (res) ->
|
||||
g = res.body
|
||||
expect(g.members.length).to.equal 15
|
||||
userInGroup = _.find g.members, (member) -> return member._id == user._id
|
||||
expect(userInGroup).to.not.exist
|
||||
done()
|
||||
@@ -0,0 +1,122 @@
|
||||
import {
|
||||
generateGroup,
|
||||
generateUser,
|
||||
resetHabiticaDB,
|
||||
requester,
|
||||
} from '../../helpers/api.helper';
|
||||
|
||||
describe('GET /groups', () => {
|
||||
const NUMBER_OF_PUBLIC_GUILDS = 3;
|
||||
const NUMBER_OF_USERS_GUILDS = 2;
|
||||
|
||||
let user, api;
|
||||
|
||||
before(() => {
|
||||
let leader, createdGroup;
|
||||
|
||||
// Set up a world with a mixture of public and private guilds
|
||||
// Invite user to a few of them
|
||||
return resetHabiticaDB().then(() => {
|
||||
return generateUser();
|
||||
}).then((_user) => {
|
||||
user = _user;
|
||||
|
||||
return generateUser({
|
||||
balance: 10,
|
||||
});
|
||||
}).then((_user) => {
|
||||
leader = _user;
|
||||
api = requester(leader);
|
||||
|
||||
let publicGuildWithUserAsMember = generateGroup(leader, {
|
||||
name: 'public guild - is member',
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
members: [leader._id, user._id],
|
||||
});
|
||||
|
||||
let publicGuildWithoutUserAsMember = generateGroup(leader, {
|
||||
name: 'public guild - is not member',
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
});
|
||||
|
||||
let privateGuildWithUserAsMember = generateGroup(leader, {
|
||||
name: 'private guild - is member',
|
||||
type: 'guild',
|
||||
privacy: 'private',
|
||||
members: [leader._id, user._id],
|
||||
});
|
||||
|
||||
let privateGuildWithoutUserAsMember = generateGroup(leader, {
|
||||
name: 'private guild - is not member',
|
||||
type: 'guild',
|
||||
privacy: 'private',
|
||||
});
|
||||
|
||||
let partyWithoutUserAsMember = generateGroup(leader, {
|
||||
name: 'party name',
|
||||
type: 'party',
|
||||
privacy: 'private',
|
||||
});
|
||||
|
||||
let promises = [
|
||||
publicGuildWithUserAsMember,
|
||||
publicGuildWithoutUserAsMember,
|
||||
privateGuildWithUserAsMember,
|
||||
privateGuildWithoutUserAsMember,
|
||||
partyWithoutUserAsMember,
|
||||
];
|
||||
|
||||
return Promise.all(promises);
|
||||
}).then((groups) => {
|
||||
api = requester(user);
|
||||
return api.post('/groups', {
|
||||
type: 'party',
|
||||
name: 'user\'s party',
|
||||
privacy: 'private',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('no query passed in', () => {
|
||||
|
||||
xit('lists all public guilds, the tavern, user\'s party, and any private guilds that user is a part of - TODO query includes duplicates - IE, tavern is included as tavern and part of public guilds. Refactor so this is not the case');
|
||||
});
|
||||
|
||||
context('tavern passed in as query', () => {
|
||||
|
||||
it('returns only the tavern', () => {
|
||||
return expect(api.get('/groups', null, {type: 'tavern'}))
|
||||
.to.eventually.have.a.lengthOf(1)
|
||||
.and.to.have.deep.property('[0]')
|
||||
.and.to.have.property('_id', 'habitrpg');
|
||||
});
|
||||
});
|
||||
|
||||
context('party passed in as query', () => {
|
||||
|
||||
it('returns only the user\'s party', () => {
|
||||
return expect(api.get('/groups', null, {type: 'party'}))
|
||||
.to.eventually.have.a.lengthOf(1)
|
||||
.and.to.have.deep.property('[0]')
|
||||
.and.to.have.property('leader', user._id);
|
||||
});
|
||||
});
|
||||
|
||||
context('public passed in as query', () => {
|
||||
|
||||
it('returns all public guilds', () => {
|
||||
return expect(api.get('/groups', null, {type: 'public'}))
|
||||
.to.eventually.have.a.lengthOf(NUMBER_OF_PUBLIC_GUILDS);
|
||||
});
|
||||
});
|
||||
|
||||
context('guilds passed in as query', () => {
|
||||
|
||||
it('returns all guilds user is a part of ', () => {
|
||||
return expect(api.get('/groups', null, {type: 'guilds'}))
|
||||
.to.eventually.have.a.lengthOf(NUMBER_OF_USERS_GUILDS);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,234 @@
|
||||
import {
|
||||
createAndPopulateGroup,
|
||||
generateUser,
|
||||
requester,
|
||||
} from '../../helpers/api.helper';
|
||||
import {
|
||||
find,
|
||||
each
|
||||
} from 'lodash';
|
||||
|
||||
describe('GET /groups/:id', () => {
|
||||
|
||||
let typesOfGroups = {};
|
||||
typesOfGroups['public guild'] = { type: 'guild', privacy: 'public' };
|
||||
typesOfGroups['private guild'] = { type: 'guild', privacy: 'private' };
|
||||
typesOfGroups['party'] = { type: 'party', privacy: 'private' };
|
||||
|
||||
each(typesOfGroups, (groupData, groupType) => {
|
||||
context(`Member of a ${groupType}`, () => {
|
||||
let leader, member, createdGroup;
|
||||
|
||||
before(() => {
|
||||
return createAndPopulateGroup({
|
||||
members: 30,
|
||||
groupDetails: {
|
||||
name: 'test guild',
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
},
|
||||
}).then((res) => {
|
||||
leader = res.leader;
|
||||
member = res.members[0];
|
||||
createdGroup = res.group;
|
||||
});
|
||||
});
|
||||
|
||||
it('returns the group object', () => {
|
||||
let api = requester(member);
|
||||
return api.get(`/groups/${createdGroup._id}`).then((group) => {
|
||||
expect(group._id).to.eql(createdGroup._id);
|
||||
expect(group.name).to.eql(createdGroup.name);
|
||||
expect(group.type).to.eql(createdGroup.type);
|
||||
expect(group.privacy).to.eql(createdGroup.privacy);
|
||||
});
|
||||
});
|
||||
|
||||
it('transforms members array to an array of user objects', () => {
|
||||
let api = requester(member);
|
||||
return api.get(`/groups/${createdGroup._id}`).then((group) => {
|
||||
let member = group.members[0];
|
||||
expect(member._id).to.exist;
|
||||
expect(member.profile.name).to.exist;
|
||||
expect(member.contributor).to.exist;
|
||||
expect(member.achievements).to.exist;
|
||||
expect(member.items).to.exist;
|
||||
});
|
||||
});
|
||||
|
||||
it('transforms leader id to leader object', () => {
|
||||
let api = requester(member);
|
||||
return api.get(`/groups/${createdGroup._id}`).then((group) => {
|
||||
expect(group.leader._id).to.eql(leader._id);
|
||||
expect(group.leader.profile.name).to.eql(leader.profile.name);
|
||||
expect(group.leader.items).to.exist;
|
||||
expect(group.leader.stats).to.exist;
|
||||
expect(group.leader.achievements).to.exist;
|
||||
expect(group.leader.contributor).to.exist;
|
||||
});
|
||||
});
|
||||
|
||||
it('includes the user in the members list', () => {
|
||||
let api = requester(member);
|
||||
return api.get(`/groups/${createdGroup._id}`).then((group) => {
|
||||
let members = group.members;
|
||||
let userInGroup = find(members, (user) => {
|
||||
return member._id === user._id;
|
||||
});
|
||||
expect(userInGroup).to.be.ok;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('Non-member of a public guild', () => {
|
||||
let leader, nonMember, createdGroup;
|
||||
|
||||
before(() => {
|
||||
return createAndPopulateGroup({
|
||||
members: 1,
|
||||
groupDetails: {
|
||||
name: 'test guild',
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
},
|
||||
}).then((res) => {
|
||||
leader = res.leader;
|
||||
createdGroup = res.group;
|
||||
return generateUser();
|
||||
}).then((user) => {
|
||||
nonMember = user;
|
||||
});
|
||||
});
|
||||
|
||||
it('returns the group object for a non-member', () => {
|
||||
let api = requester(nonMember);
|
||||
return api.get(`/groups/${createdGroup._id}`)
|
||||
.then((group) => {
|
||||
expect(group._id).to.eql(createdGroup._id);
|
||||
expect(group.name).to.eql(createdGroup.name);
|
||||
expect(group.type).to.eql(createdGroup.type);
|
||||
expect(group.privacy).to.eql(createdGroup.privacy);
|
||||
});
|
||||
});
|
||||
|
||||
it('does not include user in members list', () => {
|
||||
let api = requester(nonMember);
|
||||
return api.get(`/groups/${createdGroup._id}`).then((group) => {
|
||||
let userInGroup = find(group.members, (user) => {
|
||||
return nonMember._id === user._id;
|
||||
});
|
||||
expect(userInGroup).to.not.be.ok;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('Private Guilds', () => {
|
||||
let leader, nonMember, createdGroup;
|
||||
|
||||
before(() => {
|
||||
return createAndPopulateGroup({
|
||||
members: 1,
|
||||
groupDetails: {
|
||||
name: 'test guild',
|
||||
type: 'guild',
|
||||
privacy: 'private',
|
||||
},
|
||||
}).then((res) => {
|
||||
leader = res.leader;
|
||||
createdGroup = res.group;
|
||||
return generateUser();
|
||||
}).then((user) => {
|
||||
nonMember = user;
|
||||
});
|
||||
});
|
||||
|
||||
it('does not return the group object for a non-member', () => {
|
||||
let api = requester(nonMember);
|
||||
return expect(api.get(`/groups/${createdGroup._id}`))
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 404,
|
||||
text: 'Group not found or you don\'t have access.',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('Non-member of a party', () => {
|
||||
let leader, nonMember, createdGroup;
|
||||
|
||||
before(() => {
|
||||
return createAndPopulateGroup({
|
||||
members: 1,
|
||||
groupDetails: {
|
||||
name: 'test party',
|
||||
type: 'party',
|
||||
privacy: 'private',
|
||||
},
|
||||
}).then((res) => {
|
||||
leader = res.leader;
|
||||
createdGroup = res.group;
|
||||
return generateUser();
|
||||
}).then((user) => {
|
||||
nonMember = user;
|
||||
});
|
||||
});
|
||||
|
||||
it('does not return the group object for a non-member', () => {
|
||||
let api = requester(nonMember);
|
||||
return expect(api.get(`/groups/${createdGroup._id}`))
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 404,
|
||||
text: 'Group not found or you don\'t have access.',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('Member of a party', () => {
|
||||
let leader, member, createdGroup;
|
||||
|
||||
before(() => {
|
||||
return createAndPopulateGroup({
|
||||
members: 1,
|
||||
groupDetails: {
|
||||
name: 'test party',
|
||||
type: 'party',
|
||||
privacy: 'private',
|
||||
},
|
||||
}).then((res) => {
|
||||
leader = res.leader;
|
||||
createdGroup = res.group;
|
||||
member = res.members[0];
|
||||
});
|
||||
});
|
||||
|
||||
it('returns the user\'s party if an id of "party" is passed in', () => {
|
||||
let api = requester(member);
|
||||
return api.get('/groups/party')
|
||||
.then((group) => {
|
||||
expect(group._id).to.eql(createdGroup._id);
|
||||
expect(group.name).to.eql(createdGroup.name);
|
||||
expect(group.type).to.eql(createdGroup.type);
|
||||
expect(group.privacy).to.eql(createdGroup.privacy);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('Non-existent group', () => {
|
||||
let user;
|
||||
|
||||
beforeEach(() => {
|
||||
return generateUser().then((_user) => {
|
||||
user = _user;
|
||||
});
|
||||
});
|
||||
|
||||
it('returns error if group does not exist', () => {
|
||||
let api = requester(user);
|
||||
return expect(api.get('/groups/group-that-does-not-exist'))
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 404,
|
||||
text: 'Group not found or you don\'t have access.',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,151 @@
|
||||
import {
|
||||
generateGroup,
|
||||
generateUser,
|
||||
requester,
|
||||
} from '../../helpers/api.helper';
|
||||
|
||||
describe('POST /groups', () => {
|
||||
|
||||
context('All groups', () => {
|
||||
let api, leader;
|
||||
|
||||
beforeEach(() => {
|
||||
return generateUser().then((user) => {
|
||||
leader = user;
|
||||
api = requester(user);
|
||||
});
|
||||
});
|
||||
|
||||
xit('returns defaults? (TODO: it\'s possible to create a group without a type. Should the group default to party? Should we require type to be set?', () => {
|
||||
return api.post('/groups').then((group) => {
|
||||
expect(group._id).to.exist;
|
||||
expect(group.name).to.eql(`${leader.profile.name}'s group`);
|
||||
expect(group.type).to.eql('party');
|
||||
expect(group.privacy).to.eql('private');
|
||||
});
|
||||
});
|
||||
|
||||
it('returns a group object', () => {
|
||||
let group = {
|
||||
name: 'Test Group',
|
||||
type: 'party',
|
||||
leaderOnly: { challenges: true },
|
||||
description: 'Test Group Description',
|
||||
leaderMessage: 'Test Group Message',
|
||||
};
|
||||
|
||||
return api.post('/groups', group).then((createdGroup) => {
|
||||
expect(createdGroup._id).to.exist;
|
||||
expect(createdGroup.leader).to.eql(leader._id);
|
||||
expect(createdGroup.name).to.eql(group.name);
|
||||
expect(createdGroup.description).to.eql(group.description);
|
||||
expect(createdGroup.leaderMessage).to.eql(group.leaderMessage);
|
||||
expect(createdGroup.leaderOnly).to.eql(group.leaderOnly);
|
||||
expect(createdGroup.memberCount).to.eql(1);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns a populated members array', () => {
|
||||
return api.post('/groups', {
|
||||
type: 'party',
|
||||
}).then((party) => {
|
||||
let member = party.members[0];
|
||||
expect(member._id).to.eql(leader._id);
|
||||
expect(member.profile).to.eql(leader.profile);
|
||||
expect(member.contributor).to.eql(leader.contributor);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('Parties', () => {
|
||||
let api, leader;
|
||||
|
||||
beforeEach(() => {
|
||||
return generateUser().then((user) => {
|
||||
leader = user;
|
||||
api = requester(user);
|
||||
});
|
||||
});
|
||||
|
||||
it('allows party creation without gems', () => {
|
||||
return expect(api.post('/groups', {
|
||||
type: 'party',
|
||||
})).to.eventually.have.property('_id');
|
||||
});
|
||||
|
||||
it('prevents party creation if user is already in party', () => {
|
||||
return expect(generateGroup(leader, {
|
||||
type: 'party',
|
||||
}).then((group) => {
|
||||
return api.post('/groups', {
|
||||
type: 'party',
|
||||
});
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
text: 'Already in a party, try refreshing.',
|
||||
});
|
||||
})
|
||||
|
||||
xit('prevents creating a public party. TODO: it is possible to create a public party. Should we send back an error? Automatically switch the privacy to private?', () => {
|
||||
return expect(api.post('/groups', {
|
||||
type: 'party',
|
||||
privacy: 'public',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
text: 'Parties must be private',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('Guilds', () => {
|
||||
let api, leader;
|
||||
|
||||
beforeEach(() => {
|
||||
return generateUser({
|
||||
balance: 2,
|
||||
}).then((user) => {
|
||||
leader = user;
|
||||
api = requester(user);
|
||||
});
|
||||
});
|
||||
|
||||
it('prevents guild creation when user does not have enough gems', () => {
|
||||
return expect(generateUser({
|
||||
balance: 0.75,
|
||||
}).then((user) => {
|
||||
api = requester(user);
|
||||
return api.post('/groups', {
|
||||
type: 'guild',
|
||||
});
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
text: 'Not enough gems!',
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('can create a public guild', () => {
|
||||
return expect(api.post('/groups', {
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
})).to.eventually.have.property('leader', leader._id);
|
||||
});
|
||||
|
||||
it('can create a private guild', () => {
|
||||
return expect(api.post('/groups', {
|
||||
type: 'guild',
|
||||
privacy: 'private',
|
||||
})).to.eventually.have.property('leader', leader._id);
|
||||
});
|
||||
|
||||
it('deducts gems from user and adds them to guild bank', () => {
|
||||
return expect(api.post('/groups', {
|
||||
type: 'guild',
|
||||
privacy: 'private',
|
||||
}).then((group) => {
|
||||
expect(group.balance).to.eql(1);
|
||||
return api.get('/user');
|
||||
})).to.eventually.have.deep.property('balance', 1);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,74 @@
|
||||
import {
|
||||
generateGroup,
|
||||
generateUser,
|
||||
requester,
|
||||
} from '../../helpers/api.helper';
|
||||
|
||||
describe('POST /groups/:id', () => {
|
||||
|
||||
context('user is not the leader of the group', () => {
|
||||
let api, user, otherUser, groupUserDoesNotOwn;
|
||||
|
||||
beforeEach(() => {
|
||||
return Promise.all([
|
||||
generateUser({ balance: 10 }),
|
||||
generateUser({ balance: 10 }),
|
||||
]).then((users) => {
|
||||
user = users[0];
|
||||
otherUser = users[1];
|
||||
api = requester(user);
|
||||
|
||||
return generateGroup(otherUser, {
|
||||
name: 'Group not Owned By User',
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
members: [user, otherUser],
|
||||
});
|
||||
}).then((group) => {
|
||||
groupUserDoesNotOwn = group;
|
||||
});
|
||||
});
|
||||
|
||||
it('does not allow user to update group', () => {
|
||||
return expect(api.post(`/groups/${groupUserDoesNotOwn._id}`, {
|
||||
name: 'Change'
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
text: 'Only the group leader can update the group!',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('user is the leader of the group', () => {
|
||||
let api, user, usersGroup;
|
||||
|
||||
beforeEach(() => {
|
||||
return generateUser({
|
||||
balance: 10,
|
||||
}).then((_user) => {
|
||||
user = _user;
|
||||
api = requester(user);
|
||||
|
||||
return generateGroup(user, {
|
||||
name: 'Original Group Title',
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
});
|
||||
}).then((group) => {
|
||||
usersGroup = group;
|
||||
});
|
||||
});
|
||||
|
||||
it('allows user to update group', () => {
|
||||
return api.post(`/groups/${usersGroup._id}`, {
|
||||
name: 'New Group Title',
|
||||
description: 'New group description',
|
||||
}).then((group) => {
|
||||
return api.get(`/groups/${usersGroup._id}`);
|
||||
}).then((group) => {
|
||||
expect(group.name).to.eql('New Group Title');
|
||||
expect(group.description).to.eql('New group description');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,40 @@
|
||||
import {
|
||||
createAndPopulateGroup,
|
||||
generateUser,
|
||||
requester,
|
||||
} from '../../helpers/api.helper';
|
||||
|
||||
describe('POST /groups/:id/join', () => {
|
||||
|
||||
context('user is already a member of the group', () => {
|
||||
it('returns an error');
|
||||
});
|
||||
|
||||
context('public guild has no leader', () => {
|
||||
let user, group;
|
||||
|
||||
beforeEach(() => {
|
||||
return createAndPopulateGroup({
|
||||
groupDetails: {
|
||||
name: 'test guild',
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
},
|
||||
}).then((res) => {
|
||||
group = res.group;
|
||||
return requester(res.leader).post(`/groups/${group._id}/leave`);
|
||||
}).then((res) => {
|
||||
return generateUser();
|
||||
}).then((generatedUser) => {
|
||||
user = generatedUser;
|
||||
});
|
||||
});
|
||||
|
||||
it('makes the joining user the leader', () => {
|
||||
let api = requester(user);
|
||||
return expect(api.post(`/groups/${group._id}/join`).then((result) => {
|
||||
return api.get(`/groups/${group._id}`);
|
||||
})).to.eventually.have.deep.property('leader._id', user._id);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,163 @@
|
||||
import {
|
||||
createAndPopulateGroup,
|
||||
generateGroup,
|
||||
generateUser,
|
||||
requester,
|
||||
} from '../../helpers/api.helper';
|
||||
import { find } from 'lodash';
|
||||
|
||||
describe('POST /groups/:id/leave', () => {
|
||||
|
||||
context('user is not member of the group', () => {
|
||||
it('returns an error');
|
||||
});
|
||||
|
||||
context('user is a non-leader member of a guild', () => {
|
||||
let api, user, group;
|
||||
|
||||
beforeEach(() => {
|
||||
return createAndPopulateGroup({
|
||||
members: 3,
|
||||
groupDetails: {
|
||||
name: 'test guild',
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
},
|
||||
}).then((res) => {
|
||||
user = res.members[0];
|
||||
api = requester(user);
|
||||
group = res.group;
|
||||
});
|
||||
});
|
||||
|
||||
it('leaves the group', () => {
|
||||
return api.post(`/groups/${group._id}/leave`).then((result) => {
|
||||
return api.get(`/groups/${group._id}`);
|
||||
}).then((group) => {
|
||||
let userInGroup = find(group.members, (member) => {
|
||||
return member._id === user._id;
|
||||
});
|
||||
expect(userInGroup).to.not.be.ok;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('user is the last member of a public guild', () => {
|
||||
let api, user, group;
|
||||
|
||||
beforeEach(() => {
|
||||
return createAndPopulateGroup({
|
||||
groupDetails: {
|
||||
name: 'test guild',
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
},
|
||||
}).then((res) => {
|
||||
user = res.leader;
|
||||
api = requester(user);
|
||||
group = res.group;
|
||||
});
|
||||
});
|
||||
|
||||
it('leaves the group accessible', () => {
|
||||
return expect(api.post(`/groups/${group._id}/leave`).then((result) => {
|
||||
return api.get(`/groups/${group._id}`);
|
||||
})).to.eventually.have.property('_id', group._id);
|
||||
});
|
||||
});
|
||||
|
||||
context('user is the last member of a private group', () => {
|
||||
let api, user, group;
|
||||
|
||||
beforeEach(() => {
|
||||
return createAndPopulateGroup({
|
||||
groupDetails: {
|
||||
name: 'test guild',
|
||||
type: 'guild',
|
||||
privacy: 'private',
|
||||
},
|
||||
}).then((res) => {
|
||||
user = res.leader;
|
||||
api = requester(user);
|
||||
group = res.group;
|
||||
});
|
||||
});
|
||||
|
||||
it('group is not accessible after leaving', () => {
|
||||
return expect(api.post(`/groups/${group._id}/leave`).then((result) => {
|
||||
return api.get(`/groups/${group._id}`);
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 404,
|
||||
text: 'Group not found or you don\'t have access.',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('user is the last member of a private group with pending invites', () => {
|
||||
let api, user, inviteeRequest1, inviteeRequest2, group;
|
||||
|
||||
beforeEach(() => {
|
||||
return createAndPopulateGroup({
|
||||
invites: 2,
|
||||
groupDetails: {
|
||||
name: 'test guild',
|
||||
type: 'guild',
|
||||
privacy: 'private',
|
||||
},
|
||||
}).then((res) => {
|
||||
user = res.leader;
|
||||
inviteeRequest1 = requester(res.invitees[0]);
|
||||
inviteeRequest2 = requester(res.invitees[1]);
|
||||
api = requester(user);
|
||||
group = res.group;
|
||||
});
|
||||
});
|
||||
|
||||
it('deletes the group invitations from users', () => {
|
||||
return api.post(`/groups/${group._id}/leave`).then((result) => {
|
||||
return Promise.all([
|
||||
expect(inviteeRequest1.get(`/user`))
|
||||
.to.eventually.have.deep.property('invitations.guilds')
|
||||
.and.to.be.empty,
|
||||
expect(inviteeRequest2.get(`/user`))
|
||||
.to.eventually.have.deep.property('invitations.guilds')
|
||||
.and.to.be.empty,
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('user is the last member of a party with pending invites', () => {
|
||||
let api, user, inviteeRequest1, inviteeRequest2, group;
|
||||
|
||||
beforeEach(() => {
|
||||
return createAndPopulateGroup({
|
||||
invites: 2,
|
||||
groupDetails: {
|
||||
name: 'test party',
|
||||
type: 'party',
|
||||
privacy: 'private',
|
||||
},
|
||||
}).then((res) => {
|
||||
user = res.leader;
|
||||
inviteeRequest1 = requester(res.invitees[0]);
|
||||
inviteeRequest2 = requester(res.invitees[1]);
|
||||
api = requester(user);
|
||||
group = res.group;
|
||||
});
|
||||
});
|
||||
|
||||
it('deletes the group invitations from users', () => {
|
||||
return api.post(`/groups/${group._id}/leave`).then((result) => {
|
||||
return Promise.all([
|
||||
expect(inviteeRequest1.get(`/user`))
|
||||
.to.eventually.have.deep.property('invitations.party')
|
||||
.and.to.be.empty,
|
||||
expect(inviteeRequest2.get(`/user`))
|
||||
.to.eventually.have.deep.property('invitations.party')
|
||||
.and.to.be.empty,
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,58 @@
|
||||
import {
|
||||
createAndPopulateGroup,
|
||||
generateGroup,
|
||||
generateUser,
|
||||
requester,
|
||||
} from '../../helpers/api.helper';
|
||||
|
||||
describe('POST /groups/:id/removeMember', () => {
|
||||
|
||||
context('user is not member of the group', () => {
|
||||
it('returns an error');
|
||||
});
|
||||
|
||||
context('user is a non-leader member of a guild', () => {
|
||||
it('returns an error');
|
||||
});
|
||||
|
||||
context('user is the leader of a guild', () => {
|
||||
let api, leader, member, group;
|
||||
|
||||
beforeEach(() => {
|
||||
return createAndPopulateGroup({
|
||||
members: 1,
|
||||
groupDetails: {
|
||||
name: 'test group',
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
},
|
||||
}).then((res) => {
|
||||
leader = res.leader;
|
||||
member = res.members[0];
|
||||
group = res.group;
|
||||
|
||||
api = requester(leader);
|
||||
});
|
||||
});
|
||||
|
||||
it('does not allow leader to remove themselves', () => {
|
||||
return expect(api.post(`/groups/${group._id}/removeMember`, null, {
|
||||
uuid: leader._id,
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
text: 'You cannot remove yourself!',
|
||||
});
|
||||
});
|
||||
|
||||
it('can remove other members of guild', () => {
|
||||
return api.post(`/groups/${group._id}/removeMember`, null, {
|
||||
uuid: member._id,
|
||||
}).then((res) => {
|
||||
return api.get(`/groups/${group._id}`);
|
||||
}).then((guild) => {
|
||||
expect(guild.members).to.have.a.lengthOf(1);
|
||||
expect(guild.members[0]._id).to.not.eql(member._id);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,91 @@
|
||||
import {
|
||||
generateUser,
|
||||
requester,
|
||||
} from '../../helpers/api.helper';
|
||||
import {v4 as generateRandomUserName} from 'uuid';
|
||||
|
||||
describe('POST /register', () => {
|
||||
|
||||
context('username and email are free', () => {
|
||||
it('registers a new user', () => {
|
||||
let api = requester();
|
||||
let username = generateRandomUserName();
|
||||
let email = `${username}@example.com`;
|
||||
let password = 'password';
|
||||
|
||||
return api.post('/register', {
|
||||
username: username,
|
||||
email: email,
|
||||
password: password,
|
||||
confirmPassword: password,
|
||||
}).then((user) => {
|
||||
expect(user._id).to.exist;
|
||||
expect(user.apiToken).to.exist;
|
||||
expect(user.auth.local.username).to.eql(username);
|
||||
});
|
||||
});
|
||||
|
||||
it('requires password and confirmPassword to match', () => {
|
||||
let api = requester();
|
||||
let username = generateRandomUserName();
|
||||
let email = `${username}@example.com`;
|
||||
let password = 'password';
|
||||
let confirmPassword = 'not password';
|
||||
|
||||
return expect(api.post('/register', {
|
||||
username: username,
|
||||
email: email,
|
||||
password: password,
|
||||
confirmPassword: confirmPassword,
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
text: ':password and :confirmPassword don\'t match',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('login is already taken', () => {
|
||||
let username, email;
|
||||
beforeEach(() => {
|
||||
username = generateRandomUserName();
|
||||
email = `${username}@example.com`;
|
||||
return generateUser({
|
||||
'auth.local.username': username,
|
||||
'auth.local.lowerCaseUsername': username,
|
||||
'auth.local.email': email
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects if username is already taken', () => {
|
||||
let api = requester();
|
||||
let uniqueEmail = `${generateRandomUserName()}@exampe.com`;
|
||||
let password = 'password';
|
||||
|
||||
return expect(api.post('/register', {
|
||||
username: username,
|
||||
email: uniqueEmail,
|
||||
password: password,
|
||||
confirmPassword: password,
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
text: 'Username already taken',
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects if email is already taken', () => {
|
||||
let api = requester();
|
||||
let uniqueUsername = generateRandomUserName();
|
||||
let password = 'password';
|
||||
|
||||
return expect(api.post('/register', {
|
||||
username: uniqueUsername,
|
||||
email: email,
|
||||
password: password,
|
||||
confirmPassword: password,
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
text: 'Email already taken',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,13 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
app = require("../../website/src/server")
|
||||
|
||||
describe "Site Status", ->
|
||||
|
||||
describe "GET /status", ->
|
||||
|
||||
it "/api/v2/status", (done) ->
|
||||
request.get(baseURL + "/status").set("Accept", "application/json").end (res) ->
|
||||
expect(res.statusCode).to.equal 200
|
||||
expect(res.body.status).to.equal "up"
|
||||
done()
|
||||
@@ -0,0 +1,10 @@
|
||||
import {requester} from '../../helpers/api.helper';
|
||||
|
||||
describe('Status', () => {
|
||||
|
||||
it('returns a status of up when server is up', () => {
|
||||
let api = requester();
|
||||
return expect(api.get('/status'))
|
||||
.to.eventually.eql({status: 'up'});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,39 @@
|
||||
import {
|
||||
generateUser,
|
||||
requester,
|
||||
} from '../../helpers/api.helper';
|
||||
|
||||
describe('DELETE /user', () => {
|
||||
let api;
|
||||
|
||||
beforeEach(() => {
|
||||
return generateUser().then((user) => {
|
||||
api = requester(user);
|
||||
});
|
||||
});
|
||||
|
||||
it('deletes the user', () => {
|
||||
return expect(api.del('/user').then((fetchedUser) => {
|
||||
return api.get('/user');
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
text: 'No user found.',
|
||||
});
|
||||
});
|
||||
|
||||
context('user in solo group', () => {
|
||||
|
||||
it('deletes party when user is the only member');
|
||||
|
||||
it('deletes private guild when user is the only member');
|
||||
});
|
||||
|
||||
context('user in group with members', () => {
|
||||
|
||||
it('removes user from all groups user was a part of');
|
||||
|
||||
it('chooses new group leader for any group user was the leader of');
|
||||
|
||||
it('removes invitations from groups');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
import {
|
||||
generateUser,
|
||||
requester,
|
||||
} from '../../helpers/api.helper';
|
||||
|
||||
describe('GET /user', () => {
|
||||
let user;
|
||||
|
||||
beforeEach(() => {
|
||||
return generateUser().then((usr) => {
|
||||
user = usr;
|
||||
});
|
||||
});
|
||||
|
||||
it('gets the user object', () => {
|
||||
let api = requester(user);
|
||||
return api.get('/user').then((fetchedUser) => {
|
||||
expect(fetchedUser._id).to.eql(user._id);
|
||||
expect(fetchedUser.auth.local.username).to.eql(user.auth.local.username);
|
||||
expect(fetchedUser.todos).to.eql(user.todos);
|
||||
expect(fetchedUser.items).to.eql(user.items);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,75 @@
|
||||
import {
|
||||
generateUser,
|
||||
requester,
|
||||
} from '../../helpers/api.helper';
|
||||
|
||||
import { each } from 'lodash';
|
||||
|
||||
describe('PUT /user', () => {
|
||||
let api, user;
|
||||
|
||||
beforeEach(() => {
|
||||
return generateUser().then((usr) => {
|
||||
user = usr;
|
||||
api = requester(user);
|
||||
});
|
||||
});
|
||||
|
||||
context('allowed paths', () => {
|
||||
it('updates the user', () => {
|
||||
return api.put('/user', {
|
||||
'profile.name' : 'Frodo',
|
||||
'preferences.costume': true,
|
||||
'stats.hp': 14,
|
||||
}).then((updatedUser) => {
|
||||
expect(updatedUser.profile.name).to.eql('Frodo');
|
||||
expect(updatedUser.preferences.costume).to.eql(true);
|
||||
expect(updatedUser.stats.hp).to.eql(14);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('top level protected paths', () => {
|
||||
let protectedPaths = {
|
||||
'gem balance': {balance: 100},
|
||||
'auth': {'auth.blocked': true, 'auth.timestamps.created': new Date()},
|
||||
'contributor': {'contributor.level': 9, 'contributor.admin': true, 'contributor.text': 'some text'},
|
||||
'backer': {'backer.tier': 10, 'backer.npc': 'Bilbo'},
|
||||
'subscriptions': {'purchased.plan.extraMonths': 500, 'purchased.plan.consecutive.trinkets': 1000},
|
||||
'customization gem purchases': {'purchased.background.tavern': true, 'purchased.skin.bear': true},
|
||||
'tasks': {todos: [], habits: [], dailys: [], rewards: []},
|
||||
};
|
||||
|
||||
each(protectedPaths, (data, testName) => {
|
||||
it(`does not allow updating ${testName}`, () => {
|
||||
let errorText = [];
|
||||
each(data, (value, path) => {
|
||||
errorText.push(`path \`${path}\` was not saved, as it's a protected path.`);
|
||||
});
|
||||
return expect(api.put('/user', data)).to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
text: errorText,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('sub-level protected paths', () => {
|
||||
let protectedPaths = {
|
||||
'class stat': {'stats.class': 'wizard'},
|
||||
};
|
||||
|
||||
each(protectedPaths, (data, testName) => {
|
||||
it(`does not allow updating ${testName}`, () => {
|
||||
let errorText = [];
|
||||
each(data, (value, path) => {
|
||||
errorText.push(`path \`${path}\` was not saved, as it's a protected path.`);
|
||||
});
|
||||
return expect(api.put('/user', data)).to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
text: errorText,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,7 +0,0 @@
|
||||
--colors
|
||||
--reporter spec
|
||||
--timeout 8000
|
||||
--check-leaks
|
||||
--growl
|
||||
--compilers js:babel/register
|
||||
--require ./test/helpers/content.helper.js
|
||||
@@ -0,0 +1,217 @@
|
||||
import {
|
||||
assign,
|
||||
each,
|
||||
isEmpty,
|
||||
times,
|
||||
} from 'lodash';
|
||||
import {MongoClient as mongo} from 'mongodb';
|
||||
import {v4 as generateUUID} from 'uuid';
|
||||
import superagent from 'superagent';
|
||||
|
||||
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={}) {
|
||||
return {
|
||||
get: _requestMaker(user, 'get'),
|
||||
post: _requestMaker(user, 'post'),
|
||||
put: _requestMaker(user, 'put'),
|
||||
del: _requestMaker(user, 'del'),
|
||||
}
|
||||
};
|
||||
|
||||
// Creates a new user and returns it
|
||||
// If you need the user to have specific requirements,
|
||||
// such as a balance > 0, just pass in the adjustment
|
||||
// to the update object. If you want to adjust a nested
|
||||
// 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={}) {
|
||||
let username = generateUUID();
|
||||
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,
|
||||
confirmPassword: password,
|
||||
}).then((user) => {
|
||||
_updateDocument('users', user, update, () => {
|
||||
resolve(user);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 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={}) {
|
||||
let request = _requestMaker(leader, 'post');
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
request('/groups').then((group) => {
|
||||
_updateDocument('groups', group, update, () => {
|
||||
resolve(group);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// This is generate group + the ability to create
|
||||
// real users to populate it. The settings object
|
||||
// takes in:
|
||||
// members: Number - the number of group members to create. Defaults to 0.
|
||||
// inivtes: Number - the number of users to create and invite to the group. Defaults to 0.
|
||||
// groupDetails: Object - how to initialize the group
|
||||
// leaderDetails: Object - defaults for the leader, defaults with a gem balance so the user
|
||||
// can create the group
|
||||
//
|
||||
// Returns an object with
|
||||
// members: an array of user objects that correspond to the members of the group
|
||||
// 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;
|
||||
|
||||
let numberOfMembers = settings.members || 0;
|
||||
let numberOfInvites = settings.invites || 0;
|
||||
let groupDetails = settings.groupDetails;
|
||||
let leaderDetails = settings.leaderDetails || { balance: 10 };
|
||||
|
||||
let leaderPromise = generateUser(leaderDetails);
|
||||
|
||||
let memberPromises = Promise.all(
|
||||
times(numberOfMembers, () => {
|
||||
return generateUser();
|
||||
})
|
||||
);
|
||||
|
||||
let invitePromises = Promise.all(
|
||||
times(numberOfInvites, () => {
|
||||
return generateUser();
|
||||
})
|
||||
);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
return leaderPromise.then((user) => {
|
||||
leader = user;
|
||||
request = _requestMaker(leader, 'post');
|
||||
return memberPromises;
|
||||
}).then((users) => {
|
||||
members = users;
|
||||
groupDetails.members = groupDetails.members || [leader._id];
|
||||
|
||||
each(members, (member) => {
|
||||
groupDetails.members.push(member._id);
|
||||
});
|
||||
|
||||
return generateGroup(leader, groupDetails);
|
||||
}).then((createdGroup) => {
|
||||
group = createdGroup;
|
||||
return invitePromises;
|
||||
}).then((users) => {
|
||||
invitees = users;
|
||||
|
||||
let invitePromises = [];
|
||||
|
||||
each(invitees, (invitee) => {
|
||||
let invitePromise = request(`/groups/${group._id}/invite`, {
|
||||
uuids: [invitee._id]
|
||||
});
|
||||
invitePromises.push(invitePromise);
|
||||
});
|
||||
|
||||
return Promise.all(invitePromises);
|
||||
}).then((inviteResults) => {
|
||||
resolve({
|
||||
leader: leader,
|
||||
group: group,
|
||||
members: members,
|
||||
invitees: 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() {
|
||||
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);
|
||||
let groups = db.collection('groups');
|
||||
groups.insertOne({
|
||||
_id: 'habitrpg',
|
||||
chat: [],
|
||||
leader: '9',
|
||||
name: 'HabitRPG',
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
members: [],
|
||||
}, (err) => {
|
||||
if (err) return reject(err);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function _requestMaker(user, method) {
|
||||
return (route, send, query) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let request = superagent[method](`http://localhost:${API_TEST_SERVER_PORT}/api/v2${route}`)
|
||||
.accept('application/json');
|
||||
|
||||
if (user._id && user.apiToken) {
|
||||
request
|
||||
.set('x-api-user', user._id)
|
||||
.set('x-api-key', user.apiToken);
|
||||
}
|
||||
|
||||
request
|
||||
.query(query)
|
||||
.send(send)
|
||||
.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,
|
||||
});
|
||||
}
|
||||
|
||||
resolve(response.body);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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}`;
|
||||
|
||||
let collection = db.collection(collectionName);
|
||||
|
||||
collection.update({ _id: doc._id }, { $set: update }, (err, result) => {
|
||||
if (err) throw `Error updating ${collectionName}: ${err}`;
|
||||
assign(doc, update);
|
||||
cb();
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -5,4 +5,5 @@
|
||||
global._ = require("lodash")
|
||||
global.chai = require("chai")
|
||||
chai.use(require("sinon-chai"))
|
||||
chai.use(require("chai-as-promised"));
|
||||
global.expect = chai.expect
|
||||
|
||||
@@ -6,4 +6,5 @@
|
||||
--debug
|
||||
--compilers coffee:coffee-script
|
||||
--globals io
|
||||
--require test/api/api-helper
|
||||
--require test/api-legacy/api-helper
|
||||
--require ./test/helpers/globals.helper
|
||||
|
||||
@@ -298,10 +298,9 @@ acceptablePUTPaths = _.reduce(require('./../models/user').schema.paths, function
|
||||
return m;
|
||||
}, {})
|
||||
|
||||
//// Uncomment this if we we want to disable GP-restoring (eg, holiday events)
|
||||
//_.each('stats.gp'.split(' '), function(removePath){
|
||||
// delete acceptablePUTPaths[removePath];
|
||||
//})
|
||||
_.each('stats.class'.split(' '), function(removePath){
|
||||
delete acceptablePUTPaths[removePath];
|
||||
})
|
||||
|
||||
/**
|
||||
* Update user
|
||||
@@ -318,7 +317,7 @@ api.update = function(req, res, next) {
|
||||
if (acceptablePUTPaths[k])
|
||||
user.fns.dotSet(k, v);
|
||||
else
|
||||
errors.push("path `" + k + "` was not saved, as it's a protected path. See https://github.com/HabitRPG/habitrpg/blob/develop/API.md for PUT /api/v2/user.");
|
||||
errors.push("path `" + k + "` was not saved, as it's a protected path.");
|
||||
return true;
|
||||
});
|
||||
user.save(function(err) {
|
||||
|
||||
@@ -9,7 +9,7 @@ script(type='text/ng-template', id='modals/reroll.html')
|
||||
.modal-footer
|
||||
button.btn.btn-default(ng-click='$close()')=env.t('neverMind')
|
||||
span(ng-if='user.balance < 1')
|
||||
a.btn.btn-success(ng-click='openModal("buyGems",{track:{"Gems > Reroll"}})')=env.t('buyMoreGems')
|
||||
a.btn.btn-success(ng-click='openModal("buyGems",{track:"Gems > Reroll"})')=env.t('buyMoreGems')
|
||||
span.gem-cost=env.t('notEnoughGems')
|
||||
span(ng-if='user.balance >= 1', ng-controller='SettingsCtrl')
|
||||
a.btn.btn-danger(ng-click='$close(); reroll()')=env.t('fortify')
|
||||
|
||||
@@ -1,33 +1,40 @@
|
||||
h2 10/21/2015 - FROG PET QUEST, TO-DO SORTING FIX, AND SECOND WORLD BOSS EXHAUST STRIKE
|
||||
h2 10/26/2015 - OCTOBER SUBSCRIBER ITEM REVEALED
|
||||
hr
|
||||
tr
|
||||
td
|
||||
span.Mount_Body_Frog-Base.pull-right
|
||||
span.Mount_Head_Frog-Base.pull-right(style='margin:0')
|
||||
h3 Frog Pet Quest
|
||||
p Deep in the Swamps of Stagnation, you find your path obstructed by debris... and an angry amphibian. Yuck! If you complete the <a href='/#/options/inventory/quests'>Clutter Frog quest</a>, you'll be rewarded with some princely Frog pets!
|
||||
p.small.muted Art by starsystemic, RosemonkeyCT, Jon Arjinborn, and Breadstrings
|
||||
p.small.muted Writing by Fluitare
|
||||
tr
|
||||
td
|
||||
h3 To-Do Sorting Fix
|
||||
p To-dos will now stay sorted when you drag and drop them! Often, To-Dos used to change their order unless you cleared your completed To-Dos on a regular basis. That should no longer be a problem.
|
||||
p.small.muted by ikadzuchi and Alys
|
||||
tr
|
||||
td
|
||||
.seasonalshop_broken.pull-right
|
||||
h3 World Boss: Burnout Uses Exhaust Strike!
|
||||
p Ahh!!! Our incomplete Dailies have fed the flames of Burnout, and now it has enough energy to strike again! It lets loose a gout of spectral flame that sears the Seasonal Shop. You're horrified to see that the cheery Seasonal Sorceress has been transformed into a sorrowful Exhaust Spirit!
|
||||
br
|
||||
p We have to rescue our NPCs! Hurry, Habiticans, complete your tasks and defeat Burnout before it strikes for a third time!
|
||||
br
|
||||
p Late to the fight? Learn about Burnout and how to defeat World Bosses <a href='http://habitica.wikia.com/wiki/Boss#World_Bosses' target='_blank'>here</a>.
|
||||
.promo_mystery_201510.pull-right
|
||||
h3 October Subscriber Item: Horned Goblin!
|
||||
p The October Subscriber Item has been revealed: the Horned Goblin Set! All October subscribers will receive the Goblin Horns and the Goblin Tail. You still have four days to <a href='/#/options/settings/subscription'>subscribe</a> and receive the item set! Thank you so much for your support - we really do rely on you to keep Habitica free to use and running smoothly.
|
||||
p.small.muted by Lemoness
|
||||
|
||||
if menuItem !== 'oldNews'
|
||||
hr
|
||||
a(href='/static/old-news', target='_blank') Read older news
|
||||
|
||||
mixin oldNews
|
||||
h2 10/21/2015 - FROG PET QUEST, TO-DO SORTING FIX, AND SECOND WORLD BOSS EXHAUST STRIKE
|
||||
tr
|
||||
td
|
||||
span.Mount_Body_Frog-Base.pull-right
|
||||
span.Mount_Head_Frog-Base.pull-right(style='margin:0')
|
||||
h3 Frog Pet Quest
|
||||
p Deep in the Swamps of Stagnation, you find your path obstructed by debris... and an angry amphibian. Yuck! If you complete the <a href='/#/options/inventory/quests'>Clutter Frog quest</a>, you'll be rewarded with some princely Frog pets!
|
||||
p.small.muted Art by starsystemic, RosemonkeyCT, Jon Arjinborn, and Breadstrings
|
||||
p.small.muted Writing by Fluitare
|
||||
tr
|
||||
td
|
||||
h3 To-Do Sorting Fix
|
||||
p To-dos will now stay sorted when you drag and drop them! Often, To-Dos used to change their order unless you cleared your completed To-Dos on a regular basis. That should no longer be a problem.
|
||||
p.small.muted by ikadzuchi and Alys
|
||||
tr
|
||||
td
|
||||
.seasonalshop_broken.pull-right
|
||||
h3 World Boss: Burnout Uses Exhaust Strike!
|
||||
p Ahh!!! Our incomplete Dailies have fed the flames of Burnout, and now it has enough energy to strike again! It lets loose a gout of spectral flame that sears the Seasonal Shop. You're horrified to see that the cheery Seasonal Sorceress has been transformed into a sorrowful Exhaust Spirit!
|
||||
br
|
||||
p We have to rescue our NPCs! Hurry, Habiticans, complete your tasks and defeat Burnout before it strikes for a third time!
|
||||
br
|
||||
p Late to the fight? Learn about Burnout and how to defeat World Bosses <a href='http://habitica.wikia.com/wiki/Boss#World_Bosses' target='_blank'>here</a>.
|
||||
h2 10/14/2015 - JACK O'LANTERN PETS AND MOUNTS! WORLD BOSS EXHAUST STRIKE!
|
||||
hr
|
||||
tr
|
||||
|
||||
@@ -21,7 +21,7 @@ div(ng-if='::profile.backer.npc')
|
||||
hr
|
||||
|
||||
div(ng-if='::profile.contributor.level || user._id == profile._id')
|
||||
.achievement.achievement-firefox(ng-if='::profile.contributor.level')
|
||||
.achievement.achievement-boot(ng-if='::profile.contributor.level')
|
||||
div(ng-class='::{muted: !profile.contributor.level}')
|
||||
h5
|
||||
span.label.label-default(ng-if='::profile.contributor.level', class='label-contributor-{{::profile.contributor.level}}') {{::contribText(profile.contributor, profile.backer)}}
|
||||
|
||||