@event-driven-io/emmett-expressjs 0.4.0 → 0.5.0

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.
Files changed (50) hide show
  1. package/dist/e2e/decider/api.d.ts +6 -12
  2. package/dist/e2e/decider/api.js +79 -145
  3. package/dist/e2e/decider/api.js.map +1 -1
  4. package/dist/e2e/decider/applicationLogicWithOC.int.spec.js +132 -124
  5. package/dist/e2e/decider/applicationLogicWithOC.int.spec.js.map +1 -1
  6. package/dist/e2e/decider/applicationLogicWithOC.int.spec.mjs +0 -1
  7. package/dist/e2e/decider/applicationLogicWithOC.int.spec.mjs.map +1 -1
  8. package/dist/e2e/decider/businessLogic.js +89 -101
  9. package/dist/e2e/decider/businessLogic.js.map +1 -1
  10. package/dist/e2e/decider/shoppingCart.js +73 -89
  11. package/dist/e2e/decider/shoppingCart.js.map +1 -1
  12. package/dist/e2e/testing.js +23 -28
  13. package/dist/e2e/testing.js.map +1 -1
  14. package/dist/etag.js +54 -59
  15. package/dist/etag.js.map +1 -1
  16. package/dist/handler.d.mts +3 -1
  17. package/dist/handler.d.ts +3 -1
  18. package/dist/handler.js.map +1 -1
  19. package/dist/handler.mjs.map +1 -1
  20. package/dist/index.d.mts +7 -5
  21. package/dist/index.d.ts +7 -5
  22. package/dist/middlewares/problemDetailsMiddleware.d.mts +3 -1
  23. package/dist/middlewares/problemDetailsMiddleware.d.ts +3 -1
  24. package/dist/middlewares/problemDetailsMiddleware.js +19 -22
  25. package/dist/middlewares/problemDetailsMiddleware.js.map +1 -1
  26. package/dist/testing/apiE2ESpecification.d.mts +17 -0
  27. package/dist/testing/apiE2ESpecification.d.ts +17 -0
  28. package/dist/testing/apiE2ESpecification.js +34 -0
  29. package/dist/testing/apiE2ESpecification.js.map +1 -0
  30. package/dist/testing/apiE2ESpecification.mjs +37 -0
  31. package/dist/testing/apiE2ESpecification.mjs.map +1 -0
  32. package/dist/testing/apiSpecification.d.mts +4 -7
  33. package/dist/testing/apiSpecification.d.ts +4 -7
  34. package/dist/testing/apiSpecification.js +59 -98
  35. package/dist/testing/apiSpecification.js.map +1 -1
  36. package/dist/testing/apiSpecification.mjs +5 -32
  37. package/dist/testing/apiSpecification.mjs.map +1 -1
  38. package/dist/testing/index.d.mts +5 -3
  39. package/dist/testing/index.d.ts +5 -3
  40. package/dist/testing/index.js +2 -1
  41. package/dist/testing/index.js.map +1 -1
  42. package/dist/testing/index.mjs +1 -0
  43. package/dist/testing/index.mjs.map +1 -1
  44. package/dist/testing/utils.d.mts +12 -0
  45. package/dist/testing/utils.d.ts +12 -0
  46. package/dist/testing/utils.js +25 -0
  47. package/dist/testing/utils.js.map +1 -0
  48. package/dist/testing/utils.mjs +32 -0
  49. package/dist/testing/utils.mjs.map +1 -0
  50. package/package.json +2 -2
@@ -1,12 +1,6 @@
1
- import * as _event_driven_io_emmett_dist_eventStore_N_YMFCDT from '@event-driven-io/emmett/dist/eventStore-N_YMFCDT';
2
- import { ShoppingCartCommand } from './businessLogic.js';
3
- import { EventStore } from '@event-driven-io/emmett';
4
- import { Router } from 'express';
5
- import './shoppingCart.js';
6
-
7
- declare const handle: (eventStore: EventStore<bigint>, id: string, command: ShoppingCartCommand, options?: {
8
- expectedStreamVersion?: _event_driven_io_emmett_dist_eventStore_N_YMFCDT.e<bigint> | undefined;
9
- } | undefined) => Promise<_event_driven_io_emmett_dist_eventStore_N_YMFCDT.d<bigint>>;
10
- declare const shoppingCartApi: (eventStore: EventStore) => (router: Router) => void;
11
-
12
- export { handle, shoppingCartApi };
1
+ import { type EventStore } from '@event-driven-io/emmett';
2
+ import { type Router } from 'express';
3
+ export declare const handle: (eventStore: EventStore<bigint>, id: string, command: import("./businessLogic").ShoppingCartCommand, options?: {
4
+ expectedStreamVersion?: import("packages/emmett/dist/eventStore-N_YMFCDT").e<bigint> | undefined;
5
+ } | undefined) => Promise<import("packages/emmett/dist/commandHandling/handleCommand").CommandHandlerResult<import("./shoppingCart").ShoppingCart, bigint>>;
6
+ export declare const shoppingCartApi: (eventStore: EventStore) => (router: Router) => void;
@@ -1,149 +1,83 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
-
3
-
4
-
5
-
6
-
7
- var _emmett = require('@event-driven-io/emmett');
8
- require('express');
9
-
10
-
11
-
12
-
13
-
14
-
15
- var _ = require('../../');
16
- var _businessLogic = require('./businessLogic');
17
- require('./shoppingCart');
18
- const handle = _emmett.DeciderCommandHandler.call(void 0, _businessLogic.decider);
1
+ import { DeciderCommandHandler, STREAM_DOES_NOT_EXIST, assertNotEmptyString, assertPositiveNumber, assertUnsignedBigInt, } from '@event-driven-io/emmett';
2
+ import {} from 'express';
3
+ import { Created, NoContent, getETagValueFromIfMatch, on, toWeakETag, } from '../../';
4
+ import { decider } from './businessLogic';
5
+ import {} from './shoppingCart';
6
+ export const handle = DeciderCommandHandler(decider);
19
7
  const dummyPriceProvider = (_productId) => {
20
- return 100;
8
+ return 100;
21
9
  };
22
- const shoppingCartApi = (eventStore) => (router) => {
23
- router.post(
24
- "/clients/:clientId/shopping-carts/",
25
- _.on.call(void 0, async (request) => {
26
- const clientId = _emmett.assertNotEmptyString.call(void 0, request.params.clientId);
27
- const shoppingCartId = clientId;
28
- const result = await handle(
29
- eventStore,
30
- shoppingCartId,
31
- {
32
- type: "OpenShoppingCart",
33
- data: { clientId, shoppingCartId, now: /* @__PURE__ */ new Date() }
34
- },
35
- { expectedStreamVersion: _emmett.STREAM_DOES_NOT_EXIST }
36
- );
37
- return _.Created.call(void 0, {
38
- createdId: shoppingCartId,
39
- eTag: _.toWeakETag.call(void 0, result.nextExpectedStreamVersion)
40
- });
41
- })
42
- );
43
- router.post(
44
- "/clients/:clientId/shopping-carts/:shoppingCartId/product-items",
45
- _.on.call(void 0, async (request) => {
46
- const shoppingCartId = _emmett.assertNotEmptyString.call(void 0,
47
- request.params.shoppingCartId
48
- );
49
- const productItem = {
50
- productId: _emmett.assertNotEmptyString.call(void 0, request.body.productId),
51
- quantity: _emmett.assertPositiveNumber.call(void 0, request.body.quantity)
52
- };
53
- const unitPrice = dummyPriceProvider(productItem.productId);
54
- const result = await handle(
55
- eventStore,
56
- shoppingCartId,
57
- {
58
- type: "AddProductItemToShoppingCart",
59
- data: {
60
- shoppingCartId,
61
- productItem: { ...productItem, unitPrice }
62
- }
63
- },
64
- {
65
- expectedStreamVersion: _emmett.assertUnsignedBigInt.call(void 0,
66
- _.getETagValueFromIfMatch.call(void 0, request)
67
- )
68
- }
69
- );
70
- return _.NoContent.call(void 0, { eTag: _.toWeakETag.call(void 0, result.nextExpectedStreamVersion) });
71
- })
72
- );
73
- router.delete(
74
- "/clients/:clientId/shopping-carts/:shoppingCartId/product-items",
75
- _.on.call(void 0, async (request) => {
76
- const shoppingCartId = _emmett.assertNotEmptyString.call(void 0,
77
- request.params.shoppingCartId
78
- );
79
- const productItem = {
80
- productId: _emmett.assertNotEmptyString.call(void 0, request.query.productId),
81
- quantity: _emmett.assertPositiveNumber.call(void 0, Number(request.query.quantity)),
82
- unitPrice: _emmett.assertPositiveNumber.call(void 0, Number(request.query.unitPrice))
83
- };
84
- const result = await handle(
85
- eventStore,
86
- shoppingCartId,
87
- {
88
- type: "RemoveProductItemFromShoppingCart",
89
- data: { shoppingCartId, productItem }
90
- },
91
- {
92
- expectedStreamVersion: _emmett.assertUnsignedBigInt.call(void 0,
93
- _.getETagValueFromIfMatch.call(void 0, request)
94
- )
95
- }
96
- );
97
- return _.NoContent.call(void 0, { eTag: _.toWeakETag.call(void 0, result.nextExpectedStreamVersion) });
98
- })
99
- );
100
- router.post(
101
- "/clients/:clientId/shopping-carts/:shoppingCartId/confirm",
102
- _.on.call(void 0, async (request) => {
103
- const shoppingCartId = _emmett.assertNotEmptyString.call(void 0,
104
- request.params.shoppingCartId
105
- );
106
- const result = await handle(
107
- eventStore,
108
- shoppingCartId,
109
- {
110
- type: "ConfirmShoppingCart",
111
- data: { shoppingCartId, now: /* @__PURE__ */ new Date() }
112
- },
113
- {
114
- expectedStreamVersion: _emmett.assertUnsignedBigInt.call(void 0,
115
- _.getETagValueFromIfMatch.call(void 0, request)
116
- )
117
- }
118
- );
119
- return _.NoContent.call(void 0, { eTag: _.toWeakETag.call(void 0, result.nextExpectedStreamVersion) });
120
- })
121
- );
122
- router.delete(
123
- "/clients/:clientId/shopping-carts/:shoppingCartId",
124
- _.on.call(void 0, async (request) => {
125
- const shoppingCartId = _emmett.assertNotEmptyString.call(void 0,
126
- request.params.shoppingCartId
127
- );
128
- const result = await handle(
129
- eventStore,
130
- shoppingCartId,
131
- {
132
- type: "CancelShoppingCart",
133
- data: { shoppingCartId, now: /* @__PURE__ */ new Date() }
134
- },
135
- {
136
- expectedStreamVersion: _emmett.assertUnsignedBigInt.call(void 0,
137
- _.getETagValueFromIfMatch.call(void 0, request)
138
- )
139
- }
140
- );
141
- return _.NoContent.call(void 0, { eTag: _.toWeakETag.call(void 0, result.nextExpectedStreamVersion) });
142
- })
143
- );
10
+ export const shoppingCartApi = (eventStore) => (router) => {
11
+ // Open Shopping cart
12
+ // #region created-example
13
+ router.post('/clients/:clientId/shopping-carts/', on(async (request) => {
14
+ const clientId = assertNotEmptyString(request.params.clientId);
15
+ const shoppingCartId = clientId;
16
+ const result = await handle(eventStore, shoppingCartId, {
17
+ type: 'OpenShoppingCart',
18
+ data: { clientId, shoppingCartId, now: new Date() },
19
+ }, { expectedStreamVersion: STREAM_DOES_NOT_EXIST });
20
+ return Created({
21
+ createdId: shoppingCartId,
22
+ eTag: toWeakETag(result.nextExpectedStreamVersion),
23
+ });
24
+ }));
25
+ // #endregion created-example
26
+ router.post('/clients/:clientId/shopping-carts/:shoppingCartId/product-items', on(async (request) => {
27
+ const shoppingCartId = assertNotEmptyString(request.params.shoppingCartId);
28
+ const productItem = {
29
+ productId: assertNotEmptyString(request.body.productId),
30
+ quantity: assertPositiveNumber(request.body.quantity),
31
+ };
32
+ const unitPrice = dummyPriceProvider(productItem.productId);
33
+ const result = await handle(eventStore, shoppingCartId, {
34
+ type: 'AddProductItemToShoppingCart',
35
+ data: {
36
+ shoppingCartId,
37
+ productItem: { ...productItem, unitPrice },
38
+ },
39
+ }, {
40
+ expectedStreamVersion: assertUnsignedBigInt(getETagValueFromIfMatch(request)),
41
+ });
42
+ return NoContent({ eTag: toWeakETag(result.nextExpectedStreamVersion) });
43
+ }));
44
+ // Remove Product Item
45
+ router.delete('/clients/:clientId/shopping-carts/:shoppingCartId/product-items', on(async (request) => {
46
+ const shoppingCartId = assertNotEmptyString(request.params.shoppingCartId);
47
+ const productItem = {
48
+ productId: assertNotEmptyString(request.query.productId),
49
+ quantity: assertPositiveNumber(Number(request.query.quantity)),
50
+ unitPrice: assertPositiveNumber(Number(request.query.unitPrice)),
51
+ };
52
+ const result = await handle(eventStore, shoppingCartId, {
53
+ type: 'RemoveProductItemFromShoppingCart',
54
+ data: { shoppingCartId, productItem },
55
+ }, {
56
+ expectedStreamVersion: assertUnsignedBigInt(getETagValueFromIfMatch(request)),
57
+ });
58
+ return NoContent({ eTag: toWeakETag(result.nextExpectedStreamVersion) });
59
+ }));
60
+ // Confirm Shopping Cart
61
+ router.post('/clients/:clientId/shopping-carts/:shoppingCartId/confirm', on(async (request) => {
62
+ const shoppingCartId = assertNotEmptyString(request.params.shoppingCartId);
63
+ const result = await handle(eventStore, shoppingCartId, {
64
+ type: 'ConfirmShoppingCart',
65
+ data: { shoppingCartId, now: new Date() },
66
+ }, {
67
+ expectedStreamVersion: assertUnsignedBigInt(getETagValueFromIfMatch(request)),
68
+ });
69
+ return NoContent({ eTag: toWeakETag(result.nextExpectedStreamVersion) });
70
+ }));
71
+ // Cancel Shopping Cart
72
+ router.delete('/clients/:clientId/shopping-carts/:shoppingCartId', on(async (request) => {
73
+ const shoppingCartId = assertNotEmptyString(request.params.shoppingCartId);
74
+ const result = await handle(eventStore, shoppingCartId, {
75
+ type: 'CancelShoppingCart',
76
+ data: { shoppingCartId, now: new Date() },
77
+ }, {
78
+ expectedStreamVersion: assertUnsignedBigInt(getETagValueFromIfMatch(request)),
79
+ });
80
+ return NoContent({ eTag: toWeakETag(result.nextExpectedStreamVersion) });
81
+ }));
144
82
  };
145
-
146
-
147
-
148
- exports.handle = handle; exports.shoppingCartApi = shoppingCartApi;
149
83
  //# sourceMappingURL=api.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/e2e/decider/api.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n DeciderCommandHandler,\n STREAM_DOES_NOT_EXIST,\n assertNotEmptyString,\n assertPositiveNumber,\n assertUnsignedBigInt,\n type EventStore,\n} from '@event-driven-io/emmett';\nimport { type Request, type Router } from 'express';\nimport {\n Created,\n NoContent,\n getETagValueFromIfMatch,\n on,\n toWeakETag,\n} from '../../';\nimport { decider } from './businessLogic';\nimport { type PricedProductItem, type ProductItem } from './shoppingCart';\n\nexport const handle = DeciderCommandHandler(decider);\n\nconst dummyPriceProvider = (_productId: string) => {\n return 100;\n};\n\nexport const shoppingCartApi = (eventStore: EventStore) => (router: Router) => {\n // Open Shopping cart\n // #region created-example\n router.post(\n '/clients/:clientId/shopping-carts/',\n on(async (request: Request) => {\n const clientId = assertNotEmptyString(request.params.clientId);\n const shoppingCartId = clientId;\n\n const result = await handle(\n eventStore,\n shoppingCartId,\n {\n type: 'OpenShoppingCart',\n data: { clientId, shoppingCartId, now: new Date() },\n },\n { expectedStreamVersion: STREAM_DOES_NOT_EXIST },\n );\n\n return Created({\n createdId: shoppingCartId,\n eTag: toWeakETag(result.nextExpectedStreamVersion),\n });\n }),\n );\n // #endregion created-example\n\n router.post(\n '/clients/:clientId/shopping-carts/:shoppingCartId/product-items',\n on(async (request: AddProductItemRequest) => {\n const shoppingCartId = assertNotEmptyString(\n request.params.shoppingCartId,\n );\n const productItem: ProductItem = {\n productId: assertNotEmptyString(request.body.productId),\n quantity: assertPositiveNumber(request.body.quantity),\n };\n const unitPrice = dummyPriceProvider(productItem.productId);\n\n const result = await handle(\n eventStore,\n shoppingCartId,\n {\n type: 'AddProductItemToShoppingCart',\n data: {\n shoppingCartId,\n productItem: { ...productItem, unitPrice },\n },\n },\n {\n expectedStreamVersion: assertUnsignedBigInt(\n getETagValueFromIfMatch(request),\n ),\n },\n );\n\n return NoContent({ eTag: toWeakETag(result.nextExpectedStreamVersion) });\n }),\n );\n\n // Remove Product Item\n router.delete(\n '/clients/:clientId/shopping-carts/:shoppingCartId/product-items',\n on(async (request: Request) => {\n const shoppingCartId = assertNotEmptyString(\n request.params.shoppingCartId,\n );\n const productItem: PricedProductItem = {\n productId: assertNotEmptyString(request.query.productId),\n quantity: assertPositiveNumber(Number(request.query.quantity)),\n unitPrice: assertPositiveNumber(Number(request.query.unitPrice)),\n };\n\n const result = await handle(\n eventStore,\n shoppingCartId,\n {\n type: 'RemoveProductItemFromShoppingCart',\n data: { shoppingCartId, productItem },\n },\n {\n expectedStreamVersion: assertUnsignedBigInt(\n getETagValueFromIfMatch(request),\n ),\n },\n );\n\n return NoContent({ eTag: toWeakETag(result.nextExpectedStreamVersion) });\n }),\n );\n\n // Confirm Shopping Cart\n router.post(\n '/clients/:clientId/shopping-carts/:shoppingCartId/confirm',\n on(async (request: Request) => {\n const shoppingCartId = assertNotEmptyString(\n request.params.shoppingCartId,\n );\n\n const result = await handle(\n eventStore,\n shoppingCartId,\n {\n type: 'ConfirmShoppingCart',\n data: { shoppingCartId, now: new Date() },\n },\n {\n expectedStreamVersion: assertUnsignedBigInt(\n getETagValueFromIfMatch(request),\n ),\n },\n );\n\n return NoContent({ eTag: toWeakETag(result.nextExpectedStreamVersion) });\n }),\n );\n\n // Cancel Shopping Cart\n router.delete(\n '/clients/:clientId/shopping-carts/:shoppingCartId',\n on(async (request: Request) => {\n const shoppingCartId = assertNotEmptyString(\n request.params.shoppingCartId,\n );\n\n const result = await handle(\n eventStore,\n shoppingCartId,\n {\n type: 'CancelShoppingCart',\n data: { shoppingCartId, now: new Date() },\n },\n {\n expectedStreamVersion: assertUnsignedBigInt(\n getETagValueFromIfMatch(request),\n ),\n },\n );\n\n return NoContent({ eTag: toWeakETag(result.nextExpectedStreamVersion) });\n }),\n );\n};\n\n// Add Product Item\ntype AddProductItemRequest = Request<\n Partial<{ shoppingCartId: string }>,\n unknown,\n Partial<{ productId: number; quantity: number }>\n>;\n"]}
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/e2e/decider/api.ts"],"names":[],"mappings":"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"}
@@ -1,128 +1,136 @@
1
- "use strict"; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
-
3
-
4
- var _emmett = require('@event-driven-io/emmett');
5
- require('express');
6
- var _strict = require('node:assert/strict'); var _strict2 = _interopRequireDefault(_strict);
7
- var _nodetest = require('node:test');
8
- var _supertest = require('supertest'); var _supertest2 = _interopRequireDefault(_supertest);
9
- var _uuid = require('uuid');
10
- var _ = require('../..');
11
- var _etag = require('../../etag');
12
-
13
-
14
-
15
-
16
- var _testing = require('../testing');
17
- var _api = require('./api');
18
- var _businessLogic = require('./businessLogic');
19
- _nodetest.describe.call(void 0, "Application logic with optimistic concurrency", () => {
20
- let app;
21
- let eventStore;
22
- _nodetest.beforeEach.call(void 0, () => {
23
- eventStore = _emmett.getInMemoryEventStore.call(void 0, );
24
- app = _.getApplication.call(void 0, { apis: [_api.shoppingCartApi.call(void 0, eventStore)] });
25
- });
26
- _nodetest.it.call(void 0, "Should handle requests correctly", async () => {
27
- const clientId = _uuid.v4.call(void 0, );
28
- const createResponse = await _testing.runTwice.call(void 0,
29
- () => _supertest2.default.call(void 0, app).post(`/clients/${clientId}/shopping-carts`).send()
30
- ).expect(_testing.statuses.call(void 0, 201, 412));
31
- let currentRevision = _testing.expectNextRevisionInResponseEtag.call(void 0, createResponse);
32
- const current = createResponse.body;
33
- if (!current.id) {
34
- _strict2.default.fail();
35
- return;
36
- }
37
- _strict2.default.ok(current.id);
38
- const shoppingCartId = current.id;
39
- const twoPairsOfShoes = {
40
- quantity: 2,
41
- productId: "123"
42
- };
43
- let response = await _testing.runTwice.call(void 0,
44
- () => _supertest2.default.call(void 0, app).post(
45
- `/clients/${clientId}/shopping-carts/${shoppingCartId}/product-items`
46
- ).set(_etag.HeaderNames.IF_MATCH, _etag.toWeakETag.call(void 0, currentRevision)).send(twoPairsOfShoes)
47
- ).expect(_testing.statuses.call(void 0, 204, 412));
48
- currentRevision = _testing.expectNextRevisionInResponseEtag.call(void 0, response);
49
- const tShirt = {
50
- productId: "456",
51
- quantity: 1
52
- };
53
- response = await _testing.runTwice.call(void 0,
54
- () => _supertest2.default.call(void 0, app).post(
55
- `/clients/${clientId}/shopping-carts/${shoppingCartId}/product-items`
56
- ).set(_etag.HeaderNames.IF_MATCH, _etag.toWeakETag.call(void 0, currentRevision)).send(tShirt)
57
- ).expect(_testing.statuses.call(void 0, 204, 412));
58
- currentRevision = _testing.expectNextRevisionInResponseEtag.call(void 0, response);
59
- const pairOfShoes = {
60
- productId: "123",
61
- quantity: 1,
62
- unitPrice: 100
63
- };
64
- response = await _testing.runTwice.call(void 0,
65
- () => _supertest2.default.call(void 0, app).delete(
66
- `/clients/${clientId}/shopping-carts/${shoppingCartId}/product-items?productId=${pairOfShoes.productId}&quantity=${pairOfShoes.quantity}&unitPrice=${pairOfShoes.unitPrice}`
67
- ).set(_etag.HeaderNames.IF_MATCH, _etag.toWeakETag.call(void 0, currentRevision))
68
- ).expect(_testing.statuses.call(void 0, 204, 412));
69
- currentRevision = _testing.expectNextRevisionInResponseEtag.call(void 0, response);
70
- response = await _testing.runTwice.call(void 0,
71
- () => _supertest2.default.call(void 0, app).post(`/clients/${clientId}/shopping-carts/${shoppingCartId}/confirm`).set(_etag.HeaderNames.IF_MATCH, _etag.toWeakETag.call(void 0, currentRevision))
72
- ).expect(_testing.statuses.call(void 0, 204, 412));
73
- currentRevision = _testing.expectNextRevisionInResponseEtag.call(void 0, response);
74
- response = await _supertest2.default.call(void 0, app).delete(`/clients/${clientId}/shopping-carts/${shoppingCartId}`).set(_etag.HeaderNames.IF_MATCH, _etag.toWeakETag.call(void 0, currentRevision)).expect((response2) => {
75
- _strict2.default.equal(response2.statusCode, 403);
76
- _emmett.assertMatches.call(void 0, response2.body, {
77
- detail: _businessLogic.ShoppingCartErrors.CART_IS_ALREADY_CLOSED
78
- });
1
+ /* eslint-disable @typescript-eslint/no-floating-promises */
2
+ import { assertMatches, getInMemoryEventStore, } from '@event-driven-io/emmett';
3
+ import {} from 'express';
4
+ import assert from 'node:assert/strict';
5
+ import { beforeEach, describe, it } from 'node:test';
6
+ import request from 'supertest';
7
+ import { v4 as uuid } from 'uuid';
8
+ import { getApplication } from '../..';
9
+ import { HeaderNames, toWeakETag } from '../../etag';
10
+ import { expectNextRevisionInResponseEtag, runTwice, statuses, } from '../testing';
11
+ import { shoppingCartApi } from './api';
12
+ import { ShoppingCartErrors } from './businessLogic';
13
+ describe('Application logic with optimistic concurrency', () => {
14
+ let app;
15
+ let eventStore;
16
+ beforeEach(() => {
17
+ eventStore = getInMemoryEventStore();
18
+ app = getApplication({ apis: [shoppingCartApi(eventStore)] });
79
19
  });
80
- const result = await eventStore.readStream(shoppingCartId);
81
- _strict2.default.ok(result);
82
- _strict2.default.equal(result.events.length, Number(currentRevision));
83
- _emmett.assertMatches.call(void 0, _optionalChain([result, 'optionalAccess', _3 => _3.events]), [
84
- {
85
- type: "ShoppingCartOpened",
86
- data: {
87
- shoppingCartId,
88
- clientId
89
- //openedAt,
20
+ it('Should handle requests correctly', async () => {
21
+ const clientId = uuid();
22
+ ///////////////////////////////////////////////////
23
+ // 1. Open Shopping Cart
24
+ ///////////////////////////////////////////////////
25
+ const createResponse = (await runTwice(() => request(app).post(`/clients/${clientId}/shopping-carts`).send()).expect(statuses(201, 412)));
26
+ let currentRevision = expectNextRevisionInResponseEtag(createResponse);
27
+ const current = createResponse.body;
28
+ if (!current.id) {
29
+ assert.fail();
90
30
  }
91
- },
92
- {
93
- type: "ProductItemAddedToShoppingCart",
94
- data: {
95
- shoppingCartId,
96
- productItem: twoPairsOfShoes
97
- }
98
- },
99
- {
100
- type: "ProductItemAddedToShoppingCart",
101
- data: {
102
- shoppingCartId,
103
- productItem: tShirt
104
- }
105
- },
106
- {
107
- type: "ProductItemRemovedFromShoppingCart",
108
- data: { shoppingCartId, productItem: pairOfShoes }
109
- },
110
- {
111
- type: "ShoppingCartConfirmed",
112
- data: {
113
- shoppingCartId
114
- //confirmedAt,
115
- }
116
- }
117
- // This should fail
118
- // {
119
- // type: 'ShoppingCartCanceled',
120
- // data: {
121
- // shoppingCartId,
122
- // canceledAt,
123
- // },
124
- // },
125
- ]);
126
- });
31
+ assert.ok(current.id);
32
+ const shoppingCartId = current.id;
33
+ ///////////////////////////////////////////////////
34
+ // 2. Add Two Pair of Shoes
35
+ ///////////////////////////////////////////////////
36
+ const twoPairsOfShoes = {
37
+ quantity: 2,
38
+ productId: '123',
39
+ };
40
+ let response = await runTwice(() => request(app)
41
+ .post(`/clients/${clientId}/shopping-carts/${shoppingCartId}/product-items`)
42
+ .set(HeaderNames.IF_MATCH, toWeakETag(currentRevision))
43
+ .send(twoPairsOfShoes)).expect(statuses(204, 412));
44
+ currentRevision = expectNextRevisionInResponseEtag(response);
45
+ ///////////////////////////////////////////////////
46
+ // 3. Add T-Shirt
47
+ ///////////////////////////////////////////////////
48
+ const tShirt = {
49
+ productId: '456',
50
+ quantity: 1,
51
+ };
52
+ response = await runTwice(() => request(app)
53
+ .post(`/clients/${clientId}/shopping-carts/${shoppingCartId}/product-items`)
54
+ .set(HeaderNames.IF_MATCH, toWeakETag(currentRevision))
55
+ .send(tShirt)).expect(statuses(204, 412));
56
+ currentRevision = expectNextRevisionInResponseEtag(response);
57
+ ///////////////////////////////////////////////////
58
+ // 4. Remove pair of shoes
59
+ ///////////////////////////////////////////////////
60
+ const pairOfShoes = {
61
+ productId: '123',
62
+ quantity: 1,
63
+ unitPrice: 100,
64
+ };
65
+ response = await runTwice(() => request(app)
66
+ .delete(`/clients/${clientId}/shopping-carts/${shoppingCartId}/product-items?productId=${pairOfShoes.productId}&quantity=${pairOfShoes.quantity}&unitPrice=${pairOfShoes.unitPrice}`)
67
+ .set(HeaderNames.IF_MATCH, toWeakETag(currentRevision))).expect(statuses(204, 412));
68
+ currentRevision = expectNextRevisionInResponseEtag(response);
69
+ ///////////////////////////////////////////////////
70
+ // 5. Confirm cart
71
+ ///////////////////////////////////////////////////
72
+ response = await runTwice(() => request(app)
73
+ .post(`/clients/${clientId}/shopping-carts/${shoppingCartId}/confirm`)
74
+ .set(HeaderNames.IF_MATCH, toWeakETag(currentRevision))).expect(statuses(204, 412));
75
+ currentRevision = expectNextRevisionInResponseEtag(response);
76
+ ///////////////////////////////////////////////////
77
+ // 6. Try Cancel Cart
78
+ ///////////////////////////////////////////////////
79
+ response = await request(app)
80
+ .delete(`/clients/${clientId}/shopping-carts/${shoppingCartId}`)
81
+ .set(HeaderNames.IF_MATCH, toWeakETag(currentRevision))
82
+ .expect((response) => {
83
+ assert.equal(response.statusCode, 403);
84
+ assertMatches(response.body, {
85
+ detail: ShoppingCartErrors.CART_IS_ALREADY_CLOSED,
86
+ });
87
+ });
88
+ const result = await eventStore.readStream(shoppingCartId);
89
+ assert.ok(result);
90
+ assert.equal(result.events.length, Number(currentRevision));
91
+ assertMatches(result?.events, [
92
+ {
93
+ type: 'ShoppingCartOpened',
94
+ data: {
95
+ shoppingCartId,
96
+ clientId,
97
+ //openedAt,
98
+ },
99
+ },
100
+ {
101
+ type: 'ProductItemAddedToShoppingCart',
102
+ data: {
103
+ shoppingCartId,
104
+ productItem: twoPairsOfShoes,
105
+ },
106
+ },
107
+ {
108
+ type: 'ProductItemAddedToShoppingCart',
109
+ data: {
110
+ shoppingCartId,
111
+ productItem: tShirt,
112
+ },
113
+ },
114
+ {
115
+ type: 'ProductItemRemovedFromShoppingCart',
116
+ data: { shoppingCartId, productItem: pairOfShoes },
117
+ },
118
+ {
119
+ type: 'ShoppingCartConfirmed',
120
+ data: {
121
+ shoppingCartId,
122
+ //confirmedAt,
123
+ },
124
+ },
125
+ // This should fail
126
+ // {
127
+ // type: 'ShoppingCartCanceled',
128
+ // data: {
129
+ // shoppingCartId,
130
+ // canceledAt,
131
+ // },
132
+ // },
133
+ ]);
134
+ });
127
135
  });
128
136
  //# sourceMappingURL=applicationLogicWithOC.int.spec.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/e2e/decider/applicationLogicWithOC.int.spec.ts"],"names":["response"],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-floating-promises */\nimport {\n assertMatches,\n getInMemoryEventStore,\n type EventStore,\n} from '@event-driven-io/emmett';\nimport { type Application } from 'express';\nimport assert from 'node:assert/strict';\nimport { beforeEach, describe, it } from 'node:test';\nimport request from 'supertest';\nimport { v4 as uuid } from 'uuid';\nimport { getApplication } from '../..';\nimport { HeaderNames, toWeakETag } from '../../etag';\nimport {\n expectNextRevisionInResponseEtag,\n runTwice,\n statuses,\n type TestResponse,\n} from '../testing';\nimport { shoppingCartApi } from './api';\nimport { ShoppingCartErrors } from './businessLogic';\nimport type { ShoppingCartEvent } from './shoppingCart';\n\ndescribe('Application logic with optimistic concurrency', () => {\n let app: Application;\n let eventStore: EventStore;\n\n beforeEach(() => {\n eventStore = getInMemoryEventStore();\n app = getApplication({ apis: [shoppingCartApi(eventStore)] });\n });\n\n it('Should handle requests correctly', async () => {\n const clientId = uuid();\n ///////////////////////////////////////////////////\n // 1. Open Shopping Cart\n ///////////////////////////////////////////////////\n const createResponse = (await runTwice(() =>\n request(app).post(`/clients/${clientId}/shopping-carts`).send(),\n ).expect(statuses(201, 412))) as TestResponse<{ id: string }>;\n\n let currentRevision = expectNextRevisionInResponseEtag(createResponse);\n const current = createResponse.body;\n\n if (!current.id) {\n assert.fail();\n return;\n }\n assert.ok(current.id);\n\n const shoppingCartId = current.id;\n\n ///////////////////////////////////////////////////\n // 2. Add Two Pair of Shoes\n ///////////////////////////////////////////////////\n const twoPairsOfShoes = {\n quantity: 2,\n productId: '123',\n };\n let response = await runTwice(() =>\n request(app)\n .post(\n `/clients/${clientId}/shopping-carts/${shoppingCartId}/product-items`,\n )\n .set(HeaderNames.IF_MATCH, toWeakETag(currentRevision))\n .send(twoPairsOfShoes),\n ).expect(statuses(204, 412));\n\n currentRevision = expectNextRevisionInResponseEtag(response);\n\n ///////////////////////////////////////////////////\n // 3. Add T-Shirt\n ///////////////////////////////////////////////////\n const tShirt = {\n productId: '456',\n quantity: 1,\n };\n response = await runTwice(() =>\n request(app)\n .post(\n `/clients/${clientId}/shopping-carts/${shoppingCartId}/product-items`,\n )\n .set(HeaderNames.IF_MATCH, toWeakETag(currentRevision))\n .send(tShirt),\n ).expect(statuses(204, 412));\n\n currentRevision = expectNextRevisionInResponseEtag(response);\n\n ///////////////////////////////////////////////////\n // 4. Remove pair of shoes\n ///////////////////////////////////////////////////\n const pairOfShoes = {\n productId: '123',\n quantity: 1,\n unitPrice: 100,\n };\n response = await runTwice(() =>\n request(app)\n .delete(\n `/clients/${clientId}/shopping-carts/${shoppingCartId}/product-items?productId=${pairOfShoes.productId}&quantity=${pairOfShoes.quantity}&unitPrice=${pairOfShoes.unitPrice}`,\n )\n .set(HeaderNames.IF_MATCH, toWeakETag(currentRevision)),\n ).expect(statuses(204, 412));\n\n currentRevision = expectNextRevisionInResponseEtag(response);\n\n ///////////////////////////////////////////////////\n // 5. Confirm cart\n ///////////////////////////////////////////////////\n\n response = await runTwice(() =>\n request(app)\n .post(`/clients/${clientId}/shopping-carts/${shoppingCartId}/confirm`)\n .set(HeaderNames.IF_MATCH, toWeakETag(currentRevision)),\n ).expect(statuses(204, 412));\n\n currentRevision = expectNextRevisionInResponseEtag(response);\n\n ///////////////////////////////////////////////////\n // 6. Try Cancel Cart\n ///////////////////////////////////////////////////\n\n response = await request(app)\n .delete(`/clients/${clientId}/shopping-carts/${shoppingCartId}`)\n .set(HeaderNames.IF_MATCH, toWeakETag(currentRevision))\n .expect((response) => {\n assert.equal(response.statusCode, 403);\n assertMatches(response.body, {\n detail: ShoppingCartErrors.CART_IS_ALREADY_CLOSED,\n });\n });\n\n const result =\n await eventStore.readStream<ShoppingCartEvent>(shoppingCartId);\n\n assert.ok(result);\n assert.equal(result.events.length, Number(currentRevision));\n\n assertMatches(result?.events, [\n {\n type: 'ShoppingCartOpened',\n data: {\n shoppingCartId,\n clientId,\n //openedAt,\n },\n },\n {\n type: 'ProductItemAddedToShoppingCart',\n data: {\n shoppingCartId,\n productItem: twoPairsOfShoes,\n },\n },\n {\n type: 'ProductItemAddedToShoppingCart',\n data: {\n shoppingCartId,\n productItem: tShirt,\n },\n },\n {\n type: 'ProductItemRemovedFromShoppingCart',\n data: { shoppingCartId, productItem: pairOfShoes },\n },\n {\n type: 'ShoppingCartConfirmed',\n data: {\n shoppingCartId,\n //confirmedAt,\n },\n },\n // This should fail\n // {\n // type: 'ShoppingCartCanceled',\n // data: {\n // shoppingCartId,\n // canceledAt,\n // },\n // },\n ]);\n });\n});\n"]}
1
+ {"version":3,"file":"applicationLogicWithOC.int.spec.js","sourceRoot":"","sources":["../../../src/e2e/decider/applicationLogicWithOC.int.spec.ts"],"names":[],"mappings":"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"}
@@ -32,7 +32,6 @@ describe("Application logic with optimistic concurrency", () => {
32
32
  const current = createResponse.body;
33
33
  if (!current.id) {
34
34
  assert.fail();
35
- return;
36
35
  }
37
36
  assert.ok(current.id);
38
37
  const shoppingCartId = current.id;