@@ -52,11 +52,47 @@ describe("findFfBinary", () => {
5252 const mocked = { execFileSync : ( ) => "C:\\tools\\ffmpeg.cmd\r\nC:\\tools\\ffmpeg.exe\r\n" } ;
5353 return { ...mocked , default : mocked } ;
5454 } ) ;
55+ vi . doMock ( "node:fs" , ( ) => {
56+ const mocked = {
57+ existsSync : ( candidate : unknown ) => candidate === "C:\\tools\\ffmpeg.exe" ,
58+ accessSync : ( ) => { } ,
59+ constants : { X_OK : 1 } ,
60+ } ;
61+ return { ...mocked , default : mocked } ;
62+ } ) ;
5563 const { findFfBinary } = await importFresh ( ) ;
5664
5765 expect ( findFfBinary ( "ffmpeg" ) ) . toBe ( resolve ( "C:\\tools\\ffmpeg.exe" ) ) ;
5866 } ) ;
5967
68+ it ( "falls back to PATH when Windows where output decodes to a missing path" , async ( ) => {
69+ delete process . env . HYPERFRAMES_FFMPEG_PATH ;
70+ Object . defineProperty ( process , "platform" , { value : "win32" , configurable : true } ) ;
71+ process . env . PATH = "/valid-tools" ;
72+ const execFileSync = vi . fn ( ( ) => "C:\\Users\\��\\ffmpeg.exe\r\n" ) ;
73+ vi . resetModules ( ) ;
74+ vi . doMock ( "node:child_process" , ( ) => ( {
75+ execFileSync,
76+ default : { execFileSync } ,
77+ } ) ) ;
78+ vi . doMock ( "node:fs" , ( ) => {
79+ const mocked = {
80+ existsSync : ( candidate : unknown ) => candidate === "/valid-tools/ffmpeg.exe" ,
81+ accessSync : ( ) => { } ,
82+ constants : { X_OK : 1 } ,
83+ } ;
84+ return { ...mocked , default : mocked } ;
85+ } ) ;
86+ const { findFfBinary } = await importFresh ( ) ;
87+
88+ expect ( findFfBinary ( "ffmpeg" ) ) . toBe ( "/valid-tools/ffmpeg.exe" ) ;
89+ expect ( execFileSync ) . toHaveBeenCalledWith (
90+ "where" ,
91+ [ "ffmpeg" ] ,
92+ expect . objectContaining ( { encoding : "utf-8" } ) ,
93+ ) ;
94+ } ) ;
95+
6096 it ( "falls back to scanning PATH when which/where fails" , async ( ) => {
6197 delete process . env . HYPERFRAMES_FFMPEG_PATH ;
6298 const binDir = mkdtempSync ( join ( tmpdir ( ) , "hyperframes-ffbinaries-" ) ) ;
0 commit comments