@@ -22,7 +22,13 @@ import { visit } from '@codama/visitors-core';
2222import { test } from 'vitest' ;
2323
2424import { getRenderMapVisitor } from '../src' ;
25- import { codeContains , codeDoesNotContain , renderMapContains , renderMapContainsImports } from './_setup' ;
25+ import {
26+ codeContains ,
27+ codeDoesNotContain ,
28+ renderMapContains ,
29+ renderMapContainsImports ,
30+ renderMapDoesNotContain ,
31+ } from './_setup' ;
2632
2733test ( 'it renders instruction accounts that can either be signer or non-signer' , async ( ) => {
2834 // Given the following instruction with a signer or non-signer account.
@@ -417,7 +423,104 @@ test('it renders optional config that can override the program address', async (
417423 // Then we expect an optional config parameter with an optional programAddress field
418424 // And we expect this to be used to override programAddress if it is set
419425 await renderMapContains ( renderMap , 'instructions/myInstruction.ts' , [
420- 'config?: { programAddress?: TProgramAddress }' ,
426+ 'config?: { programAddress?: TProgramAddress; }' ,
421427 'programAddress = config?.programAddress ?? MY_PROGRAM_PROGRAM_ADDRESS' ,
422428 ] ) ;
423429} ) ;
430+
431+ test ( 'it renders instructions with no accounts and no data' , async ( ) => {
432+ // Given the following instruction with no accounts and no arguments.
433+ const node = programNode ( {
434+ instructions : [ instructionNode ( { name : 'myInstruction' } ) ] ,
435+ name : 'myProgram' ,
436+ publicKey : '1111' ,
437+ } ) ;
438+
439+ // When we render it.
440+ const renderMap = visit ( node , getRenderMapVisitor ( ) ) ;
441+
442+ // Then the instruction input type is generated as an empty object.
443+ await renderMapContains ( renderMap , 'instructions/myInstruction.ts' , [ 'export type MyInstructionInput = {};' ] ) ;
444+
445+ // But the instruction function does not use it as an argument.
446+ await renderMapDoesNotContain ( renderMap , 'instructions/myInstruction.ts' , [ 'input: MyInstructionInput' ] ) ;
447+ } ) ;
448+
449+ test ( 'it renders instructions with no accounts but with some omitted data' , async ( ) => {
450+ // Given the following instruction with no accounts but with a discriminator argument.
451+ const node = programNode ( {
452+ instructions : [
453+ instructionNode ( {
454+ arguments : [
455+ instructionArgumentNode ( {
456+ defaultValue : numberValueNode ( 42 ) ,
457+ defaultValueStrategy : 'omitted' ,
458+ name : 'myDiscriminator' ,
459+ type : numberTypeNode ( 'u32' ) ,
460+ } ) ,
461+ ] ,
462+ discriminators : [ fieldDiscriminatorNode ( 'myDiscriminator' ) ] ,
463+ name : 'myInstruction' ,
464+ } ) ,
465+ ] ,
466+ name : 'myProgram' ,
467+ publicKey : '1111' ,
468+ } ) ;
469+
470+ // When we render it.
471+ const renderMap = visit ( node , getRenderMapVisitor ( ) ) ;
472+
473+ // Then the instruction input type is generated as an empty object.
474+ await renderMapContains ( renderMap , 'instructions/myInstruction.ts' , [ 'export type MyInstructionInput = {};' ] ) ;
475+
476+ // But the instruction function does not use it as an argument.
477+ await renderMapDoesNotContain ( renderMap , 'instructions/myInstruction.ts' , [ 'input: MyInstructionInput' ] ) ;
478+ } ) ;
479+
480+ test ( 'it renders instructions with no accounts but with some arguments' , async ( ) => {
481+ // Given the following instruction with no accounts but with a non-omitted argument.
482+ const node = programNode ( {
483+ instructions : [
484+ instructionNode ( {
485+ arguments : [ instructionArgumentNode ( { name : 'myArgument' , type : numberTypeNode ( 'u32' ) } ) ] ,
486+ name : 'myInstruction' ,
487+ } ) ,
488+ ] ,
489+ name : 'myProgram' ,
490+ publicKey : '1111' ,
491+ } ) ;
492+
493+ // When we render it.
494+ const renderMap = visit ( node , getRenderMapVisitor ( ) ) ;
495+
496+ // Then we expect the following input type to be rendered
497+ // and used as an argument of the instruction function.
498+ await renderMapContains ( renderMap , 'instructions/myInstruction.ts' , [
499+ "export type MyInstructionInput = { myArgument: MyInstructionInstructionDataArgs['myArgument']; };" ,
500+ 'input: MyInstructionInput' ,
501+ ] ) ;
502+ } ) ;
503+
504+ test ( 'it renders instructions with no arguments but with some accounts' , async ( ) => {
505+ // Given the following instruction with no arguments but with an account.
506+ const node = programNode ( {
507+ instructions : [
508+ instructionNode ( {
509+ accounts : [ instructionAccountNode ( { isSigner : false , isWritable : false , name : 'myAccount' } ) ] ,
510+ name : 'myInstruction' ,
511+ } ) ,
512+ ] ,
513+ name : 'myProgram' ,
514+ publicKey : '1111' ,
515+ } ) ;
516+
517+ // When we render it.
518+ const renderMap = visit ( node , getRenderMapVisitor ( ) ) ;
519+
520+ // Then we expect the following input type to be rendered
521+ // and used as an argument of the instruction function.
522+ await renderMapContains ( renderMap , 'instructions/myInstruction.ts' , [
523+ 'export type MyInstructionInput <TAccountMyAccount extends string = string> = { myAccount: Address<TAccountMyAccount>; };' ,
524+ 'input: MyInstructionInput<TAccountMyAccount>' ,
525+ ] ) ;
526+ } ) ;
0 commit comments