tests/bundle-get-filter.test.ts
Rama main · réplica de lectura del repositorio original.
import { randomUUID } from 'node:crypto'
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
import {
BASE_URL,
createAppVersions,
createDirectApiKeyWithBindings,
getSupabaseClient,
headers,
ORG_ID_2,
resetAndSeedAppData,
resetAppData,
USER_ID_2,
} from './test-utils.ts'
const fixtureId = randomUUID()
const APP_A = `com.test.bundle.lookup.a.${fixtureId}`
const APP_B = `com.test.bundle.lookup.b.${fixtureId}`
const VERSION_NAME = `9.8.7-lookup-${fixtureId}`
let versionIdOnA: number
let deniedHeaders: typeof headers
let deniedKeyId: number
async function getBundles(query: Record<string, string>, requestHeaders: typeof headers = headers) {
const params = new URLSearchParams(query)
const response = await fetch(`${BASE_URL}/bundle?${params.toString()}`, {
method: 'GET',
headers: requestHeaders,
})
const data = await response.json()
return { response, data }
}
beforeAll(async () => {
await resetAndSeedAppData(APP_A)
await resetAndSeedAppData(APP_B)
const version = await createAppVersions(VERSION_NAME, APP_A)
versionIdOnA = version.id
const deniedKey = await createDirectApiKeyWithBindings({
userId: USER_ID_2,
key: randomUUID(),
name: `bundle-lookup-denied-${fixtureId}`,
orgId: ORG_ID_2,
roleName: 'org_admin',
})
if (!deniedKey.key)
throw new Error('Failed to create denied API key')
deniedKeyId = deniedKey.id
deniedHeaders = {
'Content-Type': 'application/json',
Authorization: deniedKey.key,
}
})
afterAll(async () => {
await resetAppData(APP_A)
await resetAppData(APP_B)
if (deniedKeyId)
await getSupabaseClient().from('apikeys').delete().eq('id', deniedKeyId)
})
describe('[GET] /bundle version and id filters', () => {
it.concurrent('returns one bundle when version exists on the app', async () => {
const { response, data } = await getBundles({ app_id: APP_A, version: VERSION_NAME })
expect(response.status).toBe(200)
expect(Array.isArray(data)).toBe(true)
expect(data).toHaveLength(1)
expect((data as { id: number, name: string }[])[0].id).toBe(versionIdOnA)
expect((data as { name: string }[])[0].name).toBe(VERSION_NAME)
})
it.concurrent('returns empty array when version does not exist', async () => {
const { response, data } = await getBundles({
app_id: APP_A,
version: `missing-${fixtureId}`,
})
expect(response.status).toBe(200)
expect(data).toEqual([])
})
it.concurrent('returns empty array when version exists on another app', async () => {
const { response, data } = await getBundles({ app_id: APP_B, version: VERSION_NAME })
expect(response.status).toBe(200)
expect(data).toEqual([])
})
it.concurrent('rejects unsafe bundle id query values', async () => {
const { response, data } = await getBundles({
app_id: APP_A,
id: '99999999999999999999',
})
expect(response.status).toBe(400)
expect((data as { error: string }).error).toBe('invalid_query')
})
it.concurrent('returns one bundle when id exists on the app', async () => {
const { response, data } = await getBundles({
app_id: APP_A,
id: String(versionIdOnA),
})
expect(response.status).toBe(200)
expect(data).toHaveLength(1)
expect((data as { id: number }[])[0].id).toBe(versionIdOnA)
})
it.concurrent('rejects API key without access to the app', async () => {
const { response, data } = await getBundles({ app_id: APP_A, version: VERSION_NAME }, deniedHeaders)
expect(response.status).toBe(404)
expect((data as { error: string }).error).toBe('app_not_found')
})
it.concurrent('keeps unpaginated list paging behavior unchanged', async () => {
const { response, data } = await getBundles({ app_id: APP_A, page: '99' })
expect(response.status).toBe(200)
expect(data).toEqual([])
})
it.concurrent('fields=summary leaves out manifest and native_packages', async () => {
const { response, data } = await getBundles({ app_id: APP_A, version: VERSION_NAME, fields: 'summary' })
expect(response.status).toBe(200)
const row = (data as Record<string, unknown>[])[0]
expect(row.id).toBe(versionIdOnA)
expect(row).toHaveProperty('checksum')
expect(row).not.toHaveProperty('native_packages')
expect(row).not.toHaveProperty('manifest')
})
it.concurrent('limit returns larger list pages', async () => {
const [{ response: small, data: smallPage }, { response: large, data: largePage }] = await Promise.all([
getBundles({ app_id: APP_A, limit: '1', fields: 'summary' }),
getBundles({ app_id: APP_A, limit: '1000', fields: 'summary' }),
])
expect(small.status).toBe(200)
expect(large.status).toBe(200)
expect(smallPage).toHaveLength(1)
expect((largePage as unknown[]).length).toBeGreaterThan(1)
expect((largePage as { id: number }[]).map(row => row.id)).toContain(versionIdOnA)
})
it.concurrent('rejects limits above the PostgREST page cap', async () => {
const { response, data } = await getBundles({ app_id: APP_A, limit: '1001' })
expect(response.status).toBe(400)
expect((data as { error: string }).error).toBe('invalid_query')
})
})