summaryrefslogtreecommitdiff
path: root/apps/web/src/services/storage/migrations/__tests__
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2026-04-22 02:41:18 +0200
committerMaze Winther <mazewinther@gmail.com>2026-04-22 02:41:18 +0200
commitf5f31b43df9ef46f1afdd63ba759b2f9bd80e7a3 (patch)
tree779132620064669a21c5fd9a787ba28187c0384e /apps/web/src/services/storage/migrations/__tests__
parenta709af0059dae4702b52197f34af85a817c59a6a (diff)
downloadopencut-f5f31b43df9ef46f1afdd63ba759b2f9bd80e7a3.tar.gz
refactor: migration run() and pure v1-to-v2 transform
Diffstat (limited to 'apps/web/src/services/storage/migrations/__tests__')
-rw-r--r--apps/web/src/services/storage/migrations/__tests__/v1-to-v2.test.ts172
1 files changed, 112 insertions, 60 deletions
diff --git a/apps/web/src/services/storage/migrations/__tests__/v1-to-v2.test.ts b/apps/web/src/services/storage/migrations/__tests__/v1-to-v2.test.ts
index 6d0c37fb..0840ac76 100644
--- a/apps/web/src/services/storage/migrations/__tests__/v1-to-v2.test.ts
+++ b/apps/web/src/services/storage/migrations/__tests__/v1-to-v2.test.ts
@@ -1,10 +1,9 @@
import { describe, expect, test } from "bun:test";
-import { DEFAULT_BACKGROUND_BLUR_INTENSITY } from "@/background/blur";
-import { DEFAULT_BACKGROUND_COLOR } from "@/background/color";
-import { DEFAULT_CANVAS_SIZE } from "@/canvas/sizes";
-const DEFAULT_FPS = 30;
-import type { MediaAssetData } from "@/services/storage/types";
-import { getProjectId, transformProjectV1ToV2 } from "../transformers/v1-to-v2";
+import {
+ getProjectId,
+ transformProjectV1ToV2,
+ type V1ToV2Context,
+} from "../transformers/v1-to-v2";
import {
projectWithNoId,
projectWithNullValues,
@@ -13,10 +12,15 @@ import {
v2Project,
} from "./fixtures";
+const DEFAULT_FPS = 30;
+const DEFAULT_BACKGROUND_BLUR_INTENSITY = 10;
+const DEFAULT_BACKGROUND_COLOR = "#000000";
+const DEFAULT_CANVAS_SIZE = { width: 1920, height: 1080 };
+
describe("V1 to V2 Migration", () => {
describe("transformProjectV1ToV2", () => {
- test("creates metadata object from flat properties", async () => {
- const result = await transformProjectV1ToV2({ project: v1Project });
+ test("creates metadata object from flat properties", () => {
+ const result = transformProjectV1ToV2({ project: v1Project });
expect(result.skipped).toBe(false);
expect(result.project.version).toBe(2);
@@ -28,8 +32,8 @@ describe("V1 to V2 Migration", () => {
expect(typeof metadata.updatedAt).toBe("string");
});
- test("creates settings object from flat properties", async () => {
- const result = await transformProjectV1ToV2({ project: v1Project });
+ test("creates settings object from flat properties", () => {
+ const result = transformProjectV1ToV2({ project: v1Project });
const settings = result.project.settings as Record<string, unknown>;
expect(settings.fps).toBe(v1Project.fps);
@@ -37,8 +41,8 @@ describe("V1 to V2 Migration", () => {
expect(settings.originalCanvasSize).toBe(null);
});
- test("converts color background correctly", async () => {
- const result = await transformProjectV1ToV2({ project: v1Project });
+ test("converts color background correctly", () => {
+ const result = transformProjectV1ToV2({ project: v1Project });
const settings = result.project.settings as Record<string, unknown>;
const background = settings.background as Record<string, unknown>;
@@ -46,13 +50,13 @@ describe("V1 to V2 Migration", () => {
expect(background.color).toBe(v1Project.backgroundColor);
});
- test("converts blur background correctly", async () => {
+ test("converts blur background correctly", () => {
const projectWithBlur = {
...v1Project,
backgroundType: "blur",
blurIntensity: 30,
};
- const result = await transformProjectV1ToV2({ project: projectWithBlur });
+ const result = transformProjectV1ToV2({ project: projectWithBlur });
const settings = result.project.settings as Record<string, unknown>;
const background = settings.background as Record<string, unknown>;
@@ -60,16 +64,16 @@ describe("V1 to V2 Migration", () => {
expect(background.blurIntensity).toBe(30);
});
- test("applies legacy bookmarks to main scene", async () => {
- const result = await transformProjectV1ToV2({ project: v1Project });
+ test("applies legacy bookmarks to main scene", () => {
+ const result = transformProjectV1ToV2({ project: v1Project });
const scenes = result.project.scenes as Array<Record<string, unknown>>;
const mainScene = scenes.find((s) => s.isMain === true);
expect(mainScene?.bookmarks).toEqual(v1Project.bookmarks);
});
- test("preserves existing scene bookmarks", async () => {
- const result = await transformProjectV1ToV2({
+ test("preserves existing scene bookmarks", () => {
+ const result = transformProjectV1ToV2({
project: v1ProjectWithMultipleScenes,
});
@@ -78,22 +82,22 @@ describe("V1 to V2 Migration", () => {
expect(introScene?.bookmarks).toEqual([1.0]);
});
- test("skips project that already has v2 structure", async () => {
- const result = await transformProjectV1ToV2({ project: v2Project });
+ test("skips project that already has v2 structure", () => {
+ const result = transformProjectV1ToV2({ project: v2Project });
expect(result.skipped).toBe(true);
expect(result.reason).toBe("already v2");
});
- test("skips project with no id", async () => {
- const result = await transformProjectV1ToV2({ project: projectWithNoId });
+ test("skips project with no id", () => {
+ const result = transformProjectV1ToV2({ project: projectWithNoId });
expect(result.skipped).toBe(true);
expect(result.reason).toBe("no project id");
});
- test("handles null values gracefully", async () => {
- const result = await transformProjectV1ToV2({
+ test("handles null values gracefully", () => {
+ const result = transformProjectV1ToV2({
project: projectWithNullValues,
});
@@ -103,13 +107,13 @@ describe("V1 to V2 Migration", () => {
expect(settings.canvasSize).toEqual(DEFAULT_CANVAS_SIZE);
});
- test("uses default values for missing properties", async () => {
+ test("uses default values for missing properties", () => {
const minimalProject = {
id: "minimal",
version: 1,
scenes: [],
};
- const result = await transformProjectV1ToV2({ project: minimalProject });
+ const result = transformProjectV1ToV2({ project: minimalProject });
const settings = result.project.settings as Record<string, unknown>;
expect(settings.fps).toBe(DEFAULT_FPS);
@@ -120,14 +124,14 @@ describe("V1 to V2 Migration", () => {
expect(background.color).toBe(DEFAULT_BACKGROUND_COLOR);
});
- test("uses default blur intensity when missing", async () => {
+ test("uses default blur intensity when missing", () => {
const projectWithBlurNoIntensity = {
id: "blur-no-intensity",
version: 1,
backgroundType: "blur",
scenes: [],
};
- const result = await transformProjectV1ToV2({
+ const result = transformProjectV1ToV2({
project: projectWithBlurNoIntensity,
});
@@ -136,23 +140,23 @@ describe("V1 to V2 Migration", () => {
expect(background.blurIntensity).toBe(DEFAULT_BACKGROUND_BLUR_INTENSITY);
});
- test("preserves currentSceneId", async () => {
- const result = await transformProjectV1ToV2({ project: v1Project });
+ test("preserves currentSceneId", () => {
+ const result = transformProjectV1ToV2({ project: v1Project });
expect(result.project.currentSceneId).toBe(v1Project.currentSceneId);
});
- test("finds main scene id when currentSceneId missing", async () => {
+ test("finds main scene id when currentSceneId missing", () => {
const projectWithoutCurrentScene = {
...v1Project,
currentSceneId: undefined,
};
- const result = await transformProjectV1ToV2({
+ const result = transformProjectV1ToV2({
project: projectWithoutCurrentScene,
});
expect(result.project.currentSceneId).toBe("scene-main");
});
- test("skips loading tracks if scene already has tracks", async () => {
+ test("skips loading tracks if scene already has tracks", () => {
const projectWithTracks = {
...v1Project,
scenes: [
@@ -175,7 +179,7 @@ describe("V1 to V2 Migration", () => {
],
};
- const result = await transformProjectV1ToV2({
+ const result = transformProjectV1ToV2({
project: projectWithTracks,
});
@@ -188,22 +192,32 @@ describe("V1 to V2 Migration", () => {
});
describe("Track Loading and Transformation", () => {
- test("loads tracks from legacy DB and transforms media track to video track", async () => {
- const mockLoadMediaAsset = async ({
- mediaId,
- }: {
- mediaId: string;
- }): Promise<MediaAssetData | null> => {
- if (mediaId === "media-1") {
- return {
- id: "media-1",
- name: "Test Video",
- type: "video",
- size: 1000,
- lastModified: Date.now(),
- };
- }
- return null;
+ test("loads tracks from legacy DB and transforms media track to video track", () => {
+ const context: V1ToV2Context = {
+ legacyTracksBySceneId: {
+ "scene-main": [
+ {
+ id: "legacy-track-1",
+ type: "media",
+ name: "Legacy media track",
+ elements: [
+ {
+ id: "media-element-1",
+ name: "Test video clip",
+ type: "media",
+ mediaId: "media-1",
+ duration: 120,
+ startTime: 0,
+ trimStart: 0,
+ trimEnd: 0,
+ },
+ ],
+ },
+ ],
+ },
+ mediaTypesById: {
+ "media-1": "video",
+ },
};
const projectWithLegacyTracks = {
@@ -221,19 +235,50 @@ describe("V1 to V2 Migration", () => {
],
};
- // mock IndexedDB for this test would require setting up a test environment
- // for now, we test that the transformer handles empty tracks gracefully
- const result = await transformProjectV1ToV2({
+ const result = transformProjectV1ToV2({
project: projectWithLegacyTracks,
- options: { loadMediaAsset: mockLoadMediaAsset },
+ context,
});
const scenes = result.project.scenes as Array<Record<string, unknown>>;
const mainScene = scenes[0];
- expect(Array.isArray(mainScene.tracks)).toBe(true);
+ const tracks = mainScene.tracks as Array<Record<string, unknown>>;
+ expect(Array.isArray(tracks)).toBe(true);
+ expect(tracks).toHaveLength(1);
+ expect(tracks[0].type).toBe("video");
+ expect(tracks[0].isMain).toBe(true);
});
- test("transforms text element preserving opacity and migrating position", async () => {
+ test("transforms text element preserving opacity and migrating position", () => {
+ const context: V1ToV2Context = {
+ legacyTracksBySceneId: {
+ "scene-1": [
+ {
+ id: "legacy-text-track",
+ type: "text",
+ name: "Text",
+ elements: [
+ {
+ id: "text-element-1",
+ name: "Title",
+ type: "text",
+ content: "Hello",
+ x: 120,
+ y: 240,
+ rotation: 15,
+ opacity: 0.5,
+ duration: 90,
+ startTime: 10,
+ trimStart: 0,
+ trimEnd: 0,
+ },
+ ],
+ },
+ ],
+ },
+ mediaTypesById: {},
+ };
+
const projectWithTextTrack = {
id: "project-text",
version: 1,
@@ -251,15 +296,22 @@ describe("V1 to V2 Migration", () => {
],
};
- // since tracks are empty, transformation won't happen
- // but we verify the structure is correct
- const result = await transformProjectV1ToV2({
+ const result = transformProjectV1ToV2({
project: projectWithTextTrack,
+ context,
});
expect(result.skipped).toBe(false);
const scenes = result.project.scenes as Array<Record<string, unknown>>;
- expect(scenes.length).toBe(1);
+ const tracks = scenes[0].tracks as Array<Record<string, unknown>>;
+ const elements = tracks[0].elements as Array<Record<string, unknown>>;
+ const textElement = elements[0];
+ expect(textElement.opacity).toBe(0.5);
+ expect(textElement.transform).toEqual({
+ scale: 1,
+ position: { x: 120, y: 240 },
+ rotate: 15,
+ });
});
});