Skip to content

Commit b85058e

Browse files
committed
Fixed event-sourced e2e tests
1 parent a3a4235 commit b85058e

File tree

7 files changed

+146
-118
lines changed

7 files changed

+146
-118
lines changed

samples/from_crud_to_eventsourcing/src/core/http.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ export const getETagFromHeader = (
4040
): ETag | undefined => {
4141
const etag = request.headers[headerName];
4242

43-
if (etag === undefined || etag.length > 0) {
43+
if (etag === undefined) {
4444
return undefined;
4545
}
4646

47-
return etag[0];
47+
return Array.isArray(etag) ? etag[0] : etag;
4848
};
4949

5050
export const getWeakETagValueFromHeader = (

samples/from_crud_to_eventsourcing/src/crud/migrations/0001-initial_migration.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ CREATE TABLE "ecommerce"."cart" (
88
"firstName" VARCHAR(50) NULL DEFAULT NULL,
99
"middleName" VARCHAR(50) NULL DEFAULT NULL,
1010
"lastName" VARCHAR(50) NULL DEFAULT NULL,
11-
"mobile" VARCHAR(15) NULL,
11+
"mobile" VARCHAR(50) NULL,
1212
"email" VARCHAR(50) NULL,
1313
"line1" VARCHAR(50) NULL DEFAULT NULL,
1414
"line2" VARCHAR(50) NULL DEFAULT NULL,

samples/from_crud_to_eventsourcing/src/eventsourced/e2e/fullFlow.e2e.test.ts

Lines changed: 132 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,17 @@ describe('Full flow', () => {
4949

5050
afterAll(async () => {
5151
await subscription.unsubscribe();
52-
await disconnectFromPostgres();
5352
await disconnectFromEventStore();
54-
await postgresContainer.stop();
5553
await esdbContainer.stop();
54+
55+
await disconnectFromPostgres();
56+
await postgresContainer.stop();
5657
});
5758

5859
describe('Shopping Cart', () => {
5960
let shoppingCartId: string;
6061
let currentRevision: string;
62+
let lastRevision: string;
6163
// const firstProductId: string = uuid();
6264

6365
it('should go through whole flow successfuly', async () => {
@@ -83,9 +85,11 @@ describe('Full flow', () => {
8385

8486
response = await request(app)
8587
.get(`/v2/shopping-carts/${shoppingCartId}`)
88+
//.set('If-Not-Match', lastRevision)
8689
.expect(200);
8790

8891
expect(response.headers['etag']).toBe(currentRevision);
92+
lastRevision = response.headers['etag'];
8993

9094
expect(response.body).toMatchObject({
9195
sessionId: shoppingCartId,
@@ -111,10 +115,10 @@ describe('Full flow', () => {
111115

112116
// 2. Add product item
113117
const twoPairsOfShoes = {
114-
price: 200,
115118
quantity: 2,
119+
productId: 123,
116120
};
117-
await request(app)
121+
response = await request(app)
118122
.post(`/v2/shopping-carts/${shoppingCartId}/product-items`)
119123
.set('If-Match', currentRevision)
120124
.send(twoPairsOfShoes)
@@ -125,10 +129,12 @@ describe('Full flow', () => {
125129
currentRevision = response.headers['etag'];
126130

127131
response = await request(app)
128-
.get(`/shopping-carts/${shoppingCartId}`)
132+
.get(`/v2/shopping-carts/${shoppingCartId}`)
133+
.set('If-Not-Match', lastRevision)
129134
.expect(200);
130135

131136
expect(response.headers['etag']).toBe(currentRevision);
137+
lastRevision = response.headers['etag'];
132138

133139
expect(response.body).toMatchObject({
134140
id: current.id,
@@ -152,114 +158,133 @@ describe('Full flow', () => {
152158
expect(response.body.updatedAt).not.toBeNull();
153159
current = response.body;
154160

155-
// // 3. Add another item
156-
// const tShirt = {
157-
// content: 'tshirt',
158-
// discount: 20,
159-
// productId: 456,
160-
// price: 100,
161-
// quantity: 1,
162-
// sku: 'tshirt-123',
163-
// };
164-
// await request(app)
165-
// .post(`/shopping-carts/${shoppingCartId}`)
166-
// .send({
167-
// ...current,
168-
// items: [...current.items, tShirt],
169-
// })
170-
// .expect(200);
161+
// 3. Add another item
162+
const tShirt = {
163+
productId: 456,
164+
quantity: 1,
165+
};
166+
response = await request(app)
167+
.post(`/v2/shopping-carts/${shoppingCartId}/product-items`)
168+
.set('If-Match', currentRevision)
169+
.send(tShirt)
170+
.expect(200);
171171

172-
// response = await request(app)
173-
// .get(`/shopping-carts/${shoppingCartId}`)
174-
// .expect(200);
172+
expect(response.headers['etag']).toBeDefined();
173+
expect(response.headers['etag']).toMatch(/W\/"\d+.*"/);
174+
currentRevision = response.headers['etag'];
175175

176-
// expect(response.body).toMatchObject({
177-
// id: current.id,
178-
// createdAt: current.createdAt,
179-
// sessionId: shoppingCartId,
180-
// city: null,
181-
// content: null,
182-
// country: null,
183-
// email: null,
184-
// firstName: null,
185-
// items: [twoPairsOfShoes, tShirt],
186-
// lastName: null,
187-
// line1: null,
188-
// line2: null,
189-
// middleName: null,
190-
// mobile: null,
191-
// province: null,
192-
// userId: null,
193-
// status: ShoppingCartStatus.Opened,
194-
// });
195-
// expect(response.body.updatedAt > current.updatedAt).toBeTruthy();
176+
response = await request(app)
177+
.get(`/v2/shopping-carts/${shoppingCartId}`)
178+
.set('If-Not-Match', lastRevision)
179+
.expect(200);
196180

197-
// current = response.body;
181+
expect(response.headers['etag']).toBe(currentRevision);
182+
lastRevision = response.headers['etag'];
198183

199-
// // 3. Remove one item
200-
// const pairOfShoes = {
201-
// content: 'shoes',
202-
// discount: 10,
203-
// productId: 123,
204-
// price: 200,
205-
// quantity: 2,
206-
// sku: 'shoes-123',
207-
// };
208-
// await request(app)
209-
// .post(`/shopping-carts/${shoppingCartId}`)
210-
// .send({
211-
// ...current,
212-
// items: [pairOfShoes, tShirt],
213-
// })
214-
// .expect(200);
184+
expect(response.body).toMatchObject({
185+
id: current.id,
186+
createdAt: current.createdAt,
187+
sessionId: shoppingCartId,
188+
city: null,
189+
content: null,
190+
country: null,
191+
email: null,
192+
firstName: null,
193+
items: [twoPairsOfShoes, tShirt],
194+
lastName: null,
195+
line1: null,
196+
line2: null,
197+
middleName: null,
198+
mobile: null,
199+
province: null,
200+
userId: null,
201+
status: ShoppingCartStatus.Opened,
202+
});
203+
expect(response.body.updatedAt > current.updatedAt).toBeTruthy();
204+
current = response.body;
215205

216-
// response = await request(app)
217-
// .get(`/shopping-carts/${shoppingCartId}`)
218-
// .expect(200);
206+
// 3. Remove one item
207+
const pairOfShoes = {
208+
productId: 123,
209+
quantity: 1,
210+
};
211+
response = await request(app)
212+
.delete(
213+
`/v2/shopping-carts/${shoppingCartId}/product-items?productId=${pairOfShoes.productId}&quantity=${pairOfShoes.quantity}`
214+
)
215+
.set('If-Match', currentRevision)
216+
.expect(200);
219217

220-
// expect(response.body).toMatchObject({
221-
// id: current.id,
222-
// createdAt: current.createdAt,
223-
// sessionId: shoppingCartId,
224-
// city: null,
225-
// content: null,
226-
// country: null,
227-
// email: null,
228-
// firstName: null,
229-
// items: [pairOfShoes, tShirt],
230-
// lastName: null,
231-
// line1: null,
232-
// line2: null,
233-
// middleName: null,
234-
// mobile: null,
235-
// province: null,
236-
// userId: null,
237-
// status: ShoppingCartStatus.Opened,
238-
// });
239-
// expect(response.body.updatedAt > current.updatedAt).toBeTruthy();
240-
241-
// // 3. Confirm cart
242-
// const confirmedData = {
243-
// city: 'Legnica',
244-
// content: 'Some content',
245-
// country: 'Poland',
246-
// email: 'oskar@someemail.pl',
247-
// firstName: 'Oskar',
248-
// middleName: 'the',
249-
// lastName: 'Grouch',
250-
// line1: 'line 1',
251-
// line2: 'line 2',
252-
// mobile: '123456789',
253-
// province: 'Sesame street',
254-
// status: ShoppingCartStatus.Confirmed,
255-
// };
256-
// await request(app)
257-
// .post(`/shopping-carts/${shoppingCartId}`)
258-
// .send({
259-
// ...current,
260-
// ...confirmedData,
261-
// })
262-
// .expect(200);
218+
expect(response.headers['etag']).toBeDefined();
219+
expect(response.headers['etag']).toMatch(/W\/"\d+.*"/);
220+
currentRevision = response.headers['etag'];
221+
222+
response = await request(app)
223+
.get(`/v2/shopping-carts/${shoppingCartId}`)
224+
.set('If-Not-Match', lastRevision)
225+
.expect(200);
226+
227+
expect(response.headers['etag']).toBe(currentRevision);
228+
lastRevision = response.headers['etag'];
229+
230+
expect(response.body).toMatchObject({
231+
id: current.id,
232+
createdAt: current.createdAt,
233+
sessionId: shoppingCartId,
234+
city: null,
235+
content: null,
236+
country: null,
237+
email: null,
238+
firstName: null,
239+
items: [pairOfShoes, tShirt],
240+
lastName: null,
241+
line1: null,
242+
line2: null,
243+
middleName: null,
244+
mobile: null,
245+
province: null,
246+
userId: null,
247+
status: ShoppingCartStatus.Opened,
248+
});
249+
expect(response.body.updatedAt > current.updatedAt).toBeTruthy();
250+
current = response.body;
251+
252+
// 3. Confirm cart
253+
const userId = 1694;
254+
const confirmedData = {
255+
content: 'Some content',
256+
line1: 'line 1',
257+
line2: 'line 2',
258+
};
259+
260+
response = await request(app)
261+
.put(`/v2/users/${userId}/shopping-carts/${shoppingCartId}`)
262+
.set('If-Match', currentRevision)
263+
.send(confirmedData)
264+
.expect(200);
265+
266+
expect(response.headers['etag']).toBeDefined();
267+
expect(response.headers['etag']).toMatch(/W\/"\d+.*"/);
268+
currentRevision = response.headers['etag'];
269+
270+
response = await request(app)
271+
.get(`/v2/shopping-carts/${shoppingCartId}`)
272+
.set('If-Not-Match', lastRevision)
273+
.expect(200);
274+
275+
expect(response.headers['etag']).toBe(currentRevision);
276+
lastRevision = response.headers['etag'];
277+
278+
expect(response.body).toMatchObject({
279+
id: current.id,
280+
createdAt: current.createdAt,
281+
sessionId: shoppingCartId,
282+
items: [pairOfShoes, tShirt],
283+
status: ShoppingCartStatus.Confirmed,
284+
...confirmedData,
285+
});
286+
expect(response.body.updatedAt > current.updatedAt).toBeTruthy();
287+
current = response.body;
263288

264289
// response = await request(app)
265290
// .get(`/shopping-carts/${shoppingCartId}`)

samples/from_crud_to_eventsourcing/src/eventsourced/migrations/0001-initial_migration.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ CREATE TABLE "ecommerce"."cart" (
88
"firstName" VARCHAR(50) NULL DEFAULT NULL,
99
"middleName" VARCHAR(50) NULL DEFAULT NULL,
1010
"lastName" VARCHAR(50) NULL DEFAULT NULL,
11-
"mobile" VARCHAR(15) NULL,
11+
"mobile" VARCHAR(50) NULL,
1212
"email" VARCHAR(50) NULL,
1313
"line1" VARCHAR(50) NULL DEFAULT NULL,
1414
"line2" VARCHAR(50) NULL DEFAULT NULL,

samples/from_crud_to_eventsourcing/src/eventsourced/shoppingCarts/routes.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
assertPositiveNumber,
1111
assertStringOrUndefined,
1212
} from '#core/validation';
13-
import { WhereCondition } from '@databases/pg-typed';
13+
import { not, WhereCondition } from '@databases/pg-typed';
1414
import { NextFunction, Request, Response, Router } from 'express';
1515
import { v4 as uuid } from 'uuid';
1616
import { create, update } from '../core/commandHandling';
@@ -117,8 +117,8 @@ router.delete(
117117
{
118118
shoppingCartId: assertNotEmptyString(request.params.shoppingCartId),
119119
productItem: {
120-
productId: assertPositiveNumber(request.body.productId),
121-
quantity: assertPositiveNumber(request.body.quantity),
120+
productId: assertPositiveNumber(Number(request.query.productId)),
121+
quantity: assertPositiveNumber(Number(request.query.quantity)),
122122
},
123123
},
124124
expectedRevision
@@ -151,7 +151,7 @@ router.put(
151151
streamName,
152152
{
153153
shoppingCartId: assertNotEmptyString(request.params.shoppingCartId),
154-
userId: assertPositiveNumber(request.params.userId),
154+
userId: assertPositiveNumber(Number(request.params.userId)),
155155
additionalInfo: {
156156
content: assertStringOrUndefined(request.body.content),
157157
line1: assertStringOrUndefined(request.body.line1),
@@ -185,7 +185,7 @@ router.get(
185185
if (expectedRevision != undefined) {
186186
query = {
187187
...query,
188-
revision: Number(expectedRevision),
188+
revision: not(Number(expectedRevision)),
189189
};
190190
}
191191

@@ -205,7 +205,9 @@ router.get(
205205
response.set('ETag', toWeakETag(result.revision));
206206
response.send({
207207
...result,
208-
items,
208+
items: items.sort(
209+
(a, b) => a.createdAt.getTime() - b.createdAt.getTime()
210+
),
209211
});
210212
} catch (error) {
211213
console.error(error);

samples/from_crud_to_eventsourcing/src/eventsourced/shoppingCarts/shoppingCartDetails.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ export const projectShoppingCartConfirmed = async (
166166
email,
167167
...additionalInfo,
168168
...address,
169+
status: ShoppingCartStatus.Confirmed,
169170
updatedAt: new Date(confirmedAt),
170171
}
171172
);

samples/from_crud_to_eventsourcing/src/eventsourced/shoppingCarts/user.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export interface User {
1818
const fakeUsers = new Map<number, User>();
1919

2020
export const getUserData = (userId: number) => {
21-
if (fakeUsers.has(userId)) {
21+
if (!fakeUsers.has(userId)) {
2222
fakeUsers.set(userId, {
2323
id: userId,
2424
firstName: faker.name.firstName(),

0 commit comments

Comments
 (0)