@jeremyckahn/farmhand
Version:
A farming game
278 lines (255 loc) • 7.34 kB
text/typescript
import { LOAN_GARNISHMENT_RATE } from '../../constants.js'
import { carrot } from '../../data/crops/index.js'
import { LOAN_PAYOFF } from '../../templates.js'
import { castToMoney } from '../../utils/castToMoney.js'
import { getKegValue } from '../../utils/getKegValue.js'
import { testState } from '../../test-utils/index.js'
import { sellKeg } from './sellKeg.js'
const stubKeg: farmhand.keg = {
id: 'stub-keg',
daysUntilMature: -4,
itemId: carrot.id,
}
const stubKegValue = getKegValue(stubKeg)
describe('sellKeg', () => {
test('updates inventory', () => {
const state = sellKeg(
testState({
playerId: 'abc123',
cellarInventory: [stubKeg],
cellarItemsSold: {},
completedAchievements: {},
itemsSold: {},
learnedRecipes: {},
loanBalance: 500,
money: 1000,
pendingPeerMessages: [],
revenue: 0,
todaysRevenue: 0,
}),
stubKeg
)
expect(state).toMatchObject({
cellarInventory: [],
})
})
test('updates sales records', () => {
const state = sellKeg(
testState({
playerId: 'abc123',
cellarInventory: [stubKeg],
cellarItemsSold: {},
completedAchievements: {},
itemsSold: {},
learnedRecipes: {},
loanBalance: 500,
money: 1000,
pendingPeerMessages: [],
revenue: 0,
todaysRevenue: 0,
}),
stubKeg
)
expect(state).toMatchObject({
cellarItemsSold: { carrot: 1 },
itemsSold: { carrot: 1 },
pendingPeerMessages: [
{
playerId: 'abc123',
message: 'sold one unit of Fermented Carrot.',
severity: 'warning',
},
],
})
})
test('applies achievement bonus', () => {
const state = sellKeg(
testState({
playerId: 'abc123',
cellarInventory: [stubKeg],
cellarItemsSold: {},
completedAchievements: { 'i-am-rich-1': true },
itemsSold: {},
learnedRecipes: {},
loanBalance: 500,
money: 1000,
pendingPeerMessages: [],
revenue: 0,
todaysRevenue: 0,
}),
stubKeg
)
const adjustedKegValue = stubKegValue * 1.05
expect(state).toMatchObject({
loanBalance: castToMoney(500 - stubKegValue * LOAN_GARNISHMENT_RATE),
money: castToMoney(
1000 + adjustedKegValue - stubKegValue * LOAN_GARNISHMENT_RATE
),
revenue: castToMoney(
adjustedKegValue - stubKegValue * LOAN_GARNISHMENT_RATE
),
todaysRevenue: castToMoney(
adjustedKegValue - stubKegValue * LOAN_GARNISHMENT_RATE
),
})
})
test('updates learnedRecipes', () => {
const state = sellKeg(
testState({
playerId: 'abc123',
cellarInventory: [stubKeg],
cellarItemsSold: {},
completedAchievements: {},
itemsSold: { carrot: 9 },
learnedRecipes: {},
loanBalance: 500,
money: 1000,
pendingPeerMessages: [],
revenue: 0,
todaysRevenue: 0,
}),
stubKeg
)
expect(state).toMatchObject({
learnedRecipes: { 'carrot-soup': true },
itemsSold: { carrot: 10 },
})
})
describe('there is an outstanding loan', () => {
describe('loan is greater than garnishment', () => {
test('sale is garnished', () => {
const state = sellKeg(
testState({
playerId: 'abc123',
cellarInventory: [stubKeg],
cellarItemsSold: {},
completedAchievements: {},
itemsSold: {},
learnedRecipes: {},
loanBalance: 500,
money: 1000,
pendingPeerMessages: [],
revenue: 0,
todaysRevenue: 0,
}),
stubKeg
)
expect(state).toMatchObject({
loanBalance: castToMoney(500 - stubKegValue * LOAN_GARNISHMENT_RATE),
money: castToMoney(
1000 + stubKegValue - stubKegValue * LOAN_GARNISHMENT_RATE
),
revenue: castToMoney(
stubKegValue - stubKegValue * LOAN_GARNISHMENT_RATE
),
todaysRevenue: castToMoney(
stubKegValue - stubKegValue * LOAN_GARNISHMENT_RATE
),
})
})
})
describe('loan is less than garnishment', () => {
test('loan is payed off', () => {
const state = sellKeg(
testState({
playerId: 'abc123',
cellarInventory: [stubKeg],
cellarItemsSold: {},
completedAchievements: {},
itemsSold: {},
learnedRecipes: {},
loanBalance: 1,
money: 1000,
pendingPeerMessages: [],
revenue: 0,
todaysRevenue: 0,
todaysNotifications: [],
}),
stubKeg
)
expect(state).toMatchObject({
loanBalance: 0,
})
})
test('sale is reduced by remaining loan balance', () => {
const state = sellKeg(
testState({
playerId: 'abc123',
cellarInventory: [stubKeg],
cellarItemsSold: {},
completedAchievements: {},
itemsSold: {},
learnedRecipes: {},
loanBalance: 1,
money: 1000,
pendingPeerMessages: [],
revenue: 0,
todaysRevenue: 0,
todaysNotifications: [],
}),
stubKeg
)
expect(state).toMatchObject({
money: castToMoney(1000 + stubKegValue - 1),
revenue: castToMoney(stubKegValue - 1),
todaysRevenue: castToMoney(stubKegValue - 1),
})
})
test('payoff notification is shown', () => {
const state = sellKeg(
testState({
playerId: 'abc123',
cellarInventory: [stubKeg],
cellarItemsSold: {},
completedAchievements: {},
itemsSold: {},
learnedRecipes: {},
loanBalance: 1,
money: 1000,
pendingPeerMessages: [],
revenue: 0,
todaysRevenue: 0,
todaysNotifications: [],
}),
stubKeg
)
expect(state).toMatchObject({
todaysNotifications: [
{ message: LOAN_PAYOFF(), severity: 'success' },
],
})
})
})
})
describe('there is not an outstanding loan', () => {
test('sale is not garnished', () => {
const state = sellKeg(
testState({
playerId: 'abc123',
cellarInventory: [stubKeg],
cellarItemsSold: {},
completedAchievements: {},
itemsSold: {},
learnedRecipes: {},
loanBalance: 0,
money: 1000,
pendingPeerMessages: [],
revenue: 0,
todaysRevenue: 0,
}),
stubKeg
)
expect(state).toMatchObject({
cellarInventory: [],
cellarItemsSold: { carrot: 1 },
completedAchievements: {},
itemsSold: { carrot: 1 },
learnedRecipes: {},
loanBalance: 0,
money: castToMoney(1000 + stubKegValue),
revenue: castToMoney(stubKegValue),
todaysRevenue: castToMoney(stubKegValue),
})
})
})
})