11import { describe , it } from 'node:test' ;
22import assert from 'node:assert/strict' ;
33import { runTutorial } from './run-tutorial.mjs' ;
4- import { assertTutorialSuccess , extractId } from './assertions.mjs' ;
4+ import {
5+ assertTutorialSuccess ,
6+ extractId ,
7+ extractKeyId ,
8+ } from './assertions.mjs' ;
59
610// Accumulated state passed forward as env vars to dependent tutorials.
711const state = { } ;
@@ -24,7 +28,7 @@ describe('Write tutorials (sequential)', { concurrency: 1 }, () => {
2428 / I d e n t i t y r e g i s t e r e d ! / ,
2529 `Expected identity registration output.\nSTDOUT: ${ result . stdout } \nSTDERR: ${ result . stderr } ` ,
2630 ) ;
27- console . log ( result . stdout )
31+ console . log ( result . stdout ) ;
2832 } ) ;
2933
3034 it ( 'identity-retrieve' , { timeout : 120_000 } , async ( ) => {
@@ -85,10 +89,48 @@ describe('Write tutorials (sequential)', { concurrency: 1 }, () => {
8589 expectedPatterns : [ 'Identity updated:' ] ,
8690 errorPatterns : [ 'Something went wrong' ] ,
8791 } ) ;
92+
93+ const keyId = extractKeyId ( result . stdout ) ;
94+ assert . ok ( keyId , `Failed to extract key ID from stdout:\n${ result . stdout } ` ) ;
95+ state . addedKeyId = keyId ;
96+ } ) ;
97+
98+ it ( 'identity-update-disable-key' , { timeout : 120_000 } , async ( ctx ) => {
99+ if ( ! state . addedKeyId ) {
100+ ctx . skip ( 'No KEY_ID (identity-update-add-key must pass first)' ) ;
101+ return ;
102+ }
103+ const result = await runTutorial (
104+ '1-Identities-and-Names/identity-update-disable-key.mjs' ,
105+ {
106+ env : { DISABLE_KEY_ID : state . addedKeyId } ,
107+ timeoutMs : 120_000 ,
108+ } ,
109+ ) ;
110+ assertTutorialSuccess ( result , {
111+ name : 'identity-update-disable-key' ,
112+ expectedPatterns : [ 'Identity updated:' ] ,
113+ errorPatterns : [ 'Something went wrong' ] ,
114+ } ) ;
88115 } ) ;
89116
90- // Skipped: identity-update-disable-key.mjs — KEY_ID = 99 hardcoded
91- // Skipped: name-register.mjs — NAME_LABEL = 'alice' hardcoded
117+ it ( 'name-register' , { timeout : 120_000 } , async ( ) => {
118+ const label = `test-${ Date . now ( ) } -${ Math . random ( )
119+ . toString ( 36 )
120+ . slice ( 2 , 6 ) } `;
121+ const result = await runTutorial (
122+ '1-Identities-and-Names/name-register.mjs' ,
123+ {
124+ env : { NAME_LABEL : label } ,
125+ timeoutMs : 120_000 ,
126+ } ,
127+ ) ;
128+ assertTutorialSuccess ( result , {
129+ name : 'name-register' ,
130+ expectedPatterns : [ 'Name registered:' ] ,
131+ errorPatterns : [ 'Something went wrong' , 'already registered' ] ,
132+ } ) ;
133+ } ) ;
92134
93135 // -----------------------------------------------------------------------
94136 // Phase 2: Contracts
@@ -105,7 +147,10 @@ describe('Write tutorials (sequential)', { concurrency: 1 }, () => {
105147 errorPatterns : [ 'Something went wrong' ] ,
106148 } ) ;
107149 const id = extractId ( result . stdout ) ;
108- assert . ok ( id , `Failed to extract contract ID from stdout:\n${ result . stdout } ` ) ;
150+ assert . ok (
151+ id ,
152+ `Failed to extract contract ID from stdout:\n${ result . stdout } ` ,
153+ ) ;
109154 state . dataContractId = id ;
110155 } ) ;
111156
@@ -155,6 +200,13 @@ describe('Write tutorials (sequential)', { concurrency: 1 }, () => {
155200 expectedPatterns : [ 'Contract registered:' ] ,
156201 errorPatterns : [ 'Something went wrong' ] ,
157202 } ) ;
203+
204+ const id = extractId ( result . stdout ) ;
205+ assert . ok (
206+ id ,
207+ `Failed to extract history contract ID from stdout:\n${ result . stdout } ` ,
208+ ) ;
209+ state . historyContractId = id ;
158210 } ) ;
159211
160212 it ( 'contract-register-nft' , { timeout : 180_000 } , async ( ) => {
@@ -171,7 +223,9 @@ describe('Write tutorials (sequential)', { concurrency: 1 }, () => {
171223
172224 it ( 'contract-update-minimal' , { timeout : 120_000 } , async ( ctx ) => {
173225 if ( ! state . dataContractId ) {
174- ctx . skip ( 'No DATA_CONTRACT_ID (contract-register-minimal must pass first)' ) ;
226+ ctx . skip (
227+ 'No DATA_CONTRACT_ID (contract-register-minimal must pass first)' ,
228+ ) ;
175229 return ;
176230 }
177231 const result = await runTutorial (
@@ -188,13 +242,36 @@ describe('Write tutorials (sequential)', { concurrency: 1 }, () => {
188242 } ) ;
189243 } ) ;
190244
245+ it ( 'contract-update-history' , { timeout : 120_000 } , async ( ctx ) => {
246+ if ( ! state . historyContractId ) {
247+ ctx . skip (
248+ 'No DATA_CONTRACT_ID (contract-register-history must pass first)' ,
249+ ) ;
250+ return ;
251+ }
252+ const result = await runTutorial (
253+ '2-Contracts-and-Documents/contract-update-history.mjs' ,
254+ {
255+ env : { DATA_CONTRACT_ID : state . historyContractId } ,
256+ timeoutMs : 120_000 ,
257+ } ,
258+ ) ;
259+ assertTutorialSuccess ( result , {
260+ name : 'contract-update-history' ,
261+ expectedPatterns : [ 'Contract updated:' ] ,
262+ errorPatterns : [ 'Something went wrong' ] ,
263+ } ) ;
264+ } ) ;
265+
191266 // -----------------------------------------------------------------------
192267 // Phase 3: Documents (depend on contract from Phase 2)
193268 // -----------------------------------------------------------------------
194269
195270 it ( 'document-submit' , { timeout : 120_000 } , async ( ctx ) => {
196271 if ( ! state . dataContractId ) {
197- ctx . skip ( 'No DATA_CONTRACT_ID (contract-register-minimal must pass first)' ) ;
272+ ctx . skip (
273+ 'No DATA_CONTRACT_ID (contract-register-minimal must pass first)' ,
274+ ) ;
198275 return ;
199276 }
200277 const result = await runTutorial (
@@ -211,11 +288,58 @@ describe('Write tutorials (sequential)', { concurrency: 1 }, () => {
211288 } ) ;
212289
213290 const docId = extractId ( result . stdout ) ;
214- assert . ok ( docId , `Failed to extract document ID from stdout:\n${ result . stdout } ` ) ;
291+ assert . ok (
292+ docId ,
293+ `Failed to extract document ID from stdout:\n${ result . stdout } ` ,
294+ ) ;
215295 state . documentId = docId ;
216296 } ) ;
217297
218- // TODO: document-update.mjs and document-delete.mjs need a
219- // `process.env.DOCUMENT_ID ??` prefix before they can be tested here.
220- // Once added, use state.documentId (extracted above) via env var.
298+ it ( 'document-update' , { timeout : 120_000 } , async ( ctx ) => {
299+ if ( ! state . dataContractId || ! state . documentId ) {
300+ ctx . skip (
301+ 'No DATA_CONTRACT_ID or DOCUMENT_ID (earlier tests must pass first)' ,
302+ ) ;
303+ return ;
304+ }
305+ const result = await runTutorial (
306+ '2-Contracts-and-Documents/document-update.mjs' ,
307+ {
308+ env : {
309+ DATA_CONTRACT_ID : state . dataContractId ,
310+ DOCUMENT_ID : state . documentId ,
311+ } ,
312+ timeoutMs : 120_000 ,
313+ } ,
314+ ) ;
315+ assertTutorialSuccess ( result , {
316+ name : 'document-update' ,
317+ expectedPatterns : [ 'Document updated:' ] ,
318+ errorPatterns : [ 'Something went wrong' ] ,
319+ } ) ;
320+ } ) ;
321+
322+ it ( 'document-delete' , { timeout : 120_000 } , async ( ctx ) => {
323+ if ( ! state . dataContractId || ! state . documentId ) {
324+ ctx . skip (
325+ 'No DATA_CONTRACT_ID or DOCUMENT_ID (earlier tests must pass first)' ,
326+ ) ;
327+ return ;
328+ }
329+ const result = await runTutorial (
330+ '2-Contracts-and-Documents/document-delete.mjs' ,
331+ {
332+ env : {
333+ DATA_CONTRACT_ID : state . dataContractId ,
334+ DOCUMENT_ID : state . documentId ,
335+ } ,
336+ timeoutMs : 120_000 ,
337+ } ,
338+ ) ;
339+ assertTutorialSuccess ( result , {
340+ name : 'document-delete' ,
341+ expectedPatterns : [ 'Document deleted successfully' ] ,
342+ errorPatterns : [ 'Something went wrong' ] ,
343+ } ) ;
344+ } ) ;
221345} ) ;
0 commit comments