1- import { describe , expect , it } from "vitest" ;
1+ import { afterEach , describe , expect , it , vi } from "vitest" ;
22
33import { ipxHttpStorage } from "../../src/storage/http.ts" ;
44
55describe ( "http" , ( ) => {
6+ afterEach ( ( ) => {
7+ vi . unstubAllGlobals ( ) ;
8+ } ) ;
9+
610 describe ( "getMeta" , ( ) => {
711 const storage = ipxHttpStorage ( { } ) ;
812 const sut = storage . getMeta ;
@@ -17,4 +21,77 @@ describe("http", () => {
1721 ) ;
1822 } ) ;
1923 } ) ;
24+
25+ describe ( "validateId" , ( ) => {
26+ const storage = ipxHttpStorage ( { domains : [ "example.com" ] } ) ;
27+
28+ it ( "unparseable id throws a 400 HTTPError" , async ( ) => {
29+ await expect ( storage . getData ( "not-a-url" ) ) . rejects . toMatchObject ( {
30+ statusCode : 400 ,
31+ statusText : "IPX_INVALID_URL" ,
32+ message : expect . stringContaining ( "not-a-url" ) ,
33+ } ) ;
34+ } ) ;
35+
36+ it ( "missing hostname throws a 403 HTTPError" , async ( ) => {
37+ await expect ( storage . getData ( "file://" ) ) . rejects . toMatchObject ( {
38+ statusCode : 403 ,
39+ statusText : "IPX_MISSING_HOSTNAME" ,
40+ } ) ;
41+ } ) ;
42+
43+ it ( "forbidden host throws a 403 HTTPError" , async ( ) => {
44+ await expect (
45+ storage . getData ( "https://not-example.com/image.png" ) ,
46+ ) . rejects . toMatchObject ( {
47+ statusCode : 403 ,
48+ statusText : "IPX_FORBIDDEN_HOST" ,
49+ } ) ;
50+ } ) ;
51+
52+ it ( "malformed percent-encoding is not a URIError (forbidden host)" , async ( ) => {
53+ await expect (
54+ storage . getData ( "https://not-example.com/100%.jpg" ) ,
55+ ) . rejects . toMatchObject ( {
56+ statusCode : 403 ,
57+ statusText : "IPX_FORBIDDEN_HOST" ,
58+ } ) ;
59+ } ) ;
60+
61+ it ( "malformed percent-encoding is fetched as-is for allowed hosts" , async ( ) => {
62+ const fetch = vi
63+ . fn ( )
64+ . mockResolvedValue ( new Response ( new Uint8Array ( [ 1 , 2 , 3 ] ) ) ) ;
65+ vi . stubGlobal ( "fetch" , fetch ) ;
66+
67+ await expect (
68+ storage . getData ( "https://example.com/100%.jpg" ) ,
69+ ) . resolves . toBeInstanceOf ( ArrayBuffer ) ;
70+
71+ expect ( fetch ) . toHaveBeenCalledWith (
72+ "https://example.com/100%.jpg" ,
73+ expect . anything ( ) ,
74+ ) ;
75+ } ) ;
76+
77+ it ( "encoded ids are decoded (direct storage usage)" , async ( ) => {
78+ const fetch = vi
79+ . fn ( )
80+ . mockResolvedValue ( new Response ( new Uint8Array ( [ 1 , 2 , 3 ] ) ) ) ;
81+ vi . stubGlobal ( "fetch" , fetch ) ;
82+
83+ await storage . getData ( "https%3A%2F%2Fexample.com%2Fimage.png" ) ;
84+ expect ( fetch ) . toHaveBeenCalledWith (
85+ "https://example.com/image.png" ,
86+ expect . anything ( ) ,
87+ ) ;
88+ } ) ;
89+
90+ it ( "getMeta propagates HTTPError for invalid ids" , async ( ) => {
91+ await expect ( storage . getMeta ( "not-a-url" ) ) . rejects . toMatchObject ( {
92+ statusCode : 400 ,
93+ statusText : "IPX_INVALID_URL" ,
94+ } ) ;
95+ } ) ;
96+ } ) ;
2097} ) ;
0 commit comments