@jeremyckahn/farmhand
Version:
A farming game
372 lines (338 loc) • 10.9 kB
text/typescript
import { testState } from '../../test-utils/index.js'
import { LOAN_PAYOFF } from '../../templates.js'
import { carrot, carrotSeed, corn } from '../../data/crops/index.js'
import { apple, bronzeOre, coal, milk1, saltRock } from '../../data/items.js'
import { carrotSoup } from '../../data/recipes.js'
import { sellItem } from './sellItem.js'
describe('sellItem', () => {
test('sells item', () => {
const state = sellItem(
testState({
// Chosen so carrot's SPRING high-demand seasonal bonus doesn't apply.
dayCount: 16,
inventory: [{ id: carrot.id, quantity: 1 }],
itemsSold: {},
loanBalance: 0,
money: 100,
pendingPeerMessages: [],
todaysNotifications: [],
revenue: 0,
todaysRevenue: 0,
valueAdjustments: { [carrotSeed.id]: 1 },
}),
carrot
)
expect(state.inventory).toEqual([])
expect(state.money).toEqual(125)
expect(state.revenue).toEqual(25)
expect(state.todaysRevenue).toEqual(25)
expect(state.itemsSold).toEqual({ carrot: 1 })
})
test('does not change revenue for seed sales', () => {
const state = sellItem(
testState({
inventory: [{ id: carrotSeed.id, quantity: 1 }],
itemsSold: {},
loanBalance: 0,
money: 100,
pendingPeerMessages: [],
todaysNotifications: [],
revenue: 0,
todaysRevenue: 0,
valueAdjustments: { [carrotSeed.id]: 1 },
}),
carrotSeed
)
expect(state.inventory).toEqual([])
expect(state.money).toEqual(107.5)
expect(state.revenue).toEqual(0)
expect(state.todaysRevenue).toEqual(0)
expect(state.itemsSold).toEqual({ [carrotSeed.id]: 1 })
})
test('applies achievement bonus to farm products', () => {
const state = sellItem(
testState({
// Chosen so carrot's SPRING high-demand seasonal bonus doesn't apply.
dayCount: 16,
inventory: [{ id: carrot.id, quantity: 1 }],
itemsSold: {},
loanBalance: 0,
money: 100,
pendingPeerMessages: [],
todaysNotifications: [],
revenue: 0,
todaysRevenue: 0,
valueAdjustments: { [carrot.id]: 1 },
completedAchievements: {
'i-am-rich-3': true,
},
}),
carrot
)
expect(state.inventory).toEqual([])
expect(state.money).toEqual(131.25)
expect(state.revenue).toEqual(31.25)
expect(state.todaysRevenue).toEqual(31.25)
expect(state.itemsSold).toEqual({ [carrot.id]: 1 })
})
test('does not apply achievement bonus to seeds', () => {
const state = sellItem(
testState({
inventory: [{ id: carrotSeed.id, quantity: 1 }],
itemsSold: {},
loanBalance: 0,
money: 100,
pendingPeerMessages: [],
todaysNotifications: [],
revenue: 0,
todaysRevenue: 0,
valueAdjustments: { [carrotSeed.id]: 1 },
completedAchievements: {
'i-am-rich-3': true,
},
}),
carrotSeed
)
expect(state.inventory).toEqual([])
expect(state.money).toEqual(107.5)
expect(state.revenue).toEqual(0)
expect(state.todaysRevenue).toEqual(0)
expect(state.itemsSold).toEqual({ [carrotSeed.id]: 1 })
})
test('updates learnedRecipes', () => {
const { learnedRecipes } = sellItem(
testState({
// Chosen so carrot's SPRING high-demand seasonal bonus doesn't apply.
dayCount: 16,
inventory: [{ id: carrot.id, quantity: 2 }],
itemsSold: {},
loanBalance: 0,
money: 100,
pendingPeerMessages: [],
todaysNotifications: [],
revenue: 0,
todaysRevenue: 0,
valueAdjustments: { [carrot.id]: 1 },
}),
carrot,
15
)
expect(learnedRecipes[carrotSoup.id]).toBeTruthy()
})
describe('there is an outstanding loan', () => {
let state: farmhand.state
describe('item is not a farm product', () => {
beforeEach(() => {
state = sellItem(
testState({
experience: 0,
inventory: [{ id: carrotSeed.id, quantity: 3 }],
itemsSold: {},
loanBalance: 100,
money: 100,
pendingPeerMessages: [],
todaysNotifications: [],
revenue: 0,
todaysRevenue: 0,
valueAdjustments: { [carrotSeed.id]: 1 },
}),
carrotSeed,
3
)
})
test('sale is not garnished', () => {
expect(state.loanBalance).toEqual(100)
expect(state.money).toEqual(122.5)
expect(state.revenue).toEqual(0)
expect(state.todaysRevenue).toEqual(0)
})
test('experience is not gained', () => {
expect(state.experience).toEqual(0)
})
})
describe('item is a farm product', () => {
describe('loan is greater than garnishment', () => {
test('sale is garnished', () => {
state = sellItem(
testState({
// Chosen so carrot's SPRING high-demand seasonal bonus doesn't apply.
dayCount: 16,
inventory: [{ id: carrot.id, quantity: 3 }],
itemsSold: {},
loanBalance: 100,
money: 100,
pendingPeerMessages: [],
todaysNotifications: [],
revenue: 0,
todaysRevenue: 0,
valueAdjustments: { [carrot.id]: 1 },
}),
carrot,
3
)
expect(state.loanBalance).toEqual(96.25)
expect(state.money).toEqual(171.25)
expect(state.revenue).toEqual(71.25)
expect(state.todaysRevenue).toEqual(71.25)
})
})
describe('loan is less than garnishment', () => {
beforeEach(() => {
state = sellItem(
testState({
// Chosen so carrot's SPRING high-demand seasonal bonus doesn't apply.
dayCount: 16,
experience: 0,
inventory: [{ id: carrot.id, quantity: 3 }],
itemsSold: {},
loanBalance: 1.5,
money: 100,
pendingPeerMessages: [],
todaysNotifications: [],
revenue: 0,
todaysRevenue: 0,
valueAdjustments: { [carrot.id]: 1 },
}),
carrot,
3
)
})
test('loan is payed off', () => {
expect(state.loanBalance).toEqual(0)
})
test('sale is reduced based on remaining loan balance', () => {
expect(state.money).toEqual(173.5)
expect(state.todaysRevenue).toEqual(73.5)
})
test('payoff notification is shown', () => {
expect(state.todaysNotifications).toEqual([
{ message: LOAN_PAYOFF(), severity: 'success' },
])
})
test('experience is gained', () => {
expect(state.experience).toEqual(3)
})
})
})
})
const experienceTestArgs = [
carrot,
apple,
milk1,
coal,
carrotSoup,
bronzeOre,
saltRock,
].map(item => [item.type, item])
test.each(experienceTestArgs)(
'selling item of type %s gives experience',
(_, item) => {
// Cast item to ensure TypeScript recognizes it as an item object
const itemObj = item as any
const state = sellItem(
testState({
experience: 0,
inventory: [{ id: itemObj.id, quantity: 1 }],
itemsSold: {},
loanBalance: 0,
money: 100,
pendingPeerMessages: [],
todaysNotifications: [],
revenue: 0,
todaysRevenue: 0,
valueAdjustments: { [itemObj.id]: 1 },
}),
itemObj,
1
)
expect(state.experience).toEqual(1)
}
)
describe('seasonal demand', () => {
test('applies a high demand bonus during a crop high demand season', () => {
// dayCount 1 is SPRING, carrot's configured high demand season.
const state = sellItem(
testState({
dayCount: 1,
inventory: [{ id: carrot.id, quantity: 1 }],
itemsSold: {},
loanBalance: 0,
money: 100,
pendingPeerMessages: [],
todaysNotifications: [],
revenue: 0,
todaysRevenue: 0,
valueAdjustments: { [carrot.id]: 1 },
}),
carrot
)
expect(state.money).toEqual(130)
expect(state.revenue).toEqual(30)
})
test('bases loan garnishment on the seasonally-adjusted sale price, not the base price', () => {
// dayCount 1 is SPRING, carrot's configured high demand season, so the
// $25 base value sells for $30. Garnishment is 5% of that $30 (=
// $1.50), not 5% of the un-boosted $25 (= $1.25) - otherwise the
// effective garnishment rate would drift with the season instead of
// staying at a flat LOAN_GARNISHMENT_RATE.
const state = sellItem(
testState({
dayCount: 1,
inventory: [{ id: carrot.id, quantity: 1 }],
itemsSold: {},
loanBalance: 100,
money: 100,
pendingPeerMessages: [],
todaysNotifications: [],
revenue: 0,
todaysRevenue: 0,
valueAdjustments: { [carrot.id]: 1 },
}),
carrot
)
expect(state.loanBalance).toEqual(98.5)
expect(state.money).toEqual(128.5)
expect(state.revenue).toEqual(28.5)
})
test('applies a low demand penalty during a crop low demand season', () => {
// dayCount 1 is SPRING, corn's configured low demand season.
const state = sellItem(
testState({
dayCount: 1,
inventory: [{ id: corn.id, quantity: 1 }],
itemsSold: {},
loanBalance: 0,
money: 100,
pendingPeerMessages: [],
todaysNotifications: [],
revenue: 0,
todaysRevenue: 0,
valueAdjustments: { [corn.id]: 1 },
}),
corn
)
expect(state.money).toEqual(156)
expect(state.revenue).toEqual(56)
})
test('does not apply the seasonal multiplier to seed sales', () => {
// dayCount 1 is SPRING, which is carrot's high demand season, but this
// must not apply to selling the seed - see the #140 guard in Item.tsx.
const state = sellItem(
testState({
dayCount: 1,
inventory: [{ id: carrotSeed.id, quantity: 1 }],
itemsSold: {},
loanBalance: 0,
money: 100,
pendingPeerMessages: [],
todaysNotifications: [],
revenue: 0,
todaysRevenue: 0,
valueAdjustments: { [carrotSeed.id]: 1 },
}),
carrotSeed
)
expect(state.money).toEqual(107.5)
})
})
})