wrolpi/app/src/components/DesktopToggle.test.js

61 lines
2.3 KiB
JavaScript
Raw Normal View History

import React from 'react';
ui: Common.js and thirteen more files off Semantic Phase 2, part 3. Baseline 63 -> 50. Common.js is the one that mattered: 51 files import it, so its Semantic usage was propping up the rest of the migration. Everything in it now comes from the library -- Paginator, the two search inputs, DirectorySearch, TabLinks, the toggles, the messages, APIButton, Breadcrumbs, SimpleAccordion, IframeViewer, CardPoster, FileIcon, LoadStatistic, the theme menu, and the hotspot icons. Also migrated: Placeholder, Apps, ArchivePreview, CbzViewer, AddToPlaylist, TaggedDeleteConfirmModal, the collection edit/tag forms, and four inventory components. New in the library, all in the gallery and tested: SearchBox Semantic's `<Search category>` with its grouped results shape kept, because four call sites already build it. A real combobox rather than a div that listens for clicks. Pagination Semantic's prop names; onPageChange gets the page number. TabBar the strip only -- routing stays with the caller. IconStack Semantic's IconGroup, named once for assistive technology. Table.HeaderCell sorted/onSort -- a real button carrying aria-sort. Button/IconButton translate Semantic's size names. That last one is defensive: unmigrated callers still pass size='tiny', and Mantine drops a size it does not recognise without a word, so the button quietly renders at the wrong size. Mapping here keeps the mixed state honest. Three real bugs found and fixed on the way, none of them cosmetic: * `fileSuffixIconName` returned fourteen icon names the map did not have, so opening a folder with a PDF, a Word document or an archive in it logged an error and drew a fallback glyph. All fourteen mapped, with a test that walks the mapper's own return values, and another asserting every mapped name resolves to a Tabler component that exists. * `Statistic` relied on Semantic's `Statistic.Group` for its spacing, so on the dashboard the load averages ran together into "1 MIN. LOAD5 MIN. LOAD15 MIN. LOAD". It carries its own spacing now. * Semantic's inverted stylesheet colors every descendant of an inverted segment, so Toggle labels inherited #dddddd -- white pixels in night mode, on the Settings page, which is exactly where someone adjusts their WROLPi in the dark. Restated from tokens. The baseline ratchet gained a third assertion: a migrated file may still lean on Semantic's CSS classes without importing the library, which the import check cannot see and which would collapse silently when Phase 4 deletes the stylesheet. There is one such bridge today and it is now declared.
2026-07-30 10:00:48 -06:00
import {render, screen} from '../test-utils';
import userEvent from '@testing-library/user-event';
import {DesktopToggle} from './Common';
const mockSetDesktop = jest.fn();
let mockDesktopState = {on: true};
jest.mock('../hooks/customHooks', () => ({
...jest.requireActual('../hooks/customHooks'),
useDesktop: () => ({...mockDesktopState, setDesktop: mockSetDesktop}),
}));
describe('DesktopToggle', () => {
beforeEach(() => {
mockSetDesktop.mockClear();
mockDesktopState = {on: true};
});
it('renders checked when the desktop is running', () => {
render(<DesktopToggle/>);
expect(screen.getByTestId('toggle')).toBeChecked();
});
it('starts the desktop immediately when toggled on', async () => {
mockDesktopState = {on: false};
render(<DesktopToggle/>);
await userEvent.click(screen.getByTestId('toggle'));
expect(mockSetDesktop).toHaveBeenCalledWith(true);
});
it('asks for confirmation before stopping the desktop', async () => {
render(<DesktopToggle/>);
await userEvent.click(screen.getByTestId('toggle'));
// Not stopped yet; the Confirm modal is shown instead.
expect(mockSetDesktop).not.toHaveBeenCalled();
ui: Common.js and thirteen more files off Semantic Phase 2, part 3. Baseline 63 -> 50. Common.js is the one that mattered: 51 files import it, so its Semantic usage was propping up the rest of the migration. Everything in it now comes from the library -- Paginator, the two search inputs, DirectorySearch, TabLinks, the toggles, the messages, APIButton, Breadcrumbs, SimpleAccordion, IframeViewer, CardPoster, FileIcon, LoadStatistic, the theme menu, and the hotspot icons. Also migrated: Placeholder, Apps, ArchivePreview, CbzViewer, AddToPlaylist, TaggedDeleteConfirmModal, the collection edit/tag forms, and four inventory components. New in the library, all in the gallery and tested: SearchBox Semantic's `<Search category>` with its grouped results shape kept, because four call sites already build it. A real combobox rather than a div that listens for clicks. Pagination Semantic's prop names; onPageChange gets the page number. TabBar the strip only -- routing stays with the caller. IconStack Semantic's IconGroup, named once for assistive technology. Table.HeaderCell sorted/onSort -- a real button carrying aria-sort. Button/IconButton translate Semantic's size names. That last one is defensive: unmigrated callers still pass size='tiny', and Mantine drops a size it does not recognise without a word, so the button quietly renders at the wrong size. Mapping here keeps the mixed state honest. Three real bugs found and fixed on the way, none of them cosmetic: * `fileSuffixIconName` returned fourteen icon names the map did not have, so opening a folder with a PDF, a Word document or an archive in it logged an error and drew a fallback glyph. All fourteen mapped, with a test that walks the mapper's own return values, and another asserting every mapped name resolves to a Tabler component that exists. * `Statistic` relied on Semantic's `Statistic.Group` for its spacing, so on the dashboard the load averages ran together into "1 MIN. LOAD5 MIN. LOAD15 MIN. LOAD". It carries its own spacing now. * Semantic's inverted stylesheet colors every descendant of an inverted segment, so Toggle labels inherited #dddddd -- white pixels in night mode, on the Settings page, which is exactly where someone adjusts their WROLPi in the dark. Restated from tokens. The baseline ratchet gained a third assertion: a migrated file may still lean on Semantic's CSS classes without importing the library, which the import check cannot see and which would collapse silently when Phase 4 deletes the stylesheet. There is one such bridge today and it is now declared.
2026-07-30 10:00:48 -06:00
// Mantine's Modal mounts its content on a subsequent render pass, so the
// text isn't present synchronously after the click.
expect(await screen.findByText('Stop the desktop')).toBeInTheDocument();
await userEvent.click(screen.getByText('Stop'));
expect(mockSetDesktop).toHaveBeenCalledWith(false);
});
it('cancelling the confirmation leaves the desktop running', async () => {
render(<DesktopToggle/>);
await userEvent.click(screen.getByTestId('toggle'));
ui: Common.js and thirteen more files off Semantic Phase 2, part 3. Baseline 63 -> 50. Common.js is the one that mattered: 51 files import it, so its Semantic usage was propping up the rest of the migration. Everything in it now comes from the library -- Paginator, the two search inputs, DirectorySearch, TabLinks, the toggles, the messages, APIButton, Breadcrumbs, SimpleAccordion, IframeViewer, CardPoster, FileIcon, LoadStatistic, the theme menu, and the hotspot icons. Also migrated: Placeholder, Apps, ArchivePreview, CbzViewer, AddToPlaylist, TaggedDeleteConfirmModal, the collection edit/tag forms, and four inventory components. New in the library, all in the gallery and tested: SearchBox Semantic's `<Search category>` with its grouped results shape kept, because four call sites already build it. A real combobox rather than a div that listens for clicks. Pagination Semantic's prop names; onPageChange gets the page number. TabBar the strip only -- routing stays with the caller. IconStack Semantic's IconGroup, named once for assistive technology. Table.HeaderCell sorted/onSort -- a real button carrying aria-sort. Button/IconButton translate Semantic's size names. That last one is defensive: unmigrated callers still pass size='tiny', and Mantine drops a size it does not recognise without a word, so the button quietly renders at the wrong size. Mapping here keeps the mixed state honest. Three real bugs found and fixed on the way, none of them cosmetic: * `fileSuffixIconName` returned fourteen icon names the map did not have, so opening a folder with a PDF, a Word document or an archive in it logged an error and drew a fallback glyph. All fourteen mapped, with a test that walks the mapper's own return values, and another asserting every mapped name resolves to a Tabler component that exists. * `Statistic` relied on Semantic's `Statistic.Group` for its spacing, so on the dashboard the load averages ran together into "1 MIN. LOAD5 MIN. LOAD15 MIN. LOAD". It carries its own spacing now. * Semantic's inverted stylesheet colors every descendant of an inverted segment, so Toggle labels inherited #dddddd -- white pixels in night mode, on the Settings page, which is exactly where someone adjusts their WROLPi in the dark. Restated from tokens. The baseline ratchet gained a third assertion: a migrated file may still lean on Semantic's CSS classes without importing the library, which the import check cannot see and which would collapse silently when Phase 4 deletes the stylesheet. There is one such bridge today and it is now declared.
2026-07-30 10:00:48 -06:00
await userEvent.click(await screen.findByText('Cancel'));
expect(mockSetDesktop).not.toHaveBeenCalled();
expect(screen.getByTestId('toggle')).toBeChecked();
});
it('does nothing when the desktop is not supported', async () => {
mockDesktopState = {on: null};
render(<DesktopToggle/>);
await userEvent.click(screen.getByTestId('toggle'));
expect(mockSetDesktop).not.toHaveBeenCalled();
expect(screen.queryByText('Stop the desktop')).not.toBeInTheDocument();
});
});