Skip to content

Commit

Permalink
Added test project to ensure compatibility with ESM
Browse files Browse the repository at this point in the history
Added also initial CI script to ensure that new version will keep compatibility
  • Loading branch information
oskardudycz committed Mar 8, 2024
1 parent b4ca9ab commit 7f2164f
Show file tree
Hide file tree
Showing 8 changed files with 580 additions and 0 deletions.
47 changes: 47 additions & 0 deletions .github/workflows/compatibility.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: Build and test

on:
# run it on push to the default repository branch
push:
branches: [main]
# run it during pull request
pull_request:

jobs:
build-and-test-compatibility:
name: Build application code
# use system defined below in the tests matrix
runs-on: ${{ matrix.os }}

strategy:
# define the test matrix
matrix:
# selected operation systems to run CI
os: [ubuntu-latest] #, windows-latest, macos-latest]
# selected node version to run CI
node-version: [20.11.1]

steps:
- name: Check Out Repo
uses: actions/checkout@v4

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
# use the node version defined in matrix above
node-version: ${{ matrix.node-version }}
cache: 'npm'

- name: Pack Emmett locally
run: echo "npm pack --json --pack-destination './e2e/esmCompatibility' -w @event-driven-io/emmett | jq '.[] | .filename" >> $PACKAGE_FILENAME

- name: Test
run: echo $PACKAGE_FILENAME

- name: Install dependencies
working-directory: ./e2e/esmCompatibility
run: npm ci

- name: Build TS
working-directory: ./e2e/esmCompatibility
run: npm run build
68 changes: 68 additions & 0 deletions e2e/esmCompatibility/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions e2e/esmCompatibility/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "esmcompatibility",
"version": "1.0.0",
"description": "Testing Emmett Compatibility",
"main": "index.js",
"scripts": {
"build": "tsc"
},
"author": "",
"license": "ISC",
"type": "module",
"devDependencies": {
"@types/node": "^20.11.25",
"typescript": "^5.4.2"
},
"dependencies": {
"@event-driven-io/emmett": "0.5.0"
}
}
23 changes: 23 additions & 0 deletions e2e/esmCompatibility/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { CommandHandler, getInMemoryEventStore } from '@event-driven-io/emmett';
import { randomUUID } from 'crypto';
import {
AddProductItemToShoppingCart,
addProductItem,
} from './shoppingCart/businessLogic';
import { evolve, getInitialState } from './shoppingCart/shoppingCart';

export const handle = CommandHandler(evolve, getInitialState);
const store = getInMemoryEventStore();

const shoppingCartId = '123';
const command: AddProductItemToShoppingCart = {
type: 'AddProductItemToShoppingCart',
data: {
productItem: { productId: randomUUID(), quantity: 10, unitPrice: 10 },
shoppingCartId,
},
};
const x = await handle(store, shoppingCartId, (state) =>
addProductItem(command, state),
);
console.log(x);
179 changes: 179 additions & 0 deletions e2e/esmCompatibility/src/shoppingCart/businessLogic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import {
EmmettError,
IllegalStateError,
sum,
type Command,
type Decider,
} from '@event-driven-io/emmett';
import {
PricedProductItem,
ProductItemAddedToShoppingCart,
ProductItemRemovedFromShoppingCart,
ShoppingCart,
ShoppingCartCancelled,
ShoppingCartConfirmed,
ShoppingCartEvent,
evolve,
getInitialState,
} from './shoppingCart';

export type AddProductItemToShoppingCart = Command<
'AddProductItemToShoppingCart',
{
shoppingCartId: string;
productItem: PricedProductItem;
}
>;

export type RemoveProductItemFromShoppingCart = Command<
'RemoveProductItemFromShoppingCart',
{
shoppingCartId: string;
productItem: PricedProductItem;
}
>;

export type ConfirmShoppingCart = Command<
'ConfirmShoppingCart',
{
shoppingCartId: string;
}
>;

export type CancelShoppingCart = Command<
'CancelShoppingCart',
{
shoppingCartId: string;
}
>;

export type ShoppingCartCommand =
| AddProductItemToShoppingCart
| RemoveProductItemFromShoppingCart
| ConfirmShoppingCart
| CancelShoppingCart;

export const addProductItem = (
command: AddProductItemToShoppingCart,
state: ShoppingCart,
): ProductItemAddedToShoppingCart => {
if (state.status === 'Closed')
throw new IllegalStateError('Shopping Cart already closed');

const {
data: { shoppingCartId, productItem },
metadata,
} = command;

return {
type: 'ProductItemAddedToShoppingCart',
data: {
shoppingCartId,
productItem,
addedAt: metadata?.now ?? new Date(),
},
};
};

export const removeProductItem = (
command: RemoveProductItemFromShoppingCart,
state: ShoppingCart,
): ProductItemRemovedFromShoppingCart => {
if (state.status !== 'Opened')
throw new IllegalStateError('Shopping Cart is not opened');

const {
data: { shoppingCartId, productItem },
metadata,
} = command;

const currentQuantity = state.productItems.get(productItem.productId) ?? 0;

if (currentQuantity < productItem.quantity)
throw new IllegalStateError('Not enough products');

return {
type: 'ProductItemRemovedFromShoppingCart',
data: {
shoppingCartId,
productItem,
removedAt: metadata?.now ?? new Date(),
},
};
};

export const confirm = (
command: ConfirmShoppingCart,
state: ShoppingCart,
): ShoppingCartConfirmed => {
if (state.status !== 'Opened')
throw new IllegalStateError('Shopping Cart is not opened');

const totalQuantityOfAllProductItems = sum(state.productItems.values());

if (totalQuantityOfAllProductItems <= 0)
throw new IllegalStateError('Shopping Cart is empty');

const {
data: { shoppingCartId },
metadata,
} = command;

return {
type: 'ShoppingCartConfirmed',
data: {
shoppingCartId,
confirmedAt: metadata?.now ?? new Date(),
},
};
};

export const cancel = (
command: CancelShoppingCart,
state: ShoppingCart,
): ShoppingCartCancelled => {
if (state.status !== 'Opened')
throw new IllegalStateError('Shopping Cart is not opened');

const {
data: { shoppingCartId },
metadata,
} = command;

return {
type: 'ShoppingCartCancelled',
data: {
shoppingCartId,
canceledAt: metadata?.now ?? new Date(),
},
};
};

export const decide = (command: ShoppingCartCommand, state: ShoppingCart) => {
const { type } = command;

switch (type) {
case 'AddProductItemToShoppingCart':
return addProductItem(command, state);
case 'RemoveProductItemFromShoppingCart':
return removeProductItem(command, state);
case 'ConfirmShoppingCart':
return confirm(command, state);
case 'CancelShoppingCart':
return cancel(command, state);
default: {
const _notExistingCommandType: never = type;
throw new EmmettError(`Unknown command type`);
}
}
};

export const decider: Decider<
ShoppingCart,
ShoppingCartCommand,
ShoppingCartEvent
> = {
decide,
evolve,
getInitialState,
};
Loading

0 comments on commit 7f2164f

Please sign in to comment.