@@ -245,4 +245,233 @@ describe("solidity - hooks", () => {
245245 } ) ;
246246 } ) ;
247247 } ) ;
248+
249+ describe ( "downloadCompilers" , ( ) => {
250+ useFixtureProject ( "solidity/simple-project" ) ;
251+
252+ it ( "should invoke downloadCompilers hook with compiler configs during build" , async ( ) => {
253+ let capturedConfigs : SolidityCompilerConfig [ ] = [ ] ;
254+ let downloadHookCalled = false ;
255+
256+ const downloadPlugin : HardhatPlugin = {
257+ id : "test-download-compilers-plugin" ,
258+ hookHandlers : {
259+ solidity : async ( ) => ( {
260+ default : async ( ) => {
261+ const handlers : Partial < SolidityHooks > = {
262+ downloadCompilers : async (
263+ _context : HookContext ,
264+ compilerConfigs : SolidityCompilerConfig [ ] ,
265+ _quiet : boolean ,
266+ ) => {
267+ downloadHookCalled = true ;
268+ capturedConfigs = compilerConfigs ;
269+ } ,
270+ } ;
271+
272+ return handlers ;
273+ } ,
274+ } ) ,
275+ } ,
276+ } ;
277+
278+ const hre = await createHardhatRuntimeEnvironment ( {
279+ plugins : [ downloadPlugin ] ,
280+ solidity : "0.8.23" ,
281+ } ) ;
282+
283+ const roots = await hre . solidity . getRootFilePaths ( ) ;
284+ await hre . solidity . build ( roots , {
285+ force : true ,
286+ quiet : true ,
287+ } ) ;
288+
289+ assert . ok (
290+ downloadHookCalled ,
291+ "The downloadCompilers hook should be triggered during build" ,
292+ ) ;
293+ assert . ok (
294+ capturedConfigs . length > 0 ,
295+ "The downloadCompilers hook should receive compiler configs" ,
296+ ) ;
297+ assert . equal (
298+ capturedConfigs [ 0 ] . version ,
299+ "0.8.23" ,
300+ "The compiler config should have the expected version" ,
301+ ) ;
302+ } ) ;
303+
304+ it ( "should pass all compiler configs from all profiles" , async ( ) => {
305+ let capturedConfigs : SolidityCompilerConfig [ ] = [ ] ;
306+
307+ const downloadPlugin : HardhatPlugin = {
308+ id : "test-download-all-configs-plugin" ,
309+ hookHandlers : {
310+ solidity : async ( ) => ( {
311+ default : async ( ) => {
312+ const handlers : Partial < SolidityHooks > = {
313+ downloadCompilers : async (
314+ _context : HookContext ,
315+ compilerConfigs : SolidityCompilerConfig [ ] ,
316+ _quiet : boolean ,
317+ ) => {
318+ capturedConfigs = compilerConfigs ;
319+ } ,
320+ } ;
321+
322+ return handlers ;
323+ } ,
324+ } ) ,
325+ } ,
326+ } ;
327+
328+ const hre = await createHardhatRuntimeEnvironment ( {
329+ plugins : [ downloadPlugin ] ,
330+ solidity : {
331+ compilers : [ { version : "0.8.23" } , { version : "0.8.24" } ] ,
332+ } ,
333+ } ) ;
334+
335+ const roots = await hre . solidity . getRootFilePaths ( ) ;
336+ await hre . solidity . build ( roots , {
337+ force : true ,
338+ quiet : true ,
339+ } ) ;
340+
341+ const versions = capturedConfigs . map ( ( c ) => c . version ) ;
342+ // Both default and production profiles have these compilers
343+ assert . ok ( versions . includes ( "0.8.23" ) , "Should include version 0.8.23" ) ;
344+ assert . ok ( versions . includes ( "0.8.24" ) , "Should include version 0.8.24" ) ;
345+ } ) ;
346+
347+ it ( "should include overrides in compiler configs" , async ( ) => {
348+ let capturedConfigs : SolidityCompilerConfig [ ] = [ ] ;
349+
350+ const downloadPlugin : HardhatPlugin = {
351+ id : "test-download-overrides-plugin" ,
352+ hookHandlers : {
353+ solidity : async ( ) => ( {
354+ default : async ( ) => {
355+ const handlers : Partial < SolidityHooks > = {
356+ downloadCompilers : async (
357+ _context : HookContext ,
358+ compilerConfigs : SolidityCompilerConfig [ ] ,
359+ _quiet : boolean ,
360+ ) => {
361+ capturedConfigs = compilerConfigs ;
362+ } ,
363+ } ;
364+
365+ return handlers ;
366+ } ,
367+ } ) ,
368+ } ,
369+ } ;
370+
371+ const hre = await createHardhatRuntimeEnvironment ( {
372+ plugins : [ downloadPlugin ] ,
373+ solidity : {
374+ compilers : [ { version : "0.8.23" } ] ,
375+ overrides : {
376+ "contracts/Special.sol" : { version : "0.8.24" } ,
377+ } ,
378+ } ,
379+ } ) ;
380+
381+ const roots = await hre . solidity . getRootFilePaths ( ) ;
382+ await hre . solidity . build ( roots , {
383+ force : true ,
384+ quiet : true ,
385+ } ) ;
386+
387+ const versions = capturedConfigs . map ( ( c ) => c . version ) ;
388+ assert . ok (
389+ versions . includes ( "0.8.24" ) ,
390+ "Should include override version 0.8.24" ,
391+ ) ;
392+ } ) ;
393+
394+ it ( "should filter non-solc configs in built-in handler" , async ( ) => {
395+ // The built-in handler should only download solc compilers.
396+ // A non-solc config (type: "solx") should not cause a download failure.
397+ // We verify this by building with a mixed config — if the built-in
398+ // handler tried to download "solx" type, it would fail since there's
399+ // no solx binary to download via the solc downloader.
400+ let capturedConfigs : SolidityCompilerConfig [ ] = [ ] ;
401+
402+ const downloadPlugin : HardhatPlugin = {
403+ id : "test-filter-non-solc-plugin" ,
404+ hookHandlers : {
405+ solidity : async ( ) => ( {
406+ default : async ( ) => {
407+ const handlers : Partial < SolidityHooks > = {
408+ downloadCompilers : async (
409+ _context : HookContext ,
410+ compilerConfigs : SolidityCompilerConfig [ ] ,
411+ _quiet : boolean ,
412+ ) => {
413+ capturedConfigs = compilerConfigs ;
414+ // Don't call next — we handle all downloads here
415+ // to prevent the built-in handler from running
416+ } ,
417+ } ;
418+
419+ return handlers ;
420+ } ,
421+ } ) ,
422+ } ,
423+ } ;
424+
425+ const hre = await createHardhatRuntimeEnvironment ( {
426+ plugins : [ downloadPlugin ] ,
427+ solidity : {
428+ compilers : [
429+ { version : "0.8.23" } ,
430+ { type : "solx" , version : "0.8.23" } ,
431+ ] ,
432+ } ,
433+ } ) ;
434+
435+ const roots = await hre . solidity . getRootFilePaths ( ) ;
436+ await hre . solidity . build ( roots , {
437+ force : true ,
438+ quiet : true ,
439+ } ) ;
440+
441+ // Verify both configs are passed (the hook receives ALL configs)
442+ assert . equal (
443+ capturedConfigs . filter ( ( c ) => c . type === undefined ) . length > 0 ,
444+ true ,
445+ "Should include solc configs (type undefined)" ,
446+ ) ;
447+ assert . equal (
448+ capturedConfigs . filter ( ( c ) => c . type === "solx" ) . length > 0 ,
449+ true ,
450+ "Should include non-solc configs (type solx)" ,
451+ ) ;
452+ } ) ;
453+
454+ it ( "should only download solc compilers in built-in handler" , async ( ) => {
455+ // Build with both solc and non-solc configs.
456+ // The built-in handler uses isSolcConfig() to filter — only solc
457+ // versions should be downloaded. If it tried to download a non-existent
458+ // "solx" version via the solc downloader, the build would fail.
459+ const hre = await createHardhatRuntimeEnvironment ( {
460+ solidity : {
461+ compilers : [
462+ { version : "0.8.23" } ,
463+ { type : "solx" , version : "0.8.23" , path : "/mock/path/to/solx" } ,
464+ ] ,
465+ } ,
466+ } ) ;
467+
468+ const roots = await hre . solidity . getRootFilePaths ( ) ;
469+ // This should NOT throw — the built-in handler should skip the solx
470+ // config and only download solc 0.8.23 (which is cached)
471+ await hre . solidity . build ( roots , {
472+ force : true ,
473+ quiet : true ,
474+ } ) ;
475+ } ) ;
476+ } ) ;
248477} ) ;
0 commit comments