Files
Randify.pro/tests/import-flow.test.ts
T
emilandClaude Opus 4.7 701398f627 feat(dm-dashboard): Wave 7 — FREE→PRO data import flow (Task 22)
Adds an opt-in modal that prompts a PRO user with local data to migrate
their localStorage notes and sessionStorage initiative into the cloud.

- src/lib/client/import.ts: pure helpers (hasLocalData, shouldShowImport)
- src/components/dm/ImportModal.astro: modal UI + import orchestration
  with conflict handling for existing "DM Notes" record
- src/i18n/dm-translations.ts: 14 new keys for the import flow
- Wired into both EN and RU dm/index.astro
- tests/import-flow.test.ts: 18 unit tests on the helpers

Local storage is preserved as backup; only a "dm-import-asked" flag is
set after the user makes a decision (import or skip).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-15 23:33:39 +03:00

129 lines
3.7 KiB
TypeScript

import { describe, it, expect, beforeEach } from "vitest";
import {
getLocalNotes,
getLocalInitiative,
hasLocalData,
wasAsked,
markAsked,
shouldShowImport,
} from "../src/lib/client/import";
describe("import flow helpers", () => {
beforeEach(() => {
localStorage.clear();
sessionStorage.clear();
});
it("returns empty notes when not set", () => {
expect(getLocalNotes()).toBe("");
});
it("returns local notes content", () => {
localStorage.setItem("dm-notes", "Battle plan: flank left");
expect(getLocalNotes()).toBe("Battle plan: flank left");
});
it("returns empty initiative when not set", () => {
expect(getLocalInitiative()).toEqual([]);
});
it("parses valid initiative from sessionStorage", () => {
const data = [
{ id: "a", name: "Goblin", initiative: 12, hp: 7 },
{ id: "b", name: "Bandit", initiative: 9 },
];
sessionStorage.setItem("dm-initiative", JSON.stringify(data));
const result = getLocalInitiative();
expect(result).toHaveLength(2);
expect(result[0].name).toBe("Goblin");
expect(result[0].hp).toBe(7);
expect(result[1].initiative).toBe(9);
});
it("falls back to legacy initiative key", () => {
sessionStorage.setItem(
"it-combatants",
JSON.stringify([{ name: "Old", initiative: 5 }]),
);
const result = getLocalInitiative();
expect(result).toHaveLength(1);
expect(result[0].name).toBe("Old");
});
it("filters out entries without a name", () => {
sessionStorage.setItem(
"dm-initiative",
JSON.stringify([{ id: "x", initiative: 1 }, { name: "Keep", id: "y" }]),
);
const result = getLocalInitiative();
expect(result).toHaveLength(1);
expect(result[0].name).toBe("Keep");
});
it("handles malformed JSON gracefully", () => {
sessionStorage.setItem("dm-initiative", "not-json");
expect(getLocalInitiative()).toEqual([]);
});
it("hasLocalData returns false for empty storage", () => {
expect(hasLocalData()).toBe(false);
});
it("hasLocalData returns true when notes have content", () => {
localStorage.setItem("dm-notes", "hi");
expect(hasLocalData()).toBe(true);
});
it("hasLocalData ignores whitespace-only notes", () => {
localStorage.setItem("dm-notes", " \n ");
expect(hasLocalData()).toBe(false);
});
it("hasLocalData returns true when initiative has entries", () => {
sessionStorage.setItem(
"dm-initiative",
JSON.stringify([{ id: "a", name: "X" }]),
);
expect(hasLocalData()).toBe(true);
});
it("wasAsked toggles via markAsked", () => {
expect(wasAsked()).toBe(false);
markAsked();
expect(wasAsked()).toBe(true);
});
it("shouldShowImport: false when not pro", () => {
localStorage.setItem("dm-notes", "x");
expect(shouldShowImport("free", 1)).toBe(false);
});
it("shouldShowImport: false when pro but no userId", () => {
localStorage.setItem("dm-notes", "x");
expect(shouldShowImport("pro", undefined)).toBe(false);
});
it("shouldShowImport: false when no local data", () => {
expect(shouldShowImport("pro", 1)).toBe(false);
});
it("shouldShowImport: false when already asked", () => {
localStorage.setItem("dm-notes", "x");
markAsked();
expect(shouldShowImport("pro", 1)).toBe(false);
});
it("shouldShowImport: true when pro, has data, not asked", () => {
localStorage.setItem("dm-notes", "x");
expect(shouldShowImport("pro", 42)).toBe(true);
});
it("shouldShowImport: true with only initiative data", () => {
sessionStorage.setItem(
"dm-initiative",
JSON.stringify([{ id: "a", name: "Orc" }]),
);
expect(shouldShowImport("pro", 7)).toBe(true);
});
});