Files
movieloop-frontend/src/components/layout/PageHeader.test.tsx
T
TehRiehlDeal 8d0b7f39ee feat(ui): give the app one visual identity as Movie Loop
Gold is the primary in both themes, Bricolage Grotesque carries the
wordmark, titles and the score, and Movie A / Movie B wear the blue and
magenta of three-strip Technicolor on their posters instead of colouring
whole rows. The loop closes on screen - connectors light, a gold line
draws back to Movie A, the row glows, then the result arrives - in place
of confetti, on every play mode, scaled to the chain's length. Every
page shares one header and hairline lists; copy is sentence case with
one verb per flow, and the Home hero shows a real finished loop.

Also clamps link counts at zero: an opponent who had not moved yet
showed "-1 links".
2026-09-12 22:42:55 -07:00

85 lines
2.5 KiB
TypeScript

import { render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router';
import { describe, expect, it } from 'vitest';
import PageHeader from './PageHeader';
/**
* The one page-title treatment. Rendered inside a MemoryRouter since an
* optional `back` link uses react-router's `Link` directly.
*/
describe('PageHeader', () => {
it('renders the title as the level-1 heading', () => {
render(
<MemoryRouter>
<PageHeader title="Daily Challenge" />
</MemoryRouter>,
);
expect(screen.getByRole('heading', { level: 1, name: 'Daily Challenge' })).toBeInTheDocument();
});
it('renders the description when given', () => {
render(
<MemoryRouter>
<PageHeader title="Daily Challenge" description="One puzzle a day." />
</MemoryRouter>,
);
expect(screen.getByText('One puzzle a day.')).toBeInTheDocument();
});
it('omits the description when not given', () => {
render(
<MemoryRouter>
<PageHeader title="Daily Challenge" />
</MemoryRouter>,
);
expect(screen.queryByText('One puzzle a day.')).toBeNull();
});
it('renders page-level actions', () => {
render(
<MemoryRouter>
<PageHeader title="Daily Challenge" actions={<button type="button">Share</button>} />
</MemoryRouter>,
);
expect(screen.getByRole('button', { name: 'Share' })).toBeInTheDocument();
});
it('omits the actions slot when not given', () => {
render(
<MemoryRouter>
<PageHeader title="Daily Challenge" />
</MemoryRouter>,
);
expect(screen.queryByRole('button')).toBeNull();
});
it('renders a back link with the given label and href', () => {
render(
<MemoryRouter>
<PageHeader title="Daily Challenge" back={{ to: '/', label: 'Home' }} />
</MemoryRouter>,
);
const back = screen.getByRole('link', { name: /Home/ });
expect(back).toHaveAttribute('href', '/');
});
it('omits the back link when not given', () => {
render(
<MemoryRouter>
<PageHeader title="Daily Challenge" />
</MemoryRouter>,
);
expect(screen.queryByRole('link')).toBeNull();
});
it('merges a custom className', () => {
const { container } = render(
<MemoryRouter>
<PageHeader title="Daily Challenge" className="mt-4" />
</MemoryRouter>,
);
expect(container.firstElementChild?.className).toContain('mt-4');
expect(container.firstElementChild?.className).toContain('mb-6');
});
});