@@ -4,10 +4,12 @@ import * as chain from "../core/chain.js";
44import * as splToken from "@solana/spl-token" ;
55
66// readSkillText joins readSkillMintMetadata (getTokenMetadata) → readCodeIn.
7- vi . mock ( "../core/chain.js" , ( ) => ( {
8- signerAddress : vi . fn ( ) ,
9- readCodeIn : vi . fn ( ) ,
10- } ) ) ;
7+ // Keep the real inscriptionSigOf: the uri→sig extraction IS part of the path
8+ // under test (legacy bare-sig uris and gateway-URL uris must both resolve).
9+ vi . mock ( "../core/chain.js" , async ( importOriginal ) => {
10+ const actual = await importOriginal < typeof import ( "../core/chain.js" ) > ( ) ;
11+ return { ...actual , signerAddress : vi . fn ( ) , readCodeIn : vi . fn ( ) } ;
12+ } ) ;
1113
1214vi . mock ( "./minter.js" , ( ) => ( {
1315 resolveMinter : vi . fn ( ) ,
@@ -20,33 +22,63 @@ vi.mock("@solana/spl-token", async (importOriginal) => {
2022} ) ;
2123
2224const MINT = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPvZeJ" ;
25+ // A realistically-shaped inscription signature (64 raw bytes → 87-88 base58).
26+ const TXID = "4K3z7cWH8QAxd74tK4ErtNv8ZL1k97yrAsm7SQJg4zPRya7DnbsxtmZwEgza4H34Z6QX9ewjqpmospXe3KQahruh" ;
27+
28+ const SKILL_JSON = JSON . stringify ( {
29+ name : "my-skill" ,
30+ description : "d" ,
31+ attributes : [ { trait_type : "category" , value : "ai" } ] ,
32+ skillText : "# SKILL body text" ,
33+ } ) ;
2334
2435describe ( "nft/readSkillText" , ( ) => {
2536 beforeEach ( ( ) => vi . clearAllMocks ( ) ) ;
2637
27- it ( "resolves mint → uri (txid) → skillText in the code-in JSON" , async ( ) => {
38+ it ( "resolves mint → legacy bare-sig uri → skillText in the code-in JSON" , async ( ) => {
2839 vi . mocked ( splToken . getTokenMetadata ) . mockResolvedValue ( {
2940 name : "my-skill" ,
3041 symbol : "MY" ,
31- uri : "txid123" ,
42+ uri : TXID ,
3243 additionalMetadata : [ ] ,
3344 } as any ) ;
3445 // The inscription is the standard NFT JSON; the body is its skillText field.
35- vi . mocked ( chain . readCodeIn ) . mockResolvedValue ( {
36- data : JSON . stringify ( {
37- name : "my-skill" ,
38- description : "d" ,
39- attributes : [ { trait_type : "category" , value : "ai" } ] ,
40- skillText : "# SKILL body text" ,
41- } ) ,
42- metadata : "" ,
43- } ) ;
46+ vi . mocked ( chain . readCodeIn ) . mockResolvedValue ( { data : SKILL_JSON , metadata : "" } ) ;
4447
4548 const text = await readSkillText ( { } as any , MINT ) ;
4649
4750 expect ( text ) . toBe ( "# SKILL body text" ) ;
48- // the uri recovered from the mint is what readCodeIn is asked for
49- expect ( chain . readCodeIn ) . toHaveBeenCalledWith ( "txid123" ) ;
51+ // the sig recovered from the mint uri is what readCodeIn is asked for
52+ expect ( chain . readCodeIn ) . toHaveBeenCalledWith ( TXID ) ;
53+ } ) ;
54+
55+ it ( "resolves a gateway-URL uri by extracting the sig from its last segment" , async ( ) => {
56+ vi . mocked ( splToken . getTokenMetadata ) . mockResolvedValue ( {
57+ name : "my-skill" ,
58+ symbol : "MY" ,
59+ uri : `https://gateway.iqlabs.dev/skill/${ MINT } /${ TXID } ` ,
60+ additionalMetadata : [ ] ,
61+ } as any ) ;
62+ vi . mocked ( chain . readCodeIn ) . mockResolvedValue ( { data : SKILL_JSON , metadata : "" } ) ;
63+
64+ const text = await readSkillText ( { } as any , MINT ) ;
65+
66+ expect ( text ) . toBe ( "# SKILL body text" ) ;
67+ expect ( chain . readCodeIn ) . toHaveBeenCalledWith ( TXID ) ;
68+ } ) ;
69+
70+ it ( "returns null (no on-chain read) when the uri carries no recognisable sig" , async ( ) => {
71+ vi . mocked ( splToken . getTokenMetadata ) . mockResolvedValue ( {
72+ name : "my-skill" ,
73+ symbol : "MY" ,
74+ uri : "txid123" ,
75+ additionalMetadata : [ ] ,
76+ } as any ) ;
77+
78+ const text = await readSkillText ( { } as any , MINT ) ;
79+
80+ expect ( text ) . toBeNull ( ) ;
81+ expect ( chain . readCodeIn ) . not . toHaveBeenCalled ( ) ;
5082 } ) ;
5183
5284 it ( "returns null when the mint has no metadata" , async ( ) => {
0 commit comments