Files
ihasmail-inbuxa/web/src/lib/mailbox/__tests__/mailboxName.test.ts
T
jcoffey-dev bd6a605d61 Group six more clusters out of web/src/lib
Takes the flat module count from 66 to 42, continuing what admin/ and
calendar/ started.

  lib/mailbox/  archiveDate, emptyFolder, folderMove, labelTree,
                mailboxName, mailboxRoute
  lib/sieve/    sieve, sieveApply, sieveFolders
  lib/input/    keyboard, swipe, touch, listSelection, dropUpload
  lib/notify/   notify, webpush, webpushEnable
  lib/sw/       swCache, swFacts, staleBuild
  lib/text/     html, markdown, text, emlName

FOUR THINGS THE FILENAMES GET WRONG, each checked by reading the file
rather than trusting what it is called:

  - appFolder is not a mailbox. It is the `ihasmail` folder in JMAP
    *Files*, where the client keeps signature images and synced settings.
    It stays flat.
  - format holds no formatting of text. It re-exports the date and clock
    formatters, so it belongs with dates/datetime, not with text/.
  - preview is the file viewer deciding what it can show without
    downloading, and source is where to point someone asking for this
    instance's AGPL source. Neither is about text.
  - notify is not Web Push. It is the tab title, the favicon badge and
    the new-mail sound -- in-app notification, which is why it sits with
    webpush rather than under sw/ with the service worker's own concerns.

threadScroll stays flat too: it decides where a conversation opens, which
is view state rather than a gesture, and input/ is honest only if
everything in it interprets something the reader did.

No behavior change. Almost every reference was on the @/ alias; eight
relative imports in files that did not move, or that moved away from a
sibling, needed rewriting by hand.
2026-09-15 23:17:50 -07:00

69 lines
3.0 KiB
TypeScript

import { afterEach, describe, expect, it } from "vitest";
import { isLocalizedName, mailboxDisplayName, mailboxDisplayPath } from "@/lib/mailbox/mailboxName";
import { setCatalog, type Catalog } from "@/lib/i18n";
import type { Mailbox } from "@/jmap/types";
/**
* Stalwart names the standard folders once, at account creation, and never
* renames them — so a German reader on an English-provisioned account would
* otherwise see "Deleted Items" in an otherwise German app. The role is what
* lets ihasmail say "Papierkorb" without writing anything to the server.
*/
const de: Catalog = {
strings: { Inbox: "Posteingang", "Deleted Items": "Papierkorb", Drafts: "Entwürfe" },
plurals: {},
};
const mb = (id: string, name: string, role: string | null = null, parentId: string | null = null) =>
({ id, name, role, parentId } as unknown as Mailbox);
afterEach(() => setCatalog("en", { strings: {}, plurals: {} }));
describe("mailboxDisplayName", () => {
it("is the server's name until a catalog says otherwise", () => {
expect(mailboxDisplayName(mb("1", "Deleted Items", "trash"))).toBe("Deleted Items");
});
it("follows the interface language for a folder carrying a role", () => {
setCatalog("de", de);
expect(mailboxDisplayName(mb("1", "Deleted Items", "trash"))).toBe("Papierkorb");
expect(mailboxDisplayName(mb("2", "Inbox", "inbox"))).toBe("Posteingang");
});
it("leaves a folder somebody made alone", () => {
// "Newsletters" is their word. Translating it would name a folder they
// never created, and it would not match what any other client shows.
setCatalog("de", de);
expect(mailboxDisplayName(mb("3", "Newsletters"))).toBe("Newsletters");
expect(mailboxDisplayName(mb("4", "Work", "subscribed"))).toBe("Work");
});
it("survives a missing mailbox rather than printing undefined", () => {
expect(mailboxDisplayName(null)).toBe("");
expect(mailboxDisplayName(undefined)).toBe("");
});
});
describe("isLocalizedName", () => {
it("tells an editor when the name on screen is not the server's", () => {
// A rename box prefilled with "Papierkorb" would rename the folder to that
// the moment somebody pressed Save — a real change made by accident.
expect(isLocalizedName(mb("1", "Deleted Items", "trash"))).toBe(true);
expect(isLocalizedName(mb("2", "Newsletters"))).toBe(false);
expect(isLocalizedName(mb("3", "Work", "subscribed"))).toBe(false);
});
});
describe("mailboxDisplayPath", () => {
it("localizes each part that has a role and leaves the rest", () => {
setCatalog("de", de);
const all = { a: mb("a", "Inbox", "inbox"), b: mb("b", "Projects", null, "a") };
expect(mailboxDisplayPath(all.b!, all)).toBe("Posteingang / Projects");
});
it("stops rather than looping on a parent cycle", () => {
// A malformed tree from the server must not hang the folder picker.
const all: Record<string, Mailbox> = { a: mb("a", "A", null, "b"), b: mb("b", "B", null, "a") };
expect(mailboxDisplayPath(all.a!, all)).toBe("B / A");
});
});