1
1
import type { XFormsElement } from '@getodk/common/test/fixtures/xform-dsl/XFormsElement.ts' ;
2
2
import { xmlElement } from '@getodk/common/test/fixtures/xform-dsl/index.ts' ;
3
3
import type {
4
+ AnyFormInstance ,
4
5
AnyNode ,
5
6
FormResource ,
6
7
MonolithicInstancePayload ,
@@ -19,6 +20,7 @@ import { RankValuesAnswer } from '../answer/RankValuesAnswer.ts';
19
20
import { SelectValuesAnswer } from '../answer/SelectValuesAnswer.ts' ;
20
21
import type { ValueNodeAnswer } from '../answer/ValueNodeAnswer.ts' ;
21
22
import { answerOf } from '../client/answerOf.ts' ;
23
+ import { editInstance } from '../client/editInstance.ts' ;
22
24
import type { InitializableForm , TestFormOptions } from '../client/init.ts' ;
23
25
import { initializeTestForm } from '../client/init.ts' ;
24
26
import { isRepeatRange } from '../client/predicates.ts' ;
@@ -67,14 +69,15 @@ import { JRTreeReference } from './xpath/JRTreeReference.ts';
67
69
*/
68
70
const nonReactiveIdentityStateFactory = < T extends object > ( value : T ) : T => value ;
69
71
70
- export interface ScenarioConstructorOptions {
71
- readonly owner : Owner ;
72
- readonly dispose : VoidFunction ;
72
+ interface ScenarioFormMeta {
73
73
readonly formName : string ;
74
74
readonly formElement : XFormsElement ;
75
75
readonly formOptions : TestFormOptions ;
76
- readonly formResult : InitializableForm ;
77
- readonly instanceRoot : RootNode ;
76
+ }
77
+
78
+ export interface ScenarioConfig extends ScenarioFormMeta {
79
+ readonly owner : Owner ;
80
+ readonly dispose : VoidFunction ;
78
81
}
79
82
80
83
type FormFileName = `${string } .xml`;
@@ -128,7 +131,7 @@ const isAnswerItemCollectionParams = (
128
131
type ScenarioClass = typeof Scenario ;
129
132
130
133
export interface ScenarioConstructor < T extends Scenario = Scenario > extends ScenarioClass {
131
- new ( options : ScenarioConstructorOptions ) : T ;
134
+ new ( meta : ScenarioConfig , form : InitializableForm , instanceRoot : RootNode ) : T ;
132
135
}
133
136
134
137
/**
@@ -171,75 +174,60 @@ export class Scenario {
171
174
this : This ,
172
175
...args : ScenarioStaticInitParameters
173
176
) : Promise < This [ 'prototype' ] > {
174
- let formElement : XFormsElement ;
175
- let formName : string ;
176
- let formOptions : TestFormOptions ;
177
+ let formMeta : ScenarioFormMeta ;
177
178
178
179
if ( isFormFileName ( args [ 0 ] ) ) {
179
180
return this . init ( r ( args [ 0 ] ) ) ;
180
181
} else if ( args . length === 1 ) {
181
182
const [ resource ] = args ;
182
183
183
- formElement = xmlElement ( resource . textContents ) ;
184
- formName = resource . formName ;
185
- formOptions = this . getTestFormOptions ( ) ;
184
+ formMeta = {
185
+ formElement : xmlElement ( resource . textContents ) ,
186
+ formName : resource . formName ,
187
+ formOptions : this . getTestFormOptions ( ) ,
188
+ } ;
186
189
} else {
187
- const [ name , form , overrideOptions ] = args ;
190
+ const [ formName , formElement , overrideOptions ] = args ;
188
191
189
- formName = name ;
190
- formElement = form ;
191
- formOptions = this . getTestFormOptions ( overrideOptions ) ;
192
+ formMeta = {
193
+ formName,
194
+ formElement,
195
+ formOptions : this . getTestFormOptions ( overrideOptions ) ,
196
+ } ;
192
197
}
193
198
194
- const formResource = formElement . asXml ( ) satisfies FormResource ;
195
- const { dispose, owner, formResult, instanceRoot } = await initializeTestForm (
196
- formResource ,
197
- formOptions
199
+ const { dispose, owner, form, instanceRoot } = await initializeTestForm (
200
+ formMeta . formElement . asXml ( ) satisfies FormResource ,
201
+ formMeta . formOptions
198
202
) ;
199
203
200
204
return runInSolidScope ( owner , ( ) => {
201
- return new this ( {
202
- owner ,
203
- dispose ,
204
- formName ,
205
- formElement ,
206
- formOptions ,
207
- formResult ,
208
- instanceRoot,
209
- } ) ;
205
+ return new this (
206
+ {
207
+ ... formMeta ,
208
+ owner ,
209
+ dispose ,
210
+ } ,
211
+ form ,
212
+ instanceRoot
213
+ ) ;
210
214
} ) ;
211
215
}
212
216
213
217
declare readonly [ 'constructor' ] : ScenarioConstructor < this> ;
214
218
215
- private readonly owner : Owner ;
216
- private readonly dispose : VoidFunction ;
217
- private readonly formElement : XFormsElement ;
218
- private readonly formOptions : TestFormOptions ;
219
- private readonly formResult : InitializableForm ;
220
-
221
- readonly formName : string ;
222
- readonly instanceRoot : RootNode ;
223
-
224
219
protected readonly getPositionalEvents : Accessor < PositionalEvents > ;
225
220
226
221
protected readonly getEventPosition : Accessor < number > ;
227
222
private readonly setEventPosition : Setter < number > ;
228
223
229
224
protected readonly getSelectedPositionalEvent : Accessor < AnyPositionalEvent > ;
230
225
231
- protected constructor ( options : ScenarioConstructorOptions ) {
232
- const { owner, dispose, formName, formElement, formOptions, formResult, instanceRoot } =
233
- options ;
234
-
235
- this . owner = owner ;
236
- this . dispose = dispose ;
237
- this . formName = formName ;
238
- this . formElement = formElement ;
239
- this . formOptions = formOptions ;
240
- this . formResult = formResult ;
241
- this . instanceRoot = instanceRoot ;
242
-
226
+ protected constructor (
227
+ private readonly config : ScenarioConfig ,
228
+ private readonly form : InitializableForm ,
229
+ readonly instanceRoot : RootNode
230
+ ) {
243
231
const [ getEventPosition , setEventPosition ] = createSignal ( 0 ) ;
244
232
245
233
this . getPositionalEvents = ( ) => getPositionalEvents ( instanceRoot ) ;
@@ -260,7 +248,7 @@ export class Scenario {
260
248
261
249
afterEach ( ( ) => {
262
250
PositionalEvent . cleanup ( ) ;
263
- dispose ( ) ;
251
+ config . dispose ( ) ;
264
252
} ) ;
265
253
}
266
254
@@ -768,21 +756,7 @@ export class Scenario {
768
756
* will remain) unaffected by those calls.
769
757
*/
770
758
newInstance ( ) : this {
771
- return runInSolidScope ( this . owner , ( ) => {
772
- const { dispose, owner, formName, formElement, formOptions, formResult } = this ;
773
- const instance = formResult . createInstance ( ) ;
774
- const instanceRoot = instance . root ;
775
-
776
- return new this . constructor ( {
777
- owner,
778
- dispose,
779
- formName,
780
- formElement,
781
- formOptions,
782
- formResult,
783
- instanceRoot,
784
- } ) ;
785
- } ) ;
759
+ return this . fork ( this . form . createInstance ( ) ) ;
786
760
}
787
761
788
762
getValidationOutcome ( ) : ValidateOutcome {
@@ -1086,28 +1060,18 @@ export class Scenario {
1086
1060
}
1087
1061
1088
1062
/**
1089
- * @todo We may also want a conceptually equivalent static method, composing
1090
- * `loadForm`/`restoreInstance` behavior.
1063
+ * @todo Naming? The name here was chosen to indicate this creates a "fork" of various aspects of a {@link Scenario} instance (most of which are internal/class-private) with a new {@link RootNode | form instance root} (derived from the current {@link Scenario} instance's {@link })
1091
1064
*/
1092
- async restoreWebFormsInstanceState ( payload : RestoreFormInstanceInput ) : Promise < this> {
1093
- const { dispose, owner, formName, formElement, formOptions, formResult } = this ;
1094
-
1095
- const instance = await runInSolidScope ( owner , ( ) => {
1096
- return this . formResult . restoreInstance ( payload , formOptions ) ;
1065
+ private fork ( instance : AnyFormInstance ) : this {
1066
+ return runInSolidScope ( this . config . owner , ( ) => {
1067
+ return new this . constructor ( this . config , this . form , instance . root ) ;
1097
1068
} ) ;
1098
- const instanceRoot = instance . root ;
1069
+ }
1099
1070
1100
- return runInSolidScope ( owner , ( ) => {
1101
- return new this . constructor ( {
1102
- owner,
1103
- dispose,
1104
- formName,
1105
- formElement,
1106
- formOptions,
1107
- formResult,
1108
- instanceRoot,
1109
- } ) ;
1110
- } ) ;
1071
+ async restoreWebFormsInstanceState ( payload : RestoreFormInstanceInput ) : Promise < this> {
1072
+ const instance = await this . form . restoreInstance ( payload , this . config . formOptions ) ;
1073
+
1074
+ return this . fork ( instance ) ;
1111
1075
}
1112
1076
1113
1077
// TODO: consider adapting tests which use the following interfaces to use
@@ -1186,7 +1150,7 @@ export class Scenario {
1186
1150
expect (
1187
1151
form . asXml ( ) ,
1188
1152
'Attempted to serialize instance with unexpected form XML. Is instance from an unrelated form?'
1189
- ) . toBe ( this . formElement . asXml ( ) ) ;
1153
+ ) . toBe ( this . config . formElement . asXml ( ) ) ;
1190
1154
1191
1155
return this . proposed_serializeAndRestoreInstanceState ( ) ;
1192
1156
}
@@ -1214,6 +1178,13 @@ export class Scenario {
1214
1178
1215
1179
return this . restoreWebFormsInstanceState ( payload ) ;
1216
1180
}
1181
+
1182
+ /** @see {@link editInstance } */
1183
+ async proposed_editCurrentInstanceState ( ) : Promise < this> {
1184
+ const instance = await editInstance ( this . form , this . instanceRoot ) ;
1185
+
1186
+ return this . fork ( instance ) ;
1187
+ }
1217
1188
}
1218
1189
1219
1190
/**
0 commit comments