fix(files): review round 1, the page — honest states, the keyboard, the tray's words
- A library past the list's cap is searched and sorted on the server; the count says "the newest". - Each folder and each search opens on its first page (DataTable pageScope, useCardPager scope). - A file dropped where the page takes none never reaches the browser (which would unload the app). - The viewer's arrows wait while a layer opened from it is on top, and scroll a wide text line; a text shows its first 5000 lines and says where the rest is. - Confirms name the file (no more "your downloads"); the asking menu rows end in "…". - The tray names a running step beside its bar, shows a pause mark for paused work, polls slowly while only paused work waits, and forgets a finished file that was deleted. - An unchanged rename sends nothing; a paste opens the download dialog only with nothing on top; the link box never replaces what was typed. - Honest states: folders that failed to load, a file no longer there, the storage figure; the rail says "nothing downloaded" only when there is nothing. - Focus after deleting the open folder and when the format form opens; the format name's label. - ui/Meter (one danger line for both quota bars) and ui/RenameField in the platform layer. - Copy fixes, stale comments and the speculative hub key; a contract test for the list's parameters; e2e: the Files page and the paste intake.
This commit is contained in:
@@ -24,6 +24,7 @@ import DownloadIntake from "./DownloadIntake";
|
||||
import { LinkBox } from "./LinkBox";
|
||||
import { clearPendingDownload, requestLinkBox } from "../lib/downloadIntake";
|
||||
import { ensureNavId } from "../lib/history";
|
||||
import { pushLayer, removeLayer } from "../lib/layerStack";
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
@@ -79,6 +80,18 @@ describe("DownloadIntake · a pasted link", () => {
|
||||
expect(dialog()).toBeNull();
|
||||
});
|
||||
|
||||
it("with a player or a menu on top (a layer, no aria-modal), a paste is not a download", async () => {
|
||||
render(<DownloadIntake />);
|
||||
const layer = pushLayer();
|
||||
try {
|
||||
paste(document.body, "https://a.example/1");
|
||||
await act(async () => {});
|
||||
expect(dialog()).toBeNull();
|
||||
} finally {
|
||||
removeLayer(layer);
|
||||
}
|
||||
});
|
||||
|
||||
it("closing the dialog closes it", async () => {
|
||||
render(<DownloadIntake />);
|
||||
paste(document.body, "https://a.example/1");
|
||||
@@ -102,6 +115,20 @@ describe("LinkBox", () => {
|
||||
expect((field as HTMLInputElement).value).toBe("");
|
||||
});
|
||||
|
||||
it("a clipboard link read on focus never replaces what was typed while it was read", async () => {
|
||||
let answer: (text: string) => void = () => {};
|
||||
Object.defineProperty(navigator, "clipboard", {
|
||||
configurable: true,
|
||||
value: { readText: () => new Promise<string>((resolve) => (answer = resolve)) },
|
||||
});
|
||||
render(<LinkBox />);
|
||||
const box = screen.getByRole("textbox");
|
||||
fireEvent.focus(box);
|
||||
fireEvent.change(box, { target: { value: "https://typed.example/1" } });
|
||||
await act(async () => answer("https://clipboard.example/2"));
|
||||
expect((box as HTMLInputElement).value).toBe("https://typed.example/1");
|
||||
});
|
||||
|
||||
it("an empty box downloads nothing", async () => {
|
||||
render(
|
||||
<>
|
||||
|
||||
Reference in New Issue
Block a user