feat: roll out illustrative empty states across 8 pages with 2 new guide entries

- TreeLibraryPage: split empty state into no-flows (illustration + CTA) vs no-filter-results
- MyAnalyticsPage/TeamAnalyticsPage: add zero-sessions empty state with illustration
- SessionHistoryPage: split into no-sessions (illustration) vs no-filter-results
- StepLibraryBrowser: illustrative empty state when no steps exist
- ScriptTemplateList: replace plain empty state with ScriptIllustration
- MySharesPage: replace icon-based empty state with ShareIllustration
- IntegrationsPage: add IntegrationIllustration above setup form
- Add script-templates and psa-setup guides to guides data
- Add EmptyState vitest tests (7 tests)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
chihlasm
2026-03-17 01:21:11 -04:00
parent 85d1ed8028
commit dfdc6cae9c
10 changed files with 324 additions and 43 deletions

View File

@@ -0,0 +1,92 @@
import { describe, it, expect } from 'vitest'
import { render, screen } from '@testing-library/react'
import { BrowserRouter } from 'react-router-dom'
import { EmptyState } from '../EmptyState'
import { FlowIllustration } from '../EmptyStateIllustrations'
function renderWithRouter(ui: React.ReactElement) {
return render(<BrowserRouter>{ui}</BrowserRouter>)
}
describe('EmptyState', () => {
it('renders title and description', () => {
renderWithRouter(
<EmptyState
title="No items found"
description="Try adjusting your filters."
/>
)
expect(screen.getByText('No items found')).toBeInTheDocument()
expect(screen.getByText('Try adjusting your filters.')).toBeInTheDocument()
})
it('renders illustration when provided', () => {
const { container } = renderWithRouter(
<EmptyState
title="Empty"
illustration={<FlowIllustration />}
/>
)
const svg = container.querySelector('svg')
expect(svg).toBeInTheDocument()
})
it('renders action button', () => {
renderWithRouter(
<EmptyState
title="No data"
action={<button>Create New</button>}
/>
)
expect(screen.getByRole('button', { name: 'Create New' })).toBeInTheDocument()
})
it('renders learn more link with correct href', () => {
renderWithRouter(
<EmptyState
title="Get started"
learnMoreLink="/guides/creating-flows"
/>
)
const link = screen.getByText(/Learn more/i)
expect(link).toBeInTheDocument()
expect(link).toHaveAttribute('href', '/guides/creating-flows')
})
it('renders custom learn more text', () => {
renderWithRouter(
<EmptyState
title="Get started"
learnMoreLink="/guides/test"
learnMoreText="View guide"
/>
)
expect(screen.getByText(/View guide/i)).toBeInTheDocument()
})
it('renders without optional props', () => {
renderWithRouter(<EmptyState title="Just a title" />)
expect(screen.getByText('Just a title')).toBeInTheDocument()
expect(screen.queryByRole('button')).not.toBeInTheDocument()
expect(screen.queryByRole('link')).not.toBeInTheDocument()
})
it('prefers illustration over icon when both provided', () => {
const { container } = renderWithRouter(
<EmptyState
title="Test"
icon={<span data-testid="icon">icon</span>}
illustration={<FlowIllustration />}
/>
)
expect(container.querySelector('svg')).toBeInTheDocument()
expect(screen.queryByTestId('icon')).not.toBeInTheDocument()
})
})