@@ -7,6 +7,55 @@ import { Variable } from '@/helpers/variables'
77
88import { simpleSubstitute , VariableInfoMap } from '../RichTextEditor/utils'
99
10+ const FOR_EACH_INPUT_SOURCE = {
11+ M365_EXCEL : 'm365-excel' ,
12+ TILES : 'tiles' ,
13+ STRING_ARRAY : 'string-array' ,
14+ FORMSG_TABLE : 'formsg-table' ,
15+ } as const
16+
17+ const STEP_ID_REGEX =
18+ / s t e p \. [ 0 - 9 a - f ] { 8 } - [ 0 - 9 a - f ] { 4 } - [ 0 - 9 a - f ] { 4 } - [ 0 - 9 a - f ] { 4 } - [ 0 - 9 a - f ] { 12 } / i
19+
20+ type InputSource =
21+ ( typeof FOR_EACH_INPUT_SOURCE ) [ keyof typeof FOR_EACH_INPUT_SOURCE ]
22+
23+ interface TableData {
24+ rows : Array < {
25+ data : Record < string , string | number >
26+ rowId ?: string
27+ } >
28+ columns ?: Array < {
29+ id : string
30+ name : string
31+ value : string
32+ } >
33+ inputSource ?: InputSource
34+ }
35+
36+ const hasInputSource = ( data : unknown ) : data is { inputSource : InputSource } =>
37+ typeof data === 'object' && data !== null && 'inputSource' in data
38+
39+ // Utility function to detect input source from test data
40+ const getInputSource = ( data : unknown ) : InputSource | null => {
41+ if ( typeof data === 'string' ) {
42+ try {
43+ const parsed = JSON . parse ( data )
44+ return hasInputSource ( parsed )
45+ ? parsed . inputSource
46+ : FOR_EACH_INPUT_SOURCE . FORMSG_TABLE
47+ } catch {
48+ return null
49+ }
50+ }
51+
52+ if ( hasInputSource ( data ) ) {
53+ return data . inputSource
54+ }
55+
56+ return null
57+ }
58+
1059// guardrail to not show the test result in the event that the app no longer exists
1160// and users were shown the EmptyFlowStepHeader to "add" a new step.
1261// it should already be handled by the ErrorFlowStepHeader, but just in case
@@ -24,19 +73,19 @@ export function isSameAppAndAppKey(
2473 )
2574}
2675
27- interface TableData {
28- columns ?: { name : string } [ ]
29- rows ?: unknown [ ]
76+ const getTableData = (
77+ data : unknown ,
78+ inputSource ?: InputSource | null ,
79+ ) : TableData => {
80+ if (
81+ inputSource === FOR_EACH_INPUT_SOURCE . FORMSG_TABLE &&
82+ typeof data === 'string'
83+ ) {
84+ return JSON . parse ( data ) as TableData
85+ }
86+ return data as TableData
3087}
3188
32- const STEP_ID_REGEX =
33- / s t e p \. [ 0 - 9 a - f ] { 8 } - [ 0 - 9 a - f ] { 4 } - [ 0 - 9 a - f ] { 4 } - [ 0 - 9 a - f ] { 4 } - [ 0 - 9 a - f ] { 12 } / i
34-
35- const getTableData = ( data : unknown , isFormSgTable : boolean ) : TableData =>
36- isFormSgTable && typeof data === 'string'
37- ? ( JSON . parse ( data as string ) as TableData )
38- : ( data as TableData )
39-
4089const deepCompare = ( a : any , b : any , varInfoMap : VariableInfoMap ) : boolean => {
4190 if ( a === b ) {
4291 return true
@@ -139,69 +188,55 @@ export const matchParamsToDataIn = (
139188 }
140189
141190 const match = String ( paramValue ) . match ( STEP_ID_REGEX )
142- let isFormSgTable = false
143- let searchKey = match ?. [ 0 ]
144-
145- // FormSG dataOut structure is different from our own apps
146- // the individual columns are stored in fields.answerArray,
147- // while the items object is stored as fields.answer
148- if (
149- String ( paramValue ) . includes ( 'fields' ) &&
150- String ( paramValue ) . includes ( 'answer' )
151- ) {
152- searchKey = String ( paramValue ) . replace (
153- / \{ \{ ( .* ) a n s w e r ( .* ) \} \} / ,
154- '$1answerArray.0$2' ,
155- )
156- isFormSgTable = true
157- }
191+ const inputSource = getInputSource ( lastTest )
192+ const isFormSgTable = inputSource === FOR_EACH_INPUT_SOURCE . FORMSG_TABLE
158193
159- if ( ! searchKey ) {
160- return false
161- }
194+ const searchKey = isFormSgTable
195+ ? String ( paramValue ) . replace ( / \{ \{ ( . * ) a n s w e r \} \} / , '$1answerArray.0' )
196+ : match ?. [ 0 ]
162197
163- const tableData = getTableData ( lastTest , isFormSgTable )
164- const varRowsFound = varInfoMap . get (
165- `{{${ searchKey } .rowsFound}}` ,
166- ) ?. testRunValue
167-
168- if (
169- ! isFormSgTable && // form sg table output will not have rowsFound
170- Number ( varRowsFound ) !== Number ( tableData . rows ?. length )
171- ) {
198+ if ( ! searchKey ) {
172199 return false
173200 }
174201
202+ const tableData = getTableData ( lastTest , inputSource )
175203 const lastTestColumns = tableData . columns ?. map ( ( c ) => c . name ) ?? [ ]
176204 const mapKey = isFormSgTable ? searchKey : `${ searchKey } .data`
177205 const varInfo = Array . from ( varInfoMap . entries ( ) )
178206 . filter ( ( [ key ] ) => key . includes ( mapKey ) )
179207 . map ( ( [ , value ] ) => value )
180-
181208 const varColumns = new Set ( varInfo . map ( ( item ) => item . label ) )
182209
183- /**
184- * FormSG table special case:
185- * - FormSG table columns are stored like:
186- * ["Response 6, Row 1 Column 1", "Response 6, Row 1 Column 2", "Response 6, Row 1 Column 3"]
187- *
188- * - Our variables are stored like:
189- * ["Column 1", "Column 2", "Column 3"]
190- *
191- * since there is no safe way to parse the FormSG table columns properly,
192- * we do a best-effort comparison to just check that the columns are present.
193- */
194210 if ( isFormSgTable ) {
211+ /**
212+ * FormSG table special case:
213+ * - FormSG table columns are stored like:
214+ * ["Response 6, Row 1 Col 1", "Response 6, Row 1 Col 2", "Response 6, Row 1 Col 3"]
215+ *
216+ * - Our variables are stored like:
217+ * ["Col 1", "Col 2", "Col 3"]
218+ *
219+ * since there is no safe way to parse the FormSG table columns properly,
220+ * we do a best-effort comparison to just check that the columns are present.
221+ */
195222 if ( tableData . rows ?. length === 0 ) {
196223 return true
197224 }
198225
199226 return lastTestColumns . every ( ( testCol ) =>
200227 Array . from ( varColumns ) . some ( ( varCol ) => varCol . includes ( testCol ) ) ,
201228 )
202- }
229+ } else {
230+ const varRowsFound = varInfoMap . get (
231+ `{{${ searchKey } .rowsFound}}` ,
232+ ) ?. testRunValue
203233
204- return lastTestColumns . every ( ( label ) => varColumns . has ( label ) )
234+ if ( Number ( varRowsFound ) !== Number ( tableData . rows ?. length ) ) {
235+ return false
236+ }
237+
238+ return lastTestColumns . every ( ( label ) => varColumns . has ( label ) )
239+ }
205240 }
206241
207242 // Handle arrays and objects using deep comparison
0 commit comments