@follow-app/client-sdk
Version:
TypeScript client SDK for Follow RSS Server API
245 lines (204 loc) • 6.78 kB
text/typescript
import { beforeEach, describe, expect, it, vi } from "vitest"
import { defineRoute } from "../shared/define-module"
import { HttpClient } from "./base"
// Mock fetch
const mockFetch = vi.fn()
global.fetch = mockFetch
describe("Content Types Support", () => {
let client: HttpClient
beforeEach(() => {
client = new HttpClient({
baseURL: "https://api.example.com",
fetch: mockFetch,
})
mockFetch.mockClear()
})
describe("Request Types", () => {
it("should handle JSON requests by default", async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
headers: new Map([["content-type", "application/json"]]),
json: async () => ({ code: 0, data: { result: "success" } }),
})
await client.request("/test", {
method: "POST",
body: { test: "data" },
})
expect(mockFetch).toHaveBeenCalledWith(
"https://api.example.com/test",
expect.objectContaining({
method: "POST",
headers: expect.objectContaining({
"Content-Type": "application/json",
}),
body: JSON.stringify({ test: "data" }),
}),
)
})
it("should handle FormData requests", async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
headers: new Map([["content-type", "application/json"]]),
json: async () => ({ code: 0, data: { result: "success" } }),
})
const formData = new FormData()
formData.append("file", new Blob(["test"]), "test.txt")
await client.request("/upload", {
method: "POST",
body: formData,
requestType: "formData",
})
expect(mockFetch).toHaveBeenCalledWith(
"https://api.example.com/upload",
expect.objectContaining({
method: "POST",
headers: expect.not.objectContaining({
"Content-Type": expect.any(String),
}),
body: formData,
}),
)
})
it("should handle object as FormData", async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
headers: new Map([["content-type", "application/json"]]),
json: async () => ({ code: 0, data: { result: "success" } }),
})
await client.request("/upload", {
method: "POST",
body: { name: "test", value: "123" },
requestType: "formData",
})
expect(mockFetch).toHaveBeenCalledWith(
"https://api.example.com/upload",
expect.objectContaining({
method: "POST",
headers: expect.not.objectContaining({
"Content-Type": expect.any(String),
}),
body: expect.any(FormData),
}),
)
})
it("should handle text requests", async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
headers: new Map([["content-type", "text/plain"]]),
text: async () => "success",
})
await client.request("/text", {
method: "POST",
body: "plain text content",
requestType: "text",
})
expect(mockFetch).toHaveBeenCalledWith(
"https://api.example.com/text",
expect.objectContaining({
method: "POST",
headers: expect.objectContaining({
"Content-Type": "text/plain",
}),
body: "plain text content",
}),
)
})
})
describe("Response Types", () => {
it("should handle JSON responses", async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
headers: new Map([["content-type", "application/json"]]),
json: async () => ({ code: 0, data: { result: "success" } }),
})
const result = await client.request("/test")
expect(result).toEqual({ code: 0, data: { result: "success" } })
})
it("should handle text responses", async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
headers: new Map([["content-type", "text/plain"]]),
text: async () => "plain text response",
})
const result = await client.request("/text")
expect(result).toBe("plain text response")
})
it("should handle blob responses", async () => {
const mockBlob = new Blob(["binary data"])
mockFetch.mockResolvedValueOnce({
ok: true,
headers: new Map([["content-type", "image/png"]]),
blob: async () => mockBlob,
})
const result = await client.request("/image")
expect(result).toBe(mockBlob)
})
it("should handle event stream responses", async () => {
const mockResponse = {
ok: true,
headers: new Map([["content-type", "text/event-stream"]]),
body: new ReadableStream(),
}
mockFetch.mockResolvedValueOnce(mockResponse)
const result = await client.request("/stream")
expect(result).toBe(mockResponse)
})
})
describe("defineRoute with requestType", () => {
it("should define route with requestType", () => {
const route = defineRoute<FormData, { ok: 1 }>("POST", "/upload", {
requestType: "formData",
})
expect(route).toEqual({
method: "POST",
path: "/upload",
params: undefined,
input: undefined,
response: undefined,
requestType: "formData",
})
})
it("should define route with both requestType and responseType", () => {
const route = defineRoute<string, Blob>("POST", "/convert", {
requestType: "text",
})
expect(route).toEqual({
method: "POST",
path: "/convert",
params: undefined,
input: undefined,
response: undefined,
requestType: "text",
})
})
})
describe("Convenience methods", () => {
it("should use postForm for form data", async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
headers: new Map([["content-type", "application/json"]]),
json: async () => ({ code: 0, data: { result: "success" } }),
})
const formData = new FormData()
formData.append("file", new Blob(["test"]), "test.txt")
await client.postForm("/upload", formData)
expect(mockFetch).toHaveBeenCalledWith(
"https://api.example.com/upload",
expect.objectContaining({
method: "POST",
body: formData,
}),
)
})
it("should use getStream for event streams", async () => {
const mockResponse = {
ok: true,
headers: new Map([["content-type", "text/event-stream"]]),
body: new ReadableStream(),
}
mockFetch.mockResolvedValueOnce(mockResponse)
const result = await client.getStream("/events")
expect(result).toBe(mockResponse)
})
})
})