timeline-block.test.tsx2.5 KBView on GitHub /**
* Tests for the `timeline` dashboard block — the only net-new piece of the
* Follow-up SLA report. Two concerns:
* 1. The grammar validates a spec containing a `timeline` block (and still
* rejects an unknown block type).
* 2. `TimelineView` adapts mock `{ kind, at, title }` rows into the shape
* `ConversationActivityOverview` consumes and renders one dot per event.
*/
import { render, screen } from '@testing-library/react';
import { TooltipProvider } from '@/components/ui/tooltip';
import { parseDashboardSpec, type DashboardSpec } from '@/modules/dashboards/types/dashboard';
import { LayoutNode } from '@/modules/dashboards/components/blocks';
import { SourcesProvider } from '@/modules/dashboards/components/context';
describe('timeline dashboard block — validation', () => {
it('accepts a spec containing a timeline block', () => {
const raw = {
spec_version: '2.0',
id: 'sla_timeline',
dataSources: {
ev: {
mock: [
{ kind: 'inbound_email', at: '2026-03-01T09:00:00Z', title: 'Intro' },
{ kind: 'outbound_email', at: '2026-03-01T10:00:00Z', title: 'Recap + CTA' },
],
},
},
layout: { type: 'timeline', source: 'ev', title: 'Won deal — tight cadence' },
};
const spec = parseDashboardSpec(raw);
expect(spec).not.toBeNull();
expect((spec as DashboardSpec).layout.type).toBe('timeline');
});
it('rejects an unknown block type', () => {
const raw = {
spec_version: '2.0',
id: 'bogus',
dataSources: {},
layout: { type: 'not-a-real-block' },
};
expect(parseDashboardSpec(raw)).toBeNull();
});
});
describe('timeline dashboard block — render', () => {
it('renders one dot per mock event', () => {
const events = [
{ kind: 'inbound_email', at: '2026-03-01T09:00:00Z', title: 'Intro' },
{ kind: 'outbound_email', at: '2026-03-03T10:00:00Z', title: 'Recap + CTA' },
{ kind: 'meeting', at: '2026-03-10T15:00:00Z', title: 'Demo' },
];
render(
<TooltipProvider>
<SourcesProvider value={{ ev: { rows: events, isLoading: false } }}>
<LayoutNode node={{ type: 'timeline', source: 'ev', title: 'Won deal' }} />
</SourcesProvider>
</TooltipProvider>,
);
// Each event dot is a <button>; the "now" indicator is a div, so the button
// count equals the number of events.
expect(screen.getAllByRole('button')).toHaveLength(events.length);
expect(screen.getByText('Won deal')).toBeInTheDocument();
});
});