mirror of
https://github.com/oxynote/oxynote.git
synced 2026-10-18 03:19:19 +02:00
129 lines
4.0 KiB
TypeScript
129 lines
4.0 KiB
TypeScript
import { registerEndpoint } from "@nuxt/test-utils/runtime"
|
|
import { setResponseHeader, type H3Event } from "h3"
|
|
import { afterEach, beforeEach, describe, it } from "vitest"
|
|
import {
|
|
clearQueryCache,
|
|
disposeMockEndpoints,
|
|
mockEndpoint,
|
|
runInApp,
|
|
trackEndpointDisposal,
|
|
} from "./test-helpers"
|
|
import useOrganizationAPI from "./useOrganizationAPI"
|
|
|
|
function makeOrganizationAPI() {
|
|
return runInApp(() => useOrganizationAPI())
|
|
}
|
|
|
|
interface RecordedUpload {
|
|
fieldNames: string[]
|
|
}
|
|
|
|
// registers an upload handler on the test-time h3 app that the real api
|
|
// clients route through, recording the multipart field names of each call
|
|
// for accounting. The test transport hands the fetch body to the handler
|
|
// unserialized (node-mock-http assigns it straight to req.body), so the
|
|
// field names are read off the original FormData rather than parsed from
|
|
// a wire format. The handler answers with the given location header, or
|
|
// with no header at all when location is omitted.
|
|
function mockUploadEndpoint(url: string, location?: string): RecordedUpload[] {
|
|
const calls: RecordedUpload[] = []
|
|
|
|
const dispose = registerEndpoint(url, {
|
|
method: "PUT",
|
|
handler: (event: H3Event) => {
|
|
const body = (event.node.req as { body?: unknown }).body
|
|
|
|
calls.push({
|
|
fieldNames: body instanceof FormData ? [...body.keys()] : [],
|
|
})
|
|
|
|
if (location !== undefined) {
|
|
setResponseHeader(event, "location", location)
|
|
}
|
|
|
|
return null
|
|
},
|
|
})
|
|
|
|
trackEndpointDisposal(dispose)
|
|
|
|
return calls
|
|
}
|
|
|
|
// creating the composable eagerly loads its query once; refresh() joins
|
|
// that in-flight load (or reuses its fresh result) instead of forcing a
|
|
// second request, which keeps the call accounting deterministic
|
|
describe("useOrganizationAPI", { concurrent: false }, () => {
|
|
// the tests share the app-wide query cache and the test-time endpoint
|
|
// registry, so they cannot interleave
|
|
beforeEach(clearQueryCache)
|
|
|
|
afterEach(disposeMockEndpoints)
|
|
|
|
describe("uploadOrganizationLogo", () => {
|
|
it("uploads the logo and returns the stored location", async ({
|
|
expect,
|
|
}) => {
|
|
const statsCalls = mockEndpoint(
|
|
"GET",
|
|
"http://test.local/auth-realtime/api/organizations/stats",
|
|
() => ({ availableSlots: 3 }),
|
|
)
|
|
const uploadCalls = mockUploadEndpoint(
|
|
"/api/organizations/logo",
|
|
"/files/organization-logo-1",
|
|
)
|
|
const api = makeOrganizationAPI()
|
|
// settle the eager stats load so its single call is accounted for
|
|
await api.fetchOrganizationStats.refresh()
|
|
const file = new File(["x"], "x.png", { type: "image/png" })
|
|
|
|
const location = await api.uploadOrganizationLogo.mutateAsync(file)
|
|
|
|
expect(location).toBe("/files/organization-logo-1")
|
|
expect(uploadCalls).toHaveLength(1)
|
|
expect(uploadCalls[0]?.fieldNames).toEqual(["logo"])
|
|
expect(statsCalls).toHaveLength(1)
|
|
})
|
|
|
|
it("rejects when the response has no location header", async ({
|
|
expect,
|
|
}) => {
|
|
const statsCalls = mockEndpoint(
|
|
"GET",
|
|
"http://test.local/auth-realtime/api/organizations/stats",
|
|
() => ({ availableSlots: 3 }),
|
|
)
|
|
const uploadCalls = mockUploadEndpoint("/api/organizations/logo")
|
|
const api = makeOrganizationAPI()
|
|
// settle the eager stats load so its single call is accounted for
|
|
await api.fetchOrganizationStats.refresh()
|
|
const file = new File(["x"], "x.png", { type: "image/png" })
|
|
|
|
await expect(
|
|
api.uploadOrganizationLogo.mutateAsync(file),
|
|
).rejects.toThrow("missing location header")
|
|
|
|
expect(uploadCalls).toHaveLength(1)
|
|
expect(uploadCalls[0]?.fieldNames).toEqual(["logo"])
|
|
expect(statsCalls).toHaveLength(1)
|
|
})
|
|
})
|
|
|
|
describe("fetchOrganizationStats", () => {
|
|
it("fetches the organization stats", async ({ expect }) => {
|
|
const statsCalls = mockEndpoint(
|
|
"GET",
|
|
"http://test.local/auth-realtime/api/organizations/stats",
|
|
() => ({ availableSlots: 3 }),
|
|
)
|
|
const api = makeOrganizationAPI()
|
|
|
|
const result = await api.fetchOrganizationStats.refresh()
|
|
|
|
expect(result.data).toEqual({ availableSlots: 3 })
|
|
expect(statsCalls).toHaveLength(1)
|
|
})
|
|
})
|
|
})
|