@auto-engineer/narrative 0.12.1 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +24 -0
- package/dist/src/commands/export-schema-runner.js +1 -1
- package/dist/src/commands/export-schema-runner.js.map +1 -1
- package/dist/src/fluent-builder.js +3 -3
- package/dist/src/fluent-builder.js.map +1 -1
- package/dist/src/getNarratives.specs.js +157 -161
- package/dist/src/getNarratives.specs.js.map +1 -1
- package/dist/src/id/addAutoIds.d.ts.map +1 -1
- package/dist/src/id/addAutoIds.js +23 -10
- package/dist/src/id/addAutoIds.js.map +1 -1
- package/dist/src/id/addAutoIds.specs.js +55 -46
- package/dist/src/id/addAutoIds.specs.js.map +1 -1
- package/dist/src/id/generators.js +1 -1
- package/dist/src/id/generators.js.map +1 -1
- package/dist/src/id/hasAllIds.d.ts.map +1 -1
- package/dist/src/id/hasAllIds.js +8 -3
- package/dist/src/id/hasAllIds.js.map +1 -1
- package/dist/src/id/hasAllIds.specs.js +142 -215
- package/dist/src/id/hasAllIds.specs.js.map +1 -1
- package/dist/src/index.d.ts +7 -8
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/loader/graph.d.ts.map +1 -1
- package/dist/src/loader/graph.js +13 -6
- package/dist/src/loader/graph.js.map +1 -1
- package/dist/src/loader/ts-utils.d.ts +1 -0
- package/dist/src/loader/ts-utils.d.ts.map +1 -1
- package/dist/src/loader/ts-utils.js +95 -16
- package/dist/src/loader/ts-utils.js.map +1 -1
- package/dist/src/model-to-narrative.specs.js +548 -466
- package/dist/src/model-to-narrative.specs.js.map +1 -1
- package/dist/src/narrative-context.d.ts +8 -8
- package/dist/src/narrative-context.d.ts.map +1 -1
- package/dist/src/narrative-context.js +111 -301
- package/dist/src/narrative-context.js.map +1 -1
- package/dist/src/narrative-context.specs.js +15 -55
- package/dist/src/narrative-context.specs.js.map +1 -1
- package/dist/src/narrative.d.ts +19 -22
- package/dist/src/narrative.d.ts.map +1 -1
- package/dist/src/narrative.js +42 -71
- package/dist/src/narrative.js.map +1 -1
- package/dist/src/samples/questionnaires.narrative.js +10 -10
- package/dist/src/samples/questionnaires.narrative.js.map +1 -1
- package/dist/src/samples/test-with-ids.narrative.js +13 -29
- package/dist/src/samples/test-with-ids.narrative.js.map +1 -1
- package/dist/src/schema.d.ts +2704 -8293
- package/dist/src/schema.d.ts.map +1 -1
- package/dist/src/schema.js +26 -47
- package/dist/src/schema.js.map +1 -1
- package/dist/src/slice-builder.js +3 -3
- package/dist/src/slice-builder.js.map +1 -1
- package/dist/src/transformers/model-to-narrative/generators/flow.d.ts.map +1 -1
- package/dist/src/transformers/model-to-narrative/generators/flow.js +118 -74
- package/dist/src/transformers/model-to-narrative/generators/flow.js.map +1 -1
- package/dist/src/transformers/model-to-narrative/generators/gwt.d.ts +9 -1
- package/dist/src/transformers/model-to-narrative/generators/gwt.d.ts.map +1 -1
- package/dist/src/transformers/model-to-narrative/generators/gwt.js +112 -112
- package/dist/src/transformers/model-to-narrative/generators/gwt.js.map +1 -1
- package/dist/src/transformers/model-to-narrative/generators/imports.d.ts +1 -1
- package/dist/src/transformers/model-to-narrative/generators/imports.d.ts.map +1 -1
- package/dist/src/transformers/model-to-narrative/generators/imports.js +13 -9
- package/dist/src/transformers/model-to-narrative/generators/imports.js.map +1 -1
- package/dist/src/transformers/narrative-to-model/index.d.ts.map +1 -1
- package/dist/src/transformers/narrative-to-model/index.js +50 -23
- package/dist/src/transformers/narrative-to-model/index.js.map +1 -1
- package/dist/src/transformers/narrative-to-model/type-inference.specs.js +100 -90
- package/dist/src/transformers/narrative-to-model/type-inference.specs.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/src/commands/export-schema-runner.ts +3 -1
- package/src/fluent-builder.ts +3 -3
- package/src/getNarratives.specs.ts +176 -184
- package/src/id/addAutoIds.specs.ts +55 -48
- package/src/id/addAutoIds.ts +28 -11
- package/src/id/generators.ts +1 -1
- package/src/id/hasAllIds.specs.ts +147 -245
- package/src/id/hasAllIds.ts +11 -4
- package/src/index.ts +11 -12
- package/src/loader/graph.ts +23 -6
- package/src/loader/ts-utils.ts +169 -26
- package/src/model-to-narrative.specs.ts +548 -466
- package/src/narrative-context.specs.ts +73 -116
- package/src/narrative-context.ts +127 -374
- package/src/narrative.ts +70 -120
- package/src/samples/questionnaires.narrative.ts +10 -10
- package/src/samples/test-with-ids.narrative.ts +23 -31
- package/src/schema.ts +33 -52
- package/src/slice-builder.ts +3 -3
- package/src/transformers/model-to-narrative/generators/flow.ts +191 -85
- package/src/transformers/model-to-narrative/generators/gwt.ts +195 -178
- package/src/transformers/model-to-narrative/generators/imports.ts +13 -9
- package/src/transformers/narrative-to-model/index.ts +87 -26
- package/src/transformers/narrative-to-model/type-inference.specs.ts +100 -90
|
@@ -9,6 +9,7 @@ describe('modelToNarrative', () => {
|
|
|
9
9
|
data,
|
|
10
10
|
describe,
|
|
11
11
|
example,
|
|
12
|
+
given,
|
|
12
13
|
gql,
|
|
13
14
|
it,
|
|
14
15
|
narrative,
|
|
@@ -18,6 +19,8 @@ describe('modelToNarrative', () => {
|
|
|
18
19
|
sink,
|
|
19
20
|
source,
|
|
20
21
|
specs,
|
|
22
|
+
then,
|
|
23
|
+
when,
|
|
21
24
|
} from '@auto-engineer/narrative';
|
|
22
25
|
import type { Command, Event, State } from '@auto-engineer/narrative';
|
|
23
26
|
import { AI, ProductCatalog } from '../server/src/integrations.js';
|
|
@@ -114,34 +117,36 @@ narrative('Seasonal Assistant', () => {
|
|
|
114
117
|
data([sink().event('ShoppingCriteriaEntered').toStream('shopping-session-\${sessionId}')]);
|
|
115
118
|
specs('When shopper submits criteria, a shopping session is started', () => {
|
|
116
119
|
rule('Valid criteria should start a shopping session', () => {
|
|
117
|
-
example('User submits shopping criteria for children')
|
|
118
|
-
|
|
120
|
+
example('User submits shopping criteria for children', () => {
|
|
121
|
+
when<EnterShoppingCriteria>({
|
|
119
122
|
sessionId: 'shopper-123',
|
|
120
123
|
criteria:
|
|
121
124
|
'I need back-to-school items for my 7-year-old daughter who loves soccer and crafts, and my 12-year-old son who is into computers and Magic the Gathering.',
|
|
122
|
-
})
|
|
123
|
-
|
|
125
|
+
});
|
|
126
|
+
then<ShoppingCriteriaEntered>({
|
|
124
127
|
sessionId: 'shopper-123',
|
|
125
128
|
criteria:
|
|
126
129
|
'I need back-to-school items for my 7-year-old daughter who loves soccer and crafts, and my 12-year-old son who is into computers and Magic the Gathering.',
|
|
127
130
|
});
|
|
131
|
+
});
|
|
128
132
|
});
|
|
129
133
|
});
|
|
130
134
|
});
|
|
131
135
|
react('creates a chat session').server(() => {
|
|
132
136
|
specs('When shopping criteria are entered, request wishlist creation', () => {
|
|
133
137
|
rule('Shopping criteria should trigger item suggestion', () => {
|
|
134
|
-
example('Criteria entered triggers wishlist creation')
|
|
135
|
-
|
|
138
|
+
example('Criteria entered triggers wishlist creation', () => {
|
|
139
|
+
when<ShoppingCriteriaEntered>({
|
|
136
140
|
sessionId: 'session-abc',
|
|
137
141
|
criteria:
|
|
138
142
|
'I need back-to-school items for my 7-year-old daughter who loves soccer and crafts, and my 12-year-old son who is into computers and Magic the Gathering.',
|
|
139
|
-
})
|
|
140
|
-
|
|
143
|
+
});
|
|
144
|
+
then<SuggestShoppingItems>({
|
|
141
145
|
sessionId: 'session-abc',
|
|
142
146
|
prompt:
|
|
143
147
|
'I need back-to-school items for my 7-year-old daughter who loves soccer and crafts, and my 12-year-old son who is into computers and Magic the Gathering.',
|
|
144
148
|
});
|
|
149
|
+
});
|
|
145
150
|
});
|
|
146
151
|
});
|
|
147
152
|
});
|
|
@@ -158,8 +163,8 @@ narrative('Seasonal Assistant', () => {
|
|
|
158
163
|
]);
|
|
159
164
|
specs('When chat is triggered, AI suggests items based on product catalog', () => {
|
|
160
165
|
rule('AI should suggest relevant items from available products', () => {
|
|
161
|
-
example('Product catalog with matching items generates suggestions')
|
|
162
|
-
|
|
166
|
+
example('Product catalog with matching items generates suggestions', () => {
|
|
167
|
+
given<Products>({
|
|
163
168
|
products: [
|
|
164
169
|
{
|
|
165
170
|
productId: 'prod-soccer-ball',
|
|
@@ -194,13 +199,13 @@ narrative('Seasonal Assistant', () => {
|
|
|
194
199
|
imageUrl: 'https://example.com/mtg-starter.jpg',
|
|
195
200
|
},
|
|
196
201
|
],
|
|
197
|
-
})
|
|
198
|
-
|
|
202
|
+
});
|
|
203
|
+
when<SuggestShoppingItems>({
|
|
199
204
|
sessionId: 'session-abc',
|
|
200
205
|
prompt:
|
|
201
206
|
'I need back-to-school items for my 7-year-old daughter who loves soccer and crafts, and my 12-year-old son who is into computers and Magic the Gathering.',
|
|
202
|
-
})
|
|
203
|
-
|
|
207
|
+
});
|
|
208
|
+
then<ShoppingItemsSuggested>({
|
|
204
209
|
sessionId: 'session-abc',
|
|
205
210
|
suggestedItems: [
|
|
206
211
|
{
|
|
@@ -229,6 +234,7 @@ narrative('Seasonal Assistant', () => {
|
|
|
229
234
|
},
|
|
230
235
|
],
|
|
231
236
|
});
|
|
237
|
+
});
|
|
232
238
|
});
|
|
233
239
|
});
|
|
234
240
|
});
|
|
@@ -257,8 +263,8 @@ narrative('Seasonal Assistant', () => {
|
|
|
257
263
|
data([source().state('SuggestedItems').fromProjection('SuggestedItemsProjection', 'sessionId')]);
|
|
258
264
|
specs('Suggested items are available for viewing', () => {
|
|
259
265
|
rule('Items should be available for viewing after suggestion', () => {
|
|
260
|
-
example('Item becomes available after AI suggestion event')
|
|
261
|
-
|
|
266
|
+
example('Item becomes available after AI suggestion event', () => {
|
|
267
|
+
when<ShoppingItemsSuggested>({
|
|
262
268
|
sessionId: 'session-abc',
|
|
263
269
|
suggestedItems: [
|
|
264
270
|
{
|
|
@@ -286,8 +292,8 @@ narrative('Seasonal Assistant', () => {
|
|
|
286
292
|
reason: 'Ideal starter set for Magic the Gathering enthusiasts',
|
|
287
293
|
},
|
|
288
294
|
],
|
|
289
|
-
})
|
|
290
|
-
|
|
295
|
+
});
|
|
296
|
+
then<SuggestedItems>({
|
|
291
297
|
sessionId: 'session-abc',
|
|
292
298
|
items: [
|
|
293
299
|
{
|
|
@@ -316,6 +322,7 @@ narrative('Seasonal Assistant', () => {
|
|
|
316
322
|
},
|
|
317
323
|
],
|
|
318
324
|
});
|
|
325
|
+
});
|
|
319
326
|
});
|
|
320
327
|
});
|
|
321
328
|
});
|
|
@@ -331,8 +338,8 @@ narrative('Seasonal Assistant', () => {
|
|
|
331
338
|
data([sink().event('ItemsAddedToCart').toStream('shopping-session-\${sessionId}')]);
|
|
332
339
|
specs('When shopper accepts items, they are added to cart', () => {
|
|
333
340
|
rule('Accepted items should be added to the shopping cart', () => {
|
|
334
|
-
example('User selects all suggested items for cart')
|
|
335
|
-
|
|
341
|
+
example('User selects all suggested items for cart', () => {
|
|
342
|
+
when<AddItemsToCart>({
|
|
336
343
|
sessionId: 'session-abc',
|
|
337
344
|
items: [
|
|
338
345
|
{ productId: 'prod-soccer-ball', quantity: 1 },
|
|
@@ -340,8 +347,8 @@ narrative('Seasonal Assistant', () => {
|
|
|
340
347
|
{ productId: 'prod-laptop-bag', quantity: 1 },
|
|
341
348
|
{ productId: 'prod-mtg-starter', quantity: 1 },
|
|
342
349
|
],
|
|
343
|
-
})
|
|
344
|
-
|
|
350
|
+
});
|
|
351
|
+
then<ItemsAddedToCart>({
|
|
345
352
|
sessionId: 'session-abc',
|
|
346
353
|
items: [
|
|
347
354
|
{ productId: 'prod-soccer-ball', quantity: 1 },
|
|
@@ -350,6 +357,7 @@ narrative('Seasonal Assistant', () => {
|
|
|
350
357
|
{ productId: 'prod-mtg-starter', quantity: 1 },
|
|
351
358
|
],
|
|
352
359
|
});
|
|
360
|
+
});
|
|
353
361
|
});
|
|
354
362
|
});
|
|
355
363
|
});
|
|
@@ -477,10 +485,13 @@ narrative('Test Flow without IDs', () => {
|
|
|
477
485
|
},
|
|
478
486
|
server: {
|
|
479
487
|
description: 'Product query server',
|
|
480
|
-
specs:
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
488
|
+
specs: [
|
|
489
|
+
{
|
|
490
|
+
type: 'gherkin',
|
|
491
|
+
feature: 'Product data specs',
|
|
492
|
+
rules: [],
|
|
493
|
+
},
|
|
494
|
+
],
|
|
484
495
|
},
|
|
485
496
|
},
|
|
486
497
|
],
|
|
@@ -528,30 +539,36 @@ narrative('Test Flow with IDs', 'FLOW-123', () => {
|
|
|
528
539
|
},
|
|
529
540
|
server: {
|
|
530
541
|
description: 'Command processing server',
|
|
531
|
-
specs:
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
542
|
+
specs: [
|
|
543
|
+
{
|
|
544
|
+
type: 'gherkin',
|
|
545
|
+
feature: 'Command Processing',
|
|
546
|
+
rules: [
|
|
547
|
+
{
|
|
548
|
+
id: 'RULE-ABC',
|
|
549
|
+
name: 'Valid commands should be processed',
|
|
550
|
+
examples: [
|
|
551
|
+
{
|
|
552
|
+
id: 'EX-001',
|
|
553
|
+
name: 'User submits valid command',
|
|
554
|
+
steps: [
|
|
555
|
+
{
|
|
556
|
+
keyword: 'When',
|
|
557
|
+
text: 'ProcessCommand',
|
|
558
|
+
docString: { id: 'cmd-123', action: 'create' },
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
keyword: 'Then',
|
|
562
|
+
text: 'CommandProcessed',
|
|
563
|
+
docString: { id: 'cmd-123', status: 'success' },
|
|
564
|
+
},
|
|
565
|
+
],
|
|
543
566
|
},
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
],
|
|
550
|
-
},
|
|
551
|
-
],
|
|
552
|
-
},
|
|
553
|
-
],
|
|
554
|
-
},
|
|
567
|
+
],
|
|
568
|
+
},
|
|
569
|
+
],
|
|
570
|
+
},
|
|
571
|
+
],
|
|
555
572
|
},
|
|
556
573
|
},
|
|
557
574
|
],
|
|
@@ -581,7 +598,8 @@ narrative('Test Flow with IDs', 'FLOW-123', () => {
|
|
|
581
598
|
integrations: [],
|
|
582
599
|
};
|
|
583
600
|
const code = await modelToNarrative(modelWithRuleIds);
|
|
584
|
-
expect(code)
|
|
601
|
+
expect(code)
|
|
602
|
+
.toEqual(`import { command, example, narrative, rule, specs, then, when } from '@auto-engineer/narrative';
|
|
585
603
|
import type { Command, Event } from '@auto-engineer/narrative';
|
|
586
604
|
type ProcessCommand = Command<
|
|
587
605
|
'ProcessCommand',
|
|
@@ -601,9 +619,10 @@ narrative('Test Flow with Rule IDs', 'FLOW-456', () => {
|
|
|
601
619
|
command('process command', 'SLICE-789').server(() => {
|
|
602
620
|
specs('Command Processing', () => {
|
|
603
621
|
rule('Valid commands should be processed', 'RULE-ABC', () => {
|
|
604
|
-
example('User submits valid command')
|
|
605
|
-
|
|
606
|
-
|
|
622
|
+
example('User submits valid command', () => {
|
|
623
|
+
when<ProcessCommand>({ id: 'cmd-123', action: 'create' });
|
|
624
|
+
then<CommandProcessed>({ id: 'cmd-123', status: 'success' });
|
|
625
|
+
});
|
|
607
626
|
});
|
|
608
627
|
});
|
|
609
628
|
});
|
|
@@ -680,11 +699,11 @@ narrative('Questionnaire Flow', 'QUEST-001', () => {});
|
|
|
680
699
|
narratives: [
|
|
681
700
|
{
|
|
682
701
|
name: 'Questionnaires',
|
|
683
|
-
id: '
|
|
702
|
+
id: 'Q9m2Kp4Lx',
|
|
684
703
|
slices: [
|
|
685
704
|
{
|
|
686
705
|
name: 'Homepage',
|
|
687
|
-
id: '
|
|
706
|
+
id: 'H1a4Bn6Cy',
|
|
688
707
|
type: 'experience',
|
|
689
708
|
client: {
|
|
690
709
|
specs: [
|
|
@@ -695,7 +714,7 @@ narrative('Questionnaire Flow', 'QUEST-001', () => {});
|
|
|
695
714
|
},
|
|
696
715
|
{
|
|
697
716
|
name: 'views the questionnaire',
|
|
698
|
-
id: '
|
|
717
|
+
id: 'V7n8Rq5M',
|
|
699
718
|
type: 'query',
|
|
700
719
|
client: {
|
|
701
720
|
specs: [
|
|
@@ -727,59 +746,64 @@ narrative('Questionnaire Flow', 'QUEST-001', () => {});
|
|
|
727
746
|
},
|
|
728
747
|
},
|
|
729
748
|
],
|
|
730
|
-
specs:
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
749
|
+
specs: [
|
|
750
|
+
{
|
|
751
|
+
type: 'gherkin',
|
|
752
|
+
feature: '',
|
|
753
|
+
rules: [
|
|
754
|
+
{
|
|
755
|
+
id: 'r1A3Bp9W',
|
|
756
|
+
name: 'questionnaires show current progress',
|
|
757
|
+
examples: [
|
|
758
|
+
{
|
|
759
|
+
id: 'EX-001',
|
|
760
|
+
name: 'a question has already been answered',
|
|
761
|
+
steps: [
|
|
762
|
+
{
|
|
763
|
+
keyword: 'Given',
|
|
764
|
+
text: 'QuestionnaireLinkSent',
|
|
765
|
+
docString: {
|
|
766
|
+
questionnaireId: 'q-001',
|
|
767
|
+
participantId: 'participant-abc',
|
|
768
|
+
link: 'https://app.example.com/q/q-001?participant=participant-abc',
|
|
769
|
+
sentAt: new Date('2030-01-01T09:00:00.000Z'),
|
|
770
|
+
},
|
|
747
771
|
},
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
eventRef: 'QuestionAnswered',
|
|
759
|
-
},
|
|
760
|
-
then: [
|
|
761
|
-
{
|
|
762
|
-
stateRef: 'QuestionnaireProgress',
|
|
763
|
-
exampleData: {
|
|
764
|
-
questionnaireId: 'q-001',
|
|
765
|
-
participantId: 'participant-abc',
|
|
766
|
-
status: 'in_progress',
|
|
767
|
-
currentQuestionId: 'q2',
|
|
768
|
-
remainingQuestions: ['q2', 'q3'],
|
|
769
|
-
answers: [
|
|
770
|
-
{
|
|
771
|
-
questionId: 'q1',
|
|
772
|
-
value: 'Yes',
|
|
773
|
-
},
|
|
774
|
-
],
|
|
772
|
+
{
|
|
773
|
+
keyword: 'When',
|
|
774
|
+
text: 'QuestionAnswered',
|
|
775
|
+
docString: {
|
|
776
|
+
questionnaireId: 'q-001',
|
|
777
|
+
participantId: 'participant-abc',
|
|
778
|
+
questionId: 'q1',
|
|
779
|
+
answer: 'Yes',
|
|
780
|
+
savedAt: new Date('2030-01-01T09:05:00.000Z'),
|
|
781
|
+
},
|
|
775
782
|
},
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
+
{
|
|
784
|
+
keyword: 'Then',
|
|
785
|
+
text: 'QuestionnaireProgress',
|
|
786
|
+
docString: {
|
|
787
|
+
questionnaireId: 'q-001',
|
|
788
|
+
participantId: 'participant-abc',
|
|
789
|
+
status: 'in_progress',
|
|
790
|
+
currentQuestionId: 'q2',
|
|
791
|
+
remainingQuestions: ['q2', 'q3'],
|
|
792
|
+
answers: [
|
|
793
|
+
{
|
|
794
|
+
questionId: 'q1',
|
|
795
|
+
value: 'Yes',
|
|
796
|
+
},
|
|
797
|
+
],
|
|
798
|
+
},
|
|
799
|
+
},
|
|
800
|
+
],
|
|
801
|
+
},
|
|
802
|
+
],
|
|
803
|
+
},
|
|
804
|
+
],
|
|
805
|
+
},
|
|
806
|
+
],
|
|
783
807
|
},
|
|
784
808
|
},
|
|
785
809
|
],
|
|
@@ -899,6 +923,7 @@ narrative('Questionnaire Flow', 'QUEST-001', () => {});
|
|
|
899
923
|
describe,
|
|
900
924
|
example,
|
|
901
925
|
experience,
|
|
926
|
+
given,
|
|
902
927
|
gql,
|
|
903
928
|
it,
|
|
904
929
|
narrative,
|
|
@@ -906,6 +931,8 @@ narrative('Questionnaire Flow', 'QUEST-001', () => {});
|
|
|
906
931
|
rule,
|
|
907
932
|
source,
|
|
908
933
|
specs,
|
|
934
|
+
then,
|
|
935
|
+
when,
|
|
909
936
|
} from '@auto-engineer/narrative';
|
|
910
937
|
import type { Event, State } from '@auto-engineer/narrative';
|
|
911
938
|
type QuestionnaireLinkSent = Event<
|
|
@@ -941,12 +968,12 @@ type QuestionnaireProgress = State<
|
|
|
941
968
|
}[];
|
|
942
969
|
}
|
|
943
970
|
>;
|
|
944
|
-
narrative('Questionnaires', '
|
|
945
|
-
experience('Homepage', '
|
|
971
|
+
narrative('Questionnaires', 'Q9m2Kp4Lx', () => {
|
|
972
|
+
experience('Homepage', 'H1a4Bn6Cy').client(() => {
|
|
946
973
|
it('show a hero section with a welcome message');
|
|
947
974
|
it('allow user to start the questionnaire');
|
|
948
975
|
});
|
|
949
|
-
query('views the questionnaire', '
|
|
976
|
+
query('views the questionnaire', 'V7n8Rq5M')
|
|
950
977
|
.client(() => {
|
|
951
978
|
describe('Questionnaire Progress', () => {
|
|
952
979
|
it('focus on the current question based on the progress state');
|
|
@@ -973,22 +1000,22 @@ narrative('Questionnaires', 'AUTO-Q9m2Kp4Lx', () => {
|
|
|
973
1000
|
.server(() => {
|
|
974
1001
|
data([source().state('QuestionnaireProgress').fromProjection('Questionnaires', 'questionnaire-participantId')]);
|
|
975
1002
|
specs(() => {
|
|
976
|
-
rule('questionnaires show current progress', '
|
|
977
|
-
example('a question has already been answered')
|
|
978
|
-
|
|
1003
|
+
rule('questionnaires show current progress', 'r1A3Bp9W', () => {
|
|
1004
|
+
example('a question has already been answered', () => {
|
|
1005
|
+
given<QuestionnaireLinkSent>({
|
|
979
1006
|
questionnaireId: 'q-001',
|
|
980
1007
|
participantId: 'participant-abc',
|
|
981
1008
|
link: 'https://app.example.com/q/q-001?participant=participant-abc',
|
|
982
1009
|
sentAt: new Date('2030-01-01T09:00:00.000Z'),
|
|
983
|
-
})
|
|
984
|
-
|
|
1010
|
+
});
|
|
1011
|
+
when<QuestionAnswered>({
|
|
985
1012
|
questionnaireId: 'q-001',
|
|
986
1013
|
participantId: 'participant-abc',
|
|
987
1014
|
questionId: 'q1',
|
|
988
1015
|
answer: 'Yes',
|
|
989
1016
|
savedAt: new Date('2030-01-01T09:05:00.000Z'),
|
|
990
|
-
})
|
|
991
|
-
|
|
1017
|
+
});
|
|
1018
|
+
then<QuestionnaireProgress>({
|
|
992
1019
|
questionnaireId: 'q-001',
|
|
993
1020
|
participantId: 'participant-abc',
|
|
994
1021
|
status: 'in_progress',
|
|
@@ -996,6 +1023,7 @@ narrative('Questionnaires', 'AUTO-Q9m2Kp4Lx', () => {
|
|
|
996
1023
|
remainingQuestions: ['q2', 'q3'],
|
|
997
1024
|
answers: [{ questionId: 'q1', value: 'Yes' }],
|
|
998
1025
|
});
|
|
1026
|
+
});
|
|
999
1027
|
});
|
|
1000
1028
|
});
|
|
1001
1029
|
});
|
|
@@ -1019,71 +1047,78 @@ narrative('Questionnaires', 'AUTO-Q9m2Kp4Lx', () => {
|
|
|
1019
1047
|
},
|
|
1020
1048
|
server: {
|
|
1021
1049
|
description: 'Test server for duplicate rules',
|
|
1022
|
-
specs:
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1050
|
+
specs: [
|
|
1051
|
+
{
|
|
1052
|
+
type: 'gherkin',
|
|
1053
|
+
feature: 'Test Rules',
|
|
1054
|
+
rules: [
|
|
1055
|
+
{
|
|
1056
|
+
id: 'r1A3Bp9W',
|
|
1057
|
+
name: 'questionnaires show current progress',
|
|
1058
|
+
examples: [
|
|
1059
|
+
{
|
|
1060
|
+
id: 'EX-001',
|
|
1061
|
+
name: 'a question has already been answered',
|
|
1062
|
+
steps: [
|
|
1063
|
+
{
|
|
1064
|
+
keyword: 'Given',
|
|
1065
|
+
text: 'QuestionnaireLinkSent',
|
|
1066
|
+
docString: {
|
|
1067
|
+
questionnaireId: 'q-001',
|
|
1068
|
+
participantId: 'participant-abc',
|
|
1069
|
+
},
|
|
1037
1070
|
},
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
},
|
|
1047
|
-
},
|
|
1048
|
-
then: [
|
|
1049
|
-
{
|
|
1050
|
-
stateRef: 'QuestionnaireProgress',
|
|
1051
|
-
exampleData: {
|
|
1052
|
-
questionnaireId: 'q-001',
|
|
1053
|
-
status: 'in_progress',
|
|
1071
|
+
{
|
|
1072
|
+
keyword: 'When',
|
|
1073
|
+
text: 'QuestionAnswered',
|
|
1074
|
+
docString: {
|
|
1075
|
+
questionnaireId: 'q-001',
|
|
1076
|
+
questionId: 'q1',
|
|
1077
|
+
answer: 'Yes',
|
|
1078
|
+
},
|
|
1054
1079
|
},
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
eventRef: 'QuestionnaireLinkSent',
|
|
1063
|
-
exampleData: {
|
|
1064
|
-
questionnaireId: 'q-001',
|
|
1065
|
-
participantId: 'participant-abc',
|
|
1080
|
+
{
|
|
1081
|
+
keyword: 'Then',
|
|
1082
|
+
text: 'QuestionnaireProgress',
|
|
1083
|
+
docString: {
|
|
1084
|
+
questionnaireId: 'q-001',
|
|
1085
|
+
status: 'in_progress',
|
|
1086
|
+
},
|
|
1066
1087
|
},
|
|
1067
|
-
|
|
1068
|
-
],
|
|
1069
|
-
when: {
|
|
1070
|
-
eventRef: 'QuestionnaireLinkSent',
|
|
1071
|
-
exampleData: {},
|
|
1088
|
+
],
|
|
1072
1089
|
},
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1090
|
+
{
|
|
1091
|
+
id: 'EX-002',
|
|
1092
|
+
name: 'no questions have been answered yet',
|
|
1093
|
+
steps: [
|
|
1094
|
+
{
|
|
1095
|
+
keyword: 'Given',
|
|
1096
|
+
text: 'QuestionnaireLinkSent',
|
|
1097
|
+
docString: {
|
|
1098
|
+
questionnaireId: 'q-001',
|
|
1099
|
+
participantId: 'participant-abc',
|
|
1100
|
+
},
|
|
1079
1101
|
},
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1102
|
+
{
|
|
1103
|
+
keyword: 'When',
|
|
1104
|
+
text: 'QuestionnaireLinkSent',
|
|
1105
|
+
docString: {},
|
|
1106
|
+
},
|
|
1107
|
+
{
|
|
1108
|
+
keyword: 'Then',
|
|
1109
|
+
text: 'QuestionnaireProgress',
|
|
1110
|
+
docString: {
|
|
1111
|
+
questionnaireId: 'q-001',
|
|
1112
|
+
status: 'in_progress',
|
|
1113
|
+
},
|
|
1114
|
+
},
|
|
1115
|
+
],
|
|
1116
|
+
},
|
|
1117
|
+
],
|
|
1118
|
+
},
|
|
1119
|
+
],
|
|
1120
|
+
},
|
|
1121
|
+
],
|
|
1087
1122
|
},
|
|
1088
1123
|
},
|
|
1089
1124
|
],
|
|
@@ -1124,7 +1159,8 @@ narrative('Questionnaires', 'AUTO-Q9m2Kp4Lx', () => {
|
|
|
1124
1159
|
integrations: [],
|
|
1125
1160
|
};
|
|
1126
1161
|
const code = await modelToNarrative(modelWithDuplicateRules);
|
|
1127
|
-
expect(code)
|
|
1162
|
+
expect(code)
|
|
1163
|
+
.toEqual(`import { example, given, narrative, query, rule, specs, then, when } from '@auto-engineer/narrative';
|
|
1128
1164
|
import type { Event, State } from '@auto-engineer/narrative';
|
|
1129
1165
|
type QuestionnaireLinkSent = Event<
|
|
1130
1166
|
'QuestionnaireLinkSent',
|
|
@@ -1151,22 +1187,23 @@ type QuestionnaireProgress = State<
|
|
|
1151
1187
|
narrative('Test Flow', 'TEST-FLOW', () => {
|
|
1152
1188
|
query('test slice', 'TEST-SLICE').server(() => {
|
|
1153
1189
|
specs('Test Rules', () => {
|
|
1154
|
-
rule('questionnaires show current progress', '
|
|
1155
|
-
example('a question has already been answered')
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1190
|
+
rule('questionnaires show current progress', 'r1A3Bp9W', () => {
|
|
1191
|
+
example('a question has already been answered', () => {
|
|
1192
|
+
given<QuestionnaireLinkSent>({ questionnaireId: 'q-001', participantId: 'participant-abc' });
|
|
1193
|
+
when<QuestionAnswered>({ questionnaireId: 'q-001', questionId: 'q1', answer: 'Yes' });
|
|
1194
|
+
then<QuestionnaireProgress>({ questionnaireId: 'q-001', status: 'in_progress' });
|
|
1195
|
+
});
|
|
1196
|
+
example('no questions have been answered yet', () => {
|
|
1197
|
+
given<QuestionnaireLinkSent>({ questionnaireId: 'q-001', participantId: 'participant-abc' });
|
|
1198
|
+
then<QuestionnaireProgress>({ questionnaireId: 'q-001', status: 'in_progress' });
|
|
1199
|
+
});
|
|
1163
1200
|
});
|
|
1164
1201
|
});
|
|
1165
1202
|
});
|
|
1166
1203
|
});
|
|
1167
1204
|
`);
|
|
1168
1205
|
});
|
|
1169
|
-
it('should chain multiple given examples with
|
|
1206
|
+
it('should chain multiple given examples with and() syntax', async () => {
|
|
1170
1207
|
const modelWithMultiGiven = {
|
|
1171
1208
|
variant: 'specs',
|
|
1172
1209
|
narratives: [
|
|
@@ -1183,84 +1220,92 @@ narrative('Test Flow', 'TEST-FLOW', () => {
|
|
|
1183
1220
|
},
|
|
1184
1221
|
server: {
|
|
1185
1222
|
description: 'Multi given server rules',
|
|
1186
|
-
specs:
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1223
|
+
specs: [
|
|
1224
|
+
{
|
|
1225
|
+
type: 'gherkin',
|
|
1226
|
+
feature: 'Multi Given Rules',
|
|
1227
|
+
rules: [
|
|
1228
|
+
{
|
|
1229
|
+
id: 'MultiGiven',
|
|
1230
|
+
name: 'all questions have been answered',
|
|
1231
|
+
examples: [
|
|
1232
|
+
{
|
|
1233
|
+
id: 'EX-001',
|
|
1234
|
+
name: 'questionnaire with multiple events',
|
|
1235
|
+
steps: [
|
|
1236
|
+
{
|
|
1237
|
+
keyword: 'Given',
|
|
1238
|
+
text: 'QuestionnaireConfig',
|
|
1239
|
+
docString: {
|
|
1240
|
+
questionnaireId: 'q-001',
|
|
1241
|
+
numberOfQuestions: 3,
|
|
1242
|
+
},
|
|
1201
1243
|
},
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1244
|
+
{
|
|
1245
|
+
keyword: 'And',
|
|
1246
|
+
text: 'QuestionnaireLinkSent',
|
|
1247
|
+
docString: {
|
|
1248
|
+
questionnaireId: 'q-001',
|
|
1249
|
+
participantId: 'participant-abc',
|
|
1250
|
+
link: 'https://example.com/q/q-001',
|
|
1251
|
+
sentAt: new Date('2030-01-01T09:00:00.000Z'),
|
|
1252
|
+
},
|
|
1210
1253
|
},
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1254
|
+
{
|
|
1255
|
+
keyword: 'And',
|
|
1256
|
+
text: 'QuestionAnswered',
|
|
1257
|
+
docString: {
|
|
1258
|
+
questionnaireId: 'q-001',
|
|
1259
|
+
participantId: 'participant-abc',
|
|
1260
|
+
questionId: 'q1',
|
|
1261
|
+
answer: 'Yes',
|
|
1262
|
+
savedAt: new Date('2030-01-01T09:05:00.000Z'),
|
|
1263
|
+
},
|
|
1220
1264
|
},
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1265
|
+
{
|
|
1266
|
+
keyword: 'And',
|
|
1267
|
+
text: 'QuestionAnswered',
|
|
1268
|
+
docString: {
|
|
1269
|
+
questionnaireId: 'q-001',
|
|
1270
|
+
participantId: 'participant-abc',
|
|
1271
|
+
questionId: 'q2',
|
|
1272
|
+
answer: 'No',
|
|
1273
|
+
savedAt: new Date('2030-01-01T09:10:00.000Z'),
|
|
1274
|
+
},
|
|
1230
1275
|
},
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
},
|
|
1242
|
-
},
|
|
1243
|
-
then: [
|
|
1244
|
-
{
|
|
1245
|
-
stateRef: 'QuestionnaireProgress',
|
|
1246
|
-
exampleData: {
|
|
1247
|
-
questionnaireId: 'q-001',
|
|
1248
|
-
participantId: 'participant-abc',
|
|
1249
|
-
status: 'ready_to_submit',
|
|
1250
|
-
currentQuestionId: null,
|
|
1251
|
-
remainingQuestions: [],
|
|
1252
|
-
answers: [
|
|
1253
|
-
{ questionId: 'q1', value: 'Yes' },
|
|
1254
|
-
{ questionId: 'q2', value: 'No' },
|
|
1255
|
-
],
|
|
1276
|
+
{
|
|
1277
|
+
keyword: 'When',
|
|
1278
|
+
text: 'QuestionAnswered',
|
|
1279
|
+
docString: {
|
|
1280
|
+
questionnaireId: 'q-001',
|
|
1281
|
+
participantId: 'participant-abc',
|
|
1282
|
+
questionId: 'q3',
|
|
1283
|
+
answer: 'Maybe',
|
|
1284
|
+
savedAt: new Date('2030-01-01T09:15:00.000Z'),
|
|
1285
|
+
},
|
|
1256
1286
|
},
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1287
|
+
{
|
|
1288
|
+
keyword: 'Then',
|
|
1289
|
+
text: 'QuestionnaireProgress',
|
|
1290
|
+
docString: {
|
|
1291
|
+
questionnaireId: 'q-001',
|
|
1292
|
+
participantId: 'participant-abc',
|
|
1293
|
+
status: 'ready_to_submit',
|
|
1294
|
+
currentQuestionId: null,
|
|
1295
|
+
remainingQuestions: [],
|
|
1296
|
+
answers: [
|
|
1297
|
+
{ questionId: 'q1', value: 'Yes' },
|
|
1298
|
+
{ questionId: 'q2', value: 'No' },
|
|
1299
|
+
],
|
|
1300
|
+
},
|
|
1301
|
+
},
|
|
1302
|
+
],
|
|
1303
|
+
},
|
|
1304
|
+
],
|
|
1305
|
+
},
|
|
1306
|
+
],
|
|
1307
|
+
},
|
|
1308
|
+
],
|
|
1264
1309
|
},
|
|
1265
1310
|
},
|
|
1266
1311
|
],
|
|
@@ -1318,7 +1363,8 @@ narrative('Test Flow', 'TEST-FLOW', () => {
|
|
|
1318
1363
|
integrations: [],
|
|
1319
1364
|
};
|
|
1320
1365
|
const code = await modelToNarrative(modelWithMultiGiven);
|
|
1321
|
-
expect(code)
|
|
1366
|
+
expect(code)
|
|
1367
|
+
.toEqual(`import { and, example, given, narrative, query, rule, specs, then, when } from '@auto-engineer/narrative';
|
|
1322
1368
|
import type { Event, State } from '@auto-engineer/narrative';
|
|
1323
1369
|
type QuestionnaireConfig = State<
|
|
1324
1370
|
'QuestionnaireConfig',
|
|
@@ -1363,37 +1409,37 @@ type QuestionnaireProgress = State<
|
|
|
1363
1409
|
narrative('Multi Given Flow', 'MULTI-GIVEN', () => {
|
|
1364
1410
|
query('multi given slice', 'MULTI-SLICE').server(() => {
|
|
1365
1411
|
specs('Multi Given Rules', () => {
|
|
1366
|
-
rule('all questions have been answered', '
|
|
1367
|
-
example('questionnaire with multiple events')
|
|
1368
|
-
|
|
1369
|
-
|
|
1412
|
+
rule('all questions have been answered', 'MultiGiven', () => {
|
|
1413
|
+
example('questionnaire with multiple events', () => {
|
|
1414
|
+
given<QuestionnaireConfig>({ questionnaireId: 'q-001', numberOfQuestions: 3 });
|
|
1415
|
+
and<QuestionnaireLinkSent>({
|
|
1370
1416
|
questionnaireId: 'q-001',
|
|
1371
1417
|
participantId: 'participant-abc',
|
|
1372
1418
|
link: 'https://example.com/q/q-001',
|
|
1373
1419
|
sentAt: new Date('2030-01-01T09:00:00.000Z'),
|
|
1374
|
-
})
|
|
1375
|
-
|
|
1420
|
+
});
|
|
1421
|
+
and<QuestionAnswered>({
|
|
1376
1422
|
questionnaireId: 'q-001',
|
|
1377
1423
|
participantId: 'participant-abc',
|
|
1378
1424
|
questionId: 'q1',
|
|
1379
1425
|
answer: 'Yes',
|
|
1380
1426
|
savedAt: new Date('2030-01-01T09:05:00.000Z'),
|
|
1381
|
-
})
|
|
1382
|
-
|
|
1427
|
+
});
|
|
1428
|
+
and<QuestionAnswered>({
|
|
1383
1429
|
questionnaireId: 'q-001',
|
|
1384
1430
|
participantId: 'participant-abc',
|
|
1385
1431
|
questionId: 'q2',
|
|
1386
1432
|
answer: 'No',
|
|
1387
1433
|
savedAt: new Date('2030-01-01T09:10:00.000Z'),
|
|
1388
|
-
})
|
|
1389
|
-
|
|
1434
|
+
});
|
|
1435
|
+
when<QuestionAnswered>({
|
|
1390
1436
|
questionnaireId: 'q-001',
|
|
1391
1437
|
participantId: 'participant-abc',
|
|
1392
1438
|
questionId: 'q3',
|
|
1393
1439
|
answer: 'Maybe',
|
|
1394
1440
|
savedAt: new Date('2030-01-01T09:15:00.000Z'),
|
|
1395
|
-
})
|
|
1396
|
-
|
|
1441
|
+
});
|
|
1442
|
+
then<QuestionnaireProgress>({
|
|
1397
1443
|
questionnaireId: 'q-001',
|
|
1398
1444
|
participantId: 'participant-abc',
|
|
1399
1445
|
status: 'ready_to_submit',
|
|
@@ -1404,6 +1450,7 @@ narrative('Multi Given Flow', 'MULTI-GIVEN', () => {
|
|
|
1404
1450
|
{ questionId: 'q2', value: 'No' },
|
|
1405
1451
|
],
|
|
1406
1452
|
});
|
|
1453
|
+
});
|
|
1407
1454
|
});
|
|
1408
1455
|
});
|
|
1409
1456
|
});
|
|
@@ -1451,45 +1498,50 @@ narrative('Multi Given Flow', 'MULTI-GIVEN', () => {
|
|
|
1451
1498
|
},
|
|
1452
1499
|
},
|
|
1453
1500
|
],
|
|
1454
|
-
specs:
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1501
|
+
specs: [
|
|
1502
|
+
{
|
|
1503
|
+
type: 'gherkin',
|
|
1504
|
+
feature: 'Database State Rules',
|
|
1505
|
+
rules: [
|
|
1506
|
+
{
|
|
1507
|
+
id: 'RefState',
|
|
1508
|
+
name: 'questionnaire config is available when referenced',
|
|
1509
|
+
examples: [
|
|
1510
|
+
{
|
|
1511
|
+
id: 'EX-001',
|
|
1512
|
+
name: 'config from database is accessible',
|
|
1513
|
+
steps: [
|
|
1514
|
+
{
|
|
1515
|
+
keyword: 'Given',
|
|
1516
|
+
text: 'QuestionnaireConfig',
|
|
1517
|
+
docString: {
|
|
1518
|
+
questionnaireId: 'q-001',
|
|
1519
|
+
numberOfQuestions: 5,
|
|
1520
|
+
title: 'Customer Satisfaction Survey',
|
|
1521
|
+
},
|
|
1470
1522
|
},
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
exampleData: {},
|
|
1476
|
-
},
|
|
1477
|
-
then: [
|
|
1478
|
-
{
|
|
1479
|
-
stateRef: 'QuestionnaireProgress',
|
|
1480
|
-
exampleData: {
|
|
1481
|
-
questionnaireId: 'q-001',
|
|
1482
|
-
participantId: 'participant-abc',
|
|
1483
|
-
status: 'in_progress',
|
|
1484
|
-
totalQuestions: 5,
|
|
1523
|
+
{
|
|
1524
|
+
keyword: 'When',
|
|
1525
|
+
text: 'QuestionnaireProgress',
|
|
1526
|
+
docString: {},
|
|
1485
1527
|
},
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1528
|
+
{
|
|
1529
|
+
keyword: 'Then',
|
|
1530
|
+
text: 'QuestionnaireProgress',
|
|
1531
|
+
docString: {
|
|
1532
|
+
questionnaireId: 'q-001',
|
|
1533
|
+
participantId: 'participant-abc',
|
|
1534
|
+
status: 'in_progress',
|
|
1535
|
+
totalQuestions: 5,
|
|
1536
|
+
},
|
|
1537
|
+
},
|
|
1538
|
+
],
|
|
1539
|
+
},
|
|
1540
|
+
],
|
|
1541
|
+
},
|
|
1542
|
+
],
|
|
1543
|
+
},
|
|
1544
|
+
],
|
|
1493
1545
|
},
|
|
1494
1546
|
},
|
|
1495
1547
|
],
|
|
@@ -1522,7 +1574,7 @@ narrative('Multi Given Flow', 'MULTI-GIVEN', () => {
|
|
|
1522
1574
|
};
|
|
1523
1575
|
const code = await modelToNarrative(modelWithReferencedStates);
|
|
1524
1576
|
expect(code)
|
|
1525
|
-
.toEqual(`import { data, example, narrative, query, rule, source, specs } from '@auto-engineer/narrative';
|
|
1577
|
+
.toEqual(`import { data, example, given, narrative, query, rule, source, specs, then } from '@auto-engineer/narrative';
|
|
1526
1578
|
import type { State } from '@auto-engineer/narrative';
|
|
1527
1579
|
type QuestionnaireProgress = State<
|
|
1528
1580
|
'QuestionnaireProgress',
|
|
@@ -1548,20 +1600,20 @@ narrative('Referenced States Flow', 'REF-STATES', () => {
|
|
|
1548
1600
|
source().state('QuestionnaireConfig').fromDatabase('ConfigStore', { questionnaireId: '$questionnaireId' }),
|
|
1549
1601
|
]);
|
|
1550
1602
|
specs('Database State Rules', () => {
|
|
1551
|
-
rule('questionnaire config is available when referenced', '
|
|
1552
|
-
example('config from database is accessible')
|
|
1553
|
-
|
|
1603
|
+
rule('questionnaire config is available when referenced', 'RefState', () => {
|
|
1604
|
+
example('config from database is accessible', () => {
|
|
1605
|
+
given<QuestionnaireConfig>({
|
|
1554
1606
|
questionnaireId: 'q-001',
|
|
1555
1607
|
numberOfQuestions: 5,
|
|
1556
1608
|
title: 'Customer Satisfaction Survey',
|
|
1557
|
-
})
|
|
1558
|
-
|
|
1559
|
-
.then<QuestionnaireProgress>({
|
|
1609
|
+
});
|
|
1610
|
+
then<QuestionnaireProgress>({
|
|
1560
1611
|
questionnaireId: 'q-001',
|
|
1561
1612
|
participantId: 'participant-abc',
|
|
1562
1613
|
status: 'in_progress',
|
|
1563
1614
|
totalQuestions: 5,
|
|
1564
1615
|
});
|
|
1616
|
+
});
|
|
1565
1617
|
});
|
|
1566
1618
|
});
|
|
1567
1619
|
});
|
|
@@ -1585,48 +1637,53 @@ narrative('Referenced States Flow', 'REF-STATES', () => {
|
|
|
1585
1637
|
},
|
|
1586
1638
|
server: {
|
|
1587
1639
|
description: 'Date server with Date fields',
|
|
1588
|
-
specs:
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1640
|
+
specs: [
|
|
1641
|
+
{
|
|
1642
|
+
type: 'gherkin',
|
|
1643
|
+
feature: 'Date Field Rules',
|
|
1644
|
+
rules: [
|
|
1645
|
+
{
|
|
1646
|
+
id: 'DateRule',
|
|
1647
|
+
name: 'handles Date fields correctly',
|
|
1648
|
+
examples: [
|
|
1649
|
+
{
|
|
1650
|
+
id: 'EX-001',
|
|
1651
|
+
name: 'event with Date fields',
|
|
1652
|
+
steps: [
|
|
1653
|
+
{
|
|
1654
|
+
keyword: 'Given',
|
|
1655
|
+
text: 'TimestampedEvent',
|
|
1656
|
+
docString: {
|
|
1657
|
+
id: 'event-123',
|
|
1658
|
+
sentAt: new Date('2030-01-01T09:00:00.000Z'),
|
|
1659
|
+
savedAt: new Date('2030-01-01T09:05:00.000Z'),
|
|
1660
|
+
attemptedAt: '2030-01-01T09:10:00.000Z',
|
|
1661
|
+
submittedAt: '2030-01-01T09:15:00.000Z',
|
|
1662
|
+
},
|
|
1606
1663
|
},
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
},
|
|
1614
|
-
},
|
|
1615
|
-
then: [
|
|
1616
|
-
{
|
|
1617
|
-
stateRef: 'ProcessState',
|
|
1618
|
-
exampleData: {
|
|
1619
|
-
id: 'state-123',
|
|
1620
|
-
completedAt: '2030-01-01T11:00:00.000Z',
|
|
1621
|
-
status: 'completed',
|
|
1664
|
+
{
|
|
1665
|
+
keyword: 'When',
|
|
1666
|
+
text: 'ProcessEvent',
|
|
1667
|
+
docString: {
|
|
1668
|
+
processedAt: '2030-01-01T10:00:00.000Z',
|
|
1669
|
+
},
|
|
1622
1670
|
},
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1671
|
+
{
|
|
1672
|
+
keyword: 'Then',
|
|
1673
|
+
text: 'ProcessState',
|
|
1674
|
+
docString: {
|
|
1675
|
+
id: 'state-123',
|
|
1676
|
+
completedAt: '2030-01-01T11:00:00.000Z',
|
|
1677
|
+
status: 'completed',
|
|
1678
|
+
},
|
|
1679
|
+
},
|
|
1680
|
+
],
|
|
1681
|
+
},
|
|
1682
|
+
],
|
|
1683
|
+
},
|
|
1684
|
+
],
|
|
1685
|
+
},
|
|
1686
|
+
],
|
|
1630
1687
|
},
|
|
1631
1688
|
},
|
|
1632
1689
|
],
|
|
@@ -1667,7 +1724,8 @@ narrative('Referenced States Flow', 'REF-STATES', () => {
|
|
|
1667
1724
|
integrations: [],
|
|
1668
1725
|
};
|
|
1669
1726
|
const code = await modelToNarrative(modelWithDateFields);
|
|
1670
|
-
expect(code)
|
|
1727
|
+
expect(code)
|
|
1728
|
+
.toEqual(`import { example, given, narrative, query, rule, specs, then, when } from '@auto-engineer/narrative';
|
|
1671
1729
|
import type { Event, State } from '@auto-engineer/narrative';
|
|
1672
1730
|
type TimestampedEvent = Event<
|
|
1673
1731
|
'TimestampedEvent',
|
|
@@ -1696,21 +1754,22 @@ type ProcessState = State<
|
|
|
1696
1754
|
narrative('Date Handling Flow', 'DATE-FLOW', () => {
|
|
1697
1755
|
query('date handling slice', 'DATE-SLICE').server(() => {
|
|
1698
1756
|
specs('Date Field Rules', () => {
|
|
1699
|
-
rule('handles Date fields correctly', '
|
|
1700
|
-
example('event with Date fields')
|
|
1701
|
-
|
|
1757
|
+
rule('handles Date fields correctly', 'DateRule', () => {
|
|
1758
|
+
example('event with Date fields', () => {
|
|
1759
|
+
given<TimestampedEvent>({
|
|
1702
1760
|
id: 'event-123',
|
|
1703
1761
|
sentAt: new Date('2030-01-01T09:00:00.000Z'),
|
|
1704
1762
|
savedAt: new Date('2030-01-01T09:05:00.000Z'),
|
|
1705
1763
|
attemptedAt: new Date('2030-01-01T09:10:00.000Z'),
|
|
1706
1764
|
submittedAt: new Date('2030-01-01T09:15:00.000Z'),
|
|
1707
|
-
})
|
|
1708
|
-
|
|
1709
|
-
|
|
1765
|
+
});
|
|
1766
|
+
when<ProcessEvent>({ processedAt: new Date('2030-01-01T10:00:00.000Z') });
|
|
1767
|
+
then<ProcessState>({
|
|
1710
1768
|
id: 'state-123',
|
|
1711
1769
|
completedAt: new Date('2030-01-01T11:00:00.000Z'),
|
|
1712
1770
|
status: 'completed',
|
|
1713
1771
|
});
|
|
1772
|
+
});
|
|
1714
1773
|
});
|
|
1715
1774
|
});
|
|
1716
1775
|
});
|
|
@@ -1727,7 +1786,7 @@ narrative('Date Handling Flow', 'DATE-FLOW', () => {
|
|
|
1727
1786
|
slices: [
|
|
1728
1787
|
{
|
|
1729
1788
|
name: 'Active Surveys Summary',
|
|
1730
|
-
id: '
|
|
1789
|
+
id: 'aifPcU3hw',
|
|
1731
1790
|
type: 'experience',
|
|
1732
1791
|
client: {
|
|
1733
1792
|
specs: [{ type: 'it', title: 'show active surveys summary' }],
|
|
@@ -1741,7 +1800,7 @@ narrative('Date Handling Flow', 'DATE-FLOW', () => {
|
|
|
1741
1800
|
slices: [
|
|
1742
1801
|
{
|
|
1743
1802
|
name: 'Create Survey Form',
|
|
1744
|
-
id: '
|
|
1803
|
+
id: 'MPviTMrQC',
|
|
1745
1804
|
type: 'experience',
|
|
1746
1805
|
client: {
|
|
1747
1806
|
specs: [{ type: 'it', title: 'allow entering survey title' }],
|
|
@@ -1755,7 +1814,7 @@ narrative('Date Handling Flow', 'DATE-FLOW', () => {
|
|
|
1755
1814
|
slices: [
|
|
1756
1815
|
{
|
|
1757
1816
|
name: 'Response Rate Charts',
|
|
1758
|
-
id: '
|
|
1817
|
+
id: 'eME978Euk',
|
|
1759
1818
|
type: 'experience',
|
|
1760
1819
|
client: {
|
|
1761
1820
|
specs: [{ type: 'it', title: 'show daily response rate charts' }],
|
|
@@ -1770,17 +1829,17 @@ narrative('Date Handling Flow', 'DATE-FLOW', () => {
|
|
|
1770
1829
|
const code = await modelToNarrative(modelWithMultipleFlowsSameSource);
|
|
1771
1830
|
expect(code).toEqual(`import { experience, it, narrative } from '@auto-engineer/narrative';
|
|
1772
1831
|
narrative('Home Screen', () => {
|
|
1773
|
-
experience('Active Surveys Summary', '
|
|
1832
|
+
experience('Active Surveys Summary', 'aifPcU3hw').client(() => {
|
|
1774
1833
|
it('show active surveys summary');
|
|
1775
1834
|
});
|
|
1776
1835
|
});
|
|
1777
1836
|
narrative('Create Survey', () => {
|
|
1778
|
-
experience('Create Survey Form', '
|
|
1837
|
+
experience('Create Survey Form', 'MPviTMrQC').client(() => {
|
|
1779
1838
|
it('allow entering survey title');
|
|
1780
1839
|
});
|
|
1781
1840
|
});
|
|
1782
1841
|
narrative('Response Analytics', () => {
|
|
1783
|
-
experience('Response Rate Charts', '
|
|
1842
|
+
experience('Response Rate Charts', 'eME978Euk').client(() => {
|
|
1784
1843
|
it('show daily response rate charts');
|
|
1785
1844
|
});
|
|
1786
1845
|
});
|
|
@@ -1803,71 +1862,74 @@ narrative('Response Analytics', () => {
|
|
|
1803
1862
|
},
|
|
1804
1863
|
server: {
|
|
1805
1864
|
description: 'Summary calculation server',
|
|
1806
|
-
specs:
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1865
|
+
specs: [
|
|
1866
|
+
{
|
|
1867
|
+
type: 'gherkin',
|
|
1868
|
+
feature: 'Summary Statistics',
|
|
1869
|
+
rules: [
|
|
1870
|
+
{
|
|
1871
|
+
id: 'RULE-SUMMARY',
|
|
1872
|
+
name: 'summary shows overall todo list statistics',
|
|
1873
|
+
examples: [
|
|
1874
|
+
{
|
|
1875
|
+
id: 'EX-001',
|
|
1876
|
+
name: 'calculates summary from multiple todos',
|
|
1877
|
+
steps: [
|
|
1878
|
+
{
|
|
1879
|
+
keyword: 'Given',
|
|
1880
|
+
text: 'TodoAdded',
|
|
1881
|
+
docString: {
|
|
1882
|
+
todoId: 'todo-001',
|
|
1883
|
+
description: 'Buy groceries',
|
|
1884
|
+
status: 'pending',
|
|
1885
|
+
addedAt: new Date('2030-01-01T09:00:00.000Z'),
|
|
1886
|
+
},
|
|
1823
1887
|
},
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1888
|
+
{
|
|
1889
|
+
keyword: 'And',
|
|
1890
|
+
text: 'TodoAdded',
|
|
1891
|
+
docString: {
|
|
1892
|
+
todoId: 'todo-002',
|
|
1893
|
+
description: 'Write report',
|
|
1894
|
+
status: 'pending',
|
|
1895
|
+
addedAt: new Date('2030-01-01T09:10:00.000Z'),
|
|
1896
|
+
},
|
|
1832
1897
|
},
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1898
|
+
{
|
|
1899
|
+
keyword: 'And',
|
|
1900
|
+
text: 'TodoMarkedInProgress',
|
|
1901
|
+
docString: {
|
|
1902
|
+
todoId: 'todo-001',
|
|
1903
|
+
markedAt: new Date('2030-01-01T10:00:00.000Z'),
|
|
1904
|
+
},
|
|
1839
1905
|
},
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1906
|
+
{
|
|
1907
|
+
keyword: 'And',
|
|
1908
|
+
text: 'TodoMarkedComplete',
|
|
1909
|
+
docString: {
|
|
1910
|
+
todoId: 'todo-002',
|
|
1911
|
+
completedAt: new Date('2030-01-01T11:00:00.000Z'),
|
|
1912
|
+
},
|
|
1846
1913
|
},
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
totalTodos: 2,
|
|
1859
|
-
pendingCount: 0,
|
|
1860
|
-
inProgressCount: 1,
|
|
1861
|
-
completedCount: 1,
|
|
1862
|
-
completionPercentage: 50,
|
|
1914
|
+
{
|
|
1915
|
+
keyword: 'Then',
|
|
1916
|
+
text: 'TodoListSummary',
|
|
1917
|
+
docString: {
|
|
1918
|
+
summaryId: 'main-summary',
|
|
1919
|
+
totalTodos: 2,
|
|
1920
|
+
pendingCount: 0,
|
|
1921
|
+
inProgressCount: 1,
|
|
1922
|
+
completedCount: 1,
|
|
1923
|
+
completionPercentage: 50,
|
|
1924
|
+
},
|
|
1863
1925
|
},
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1926
|
+
],
|
|
1927
|
+
},
|
|
1928
|
+
],
|
|
1929
|
+
},
|
|
1930
|
+
],
|
|
1931
|
+
},
|
|
1932
|
+
],
|
|
1871
1933
|
},
|
|
1872
1934
|
},
|
|
1873
1935
|
],
|
|
@@ -1923,7 +1985,8 @@ narrative('Response Analytics', () => {
|
|
|
1923
1985
|
integrations: [],
|
|
1924
1986
|
};
|
|
1925
1987
|
const code = await modelToNarrative(modelWithEmptyWhen);
|
|
1926
|
-
expect(code)
|
|
1988
|
+
expect(code)
|
|
1989
|
+
.toEqual(`import { and, example, given, narrative, query, rule, specs, then } from '@auto-engineer/narrative';
|
|
1927
1990
|
import type { Event, State } from '@auto-engineer/narrative';
|
|
1928
1991
|
type TodoAdded = Event<
|
|
1929
1992
|
'TodoAdded',
|
|
@@ -1963,22 +2026,22 @@ narrative('Todo List Summary', 'TODO-001', () => {
|
|
|
1963
2026
|
query('views completion summary', 'SUMMARY-001').server(() => {
|
|
1964
2027
|
specs('Summary Statistics', () => {
|
|
1965
2028
|
rule('summary shows overall todo list statistics', 'RULE-SUMMARY', () => {
|
|
1966
|
-
example('calculates summary from multiple todos')
|
|
1967
|
-
|
|
2029
|
+
example('calculates summary from multiple todos', () => {
|
|
2030
|
+
given<TodoAdded>({
|
|
1968
2031
|
todoId: 'todo-001',
|
|
1969
2032
|
description: 'Buy groceries',
|
|
1970
2033
|
status: 'pending',
|
|
1971
2034
|
addedAt: new Date('2030-01-01T09:00:00.000Z'),
|
|
1972
|
-
})
|
|
1973
|
-
|
|
2035
|
+
});
|
|
2036
|
+
and<TodoAdded>({
|
|
1974
2037
|
todoId: 'todo-002',
|
|
1975
2038
|
description: 'Write report',
|
|
1976
2039
|
status: 'pending',
|
|
1977
2040
|
addedAt: new Date('2030-01-01T09:10:00.000Z'),
|
|
1978
|
-
})
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
2041
|
+
});
|
|
2042
|
+
and<TodoMarkedInProgress>({ todoId: 'todo-001', markedAt: new Date('2030-01-01T10:00:00.000Z') });
|
|
2043
|
+
and<TodoMarkedComplete>({ todoId: 'todo-002', completedAt: new Date('2030-01-01T11:00:00.000Z') });
|
|
2044
|
+
then<TodoListSummary>({
|
|
1982
2045
|
summaryId: 'main-summary',
|
|
1983
2046
|
totalTodos: 2,
|
|
1984
2047
|
pendingCount: 0,
|
|
@@ -1986,13 +2049,14 @@ narrative('Todo List Summary', 'TODO-001', () => {
|
|
|
1986
2049
|
completedCount: 1,
|
|
1987
2050
|
completionPercentage: 50,
|
|
1988
2051
|
});
|
|
2052
|
+
});
|
|
1989
2053
|
});
|
|
1990
2054
|
});
|
|
1991
2055
|
});
|
|
1992
2056
|
});
|
|
1993
2057
|
`);
|
|
1994
|
-
expect(code).not.toContain('
|
|
1995
|
-
expect(code).not.toContain('
|
|
2058
|
+
expect(code).not.toContain('when({})');
|
|
2059
|
+
expect(code).not.toContain('when<');
|
|
1996
2060
|
});
|
|
1997
2061
|
describe('projection DSL generation', () => {
|
|
1998
2062
|
it('should generate fromSingletonProjection for singleton projections', async () => {
|
|
@@ -2025,10 +2089,13 @@ narrative('Todo List Summary', 'TODO-001', () => {
|
|
|
2025
2089
|
},
|
|
2026
2090
|
},
|
|
2027
2091
|
],
|
|
2028
|
-
specs:
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2092
|
+
specs: [
|
|
2093
|
+
{
|
|
2094
|
+
type: 'gherkin',
|
|
2095
|
+
feature: 'Summary Rules',
|
|
2096
|
+
rules: [],
|
|
2097
|
+
},
|
|
2098
|
+
],
|
|
2032
2099
|
},
|
|
2033
2100
|
},
|
|
2034
2101
|
],
|
|
@@ -2095,10 +2162,13 @@ narrative('Todo Summary Flow', 'TODO-SUMMARY', () => {
|
|
|
2095
2162
|
},
|
|
2096
2163
|
},
|
|
2097
2164
|
],
|
|
2098
|
-
specs:
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2165
|
+
specs: [
|
|
2166
|
+
{
|
|
2167
|
+
type: 'gherkin',
|
|
2168
|
+
feature: 'Todo Rules',
|
|
2169
|
+
rules: [],
|
|
2170
|
+
},
|
|
2171
|
+
],
|
|
2102
2172
|
},
|
|
2103
2173
|
},
|
|
2104
2174
|
],
|
|
@@ -2165,10 +2235,13 @@ narrative('Todo Flow', 'TODO-FLOW', () => {
|
|
|
2165
2235
|
},
|
|
2166
2236
|
},
|
|
2167
2237
|
],
|
|
2168
|
-
specs:
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2238
|
+
specs: [
|
|
2239
|
+
{
|
|
2240
|
+
type: 'gherkin',
|
|
2241
|
+
feature: 'User Project Rules',
|
|
2242
|
+
rules: [],
|
|
2243
|
+
},
|
|
2244
|
+
],
|
|
2172
2245
|
},
|
|
2173
2246
|
},
|
|
2174
2247
|
],
|
|
@@ -2237,10 +2310,13 @@ narrative('User Project Flow', 'USER-PROJECT-FLOW', () => {
|
|
|
2237
2310
|
},
|
|
2238
2311
|
},
|
|
2239
2312
|
],
|
|
2240
|
-
specs:
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2313
|
+
specs: [
|
|
2314
|
+
{
|
|
2315
|
+
type: 'gherkin',
|
|
2316
|
+
feature: 'Summary Rules',
|
|
2317
|
+
rules: [],
|
|
2318
|
+
},
|
|
2319
|
+
],
|
|
2244
2320
|
},
|
|
2245
2321
|
},
|
|
2246
2322
|
{
|
|
@@ -2265,10 +2341,13 @@ narrative('User Project Flow', 'USER-PROJECT-FLOW', () => {
|
|
|
2265
2341
|
},
|
|
2266
2342
|
},
|
|
2267
2343
|
],
|
|
2268
|
-
specs:
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2344
|
+
specs: [
|
|
2345
|
+
{
|
|
2346
|
+
type: 'gherkin',
|
|
2347
|
+
feature: 'Todo Rules',
|
|
2348
|
+
rules: [],
|
|
2349
|
+
},
|
|
2350
|
+
],
|
|
2272
2351
|
},
|
|
2273
2352
|
},
|
|
2274
2353
|
{
|
|
@@ -2293,10 +2372,13 @@ narrative('User Project Flow', 'USER-PROJECT-FLOW', () => {
|
|
|
2293
2372
|
},
|
|
2294
2373
|
},
|
|
2295
2374
|
],
|
|
2296
|
-
specs:
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2375
|
+
specs: [
|
|
2376
|
+
{
|
|
2377
|
+
type: 'gherkin',
|
|
2378
|
+
feature: 'User Project Rules',
|
|
2379
|
+
rules: [],
|
|
2380
|
+
},
|
|
2381
|
+
],
|
|
2300
2382
|
},
|
|
2301
2383
|
},
|
|
2302
2384
|
],
|