@@ -8,13 +8,50 @@ import (
88 "github.com/mendixlabs/mxcli/model"
99 "github.com/mendixlabs/mxcli/sdk/pages"
1010 "go.mongodb.org/mongo-driver/bson"
11+ "go.mongodb.org/mongo-driver/bson/primitive"
1112)
1213
13- // TestPageClientAction_Variable_NonNull verifies that Forms$PageParameterMapping
14- // always includes a non-null Forms$PageVariable in the Variable field (issue #295).
15- // Studio Pro's set_Variable property setter requires a non-null PageVariable and
16- // throws ArgumentNullException when it receives nil.
17- func TestPageClientAction_Variable_NonNull (t * testing.T ) {
14+ // getFormSettings extracts FormSettings from a serialized Forms$FormAction document.
15+ func getFormSettings (t * testing.T , doc bson.D ) bson.D {
16+ t .Helper ()
17+ for _ , e := range doc {
18+ if e .Key == "FormSettings" {
19+ fs , ok := e .Value .(bson.D )
20+ if ! ok {
21+ t .Fatalf ("FormSettings is not bson.D, got %T" , e .Value )
22+ }
23+ return fs
24+ }
25+ }
26+ t .Fatal ("FormSettings not found" )
27+ return nil
28+ }
29+
30+ // getParamMappings extracts ParameterMappings from a FormSettings document.
31+ func getParamMappings (t * testing.T , formSettings bson.D ) primitive.A {
32+ t .Helper ()
33+ for _ , e := range formSettings {
34+ if e .Key == "ParameterMappings" {
35+ arr , ok := e .Value .(primitive.A )
36+ if ! ok {
37+ t .Fatalf ("ParameterMappings is not primitive.A, got %T" , e .Value )
38+ }
39+ return arr
40+ }
41+ }
42+ t .Fatal ("ParameterMappings not found" )
43+ return nil
44+ }
45+
46+ // TestPageClientAction_ParameterMappings_TypeIndicator verifies that
47+ // Forms$FormAction always serializes ParameterMappings as [2] (type indicator
48+ // only, no inline mapping objects), matching Studio Pro's native format.
49+ //
50+ // Studio Pro infers $currentObject from the enclosing widget context at runtime
51+ // rather than reading explicit Forms$PageParameterMapping objects from BSON.
52+ // Using int32(len) as the array's first element produces an invalid type
53+ // indicator that Studio Pro cannot read, causing CE0115 (issue #296).
54+ func TestPageClientAction_ParameterMappings_TypeIndicator (t * testing.T ) {
1855 action := & pages.PageClientAction {
1956 BaseElement : model.BaseElement {ID : "action-id" },
2057 PageName : "AuditTrail.Log_View" ,
@@ -32,75 +69,27 @@ func TestPageClientAction_Variable_NonNull(t *testing.T) {
3269 t .Fatal ("serializeClientAction returned nil" )
3370 }
3471
35- // Navigate to FormSettings.ParameterMappings[1] (index 0 is the count int32)
36- var formSettings bson.D
37- for _ , e := range doc {
38- if e .Key == "FormSettings" {
39- formSettings , _ = e .Value .(bson.D )
40- }
41- }
42- if formSettings == nil {
43- t .Fatal ("FormSettings is nil" )
44- }
45-
46- var paramMappings bson.A
47- for _ , e := range formSettings {
48- if e .Key == "ParameterMappings" {
49- paramMappings , _ = e .Value .(bson.A )
50- }
51- }
52- if len (paramMappings ) < 2 {
53- t .Fatalf ("ParameterMappings: want at least 2 elements (count + mapping), got %d" , len (paramMappings ))
54- }
55-
56- // Element 0 is the int32 count; element 1 is the first mapping
57- mapping , ok := paramMappings [1 ].(bson.D )
58- if ! ok {
59- t .Fatalf ("ParameterMappings[1] is not bson.D, got %T" , paramMappings [1 ])
60- }
61-
62- var bsonType , argument string
63- var variable any
64- for _ , e := range mapping {
65- switch e .Key {
66- case "$Type" :
67- bsonType , _ = e .Value .(string )
68- case "Argument" :
69- argument , _ = e .Value .(string )
70- case "Variable" :
71- variable = e .Value
72- }
73- }
72+ formSettings := getFormSettings (t , doc )
73+ mappings := getParamMappings (t , formSettings )
7474
75- if bsonType != "Forms$PageParameterMapping" {
76- t .Errorf ("$Type = %q, want %q" , bsonType , "Forms$PageParameterMapping" )
77- }
78- if argument != "$currentObject" {
79- t .Errorf ("Argument = %q, want %q" , argument , "$currentObject" )
80- }
81- if variable == nil {
82- t .Fatal ("Variable is nil — Studio Pro requires a non-null Forms$PageVariable (issue #295)" )
75+ // Must be exactly [int32(2)] — type indicator only, no inline objects.
76+ // Studio Pro's reader skips the type indicator (2 or 3) and reads the rest
77+ // as items; any other first-element value is treated as invalid.
78+ if len (mappings ) != 1 {
79+ t .Fatalf ("ParameterMappings: want exactly 1 element (type indicator), got %d" , len (mappings ))
8380 }
84-
85- varDoc , ok := variable .(bson.D )
81+ indicator , ok := mappings [0 ].(int32 )
8682 if ! ok {
87- t .Fatalf ("Variable is not bson.D , got %T" , variable )
83+ t .Fatalf ("ParameterMappings[0] is not int32 , got %T" , mappings [ 0 ] )
8884 }
89-
90- var varType string
91- for _ , e := range varDoc {
92- if e .Key == "$Type" {
93- varType , _ = e .Value .(string )
94- }
95- }
96- if varType != "Forms$PageVariable" {
97- t .Errorf ("Variable.$Type = %q, want %q" , varType , "Forms$PageVariable" )
85+ if indicator != 2 {
86+ t .Errorf ("ParameterMappings type indicator = %d, want 2" , indicator )
9887 }
9988}
10089
101- // TestPageClientAction_NoParams_NoMappings verifies that a PageClientAction
102- // without parameter mappings serializes correctly (no regression) .
103- func TestPageClientAction_NoParams_NoMappings (t * testing.T ) {
90+ // TestPageClientAction_NoParams_TypeIndicator verifies that a PageClientAction
91+ // without parameter mappings still serializes ParameterMappings as [2] .
92+ func TestPageClientAction_NoParams_TypeIndicator (t * testing.T ) {
10493 action := & pages.PageClientAction {
10594 BaseElement : model.BaseElement {ID : "action-id" },
10695 PageName : "Sales.Customer_Overview" ,
@@ -120,58 +109,45 @@ func TestPageClientAction_NoParams_NoMappings(t *testing.T) {
120109 if bsonType != "Forms$FormAction" {
121110 t .Errorf ("$Type = %q, want %q" , bsonType , "Forms$FormAction" )
122111 }
112+
113+ formSettings := getFormSettings (t , doc )
114+ mappings := getParamMappings (t , formSettings )
115+ if len (mappings ) != 1 {
116+ t .Fatalf ("ParameterMappings: want [2], got %v" , mappings )
117+ }
123118}
124119
125- // TestPageClientAction_MultipleParams_AllHaveVariable verifies that each
126- // mapping in a multi-param action has a non-null Variable field.
127- func TestPageClientAction_MultipleParams_AllHaveVariable (t * testing.T ) {
120+ // TestPageClientAction_RequiredFields verifies that Forms$FormAction includes
121+ // all fields required by Studio Pro: NumberOfPagesToClose2, PagesForSpecializations,
122+ // and FormSettings.TitleOverride.
123+ func TestPageClientAction_RequiredFields (t * testing.T ) {
128124 action := & pages.PageClientAction {
129125 BaseElement : model.BaseElement {ID : "action-id" },
130126 PageName : "Sales.Order_Detail" ,
131127 ParameterMappings : []* pages.PageClientParameterMapping {
132- {
133- BaseElement : model.BaseElement {ID : "m1" },
134- ParameterName : "Order" ,
135- Variable : "$Order" ,
136- },
137- {
138- BaseElement : model.BaseElement {ID : "m2" },
139- ParameterName : "Customer" ,
140- Variable : "$Customer" ,
141- },
128+ {ParameterName : "Order" , Variable : "$Order" },
129+ {ParameterName : "Customer" , Variable : "$Customer" },
142130 },
143131 }
144132
145133 doc := serializeClientAction (action )
146134
147- var formSettings bson. D
135+ fields := map [ string ] bool {}
148136 for _ , e := range doc {
149- if e .Key == "FormSettings" {
150- formSettings , _ = e .Value .(bson.D )
137+ fields [e .Key ] = true
138+ }
139+ for _ , required := range []string {"NumberOfPagesToClose2" , "PagesForSpecializations" } {
140+ if ! fields [required ] {
141+ t .Errorf ("Forms$FormAction missing required field %q" , required )
151142 }
152143 }
153144
154- var paramMappings bson.A
145+ formSettings := getFormSettings (t , doc )
146+ fsFields := map [string ]bool {}
155147 for _ , e := range formSettings {
156- if e .Key == "ParameterMappings" {
157- paramMappings , _ = e .Value .(bson.A )
158- }
148+ fsFields [e .Key ] = true
159149 }
160-
161- // Index 0 is the int32 count; indices 1 and 2 are the mappings
162- for i := 1 ; i <= 2 ; i ++ {
163- m , ok := paramMappings [i ].(bson.D )
164- if ! ok {
165- t .Fatalf ("ParameterMappings[%d] is not bson.D" , i )
166- }
167- var varVal any
168- for _ , e := range m {
169- if e .Key == "Variable" {
170- varVal = e .Value
171- }
172- }
173- if varVal == nil {
174- t .Errorf ("ParameterMappings[%d].Variable is nil — must be non-null Forms$PageVariable" , i )
175- }
150+ if ! fsFields ["TitleOverride" ] {
151+ t .Errorf ("FormSettings missing required field %q" , "TitleOverride" )
176152 }
177153}
0 commit comments