Merge branch 'api-v3' into api-v3-groups

This commit is contained in:
Matteo Pagliazzi
2015-12-29 18:17:36 +01:00
552 changed files with 12321 additions and 8213 deletions
@@ -36,6 +36,22 @@ One caveat. If you have a severe syntax error in your files, the tests may fail
$ gulp test:api:safe
```
If you'd like to run the tests individually and inspect the output from the server, in one pane you can run:
```bash
$ export PORT=3003; export NODE_DB_URI="mongodb://localhost/habitrpgtest"
$ gulp nodemon
```
And run your tests in another pane:
```bash
$ mocha path/to/file.js
# Mark a test with the `.only` attribute
$ mocha
```
## Structure
Each top level route has it's own directory. So, all the routes that begin with `/groups/` live in `/test/api/groups/`.
+76
View File
@@ -0,0 +1,76 @@
import moment from 'moment';
import { generateTodo } from '../helpers/common.helper';
import { preenTodos } from '../../common/script/index.js';
describe('#preenTodos', () => {
let todos, uncompletedTodo, completedChallengeTodo, newlyCompletedTodo, completedTodoFromTwoDaysAgo, completedTodoFromThreeDaysAgo, completedTodoFromTenDaysAgo;
beforeEach(() => {
uncompletedTodo = generateTodo({ completed: false });
completedChallengeTodo = generateTodo({
completed: true,
challenge: { id: 'some-challenge' },
});
newlyCompletedTodo = generateTodo({
completed: true,
dateCompleted: moment(),
});
completedTodoFromTwoDaysAgo = generateTodo({
completed: true,
dateCompleted: moment().subtract({ days: 2 }),
});
completedTodoFromThreeDaysAgo = generateTodo({
completed: true,
dateCompleted: moment().subtract({ days: 3 }),
});
completedTodoFromTenDaysAgo = generateTodo({
completed: true,
dateCompleted: moment().subtract({ days: 10 }),
});
todos = [
uncompletedTodo,
completedChallengeTodo,
newlyCompletedTodo,
completedTodoFromTwoDaysAgo,
completedTodoFromThreeDaysAgo,
completedTodoFromTenDaysAgo,
];
});
it('includes uncompleted todos', () => {
let preenedTodos = preenTodos(todos);
expect(preenedTodos).to.include(uncompletedTodo);
});
it('includes completed challenge todos', () => {
let preenedTodos = preenTodos(todos);
expect(preenedTodos).to.include(completedChallengeTodo);
});
it('includes recently completed todos', () => {
let preenedTodos = preenTodos(todos);
expect(preenedTodos).to.include(newlyCompletedTodo);
});
it('includes todos completed two days ago', () => {
let preenedTodos = preenTodos(todos);
expect(preenedTodos).to.include(completedTodoFromTwoDaysAgo);
});
it('does not include todos completed three days ago', () => {
let preenedTodos = preenTodos(todos);
expect(preenedTodos).to.not.include(completedTodoFromThreeDaysAgo);
});
it('does not include todos completed more than three days ago', () => {
let preenedTodos = preenTodos(todos);
expect(preenedTodos).to.not.include(completedTodoFromTenDaysAgo);
});
});
+73
View File
@@ -0,0 +1,73 @@
import {
generateUser,
} from '../helpers/common.helper';
describe('user.fns.updateStats', () => {
let user;
beforeEach(() => {
user = generateUser({});
});
context('no hp', () => {
it('returns 0 if user\'s hp is 0', () => {
let stats = {
hp: 0,
};
expect(user.fns.updateStats(stats)).to.eql(0);
});
it('returns 0 if user\'s hp is less than 0', () => {
let stats = {
hp: -5,
};
expect(user.fns.updateStats(stats)).to.eql(0);
});
it('sets user\'s hp to 0 if it is less than 0', () => {
let stats = {
hp: -5,
};
user.fns.updateStats(stats);
expect(user.stats.hp).to.eql(0);
});
});
context('Stat Allocation', () => {
it('Adds an attibute point when user\'s stat points are less than max level', () => {
let stats = {
exp: 3581,
};
user.stats.lvl = 99;
user.stats.str = 25;
user.stats.int = 25;
user.stats.con = 25;
user.stats.per = 24;
user.fns.updateStats(stats);
expect(user.stats.points).to.eql(1);
});
it('Does not add an attibute point when user\'s stat points are equal to max level', () => {
let stats = {
exp: 3581,
};
user.stats.lvl = 99;
user.stats.str = 25;
user.stats.int = 25;
user.stats.con = 25;
user.stats.per = 25;
user.fns.updateStats(stats);
expect(user.stats.points).to.eql(0);
});
});
});
+1 -2
View File
@@ -1,8 +1,7 @@
import {
expectValidTranslationString,
} from '../helpers/content.helper';
import { each } from 'lodash';
import camelCase from 'lodash.camelcase';
import { each, camelCase } from 'lodash';
import { tree as allGear } from '../../common/script/content/gear';
import backerGear from '../../common/script/content/gear/sets/special/special-backer';
+14
View File
@@ -0,0 +1,14 @@
import {each} from 'lodash';
import {
expectValidTranslationString
} from '../helpers/content.helper';
import mysterySets from '../../common/script/content/mystery-sets';
describe('Mystery Sets', () => {
it('has a valid text string', () => {
each(mysterySets, (set, key) => {
expectValidTranslationString(set.text);
});
});
});
+109 -33
View File
@@ -1,45 +1,121 @@
'use strict';
describe('Auth Controller', function() {
var scope, ctrl, user, $httpBackend, $window, $modal;
describe('AuthCtrl', function(){
var scope, ctrl, user, $httpBackend, $window;
beforeEach(function(){
module(function($provide) {
$provide.value('Analytics', analyticsMock);
$provide.value('Chat', { seenMessage: function() {} });
});
inject(function(_$httpBackend_, $rootScope, $controller) {
$httpBackend = _$httpBackend_;
scope = $rootScope.$new();
scope.loginUsername = 'user';
scope.loginPassword = 'pass';
$window = { location: { href: ""}, alert: sandbox.spy() };
user = { user: {}, authenticate: sandbox.spy() };
ctrl = $controller('AuthCtrl', {$scope: scope, $window: $window, User: user});
})
beforeEach(function(){
module(function($provide) {
$provide.value('Analytics', analyticsMock);
$provide.value('Chat', { seenMessage: function() {} });
});
describe('logging in', function() {
inject(function(_$httpBackend_, $rootScope, $controller, _$modal_) {
$httpBackend = _$httpBackend_;
scope = $rootScope.$new();
scope.loginUsername = 'user';
scope.loginPassword = 'pass';
$window = { location: { href: ""}, alert: sandbox.spy() };
$modal = _$modal_;
user = { user: {}, authenticate: sandbox.spy() };
it('should log in users with correct uname / pass', function() {
$httpBackend.expectPOST('/api/v2/user/auth/local').respond({id: 'abc', token: 'abc'});
scope.auth();
$httpBackend.flush();
expect(user.authenticate).to.be.calledOnce;
expect($window.alert).to.not.be.called;
ctrl = $controller('AuthCtrl', {$scope: scope, $window: $window, User: user});
})
});
describe('logging in', function() {
it('should log in users with correct uname / pass', function() {
$httpBackend.expectPOST('/api/v2/user/auth/local').respond({id: 'abc', token: 'abc'});
scope.auth();
$httpBackend.flush();
expect(user.authenticate).to.be.calledOnce;
expect($window.alert).to.not.be.called;
});
it('should not log in users with incorrect uname / pass', function() {
$httpBackend.expectPOST('/api/v2/user/auth/local').respond(404, '');
scope.auth();
$httpBackend.flush();
expect(user.authenticate).to.not.be.called;
expect($window.alert).to.be.calledOnce;
});
});
describe('#clearLocalStorage', function () {
var timer;
beforeEach(function () {
timer = sandbox.useFakeTimers();
sandbox.stub($modal, 'open');
});
it('opens modal with message about clearing local storage and logging out', function () {
scope.clearLocalStorage();
expect($modal.open).to.be.calledOnce;
expect($modal.open).to.be.calledWith({
templateUrl: 'modals/message-modal.html',
scope: scope
});
it('should not log in users with incorrect uname / pass', function() {
$httpBackend.expectPOST('/api/v2/user/auth/local').respond(404, '');
scope.auth();
$httpBackend.flush();
expect(user.authenticate).to.not.be.called;
expect($window.alert).to.be.calledOnce;
});
expect(scope.messageModal.title).to.eql(window.env.t('localStorageClearing'));
expect(scope.messageModal.body).to.eql(window.env.t('localStorageClearingExplanation'));
});
it('does not call $scope.logout before 3 seconds', function () {
sandbox.stub(scope, 'logout');
scope.clearLocalStorage();
timer.tick(2999);
expect(scope.logout).to.not.be.called;
});
it('calls $scope.logout after 3 seconds', function () {
sandbox.stub(scope, 'logout');
scope.clearLocalStorage();
timer.tick(3000);
expect(scope.logout).to.be.calledOnce;
});
it('does not clear local storage before 3 seconds', function () {
sandbox.stub(localStorage, 'clear');
scope.clearLocalStorage();
timer.tick(2999);
expect(localStorage.clear).to.not.be.called;
});
it('clears local storage after 3 seconds', function () {
sandbox.stub(localStorage, 'clear');
scope.clearLocalStorage();
timer.tick(3000);
expect(localStorage.clear).to.be.calledOnce;
});
it('does not redirect to /logout route before 3 seconds', function () {
scope.clearLocalStorage();
timer.tick(2999);
expect($window.location.href).to.eql('');
});
it('redirects to /logout after 3 seconds', function () {
scope.clearLocalStorage();
timer.tick(3000);
expect($window.location.href).to.eql('/logout');
});
});
});
@@ -68,13 +68,13 @@ describe('Invite to Group Controller', function() {
it('uses provided name', function() {
scope.group.name = 'test party';
scope.inviteNewUsers('uuid');
expect(group.name).to.eql('test party');
expect(scope.group.name).to.eql('test party');
});
it('names the group if no name is provided', function() {
scope.group.name = '';
scope.inviteNewUsers('uuid');
expect(group.name).to.eql(env.t('possessiveParty', {name: user.profile.name}));
expect(scope.group.name).to.eql(env.t('possessiveParty', {name: user.profile.name}));
});
});
+210 -10
View File
@@ -1,15 +1,28 @@
'use strict';
describe('Settings Controller', function() {
describe('Settings Controller', function () {
var rootScope, scope, user, User, ctrl;
beforeEach(function() {
const actionClickEvent = {
target: document.createElement('button'),
};
beforeEach(function () {
module(function($provide) {
user = specHelper.newUser();
User = {
set: sandbox.stub(),
user: user
};
User.user.ops = {
reroll: sandbox.stub(),
rebirth: sandbox.stub(),
releasePets: sandbox.stub(),
releaseMounts: sandbox.stub(),
releaseBoth: sandbox.stub(),
};
$provide.value('User', User);
$provide.value('Guide', sandbox.stub());
});
@@ -25,20 +38,20 @@ describe('Settings Controller', function() {
});
});
describe('#openDayStartModal', function() {
beforeEach(function() {
describe('#openDayStartModal', function () {
beforeEach(function () {
sandbox.stub(rootScope, 'openModal');
sandbox.stub(window, 'alert');
});
it('opens the day start modal', function() {
it('opens the day start modal', function () {
scope.openDayStartModal(5);
expect(rootScope.openModal).to.be.calledOnce;
expect(rootScope.openModal).to.be.calledWith('change-day-start', {scope: scope});
});
it('sets nextCron variable', function() {
it('sets nextCron variable', function () {
expect(scope.nextCron).to.not.exist;
scope.openDayStartModal(5);
@@ -46,7 +59,7 @@ describe('Settings Controller', function() {
expect(scope.nextCron).to.exist;
});
it('calculates the next time cron will run', function() {
it('calculates the next time cron will run', function () {
var fakeCurrentTime = new Date(2013, 3, 1, 3, 12).getTime();
var expectedTime = new Date(2013, 3, 1, 5, 0, 0).getTime();
sandbox.useFakeTimers(fakeCurrentTime);
@@ -56,7 +69,7 @@ describe('Settings Controller', function() {
expect(scope.nextCron).to.eq(expectedTime);
});
it('calculates the next time cron will run and adds a day if cron would have already passed', function() {
it('calculates the next time cron will run and adds a day if cron would have already passed', function () {
var fakeCurrentTime = new Date(2013, 3, 1, 8, 12).getTime();
var expectedTime = new Date(2013, 3, 2, 5, 0, 0).getTime();
sandbox.useFakeTimers(fakeCurrentTime);
@@ -67,9 +80,9 @@ describe('Settings Controller', function() {
});
});
describe('#saveDayStart', function() {
describe('#saveDayStart', function () {
it('updates user\'s custom day start and last cron', function() {
it('updates user\'s custom day start and last cron', function () {
var fakeCurrentTime = new Date(2013, 3, 1, 8, 12).getTime();
var expectedTime = fakeCurrentTime;
sandbox.useFakeTimers(fakeCurrentTime);
@@ -83,4 +96,191 @@ describe('Settings Controller', function() {
});
});
});
context('Player Reroll', function () {
describe('#reroll', function () {
beforeEach(function () {
scope.clickReroll(actionClickEvent);
});
it('destroys the previous popover if it exists', function () {
sandbox.spy($.fn, 'popover');
scope.reroll(false);
expect(scope.popoverEl).to.exist;
expect($.fn.popover).to.be.calledWith('destroy');
});
it('doesn\'t call reroll when not confirmed', function () {
scope.reroll(false);
expect(user.ops.reroll).to.not.be.calledOnce;
});
it('calls reroll on the user when confirmed', function () {
sandbox.stub(rootScope.$state, 'go');
scope.reroll(true);
expect(user.ops.reroll).to.be.calledWith({});
});
it('navigates to the tasks page when confirmed', function () {
sandbox.stub(rootScope.$state, 'go');
scope.reroll(true);
expect(rootScope.$state.go).to.be.calledWith('tasks');
});
});
describe('#clickReroll', function () {
it('displays a confirmation popover for the user', function () {
sandbox.spy($.fn, 'popover');
scope.clickReroll(actionClickEvent);
expect($.fn.popover).to.be.calledWith('destroy');
expect($.fn.popover).to.be.calledWith('show');
});
});
});
context('Player Rebirth', function () {
describe('#rebirth', function () {
beforeEach(function () {
scope.clickRebirth(actionClickEvent);
});
it('destroys the previous popover if it exists', function () {
sandbox.spy($.fn, 'popover');
scope.rebirth(false);
expect(scope.popoverEl).to.exist;
expect($.fn.popover).to.be.calledWith('destroy');
});
it('doesn\'t call rebirth when not confirmed', function () {
scope.rebirth(false);
expect(user.ops.rebirth).to.not.be.calledOnce;
});
it('calls rebirth on the user when confirmed', function () {
sandbox.stub(rootScope.$state, 'go');
scope.rebirth(true);
expect(user.ops.rebirth).to.be.calledWith({});
});
it('navigates to tasks page when confirmed', function () {
sandbox.stub(rootScope.$state, 'go');
scope.rebirth(true);
expect(rootScope.$state.go).to.be.calledWith('tasks');
});
});
describe('#clickRebirth', function () {
it('displays a confirmation popover for the user', function () {
sandbox.spy($.fn, 'popover');
scope.clickRebirth(actionClickEvent);
expect($.fn.popover).to.be.calledWith('destroy');
expect($.fn.popover).to.be.calledWith('show');
});
});
})
context('Releasing pets and mounts', function () {
describe('#release', function () {
beforeEach(function () {
scope.clickRelease('dummy', actionClickEvent);
sandbox.stub(rootScope.$state, 'go');
});
it('destroys the previous popover if it exists', function () {
sandbox.spy($.fn, 'popover');
scope.releaseAnimals('', false);
expect($.fn.popover).to.be.calledWith('destroy');
});
it('doesn\'t call any release method if type is not provided', function () {
scope.releaseAnimals();
expect(User.user.ops.releasePets).to.not.be.called;
expect(User.user.ops.releaseMounts).to.not.be.called;
expect(User.user.ops.releaseBoth).to.not.be.called;
});
it('doesn\'t redirect to tasks page if type is not provided', function () {
scope.releaseAnimals();
expect(rootScope.$state.go).to.not.be.called;
})
it('calls releasePets when "pets" is provided', function () {
scope.releaseAnimals('pets');
expect(User.user.ops.releasePets).to.be.calledOnce;
});
it('navigates to the tasks page when "pets" is provided', function () {
scope.releaseAnimals('pets');
expect(rootScope.$state.go).to.be.calledOnce;
});
it('calls releaseMounts when "mounts" is provided', function () {
scope.releaseAnimals('mounts');
expect(User.user.ops.releaseMounts).to.be.calledOnce;
});
it('navigates to the tasks page when "mounts" is provided', function () {
scope.releaseAnimals('mounts');
expect(rootScope.$state.go).to.be.calledOnce;
});
it('calls releaseBoth when "both" is provided', function () {
scope.releaseAnimals('both');
expect(User.user.ops.releaseBoth).to.be.calledOnce;
});
it('navigates to the tasks page when "both" is provided', function () {
scope.releaseAnimals('both');
expect(rootScope.$state.go).to.be.calledOnce;
});
it('does not call release functions when non-applicable argument is passed in', function () {
scope.releaseAnimals('dummy');
expect(User.user.ops.releasePets).to.not.be.called;
expect(User.user.ops.releaseMounts).to.not.be.called;
expect(User.user.ops.releaseBoth).to.not.be.called;
});
});
describe('#clickRelease', function () {
it('displays a confirmation popover for the user', function () {
sandbox.spy($.fn, 'popover');
scope.clickRelease('dummy', actionClickEvent);
expect($.fn.popover).to.be.calledWith('destroy');
expect($.fn.popover).to.be.called;
expect($.fn.popover).to.be.calledWith('show');
});
});
});
});
+36 -4
View File
@@ -1,12 +1,18 @@
'use strict';
describe('Tasks Controller', function() {
var $rootScope, shared, scope, user, ctrl;
var $rootScope, shared, scope, user, User, ctrl;
beforeEach(function() {
user = specHelper.newUser();
User = {
user: user
};
User.user.ops = {
deleteTask: sandbox.stub(),
};
module(function($provide) {
$provide.value('User', {user: user});
$provide.value('User', User);
$provide.value('Guide', {});
});
@@ -14,9 +20,9 @@ describe('Tasks Controller', function() {
scope = $rootScope.$new();
shared = Shared;
$controller('RootCtrl', {$scope: scope, User: {user: user}});
$controller('RootCtrl', {$scope: scope, User: User});
ctrl = $controller('TasksCtrl', {$scope: scope, User: {user: user}});
ctrl = $controller('TasksCtrl', {$scope: scope, User: User});
});
});
@@ -29,6 +35,32 @@ describe('Tasks Controller', function() {
});
});
describe('removeTask', function() {
var task;
beforeEach(function() {
sandbox.stub(window, 'confirm');
task = specHelper.newTodo();
});
it('asks user to confirm deletion', function() {
scope.removeTask(task);
expect(window.confirm).to.be.calledOnce;
});
it('does not remove task if not confirmed', function() {
window.confirm.returns(false);
scope.removeTask(task);
expect(user.ops.deleteTask).to.not.be.called;
});
it('removes task', function() {
window.confirm.returns(true);
scope.removeTask(task);
expect(user.ops.deleteTask).to.be.calledOnce;
});
});
describe('watch to updateStore', function() {
it('updates itemStore when user gear changes', function() {
sinon.stub(shared, 'updateStore').returns({item: true});
+2 -2
View File
@@ -26,7 +26,7 @@ var specHelper = {};
gear: { equipped: {}, costume: {}, owned: {} }
};
user = {
var user = {
_id: 'unique-user-id',
auth: { timestamps: {} },
stats: stats,
@@ -53,7 +53,7 @@ var specHelper = {};
function newGroup(overrides) {
var quest = { progress: { }, active: false };
group = {
var group = {
_id: 'group-id',
leader : 'leader-id',
memberCount : 1,