Files
supabase/apps/studio/data/storage/versioning/object-versions-query.test.ts
T
Claude af75b3f188 fix(storage): keep each version's own mime type
An overwrite can change an object's type, so labelling every version with the
current file's would have consumers classify historical bytes by what the file
happens to be now.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N3euXsz25sTybsGTcxCFfn
2026-10-07 16:38:40 +02:00

94 lines
3.4 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { toObjectVersions } from './object-versions-query'
type StorageObject = Parameters<typeof toObjectVersions>[0][number]
const object = (overrides: Partial<StorageObject>): StorageObject => ({
name: 'folder/photo.jpg',
id: null,
updated_at: null,
created_at: null,
last_accessed_at: null,
metadata: { size: 100 },
...overrides,
})
describe('toObjectVersions', () => {
it('returns newest first', () => {
const versions = toObjectVersions([
object({ version: 'old', created_at: '2026-01-01T00:00:00Z', archived_at: '2026-02-01' }),
object({ version: 'new', created_at: '2026-03-01T00:00:00Z' }),
object({ version: 'mid', created_at: '2026-02-01T00:00:00Z', archived_at: '2026-03-01' }),
])
expect(versions.map((version) => version.versionId)).toEqual(['new', 'mid', 'old'])
})
it('treats a row with no archived_at as the current version', () => {
const versions = toObjectVersions([
object({ version: 'a', created_at: '2026-01-01T00:00:00Z' }),
object({ version: 'b', created_at: '2026-02-01T00:00:00Z', archived_at: '2026-03-01' }),
])
expect(versions.find((version) => version.versionId === 'a')?.isCurrent).toBe(true)
expect(versions.find((version) => version.versionId === 'b')?.isCurrent).toBe(false)
})
it('labels the oldest upload and treats the rest as overwrites', () => {
const versions = toObjectVersions([
object({ version: 'a', created_at: '2026-01-01T00:00:00Z' }),
object({ version: 'b', created_at: '2026-02-01T00:00:00Z' }),
object({ version: 'c', created_at: '2026-03-01T00:00:00Z' }),
])
expect(versions.map((version) => version.action)).toEqual([
'overwrite',
'overwrite',
'initial upload',
])
})
it('labels delete markers and does not count them as the initial upload', () => {
const versions = toObjectVersions([
object({ version: 'upload', created_at: '2026-01-01T00:00:00Z' }),
object({
version: 'marker',
created_at: '2026-02-01T00:00:00Z',
is_delete_marker: true,
metadata: null,
}),
])
expect(versions.map((version) => version.action)).toEqual(['delete marker', 'initial upload'])
})
it('reads the size off the metadata, defaulting to zero', () => {
const versions = toObjectVersions([
object({ version: 'a', created_at: '2026-01-01T00:00:00Z', metadata: { size: 2048 } }),
object({ version: 'b', created_at: '2026-02-01T00:00:00Z', metadata: null }),
])
expect(versions.find((version) => version.versionId === 'a')?.size).toBe(2048)
expect(versions.find((version) => version.versionId === 'b')?.size).toBe(0)
})
it('keeps each version its own mime type, since an overwrite can change it', () => {
const versions = toObjectVersions([
object({
version: 'a',
created_at: '2026-01-01T00:00:00Z',
metadata: { mimetype: 'image/png' },
}),
object({ version: 'b', created_at: '2026-02-01T00:00:00Z', metadata: { size: 1 } }),
])
expect(versions.find((version) => version.versionId === 'a')?.mimeType).toBe('image/png')
expect(versions.find((version) => version.versionId === 'b')?.mimeType).toBeUndefined()
})
it('drops rows the API returned without a version id', () => {
expect(toObjectVersions([object({ created_at: '2026-01-01T00:00:00Z' })])).toEqual([])
})
})