123 lines
4.2 KiB
TypeScript
123 lines
4.2 KiB
TypeScript
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
import userEvent from '@testing-library/user-event';
|
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
import App from './App';
|
|
import { PREFERENCES_KEY } from './preferences';
|
|
import { catalogue, catalogueFetch } from './test/fixtures';
|
|
|
|
afterEach(() => vi.unstubAllGlobals());
|
|
|
|
describe('portal UI', () => {
|
|
it('renders app cards and persists accessible pin/hide controls', async () => {
|
|
vi.stubGlobal('fetch', vi.fn(catalogueFetch()));
|
|
const user = userEvent.setup();
|
|
render(<App />);
|
|
expect(
|
|
await screen.findByRole('heading', { name: 'PDF Workbench' })
|
|
).toBeInTheDocument();
|
|
expect(
|
|
screen.getByText(
|
|
'Local processing · no file uploads declared · no telemetry declared'
|
|
)
|
|
).toBeInTheDocument();
|
|
const sourceLinks = screen.getAllByRole('link', {
|
|
name: 'Source and license',
|
|
});
|
|
expect(sourceLinks).toHaveLength(2);
|
|
expect(
|
|
sourceLinks.find(
|
|
(link) =>
|
|
link.getAttribute('href') ===
|
|
'https://git.add-ideas.de/zemion/pdf-tools'
|
|
)
|
|
).toHaveAttribute('rel', 'noopener noreferrer');
|
|
expect(
|
|
sourceLinks.find((link) =>
|
|
link.getAttribute('href')?.endsWith('/toolbox-portal/src/tag/v0.1.0')
|
|
)
|
|
).toBeDefined();
|
|
const launch = screen.getByRole('link', { name: /open tool/i });
|
|
expect(
|
|
new URL(launch.getAttribute('href')!).searchParams.get('toolbox')
|
|
).toContain('toolbox.catalog.json');
|
|
|
|
await user.click(screen.getByRole('button', { name: 'Pin PDF Workbench' }));
|
|
await waitFor(() =>
|
|
expect(localStorage.getItem(PREFERENCES_KEY)).toContain(
|
|
'de.add-ideas.pdf-tools'
|
|
)
|
|
);
|
|
expect(screen.getByText('Pinned')).toBeInTheDocument();
|
|
|
|
await user.click(
|
|
screen.getByRole('button', { name: 'Hide PDF Workbench' })
|
|
);
|
|
expect(
|
|
screen.queryByRole('heading', { name: 'PDF Workbench' })
|
|
).not.toBeInTheDocument();
|
|
fireEvent.click(screen.getByRole('checkbox', { name: /show hidden/i }));
|
|
expect(
|
|
screen.getByRole('heading', { name: 'PDF Workbench' })
|
|
).toBeInTheDocument();
|
|
});
|
|
|
|
it('shows a recoverable catalogue error', async () => {
|
|
const fetchMock = vi
|
|
.fn()
|
|
.mockResolvedValueOnce(new Response('no', { status: 503 }))
|
|
.mockImplementation(catalogueFetch());
|
|
vi.stubGlobal('fetch', fetchMock);
|
|
render(<App />);
|
|
expect(
|
|
await screen.findByRole('heading', { name: 'Toolbox unavailable' })
|
|
).toBeInTheDocument();
|
|
fireEvent.click(screen.getByRole('button', { name: 'Try again' }));
|
|
expect(
|
|
await screen.findByRole('heading', { name: 'PDF Workbench' })
|
|
).toBeInTheDocument();
|
|
});
|
|
|
|
it('shows a dedicated empty state for a valid catalogue', async () => {
|
|
vi.stubGlobal(
|
|
'fetch',
|
|
vi.fn(
|
|
catalogueFetch({
|
|
'/toolbox.catalog.json': Response.json({ ...catalogue, apps: [] }),
|
|
})
|
|
)
|
|
);
|
|
render(<App />);
|
|
expect(
|
|
await screen.findByRole('heading', { name: 'No tools yet' })
|
|
).toBeInTheDocument();
|
|
});
|
|
|
|
it('contains preference focus and restores it to Personalize', async () => {
|
|
vi.stubGlobal('fetch', vi.fn(catalogueFetch()));
|
|
const user = userEvent.setup();
|
|
const { container } = render(<App />);
|
|
const personalize = screen.getByRole('button', { name: 'Personalize' });
|
|
|
|
await user.click(personalize);
|
|
const dialog = screen.getByRole('dialog', {
|
|
name: 'Personalize your toolbox',
|
|
});
|
|
const close = screen.getByRole('button', { name: 'Close preferences' });
|
|
expect(close).toHaveFocus();
|
|
expect(container.querySelector('.site-shell')).toHaveAttribute('inert');
|
|
expect(dialog).toBeInTheDocument();
|
|
expect(screen.getByText(/does not transmit them/i)).toHaveTextContent(
|
|
/Trusted code in another Toolbox app on this site can access same-origin storage/i
|
|
);
|
|
|
|
const reset = screen.getByRole('button', { name: 'Reset' });
|
|
reset.focus();
|
|
await user.tab();
|
|
expect(close).toHaveFocus();
|
|
|
|
await user.keyboard('{Escape}');
|
|
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
|
|
expect(personalize).toHaveFocus();
|
|
});
|
|
});
|