mirror of
https://github.com/lrnselfreliance/wrolpi.git
synced 2026-10-26 19:01:39 -04:00
Phase 2, part 4. Baseline 50 -> 15.
Migrated: all eight calculators, the rest of inventory and collections, the
Map/Zim/Docs cluster, Videos, Files, Search, Archive, DashboardPage,
DatesSelector, HelpModal, Events, Tags, Flasher's neighbours, admin Settings
and Status, Download, and App.
Also the three shared modules everything imports: api.js and customHooks.js
swap the Semantic toast library for the library's shim (same call shape), and
useForm.js renders the library's Message. useForm accepts both the old
`{content, header, positive|negative}` shape and the new `{kind, title}`,
because the pages building those objects migrate separately.
Two library gaps closed, both found by call sites needing them:
ActionInput is a forwardRef now. Its ref reaches the input rather than the
wrapper, because callers use it to focus or select the field -- a ref to the
surrounding div would do neither, which is why one call site had resorted to
hand-copying the component's markup.
Header takes a `color` token name. Three separate call sites had reached for
an inline style to colour a heading that carries meaning ("3 items to add"
against "2 to remove"), which is how a hex ends up in markup.
Two files needed repair after being interrupted mid-edit: MapViewer had a
Segment left in its error branch, and VideoPlayer had lost the useContext
import its own code still used. Neither jest nor tsc noticed; only
`npm run build` did, which is the whole reason that check exists.
Fifteen files remain: Archive, BulkTagModal, Channels, Docs, FileBrowser,
FilePreview, Flasher, Nav, Playlists, Theme.tsx, Upload, VideoPlayer, Zim,
ControllerPage, admin/Downloads. Theme.tsx is deliberately last -- the
unmigrated files still import its Semantic-backed wrappers, so it can only go
once they have.
68 lines
3.1 KiB
JavaScript
68 lines
3.1 KiB
JavaScript
import React from "react";
|
|
import {fireEvent, render, screen, waitFor, within} from "../../test-utils";
|
|
|
|
jest.mock("../../api", () => ({
|
|
getInventoryBackups: jest.fn(),
|
|
postInventoryRestorePreview: jest.fn(),
|
|
postInventoryRestore: jest.fn(),
|
|
reimportInventories: jest.fn(),
|
|
}));
|
|
|
|
import {InventoryImportModal} from "./InventoryImportModal";
|
|
import {getInventoryBackups, postInventoryRestore, postInventoryRestorePreview, reimportInventories} from "../../api";
|
|
|
|
const renderModal = (props = {}) => {
|
|
const onChanged = jest.fn(() => Promise.resolve());
|
|
const onClose = jest.fn();
|
|
render(<InventoryImportModal open slug='food-storage' name='Food Storage'
|
|
onChanged={onChanged} onClose={onClose} {...props}/>);
|
|
return {onChanged, onClose};
|
|
};
|
|
|
|
describe('InventoryImportModal', () => {
|
|
// CRA's jest config resets mock implementations before each test, so (re)set them here.
|
|
beforeEach(() => {
|
|
getInventoryBackups.mockResolvedValue(['20260115', '20260101']);
|
|
postInventoryRestorePreview.mockResolvedValue({
|
|
mode: 'merge', add: [{id: 2, name: 'Beans'}], remove: [], unchanged: 1,
|
|
fields_change: false, current_count: 1, backup_count: 2, backup_name: 'Food Storage',
|
|
});
|
|
postInventoryRestore.mockResolvedValue({slug: 'food-storage', items: []});
|
|
reimportInventories.mockResolvedValue([{slug: 'food-storage'}]);
|
|
});
|
|
|
|
test('lists backups and applies a merge restore', async () => {
|
|
const {onChanged, onClose} = renderModal();
|
|
|
|
// Backup dates load (newest first).
|
|
const row = (await screen.findByText('2026-01-15')).closest('tr');
|
|
fireEvent.click(within(row).getByRole('button', {name: /merge/i}));
|
|
|
|
// Preview is requested for that date/mode, then the confirmation view appears.
|
|
await waitFor(() => expect(postInventoryRestorePreview)
|
|
.toHaveBeenCalledWith('food-storage', '20260115', 'merge'));
|
|
await screen.findByText(/Merge backup from 2026-01-15/);
|
|
expect(screen.getByText(/1 to add/)).toBeInTheDocument();
|
|
expect(screen.getByText('Beans')).toBeInTheDocument();
|
|
|
|
fireEvent.click(screen.getByRole('button', {name: /apply/i}));
|
|
await waitFor(() => expect(postInventoryRestore)
|
|
.toHaveBeenCalledWith('food-storage', '20260115', 'merge'));
|
|
await waitFor(() => expect(onChanged).toHaveBeenCalled());
|
|
await waitFor(() => expect(onClose).toHaveBeenCalled());
|
|
});
|
|
|
|
test('re-import from disk reloads inventories', async () => {
|
|
const {onChanged} = renderModal();
|
|
await screen.findByText('2026-01-15'); // wait for initial load to settle
|
|
|
|
fireEvent.click(screen.getByRole('button', {name: /re-import from disk/i}));
|
|
await waitFor(() => expect(reimportInventories).toHaveBeenCalled());
|
|
await waitFor(() => expect(onChanged).toHaveBeenCalled());
|
|
});
|
|
|
|
test('fetches backups for the inventory on open', async () => {
|
|
renderModal();
|
|
await waitFor(() => expect(getInventoryBackups).toHaveBeenCalledWith('food-storage'));
|
|
});
|
|
});
|