habitica-self-host/tests/algos.mocha.coffee

206 lines
7.9 KiB
CoffeeScript
Raw Normal View History

_ = require 'lodash'
expect = require 'expect.js'
moment = require 'moment'
# Custom modules
algos = require '../script/algos'
helpers = require '../script/helpers'
items = require '../script/items'
### Helper Functions ####
expectStrings = (obj, paths) ->
_.each paths, (path) -> expect(obj[path]).to.be.ok()
beforeAfter = (options={}) ->
user = helpers.newUser()
[before, after] = [_.cloneDeep(user), _.cloneDeep(user)]
2013-05-25 15:32:58 +00:00
before.preferences.dayStart = after.preferences.dayStart = options.dayStart if options.dayStart
if options.limitOne
before["#{options.limitOne}s"] = [before["#{options.limitOne}s"][0]]
after["#{options.limitOne}s"] = [after["#{options.limitOne}s"][0]]
lastCron = +(moment(options.now || +new Date).subtract('days', options.daysAgo)) if options.daysAgo
_.each [before,after], (obj) ->
obj.lastCron = lastCron if options.daysAgo
{before:before, after:after}
#TODO calculate actual poins
expectLostPoints = (before, after, taskType) ->
if taskType in ['daily','habit']
expect(after.stats.hp).to.be.lessThan before.stats.hp
expect(_.size(after["#{taskType}s"][0].history)).to.be(1)
else expect(_.size(after.history.todos)).to.be(1)
expect(after.stats.exp).to.be 0
expect(after.stats.gp).to.be 0
expect(after["#{taskType}s"][0].value).to.be.lessThan before["#{taskType}s"][0].value
expectGainedPoints = (before, after, taskType) ->
expect(after.stats.hp).to.be 50
expect(after.stats.exp).to.be.greaterThan before.stats.exp
expect(after.stats.gp).to.be.greaterThan before.stats.gp
expect(after["#{taskType}s"][0].value).to.be.greaterThan before["#{taskType}s"][0].value
expect(_.size(after["#{taskType}s"][0].history)).to.be(1) if taskType is 'habit'
# daily & todo histories handled on cron
2013-05-25 15:32:58 +00:00
expectNoChange = (before,after) -> expect(before).to.eql after
expectDayResetNoDamage = (b,a) ->
[before,after] = [_.cloneDeep(b); _.cloneDeep(a)]
_.each after.dailys, (task,i) ->
expect(task.completed).to.be false
expect(before.dailys[i].value).to.be task.value
expect(before.dailys[i].streak).to.be task.streak
expect(_.size(task.history)).to.be(1)
_.each after.todos, (task,i) ->
expect(task.completed).to.be false
expect(before.todos[i].value).to.be.greaterThan task.value
expect(_.size(after.history.todos)).to.be(1)
# hack so we can compare user before/after obj equality sans effected paths
_.each ['dailys','todos','history','lastCron'], (path) ->
_.each [before,after], (obj) -> delete obj[path]
expect(after).to.eql before
###### Specs ######
describe 'User', ->
it 'sets correct user defaults', ->
user = helpers.newUser()
expect(user.stats).to.eql { gp: 0, exp: 0, lvl: 1, hp: 50 }
expect(user.party).to.eql { invitation: null }
expect(user.items).to.eql { weapon: 0, armor: 0, head: 0, shield: 0 }
expect(user.preferences).to.eql { gender: 'm', skin: 'white', hair: 'blond', armorSet: 'v1', dayStart:0, showHelm: true }
expect(user.balance).to.eql 0
expect(user.lastCron).to.eql 'new'
expect(user.flags).to.eql {partyEnabled: false, itemsEnabled: false, ads: 'show'}
expectStrings(user, ['apiToken'])
expectStrings(user.habits[0], ['text','id'])
expectStrings(user.dailys[0], ['text','id'])
expectStrings(user.todos[0], ['text','id'])
expectStrings(user.rewards[0], ['text','id'])
expectStrings(user.tags[0], ['name','id'])
expectStrings(user.tags[1], ['name','id'])
expectStrings(user.tags[2], ['name','id'])
describe 'Simple Scoring', ->
it 'Habits : Up', ->
{before,after} = beforeAfter()
algos.score(after, after.habits[0], 'down', {times:5})
expectLostPoints(before,after,'habit')
it 'Habits : Down', ->
{before,after} = beforeAfter()
algos.score(after, after.habits[0], 'up', {times:5})
expectGainedPoints(before,after,'habit')
it 'Dailys : Up', ->
{before,after} = beforeAfter()
algos.score(after, after.dailys[0], 'up')
expectGainedPoints(before,after,'daily')
2013-05-24 15:12:55 +00:00
it 'Todos : Up', ->
{before,after} = beforeAfter()
algos.score(after, after.todos[0], 'up')
expectGainedPoints(before,after,'todo')
describe 'Cron', ->
2013-05-24 15:12:55 +00:00
it 'computes shouldCron', ->
user = helpers.newUser()
2013-05-24 15:12:55 +00:00
expect(algos.shouldCron(user)).to.be true # handlomg lastCron='new'
2013-05-25 15:32:58 +00:00
user.lastCron = +moment().subtract('days',1)
expect(algos.shouldCron(user)).to.be true
2013-05-25 15:32:58 +00:00
user.lastCron = +moment().add('days',1)
2013-05-24 15:12:55 +00:00
expect(algos.shouldCron(user)).to.be false
it 'only dailies & todos are effected', ->
{before,after} = beforeAfter({daysAgo:1})
before.dailys = before.todos = after.dailys = after.todos = []
algos.cron(after)
expect(after.lastCron).to.not.be before.lastCron # make sure cron was run
expect(before.stats).to.eql after.stats
beforeTasks = before.habits.concat(before.dailys).concat(before.todos).concat(before.rewards)
afterTasks = after.habits.concat(after.dailys).concat(after.todos).concat(after.rewards)
expect(beforeTasks).to.eql afterTasks
describe 'Todos', ->
it '1 day missed', ->
{before,after} = beforeAfter({daysAgo:1})
before.dailys = after.dailys = []
algos.cron(after)
# todos don't effect stats
expect(after.stats.hp).to.be 50
expect(after.stats.exp).to.be 0
expect(after.stats.gp).to.be 0
# but they devalue
expect(after.todos[0].value).to.be.lessThan before.todos[0].value
expect(_.size(after.history.todos)).to.be 1
2013-05-25 15:32:58 +00:00
describe 'dailies', ->
2013-05-25 15:32:58 +00:00
describe 'new day', ->
#TODO check helpers.isDue()
2013-05-25 15:32:58 +00:00
runCron = (options) ->
now = moment().startOf('week').add('hours',options.currentHour || 0)
{before,after} = beforeAfter({now, daysAgo:1, dayStart:options.dayStart||0, limitOne:'daily'})
before.dailys[0].repeat = after.dailys[0].repeat = options.repeat if options.repeat
before.dailys[0].streak = after.dailys[0].streak = 10
algos.cron(after,{now})
{before,after}
2013-05-25 15:32:58 +00:00
it 'due yesterday', ->
{before,after} = beforeAfter({daysAgo:1, limitOne: 'daily'})
algos.cron(after)
expectLostPoints(before,after,'daily')
2013-05-25 15:32:58 +00:00
it 'due yesterday, custom day started', ->
repeat = {su:1,m:1,t:1,w:1,th:1,f:1,s:true}
expect(helpers.shouldDo())
{before,after} = runCron({currentHour:5, dayStart:4, repeat})
2013-05-25 15:32:58 +00:00
expectLostPoints(before,after,'daily')
2013-05-25 15:32:58 +00:00
it 'due yesterday, custom day NOT started', ->
{before,after} = runCron({currentHour:3, dayStart:4, repeat:{su:1,m:1,t:1,w:1,th:1,f:1,s:true}})
expectNoChange(before,after)
it 'not due yesterday', ->
{before,after} = runCron({repeat:{su:1,m:1,t:1,w:1,th:1,f:1,s:false}})
expectDayResetNoDamage(before,after)
it 'not due yesterday, custom day started', ->
{before,after} = runCron({currentHour:5,dayStart:4,repeat:{su:1,m:1,t:1,w:1,th:1,f:1,s:false}})
expectDayResetNoDamage(before,after)
it 'not due yesterday, custom day NOT started', ->
{before,after} = runCron({currentHour:3,dayStart:4,repeat:{su:1,m:1,t:1,w:1,th:1,f:1,s:false}})
expectNoChange(before,after)
2013-05-24 15:12:55 +00:00
it 'due today, custom day not started'
it 'checked yesterday, custom day not started'
it 'checked yesterday, custom day started'
it '1 day missed, not due'
it '1 day missed, not day start yet'
it '3 day missed, only 1 due'
it '3 day missed, only 1 due, not day start yet'
2013-05-24 15:12:55 +00:00
it 'calculates day differences with dayStart properly', ->
dayStart = 4
yesterday = moment().subtract('d', 1).add('h', dayStart)
now = moment().startOf('day').add('h', dayStart-1) #today
console.log {yesterday: yesterday.format('MM/DD HH:00'), now: now.format('MM/DD HH:00')}
console.log {diff: Math.abs(moment(yesterday).diff(moment(now), 'days'))}
expect(helpers.daysBetween(yesterday, now, dayStart)).to.eql 0
now = moment().startOf('day').add('h', dayStart)
console.log {now: now.format('MM/DD HH:00')}
expect(helpers.daysBetween(yesterday, now, dayStart)).to.eql 1