@@ -125,6 +125,7 @@ const { readAllowFromStoreMock, upsertPairingRequestMock } = vi.hoisted(() => ({
125125 readAllowFromStoreMock : vi . fn ( async ( ) => [ ] as string [ ] ) ,
126126 upsertPairingRequestMock : vi . fn ( async ( _args : unknown ) => ( { code : "CODE" , created : true } ) ) ,
127127} ) ) ;
128+ const downloadLineMediaMock = vi . hoisted ( ( ) => vi . fn ( ) ) ;
128129
129130vi . mock ( "openclaw/plugin-sdk/conversation-runtime" , ( ) => ( {
130131 resolvePairingIdLabel : ( ) => "lineUserId" ,
@@ -133,9 +134,7 @@ vi.mock("openclaw/plugin-sdk/conversation-runtime", () => ({
133134} ) ) ;
134135
135136vi . mock ( "./download.js" , ( ) => ( {
136- downloadLineMedia : async ( ) => {
137- throw new Error ( "downloadLineMedia should not be called from bot-handlers tests" ) ;
138- } ,
137+ downloadLineMedia : downloadLineMediaMock ,
139138} ) ) ;
140139
141140vi . mock ( "./send.js" , ( ) => ( {
@@ -350,6 +349,10 @@ describe("handleLineWebhookEvents", () => {
350349 readAllowFromStoreMock . mockImplementation ( async ( ) => [ ] as string [ ] ) ;
351350 upsertPairingRequestMock . mockReset ( ) ;
352351 upsertPairingRequestMock . mockImplementation ( async ( ) => ( { code : "CODE" , created : true } ) ) ;
352+ downloadLineMediaMock . mockReset ( ) ;
353+ downloadLineMediaMock . mockImplementation ( async ( ) => {
354+ throw new Error ( "downloadLineMedia should not be called from bot-handlers tests" ) ;
355+ } ) ;
353356 } ) ;
354357 it ( "blocks group messages when groupPolicy is disabled" , async ( ) => {
355358 const processMessage = vi . fn ( ) ;
@@ -1006,6 +1009,48 @@ describe("handleLineWebhookEvents", () => {
10061009 expect ( processMessage ) . toHaveBeenCalledTimes ( 1 ) ;
10071010 } ) ;
10081011
1012+ it ( "forwards LINE file names to media downloads" , async ( ) => {
1013+ const processMessage = vi . fn ( ) ;
1014+ downloadLineMediaMock . mockResolvedValueOnce ( {
1015+ path : "/tmp/line-media/voice-note.m4a" ,
1016+ contentType : "audio/x-m4a" ,
1017+ size : 1234 ,
1018+ } ) ;
1019+ const event = createTestMessageEvent ( {
1020+ message : {
1021+ id : "file-audio-1" ,
1022+ type : "file" ,
1023+ fileName : "voice-note.m4a" ,
1024+ fileSize : 4096 ,
1025+ } as MessageEvent [ "message" ] ,
1026+ source : { type : "user" , userId : "user-file-audio" } ,
1027+ webhookEventId : "evt-file-audio" ,
1028+ } ) ;
1029+
1030+ await handleLineWebhookEvents (
1031+ [ event ] ,
1032+ createLineWebhookTestContext ( {
1033+ processMessage,
1034+ dmPolicy : "open" ,
1035+ } ) ,
1036+ ) ;
1037+
1038+ expect ( downloadLineMediaMock ) . toHaveBeenCalledWith ( "file-audio-1" , "token" , 1 , {
1039+ originalFilename : "voice-note.m4a" ,
1040+ } ) ;
1041+ expect ( buildLineMessageContextMock ) . toHaveBeenCalledWith (
1042+ expect . objectContaining ( {
1043+ allMedia : [
1044+ {
1045+ path : "/tmp/line-media/voice-note.m4a" ,
1046+ contentType : "audio/x-m4a" ,
1047+ } ,
1048+ ] ,
1049+ } ) ,
1050+ ) ;
1051+ expect ( processMessage ) . toHaveBeenCalledTimes ( 1 ) ;
1052+ } ) ;
1053+
10091054 it ( "allows non-text group messages through when requireMention is set (cannot detect mention)" , async ( ) => {
10101055 // Image message -- LINE only carries mention metadata on text messages.
10111056 const event = createTestMessageEvent ( {
0 commit comments