From aa4413fceb90a6bcdba88823456ad8fba9842186 Mon Sep 17 00:00:00 2001 From: Oskar Dudycz Date: Thu, 29 Feb 2024 09:32:33 +0100 Subject: [PATCH] Added easier possibility to check both api response and events in API integrationt ests --- docs/getting-started.md | 3 +- .../gettingStarted/webApi/apiBDD.int.spec.ts | 30 +++++++++---------- .../gettingStarted/webApi/simpleApi.ts | 3 -- .../src/testing/apiSpecification.ts | 28 +++++++++-------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 50887319..8d9f7a61 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -260,7 +260,8 @@ We recommend providing different web app configurations for different endpoints' That's what we did in our case. We've set up our Shopping Carts API and injected external dependencies: - event store to store and retrieve events, -- The `getUnitPrice` method represents a call to an external service to get the price of a product added to the shopping cart. +- The `getUnitPrice` method represents a call to an external service to get the price of a product added to the shopping cart, +- We're also passing the current date generator. Embracing this non-deterministic dependency will be helpful for integration testing later on. That clearly explains what dependencies this API needs, and by reading the file, you can understand what your application technology needs. That should cut the onboarding time for new people grasping our system setup. diff --git a/docs/snippets/gettingStarted/webApi/apiBDD.int.spec.ts b/docs/snippets/gettingStarted/webApi/apiBDD.int.spec.ts index aab9cc31..c0486e3d 100644 --- a/docs/snippets/gettingStarted/webApi/apiBDD.int.spec.ts +++ b/docs/snippets/gettingStarted/webApi/apiBDD.int.spec.ts @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/no-unsafe-call */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ /* eslint-disable @typescript-eslint/no-floating-promises */ import { getInMemoryEventStore, @@ -10,6 +8,7 @@ import { existingStream, expectError, expectNewEvents, + expectResponse, getApplication, } from '@event-driven-io/emmett-expressjs'; import { beforeEach, describe, it } from 'node:test'; @@ -22,10 +21,13 @@ const getUnitPrice = (_productId: string) => { }; describe('ShoppingCart', () => { + let clientId: string; + let shoppingCartId: string; beforeEach(() => { clientId = uuid(); shoppingCartId = `shopping_cart:${clientId}:current`; }); + describe('When empty', () => { it('should add product item', () => { return given() @@ -67,6 +69,7 @@ describe('ShoppingCart', () => { request.post(`/clients/${clientId}/shopping-carts/current/confirm`), ) .then([ + expectResponse(204), expectNewEvents(shoppingCartId, [ { type: 'ShoppingCartConfirmed', @@ -114,20 +117,7 @@ describe('ShoppingCart', () => { }); }); - let clientId: string; - let shoppingCartId: string; - - const getRandomProduct = (): PricedProductItem => { - return { - productId: uuid(), - unitPrice: 100, - quantity: Math.random() * 10, - }; - }; const oldTime = new Date(); - - const productItem = getRandomProduct(); - const now = new Date(); const given = ApiSpecification.for( @@ -137,4 +127,14 @@ describe('ShoppingCart', () => { apis: [shoppingCartApi(eventStore, getUnitPrice, () => now)], }), ); + + const getRandomProduct = (): PricedProductItem => { + return { + productId: uuid(), + unitPrice: 100, + quantity: Math.random() * 10, + }; + }; + + const productItem = getRandomProduct(); }); diff --git a/docs/snippets/gettingStarted/webApi/simpleApi.ts b/docs/snippets/gettingStarted/webApi/simpleApi.ts index 0dd3e0f9..ad09a86f 100644 --- a/docs/snippets/gettingStarted/webApi/simpleApi.ts +++ b/docs/snippets/gettingStarted/webApi/simpleApi.ts @@ -1,6 +1,3 @@ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/* eslint-disable @typescript-eslint/no-unsafe-call */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ import { assertNotEmptyString, assertPositiveNumber, diff --git a/packages/emmett-expressjs/src/testing/apiSpecification.ts b/packages/emmett-expressjs/src/testing/apiSpecification.ts index 2930102d..5caf7961 100644 --- a/packages/emmett-expressjs/src/testing/apiSpecification.ts +++ b/packages/emmett-expressjs/src/testing/apiSpecification.ts @@ -37,13 +37,12 @@ export const existingStream = ( /////////// Asserts //////////////////////////////// +export type ResponseAssert = (response: Response) => boolean | void; + export type ApiSpecificationAssert = | TestEventStream[] - | ((response: Response) => boolean | void) - | { - events: TestEventStream[]; - responseMatches: (response: Response) => boolean; - }; + | ResponseAssert + | [ResponseAssert, ...TestEventStream[]]; export const expect = ( streamId: string, @@ -128,17 +127,20 @@ export const ApiSpecification = { if (succeded === false) assert.fail(); } else if (Array.isArray(verify)) { + const [first, ...rest] = verify; + + if (typeof first === 'function') { + const succeded = first(response); + + if (succeded === false) assert.fail(); + } + + const events = typeof first === 'function' ? rest : verify; + assertMatches( Array.from(eventStore.appendedEvents.values()), - verify, - ); - } else { - assert.ok(verify.responseMatches(response)); - assertMatches( - Array.from(eventStore.appendedEvents.values()), - givenStreams, + events, ); - return; } }, };