@@ -239,6 +239,12 @@ describe("SubscriptionDashboardSurface", () => {
239239 getItem : vi . fn ( ( ) => null ) ,
240240 setItem : vi . fn ( ) ,
241241 } ) ;
242+ vi . stubGlobal ( "window" , {
243+ location : {
244+ href : "http://localhost/dashboard" ,
245+ origin : "http://localhost" ,
246+ } ,
247+ } ) ;
242248 } ) ;
243249
244250 afterEach ( ( ) => {
@@ -344,8 +350,11 @@ describe("SubscriptionDashboardSurface", () => {
344350 const fetchMock = vi . fn ( async ( ) => ( { ok : true , status : 200 , blob : vi . fn ( async ( ) => blob ) } ) ) ;
345351 const createObjectURL = vi . fn ( ( ) => "blob:subboost-config" ) ;
346352 const revokeObjectURL = vi . fn ( ) ;
353+ class TestURL extends URL { }
354+ TestURL . createObjectURL = createObjectURL ;
355+ TestURL . revokeObjectURL = revokeObjectURL ;
347356 vi . stubGlobal ( "fetch" , fetchMock ) ;
348- vi . stubGlobal ( "URL" , { createObjectURL , revokeObjectURL } ) ;
357+ vi . stubGlobal ( "URL" , TestURL ) ;
349358
350359 renderSurface ( createAdapter ( ) , { 0 : [ subscription ] , 1 : false , 2 : null , 3 : null } ) ;
351360 await mocks . captures . buttons . find ( ( props : any ) => props . title === "下载订阅配置" ) . onClick ( ) ;
@@ -379,6 +388,29 @@ describe("SubscriptionDashboardSurface", () => {
379388 } ) ) ;
380389 } ) ;
381390
391+ it ( "fetches cross-origin subscription links through the current origin for downloads" , async ( ) => {
392+ const dom = stubDocumentActions ( ) ;
393+ const blob = new Blob ( [ "mixed-port: 7890\n" ] , { type : "text/yaml" } ) ;
394+ const fetchMock = vi . fn ( async ( ) => ( { ok : true , status : 200 , blob : vi . fn ( async ( ) => blob ) } ) ) ;
395+ vi . stubGlobal ( "fetch" , fetchMock ) ;
396+ class TestURL extends URL { }
397+ TestURL . createObjectURL = vi . fn ( ( ) => "blob:subboost-config" ) ;
398+ TestURL . revokeObjectURL = vi . fn ( ) ;
399+ vi . stubGlobal ( "URL" , TestURL ) ;
400+
401+ renderSurface ( createAdapter ( ) , {
402+ 0 : [ { ...subscription , subscriptionUrl : "https://ryan-ai.de/api/subscription/token-1?download=1" } ] ,
403+ 1 : false ,
404+ 2 : null ,
405+ 3 : null ,
406+ } ) ;
407+ await mocks . captures . buttons . find ( ( props : any ) => props . title === "下载订阅配置" ) . onClick ( ) ;
408+ await flushPromises ( ) ;
409+
410+ expect ( fetchMock ) . toHaveBeenCalledWith ( "http://localhost/api/subscription/token-1?download=1" ) ;
411+ expect ( dom . anchor . download ) . toBe ( "Primary.yaml" ) ;
412+ } ) ;
413+
382414 it ( "guards cancelled delete and in-flight refresh failures" , async ( ) => {
383415 const adapter = createAdapter ( { refreshSubscription : vi . fn ( async ( ) => { throw new Error ( "refresh failed" ) ; } ) } ) ;
384416 renderSurface ( adapter , { 0 : [ subscription ] , 1 : false , 2 : null , 3 : "sub-1" } ) ;
0 commit comments