Refactor Study Desk application structure
This commit is contained in:
parent
faaccf8a7e
commit
089439ed90
145 changed files with 8087 additions and 3412 deletions
70
src/lib/progressNormalization.test.ts
Normal file
70
src/lib/progressNormalization.test.ts
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { normalizeProgress } from "./progressNormalization";
|
||||
|
||||
const isGrade = (value: unknown): value is "correct" | "missed" =>
|
||||
value === "correct" || value === "missed";
|
||||
|
||||
function normalize(order: string[], currentIndex: number, liveIds: string[]) {
|
||||
return normalizeProgress({
|
||||
orderJson: JSON.stringify(order),
|
||||
currentIndex,
|
||||
dataJson: JSON.stringify({ a: "correct", deleted: "missed" }),
|
||||
liveIds,
|
||||
isValidValue: isGrade,
|
||||
});
|
||||
}
|
||||
|
||||
describe("normalizeProgress", () => {
|
||||
it("preserves the logical current card when a prior card was deleted", () => {
|
||||
expect(normalize(["a", "b", "c"], 1, ["b", "c"]).currentIndex).toBe(0);
|
||||
});
|
||||
|
||||
it("uses the next survivor when the current card was deleted", () => {
|
||||
expect(normalize(["a", "b", "c"], 1, ["a", "c"]).currentIndex).toBe(1);
|
||||
});
|
||||
|
||||
it("uses the previous survivor when no later card remains", () => {
|
||||
expect(normalize(["a", "b", "c"], 2, ["a", "b"]).currentIndex).toBe(1);
|
||||
});
|
||||
|
||||
it("preserves completed state after stale IDs are removed", () => {
|
||||
const result = normalize(["a", "b", "c"], 3, ["a", "c"]);
|
||||
expect(result.currentIndex).toBe(2);
|
||||
expect(result.completed).toBe(true);
|
||||
});
|
||||
|
||||
it("recovers malformed JSON and filters stale result keys", () => {
|
||||
const result = normalizeProgress({
|
||||
orderJson: "not-json",
|
||||
currentIndex: -1,
|
||||
dataJson: '{"a":"correct","b":"invalid"}',
|
||||
liveIds: ["a", "b"],
|
||||
isValidValue: isGrade,
|
||||
});
|
||||
expect(result).toMatchObject({
|
||||
order: ["a", "b"],
|
||||
currentIndex: 0,
|
||||
data: { a: "correct" },
|
||||
completed: false,
|
||||
wasRecovered: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("returns a clear completed state when all saved cards were deleted", () => {
|
||||
const result = normalize(["deleted"], 0, []);
|
||||
expect(result).toMatchObject({ order: [], currentIndex: 0, completed: true });
|
||||
});
|
||||
|
||||
it("lets content-specific validation reject a value owned by another item", () => {
|
||||
const result = normalizeProgress({
|
||||
orderJson: '["q1","q2"]',
|
||||
currentIndex: 0,
|
||||
dataJson: '{"q1":["q2-option"]}',
|
||||
liveIds: ["q1", "q2"],
|
||||
isValidValue: (value, id): value is string[] =>
|
||||
Array.isArray(value) && value.every((optionId) => optionId === `${id}-option`),
|
||||
});
|
||||
expect(result.data).toEqual({});
|
||||
expect(result.wasRecovered).toBe(true);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue