mirror of
https://github.com/AmanTahiliani/box-box.git
synced 2026-08-08 04:06:18 -04:00
Phase 22: Race Story Deepening
This commit is contained in:
@@ -1,131 +0,0 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import { ClassificationTable } from '../components/ClassificationTable'
|
||||
import type { EnrichedResult, EnrichedGrid } from '../types'
|
||||
|
||||
const mockResults: EnrichedResult[] = [
|
||||
{
|
||||
driver_number: 16,
|
||||
position: 1,
|
||||
name_acronym: 'LEC',
|
||||
full_name: 'Charles Leclerc',
|
||||
team_name: 'Ferrari',
|
||||
team_colour: 'e8002d',
|
||||
dnf: false,
|
||||
dns: false,
|
||||
dsq: false,
|
||||
duration: 5534.456,
|
||||
gap_to_leader: null,
|
||||
number_of_laps: 78,
|
||||
points: 25,
|
||||
session_key: 9472,
|
||||
meeting_key: 1234,
|
||||
},
|
||||
{
|
||||
driver_number: 1,
|
||||
position: 2,
|
||||
name_acronym: 'VER',
|
||||
full_name: 'Max Verstappen',
|
||||
team_name: 'Red Bull Racing',
|
||||
team_colour: '3671c6',
|
||||
dnf: false,
|
||||
dns: false,
|
||||
dsq: false,
|
||||
duration: null,
|
||||
gap_to_leader: 3.456,
|
||||
number_of_laps: 78,
|
||||
points: 18,
|
||||
session_key: 9472,
|
||||
meeting_key: 1234,
|
||||
},
|
||||
{
|
||||
driver_number: 44,
|
||||
position: 5,
|
||||
name_acronym: 'HAM',
|
||||
full_name: 'Lewis Hamilton',
|
||||
team_name: 'Ferrari',
|
||||
team_colour: 'e8002d',
|
||||
dnf: false,
|
||||
dns: false,
|
||||
dsq: false,
|
||||
duration: null,
|
||||
gap_to_leader: 21.234,
|
||||
number_of_laps: 78,
|
||||
points: 10,
|
||||
session_key: 9472,
|
||||
meeting_key: 1234,
|
||||
},
|
||||
]
|
||||
|
||||
const mockGrid: EnrichedGrid[] = [
|
||||
{
|
||||
driver_number: 1,
|
||||
position: 1,
|
||||
name_acronym: 'VER',
|
||||
full_name: 'Max Verstappen',
|
||||
team_name: 'Red Bull Racing',
|
||||
team_colour: '3671c6',
|
||||
session_key: 9472,
|
||||
meeting_key: 1234,
|
||||
lap_duration: 74.892,
|
||||
},
|
||||
{
|
||||
driver_number: 16,
|
||||
position: 3,
|
||||
name_acronym: 'LEC',
|
||||
full_name: 'Charles Leclerc',
|
||||
team_name: 'Ferrari',
|
||||
team_colour: 'e8002d',
|
||||
session_key: 9472,
|
||||
meeting_key: 1234,
|
||||
lap_duration: 75.123,
|
||||
},
|
||||
]
|
||||
|
||||
describe('ClassificationTable', () => {
|
||||
it('renders driver acronyms', () => {
|
||||
render(<ClassificationTable results={mockResults} grid={mockGrid} />)
|
||||
expect(screen.getByText('LEC')).toBeInTheDocument()
|
||||
expect(screen.getByText('VER')).toBeInTheDocument()
|
||||
expect(screen.getByText('HAM')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders P1 badge for LEC', () => {
|
||||
const { container } = render(<ClassificationTable results={mockResults} grid={mockGrid} />)
|
||||
const p1 = container.querySelector('.pos-p1')
|
||||
expect(p1).toBeInTheDocument()
|
||||
expect(p1?.textContent).toBe('1')
|
||||
})
|
||||
|
||||
it('shows grid gain arrow for LEC (started P3, finished P1)', () => {
|
||||
render(<ClassificationTable results={mockResults} grid={mockGrid} />)
|
||||
expect(screen.getByText('↑2')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('shows grid loss arrow for VER (started P1, finished P2)', () => {
|
||||
render(<ClassificationTable results={mockResults} grid={mockGrid} />)
|
||||
expect(screen.getByText('↓1')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders missing notice when results are empty', () => {
|
||||
render(<ClassificationTable results={[]} grid={[]} />)
|
||||
expect(screen.getByText(/not ingested/i)).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
describe('ClassificationTable — DNF/DNS/DSQ', () => {
|
||||
it('shows DNF label', () => {
|
||||
const dnfResult: EnrichedResult = {
|
||||
...mockResults[0],
|
||||
driver_number: 23,
|
||||
name_acronym: 'ALB',
|
||||
position: 20,
|
||||
dnf: true,
|
||||
duration: null,
|
||||
gap_to_leader: null,
|
||||
points: 0,
|
||||
}
|
||||
render(<ClassificationTable results={[dnfResult]} grid={[]} />)
|
||||
expect(screen.getByText('DNF')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
@@ -1,200 +0,0 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import { PositionEvolutionView } from '../components/PositionEvolutionView'
|
||||
import type { EnrichedResult, EnrichedGrid, PositionSample, Lap } from '../types'
|
||||
|
||||
const results: EnrichedResult[] = [
|
||||
{
|
||||
driver_number: 1,
|
||||
position: 1,
|
||||
name_acronym: 'VER',
|
||||
full_name: 'Max Verstappen',
|
||||
team_name: 'Red Bull Racing',
|
||||
team_colour: '3671C6',
|
||||
dnf: false,
|
||||
dns: false,
|
||||
dsq: false,
|
||||
duration: null,
|
||||
gap_to_leader: null,
|
||||
number_of_laps: 78,
|
||||
points: 25,
|
||||
session_key: 9472,
|
||||
meeting_key: 1229,
|
||||
},
|
||||
{
|
||||
driver_number: 44,
|
||||
position: 2,
|
||||
name_acronym: 'HAM',
|
||||
full_name: 'Lewis Hamilton',
|
||||
team_name: 'Ferrari',
|
||||
team_colour: 'E8002D',
|
||||
dnf: false,
|
||||
dns: false,
|
||||
dsq: false,
|
||||
duration: null,
|
||||
gap_to_leader: 5.1,
|
||||
number_of_laps: 78,
|
||||
points: 18,
|
||||
session_key: 9472,
|
||||
meeting_key: 1229,
|
||||
},
|
||||
]
|
||||
|
||||
const grid: EnrichedGrid[] = [
|
||||
{
|
||||
driver_number: 1,
|
||||
position: 1,
|
||||
name_acronym: 'VER',
|
||||
full_name: 'Max Verstappen',
|
||||
team_name: 'Red Bull Racing',
|
||||
team_colour: '3671C6',
|
||||
session_key: 9472,
|
||||
meeting_key: 1229,
|
||||
lap_duration: 71.234,
|
||||
},
|
||||
{
|
||||
driver_number: 44,
|
||||
position: 2,
|
||||
name_acronym: 'HAM',
|
||||
full_name: 'Lewis Hamilton',
|
||||
team_name: 'Ferrari',
|
||||
team_colour: 'E8002D',
|
||||
session_key: 9472,
|
||||
meeting_key: 1229,
|
||||
lap_duration: 71.456,
|
||||
},
|
||||
]
|
||||
|
||||
const positions: PositionSample[] = [
|
||||
{
|
||||
session_key: 9472,
|
||||
driver_number: 1,
|
||||
meeting_key: 1229,
|
||||
date: '2025-05-25T13:05:00+00:00',
|
||||
position: 1,
|
||||
},
|
||||
{
|
||||
session_key: 9472,
|
||||
driver_number: 1,
|
||||
meeting_key: 1229,
|
||||
date: '2025-05-25T13:10:00+00:00',
|
||||
position: 1,
|
||||
},
|
||||
{
|
||||
session_key: 9472,
|
||||
driver_number: 44,
|
||||
meeting_key: 1229,
|
||||
date: '2025-05-25T13:05:00+00:00',
|
||||
position: 2,
|
||||
},
|
||||
]
|
||||
|
||||
const laps: Lap[] = [
|
||||
{
|
||||
session_key: 9472,
|
||||
driver_number: 1,
|
||||
meeting_key: 1229,
|
||||
lap_number: 1,
|
||||
date_start: '2025-05-25T13:00:00+00:00',
|
||||
lap_duration: 75.1,
|
||||
is_pit_out_lap: false,
|
||||
},
|
||||
]
|
||||
|
||||
describe('PositionEvolutionView — positions available', () => {
|
||||
it('renders the position chart container', () => {
|
||||
const { container } = render(
|
||||
<PositionEvolutionView
|
||||
results={results}
|
||||
grid={grid}
|
||||
positions={positions}
|
||||
laps={laps}
|
||||
hasPositions={true}
|
||||
/>
|
||||
)
|
||||
expect(container.querySelector('[data-testid="position-chart"]')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders an SVG chart', () => {
|
||||
const { container } = render(
|
||||
<PositionEvolutionView
|
||||
results={results}
|
||||
grid={grid}
|
||||
positions={positions}
|
||||
laps={laps}
|
||||
hasPositions={true}
|
||||
/>
|
||||
)
|
||||
expect(container.querySelector('svg')).toBeInTheDocument()
|
||||
expect(container.querySelectorAll('polyline').length).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
it('does not show the missing-data notice', () => {
|
||||
render(
|
||||
<PositionEvolutionView
|
||||
results={results}
|
||||
grid={grid}
|
||||
positions={positions}
|
||||
laps={laps}
|
||||
hasPositions={true}
|
||||
/>
|
||||
)
|
||||
expect(screen.queryByText(/Lap-by-lap positions not available/i)).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders Grid → Finish table below chart', () => {
|
||||
render(
|
||||
<PositionEvolutionView
|
||||
results={results}
|
||||
grid={grid}
|
||||
positions={positions}
|
||||
laps={laps}
|
||||
hasPositions={true}
|
||||
/>
|
||||
)
|
||||
expect(screen.getByText('Grid → Finish')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
describe('PositionEvolutionView — positions missing', () => {
|
||||
it('shows the missing-data notice', () => {
|
||||
render(
|
||||
<PositionEvolutionView
|
||||
results={results}
|
||||
grid={grid}
|
||||
positions={[]}
|
||||
laps={[]}
|
||||
hasPositions={false}
|
||||
/>
|
||||
)
|
||||
expect(screen.getByText(/Lap-by-lap positions not available/i)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('falls back to grid → finish table when both results and grid exist', () => {
|
||||
render(
|
||||
<PositionEvolutionView
|
||||
results={results}
|
||||
grid={grid}
|
||||
positions={[]}
|
||||
laps={[]}
|
||||
hasPositions={false}
|
||||
/>
|
||||
)
|
||||
expect(screen.getByText('Grid → Finish')).toBeInTheDocument()
|
||||
expect(screen.getByText('VER')).toBeInTheDocument()
|
||||
expect(screen.getByText('HAM')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('does not render the position chart', () => {
|
||||
const { container } = render(
|
||||
<PositionEvolutionView
|
||||
results={results}
|
||||
grid={grid}
|
||||
positions={[]}
|
||||
laps={[]}
|
||||
hasPositions={false}
|
||||
/>
|
||||
)
|
||||
expect(container.querySelector('[data-testid="position-chart"]')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
@@ -234,10 +234,8 @@ describe('RaceHubPage', () => {
|
||||
|
||||
fireEvent.click(screen.getByRole('tab', { name: 'Race Story' }))
|
||||
|
||||
expect(screen.getByRole('tab', { name: 'Classification' })).toBeInTheDocument()
|
||||
expect(screen.getByRole('tab', { name: 'Starting Grid' })).toBeInTheDocument()
|
||||
expect(screen.getByRole('tab', { name: 'Positions' })).toBeInTheDocument()
|
||||
expect(screen.getByText('Final Classification')).toBeInTheDocument()
|
||||
expect(screen.getByText('VER')).toBeInTheDocument()
|
||||
|
||||
})
|
||||
|
||||
it('keeps Data Status accessible and free of inline CLI guidance', async () => {
|
||||
|
||||
Reference in New Issue
Block a user