1- import { CodyHook , Node , NodeType } from "@proophboard/cody-types" ;
2- import { parseJsonMetadata } from "@proophboard/cody-utils" ;
3- import { Context } from "./context" ;
4- import { getOriginalNode } from "./utils/get-original-node" ;
5- import { names } from "@event-engine/messaging/helpers" ;
6- import { formatFiles , generateFiles } from "@nx/devkit" ;
7- import { CodyResponseException , withErrorCheck } from "./utils/error-handling" ;
8- import { detectService } from "./utils/detect-service" ;
1+ import { CodyHook , CodyResponseType , Node , NodeType } from "@proophboard/cody-types" ;
2+ import { getSingleTarget , isCodyError , parseJsonMetadata } from "@proophboard/cody-utils" ;
3+ import { Context } from "./context" ;
4+ import { getOriginalNode } from "./utils/get-original-node" ;
5+ import { names } from "@event-engine/messaging/helpers" ;
6+ import { formatFiles , generateFiles } from "@nx/devkit" ;
7+ import { CodyResponseException , withErrorCheck } from "./utils/error-handling" ;
8+ import { detectService } from "./utils/detect-service" ;
99import { flushChanges } from "nx/src/generators/tree" ;
1010import { listChangesForCodyResponse } from "./utils/fs-tree" ;
11+ import { getNodeFromSyncedNodes } from "@cody-engine/cody/hooks/utils/node-tree" ;
12+ import { findAggregateState } from "@cody-engine/cody/hooks/utils/aggregate/find-aggregate-state" ;
13+ import { getVoMetadata } from "@cody-engine/cody/hooks/utils/value-object/get-vo-metadata" ;
1114
1215const modeKey = "mode" ;
1316const modeValueTest = "test-scenario" ;
@@ -18,10 +21,16 @@ const thenKey = "then";
1821export const onFeature : CodyHook < Context > = async ( feature : Node , ctx : Context ) => {
1922 try {
2023 feature = getOriginalNode ( feature , ctx ) ;
21- const featureMeta : any = feature ?. getMetadata ( ) ? parseJsonMetadata < { service ?: string } > ( feature ) : { } ;
24+ const featureMeta : any = feature ?. getMetadata ( ) ? parseJsonMetadata < { service ?: string , mode ?: string } > ( feature ) : { } ;
2225 const parentContainer = feature . getParent ( ) ;
2326 const parentContainerMeta : any = parentContainer ?. getMetadata ( ) ? parseJsonMetadata < { service ?: string } > ( parentContainer ) : { } ;
2427
28+ if ( featureMeta [ modeKey ] != modeValueTest && parentContainerMeta [ modeKey ] != modeValueTest ) {
29+ return {
30+ cody : "Feature code generation is not yet implemented" ,
31+ }
32+ }
33+
2534 // add all test nodes to a map with their ID as the key, for easy access
2635 const validTestNodes = [ NodeType . command , NodeType . event ] ;
2736 const testNodesMap = new Map < any , Node > ( ) ;
@@ -31,67 +40,64 @@ export const onFeature: CodyHook<Context> = async (feature: Node, ctx: Context)
3140 }
3241 } ) ;
3342
34- // check if either the feature (the test) or its bounded context (the test container) have their mode set to "test"
35- if ( featureMeta [ modeKey ] == modeValueTest || parentContainerMeta [ modeKey ] == modeValueTest ) {
36-
37- let whenCommand : Node | undefined ;
38-
39- // find "when" command node
40- feature . getChildren ( ) . forEach ( function ( elem ) {
41- if ( elem . getType ( ) == NodeType . command ) {
42- whenCommand = elem ;
43- }
44- } ) ;
45-
46- if ( whenCommand ) {
47- const givenNodes : Array < Node > = [ ] ;
48- const thenNodes : Array < Node > = [ ] ;
49- let currentNode : Node | undefined = whenCommand ;
50-
51- // everything before the "when" command node is seen as "given"
52- while ( currentNode ) {
53- currentNode = testNodesMap . get ( currentNode . getSources ( ) . first ( ) ?. getId ( ) ) || undefined ;
54-
55- if ( currentNode ) {
56- givenNodes . unshift ( currentNode ) ;
57- }
58- }
59-
60- // everything after the "when" command is "then"
61- currentNode = whenCommand ;
62- while ( currentNode ) {
63- currentNode = testNodesMap . get ( currentNode . getTargets ( ) . first ( ) ?. getId ( ) ) || undefined ;
64-
65- if ( currentNode ) {
66- thenNodes . push ( currentNode ) ;
67- }
68- }
69-
70- const changesForCodyResponse = await createTestFiles ( feature . getName ( ) , featureMeta , givenNodes , whenCommand , thenNodes , ctx ) ;
71-
72- // for logging:
73- const loggedNodes : Array < string > = [ ] ;
74- loggedNodes . push ( "GIVEN" ) ;
75- givenNodes . forEach ( function ( node ) {
76- loggedNodes . push ( node . getName ( ) ) ;
77- } ) ;
78- loggedNodes . push ( "WHEN" ) ;
79- loggedNodes . push ( whenCommand . getName ( ) ) ;
80- loggedNodes . push ( "THEN" ) ;
81- thenNodes . forEach ( function ( node ) {
82- //@ToDo extract and slice expectedIdentifier
83- loggedNodes . push ( node . getName ( ) ) ;
84- } ) ;
85-
86- return {
87- cody : `Running test called "${ feature . getName ( ) . trim ( ) } ".\nThese are the nodes included in the test: ${ loggedNodes . toString ( ) } ` ,
88- details : changesForCodyResponse
89- }
43+ let whenCommand : Node | undefined ;
44+
45+ // find "when" command node
46+ feature . getChildren ( ) . forEach ( function ( elem ) {
47+ if ( elem . getType ( ) == NodeType . command ) {
48+ whenCommand = elem ;
49+ }
50+ } ) ;
51+
52+ if ( ! whenCommand ) {
53+
54+ return {
55+ cody : "Feature code generation is not yet implemented" ,
56+ }
57+ }
58+
59+ const givenNodes : Array < Node > = [ ] ;
60+ const thenNodes : Array < Node > = [ ] ;
61+ let currentNode : Node | undefined = whenCommand ;
62+
63+ // everything before the "when" command node is seen as "given"
64+ while ( currentNode ) {
65+ currentNode = testNodesMap . get ( currentNode . getSources ( ) . first ( ) ?. getId ( ) ) || undefined ;
66+
67+ if ( currentNode ) {
68+ givenNodes . unshift ( currentNode ) ;
69+ }
70+ }
71+
72+ // everything after the "when" command is "then"
73+ currentNode = whenCommand ;
74+ while ( currentNode ) {
75+ currentNode = testNodesMap . get ( currentNode . getTargets ( ) . first ( ) ?. getId ( ) ) || undefined ;
76+
77+ if ( currentNode ) {
78+ thenNodes . push ( currentNode ) ;
9079 }
9180 }
9281
82+ const changesForCodyResponse = await createTestFiles ( feature . getName ( ) , featureMeta , givenNodes , whenCommand , thenNodes , ctx ) ;
83+
84+ // for logging:
85+ const loggedNodes : Array < string > = [ ] ;
86+ loggedNodes . push ( "GIVEN" ) ;
87+ givenNodes . forEach ( function ( node ) {
88+ loggedNodes . push ( node . getName ( ) ) ;
89+ } ) ;
90+ loggedNodes . push ( "WHEN" ) ;
91+ loggedNodes . push ( whenCommand . getName ( ) ) ;
92+ loggedNodes . push ( "THEN" ) ;
93+ thenNodes . forEach ( function ( node ) {
94+ //@ToDo extract and slice expectedIdentifier
95+ loggedNodes . push ( node . getName ( ) ) ;
96+ } ) ;
97+
9398 return {
94- cody : "Feature code generation is not yet implemented" ,
99+ cody : `Running test called "${ feature . getName ( ) . trim ( ) } ".\nThese are the nodes included in the test: ${ loggedNodes . toString ( ) } ` ,
100+ details : changesForCodyResponse
95101 }
96102 } catch ( e ) {
97103 if ( e instanceof CodyResponseException ) {
@@ -106,7 +112,39 @@ async function createTestFiles(featureName: string, featureMeta: any, givenNodes
106112 // if using a service from another board (e.g. Fleet Management), make sure to set this up in the test feature's metadata!
107113 const service = withErrorCheck ( detectService , [ whenCommand , ctx ] ) ;
108114
109- const aggregate = 'car' ;
115+ let aggregate : Node | undefined ;
116+ for ( const [ , syncedNode ] of ctx . syncedNodes ) {
117+ if ( syncedNode . getType ( ) === NodeType . command && syncedNode . getName ( ) === whenCommand . getName ( )
118+ && syncedNode . getTags ( ) . contains ( 'pb:connected' ) ) {
119+ const aggregateObj = getSingleTarget ( syncedNode , NodeType . aggregate ) ;
120+
121+ if ( ! isCodyError ( aggregateObj ) ) {
122+ aggregate = aggregateObj ;
123+ break ;
124+ }
125+ }
126+ }
127+
128+ if ( ! aggregate ) {
129+ throw new CodyResponseException ( {
130+ cody : 'Could not find aggregate for test generation.' ,
131+ type : CodyResponseType . Error
132+ } ) ;
133+ }
134+
135+ const givenNode = givenNodes [ 0 ] ;
136+ const syncedAggregate = withErrorCheck ( getNodeFromSyncedNodes , [ aggregate , ctx . syncedNodes ] ) ;
137+ const aggregateState = withErrorCheck ( findAggregateState , [ syncedAggregate , ctx ] ) ;
138+ const aggregateStateMeta = withErrorCheck ( getVoMetadata , [ aggregateState , ctx ] ) ;
139+ const aggregateStateNames = names ( aggregateState . getName ( ) ) ;
140+
141+ const thenNode = thenNodes [ 0 ] ;
142+ const body = '{' + thenNode . getDescription ( ) . replaceAll ( '\'' , '"' ) + '}' ;
143+ console . log ( 'Json body: ' + body ) ;
144+ const thenNodeDescriptionObject = JSON . parse ( body ) ;
145+
146+ const aggregateIdentifierProperty = aggregateStateMeta . identifier as keyof typeof thenNodeDescriptionObject ;
147+ const givenAggregateMetaType = `${ names ( service ) . className } .${ names ( aggregate . getName ( ) ) . className } ` ;
110148
111149 // TODO: currently only using the first "when" & "then" nodes
112150 const substitutions = {
@@ -117,16 +155,16 @@ async function createTestFiles(featureName: string, featureMeta: any, givenNodes
117155 "given" : featureMeta [ givenKey ] ,
118156 "when" : featureMeta [ whenKey ] ,
119157 "then" : featureMeta [ thenKey ] ,
120- "givenEvent" : names ( givenNodes [ 0 ] . getName ( ) ) ,
158+ "givenEvent" : names ( givenNode . getName ( ) ) ,
159+ "givenAggregateMetaType" : givenAggregateMetaType ,
121160 "whenEvent" : names ( whenCommand . getName ( ) ) ,
122161 "thenEvent" : names ( thenNodes [ 0 ] . getName ( ) ) ,
123- "givenPayload" : givenNodes [ 0 ] . getDescription ( ) ,
162+ "givenPayload" : givenNode . getDescription ( ) ,
124163 "whenPayload" : whenCommand . getDescription ( ) ,
125164 "thenPayload" : thenNodes [ 0 ] . getDescription ( ) ,
126- "aggregate" : aggregate ,
127- "expectedIdentifier" : "6a76bead-46ce-4651-bea0-d8a387b2e9d0" // TODO: read from "then" node payload (convert to json, read & remove "expectedIdentifier", convert back to string)
165+ "aggregate" : names ( aggregate . getName ( ) ) . fileName ,
166+ "expectedIdentifier" : thenNodeDescriptionObject [ aggregateIdentifierProperty ]
128167 }
129- // console.log(substitutions);
130168
131169 // generate test files
132170 const { tree} = ctx ;
0 commit comments