habitica/test/user.mocha.coffee

255 lines
9.1 KiB
CoffeeScript
Raw Normal View History

2012-09-23 19:19:29 +00:00
{expect} = require 'derby/node_modules/racer/test/util'
{BrowserModel: Model} = require 'derby/node_modules/racer/test/util/model'
2012-09-24 01:07:37 +00:00
derby = require 'derby'
2012-09-24 22:47:08 +00:00
_ = require 'lodash'
moment = require 'moment'
2012-09-24 01:07:37 +00:00
# Custom modules
2012-09-23 19:19:29 +00:00
scoring = require '../src/app/scoring'
schema = require '../src/app/schema'
2012-09-24 20:19:27 +00:00
###### Helpers & Variables ######
model = null
uuid = null
taskPath = null
## Helper which clones the content at a path so tests can compare before/after values
# Otherwise, using model.get(path) will give the same object before as after
pathSnapshots = (paths) ->
if _.isString(paths)
return _.clone(model.get(paths))
_.map paths, (path) -> _.clone(model.get(path))
statsTask = -> pathSnapshots(['_user.stats', taskPath]) # quick snapshot of user.stats & task
cleanUserObj = ->
userObj = schema.newUserObject()
userObj.tasks = {}
userObj.habitIds = []
userObj.dailyIds = []
userObj.todoIds = []
userObj.rewardIds = []
return userObj
resetUser = -> model.set '_user', cleanUserObj()
freshTask = (taskObj) ->
resetUser()
# create a test task
uuid = derby.uuid()
taskPath = "_user.tasks.#{uuid}"
{type} = taskObj
model.refList "_#{type}List", "_user.tasks", "_user.#{type}Ids"
[taskObj.id, taskObj.value] = [uuid, 0]
model.at("_#{type}List").push taskObj
###
Helper function to determine if stats-updates are numerically correct based on scoring
{modifiers} The user stats modifiers as {lvl, armor, weapon}
{direction} 'up' or 'down'
###
modificationsLookup = (modifiers, direction, times=1) ->
userObj = cleanUserObj()
value = 0
{lvl, armor, weapon} = modifiers
_.times times, (n) ->
delta = scoring.taskDeltaFormula(value, direction)
value += delta
if direction=='up'
gain = scoring.expModifier(delta, modifiers)
userObj.stats.exp += gain
userObj.stats.gp += gain
else
loss = scoring.hpModifier(delta, modifiers)
userObj.stats.hp += loss
console.log {stats:userObj.stats, value:value}
return userObj
###### Specs ######
2012-09-24 16:52:44 +00:00
2012-09-24 15:28:01 +00:00
describe 'User', ->
2012-09-23 01:04:34 +00:00
model = null
before ->
2012-09-23 01:04:34 +00:00
model = new Model
2012-09-23 19:19:29 +00:00
model.set '_user', schema.newUserObject()
2012-09-24 13:45:05 +00:00
scoring.setModel model
2012-09-23 19:19:29 +00:00
2012-09-24 15:36:44 +00:00
it 'sets correct user defaults', ->
2012-09-23 01:04:34 +00:00
user = model.get '_user'
2012-09-23 19:19:29 +00:00
expect(user.stats).to.eql { money: 0, exp: 0, lvl: 1, hp: 50 }
expect(user.items).to.eql { itemsEnabled: false, armor: 0, weapon: 0 }
2012-09-23 19:19:29 +00:00
expect(user.balance).to.eql 2
expect(_.size(user.tasks)).to.eql 9
expect(_.size(user.habitIds)).to.eql 3
expect(_.size(user.dailyIds)).to.eql 3
expect(_.size(user.todoIds)).to.eql 1
expect(_.size(user.completedIds)).to.eql 0
expect(_.size(user.rewardIds)).to.eql 2
2012-09-24 13:45:05 +00:00
##### Habits #####
2012-09-24 15:36:44 +00:00
describe 'Tasks', ->
2012-09-24 01:07:37 +00:00
2012-09-26 03:04:24 +00:00
beforeEach ->
resetUser()
describe 'Habits', ->
beforeEach ->
freshTask {type: 'habit', text: 'Habit', up: true, down: true}
2012-09-24 13:45:05 +00:00
2012-09-24 15:36:44 +00:00
it 'created the habit', ->
task = model.get(taskPath)
expect(task.text).to.eql 'Habit'
expect(task.value).to.eql 0
it 'made proper modifications when down-scored', ->
2012-09-24 16:52:44 +00:00
## Trial 1
2012-09-24 22:47:08 +00:00
[statsBefore, taskBefore] = statsTask()
2012-09-24 16:52:44 +00:00
scoring.score(uuid, 'down')
2012-09-24 22:47:08 +00:00
[statsAfter, taskAfter] = statsTask()
2012-09-24 15:36:44 +00:00
# User should have lost HP
2012-09-24 16:52:44 +00:00
expect(statsAfter.hp).to.be.lessThan statsBefore.hp
2012-09-24 15:36:44 +00:00
# Exp, GP should stay the same
2012-09-24 16:52:44 +00:00
expect(statsAfter.money).to.eql statsBefore.money
expect(statsAfter.exp).to.eql statsBefore.exp
# Task should have gained in value (we're going down, so think Math.abs(task.value))
expect(taskBefore.value).to.eql 0
expect(taskAfter.value).to.eql -1
## Trial 2
2012-09-24 22:47:08 +00:00
taskBefore = pathSnapshots(taskPath)
2012-09-24 16:52:44 +00:00
scoring.score(uuid, 'down')
2012-09-24 22:47:08 +00:00
taskAfter = pathSnapshots(taskPath)
2012-09-24 16:52:44 +00:00
# Should have gained in value
expect(taskAfter.value).to.be < taskBefore.value
# And gained more than trial 1
2012-09-24 22:47:08 +00:00
diff = Math.abs(taskAfter.value) - Math.abs(taskBefore.value)
expect(diff).to.be.greaterThan 1
2012-09-24 15:36:44 +00:00
it 'made proper modifications when up-scored', ->
# Up-score the habit
2012-09-24 22:47:08 +00:00
[statsBefore, taskBefore] = statsTask()
2012-09-24 15:36:44 +00:00
scoring.score(uuid, 'up')
2012-09-24 22:47:08 +00:00
[statsAfter, taskAfter] = statsTask()
2012-09-24 15:36:44 +00:00
# User should have gained Exp, GP
2012-09-24 16:52:44 +00:00
expect(statsAfter.exp).to.be.greaterThan statsBefore.exp
expect(statsAfter.money).to.be.greaterThan statsBefore.money
2012-09-24 15:36:44 +00:00
# HP should not change
2012-09-24 16:52:44 +00:00
expect(statsAfter.hp).to.eql statsBefore.hp
2012-09-24 15:36:44 +00:00
# Task should have lost value
2012-09-24 16:52:44 +00:00
expect(taskBefore.value).to.eql 0
2012-09-24 23:03:26 +00:00
expect(taskAfter.value).to.be.greaterThan taskBefore.value
## Trial 2
taskBefore = pathSnapshots(taskPath)
scoring.score(uuid, 'up')
taskAfter = pathSnapshots(taskPath)
# Should have lost in value
expect(taskAfter.value).to.be > taskBefore.value
# And lost more than trial 1
diff = Math.abs(taskAfter.value) - Math.abs(taskBefore.value)
expect(diff).to.be.lessThan 1
2012-09-24 15:36:44 +00:00
2012-09-24 16:52:44 +00:00
it 'makes history entry for habit'
it 'makes proper modifications each time when clicking + / - in rapid succession'
# saw an issue here once, so test that it wasn't a fluke
2012-09-24 15:36:44 +00:00
it 'should not modify certain attributes given certain conditions'
# non up+down habits
# what else?
it 'should show "undo" notification if user unchecks completed daily'
2012-09-24 13:45:05 +00:00
describe 'Lvl & Items', ->
2012-09-26 03:04:24 +00:00
beforeEach ->
freshTask {type: 'habit', text: 'Habit', up: true, down: true}
it 'modified damage based on lvl & armor', ->
## No Armor, Lvl 1
[stats, task] = statsTask()
expect(stats.hp).to.eql 50
expect(task.value).to.eql 0
scoring.score(uuid, 'down')
[stats, task] = statsTask()
2012-09-26 03:04:24 +00:00
expect(stats.hp).to.eql 49
expect(task.value).to.eql -1
scoring.score(uuid, 'down')
[stats, task] = statsTask()
2012-09-26 03:04:24 +00:00
expect(stats.hp).to.eql 47.9
expect(task.value).to.eql -2.1
scoring.score(uuid, 'down')
[stats, task] = statsTask()
2012-09-26 03:04:24 +00:00
expect(stats.hp).to.eql 46.69
expect(task.value).to.eql -3.31
it 'modified exp/gp based on lvl & weapon', ->
it 'always decreases hp with damage, regardless of stats/items'
it 'always increases exp/gp with gain, regardless of stats/items'
2012-09-24 20:19:27 +00:00
describe 'Dailies', ->
beforeEach ->
freshTask {type: 'daily', text: 'Daily', completed: false}
2012-09-24 20:19:27 +00:00
it 'created the daily', ->
task = model.get(taskPath)
expect(task.text).to.eql 'Daily'
expect(task.value).to.eql 0
it 'does proper calculations when daily is complete'
it 'calculates dailys properly when they have repeat dates'
2012-09-24 20:19:27 +00:00
it 'calculates user.stats & task.value properly on cron', ->
modificationsLookup({lvl:1,armor:0,weapon:0}, 'down', 10)
2012-09-24 22:47:08 +00:00
[statsBefore, taskBefore] = statsTask()
2012-09-24 20:19:27 +00:00
# Set lastCron to yesterday
today = new moment()
yesterday = new moment().subtract('days',1)
model.set '_user.lastCron', yesterday.toDate()
2012-09-24 20:19:27 +00:00
# Run run
scoring.cron()
2012-09-24 22:47:08 +00:00
[statsAfter, taskAfter] = statsTask()
2012-09-24 20:19:27 +00:00
# Should have updated cron to today
lastCron = moment(model.get('_user.lastCron'))
expect(today.diff(lastCron, 'days')).to.eql 0
# Should have updated points properly
expect(statsBefore.hp).to.be.greaterThan statsAfter.hp
2012-09-24 20:19:27 +00:00
expect(taskBefore.value).to.eql 0
expect(taskAfter.value).to.eql -1
2012-09-24 20:19:27 +00:00
2012-09-24 15:36:44 +00:00
#TODO clicking repeat dates on newly-created item doesn't refresh until you refresh the page
#TODO dates on dailies is having issues, possibility: date cusps? my saturday exempts were set to exempt at 8pm friday
2012-09-24 20:19:27 +00:00
describe 'Todos', ->
describe 'Cron', ->
2012-09-24 22:47:08 +00:00
it 'calls cron asyncronously'
2012-09-24 20:19:27 +00:00
it 'should calculate user.stats & task.value properly on cron'
it 'should calculate cron based on difference between start-of-days, and not run in the middle of the day'
it 'should only run set operations once per task, even when daysPassed > 1'
# pass in daysPassed to score, multiply modification values by daysPassed before running set
it 'should only push a history point for lastCron, not each day in between'
# stop passing in tallyFor, let moment().sod().toDate() be handled in scoring.score()
it 'should defer saving user modifications until, save as aggregate values'
# pass in commit parameter to scoring func, if true save right away, otherwise return aggregated array so can save in the end (so total hp loss, etc)
describe 'Rewards', ->
2012-09-24 13:45:05 +00:00
2012-09-24 15:23:28 +00:00
#### Require.js stuff, might be necessary to place in casper.coffee
it "doesn't setup dependent functions until their modules are loaded, require.js callback"
# sortable, stripe, etc
2012-09-24 20:19:27 +00:00
#TODO refactor as user->habits, user->dailys, user->todos, user->rewards