83 lines
2.6 KiB
TypeScript
83 lines
2.6 KiB
TypeScript
/**
|
|||
|
|
* Tests for DsmrPanel — latest parsed DSMR telegram view.
|
||
|
|
*
|
||
|
|
* Coverage:
|
||
|
|
* 1. Loading state.
|
||
|
|
* 2. Empty state (found=false) with a helpful hint.
|
||
|
|
* 3. Renders the payload as a key/value table; null values shown as "—".
|
||
|
|
* 4. Error state.
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||
|
|
import { screen, waitFor } from '@testing-library/react'
|
||
|
|
import { renderWithProviders } from '../test-utils'
|
||
|
|
|
||
|
|
const mockGet = vi.fn()
|
||
|
|
|
||
|
|
vi.mock('../api/client', () => ({
|
||
|
|
default: {
|
||
|
|
GET: (...args: unknown[]) => mockGet(...args),
|
||
|
|
POST: vi.fn(),
|
||
|
|
PATCH: vi.fn(),
|
||
|
|
DELETE: vi.fn(),
|
||
|
|
},
|
||
|
|
ApiError: class ApiError extends Error {
|
||
|
|
status: number
|
||
|
|
body: unknown
|
||
|
|
constructor(status: number, body: unknown) {
|
||
|
|
super(`API error ${status}`)
|
||
|
|
this.name = 'ApiError'
|
||
|
|
this.status = status
|
||
|
|
this.body = body
|
||
|
|
}
|
||
|
|
},
|
||
|
|
registerLoginRedirect: vi.fn(),
|
||
|
|
}))
|
||
|
|
|
||
|
|
import { DsmrPanel } from './DsmrPanel'
|
||
|
|
|
||
|
|
describe('DsmrPanel', () => {
|
||
|
|
beforeEach(() => vi.clearAllMocks())
|
||
|
|
|
||
|
|
it('renders loading state initially', () => {
|
||
|
|
mockGet.mockImplementation(() => new Promise(() => {}))
|
||
|
|
renderWithProviders(<DsmrPanel />)
|
||
|
|
expect(screen.getByTestId('dsmr-loading')).toBeInTheDocument()
|
||
|
|
})
|
||
|
|
|
||
|
|
it('shows an empty hint when no DSMR data has been ingested', async () => {
|
||
|
|
mockGet.mockResolvedValue({ data: { found: false, recorded_at: null, payload: null } })
|
||
|
|
renderWithProviders(<DsmrPanel />)
|
||
|
|
await waitFor(() => expect(screen.getByTestId('dsmr-empty')).toBeInTheDocument())
|
||
|
|
expect(screen.queryByTestId('dsmr-table')).not.toBeInTheDocument()
|
||
|
|
})
|
||
|
|
|
||
|
|
it('renders the latest telegram as a key/value table; null shown as dash', async () => {
|
||
|
|
mockGet.mockResolvedValue({
|
||
|
|
data: {
|
||
|
|
found: true,
|
||
|
|
recorded_at: '2026-06-23T12:16:00Z',
|
||
|
|
payload: {
|
||
|
|
electricity_delivered_1: '20915.154',
|
||
|
|
phase_voltage_l2: null,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
})
|
||
|
|
renderWithProviders(<DsmrPanel />)
|
||
|
|
|
||
|
|
await waitFor(() => expect(screen.getByTestId('dsmr-table')).toBeInTheDocument())
|
||
|
|
|
||
|
|
// Field rows present (keys are sorted).
|
||
|
|
expect(screen.getByTestId('dsmr-row-electricity_delivered_1')).toHaveTextContent('20915.154')
|
||
|
|
// Null phase value rendered as an em dash, not omitted.
|
||
|
|
expect(screen.getByTestId('dsmr-row-phase_voltage_l2')).toHaveTextContent('—')
|
||
|
|
expect(screen.getByTestId('dsmr-recorded-at')).toBeInTheDocument()
|
||
|
|
})
|
||
|
|
|
||
|
|
it('renders an error state when the request fails', async () => {
|
||
|
|
mockGet.mockRejectedValue(new Error('network down'))
|
||
|
|
renderWithProviders(<DsmrPanel />)
|
||
|
|
await waitFor(() => expect(screen.getByTestId('dsmr-error')).toBeInTheDocument())
|
||
|
|
})
|
||
|
|
})
|