Files
aris/packages/aelis-source-tfl/src/renderer.test.tsx
kenneth 5cadcd1559 feat: combine TFL alerts into single feed item
TflSource.fetchItems() now returns one TflStatusFeedItem with an
alerts array instead of separate items per line disruption. Signals
use the highest severity. Alerts sorted by station distance.

Co-authored-by: Ona <no-reply@ona.com>
2026-03-29 22:32:35 +00:00

142 lines
4.5 KiB
TypeScript

/** @jsxImportSource @nym.sh/jrx */
import { render } from "@nym.sh/jrx"
import { describe, expect, test } from "bun:test"
import type { TflAlertData, TflStatusFeedItem } from "./types.ts"
import { renderTflStatus } from "./renderer.tsx"
function makeAlert(overrides: Partial<TflAlertData> = {}): TflAlertData {
return {
line: "northern",
lineName: "Northern",
severity: "minor-delays",
description: "Minor delays due to signal failure",
closestStationDistance: null,
...overrides,
}
}
function makeItem(alerts: TflAlertData[]): TflStatusFeedItem {
return {
id: "tfl-status",
sourceId: "aelis.tfl",
type: "tfl-status",
timestamp: new Date("2026-01-15T12:00:00Z"),
data: { alerts },
}
}
/** Collect all SansSerifText elements from a rendered spec, filtering out Fragments. */
function collectTextElements(spec: ReturnType<typeof render>) {
return Object.values(spec.elements).filter((el) => el.type === "SansSerifText")
}
describe("renderTflStatus", () => {
test("renders a single FeedCard", () => {
const node = renderTflStatus(makeItem([makeAlert()]))
const spec = render(node)
const root = spec.elements[spec.root]!
expect(root.type).toBe("FeedCard")
})
test("renders one alert with title and description", () => {
const node = renderTflStatus(makeItem([makeAlert()]))
const spec = render(node)
const texts = collectTextElements(spec)
const titleText = texts.find((el) => el.props.content === "Northern · Minor delays")
const bodyText = texts.find((el) => el.props.content === "Minor delays due to signal failure")
expect(titleText).toBeDefined()
expect(bodyText).toBeDefined()
})
test("renders multiple alerts stacked in one card", () => {
const alerts = [
makeAlert({ line: "northern", lineName: "Northern", severity: "minor-delays" }),
makeAlert({
line: "central",
lineName: "Central",
severity: "closure",
description: "Closed due to strike",
}),
]
const node = renderTflStatus(makeItem(alerts))
const spec = render(node)
const root = spec.elements[spec.root]!
expect(root.type).toBe("FeedCard")
const texts = collectTextElements(spec)
const northernTitle = texts.find((el) => el.props.content === "Northern · Minor delays")
const centralTitle = texts.find((el) => el.props.content === "Central · Closed")
const centralBody = texts.find((el) => el.props.content === "Closed due to strike")
expect(northernTitle).toBeDefined()
expect(centralTitle).toBeDefined()
expect(centralBody).toBeDefined()
})
test("shows nearest station distance when available", () => {
const node = renderTflStatus(makeItem([makeAlert({ closestStationDistance: 0.35 })]))
const spec = render(node)
const texts = collectTextElements(spec)
const caption = texts.find((el) => el.props.content === "Nearest station: 350m away")
expect(caption).toBeDefined()
})
test("formats distance in km when >= 1km", () => {
const node = renderTflStatus(makeItem([makeAlert({ closestStationDistance: 2.456 })]))
const spec = render(node)
const texts = collectTextElements(spec)
const caption = texts.find((el) => el.props.content === "Nearest station: 2.5km away")
expect(caption).toBeDefined()
})
test("formats near-1km boundary as km not meters", () => {
const node = renderTflStatus(makeItem([makeAlert({ closestStationDistance: 0.9999 })]))
const spec = render(node)
const texts = collectTextElements(spec)
const caption = texts.find((el) => el.props.content === "Nearest station: 1.0km away")
expect(caption).toBeDefined()
})
test("omits station distance when null", () => {
const node = renderTflStatus(makeItem([makeAlert({ closestStationDistance: null })]))
const spec = render(node)
const texts = collectTextElements(spec)
const distanceTexts = texts.filter((el) =>
(el.props.content as string).startsWith("Nearest station:"),
)
expect(distanceTexts).toHaveLength(0)
})
test("renders closure severity label", () => {
const node = renderTflStatus(
makeItem([makeAlert({ severity: "closure", lineName: "Central" })]),
)
const spec = render(node)
const texts = collectTextElements(spec)
const title = texts.find((el) => el.props.content === "Central · Closed")
expect(title).toBeDefined()
})
test("renders major delays severity label", () => {
const node = renderTflStatus(
makeItem([makeAlert({ severity: "major-delays", lineName: "Jubilee" })]),
)
const spec = render(node)
const texts = collectTextElements(spec)
const title = texts.find((el) => el.props.content === "Jubilee · Major delays")
expect(title).toBeDefined()
})
})