- Own folders are made, renamed and deleted from the rail (right click, long press, Shift+F10) or the "…" beside an open folder's name; any folder's retention is a submenu (7/30/90 days, until deleted). Deleting confirms where its files go. - List or grid per folder, sharing one sort; the grid is the one media card. - A file dropped anywhere on the page opens Upload with it, bound for the folder on screen. - A link (?item=) or the upload notice opens Files on the file: its page turned to, the keyboard on it, a ring round it. - An in-place name field left by Enter or Escape hands the focus back to what replaced it (the row, the entry, the "…") instead of dropping it on <body>. - The table's saved page size is per account.
93 lines
3.6 KiB
TypeScript
93 lines
3.6 KiB
TypeScript
// @vitest-environment jsdom
|
|
//
|
|
// FilesProvider's arrival at one file: `openFile` (a notice's "Open") and a `?item=` link both make a
|
|
// pending focus that the Files page spends once it has looked; what it found is held until the page
|
|
// is left. Real storage with the tab's account pinned; only the navigation is mocked, its page
|
|
// switchable.
|
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { act, renderHook } from "@testing-library/react";
|
|
import type { ReactNode } from "react";
|
|
|
|
const nav = vi.hoisted(() => ({ page: "files", setPage: vi.fn() }));
|
|
vi.mock("./navigationContext", () => ({
|
|
useNavigation: () => ({ page: nav.page }),
|
|
useNavigationActions: () => ({ setPage: nav.setPage }),
|
|
}));
|
|
|
|
import { FilesProvider } from "./FilesProvider";
|
|
import { ALL_FILES, useFiles, useFilesActions } from "./filesContext";
|
|
|
|
const wrapper = ({ children }: { children: ReactNode }) => (
|
|
<FilesProvider>{children}</FilesProvider>
|
|
);
|
|
const render = () => renderHook(() => ({ ...useFiles(), ...useFilesActions() }), { wrapper });
|
|
|
|
beforeEach(() => {
|
|
localStorage.clear();
|
|
sessionStorage.setItem("siftlode.activeAccount", "1");
|
|
window.history.replaceState(null, "", "/");
|
|
nav.page = "files";
|
|
nav.setPage.mockClear();
|
|
});
|
|
|
|
describe("FilesProvider · arriving at one file", () => {
|
|
it("openFile opens its folder on the Files page, with no search hiding it", () => {
|
|
nav.page = "feed";
|
|
const { result, rerender } = render();
|
|
act(() => result.current.setSearch("valami"));
|
|
act(() => result.current.openFile(7, 3));
|
|
expect(nav.setPage).toHaveBeenCalledWith("files");
|
|
expect(result.current.view).toEqual({ kind: "folder", id: 3 });
|
|
expect(result.current.search).toBe("");
|
|
nav.page = "files";
|
|
rerender();
|
|
expect(result.current.focus).toMatchObject({ id: 7 });
|
|
// The address carries it until it is spent, so a reload mid-arrival still lands on the file.
|
|
expect(new URLSearchParams(window.location.search).get("item")).toBe("7");
|
|
});
|
|
|
|
it("a file in no folder opens every file", () => {
|
|
const { result } = render();
|
|
act(() => result.current.openFile(7, null));
|
|
expect(result.current.view).toEqual(ALL_FILES);
|
|
});
|
|
|
|
it("a ?item= link is an arrival from the start", () => {
|
|
window.history.replaceState(null, "", "/?item=12");
|
|
const { result } = render();
|
|
expect(result.current.focus).toMatchObject({ id: 12 });
|
|
});
|
|
|
|
it("spent, it is what the page found — until the page is left", () => {
|
|
const { result, rerender } = render();
|
|
act(() => result.current.openFile(7, null));
|
|
act(() => result.current.consumeFocus("all"));
|
|
expect(result.current.focus).toBeNull();
|
|
expect(result.current.arrived).toMatchObject({ id: 7, view: "all" });
|
|
expect(new URLSearchParams(window.location.search).get("item")).toBeNull();
|
|
nav.page = "feed";
|
|
rerender();
|
|
expect(result.current.arrived).toBeNull();
|
|
nav.page = "files";
|
|
rerender();
|
|
// Back on the page later: nothing is rung or turned to again.
|
|
expect(result.current.arrived).toBeNull();
|
|
});
|
|
|
|
it("an arrival found nowhere leaves nothing found", () => {
|
|
const { result } = render();
|
|
act(() => result.current.openFile(7, null));
|
|
act(() => result.current.consumeFocus(null));
|
|
expect(result.current.focus).toBeNull();
|
|
expect(result.current.arrived).toBeNull();
|
|
});
|
|
|
|
it("the same file opened again is a new arrival", () => {
|
|
const { result } = render();
|
|
act(() => result.current.openFile(7, null));
|
|
act(() => result.current.consumeFocus("all"));
|
|
act(() => result.current.openFile(7, null));
|
|
expect(result.current.focus).toMatchObject({ id: 7 });
|
|
});
|
|
});
|