@foundation0/api 1.1.3 → 1.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,130 @@
1
+ import { describe, expect, it } from 'bun:test'
2
+ import { curl } from './curl'
3
+
4
+ describe('api/libs/curl', () => {
5
+ const withServer = async <T>(fn: (baseUrl: string) => Promise<T>): Promise<T> => {
6
+ const server = Bun.serve({
7
+ port: 0,
8
+ fetch: async (req) => {
9
+ const url = new URL(req.url)
10
+
11
+ if (url.pathname === '/hello') {
12
+ return new Response('hello', { headers: { 'x-test': '1' } })
13
+ }
14
+
15
+ if (url.pathname === '/echo') {
16
+ const body = await req.text()
17
+ return Response.json({
18
+ method: req.method,
19
+ body,
20
+ contentType: req.headers.get('content-type'),
21
+ ua: req.headers.get('user-agent'),
22
+ })
23
+ }
24
+
25
+ if (url.pathname === '/redirect') {
26
+ return new Response('nope', { status: 302, headers: { location: '/hello' } })
27
+ }
28
+
29
+ return new Response('not found', { status: 404 })
30
+ },
31
+ })
32
+
33
+ try {
34
+ return await fn(`http://127.0.0.1:${server.port}`)
35
+ } finally {
36
+ server.stop(true)
37
+ }
38
+ }
39
+
40
+ it('fetches a URL and returns body on stdout', async () => {
41
+ await withServer(async (baseUrl) => {
42
+ const result = await curl(`${baseUrl}/hello`)
43
+ expect(result.exitCode).toBe(0)
44
+ expect(result.timedOut).toBe(false)
45
+ expect(result.stdout).toBe('hello')
46
+ expect(result.results?.[0]?.httpCode).toBe(200)
47
+ })
48
+ })
49
+
50
+ it('defaults scheme-less host URLs to http://', async () => {
51
+ await withServer(async (baseUrl) => {
52
+ const url = baseUrl.replace('http://', '')
53
+ const result = await curl(`${url}/hello`)
54
+ expect(result.exitCode).toBe(0)
55
+ expect(result.stdout).toBe('hello')
56
+ })
57
+ })
58
+
59
+ it('supports -i to include response headers', async () => {
60
+ await withServer(async (baseUrl) => {
61
+ const result = await curl('-i', `${baseUrl}/hello`)
62
+ expect(result.exitCode).toBe(0)
63
+ expect(result.stdout).toContain('HTTP/1.1 200')
64
+ expect(result.stdout.toLowerCase()).toContain('x-test: 1')
65
+ expect(result.stdout).toContain('hello')
66
+ })
67
+ })
68
+
69
+ it('supports -d for POST body and defaults method to POST', async () => {
70
+ await withServer(async (baseUrl) => {
71
+ const result = await curl('-d', 'a=1', `${baseUrl}/echo`)
72
+ expect(result.exitCode).toBe(0)
73
+ const payload = JSON.parse(result.stdout)
74
+ expect(payload.method).toBe('POST')
75
+ expect(payload.body).toBe('a=1')
76
+ expect(payload.contentType).toContain('application/x-www-form-urlencoded')
77
+ })
78
+ })
79
+
80
+ it('supports -G with -d to apply data as query params', async () => {
81
+ await withServer(async (baseUrl) => {
82
+ const result = await curl('-G', '-d', 'a=1', `${baseUrl}/hello`)
83
+ expect(result.exitCode).toBe(0)
84
+ expect(result.stdout).toBe('hello')
85
+ })
86
+ })
87
+
88
+ it('supports -L to follow redirects', async () => {
89
+ await withServer(async (baseUrl) => {
90
+ const result = await curl('-L', `${baseUrl}/redirect`)
91
+ expect(result.exitCode).toBe(0)
92
+ expect(result.results?.[0]?.redirectCount).toBe(1)
93
+ expect(result.results?.[0]?.urlEffective).toContain('/hello')
94
+ expect(result.stdout).toBe('hello')
95
+ })
96
+ })
97
+
98
+ it('supports -f to fail on HTTP >= 400 and suppress body', async () => {
99
+ await withServer(async (baseUrl) => {
100
+ const result = await curl('-f', `${baseUrl}/missing`)
101
+ expect(result.exitCode).toBe(22)
102
+ expect(result.stdout).toBe('')
103
+ expect(result.stderr).toContain('returned error')
104
+ })
105
+ })
106
+
107
+ it('supports -w to write out %{http_code}', async () => {
108
+ await withServer(async (baseUrl) => {
109
+ const result = await curl('-w', '%{http_code}', `${baseUrl}/hello`)
110
+ expect(result.exitCode).toBe(0)
111
+ expect(result.stdout).toBe('hello200')
112
+ })
113
+ })
114
+
115
+ it('accepts trailing tool options object without turning it into a curl arg', async () => {
116
+ await withServer(async (baseUrl) => {
117
+ const result = await curl(`${baseUrl}/hello`, { timeoutMs: 10_000 })
118
+ expect(result.exitCode).toBe(0)
119
+ expect(result.args).toEqual([`${baseUrl}/hello`])
120
+ })
121
+ })
122
+
123
+ it('returns usage exit code for unsupported flags', async () => {
124
+ await withServer(async (baseUrl) => {
125
+ const result = await curl('--version', `${baseUrl}/hello`)
126
+ expect(result.exitCode).toBe(2)
127
+ expect(result.stderr).toContain('Unsupported curl option')
128
+ })
129
+ })
130
+ })