Security: - Clear the offline IndexedDB cache on sign-in (not only logout) so a previous user's persisted query cache and Yjs page bodies cannot leak to the next user on a shared device when the prior session ended without an explicit logout. Regressions: - Remove the double Yjs title write from the AI title-generation path: the title editor is bound to the Yjs `title` fragment and the server REST update reseeds it, so the local setContent raced that reseed and doubled/garbled the title. Conventions / i18n / docs: - Remove the unused showAiMenuAtom. - Register the 3 offline-fallback strings in en-US and ru-RU. - Fix the 5 broken links to the nonexistent docs/offline-sync-plan.md. Stability / simplification: - warmInfiniteAll now reports truncation (returns false) when it hits maxPages with a cursor still pending instead of silently succeeding. - space-tree make-offline catch logs the raw error and surfaces the real cause. - Move the Offline/Mobile/CORS CHANGELOG entries from the released 0.93.0 section into [Unreleased] (CORS is a documented breaking change). - Drop the pass-through sync-flag forwarders in use-page-collab-providers; set the atoms directly. - Collapse the three isSwaggerEnabled true-cases into it.each. Tests / architecture: - Extract collabTokenNeedsRefresh (pure) and cover all four token states. - Extract shouldPropagateTitleChange and cover the collab-origin skip; add a TitleEditor render test for the static-h1 vs collaborative-editor switch. - Add a use-auth test asserting the sign-in cache purge runs before login. - Add an OFFLINE_PERSIST_ROOTS guard test asserting every persisted root maps to an exported query-key factory; route make-offline's currentUser warm through a new userKeys factory. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
34 lines
1.2 KiB
TypeScript
34 lines
1.2 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
|
|
// isChangeOrigin is mocked so we can simulate local vs remote/collab-origin
|
|
// transactions without constructing a real ProseMirror/Yjs transaction.
|
|
const isChangeOriginMock = vi.hoisted(() => vi.fn());
|
|
vi.mock("@tiptap/extension-collaboration", () => ({
|
|
isChangeOrigin: isChangeOriginMock,
|
|
}));
|
|
|
|
import { shouldPropagateTitleChange } from "./title-collab";
|
|
|
|
beforeEach(() => {
|
|
isChangeOriginMock.mockReset();
|
|
});
|
|
|
|
describe("shouldPropagateTitleChange", () => {
|
|
it("propagates a genuine local edit (isChangeOrigin false)", () => {
|
|
isChangeOriginMock.mockReturnValue(false);
|
|
expect(shouldPropagateTitleChange({ local: true })).toBe(true);
|
|
expect(isChangeOriginMock).toHaveBeenCalledWith({ local: true });
|
|
});
|
|
|
|
it("skips a remote/collab-origin update (isChangeOrigin true)", () => {
|
|
isChangeOriginMock.mockReturnValue(true);
|
|
expect(shouldPropagateTitleChange({ remote: true })).toBe(false);
|
|
});
|
|
|
|
it("propagates when there is no transaction (treated as local)", () => {
|
|
expect(shouldPropagateTitleChange(undefined)).toBe(true);
|
|
// isChangeOrigin must not be called for a missing transaction.
|
|
expect(isChangeOriginMock).not.toHaveBeenCalled();
|
|
});
|
|
});
|