Files
inbuxa-webmail/server/src/accountinfo.test.ts
T
jcoffey-dev ad0b913efb Fix two things live testing on 0.15.5 turned up
**About said "not detected".** Generation was only worked out from the reply to
a registry method, which we never send to a server that does not advertise
urn:stalwart:jmap — every 0.16 build does, and nothing older knows the
capability at all, so its absence is already the answer. Say so, instead of
shrugging. A session with no capabilities at all stays unknown, which is a
different thing from old.

**The caret jumped out of the OTP field after one digit.** Dialog's autofocus
effect listed onClose in its dependencies, and every caller passes an inline
arrow, so each keystroke in a dialog holding state tore the effect down, set it
up again, and refocused the first field — which in the disable-2FA dialog is
the password. Keep the handler in a ref so the effect depends only on `open`.
This was a bug in the shared dialog rather than in one screen; every dialog
with more than one field had it.

The test for it fails against the old dependency array, not just passes
against the new one.
2026-08-24 09:04:16 -07:00

68 lines
3.3 KiB
TypeScript

import { test } from "node:test";
import assert from "node:assert/strict";
import { getAccountInfo, interpretAccountInfo } from "./upstream.js";
/**
* The account locale used to be read only from `x:Account/get`, which needs
* the `sysAccountGet` permission — one the built-in `user` role is not given.
* Ordinary users therefore silently fell back to the browser locale. Stalwart
* 0.16 exposes the same field on `x:AccountSettings`, which users *can* read,
* so both are asked for and whichever answers wins.
*/
type Responses = [string, Record<string, unknown>, string][];
const settingsOk = (locale: string): Responses[number] => ["x:AccountSettings/get", { list: [{ id: "singleton", locale }] }, "s"];
const accountOk = (locale: string): Responses[number] => ["x:Account/get", { list: [{ id: "a1", locale }] }, "a"];
const failed = (id: string, type: string): Responses[number] => ["error", { type }, id];
test("prefers the locale a regular user is allowed to read", () => {
const info = interpretAccountInfo([settingsOk("de_DE.UTF-8"), accountOk("fr_FR")]);
assert.equal(info.locale, "de-DE");
assert.equal(info.generation, "0.16+");
});
test("falls back to x:Account when the settings object is forbidden", () => {
const info = interpretAccountInfo([failed("s", "forbidden"), accountOk("sr_RS@latin")]);
assert.equal(info.locale, "sr-Latn-RS");
});
test("an older server is recognised by its unknownMethod, and still yields a locale", () => {
const info = interpretAccountInfo([failed("s", "unknownMethod"), accountOk("en_GB")]);
assert.equal(info.generation, "pre-0.16");
assert.equal(info.locale, "en-GB");
});
test("a server answering the new method is 0.16+ even with no locale set", () => {
const info = interpretAccountInfo([["x:AccountSettings/get", { list: [] }, "s"], failed("a", "forbidden")]);
assert.equal(info.generation, "0.16+");
assert.equal(info.locale, null);
});
test("neither answering leaves everything unknown rather than guessing", () => {
const info = interpretAccountInfo([failed("s", "forbidden"), failed("a", "forbidden")]);
assert.deepEqual(info, { locale: null, generation: null, edition: null });
assert.deepEqual(interpretAccountInfo([]), { locale: null, generation: null, edition: null });
});
test("locales that carry no language are dropped, not passed through", () => {
assert.equal(interpretAccountInfo([settingsOk("C")]).locale, null);
assert.equal(interpretAccountInfo([settingsOk("POSIX")]).locale, null);
});
test("a server that never heard of the Stalwart capability is reported as pre-0.16", async () => {
// 0.16 always advertises urn:stalwart:jmap and nothing older knows it at all,
// so its absence is the answer - and asking anyway would fail the whole
// request on those servers. This is what the live 0.15.5 box hits.
const session = { capabilities: { "urn:ietf:params:jmap:core": {}, "urn:ietf:params:jmap:mail": {} }, accounts: {}, primaryAccounts: {} };
const info = await getAccountInfo("session-pre-016", "Basic x", session as never);
assert.equal(info.generation, "pre-0.16");
assert.equal(info.locale, null);
assert.equal(info.edition, null);
});
test("no capabilities at all leaves the generation unknown", async () => {
const info = await getAccountInfo("session-no-caps", "Basic x", { accounts: {}, primaryAccounts: {} } as never);
assert.equal(info.generation, null);
});