IKHSAN
EN Read in EnglishID

snapme

Publik
Branch
master
Commit terakhir
130fdb828 Oktober 2026

session-record.test.ts

Buka raw
import { describe, expect, it } from "vitest"

import { SESSION_VERSION, serializeSession, validateRecord } from "@/features/session/sessionDb"
import type { SessionState } from "@/features/session/sessionDb"
import type { Shot } from "@/stores/booth"

/* FR-14: bentuk rekaman sesi di IndexedDB. Validasi adalah satu-satunya pagar
   antara penyimpanan dan store, jadi kasus rusaknya diuji langsung. */

const SHOT: Shot = { still: "data:image/jpeg;base64,AAAA", capturedAt: 1 }

function validState(): SessionState {
  return {
    layoutId: "strip-4",
    shots: [SHOT, null, null, null],
    frameId: "malam",
    effectId: "retro",
    stickers: [
      { id: "s1", assetId: "star", x: 300, y: 900, rotation: -6, width: 120 },
    ],
    texts: [{ id: "t1", value: "halo", x: 300, y: 1696, rotation: 0, fontSize: 44 }],
    showDate: true,
    share: { qrEnabled: true, strip: { id: "stripid12345", expiresAt: null } },
    relay: null,
    localOnly: false,
  }
}

describe("rekaman sesi", () => {
  it("serialisasi menyalin seluruh bidang dengan versi saat ini", () => {
    const state = validState()
    expect(serializeSession(state)).toEqual({ version: SESSION_VERSION, ...state })
  })

  it("menerima rekaman hasil serialisasi", () => {
    const record = serializeSession(validState())
    expect(validateRecord(record)).toEqual(record)
  })

  /* M7: bingkai Strip Hidup hanya di memori. Rekaman harus membuangnya, bukan
     menyerahkan `ImageBitmap` ke IndexedDB. */
  it("membuang bingkai klip dari rekaman", () => {
    const state = validState()
    const clip = [{ close: () => {} }] as unknown as ImageBitmap[]
    const record = serializeSession({
      ...state,
      shots: [{ ...SHOT, clip }, null, null, null],
    })
    expect(record.shots[0]).toEqual(SHOT)
    expect(record.shots[0]).not.toHaveProperty("clip")
    expect(validateRecord(record)?.shots).toEqual([SHOT, null, null, null])
  })

  it("menerima rekaman tanpa layout dengan nol foto", () => {
    const record = serializeSession({
      layoutId: null,
      shots: [],
      frameId: "klasik",
      effectId: "asli",
      stickers: [],
      texts: [],
      showDate: false,
      share: { qrEnabled: false, strip: null },
    })
    expect(validateRecord(record)).toEqual(record)
  })

  it("menolak versi yang tidak dikenal dan bukan objek", () => {
    expect(validateRecord(null)).toBeNull()
    expect(validateRecord("rekaman")).toBeNull()
    expect(validateRecord({ ...serializeSession(validState()), version: 2 })).toBeNull()
  })

  it("menolak layout tak dikenal dan jumlah slot yang tidak cocok", () => {
    const record = serializeSession(validState())
    expect(validateRecord({ ...record, layoutId: "strip-9" })).toBeNull()
    expect(validateRecord({ ...record, shots: [SHOT] })).toBeNull()
    expect(validateRecord({ ...record, shots: [SHOT, SHOT, SHOT, SHOT, SHOT] })).toBeNull()
    /* Tanpa layout, daftar foto harus kosong. */
    expect(
      validateRecord({ ...record, layoutId: null, shots: [SHOT] })
    ).toBeNull()
  })

  it("menolak tipe bidang yang salah", () => {
    const record = serializeSession(validState())
    expect(validateRecord({ ...record, frameId: 7 })).toBeNull()
    expect(validateRecord({ ...record, showDate: "ya" })).toBeNull()
    expect(validateRecord({ ...record, shots: [{ still: 1, capturedAt: 0 }, null, null, null] })).toBeNull()
    expect(
      validateRecord({ ...record, stickers: [{ id: "s1", assetId: "star" }] })
    ).toBeNull()
    expect(
      validateRecord({ ...record, texts: [{ id: "t1", value: "halo" }] })
    ).toBeNull()
  })

  /* M6: rekaman lama tidak punya `share`, dan bentuk yang rusak harus ditolak
     sebelum masuk store. */
  it("menerima rekaman lama tanpa irisan bagikan", () => {
    const record = serializeSession(validState())
    const tanpaShare: Record<string, unknown> = { ...record }
    delete tanpaShare.share
    expect(validateRecord(tanpaShare)).toEqual({
      ...record,
      share: { qrEnabled: false, strip: null },
    })
  })

  it("menerima link yang kedaluwarsanya belum diketahui", () => {
    const record = serializeSession(validState())
    expect(
      validateRecord({
        ...record,
        share: { qrEnabled: false, strip: { id: "stripid12345", expiresAt: "2026-10-19T09:00:00.000Z" } },
      })?.share
    ).toEqual({
      qrEnabled: false,
      strip: { id: "stripid12345", expiresAt: "2026-10-19T09:00:00.000Z" },
    })
  })

  it("menolak irisan bagikan yang rusak", () => {
    const record = serializeSession(validState())
    expect(validateRecord({ ...record, share: "nyala" })).toBeNull()
    expect(validateRecord({ ...record, share: { qrEnabled: "ya", strip: null } })).toBeNull()
    expect(
      validateRecord({ ...record, share: { qrEnabled: true, strip: { id: "pendek", expiresAt: null } } })
    ).toBeNull()
    expect(
      validateRecord({ ...record, share: { qrEnabled: true, strip: { id: "stripid12345", expiresAt: 7 } } })
    ).toBeNull()
  })
})
byte
5.007
baris
135
Jenis
ts
Commit terakhir
28 Oktober 2026