@auto-engineer/server-generator-apollo-emmett 0.10.3 → 0.10.5
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/CHANGELOG.md +16 -0
- package/dist/src/codegen/extract/events.d.ts +2 -2
- package/dist/src/codegen/extract/events.d.ts.map +1 -1
- package/dist/src/codegen/extract/events.js +16 -6
- package/dist/src/codegen/extract/events.js.map +1 -1
- package/dist/src/codegen/extract/gwt.js +7 -22
- package/dist/src/codegen/extract/gwt.js.map +1 -1
- package/dist/src/codegen/extract/imports.d.ts +29 -0
- package/dist/src/codegen/extract/imports.d.ts.map +1 -0
- package/dist/src/codegen/extract/imports.js +55 -0
- package/dist/src/codegen/extract/imports.js.map +1 -0
- package/dist/src/codegen/extract/index.d.ts +1 -0
- package/dist/src/codegen/extract/index.d.ts.map +1 -1
- package/dist/src/codegen/extract/index.js +1 -0
- package/dist/src/codegen/extract/index.js.map +1 -1
- package/dist/src/codegen/extract/messages.d.ts.map +1 -1
- package/dist/src/codegen/extract/messages.js +33 -7
- package/dist/src/codegen/extract/messages.js.map +1 -1
- package/dist/src/codegen/extract/query.d.ts +3 -1
- package/dist/src/codegen/extract/query.d.ts.map +1 -1
- package/dist/src/codegen/extract/query.js +12 -12
- package/dist/src/codegen/extract/query.js.map +1 -1
- package/dist/src/codegen/scaffoldFromSchema.d.ts.map +1 -1
- package/dist/src/codegen/scaffoldFromSchema.js +9 -1
- package/dist/src/codegen/scaffoldFromSchema.js.map +1 -1
- package/dist/src/codegen/templates/command/decide.specs.specs.ts +235 -8
- package/dist/src/codegen/templates/command/decide.specs.ts +8 -8
- package/dist/src/codegen/templates/command/decide.specs.ts.ejs +95 -30
- package/dist/src/codegen/templates/command/decide.ts.ejs +2 -2
- package/dist/src/codegen/templates/command/events.ts.ejs +2 -2
- package/dist/src/codegen/templates/command/evolve.ts.ejs +3 -3
- package/dist/src/codegen/templates/command/handle.specs.ts +6 -6
- package/dist/src/codegen/templates/command/handle.ts.ejs +3 -3
- package/dist/src/codegen/templates/query/projection.specs.specs.ts +623 -0
- package/dist/src/codegen/templates/query/projection.specs.ts.ejs +174 -52
- package/dist/src/codegen/templates/query/projection.ts.ejs +30 -29
- package/dist/src/codegen/templates/react/react.specs.specs.ts +7 -4
- package/dist/src/codegen/templates/react/react.specs.ts.ejs +118 -67
- package/dist/src/codegen/types.d.ts +2 -0
- package/dist/src/codegen/types.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/src/codegen/extract/events.ts +20 -3
- package/src/codegen/extract/gwt.ts +10 -26
- package/src/codegen/extract/imports.ts +71 -0
- package/src/codegen/extract/index.ts +1 -0
- package/src/codegen/extract/messages.ts +34 -7
- package/src/codegen/extract/query.ts +17 -19
- package/src/codegen/scaffoldFromSchema.ts +13 -0
- package/src/codegen/templates/command/decide.specs.specs.ts +235 -8
- package/src/codegen/templates/command/decide.specs.ts +8 -8
- package/src/codegen/templates/command/decide.specs.ts.ejs +95 -30
- package/src/codegen/templates/command/decide.ts.ejs +2 -2
- package/src/codegen/templates/command/events.ts.ejs +2 -2
- package/src/codegen/templates/command/evolve.ts.ejs +3 -3
- package/src/codegen/templates/command/handle.specs.ts +6 -6
- package/src/codegen/templates/command/handle.ts.ejs +3 -3
- package/src/codegen/templates/query/projection.specs.specs.ts +623 -0
- package/src/codegen/templates/query/projection.specs.ts.ejs +174 -52
- package/src/codegen/templates/query/projection.ts.ejs +30 -29
- package/src/codegen/templates/react/react.specs.specs.ts +7 -4
- package/src/codegen/templates/react/react.specs.ts.ejs +118 -67
- package/src/codegen/types.ts +2 -0
- package/dist/src/codegen/scaffoldFromSchema.query-slice-register.specs.d.ts +0 -2
- package/dist/src/codegen/scaffoldFromSchema.query-slice-register.specs.d.ts.map +0 -1
- package/dist/src/codegen/scaffoldFromSchema.query-slice-register.specs.js +0 -168
- package/dist/src/codegen/scaffoldFromSchema.query-slice-register.specs.js.map +0 -1
- package/dist/src/codegen/templates/query/projection.specs.specs..ts +0 -296
- package/src/codegen/scaffoldFromSchema.query-slice-register.specs.ts +0 -179
- package/src/codegen/templates/query/projection.specs.specs..ts +0 -296
|
@@ -99,16 +99,20 @@ describe('spec.ts.ejs', () => {
|
|
|
99
99
|
import { DeciderSpecification } from '@event-driven-io/emmett';
|
|
100
100
|
import { decide } from './decide';
|
|
101
101
|
import { evolve } from './evolve';
|
|
102
|
-
import { initialState } from './state';
|
|
102
|
+
import { initialState, State } from './state';
|
|
103
|
+
import type { ListingCreated } from './events';
|
|
104
|
+
import type { CreateListing } from './commands';
|
|
103
105
|
|
|
104
|
-
describe('
|
|
105
|
-
|
|
106
|
+
describe('Should create listing successfully', () => {
|
|
107
|
+
type Events = ListingCreated;
|
|
108
|
+
|
|
109
|
+
const given = DeciderSpecification.for<CreateListing, Events, State>({
|
|
106
110
|
decide,
|
|
107
111
|
evolve,
|
|
108
112
|
initialState,
|
|
109
113
|
});
|
|
110
114
|
|
|
111
|
-
it('
|
|
115
|
+
it('User creates listing with valid data', () => {
|
|
112
116
|
given([])
|
|
113
117
|
.when({
|
|
114
118
|
type: 'CreateListing',
|
|
@@ -237,16 +241,20 @@ describe('spec.ts.ejs', () => {
|
|
|
237
241
|
import { DeciderSpecification } from '@event-driven-io/emmett';
|
|
238
242
|
import { decide } from './decide';
|
|
239
243
|
import { evolve } from './evolve';
|
|
240
|
-
import { initialState } from './state';
|
|
244
|
+
import { initialState, State } from './state';
|
|
245
|
+
import type { ListingCreated, ListingRemoved } from './events';
|
|
246
|
+
import type { RemoveListing } from './commands';
|
|
247
|
+
|
|
248
|
+
describe('Should remove existing listing', () => {
|
|
249
|
+
type Events = ListingCreated | ListingRemoved;
|
|
241
250
|
|
|
242
|
-
|
|
243
|
-
const given = DeciderSpecification.for({
|
|
251
|
+
const given = DeciderSpecification.for<RemoveListing, Events, State>({
|
|
244
252
|
decide,
|
|
245
253
|
evolve,
|
|
246
254
|
initialState,
|
|
247
255
|
});
|
|
248
256
|
|
|
249
|
-
it('
|
|
257
|
+
it('Existing listing can be removed', () => {
|
|
250
258
|
given([
|
|
251
259
|
{
|
|
252
260
|
type: 'ListingCreated',
|
|
@@ -280,4 +288,223 @@ describe('spec.ts.ejs', () => {
|
|
|
280
288
|
"
|
|
281
289
|
`);
|
|
282
290
|
});
|
|
291
|
+
|
|
292
|
+
it('should generate separate tests for multiple examples with different scenarios', async () => {
|
|
293
|
+
const spec: SpecsSchema = {
|
|
294
|
+
variant: 'specs',
|
|
295
|
+
flows: [
|
|
296
|
+
{
|
|
297
|
+
name: 'Questionnaires',
|
|
298
|
+
slices: [
|
|
299
|
+
{
|
|
300
|
+
type: 'command',
|
|
301
|
+
name: 'submits a questionnaire answer',
|
|
302
|
+
client: { description: '' },
|
|
303
|
+
server: {
|
|
304
|
+
description: '',
|
|
305
|
+
specs: {
|
|
306
|
+
name: 'Answer question spec',
|
|
307
|
+
rules: [
|
|
308
|
+
{
|
|
309
|
+
description: 'answers are allowed while the questionnaire has not been submitted',
|
|
310
|
+
examples: [
|
|
311
|
+
{
|
|
312
|
+
description: 'no questions have been answered yet',
|
|
313
|
+
when: {
|
|
314
|
+
commandRef: 'AnswerQuestion',
|
|
315
|
+
exampleData: {
|
|
316
|
+
questionnaireId: 'q-001',
|
|
317
|
+
participantId: 'participant-abc',
|
|
318
|
+
questionId: 'q1',
|
|
319
|
+
answer: 'Yes',
|
|
320
|
+
},
|
|
321
|
+
},
|
|
322
|
+
then: [
|
|
323
|
+
{
|
|
324
|
+
eventRef: 'QuestionAnswered',
|
|
325
|
+
exampleData: {
|
|
326
|
+
questionnaireId: 'q-001',
|
|
327
|
+
participantId: 'participant-abc',
|
|
328
|
+
questionId: 'q1',
|
|
329
|
+
answer: 'Yes',
|
|
330
|
+
savedAt: '2030-01-01T09:05:00.000Z',
|
|
331
|
+
},
|
|
332
|
+
},
|
|
333
|
+
],
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
description: 'all questions have already been answered and submitted',
|
|
337
|
+
given: [
|
|
338
|
+
{
|
|
339
|
+
eventRef: 'QuestionnaireSubmitted',
|
|
340
|
+
exampleData: {
|
|
341
|
+
questionnaireId: 'q-001',
|
|
342
|
+
participantId: 'participant-abc',
|
|
343
|
+
submittedAt: '2030-01-01T09:00:00.000Z',
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
],
|
|
347
|
+
when: {
|
|
348
|
+
commandRef: 'AnswerQuestion',
|
|
349
|
+
exampleData: {
|
|
350
|
+
questionnaireId: 'q-001',
|
|
351
|
+
participantId: 'participant-abc',
|
|
352
|
+
questionId: 'q1',
|
|
353
|
+
answer: 'Yes',
|
|
354
|
+
},
|
|
355
|
+
},
|
|
356
|
+
then: [
|
|
357
|
+
{
|
|
358
|
+
eventRef: 'QuestionnaireEditRejected',
|
|
359
|
+
exampleData: {
|
|
360
|
+
questionnaireId: 'q-001',
|
|
361
|
+
participantId: 'participant-abc',
|
|
362
|
+
reason: 'Questionnaire already submitted',
|
|
363
|
+
attemptedAt: '2030-01-01T09:05:00.000Z',
|
|
364
|
+
},
|
|
365
|
+
},
|
|
366
|
+
],
|
|
367
|
+
},
|
|
368
|
+
],
|
|
369
|
+
},
|
|
370
|
+
],
|
|
371
|
+
},
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
],
|
|
375
|
+
},
|
|
376
|
+
],
|
|
377
|
+
messages: [
|
|
378
|
+
{
|
|
379
|
+
type: 'command',
|
|
380
|
+
name: 'AnswerQuestion',
|
|
381
|
+
fields: [
|
|
382
|
+
{ name: 'questionnaireId', type: 'string', required: true },
|
|
383
|
+
{ name: 'participantId', type: 'string', required: true },
|
|
384
|
+
{ name: 'questionId', type: 'string', required: true },
|
|
385
|
+
{ name: 'answer', type: 'unknown', required: true },
|
|
386
|
+
],
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
type: 'event',
|
|
390
|
+
name: 'QuestionAnswered',
|
|
391
|
+
source: 'internal',
|
|
392
|
+
fields: [
|
|
393
|
+
{ name: 'questionnaireId', type: 'string', required: true },
|
|
394
|
+
{ name: 'participantId', type: 'string', required: true },
|
|
395
|
+
{ name: 'questionId', type: 'string', required: true },
|
|
396
|
+
{ name: 'answer', type: 'unknown', required: true },
|
|
397
|
+
{ name: 'savedAt', type: 'Date', required: true },
|
|
398
|
+
],
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
type: 'event',
|
|
402
|
+
name: 'QuestionnaireSubmitted',
|
|
403
|
+
source: 'internal',
|
|
404
|
+
fields: [
|
|
405
|
+
{ name: 'questionnaireId', type: 'string', required: true },
|
|
406
|
+
{ name: 'participantId', type: 'string', required: true },
|
|
407
|
+
{ name: 'submittedAt', type: 'Date', required: true },
|
|
408
|
+
],
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
type: 'event',
|
|
412
|
+
name: 'QuestionnaireEditRejected',
|
|
413
|
+
source: 'internal',
|
|
414
|
+
fields: [
|
|
415
|
+
{ name: 'questionnaireId', type: 'string', required: true },
|
|
416
|
+
{ name: 'participantId', type: 'string', required: true },
|
|
417
|
+
{ name: 'reason', type: 'string', required: true },
|
|
418
|
+
{ name: 'attemptedAt', type: 'Date', required: true },
|
|
419
|
+
],
|
|
420
|
+
},
|
|
421
|
+
],
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
const plans = await generateScaffoldFilePlans(spec.flows, spec.messages, undefined, 'src/domain/flows');
|
|
425
|
+
const specFile = plans.find((p) => p.outputPath.endsWith('specs.ts'));
|
|
426
|
+
|
|
427
|
+
expect(specFile?.contents).toMatchInlineSnapshot(`
|
|
428
|
+
"import { describe, it } from 'vitest';
|
|
429
|
+
import { DeciderSpecification } from '@event-driven-io/emmett';
|
|
430
|
+
import { decide } from './decide';
|
|
431
|
+
import { evolve } from './evolve';
|
|
432
|
+
import { initialState, State } from './state';
|
|
433
|
+
import type { QuestionAnswered, QuestionnaireEditRejected, QuestionnaireSubmitted } from './events';
|
|
434
|
+
import type { AnswerQuestion } from './commands';
|
|
435
|
+
|
|
436
|
+
describe('answers are allowed while the questionnaire has not been submitted', () => {
|
|
437
|
+
type Events = QuestionAnswered | QuestionnaireEditRejected | QuestionnaireSubmitted;
|
|
438
|
+
|
|
439
|
+
const given = DeciderSpecification.for<AnswerQuestion, Events, State>({
|
|
440
|
+
decide,
|
|
441
|
+
evolve,
|
|
442
|
+
initialState,
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
it('no questions have been answered yet', () => {
|
|
446
|
+
given([])
|
|
447
|
+
.when({
|
|
448
|
+
type: 'AnswerQuestion',
|
|
449
|
+
data: {
|
|
450
|
+
questionnaireId: 'q-001',
|
|
451
|
+
participantId: 'participant-abc',
|
|
452
|
+
questionId: 'q1',
|
|
453
|
+
answer: 'Yes',
|
|
454
|
+
},
|
|
455
|
+
metadata: { now: new Date() },
|
|
456
|
+
})
|
|
457
|
+
|
|
458
|
+
.then([
|
|
459
|
+
{
|
|
460
|
+
type: 'QuestionAnswered',
|
|
461
|
+
data: {
|
|
462
|
+
questionnaireId: 'q-001',
|
|
463
|
+
participantId: 'participant-abc',
|
|
464
|
+
questionId: 'q1',
|
|
465
|
+
answer: 'Yes',
|
|
466
|
+
savedAt: new Date('2030-01-01T09:05:00.000Z'),
|
|
467
|
+
},
|
|
468
|
+
},
|
|
469
|
+
]);
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
it('all questions have already been answered and submitted', () => {
|
|
473
|
+
given([
|
|
474
|
+
{
|
|
475
|
+
type: 'QuestionnaireSubmitted',
|
|
476
|
+
data: {
|
|
477
|
+
questionnaireId: 'q-001',
|
|
478
|
+
participantId: 'participant-abc',
|
|
479
|
+
submittedAt: new Date('2030-01-01T09:00:00.000Z'),
|
|
480
|
+
},
|
|
481
|
+
},
|
|
482
|
+
])
|
|
483
|
+
.when({
|
|
484
|
+
type: 'AnswerQuestion',
|
|
485
|
+
data: {
|
|
486
|
+
questionnaireId: 'q-001',
|
|
487
|
+
participantId: 'participant-abc',
|
|
488
|
+
questionId: 'q1',
|
|
489
|
+
answer: 'Yes',
|
|
490
|
+
},
|
|
491
|
+
metadata: { now: new Date() },
|
|
492
|
+
})
|
|
493
|
+
|
|
494
|
+
.then([
|
|
495
|
+
{
|
|
496
|
+
type: 'QuestionnaireEditRejected',
|
|
497
|
+
data: {
|
|
498
|
+
questionnaireId: 'q-001',
|
|
499
|
+
participantId: 'participant-abc',
|
|
500
|
+
reason: 'Questionnaire already submitted',
|
|
501
|
+
attemptedAt: new Date('2030-01-01T09:05:00.000Z'),
|
|
502
|
+
},
|
|
503
|
+
},
|
|
504
|
+
]);
|
|
505
|
+
});
|
|
506
|
+
});
|
|
507
|
+
"
|
|
508
|
+
`);
|
|
509
|
+
});
|
|
283
510
|
});
|
|
@@ -81,7 +81,7 @@ describe('decide.ts.ejs', () => {
|
|
|
81
81
|
import type { CreateListing } from './commands';
|
|
82
82
|
import type { ListingCreated } from './events';
|
|
83
83
|
|
|
84
|
-
export const decide = (command: CreateListing,
|
|
84
|
+
export const decide = (command: CreateListing, _state: State): ListingCreated => {
|
|
85
85
|
switch (command.type) {
|
|
86
86
|
case 'CreateListing': {
|
|
87
87
|
/**
|
|
@@ -106,7 +106,7 @@ describe('decide.ts.ejs', () => {
|
|
|
106
106
|
throw new IllegalStateError('Not yet implemented: ' + command.type);
|
|
107
107
|
}
|
|
108
108
|
default:
|
|
109
|
-
throw new IllegalStateError(
|
|
109
|
+
throw new IllegalStateError(\`Unexpected command type: \${String(command.type)}\`);
|
|
110
110
|
}
|
|
111
111
|
};
|
|
112
112
|
"
|
|
@@ -206,7 +206,7 @@ describe('decide.ts.ejs', () => {
|
|
|
206
206
|
import type { RemoveListing } from './commands';
|
|
207
207
|
import type { ListingRemoved } from './events';
|
|
208
208
|
|
|
209
|
-
export const decide = (command: RemoveListing,
|
|
209
|
+
export const decide = (command: RemoveListing, _state: State): ListingRemoved => {
|
|
210
210
|
switch (command.type) {
|
|
211
211
|
case 'RemoveListing': {
|
|
212
212
|
/**
|
|
@@ -231,7 +231,7 @@ describe('decide.ts.ejs', () => {
|
|
|
231
231
|
throw new IllegalStateError('Not yet implemented: ' + command.type);
|
|
232
232
|
}
|
|
233
233
|
default:
|
|
234
|
-
throw new IllegalStateError(
|
|
234
|
+
throw new IllegalStateError(\`Unexpected command type: \${String(command.type)}\`);
|
|
235
235
|
}
|
|
236
236
|
};
|
|
237
237
|
"
|
|
@@ -346,7 +346,7 @@ describe('decide.ts.ejs', () => {
|
|
|
346
346
|
import type { CreateListing } from './commands';
|
|
347
347
|
import type { ListingCreated } from './events';
|
|
348
348
|
|
|
349
|
-
export const decide = (command: CreateListing,
|
|
349
|
+
export const decide = (command: CreateListing, _state: State): ListingCreated => {
|
|
350
350
|
switch (command.type) {
|
|
351
351
|
case 'CreateListing': {
|
|
352
352
|
/**
|
|
@@ -375,7 +375,7 @@ describe('decide.ts.ejs', () => {
|
|
|
375
375
|
throw new IllegalStateError('Not yet implemented: ' + command.type);
|
|
376
376
|
}
|
|
377
377
|
default:
|
|
378
|
-
throw new IllegalStateError(
|
|
378
|
+
throw new IllegalStateError(\`Unexpected command type: \${String(command.type)}\`);
|
|
379
379
|
}
|
|
380
380
|
};
|
|
381
381
|
"
|
|
@@ -532,7 +532,7 @@ describe('decide.ts.ejs', () => {
|
|
|
532
532
|
import type { ItemsSuggested } from './events';
|
|
533
533
|
import type { Products } from '@auto-engineer/product-catalogue-integration';
|
|
534
534
|
|
|
535
|
-
export const decide = (command: SuggestItems,
|
|
535
|
+
export const decide = (command: SuggestItems, _state: State, products?: Products): ItemsSuggested => {
|
|
536
536
|
switch (command.type) {
|
|
537
537
|
case 'SuggestItems': {
|
|
538
538
|
/**
|
|
@@ -566,7 +566,7 @@ describe('decide.ts.ejs', () => {
|
|
|
566
566
|
throw new IllegalStateError('Not yet implemented: ' + command.type);
|
|
567
567
|
}
|
|
568
568
|
default:
|
|
569
|
-
throw new IllegalStateError(
|
|
569
|
+
throw new IllegalStateError(\`Unexpected command type: \${String(command.type)}\`);
|
|
570
570
|
}
|
|
571
571
|
};
|
|
572
572
|
"
|
|
@@ -1,51 +1,116 @@
|
|
|
1
|
+
<%
|
|
2
|
+
const allEvents = [];
|
|
3
|
+
const ruleGroups = new Map();
|
|
4
|
+
for (const commandName in gwtMapping) {
|
|
5
|
+
const cases = gwtMapping[commandName];
|
|
6
|
+
for (const gwt of cases) {
|
|
7
|
+
const ruleDescription = gwt.ruleDescription || `${flowName} | ${sliceName}`;
|
|
8
|
+
if (!ruleGroups.has(ruleDescription)) {
|
|
9
|
+
ruleGroups.set(ruleDescription, []);
|
|
10
|
+
}
|
|
11
|
+
ruleGroups.get(ruleDescription).push({ commandName, gwt });
|
|
12
|
+
if (gwt.given && gwt.given.length) {
|
|
13
|
+
for (const g of gwt.given) {
|
|
14
|
+
if (g.eventRef) {
|
|
15
|
+
const event = events.find(e => e.type === g.eventRef);
|
|
16
|
+
if (event) allEvents.push(event);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
if (gwt.then) {
|
|
21
|
+
for (const t of gwt.then) {
|
|
22
|
+
if (t.eventRef) {
|
|
23
|
+
const event = events.find(e => e.type === t.eventRef);
|
|
24
|
+
if (event) allEvents.push(event);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const testEventImportGroups = [];
|
|
32
|
+
const testEventsByPath = new Map();
|
|
33
|
+
|
|
34
|
+
for (const event of allEvents) {
|
|
35
|
+
if (!event.type) continue;
|
|
36
|
+
const importGroup = eventImportGroups.find(group =>
|
|
37
|
+
group.eventTypes.includes(event.type)
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
if (importGroup) {
|
|
41
|
+
const path = importGroup.importPath;
|
|
42
|
+
if (!testEventsByPath.has(path)) {
|
|
43
|
+
testEventsByPath.set(path, []);
|
|
44
|
+
}
|
|
45
|
+
if (!testEventsByPath.get(path).includes(event.type)) {
|
|
46
|
+
testEventsByPath.get(path).push(event.type);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
for (const [importPath, eventTypes] of testEventsByPath.entries()) {
|
|
52
|
+
testEventImportGroups.push({ importPath, eventTypes: eventTypes.sort() });
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const uniqueEventTypes = Array.from(new Set(allEvents.map(e => e?.type).filter(Boolean))).sort();
|
|
56
|
+
_%>
|
|
1
57
|
import { describe, it } from 'vitest';
|
|
2
58
|
import { DeciderSpecification } from '@event-driven-io/emmett';
|
|
3
59
|
import { decide } from './decide';
|
|
4
60
|
import { evolve } from './evolve';
|
|
5
|
-
import { initialState } from './state';
|
|
61
|
+
import { initialState, State } from './state';
|
|
62
|
+
<% for (const group of testEventImportGroups) { -%>
|
|
63
|
+
import type { <%= group.eventTypes.join(', ') %> } from '<%= group.importPath %>';
|
|
64
|
+
<% } -%>
|
|
65
|
+
import type { <%= Object.keys(commandSchemasByName).join(', ') %> } from './commands';
|
|
66
|
+
<% for (const [ruleDescription, ruleGwts] of ruleGroups.entries()) { %>
|
|
67
|
+
describe('<%= ruleDescription %>', () => {
|
|
6
68
|
|
|
7
|
-
|
|
8
|
-
const given = DeciderSpecification.for({
|
|
9
|
-
decide,
|
|
10
|
-
evolve,
|
|
11
|
-
initialState,
|
|
12
|
-
});
|
|
69
|
+
type Events = <%= uniqueEventTypes.length > 0 ? uniqueEventTypes.join(' | ') : 'never' %>;
|
|
13
70
|
|
|
14
|
-
|
|
15
|
-
|
|
71
|
+
const given = DeciderSpecification.for<<%= Object.keys(commandSchemasByName).length === 1 ? Object.keys(commandSchemasByName)[0] : `(${Object.keys(commandSchemasByName).join(' | ')})` %>, Events, State>({
|
|
72
|
+
decide,
|
|
73
|
+
evolve,
|
|
74
|
+
initialState,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
<% for (const { commandName, gwt } of ruleGwts) {
|
|
16
78
|
const schema = commandSchemasByName[commandName];
|
|
17
|
-
for (const [i, gwt] of cases.entries()) {
|
|
18
79
|
const example = gwt.when;
|
|
19
80
|
const eventResults = gwt.then.filter(t => 'eventRef' in t);
|
|
20
81
|
const errorResult = gwt.then.find(t => 'errorType' in t);
|
|
21
|
-
|
|
82
|
+
|
|
83
|
+
const testDescription = gwt.description ||
|
|
84
|
+
(errorResult
|
|
22
85
|
? `should throw ${errorResult.errorType} when ${gwt.failingFields?.join(', ') || 'invalid input'}`
|
|
23
|
-
: `should emit ${eventResults.map(e => e.eventRef).join(', ')} for valid ${commandName}
|
|
86
|
+
: `should emit ${eventResults.map(e => e.eventRef).join(', ')} for valid ${commandName}`);
|
|
24
87
|
%>
|
|
25
|
-
it('
|
|
26
|
-
given([
|
|
88
|
+
it('<%= testDescription %>', () => {
|
|
89
|
+
given([
|
|
27
90
|
<%_ if (gwt.given && gwt.given.length) { _%>
|
|
28
|
-
|
|
91
|
+
<%- gwt.given.map(g => `{
|
|
29
92
|
type: '${g.eventRef}',
|
|
30
93
|
data: ${formatDataObject(g.exampleData, events.find(e => e.type === g.eventRef))}
|
|
31
94
|
}`).join(',\n ') %>
|
|
32
95
|
<%_ } _%>
|
|
33
|
-
])
|
|
34
|
-
.when({
|
|
35
|
-
type: '<%= example.commandRef %>',
|
|
36
|
-
data: <%- formatDataObject(example.exampleData, schema) %>,
|
|
37
|
-
metadata: { now: new Date() }
|
|
38
|
-
})
|
|
96
|
+
])
|
|
97
|
+
.when({
|
|
98
|
+
type: '<%= example.commandRef %>',
|
|
99
|
+
data: <%- formatDataObject(example.exampleData, schema) %>,
|
|
100
|
+
metadata: { now: new Date() },
|
|
101
|
+
})
|
|
39
102
|
<% if (errorResult) { %>
|
|
40
|
-
|
|
103
|
+
.thenThrows((err) => err instanceof <%= errorResult.errorType %> && err.message === '<%= errorResult.message || '' %>');
|
|
41
104
|
<% } else { %>
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
105
|
+
|
|
106
|
+
.then([
|
|
107
|
+
<%- eventResults.map(e => `{
|
|
108
|
+
type: '${e.eventRef}',
|
|
109
|
+
data: ${formatDataObject(e.exampleData, events.find(evt => evt.type === e.eventRef))}
|
|
110
|
+
}`).join(',\n ') %>
|
|
111
|
+
]);
|
|
112
|
+
<% } %>
|
|
113
|
+
});
|
|
48
114
|
<% } %>
|
|
49
115
|
});
|
|
50
|
-
<% }
|
|
51
|
-
});
|
|
116
|
+
<% } %>
|
|
@@ -45,7 +45,7 @@ function formatFieldDocLine(field) {
|
|
|
45
45
|
|
|
46
46
|
export const decide = (
|
|
47
47
|
command: <%= Object.keys(gwtMapping).map(pascalCase).join(' | ') %>,
|
|
48
|
-
|
|
48
|
+
_state: State<%= integrationReturnType ? `,\n ${camelCase(integrationReturnType)}?: ${integrationReturnType}` : '' %>
|
|
49
49
|
): <%= uniqueEventTypes.length === 0
|
|
50
50
|
? 'never'
|
|
51
51
|
: uniqueEventTypes.length === 1
|
|
@@ -102,6 +102,6 @@ throw new IllegalStateError('Not yet implemented: ' + command.type);
|
|
|
102
102
|
}
|
|
103
103
|
<% } -%>
|
|
104
104
|
default:
|
|
105
|
-
throw new IllegalStateError(
|
|
105
|
+
throw new IllegalStateError(`Unexpected command type: ${String(command.type)}`);
|
|
106
106
|
}
|
|
107
107
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
<% if (
|
|
1
|
+
<% if (localEvents.length) { -%>
|
|
2
2
|
import type { Event } from '@event-driven-io/emmett';
|
|
3
3
|
|
|
4
|
-
<% for (const event of
|
|
4
|
+
<% for (const event of localEvents) { -%>
|
|
5
5
|
export type <%= pascalCase(event.type) %> = Event<
|
|
6
6
|
'<%= event.type %>',
|
|
7
7
|
{
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<% if (events.length) { -%>
|
|
2
2
|
import type { State } from './state';
|
|
3
|
-
<%
|
|
4
|
-
import type { <%= pascalCase(
|
|
5
|
-
<% }
|
|
3
|
+
<% for (const group of eventImportGroups) { -%>
|
|
4
|
+
import type { <%= group.eventTypes.map(name => pascalCase(name)).join(', ') %> } from '<%= group.importPath %>';
|
|
5
|
+
<% } -%>
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* ## IMPLEMENTATION INSTRUCTIONS ##
|
|
@@ -117,11 +117,11 @@ describe('generateScaffoldFilePlans', () => {
|
|
|
117
117
|
|
|
118
118
|
try {
|
|
119
119
|
await handler(eventStore, streamId, (state) => decide(command, state));
|
|
120
|
-
return; // success
|
|
121
|
-
} catch (error:
|
|
120
|
+
return undefined; // success
|
|
121
|
+
} catch (error: unknown) {
|
|
122
122
|
return {
|
|
123
123
|
type: 'SKIP',
|
|
124
|
-
reason: \`Command failed: \${error
|
|
124
|
+
reason: \`Command failed: \${error instanceof Error ? error.message : 'Unknown'}\`,
|
|
125
125
|
};
|
|
126
126
|
}
|
|
127
127
|
};
|
|
@@ -315,11 +315,11 @@ describe('generateScaffoldFilePlans', () => {
|
|
|
315
315
|
// TODO: add products as a parameter to decide once implemented above
|
|
316
316
|
decide(command, state /* products */),
|
|
317
317
|
);
|
|
318
|
-
return; // success
|
|
319
|
-
} catch (error:
|
|
318
|
+
return undefined; // success
|
|
319
|
+
} catch (error: unknown) {
|
|
320
320
|
return {
|
|
321
321
|
type: 'SKIP',
|
|
322
|
-
reason: \`Command failed: \${error
|
|
322
|
+
reason: \`Command failed: \${error instanceof Error ? error.message : 'Unknown'}\`,
|
|
323
323
|
};
|
|
324
324
|
}
|
|
325
325
|
};
|
|
@@ -101,11 +101,11 @@ command: <%= commands.map(c => pascalCase(c.type)).join(' | ') %>
|
|
|
101
101
|
? ` // TODO: add ${resultVarName} as a parameter to decide once implemented above\n decide(command, state, /* ${resultVarName} */)`
|
|
102
102
|
: ` decide(command, state)` %>
|
|
103
103
|
);
|
|
104
|
-
return; // success
|
|
105
|
-
} catch (error:
|
|
104
|
+
return undefined; // success
|
|
105
|
+
} catch (error: unknown) {
|
|
106
106
|
return {
|
|
107
107
|
type: 'SKIP',
|
|
108
|
-
reason: `Command failed: ${error
|
|
108
|
+
reason: `Command failed: ${error instanceof Error ? error.message : 'Unknown'}`,
|
|
109
109
|
};
|
|
110
110
|
}
|
|
111
111
|
};
|