Skip to content

Instantly share code, notes, and snippets.

@durre
Last active November 17, 2023 07:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save durre/e1781dc56fd7591859394db918a81b8e to your computer and use it in GitHub Desktop.
Save durre/e1781dc56fd7591859394db918a81b8e to your computer and use it in GitHub Desktop.
A bit more extensive example to go with the article, https://durre.se/you-might-not-need-javascript-classes. Here we wire "everything" up and show how it can be tested.
import { createOrderDao } from './orderDao'
import { createProductDao } from './productDao'
import { createPaymentService } from './paymentService'
import { createOrderService } from './orderService'
const orderDao = createOrderDao()
const productDao = createProductDao()
const paymentService = createPaymentService()
const orderService = createOrderService({ orderDao, productDao, paymentService })
import { createPlaceOrder } from './placeOrder'
type OrderServiceDependencies = {
productDao: ProductDao;
orderDao: OrderDao;
paymentService: PaymentService;
};
export const createOrderService = (dependencies: OrderServiceDependencies) => {
const { productDao, orderDao, paymentService } = dependencies;
return {
placeOrder: createPlaceOrder({
getProductsById: productDao.getProductsById,
chargeCreditCard: paymentService.chargeCreditCard,
saveOrder: orderDao.savedOrder
})
};
};
type OrderService = ReturnType<typeof createOrderService>;
const getProductsById = jest.fn(() =>
Promise.resolve([{ price: 10, id: "1" }])
);
const chargeCreditCard = jest.fn();
const saveOrder = jest.fn();
const customerInfo: CustomerInfo = { creditCard: "1234 111 111" };
const placeOrder = createPlaceOrder({
getProductsById,
chargeCreditCard,
saveOrder
});
describe("placeOrder", () => {
test("places order successfully", async () => {
const order: Order = { productIds: ["1"], id: "1" };
await placeOrder(order, customerInfo);
expect(getProductsById).toHaveBeenCalledWith(order.productIds);
expect(chargeCreditCard).toHaveBeenCalledWith(10, customerInfo.creditCard);
expect(saveOrder).toHaveBeenCalled();
});
});
type PlaceOrderDependencies = {
getProductsById: (ids: string[]) => Promise<Product[]>;
chargeCreditCard: (amount: number, creditCard: string) => Promise<Receipt>;
saveOrder: (order: Order, receipt: Receipt) => Promise<Order>;
};
const sumTotalPrice = (products: Product[]) =>
products.reduce((acc, curr) => acc + curr.price, 0);
export const createPlaceOrder =
(deps: PlaceOrderDependencies) =>
async (order: Order, customerInfo: CustomerInfo) => {
const { getProductsById, chargeCreditCard, saveOrder } = deps;
const products = await getProductsById(order.productIds);
const receipt = await chargeCreditCard(
sumTotalPrice(products),
customerInfo.creditCard
);
return saveOrder(order, receipt);
};
type Product = {
id: string;
price: number;
};
type Order = {
id: string;
productIds: string[];
};
type CustomerInfo = {
creditCard: string;
};
// I think you get the idea anyway, right?
type Receipt = any;
type OrderDao = any;
type ProductDao = any;
type PaymentService = any;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment