From 4d127a038bf768eded68aae3cfa5c1b12241bdac Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Fri, 27 Mar 2026 00:55:15 +0100 Subject: chore: normalize line endings --- .../storage/migrations/__tests__/fixtures/index.ts | 20 +- .../storage/migrations/__tests__/fixtures/v5.ts | 108 +++---- .../migrations/__tests__/v15-to-v16.test.ts | 186 +++++------ .../migrations/__tests__/v16-to-v17.test.ts | 264 ++++++++-------- .../migrations/__tests__/v18-to-v19.test.ts | 126 ++++---- .../storage/migrations/__tests__/v3-to-v4.test.ts | 280 ++++++++--------- .../storage/migrations/__tests__/v4-to-v5.test.ts | 274 ++++++++-------- .../storage/migrations/__tests__/v5-to-v6.test.ts | 184 +++++------ .../storage/migrations/__tests__/v8-to-v9.test.ts | 350 ++++++++++----------- 9 files changed, 896 insertions(+), 896 deletions(-) (limited to 'apps/web/src/services/storage/migrations/__tests__') diff --git a/apps/web/src/services/storage/migrations/__tests__/fixtures/index.ts b/apps/web/src/services/storage/migrations/__tests__/fixtures/index.ts index 5f82e14a..a97e42d7 100644 --- a/apps/web/src/services/storage/migrations/__tests__/fixtures/index.ts +++ b/apps/web/src/services/storage/migrations/__tests__/fixtures/index.ts @@ -1,10 +1,10 @@ -/** - * Test fixtures for storage migrations. - * These represent real project data shapes from each version. - */ - -export * from "./v0"; -export * from "./v1"; -export * from "./v2"; -export * from "./v3"; -export * from "./v5"; +/** + * Test fixtures for storage migrations. + * These represent real project data shapes from each version. + */ + +export * from "./v0"; +export * from "./v1"; +export * from "./v2"; +export * from "./v3"; +export * from "./v5"; diff --git a/apps/web/src/services/storage/migrations/__tests__/fixtures/v5.ts b/apps/web/src/services/storage/migrations/__tests__/fixtures/v5.ts index 5e181c76..89bb83c3 100644 --- a/apps/web/src/services/storage/migrations/__tests__/fixtures/v5.ts +++ b/apps/web/src/services/storage/migrations/__tests__/fixtures/v5.ts @@ -1,54 +1,54 @@ -export const v5Project = { - id: "project-v5-456", - version: 5, - metadata: { - id: "project-v5-456", - name: "My V5 Project", - thumbnail: "data:image/png;base64,abc123", - duration: 30, - createdAt: "2024-06-01T10:00:00.000Z", - updatedAt: "2024-06-01T14:00:00.000Z", - }, - settings: { - fps: 30, - canvasSize: { width: 1920, height: 1080 }, - background: { type: "color", color: "#000000" }, - }, - currentSceneId: "scene-main", - scenes: [ - { - id: "scene-main", - name: "Main scene", - isMain: true, - tracks: [ - { - id: "track-1", - type: "video", - name: "Video Track", - isMain: true, - elements: [], - }, - ], - bookmarks: [2.0, 5.5, 12.0], - createdAt: "2024-06-01T10:00:00.000Z", - updatedAt: "2024-06-01T14:00:00.000Z", - }, - { - id: "scene-intro", - name: "Intro", - isMain: false, - tracks: [ - { - id: "track-2", - type: "video", - name: "Video Track", - isMain: true, - elements: [], - }, - ], - bookmarks: [], - createdAt: "2024-06-01T10:00:00.000Z", - updatedAt: "2024-06-01T14:00:00.000Z", - }, - ], -}; +export const v5Project = { + id: "project-v5-456", + version: 5, + metadata: { + id: "project-v5-456", + name: "My V5 Project", + thumbnail: "data:image/png;base64,abc123", + duration: 30, + createdAt: "2024-06-01T10:00:00.000Z", + updatedAt: "2024-06-01T14:00:00.000Z", + }, + settings: { + fps: 30, + canvasSize: { width: 1920, height: 1080 }, + background: { type: "color", color: "#000000" }, + }, + currentSceneId: "scene-main", + scenes: [ + { + id: "scene-main", + name: "Main scene", + isMain: true, + tracks: [ + { + id: "track-1", + type: "video", + name: "Video Track", + isMain: true, + elements: [], + }, + ], + bookmarks: [2.0, 5.5, 12.0], + createdAt: "2024-06-01T10:00:00.000Z", + updatedAt: "2024-06-01T14:00:00.000Z", + }, + { + id: "scene-intro", + name: "Intro", + isMain: false, + tracks: [ + { + id: "track-2", + type: "video", + name: "Video Track", + isMain: true, + elements: [], + }, + ], + bookmarks: [], + createdAt: "2024-06-01T10:00:00.000Z", + updatedAt: "2024-06-01T14:00:00.000Z", + }, + ], +}; diff --git a/apps/web/src/services/storage/migrations/__tests__/v15-to-v16.test.ts b/apps/web/src/services/storage/migrations/__tests__/v15-to-v16.test.ts index f2a4908f..122af2cb 100644 --- a/apps/web/src/services/storage/migrations/__tests__/v15-to-v16.test.ts +++ b/apps/web/src/services/storage/migrations/__tests__/v15-to-v16.test.ts @@ -1,93 +1,93 @@ -import { describe, expect, test } from "bun:test"; -import { transformProjectV15ToV16 } from "../transformers/v15-to-v16"; - -describe("V15 to V16 Migration", () => { - test("renames sticker tracks to graphic tracks", () => { - const result = transformProjectV15ToV16({ - project: { - id: "project-v15", - version: 15, - metadata: { - id: "project-v15", - name: "Project", - createdAt: "2024-01-01T00:00:00.000Z", - updatedAt: "2024-01-01T00:00:00.000Z", - }, - settings: { - fps: 30, - canvasSize: { width: 1920, height: 1080 }, - background: { type: "color", color: "#000000" }, - }, - currentSceneId: "scene-main", - scenes: [ - { - id: "scene-main", - name: "Main scene", - isMain: true, - tracks: [ - { - id: "track-graphic", - type: "sticker", - name: "Sticker Track", - hidden: false, - elements: [ - { - id: "sticker-1", - type: "sticker", - name: "Logo", - stickerId: "icons:mdi:home", - duration: 5, - startTime: 0, - trimStart: 0, - trimEnd: 0, - transform: { - scaleX: 1, - scaleY: 1, - position: { x: 0, y: 0 }, - rotate: 0, - }, - opacity: 1, - }, - ], - }, - ], - bookmarks: [], - createdAt: "2024-01-01T00:00:00.000Z", - updatedAt: "2024-01-01T00:00:00.000Z", - }, - ], - }, - }); - - expect(result.skipped).toBe(false); - expect(result.project.version).toBe(16); - expect( - (result.project.scenes as Array<{ tracks: Array<{ type: string }> }>)[0] - .tracks[0].type, - ).toBe("graphic"); - }); - - test("skips projects already on v16", () => { - const result = transformProjectV15ToV16({ - project: { - id: "project-v16", - version: 16, - }, - }); - - expect(result.skipped).toBe(true); - expect(result.reason).toBe("already v16"); - }); - - test("skips projects with no id", () => { - const result = transformProjectV15ToV16({ - project: { - version: 15, - scenes: [], - }, - }); - - expect(result.skipped).toBe(true); - expect(result.reason).toBe("no project id"); - }); -}); +import { describe, expect, test } from "bun:test"; +import { transformProjectV15ToV16 } from "../transformers/v15-to-v16"; + +describe("V15 to V16 Migration", () => { + test("renames sticker tracks to graphic tracks", () => { + const result = transformProjectV15ToV16({ + project: { + id: "project-v15", + version: 15, + metadata: { + id: "project-v15", + name: "Project", + createdAt: "2024-01-01T00:00:00.000Z", + updatedAt: "2024-01-01T00:00:00.000Z", + }, + settings: { + fps: 30, + canvasSize: { width: 1920, height: 1080 }, + background: { type: "color", color: "#000000" }, + }, + currentSceneId: "scene-main", + scenes: [ + { + id: "scene-main", + name: "Main scene", + isMain: true, + tracks: [ + { + id: "track-graphic", + type: "sticker", + name: "Sticker Track", + hidden: false, + elements: [ + { + id: "sticker-1", + type: "sticker", + name: "Logo", + stickerId: "icons:mdi:home", + duration: 5, + startTime: 0, + trimStart: 0, + trimEnd: 0, + transform: { + scaleX: 1, + scaleY: 1, + position: { x: 0, y: 0 }, + rotate: 0, + }, + opacity: 1, + }, + ], + }, + ], + bookmarks: [], + createdAt: "2024-01-01T00:00:00.000Z", + updatedAt: "2024-01-01T00:00:00.000Z", + }, + ], + }, + }); + + expect(result.skipped).toBe(false); + expect(result.project.version).toBe(16); + expect( + (result.project.scenes as Array<{ tracks: Array<{ type: string }> }>)[0] + .tracks[0].type, + ).toBe("graphic"); + }); + + test("skips projects already on v16", () => { + const result = transformProjectV15ToV16({ + project: { + id: "project-v16", + version: 16, + }, + }); + + expect(result.skipped).toBe(true); + expect(result.reason).toBe("already v16"); + }); + + test("skips projects with no id", () => { + const result = transformProjectV15ToV16({ + project: { + version: 15, + scenes: [], + }, + }); + + expect(result.skipped).toBe(true); + expect(result.reason).toBe("no project id"); + }); +}); diff --git a/apps/web/src/services/storage/migrations/__tests__/v16-to-v17.test.ts b/apps/web/src/services/storage/migrations/__tests__/v16-to-v17.test.ts index e246943e..352ca762 100644 --- a/apps/web/src/services/storage/migrations/__tests__/v16-to-v17.test.ts +++ b/apps/web/src/services/storage/migrations/__tests__/v16-to-v17.test.ts @@ -1,132 +1,132 @@ -import { describe, expect, test } from "bun:test"; -import { transformProjectV16ToV17 } from "../transformers/v16-to-v17"; - -describe("V16 to V17 Migration", () => { - test("adds center stroke alignment to masks that do not have it", () => { - const result = transformProjectV16ToV17({ - project: { - id: "project-v16", - version: 16, - metadata: { - id: "project-v16", - name: "Project", - createdAt: "2024-01-01T00:00:00.000Z", - updatedAt: "2024-01-01T00:00:00.000Z", - }, - settings: { - fps: 30, - canvasSize: { width: 1920, height: 1080 }, - background: { type: "color", color: "#000000" }, - }, - currentSceneId: "scene-main", - scenes: [ - { - id: "scene-main", - name: "Main scene", - isMain: true, - tracks: [ - { - id: "track-video", - type: "video", - name: "Video Track", - hidden: false, - elements: [ - { - id: "video-1", - type: "video", - name: "Clip", - mediaId: "media-1", - duration: 5, - startTime: 0, - trimStart: 0, - trimEnd: 0, - transform: { - scaleX: 1, - scaleY: 1, - position: { x: 0, y: 0 }, - rotate: 0, - }, - opacity: 1, - masks: [ - { - id: "mask-1", - type: "rectangle", - params: { - feather: 0, - inverted: false, - strokeColor: "#ffffff", - strokeWidth: 8, - centerX: 0, - centerY: 0, - width: 0.6, - height: 0.6, - rotation: 0, - scale: 1, - }, - }, - { - id: "mask-2", - type: "ellipse", - params: { - feather: 0, - inverted: false, - strokeColor: "#ffffff", - strokeWidth: 8, - strokeAlign: "outside", - centerX: 0, - centerY: 0, - width: 0.6, - height: 0.6, - rotation: 0, - scale: 1, - }, - }, - ], - }, - ], - }, - ], - bookmarks: [], - createdAt: "2024-01-01T00:00:00.000Z", - updatedAt: "2024-01-01T00:00:00.000Z", - }, - ], - }, - }); - - expect(result.skipped).toBe(false); - expect(result.project.version).toBe(17); - - const migratedMasks = ( - ((result.project.scenes as Array<{ tracks: Array<{ elements: Array<{ masks: Array<{ params: Record }> }> }> }>)[0] - .tracks[0].elements[0].masks) - ); - - expect(migratedMasks[0].params.strokeAlign).toBe("center"); - expect(migratedMasks[1].params.strokeAlign).toBe("outside"); - }); - - test("skips projects already on v17", () => { - const result = transformProjectV16ToV17({ - project: { - id: "project-v17", - version: 17, - }, - }); - - expect(result.skipped).toBe(true); - expect(result.reason).toBe("already v17"); - }); - - test("skips projects with no id", () => { - const result = transformProjectV16ToV17({ - project: { - version: 16, - scenes: [], - }, - }); - - expect(result.skipped).toBe(true); - expect(result.reason).toBe("no project id"); - }); -}); +import { describe, expect, test } from "bun:test"; +import { transformProjectV16ToV17 } from "../transformers/v16-to-v17"; + +describe("V16 to V17 Migration", () => { + test("adds center stroke alignment to masks that do not have it", () => { + const result = transformProjectV16ToV17({ + project: { + id: "project-v16", + version: 16, + metadata: { + id: "project-v16", + name: "Project", + createdAt: "2024-01-01T00:00:00.000Z", + updatedAt: "2024-01-01T00:00:00.000Z", + }, + settings: { + fps: 30, + canvasSize: { width: 1920, height: 1080 }, + background: { type: "color", color: "#000000" }, + }, + currentSceneId: "scene-main", + scenes: [ + { + id: "scene-main", + name: "Main scene", + isMain: true, + tracks: [ + { + id: "track-video", + type: "video", + name: "Video Track", + hidden: false, + elements: [ + { + id: "video-1", + type: "video", + name: "Clip", + mediaId: "media-1", + duration: 5, + startTime: 0, + trimStart: 0, + trimEnd: 0, + transform: { + scaleX: 1, + scaleY: 1, + position: { x: 0, y: 0 }, + rotate: 0, + }, + opacity: 1, + masks: [ + { + id: "mask-1", + type: "rectangle", + params: { + feather: 0, + inverted: false, + strokeColor: "#ffffff", + strokeWidth: 8, + centerX: 0, + centerY: 0, + width: 0.6, + height: 0.6, + rotation: 0, + scale: 1, + }, + }, + { + id: "mask-2", + type: "ellipse", + params: { + feather: 0, + inverted: false, + strokeColor: "#ffffff", + strokeWidth: 8, + strokeAlign: "outside", + centerX: 0, + centerY: 0, + width: 0.6, + height: 0.6, + rotation: 0, + scale: 1, + }, + }, + ], + }, + ], + }, + ], + bookmarks: [], + createdAt: "2024-01-01T00:00:00.000Z", + updatedAt: "2024-01-01T00:00:00.000Z", + }, + ], + }, + }); + + expect(result.skipped).toBe(false); + expect(result.project.version).toBe(17); + + const migratedMasks = ( + ((result.project.scenes as Array<{ tracks: Array<{ elements: Array<{ masks: Array<{ params: Record }> }> }> }>)[0] + .tracks[0].elements[0].masks) + ); + + expect(migratedMasks[0].params.strokeAlign).toBe("center"); + expect(migratedMasks[1].params.strokeAlign).toBe("outside"); + }); + + test("skips projects already on v17", () => { + const result = transformProjectV16ToV17({ + project: { + id: "project-v17", + version: 17, + }, + }); + + expect(result.skipped).toBe(true); + expect(result.reason).toBe("already v17"); + }); + + test("skips projects with no id", () => { + const result = transformProjectV16ToV17({ + project: { + version: 16, + scenes: [], + }, + }); + + expect(result.skipped).toBe(true); + expect(result.reason).toBe("no project id"); + }); +}); diff --git a/apps/web/src/services/storage/migrations/__tests__/v18-to-v19.test.ts b/apps/web/src/services/storage/migrations/__tests__/v18-to-v19.test.ts index 7524a8d4..0f679b6d 100644 --- a/apps/web/src/services/storage/migrations/__tests__/v18-to-v19.test.ts +++ b/apps/web/src/services/storage/migrations/__tests__/v18-to-v19.test.ts @@ -1,63 +1,63 @@ -import { describe, expect, test } from "bun:test"; -import { transformProjectV18ToV19 } from "../transformers/v18-to-v19"; - -describe("V18 to V19 Migration", () => { - test("adds canvas size mode and empty remembered custom size defaults", () => { - const result = transformProjectV18ToV19({ - project: { - id: "project-v18-defaults", - version: 18, - metadata: { - id: "project-v18-defaults", - name: "Project", - createdAt: "2024-01-01T00:00:00.000Z", - updatedAt: "2024-01-01T00:00:00.000Z", - }, - settings: { - fps: 30, - canvasSize: { width: 1920, height: 1080 }, - originalCanvasSize: { width: 1920, height: 1080 }, - background: { type: "color", color: "#000000" }, - }, - currentSceneId: "scene-main", - scenes: [], - }, - }); - - expect(result.skipped).toBe(false); - expect(result.project.version).toBe(19); - expect( - (result.project.settings as Record).canvasSizeMode, - ).toBe("preset"); - expect( - (result.project.settings as Record).lastCustomCanvasSize, - ).toBeNull(); - expect( - (result.project.settings as Record).originalCanvasSize, - ).toEqual({ width: 1920, height: 1080 }); - }); - - test("skips projects already on v19", () => { - const result = transformProjectV18ToV19({ - project: { - id: "project-v19", - version: 19, - }, - }); - - expect(result.skipped).toBe(true); - expect(result.reason).toBe("already v19"); - }); - - test("skips projects with no id", () => { - const result = transformProjectV18ToV19({ - project: { - version: 18, - scenes: [], - }, - }); - - expect(result.skipped).toBe(true); - expect(result.reason).toBe("no project id"); - }); -}); +import { describe, expect, test } from "bun:test"; +import { transformProjectV18ToV19 } from "../transformers/v18-to-v19"; + +describe("V18 to V19 Migration", () => { + test("adds canvas size mode and empty remembered custom size defaults", () => { + const result = transformProjectV18ToV19({ + project: { + id: "project-v18-defaults", + version: 18, + metadata: { + id: "project-v18-defaults", + name: "Project", + createdAt: "2024-01-01T00:00:00.000Z", + updatedAt: "2024-01-01T00:00:00.000Z", + }, + settings: { + fps: 30, + canvasSize: { width: 1920, height: 1080 }, + originalCanvasSize: { width: 1920, height: 1080 }, + background: { type: "color", color: "#000000" }, + }, + currentSceneId: "scene-main", + scenes: [], + }, + }); + + expect(result.skipped).toBe(false); + expect(result.project.version).toBe(19); + expect( + (result.project.settings as Record).canvasSizeMode, + ).toBe("preset"); + expect( + (result.project.settings as Record).lastCustomCanvasSize, + ).toBeNull(); + expect( + (result.project.settings as Record).originalCanvasSize, + ).toEqual({ width: 1920, height: 1080 }); + }); + + test("skips projects already on v19", () => { + const result = transformProjectV18ToV19({ + project: { + id: "project-v19", + version: 19, + }, + }); + + expect(result.skipped).toBe(true); + expect(result.reason).toBe("already v19"); + }); + + test("skips projects with no id", () => { + const result = transformProjectV18ToV19({ + project: { + version: 18, + scenes: [], + }, + }); + + expect(result.skipped).toBe(true); + expect(result.reason).toBe("no project id"); + }); +}); diff --git a/apps/web/src/services/storage/migrations/__tests__/v3-to-v4.test.ts b/apps/web/src/services/storage/migrations/__tests__/v3-to-v4.test.ts index 81d03147..6c2d6597 100644 --- a/apps/web/src/services/storage/migrations/__tests__/v3-to-v4.test.ts +++ b/apps/web/src/services/storage/migrations/__tests__/v3-to-v4.test.ts @@ -1,140 +1,140 @@ -import { describe, expect, test } from "bun:test"; -import { transformProjectV3ToV4 } from "../transformers/v3-to-v4"; -import { v3Project } from "./fixtures"; - -describe("V3 to V4 Migration", () => { - test("normalizes legacy text fontWeight values", () => { - const projectWithLegacyTextWeight = { - ...v3Project, - scenes: [ - { - ...v3Project.scenes[0], - tracks: [ - { - id: "track-text", - type: "text", - name: "Text Track", - hidden: false, - elements: [ - { - id: "text-1", - type: "text", - name: "Title", - content: "Hello", - duration: 5, - startTime: 0, - trimStart: 0, - trimEnd: 0, - fontSize: 64, - fontFamily: "Inter", - color: "#ffffff", - backgroundColor: "transparent", - textAlign: "center", - fontWeight: "bold", - fontStyle: "normal", - textDecoration: "none", - transform: { - scale: 1, - position: { x: 0, y: 0 }, - rotate: 0, - }, - opacity: 1, - }, - ], - }, - ], - }, - ], - }; - - const result = transformProjectV3ToV4({ - project: projectWithLegacyTextWeight, - }); - - expect(result.skipped).toBe(false); - expect(result.project.version).toBe(4); - - const migratedScene = ( - result.project.scenes as Array> - )[0]; - const migratedTrack = ( - migratedScene.tracks as Array> - )[0]; - const migratedElement = ( - migratedTrack.elements as Array> - )[0]; - - expect(migratedElement.fontWeight).toBe("700"); - }); - - test("does not mutate non-text tracks", () => { - const projectWithoutTextTrack = { - ...v3Project, - scenes: [ - { - ...v3Project.scenes[0], - tracks: [ - { - id: "track-sticker", - type: "sticker", - name: "Sticker Track", - hidden: false, - elements: [ - { - id: "sticker-1", - type: "sticker", - name: "Flag", - iconName: "mdi:home", - duration: 5, - startTime: 0, - trimStart: 0, - trimEnd: 0, - transform: { - scale: 1, - position: { x: 0, y: 0 }, - rotate: 0, - }, - opacity: 1, - }, - ], - }, - ], - }, - ], - }; - - const result = transformProjectV3ToV4({ project: projectWithoutTextTrack }); - const migratedScene = ( - result.project.scenes as Array> - )[0]; - const migratedTrack = ( - migratedScene.tracks as Array> - )[0]; - const migratedElement = ( - migratedTrack.elements as Array> - )[0]; - - expect(migratedElement.iconName).toBe("mdi:home"); - }); - - test("skips projects that are already v4", () => { - const result = transformProjectV3ToV4({ - project: { ...v3Project, version: 4 }, - }); - - expect(result.skipped).toBe(true); - expect(result.reason).toBe("already v4"); - }); - - test("skips projects with no id", () => { - const result = transformProjectV3ToV4({ - project: { - version: 3, - scenes: [], - }, - }); - - expect(result.skipped).toBe(true); - expect(result.reason).toBe("no project id"); - }); -}); +import { describe, expect, test } from "bun:test"; +import { transformProjectV3ToV4 } from "../transformers/v3-to-v4"; +import { v3Project } from "./fixtures"; + +describe("V3 to V4 Migration", () => { + test("normalizes legacy text fontWeight values", () => { + const projectWithLegacyTextWeight = { + ...v3Project, + scenes: [ + { + ...v3Project.scenes[0], + tracks: [ + { + id: "track-text", + type: "text", + name: "Text Track", + hidden: false, + elements: [ + { + id: "text-1", + type: "text", + name: "Title", + content: "Hello", + duration: 5, + startTime: 0, + trimStart: 0, + trimEnd: 0, + fontSize: 64, + fontFamily: "Inter", + color: "#ffffff", + backgroundColor: "transparent", + textAlign: "center", + fontWeight: "bold", + fontStyle: "normal", + textDecoration: "none", + transform: { + scale: 1, + position: { x: 0, y: 0 }, + rotate: 0, + }, + opacity: 1, + }, + ], + }, + ], + }, + ], + }; + + const result = transformProjectV3ToV4({ + project: projectWithLegacyTextWeight, + }); + + expect(result.skipped).toBe(false); + expect(result.project.version).toBe(4); + + const migratedScene = ( + result.project.scenes as Array> + )[0]; + const migratedTrack = ( + migratedScene.tracks as Array> + )[0]; + const migratedElement = ( + migratedTrack.elements as Array> + )[0]; + + expect(migratedElement.fontWeight).toBe("700"); + }); + + test("does not mutate non-text tracks", () => { + const projectWithoutTextTrack = { + ...v3Project, + scenes: [ + { + ...v3Project.scenes[0], + tracks: [ + { + id: "track-sticker", + type: "sticker", + name: "Sticker Track", + hidden: false, + elements: [ + { + id: "sticker-1", + type: "sticker", + name: "Flag", + iconName: "mdi:home", + duration: 5, + startTime: 0, + trimStart: 0, + trimEnd: 0, + transform: { + scale: 1, + position: { x: 0, y: 0 }, + rotate: 0, + }, + opacity: 1, + }, + ], + }, + ], + }, + ], + }; + + const result = transformProjectV3ToV4({ project: projectWithoutTextTrack }); + const migratedScene = ( + result.project.scenes as Array> + )[0]; + const migratedTrack = ( + migratedScene.tracks as Array> + )[0]; + const migratedElement = ( + migratedTrack.elements as Array> + )[0]; + + expect(migratedElement.iconName).toBe("mdi:home"); + }); + + test("skips projects that are already v4", () => { + const result = transformProjectV3ToV4({ + project: { ...v3Project, version: 4 }, + }); + + expect(result.skipped).toBe(true); + expect(result.reason).toBe("already v4"); + }); + + test("skips projects with no id", () => { + const result = transformProjectV3ToV4({ + project: { + version: 3, + scenes: [], + }, + }); + + expect(result.skipped).toBe(true); + expect(result.reason).toBe("no project id"); + }); +}); diff --git a/apps/web/src/services/storage/migrations/__tests__/v4-to-v5.test.ts b/apps/web/src/services/storage/migrations/__tests__/v4-to-v5.test.ts index ce0c3019..95386137 100644 --- a/apps/web/src/services/storage/migrations/__tests__/v4-to-v5.test.ts +++ b/apps/web/src/services/storage/migrations/__tests__/v4-to-v5.test.ts @@ -1,137 +1,137 @@ -import { describe, expect, test } from "bun:test"; -import { transformProjectV4ToV5 } from "../transformers/v4-to-v5"; -import { v3Project } from "./fixtures"; - -describe("V4 to V5 Migration", () => { - test("migrates sticker iconName to stickerId and removes legacy color", () => { - const projectWithLegacySticker = { - ...v3Project, - version: 4, - scenes: [ - { - ...v3Project.scenes[0], - tracks: [ - { - id: "track-sticker", - type: "sticker", - name: "Sticker Track", - hidden: false, - elements: [ - { - id: "sticker-1", - type: "sticker", - name: "Home", - iconName: "mdi:home", - color: "#ff0000", - duration: 5, - startTime: 0, - trimStart: 0, - trimEnd: 0, - transform: { - scale: 1, - position: { x: 0, y: 0 }, - rotate: 0, - }, - opacity: 1, - }, - ], - }, - ], - }, - ], - }; - - const result = transformProjectV4ToV5({ - project: projectWithLegacySticker, - }); - - expect(result.skipped).toBe(false); - expect(result.project.version).toBe(5); - - const migratedScene = ( - result.project.scenes as Array> - )[0]; - const migratedTrack = ( - migratedScene.tracks as Array> - )[0]; - const migratedElement = ( - migratedTrack.elements as Array> - )[0]; - - expect(migratedElement.stickerId).toBe("icons:mdi:home"); - expect("iconName" in migratedElement).toBe(false); - expect("color" in migratedElement).toBe(false); - }); - - test("keeps provider-prefixed stickerId values unchanged", () => { - const projectWithStickerId = { - ...v3Project, - version: 4, - scenes: [ - { - ...v3Project.scenes[0], - tracks: [ - { - id: "track-sticker", - type: "sticker", - name: "Sticker Track", - hidden: false, - elements: [ - { - id: "sticker-1", - type: "sticker", - name: "Flag", - stickerId: "flags:AD", - duration: 5, - startTime: 0, - trimStart: 0, - trimEnd: 0, - transform: { - scale: 1, - position: { x: 0, y: 0 }, - rotate: 0, - }, - opacity: 1, - }, - ], - }, - ], - }, - ], - }; - - const result = transformProjectV4ToV5({ project: projectWithStickerId }); - const migratedScene = ( - result.project.scenes as Array> - )[0]; - const migratedTrack = ( - migratedScene.tracks as Array> - )[0]; - const migratedElement = ( - migratedTrack.elements as Array> - )[0]; - - expect(migratedElement.stickerId).toBe("flags:AD"); - }); - - test("skips projects that are already v5", () => { - const result = transformProjectV4ToV5({ - project: { ...v3Project, version: 5 }, - }); - - expect(result.skipped).toBe(true); - expect(result.reason).toBe("already v5"); - }); - - test("skips projects with no id", () => { - const result = transformProjectV4ToV5({ - project: { - version: 4, - scenes: [], - }, - }); - - expect(result.skipped).toBe(true); - expect(result.reason).toBe("no project id"); - }); -}); +import { describe, expect, test } from "bun:test"; +import { transformProjectV4ToV5 } from "../transformers/v4-to-v5"; +import { v3Project } from "./fixtures"; + +describe("V4 to V5 Migration", () => { + test("migrates sticker iconName to stickerId and removes legacy color", () => { + const projectWithLegacySticker = { + ...v3Project, + version: 4, + scenes: [ + { + ...v3Project.scenes[0], + tracks: [ + { + id: "track-sticker", + type: "sticker", + name: "Sticker Track", + hidden: false, + elements: [ + { + id: "sticker-1", + type: "sticker", + name: "Home", + iconName: "mdi:home", + color: "#ff0000", + duration: 5, + startTime: 0, + trimStart: 0, + trimEnd: 0, + transform: { + scale: 1, + position: { x: 0, y: 0 }, + rotate: 0, + }, + opacity: 1, + }, + ], + }, + ], + }, + ], + }; + + const result = transformProjectV4ToV5({ + project: projectWithLegacySticker, + }); + + expect(result.skipped).toBe(false); + expect(result.project.version).toBe(5); + + const migratedScene = ( + result.project.scenes as Array> + )[0]; + const migratedTrack = ( + migratedScene.tracks as Array> + )[0]; + const migratedElement = ( + migratedTrack.elements as Array> + )[0]; + + expect(migratedElement.stickerId).toBe("icons:mdi:home"); + expect("iconName" in migratedElement).toBe(false); + expect("color" in migratedElement).toBe(false); + }); + + test("keeps provider-prefixed stickerId values unchanged", () => { + const projectWithStickerId = { + ...v3Project, + version: 4, + scenes: [ + { + ...v3Project.scenes[0], + tracks: [ + { + id: "track-sticker", + type: "sticker", + name: "Sticker Track", + hidden: false, + elements: [ + { + id: "sticker-1", + type: "sticker", + name: "Flag", + stickerId: "flags:AD", + duration: 5, + startTime: 0, + trimStart: 0, + trimEnd: 0, + transform: { + scale: 1, + position: { x: 0, y: 0 }, + rotate: 0, + }, + opacity: 1, + }, + ], + }, + ], + }, + ], + }; + + const result = transformProjectV4ToV5({ project: projectWithStickerId }); + const migratedScene = ( + result.project.scenes as Array> + )[0]; + const migratedTrack = ( + migratedScene.tracks as Array> + )[0]; + const migratedElement = ( + migratedTrack.elements as Array> + )[0]; + + expect(migratedElement.stickerId).toBe("flags:AD"); + }); + + test("skips projects that are already v5", () => { + const result = transformProjectV4ToV5({ + project: { ...v3Project, version: 5 }, + }); + + expect(result.skipped).toBe(true); + expect(result.reason).toBe("already v5"); + }); + + test("skips projects with no id", () => { + const result = transformProjectV4ToV5({ + project: { + version: 4, + scenes: [], + }, + }); + + expect(result.skipped).toBe(true); + expect(result.reason).toBe("no project id"); + }); +}); 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 6bbd5634..66e87713 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,92 @@ -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[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[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> }) - .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 result = transformProjectV5ToV6({ + project: { + ...v5Project, + version: 6, + scenes: [ + { + ...(v5Project as { scenes: unknown[] }).scenes[0], + bookmarks: [{ time: 2 }, { time: 5 }], + }, + ], + } as Parameters[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[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> }) + .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 }, + ]); + }); +}); diff --git a/apps/web/src/services/storage/migrations/__tests__/v8-to-v9.test.ts b/apps/web/src/services/storage/migrations/__tests__/v8-to-v9.test.ts index 51e91f78..aa79a6ea 100644 --- a/apps/web/src/services/storage/migrations/__tests__/v8-to-v9.test.ts +++ b/apps/web/src/services/storage/migrations/__tests__/v8-to-v9.test.ts @@ -1,175 +1,175 @@ -import { describe, expect, test } from "bun:test"; -import { transformProjectV8ToV9 } from "../transformers/v8-to-v9"; - -const v8ProjectWithText = { - id: "project-v8-text", - version: 8, - metadata: { - id: "project-v8-text", - name: "V8 Project with Text", - createdAt: "2024-01-01T00:00:00.000Z", - updatedAt: "2024-01-01T00:00:00.000Z", - }, - settings: { - fps: 30, - canvasSize: { width: 1920, height: 1080 }, - background: { type: "color", color: "#000000" }, - }, - currentSceneId: "scene-main", - scenes: [ - { - id: "scene-main", - name: "Main scene", - isMain: true, - tracks: [ - { - id: "track-text", - type: "text", - name: "Text Track", - hidden: false, - elements: [ - { - id: "el-1", - type: "text", - content: "With color", - startTime: 0, - duration: 5, - background: { - color: "#ff0000", - cornerRadius: 0, - paddingX: 8, - paddingY: 4, - }, - }, - { - id: "el-2", - type: "text", - content: "Transparent", - startTime: 5, - duration: 5, - background: { - color: "transparent", - paddingX: 30, - paddingY: 42, - }, - }, - ], - }, - ], - bookmarks: [], - createdAt: "2024-01-01T00:00:00.000Z", - updatedAt: "2024-01-01T00:00:00.000Z", - }, - ], -} as Parameters[0]["project"]; - -describe("V8 to V9 Migration", () => { - test("adds background.enabled from color (transparent => false, otherwise true)", () => { - const result = transformProjectV8ToV9({ project: v8ProjectWithText }); - - expect(result.skipped).toBe(false); - expect(result.project.version).toBe(9); - - const track = ( - result.project.scenes as Array<{ tracks: Array<{ elements: unknown[] }> }> - )[0].tracks[0]; - const elements = track.elements as Array<{ background: { enabled: boolean; color: string } }>; - - expect(elements[0].background.enabled).toBe(true); - expect(elements[0].background.color).toBe("#ff0000"); - - expect(elements[1].background.enabled).toBe(false); - expect(elements[1].background.color).toBe("transparent"); - }); - - test("preserves existing background.enabled if already present", () => { - const projectWithEnabled = { - ...v8ProjectWithText, - scenes: [ - { - ...(v8ProjectWithText.scenes as Record[])[0], - tracks: [ - { - id: "track-text", - type: "text", - name: "Text Track", - hidden: false, - elements: [ - { - id: "el-1", - type: "text", - content: "Already has enabled", - startTime: 0, - duration: 5, - background: { - enabled: false, - color: "#00ff00", - }, - }, - ], - }, - ], - }, - ], - } as Parameters[0]["project"]; - - const result = transformProjectV8ToV9({ project: projectWithEnabled }); - - expect(result.skipped).toBe(false); - const elements = ( - result.project.scenes as Array<{ tracks: Array<{ elements: unknown[] }> }> - )[0].tracks[0].elements as Array<{ background: { enabled: boolean } }>; - expect(elements[0].background.enabled).toBe(false); - }); - - test("skips non-text elements and tracks", () => { - const projectWithVideoOnly = { - ...v8ProjectWithText, - scenes: [ - { - id: "scene-main", - name: "Main scene", - isMain: true, - tracks: [ - { - id: "track-video", - type: "video", - name: "Video Track", - isMain: true, - elements: [], - }, - ], - bookmarks: [], - createdAt: "2024-01-01T00:00:00.000Z", - updatedAt: "2024-01-01T00:00:00.000Z", - }, - ], - } as Parameters[0]["project"]; - - const result = transformProjectV8ToV9({ project: projectWithVideoOnly }); - - expect(result.skipped).toBe(false); - expect(result.project.version).toBe(9); - }); - - test("skips projects that are already v9", () => { - const result = transformProjectV8ToV9({ - project: { ...v8ProjectWithText, version: 9 }, - }); - - expect(result.skipped).toBe(true); - expect(result.reason).toBe("already v9"); - }); - - test("skips projects with no id", () => { - const result = transformProjectV8ToV9({ - project: { - version: 8, - scenes: [], - } as Parameters[0]["project"], - }); - - expect(result.skipped).toBe(true); - expect(result.reason).toBe("no project id"); - }); -}); +import { describe, expect, test } from "bun:test"; +import { transformProjectV8ToV9 } from "../transformers/v8-to-v9"; + +const v8ProjectWithText = { + id: "project-v8-text", + version: 8, + metadata: { + id: "project-v8-text", + name: "V8 Project with Text", + createdAt: "2024-01-01T00:00:00.000Z", + updatedAt: "2024-01-01T00:00:00.000Z", + }, + settings: { + fps: 30, + canvasSize: { width: 1920, height: 1080 }, + background: { type: "color", color: "#000000" }, + }, + currentSceneId: "scene-main", + scenes: [ + { + id: "scene-main", + name: "Main scene", + isMain: true, + tracks: [ + { + id: "track-text", + type: "text", + name: "Text Track", + hidden: false, + elements: [ + { + id: "el-1", + type: "text", + content: "With color", + startTime: 0, + duration: 5, + background: { + color: "#ff0000", + cornerRadius: 0, + paddingX: 8, + paddingY: 4, + }, + }, + { + id: "el-2", + type: "text", + content: "Transparent", + startTime: 5, + duration: 5, + background: { + color: "transparent", + paddingX: 30, + paddingY: 42, + }, + }, + ], + }, + ], + bookmarks: [], + createdAt: "2024-01-01T00:00:00.000Z", + updatedAt: "2024-01-01T00:00:00.000Z", + }, + ], +} as Parameters[0]["project"]; + +describe("V8 to V9 Migration", () => { + test("adds background.enabled from color (transparent => false, otherwise true)", () => { + const result = transformProjectV8ToV9({ project: v8ProjectWithText }); + + expect(result.skipped).toBe(false); + expect(result.project.version).toBe(9); + + const track = ( + result.project.scenes as Array<{ tracks: Array<{ elements: unknown[] }> }> + )[0].tracks[0]; + const elements = track.elements as Array<{ background: { enabled: boolean; color: string } }>; + + expect(elements[0].background.enabled).toBe(true); + expect(elements[0].background.color).toBe("#ff0000"); + + expect(elements[1].background.enabled).toBe(false); + expect(elements[1].background.color).toBe("transparent"); + }); + + test("preserves existing background.enabled if already present", () => { + const projectWithEnabled = { + ...v8ProjectWithText, + scenes: [ + { + ...(v8ProjectWithText.scenes as Record[])[0], + tracks: [ + { + id: "track-text", + type: "text", + name: "Text Track", + hidden: false, + elements: [ + { + id: "el-1", + type: "text", + content: "Already has enabled", + startTime: 0, + duration: 5, + background: { + enabled: false, + color: "#00ff00", + }, + }, + ], + }, + ], + }, + ], + } as Parameters[0]["project"]; + + const result = transformProjectV8ToV9({ project: projectWithEnabled }); + + expect(result.skipped).toBe(false); + const elements = ( + result.project.scenes as Array<{ tracks: Array<{ elements: unknown[] }> }> + )[0].tracks[0].elements as Array<{ background: { enabled: boolean } }>; + expect(elements[0].background.enabled).toBe(false); + }); + + test("skips non-text elements and tracks", () => { + const projectWithVideoOnly = { + ...v8ProjectWithText, + scenes: [ + { + id: "scene-main", + name: "Main scene", + isMain: true, + tracks: [ + { + id: "track-video", + type: "video", + name: "Video Track", + isMain: true, + elements: [], + }, + ], + bookmarks: [], + createdAt: "2024-01-01T00:00:00.000Z", + updatedAt: "2024-01-01T00:00:00.000Z", + }, + ], + } as Parameters[0]["project"]; + + const result = transformProjectV8ToV9({ project: projectWithVideoOnly }); + + expect(result.skipped).toBe(false); + expect(result.project.version).toBe(9); + }); + + test("skips projects that are already v9", () => { + const result = transformProjectV8ToV9({ + project: { ...v8ProjectWithText, version: 9 }, + }); + + expect(result.skipped).toBe(true); + expect(result.reason).toBe("already v9"); + }); + + test("skips projects with no id", () => { + const result = transformProjectV8ToV9({ + project: { + version: 8, + scenes: [], + } as Parameters[0]["project"], + }); + + expect(result.skipped).toBe(true); + expect(result.reason).toBe("no project id"); + }); +}); -- cgit v1.3.1