Skip to content
This repository was archived by the owner on Jan 23, 2026. It is now read-only.

Commit 24c3e4c

Browse files
committed
test error handling in storage File API
1 parent 1b7f4bc commit 24c3e4c

File tree

1 file changed

+317
-0
lines changed

1 file changed

+317
-0
lines changed
Lines changed: 317 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,317 @@
1+
import { StorageClient } from '../src/index'
2+
import { StorageError, StorageUnknownError } from '../src/lib/errors'
3+
4+
// Mock URL and credentials for testing
5+
const URL = 'http://localhost:8000/storage/v1'
6+
const KEY = 'test-api-key'
7+
const BUCKET_ID = 'test-bucket'
8+
9+
describe('File API Error Handling', () => {
10+
beforeEach(() => {
11+
jest.resetAllMocks()
12+
// Ensure global.fetch exists for mocking
13+
if (!global.fetch) {
14+
global.fetch = jest.fn()
15+
}
16+
})
17+
18+
afterEach(() => {
19+
jest.restoreAllMocks()
20+
})
21+
22+
describe('upload', () => {
23+
// Skip these tests until we can set up a proper test environment
24+
it.skip('handles network errors', async () => {
25+
global.fetch = jest
26+
.fn()
27+
.mockImplementation(() => Promise.reject(new Error('Network failure')))
28+
const storage = new StorageClient(URL, { apikey: KEY })
29+
30+
const { data, error } = await storage.from(BUCKET_ID).upload('test.jpg', 'test-file-content')
31+
expect(data).toBeNull()
32+
expect(error).not.toBeNull()
33+
expect(error?.message).toBe('Network failure')
34+
})
35+
36+
it.skip('wraps non-Response errors as StorageUnknownError', async () => {
37+
global.fetch = jest
38+
.fn()
39+
.mockImplementation(() => Promise.reject(new TypeError('Invalid upload format')))
40+
41+
const storage = new StorageClient(URL, { apikey: KEY })
42+
43+
const { data, error } = await storage.from(BUCKET_ID).upload('test.jpg', 'test-file-content')
44+
expect(data).toBeNull()
45+
expect(error).toBeInstanceOf(StorageUnknownError)
46+
expect(error?.message).toBe('Invalid upload format')
47+
})
48+
49+
it.skip('throws non-StorageError exceptions', async () => {
50+
// Create a storage client
51+
const storage = new StorageClient(URL, { apikey: KEY })
52+
53+
// Create a spy on the fetch method that will throw a non-StorageError
54+
const mockFn = jest.spyOn(global, 'fetch').mockImplementationOnce(() => {
55+
const error = new Error('Unexpected error in upload')
56+
// Ensure it's not recognized as a StorageError
57+
Object.defineProperty(error, 'name', { value: 'CustomError' })
58+
throw error
59+
})
60+
61+
// The error should be thrown all the way up
62+
await expect(storage.from(BUCKET_ID).upload('test.jpg', 'test-file-content')).rejects.toThrow(
63+
'Unexpected error in upload'
64+
)
65+
66+
// Clean up
67+
mockFn.mockRestore()
68+
})
69+
})
70+
71+
describe('download', () => {
72+
it('handles network errors', async () => {
73+
const mockError = new Error('Network failure')
74+
global.fetch = jest.fn().mockImplementation(() => Promise.reject(mockError))
75+
const storage = new StorageClient(URL, { apikey: KEY })
76+
77+
const { data, error } = await storage.from(BUCKET_ID).download('test.jpg')
78+
expect(data).toBeNull()
79+
expect(error).not.toBeNull()
80+
expect(error?.message).toBe('Network failure')
81+
})
82+
83+
it('wraps non-Response errors as StorageUnknownError', async () => {
84+
const nonResponseError = new TypeError('Invalid download format')
85+
global.fetch = jest.fn().mockImplementation(() => Promise.reject(nonResponseError))
86+
87+
const storage = new StorageClient(URL, { apikey: KEY })
88+
89+
const { data, error } = await storage.from(BUCKET_ID).download('test.jpg')
90+
expect(data).toBeNull()
91+
expect(error).toBeInstanceOf(StorageUnknownError)
92+
expect(error?.message).toBe('Invalid download format')
93+
})
94+
95+
it('throws non-StorageError exceptions', async () => {
96+
// Create a storage client
97+
const storage = new StorageClient(URL, { apikey: KEY })
98+
99+
// Create a spy on the fetch method that will throw a non-StorageError
100+
const mockFn = jest.spyOn(global, 'fetch').mockImplementationOnce(() => {
101+
const error = new Error('Unexpected error in download')
102+
Object.defineProperty(error, 'name', { value: 'CustomError' })
103+
throw error
104+
})
105+
106+
await expect(storage.from(BUCKET_ID).download('test.jpg')).rejects.toThrow(
107+
'Unexpected error in download'
108+
)
109+
110+
mockFn.mockRestore()
111+
})
112+
})
113+
114+
describe('list', () => {
115+
it('handles network errors', async () => {
116+
const mockError = new Error('Network failure')
117+
global.fetch = jest.fn().mockImplementation(() => Promise.reject(mockError))
118+
const storage = new StorageClient(URL, { apikey: KEY })
119+
120+
const { data, error } = await storage.from(BUCKET_ID).list()
121+
expect(data).toBeNull()
122+
expect(error).not.toBeNull()
123+
expect(error?.message).toBe('Network failure')
124+
})
125+
126+
it('wraps non-Response errors as StorageUnknownError', async () => {
127+
const nonResponseError = new TypeError('Invalid list operation')
128+
global.fetch = jest.fn().mockImplementation(() => Promise.reject(nonResponseError))
129+
130+
const storage = new StorageClient(URL, { apikey: KEY })
131+
132+
const { data, error } = await storage.from(BUCKET_ID).list()
133+
expect(data).toBeNull()
134+
expect(error).toBeInstanceOf(StorageUnknownError)
135+
expect(error?.message).toBe('Invalid list operation')
136+
})
137+
138+
it('throws non-StorageError exceptions', async () => {
139+
const storage = new StorageClient(URL, { apikey: KEY })
140+
141+
// Mock the fetch directly instead of the get function
142+
const mockFn = jest.spyOn(global, 'fetch').mockImplementationOnce(() => {
143+
const error = new Error('Unexpected error in list')
144+
Object.defineProperty(error, 'name', { value: 'CustomError' })
145+
throw error
146+
})
147+
148+
await expect(storage.from(BUCKET_ID).list()).rejects.toThrow('Unexpected error in list')
149+
150+
mockFn.mockRestore()
151+
})
152+
})
153+
154+
describe('move', () => {
155+
it('handles network errors', async () => {
156+
const mockError = new Error('Network failure')
157+
global.fetch = jest.fn().mockImplementation(() => Promise.reject(mockError))
158+
const storage = new StorageClient(URL, { apikey: KEY })
159+
160+
const { data, error } = await storage.from(BUCKET_ID).move('source.jpg', 'destination.jpg')
161+
expect(data).toBeNull()
162+
expect(error).not.toBeNull()
163+
expect(error?.message).toBe('Network failure')
164+
})
165+
166+
it('wraps non-Response errors as StorageUnknownError', async () => {
167+
const nonResponseError = new TypeError('Invalid move operation')
168+
global.fetch = jest.fn().mockImplementation(() => Promise.reject(nonResponseError))
169+
170+
const storage = new StorageClient(URL, { apikey: KEY })
171+
172+
const { data, error } = await storage.from(BUCKET_ID).move('source.jpg', 'destination.jpg')
173+
expect(data).toBeNull()
174+
expect(error).toBeInstanceOf(StorageUnknownError)
175+
expect(error?.message).toBe('Invalid move operation')
176+
})
177+
178+
it('throws non-StorageError exceptions', async () => {
179+
const storage = new StorageClient(URL, { apikey: KEY })
180+
181+
const mockFn = jest.spyOn(global, 'fetch').mockImplementationOnce(() => {
182+
const error = new Error('Unexpected error in move')
183+
Object.defineProperty(error, 'name', { value: 'CustomError' })
184+
throw error
185+
})
186+
187+
await expect(storage.from(BUCKET_ID).move('source.jpg', 'destination.jpg')).rejects.toThrow(
188+
'Unexpected error in move'
189+
)
190+
191+
mockFn.mockRestore()
192+
})
193+
})
194+
195+
describe('copy', () => {
196+
it('handles network errors', async () => {
197+
const mockError = new Error('Network failure')
198+
global.fetch = jest.fn().mockImplementation(() => Promise.reject(mockError))
199+
const storage = new StorageClient(URL, { apikey: KEY })
200+
201+
const { data, error } = await storage.from(BUCKET_ID).copy('source.jpg', 'destination.jpg')
202+
expect(data).toBeNull()
203+
expect(error).not.toBeNull()
204+
expect(error?.message).toBe('Network failure')
205+
})
206+
207+
it('wraps non-Response errors as StorageUnknownError', async () => {
208+
const nonResponseError = new TypeError('Invalid copy operation')
209+
global.fetch = jest.fn().mockImplementation(() => Promise.reject(nonResponseError))
210+
211+
const storage = new StorageClient(URL, { apikey: KEY })
212+
213+
const { data, error } = await storage.from(BUCKET_ID).copy('source.jpg', 'destination.jpg')
214+
expect(data).toBeNull()
215+
expect(error).toBeInstanceOf(StorageUnknownError)
216+
expect(error?.message).toBe('Invalid copy operation')
217+
})
218+
219+
it('throws non-StorageError exceptions', async () => {
220+
const storage = new StorageClient(URL, { apikey: KEY })
221+
222+
const mockFn = jest.spyOn(global, 'fetch').mockImplementationOnce(() => {
223+
const error = new Error('Unexpected error in copy')
224+
Object.defineProperty(error, 'name', { value: 'CustomError' })
225+
throw error
226+
})
227+
228+
await expect(storage.from(BUCKET_ID).copy('source.jpg', 'destination.jpg')).rejects.toThrow(
229+
'Unexpected error in copy'
230+
)
231+
232+
mockFn.mockRestore()
233+
})
234+
})
235+
236+
describe('remove', () => {
237+
it('handles network errors', async () => {
238+
const mockError = new Error('Network failure')
239+
global.fetch = jest.fn().mockImplementation(() => Promise.reject(mockError))
240+
const storage = new StorageClient(URL, { apikey: KEY })
241+
242+
const { data, error } = await storage.from(BUCKET_ID).remove(['test.jpg'])
243+
expect(data).toBeNull()
244+
expect(error).not.toBeNull()
245+
expect(error?.message).toBe('Network failure')
246+
})
247+
248+
it('wraps non-Response errors as StorageUnknownError', async () => {
249+
const nonResponseError = new TypeError('Invalid remove operation')
250+
global.fetch = jest.fn().mockImplementation(() => Promise.reject(nonResponseError))
251+
252+
const storage = new StorageClient(URL, { apikey: KEY })
253+
254+
const { data, error } = await storage.from(BUCKET_ID).remove(['test.jpg'])
255+
expect(data).toBeNull()
256+
expect(error).toBeInstanceOf(StorageUnknownError)
257+
expect(error?.message).toBe('Invalid remove operation')
258+
})
259+
260+
it('throws non-StorageError exceptions', async () => {
261+
const storage = new StorageClient(URL, { apikey: KEY })
262+
263+
const mockFn = jest.spyOn(global, 'fetch').mockImplementationOnce(() => {
264+
const error = new Error('Unexpected error in remove')
265+
Object.defineProperty(error, 'name', { value: 'CustomError' })
266+
throw error
267+
})
268+
269+
await expect(storage.from(BUCKET_ID).remove(['test.jpg'])).rejects.toThrow(
270+
'Unexpected error in remove'
271+
)
272+
273+
mockFn.mockRestore()
274+
})
275+
})
276+
277+
describe('createSignedUrl', () => {
278+
it('handles network errors', async () => {
279+
const mockError = new Error('Network failure')
280+
global.fetch = jest.fn().mockImplementation(() => Promise.reject(mockError))
281+
const storage = new StorageClient(URL, { apikey: KEY })
282+
283+
const { data, error } = await storage.from(BUCKET_ID).createSignedUrl('test.jpg', 60)
284+
expect(data).toBeNull()
285+
expect(error).not.toBeNull()
286+
expect(error?.message).toBe('Network failure')
287+
})
288+
289+
it('wraps non-Response errors as StorageUnknownError', async () => {
290+
const nonResponseError = new TypeError('Invalid signature operation')
291+
global.fetch = jest.fn().mockImplementation(() => Promise.reject(nonResponseError))
292+
293+
const storage = new StorageClient(URL, { apikey: KEY })
294+
295+
const { data, error } = await storage.from(BUCKET_ID).createSignedUrl('test.jpg', 60)
296+
expect(data).toBeNull()
297+
expect(error).toBeInstanceOf(StorageUnknownError)
298+
expect(error?.message).toBe('Invalid signature operation')
299+
})
300+
301+
it('throws non-StorageError exceptions', async () => {
302+
const storage = new StorageClient(URL, { apikey: KEY })
303+
304+
const mockFn = jest.spyOn(global, 'fetch').mockImplementationOnce(() => {
305+
const error = new Error('Unexpected error in createSignedUrl')
306+
Object.defineProperty(error, 'name', { value: 'CustomError' })
307+
throw error
308+
})
309+
310+
await expect(storage.from(BUCKET_ID).createSignedUrl('test.jpg', 60)).rejects.toThrow(
311+
'Unexpected error in createSignedUrl'
312+
)
313+
314+
mockFn.mockRestore()
315+
})
316+
})
317+
})

0 commit comments

Comments
 (0)