@jeremyckahn/farmhand
Version:
A farming game
399 lines (353 loc) • 10.2 kB
JavaScript
import React from 'react'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { generateCow } from '../../utils/index.js'
import { noop } from '../../utils/noop.js'
import { PURCHASEABLE_COW_PENS } from '../../constants.js'
import { cowColors, genders } from '../../enums.js'
import uiEvents from '../../handlers/ui-events.js'
import { CowCard } from './CowCard.js'
describe('CowCard', () => {
const cow = generateCow({
color: cowColors.WHITE,
name: '',
baseWeight: 100,
})
/**
* @type {import("./CowCard.js").CowCardProps}
*/
const baseProps = {
allowCustomPeerCowNames: false,
cow,
cowInventory: [],
cowBreedingPen: {
cowId1: null,
cowId2: null,
daysUntilBirth: -1,
},
cowIdOfferedForTrade: '',
handleCowPurchaseClick: noop,
handleCowTradeClick: noop,
handleCowHugClick: noop,
handleCowSellClick: noop,
handleCowOfferClick: noop,
handleCowBreedChange: noop,
handleCowWithdrawClick: noop,
handleCowAutomaticHugChange: noop,
playerId: '',
isSelected: false,
isCowOfferedForTradeByPeer: false,
isOnline: false,
inventory: [],
money: 0,
purchasedCowPen: 1,
debounced: { ...uiEvents },
}
describe('cow purchase button', () => {
describe('player does not have enough money', () => {
describe('cow pen has no space', () => {
test('button is disabled', () => {
const cowCapacity = PURCHASEABLE_COW_PENS.get(1)?.cows
const testCow = generateCow({
color: cowColors.WHITE,
name: '',
baseWeight: 100,
})
render(
<CowCard
{...{
...baseProps,
cow: testCow,
money: 0,
cowInventory: Array(cowCapacity)
.fill(null)
.map(() => generateCow()),
}}
/>
)
const button = screen.getByText('Buy').closest('button')
expect(button).toHaveAttribute('disabled')
})
})
describe('cow pen has space', () => {
test('button is disabled', () => {
const testCow = generateCow({
color: cowColors.WHITE,
name: '',
baseWeight: 100,
})
render(
<CowCard
{...{
...baseProps,
cow: testCow,
money: 0,
}}
/>
)
const button = screen.getByText('Buy').closest('button')
expect(button).toHaveAttribute('disabled')
})
})
})
describe('player has enough money', () => {
describe('cow pen has no space', () => {
test('button is disabled', () => {
const cowCapacity = PURCHASEABLE_COW_PENS.get(1)?.cows
render(
<CowCard
{...{
...baseProps,
money: 150,
cowInventory: Array(cowCapacity)
.fill(null)
.map(() => generateCow()),
}}
/>
)
const button = screen.getByText('Buy').closest('button')
expect(button).toHaveAttribute('disabled')
})
})
describe('cow pen has space', () => {
test('button is not disabled', () => {
render(<CowCard {...{ ...baseProps, money: 150 }} />)
const button = screen.getByText('Buy').closest('button')
expect(button).not.toHaveAttribute('disabled')
})
})
})
})
describe('breeding checkbox', () => {
test('is enabled when pen is empty', () => {
const testCow = generateCow({
color: cowColors.WHITE,
name: '',
baseWeight: 100,
})
render(
<CowCard
{...{
...baseProps,
cow: testCow,
cowInventory: [testCow],
money: 0,
}}
/>
)
const button = screen
.getByText('Breed')
.closest('label')
?.querySelector('[type=checkbox]')
expect(button).not.toHaveAttribute('disabled')
})
test('is enabled when pen has space and compatible partner', () => {
const testCow = generateCow({
color: cowColors.WHITE,
name: '',
baseWeight: 100,
gender: genders.FEMALE,
})
const breedingCow1 = generateCow({
color: cowColors.WHITE,
name: '',
baseWeight: 100,
gender: genders.MALE,
})
render(
<CowCard
{...{
...baseProps,
cow: testCow,
cowInventory: [testCow, breedingCow1],
cowBreedingPen: {
cowId1: breedingCow1.id,
cowId2: null,
daysUntilBirth: -1,
},
money: 0,
}}
/>
)
const button = screen
.getByText('Breed')
.closest('label')
?.querySelector('[type=checkbox]')
expect(button).not.toHaveAttribute('disabled')
})
test('is enabled when cow is in the breeding pen', () => {
const breedingCow1 = generateCow({
color: cowColors.WHITE,
name: '',
baseWeight: 100,
gender: genders.MALE,
})
const breedingCow2 = generateCow({
color: cowColors.WHITE,
name: '',
baseWeight: 100,
gender: genders.FEMALE,
})
render(
<CowCard
{...{
...baseProps,
cow: breedingCow1,
cowInventory: [breedingCow1, breedingCow2],
cowBreedingPen: {
cowId1: breedingCow1.id,
cowId2: breedingCow2.id,
daysUntilBirth: -1,
},
money: 0,
}}
/>
)
const button = screen
.getByText('Breed')
.closest('label')
?.querySelector('[type=checkbox]')
expect(button).not.toHaveAttribute('disabled')
})
test('is disabled when pen has space and incompatible partner', () => {
const testCow = generateCow({
color: cowColors.WHITE,
name: '',
baseWeight: 100,
gender: genders.FEMALE,
})
const breedingCow1 = generateCow({
color: cowColors.WHITE,
name: '',
baseWeight: 100,
gender: genders.FEMALE,
})
render(
<CowCard
{...{
...baseProps,
cow: testCow,
cowInventory: [testCow, breedingCow1],
cowBreedingPen: {
cowId1: breedingCow1.id,
cowId2: null,
daysUntilBirth: -1,
},
money: 0,
}}
/>
)
const button = screen
.getByText('Breed')
.closest('label')
?.querySelector('[type=checkbox]')
expect(button).toHaveAttribute('disabled')
})
test('is disabled when pen is full', () => {
const testCow = generateCow({
color: cowColors.WHITE,
name: '',
baseWeight: 100,
})
const breedingCow1 = generateCow({
color: cowColors.WHITE,
name: '',
baseWeight: 100,
gender: genders.MALE,
})
const breedingCow2 = generateCow({
color: cowColors.WHITE,
name: '',
baseWeight: 100,
gender: genders.FEMALE,
})
render(
<CowCard
{...{
...baseProps,
cow: testCow,
cowInventory: [testCow, breedingCow1, breedingCow2],
cowBreedingPen: {
cowId1: breedingCow1.id,
cowId2: breedingCow2.id,
daysUntilBirth: -1,
},
money: 0,
}}
/>
)
const button = screen
.getByText('Breed')
.closest('label')
?.querySelector('[type=checkbox]')
expect(button).toHaveAttribute('disabled')
})
})
describe('cow selection', () => {
describe('cow is not selected', () => {
test('provides correct isSelected prop', () => {
render(
<CowCard
{...{
...baseProps,
cowInventory: [cow],
isSelected: false,
}}
/>
)
const selectedText = screen.queryByText(/is currently selected/)
expect(selectedText).toBeNull()
})
})
describe('cow is selected', () => {
test('provides correct isSelected prop', () => {
render(
<CowCard
{...{
...baseProps,
cowInventory: [cow],
isSelected: true,
}}
/>
)
const selectedText = screen.queryByText(/is currently selected/)
expect(selectedText).not.toBeNull()
})
})
})
describe('custom naming', () => {
// NOTE: Validates the fix for:
// https://github.com/jeremyckahn/farmhand/issues/527
test('cows orignally owned by the player can be renamed', async () => {
const user = userEvent.setup()
const renderComponent = () => {
render(
<CowCard
{...{
...baseProps,
cow: {
...cow,
originalOwnerId: 'player-id',
},
cowInventory: [{ ...cow }],
isSelected: true,
playerId: 'player-id',
// NOTE: This simulates how CowCard is integrated into the rest of
// the component tree. It also effectively reproduces the scenario
// that caused https://github.com/jeremyckahn/farmhand/issues/527
debounced: {
handleCowNameInputChange: () => renderComponent(),
},
}}
/>
)
}
renderComponent()
const nameInput = screen.getByPlaceholderText('Name')
const customName = 'Custom'
await user.clear(nameInput)
await user.type(nameInput, customName)
expect(nameInput).toHaveValue(customName)
})
})
})