UNPKG

@jeremyckahn/farmhand

Version:
332 lines (262 loc) 10.1 kB
import React from 'react' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { vi } from 'vitest' import { dialogView, stageFocusType } from '../../enums.js' import { INFINITE_STORAGE_LIMIT } from '../../constants.js' import { noop } from '../../utils/noop.js' import FarmhandContext, { createContextData, } from '../Farmhand/Farmhand.context.js' import { Navigation } from './Navigation.js' const defaultProps = { activePlayers: null, blockInput: false, currentDialogView: dialogView.NONE, dayCount: 0, farmName: 'Test Farm', handleActivePlayerButtonClick: noop, handleChatRoomOpenStateChange: noop, handleClickDialogViewButton: noop, handleCloseDialogView: noop, handleDialogViewExited: noop, handleFarmNameUpdate: noop, handleOnlineToggleChange: noop, handleRoomChange: noop, handleViewChange: noop, inventory: [], inventoryLimit: INFINITE_STORAGE_LIMIT, itemsSold: {}, isChatAvailable: false, isDialogViewOpen: false, isOnline: false, room: '', stageFocus: stageFocusType.FIELD, viewList: ['HOME', 'FIELD', 'SHOP', 'WORKSHOP'], } const renderWithContext = (props = {}, gameState = {}) => { const contextValue = createContextData() contextValue.gameState = { ...contextValue.gameState, dayCount: 0, experience: 100, itemsSold: {}, ...gameState, } return render( <FarmhandContext.Provider value={contextValue}> <Navigation {...defaultProps} {...props} /> </FarmhandContext.Provider> ) } describe('Navigation', () => { test('renders', () => { renderWithContext() expect(document.querySelector('.Navigation')).toBeInTheDocument() }) test('displays navigation menu items', async () => { const user = userEvent.setup() renderWithContext() // Open the dropdown to access menu items const selectElement = screen.getByRole('combobox') await user.click(selectElement) expect(screen.getAllByText('1: Home')[0]).toBeInTheDocument() expect(screen.getAllByText('2: Field')[0]).toBeInTheDocument() expect(screen.getAllByText('3: Shop')[0]).toBeInTheDocument() expect(screen.getAllByText('4: Workshop')[0]).toBeInTheDocument() }) test('calls handleViewChange when menu item is clicked', async () => { const user = userEvent.setup() const handleViewChange = vitest.fn() renderWithContext({ handleViewChange }) // First open the dropdown const selectElement = screen.getByRole('combobox') await user.click(selectElement) const shopMenuItem = screen.getByRole('option', { name: '3: Shop' }) await user.click(shopMenuItem) expect(handleViewChange).toHaveBeenCalledWith( expect.objectContaining({ target: expect.objectContaining({ value: stageFocusType.SHOP }), }), expect.anything() ) }) test('highlights current stage focus', () => { renderWithContext({ stageFocus: stageFocusType.SHOP }) // Material-UI Select shows the current value in the displayed text expect(screen.getByDisplayValue('SHOP')).toBeInTheDocument() }) describe('cow pen option', () => { test('does not show if player has not bought a cow pen', async () => { const user = userEvent.setup() renderWithContext() // Open dropdown to check available options const selectElement = screen.getByRole('combobox') await user.click(selectElement) expect(screen.queryByText(/Cows/)).not.toBeInTheDocument() }) test('does show if player has bought a cow pen', async () => { const user = userEvent.setup() const propsWithCowPen = { ...defaultProps, viewList: ['HOME', 'FIELD', 'SHOP', 'COW_PEN', 'WORKSHOP'], } renderWithContext(propsWithCowPen) // Open dropdown to see all options const selectElement = screen.getByRole('combobox') await user.click(selectElement) expect(screen.getByText('4: Cows')).toBeInTheDocument() }) test('allows navigation to cow pen when available', async () => { const user = userEvent.setup() const handleViewChange = vitest.fn() const propsWithCowPen = { ...defaultProps, viewList: ['HOME', 'FIELD', 'SHOP', 'COW_PEN', 'WORKSHOP'], handleViewChange, } renderWithContext(propsWithCowPen) // Open dropdown first const selectElement = screen.getByRole('combobox') await user.click(selectElement) const cowPenMenuItem = screen.getByRole('option', { name: '4: Cows' }) await user.click(cowPenMenuItem) expect(handleViewChange).toHaveBeenCalledWith( expect.objectContaining({ target: expect.objectContaining({ value: stageFocusType.COW_PEN }), }), expect.anything() ) }) }) describe('forest option', () => { test('does not show if player has not bought forest access', async () => { const user = userEvent.setup() renderWithContext() // Open dropdown to check available options const selectElement = screen.getByRole('combobox') await user.click(selectElement) expect(screen.queryByText(/Forest/)).not.toBeInTheDocument() }) test('shows forest option when available in viewList', async () => { const user = userEvent.setup() const propsWithForest = { ...defaultProps, viewList: ['HOME', 'FIELD', 'SHOP', 'FOREST', 'WORKSHOP'], } renderWithContext(propsWithForest) // Open dropdown to see all options const selectElement = screen.getByRole('combobox') await user.click(selectElement) expect(screen.getByText('4: Forest')).toBeInTheDocument() }) }) describe('cellar option', () => { test('does not show if player has not bought cellar access', async () => { const user = userEvent.setup() render(<Navigation {...defaultProps} />) // Open dropdown to check available options const selectElement = screen.getByRole('combobox') await user.click(selectElement) expect(screen.queryByText(/Cellar/)).not.toBeInTheDocument() }) test('shows cellar option when available in viewList', async () => { const user = userEvent.setup() const propsWithCellar = { ...defaultProps, viewList: ['HOME', 'FIELD', 'SHOP', 'CELLAR', 'WORKSHOP'], } renderWithContext(propsWithCellar) // Open dropdown to see all options const selectElement = screen.getByRole('combobox') await user.click(selectElement) expect(screen.getByText('4: Cellar')).toBeInTheDocument() }) }) test('displays farm name', () => { render(<Navigation {...defaultProps} farmName="My Test Farm" />) const farmNameInput = document.querySelector('.farm-name input') expect(farmNameInput).toHaveValue('My Test Farm') }) test('displays day count', () => { renderWithContext({}, { dayCount: 42 }) expect(screen.getByText(/Day.*42/)).toBeInTheDocument() }) test('handles view change for all available views', async () => { const user = userEvent.setup() const handleViewChange = vi.fn() const allViewsProps = { ...defaultProps, viewList: ['HOME', 'FIELD', 'SHOP', 'WORKSHOP'], handleViewChange, } renderWithContext(allViewsProps) // Open dropdown to access menu items const selectElement = screen.getByRole('combobox') await user.click(selectElement) // Test each view - just verify handleViewChange is called for each option await user.click(screen.getByRole('option', { name: '1: Home' })) // Reopen dropdown for next selection await user.click(selectElement) await user.click(screen.getByRole('option', { name: '2: Field' })) // Reopen dropdown for next selection await user.click(selectElement) await user.click(screen.getByRole('option', { name: '3: Shop' })) // Reopen dropdown for next selection await user.click(selectElement) await user.click(screen.getByRole('option', { name: '4: Workshop' })) // Verify handleViewChange was called for the selections that worked expect(handleViewChange).toHaveBeenCalledTimes(3) }) test('blocks input when blockInput prop is true', () => { renderWithContext({ blockInput: true, isDialogViewOpen: true }) const dialogElement = document.querySelector('.Farmhand') expect(dialogElement).toHaveClass('block-input') }) test('does not block input when blockInput prop is false', () => { renderWithContext({ blockInput: false }) const navigation = document.querySelector('.Navigation') expect(navigation).not.toHaveClass('block-input') }) test('handles online state changes', async () => { const user = userEvent.setup() const handleOnlineToggleChange = vitest.fn() renderWithContext({ handleOnlineToggleChange, isChatAvailable: true, }) // Look for online toggle switch or button const onlineToggle = document.querySelector('[role="switch"]') if (onlineToggle) { await user.click(onlineToggle) expect(handleOnlineToggleChange).toHaveBeenCalled() } }) test('displays online status when chat is available', () => { renderWithContext({ isChatAvailable: true, isOnline: true, activePlayers: 5, }) expect(screen.getByText(/Play online/)).toBeInTheDocument() }) test('handles dialog view opening', async () => { const user = userEvent.setup() const handleClickDialogViewButton = vitest.fn() renderWithContext({ handleClickDialogViewButton, }) // Look for settings or dialog buttons const dialogButton = screen.queryByLabelText(/settings/i) || screen.queryByText(/settings/i) if (dialogButton) { await user.click(dialogButton) expect(handleClickDialogViewButton).toHaveBeenCalled() } }) test('renders with minimal props', () => { renderWithContext() expect(document.querySelector('.Navigation')).toBeInTheDocument() expect(screen.getByText('Farmhand')).toBeInTheDocument() }) })