diff options
Diffstat (limited to 'apps/web/src/services/storage/migrations/__tests__')
| -rw-r--r-- | apps/web/src/services/storage/migrations/__tests__/v21-to-v22.test.ts | 241 | ||||
| -rw-r--r-- | apps/web/src/services/storage/migrations/__tests__/v5-to-v6.test.ts | 186 |
2 files changed, 335 insertions, 92 deletions
diff --git a/apps/web/src/services/storage/migrations/__tests__/v21-to-v22.test.ts b/apps/web/src/services/storage/migrations/__tests__/v21-to-v22.test.ts new file mode 100644 index 00000000..18b815b0 --- /dev/null +++ b/apps/web/src/services/storage/migrations/__tests__/v21-to-v22.test.ts @@ -0,0 +1,241 @@ +import { describe, expect, test } from "bun:test"; +import { transformProjectV21ToV22 } from "../transformers/v21-to-v22"; + +describe("V21 to V22 Migration", () => { + test("migrates legacy animation channels to bindings and component channels", () => { + const result = transformProjectV21ToV22({ + project: { + id: "project-v21-animations", + version: 21, + scenes: [ + { + id: "scene-1", + tracks: [ + { + id: "track-1", + elements: [ + { + id: "element-1", + type: "text", + animations: { + channels: { + opacity: { + valueKind: "number", + keyframes: [ + { + id: "opacity-1", + time: 1, + value: 0.5, + interpolation: "linear", + }, + ], + }, + "transform.position": { + valueKind: "vector", + keyframes: [ + { + id: "position-1", + time: 2, + value: { x: 10, y: 20 }, + interpolation: "hold", + }, + ], + }, + color: { + valueKind: "color", + keyframes: [ + { + id: "color-1", + time: 3, + value: "#ff0000", + interpolation: "linear", + }, + ], + }, + "effects.effect-1.params.enabled": { + valueKind: "discrete", + keyframes: [ + { + id: "enabled-1", + time: 4, + value: true, + interpolation: "hold", + }, + ], + }, + }, + }, + }, + ], + }, + ], + }, + ], + }, + }); + + expect(result.skipped).toBe(false); + expect(result.project.version).toBe(22); + + const scenes = result.project.scenes as Array<Record<string, unknown>>; + const tracks = scenes[0].tracks as Array<Record<string, unknown>>; + const elements = tracks[0].elements as Array<Record<string, unknown>>; + const animations = elements[0].animations as Record<string, unknown>; + const bindings = animations.bindings as Record<string, Record<string, unknown>>; + const channels = animations.channels as Record<string, Record<string, unknown>>; + + expect(bindings.opacity).toEqual({ + path: "opacity", + kind: "number", + components: [{ key: "value", channelId: "opacity:value" }], + }); + expect(bindings["transform.position"]).toEqual({ + path: "transform.position", + kind: "vector2", + components: [ + { key: "x", channelId: "transform.position:x" }, + { key: "y", channelId: "transform.position:y" }, + ], + }); + expect(bindings.color).toEqual({ + path: "color", + kind: "color", + colorSpace: "srgb-linear", + components: [ + { key: "r", channelId: "color:r" }, + { key: "g", channelId: "color:g" }, + { key: "b", channelId: "color:b" }, + { key: "a", channelId: "color:a" }, + ], + }); + expect(bindings["effects.effect-1.params.enabled"]).toEqual({ + path: "effects.effect-1.params.enabled", + kind: "discrete", + components: [ + { + key: "value", + channelId: "effects.effect-1.params.enabled:value", + }, + ], + }); + + expect(channels["opacity:value"]).toEqual({ + kind: "scalar", + keys: [ + { + id: "opacity-1", + time: 1, + value: 0.5, + segmentToNext: "linear", + tangentMode: "flat", + }, + ], + }); + expect(channels["transform.position:x"]).toEqual({ + kind: "scalar", + keys: [ + { + id: "position-1", + time: 2, + value: 10, + segmentToNext: "step", + tangentMode: "flat", + }, + ], + }); + expect(channels["transform.position:y"]).toEqual({ + kind: "scalar", + keys: [ + { + id: "position-1", + time: 2, + value: 20, + segmentToNext: "step", + tangentMode: "flat", + }, + ], + }); + expect(channels["color:r"]).toEqual({ + kind: "scalar", + keys: [ + { + id: "color-1", + time: 3, + value: 1, + segmentToNext: "linear", + tangentMode: "flat", + }, + ], + }); + expect(channels["color:g"]).toEqual({ + kind: "scalar", + keys: [ + { + id: "color-1", + time: 3, + value: 0, + segmentToNext: "linear", + tangentMode: "flat", + }, + ], + }); + expect(channels["color:b"]).toEqual({ + kind: "scalar", + keys: [ + { + id: "color-1", + time: 3, + value: 0, + segmentToNext: "linear", + tangentMode: "flat", + }, + ], + }); + expect(channels["color:a"]).toEqual({ + kind: "scalar", + keys: [ + { + id: "color-1", + time: 3, + value: 1, + segmentToNext: "linear", + tangentMode: "flat", + }, + ], + }); + expect(channels["effects.effect-1.params.enabled:value"]).toEqual({ + kind: "discrete", + keys: [ + { + id: "enabled-1", + time: 4, + value: true, + }, + ], + }); + }); + + test("skips projects already on v22", () => { + const result = transformProjectV21ToV22({ + project: { + id: "project-v22", + version: 22, + }, + }); + + expect(result.skipped).toBe(true); + expect(result.reason).toBe("already v22"); + }); + + test("skips projects not on v21", () => { + const result = transformProjectV21ToV22({ + project: { + id: "project-v20", + version: 20, + }, + }); + + expect(result.skipped).toBe(true); + expect(result.reason).toBe("not v21"); + }); +}); diff --git a/apps/web/src/services/storage/migrations/__tests__/v5-to-v6.test.ts b/apps/web/src/services/storage/migrations/__tests__/v5-to-v6.test.ts index 66e87713..b05d1837 100644 --- a/apps/web/src/services/storage/migrations/__tests__/v5-to-v6.test.ts +++ b/apps/web/src/services/storage/migrations/__tests__/v5-to-v6.test.ts @@ -1,92 +1,94 @@ -import { describe, expect, test } from "bun:test";
-import { transformProjectV5ToV6 } from "../transformers/v5-to-v6";
-import { v5Project } from "./fixtures";
-
-describe("V5 to V6 Migration", () => {
- test("converts number bookmarks to Bookmark objects", async () => {
- const result = transformProjectV5ToV6({
- project: v5Project as Parameters<
- typeof transformProjectV5ToV6
- >[0]["project"],
- });
-
- expect(result.skipped).toBe(false);
- expect(result.project.version).toBe(6);
-
- const mainScene = (
- result.project.scenes as Array<{ bookmarks: unknown[] }>
- )[0];
- expect(mainScene.bookmarks).toEqual([
- { time: 2.0 },
- { time: 5.5 },
- { time: 12.0 },
- ]);
-
- const introScene = (
- result.project.scenes as Array<{ bookmarks: unknown[] }>
- )[1];
- expect(introScene.bookmarks).toEqual([]);
- });
-
- test("skips projects that are already v6", () => {
- const result = transformProjectV5ToV6({
- project: {
- ...v5Project,
- version: 6,
- scenes: [
- {
- ...(v5Project as { scenes: unknown[] }).scenes[0],
- bookmarks: [{ time: 2 }, { time: 5 }],
- },
- ],
- } as Parameters<typeof transformProjectV5ToV6>[0]["project"],
- });
-
- expect(result.skipped).toBe(true);
- expect(result.reason).toBe("already v6");
- });
-
- test("skips projects with no id", () => {
- const result = transformProjectV5ToV6({
- project: {
- version: 5,
- scenes: [],
- } as Parameters<typeof transformProjectV5ToV6>[0]["project"],
- });
-
- expect(result.skipped).toBe(true);
- expect(result.reason).toBe("no project id");
- });
-
- test("preserves existing Bookmark objects with note, color, duration", () => {
- const projectWithRichBookmarks = {
- ...v5Project,
- version: 5,
- scenes: [
- {
- ...(v5Project as { scenes: Array<Record<string, unknown>> })
- .scenes[0],
- bookmarks: [
- { time: 1, note: "Intro", color: "#ef4444" },
- { time: 5.5, duration: 2 },
- ],
- },
- ],
- };
-
- const result = transformProjectV5ToV6({
- project: projectWithRichBookmarks as Parameters<
- typeof transformProjectV5ToV6
- >[0]["project"],
- });
-
- expect(result.skipped).toBe(false);
- const mainScene = (
- result.project.scenes as Array<{ bookmarks: unknown[] }>
- )[0];
- expect(mainScene.bookmarks).toEqual([
- { time: 1, note: "Intro", color: "#ef4444" },
- { time: 5.5, duration: 2 },
- ]);
- });
-});
+import { describe, expect, test } from "bun:test"; +import { transformProjectV5ToV6 } from "../transformers/v5-to-v6"; +import { v5Project } from "./fixtures"; + +describe("V5 to V6 Migration", () => { + test("converts number bookmarks to Bookmark objects", async () => { + const result = transformProjectV5ToV6({ + project: v5Project as Parameters< + typeof transformProjectV5ToV6 + >[0]["project"], + }); + + expect(result.skipped).toBe(false); + expect(result.project.version).toBe(6); + + const mainScene = ( + result.project.scenes as Array<{ bookmarks: unknown[] }> + )[0]; + expect(mainScene.bookmarks).toEqual([ + { time: 2.0 }, + { time: 5.5 }, + { time: 12.0 }, + ]); + + const introScene = ( + result.project.scenes as Array<{ bookmarks: unknown[] }> + )[1]; + expect(introScene.bookmarks).toEqual([]); + }); + + test("skips projects that are already v6", () => { + const firstScene = (v5Project as { scenes: Array<Record<string, unknown>> }) + .scenes[0]; + const result = transformProjectV5ToV6({ + project: { + ...v5Project, + version: 6, + scenes: [ + { + ...firstScene, + bookmarks: [{ time: 2 }, { time: 5 }], + }, + ], + } as Parameters<typeof transformProjectV5ToV6>[0]["project"], + }); + + expect(result.skipped).toBe(true); + expect(result.reason).toBe("already v6"); + }); + + test("skips projects with no id", () => { + const result = transformProjectV5ToV6({ + project: { + version: 5, + scenes: [], + } as Parameters<typeof transformProjectV5ToV6>[0]["project"], + }); + + expect(result.skipped).toBe(true); + expect(result.reason).toBe("no project id"); + }); + + test("preserves existing Bookmark objects with note, color, duration", () => { + const projectWithRichBookmarks = { + ...v5Project, + version: 5, + scenes: [ + { + ...(v5Project as { scenes: Array<Record<string, unknown>> }) + .scenes[0], + bookmarks: [ + { time: 1, note: "Intro", color: "#ef4444" }, + { time: 5.5, duration: 2 }, + ], + }, + ], + }; + + const result = transformProjectV5ToV6({ + project: projectWithRichBookmarks as Parameters< + typeof transformProjectV5ToV6 + >[0]["project"], + }); + + expect(result.skipped).toBe(false); + const mainScene = ( + result.project.scenes as Array<{ bookmarks: unknown[] }> + )[0]; + expect(mainScene.bookmarks).toEqual([ + { time: 1, note: "Intro", color: "#ef4444" }, + { time: 5.5, duration: 2 }, + ]); + }); +}); |
