Skip to content

Commit dc88624

Browse files
committed
Added tests checks for expected version check
1 parent 101021a commit dc88624

File tree

4 files changed

+99
-2
lines changed

4 files changed

+99
-2
lines changed

src/packages/emmett-tests/src/eventStore/features.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,24 @@ import {
22
assertDeepEqual,
33
assertEqual,
44
assertOk,
5+
assertThrowsAsync,
6+
assertTrue,
7+
CommandHandler,
8+
ExpectedVersionConflictError,
9+
isExpectedVersionConflictError,
510
type EventStore,
611
} from '@event-driven-io/emmett';
12+
import { randomUUID } from 'crypto';
713
import { after, before, describe, it } from 'node:test';
814
import { v4 as uuid } from 'uuid';
915
import {
16+
addProductItem,
1017
evolve,
1118
evolveWithMetadata,
1219
initialState,
20+
type AddProductItem,
1321
type PricedProductItem,
22+
type ShoppingCart,
1423
type ShoppingCartEvent,
1524
} from './shoppingCart.domain';
1625

@@ -119,3 +128,66 @@ export async function testAggregateStream(
119128
}
120129
});
121130
}
131+
132+
export async function testCommandHandling(
133+
eventStoreFactory: EventStoreFactory,
134+
options: TestOptions = {
135+
getInitialIndex: () => 1n,
136+
},
137+
) {
138+
return describe('Command handling', async () => {
139+
let eventStore: EventStore;
140+
141+
const handleCommand = CommandHandler<ShoppingCart, ShoppingCartEvent>({
142+
evolve,
143+
initialState,
144+
});
145+
146+
before(async () => {
147+
eventStore = await eventStoreFactory();
148+
});
149+
150+
after(async () => {
151+
const teardownHook = options.teardownHook;
152+
if (teardownHook) await teardownHook();
153+
});
154+
155+
await it('Correctly handles no retries on version conflict when retry is disabled', async () => {
156+
const productItem: PricedProductItem = {
157+
productId: '123',
158+
quantity: 10,
159+
price: 3,
160+
};
161+
162+
const shoppingCartId = randomUUID();
163+
const command: AddProductItem = {
164+
type: 'AddProductItem',
165+
data: { productItem },
166+
};
167+
168+
// Create the stream
169+
await handleCommand(
170+
eventStore,
171+
shoppingCartId,
172+
(state) => addProductItem(command, state),
173+
{ expectedStreamVersion: 'STREAM_DOES_NOT_EXIST' },
174+
);
175+
176+
let tried = 0;
177+
178+
const error = await assertThrowsAsync(
179+
async () => {
180+
await handleCommand(eventStore, shoppingCartId, () => {
181+
tried++;
182+
throw new ExpectedVersionConflictError(0, 1);
183+
});
184+
},
185+
(error) => error instanceof ExpectedVersionConflictError,
186+
);
187+
188+
assertTrue(isExpectedVersionConflictError(error));
189+
190+
assertEqual(1, tried);
191+
});
192+
});
193+
}

src/packages/emmett-tests/src/eventStore/postgresql/postgreSQLEventStore.e2e.spec.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ import {
1717
} from '@testcontainers/postgresql';
1818
import { after, describe, it } from 'node:test';
1919
import { v4 as uuid } from 'uuid';
20-
import { testAggregateStream, type EventStoreFactory } from '../features';
20+
import {
21+
testAggregateStream,
22+
testCommandHandling,
23+
type EventStoreFactory,
24+
} from '../features';
2125
import {
2226
type DiscountApplied,
2327
type PricedProductItem,
@@ -58,6 +62,10 @@ void describe('EventStoreDBEventStore', async () => {
5862
getInitialIndex: () => 1n,
5963
});
6064

65+
await testCommandHandling(eventStoreFactory, {
66+
getInitialIndex: () => 1n,
67+
});
68+
6169
void it('should append events correctly using appendEvent function', async () => {
6270
const productItem: PricedProductItem = {
6371
productId: 'p123',

src/packages/emmett-tests/src/eventStore/shoppingCart.domain.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,17 @@ export const evolveWithMetadata = (
6767
export const initialState = (): ShoppingCart => {
6868
return { productItems: [], totalAmount: 0 };
6969
};
70+
export type AddProductItem = Event<
71+
'AddProductItem',
72+
{ productItem: PricedProductItem }
73+
>;
74+
75+
export const addProductItem = (
76+
command: AddProductItem,
77+
_state: ShoppingCart,
78+
): ShoppingCartEvent => {
79+
return {
80+
type: 'ProductItemAdded',
81+
data: { productItem: command.data.productItem },
82+
};
83+
};

src/packages/emmett/src/commandHandling/handleCommand.unit.spec.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { describe, it } from 'node:test';
33
import {
44
ExpectedVersionConflictError,
55
getInMemoryEventStore,
6+
isExpectedVersionConflictError,
67
} from '../eventStore';
78
import {
89
assertDeepEqual,
@@ -505,7 +506,7 @@ void describe('Command Handler', () => {
505506

506507
let tried = 0;
507508

508-
await assertThrowsAsync(
509+
const error = await assertThrowsAsync(
509510
async () => {
510511
await handleCommand(eventStore, shoppingCartId, () => {
511512
tried++;
@@ -515,6 +516,8 @@ void describe('Command Handler', () => {
515516
(error) => error instanceof ExpectedVersionConflictError,
516517
);
517518

519+
assertTrue(isExpectedVersionConflictError(error));
520+
518521
assertEqual(1, tried);
519522
});
520523
});

0 commit comments

Comments
 (0)