diff --git a/tests/simulateTraffic.ts b/scripts/simulate-traffic.ts similarity index 68% rename from tests/simulateTraffic.ts rename to scripts/simulate-traffic.ts index c10e917..649cca6 100644 --- a/tests/simulateTraffic.ts +++ b/scripts/simulate-traffic.ts @@ -1,3 +1,15 @@ +/** + * simulate-traffic.ts — manual load test utility + * + * Fires 500 Create + GetOne requests against a running API server. + * Assumes the server is up at http://127.0.0.1:8080. + * + * Usage: + * npx ts-node scripts/simulate-traffic.ts + * + * This is NOT a Jest test file. It lives in scripts/ rather than tests/ + * to avoid polluting Jest discovery and to clarify its purpose. + */ import axios from "axios"; import { v4 } from "uuid"; @@ -8,13 +20,14 @@ async function call() { const response = await axios.post("http://127.0.0.1:8080/transaction", { price: { amount: Math.floor(Math.random() * (40 - 30)) + 30, - currency: "EUR" }, + currency: "EUR", + }, product: "demo", uuid: uuid = v4(), }); console.log("Code: ", response.status); - console.log(`http://127.1:8080/transaction/${uuid}`); + console.log(`http://127.0.0.1:8080/transaction/${uuid}`); setTimeout(async () => { await Promise.all([ @@ -23,7 +36,7 @@ async function call() { axios.get(`http://127.0.0.1:8080/transaction/${uuid}`), axios.get(`http://127.0.0.1:8080/transaction/${uuid}`), axios.get(`http://127.0.0.1:8080/transaction/${uuid}`), - ]) + ]); }, 80); } catch (err) { diff --git a/tests/Billing/Transaction/Application/UseCase/Transaction/GetOne.test.ts b/tests/Billing/Transaction/Application/UseCase/Transaction/GetOne.test.ts index 65133f9..c477bc8 100644 --- a/tests/Billing/Transaction/Application/UseCase/Transaction/GetOne.test.ts +++ b/tests/Billing/Transaction/Application/UseCase/Transaction/GetOne.test.ts @@ -1,20 +1,26 @@ -import { Framework } from "hollywood-js"; +import { Framework } from "hollywood-js"; +import * as prom from "prom-client"; import { getConnectionManager } from "typeorm"; import {TestKernelFactory} from "../../../../../TestKernelFactory"; import GetOneQuery from "@Transaction/Application/GetOne/Query"; import Transaction from "@Transaction/Domain/Transaction"; import TransactionId from "@Transaction/Domain/ValueObject/TransactionId"; import Price from "@Transaction/Domain/ValueObject/Price"; +import NotFoundException from "@Shared/Domain/Exceptions/NotFoundException"; import {InMemoryTransactionRepository} from "../../../Infrastructure/InMemoryRepository"; +const EXISTING_UUID = "ae081e7a-ec8c-4ff1-9de5-f70383fe03a7"; +const MISSING_UUID = "f47ac10b-58cc-4372-a567-0e02b2c3d479"; + describe("GetOne Transaction", () => { let kernel: Framework.Kernel; beforeEach(async () => { + prom.register.clear(); kernel = await TestKernelFactory(); const repository = kernel.container.get("domain.transaction.repository"); await repository.save(Transaction.create( - new TransactionId("ae081e7a-ec8c-4ff1-9de5-f70383fe03a7"), + new TransactionId(EXISTING_UUID), "", new Price("1", "EUR"), )); @@ -26,9 +32,15 @@ describe("GetOne Transaction", () => { test("GetOne a valid transaction", async () => { expect.assertions(3); - const transaction: any = await kernel.app.ask(new GetOneQuery("ae081e7a-ec8c-4ff1-9de5-f70383fe03a7")); + const transaction: any = await kernel.app.ask(new GetOneQuery(EXISTING_UUID)); expect(transaction).not.toBe(null); expect(transaction).not.toBe(undefined); - expect(transaction.data.uuid).toBe("ae081e7a-ec8c-4ff1-9de5-f70383fe03a7"); + expect(transaction.data.uuid).toBe(EXISTING_UUID); + }); + + test("GetOne a non-existent transaction throws NotFoundException", async () => { + expect.assertions(1); + await expect(kernel.app.ask(new GetOneQuery(MISSING_UUID))) + .rejects.toThrow(NotFoundException); }); }); diff --git a/tests/Billing/Transaction/Domain/Transaction/Transaction.test.ts b/tests/Billing/Transaction/Domain/Transaction/Transaction.test.ts index 3ee667a..cdbb7f8 100644 --- a/tests/Billing/Transaction/Domain/Transaction/Transaction.test.ts +++ b/tests/Billing/Transaction/Domain/Transaction/Transaction.test.ts @@ -3,21 +3,36 @@ import Price from "@Transaction/Domain/ValueObject/Price"; import TransactionId from "@Transaction/Domain/ValueObject/TransactionId"; import Transaction from "@Transaction/Domain/Transaction"; import TransactionWasCreated from "@Transaction/Domain/Events/TransactionWasCreated"; +import InvalidArgumentException from "@Shared/Domain/Exceptions/InvalidArgumentException"; + +const FIXED_UUID = "ae081e7a-ec8c-4ff1-9de5-f70383fe03a7"; describe("Transaction", () => { test("Create transaction", () => { const price = new Price("2", "EUR"); - const transactionID = new TransactionId("ae081e7a-ec8c-4ff1-9de5-f70383fe03a7"); + const transactionID = new TransactionId(FIXED_UUID); const instance = Transaction.create(transactionID, "product", price); const stream = instance.getUncommittedEvents(); const event = stream.events[0].event as TransactionWasCreated; - expect(instance.getAggregateRootId().toString()).toBe("ae081e7a-ec8c-4ff1-9de5-f70383fe03a7"); + expect(instance.getAggregateRootId().toString()).toBe(FIXED_UUID); expect(stream.events[0]).toBeInstanceOf(Domain.DomainMessage); expect(event.product).toBe("product"); expect(event.amount).toBe(price.amount); expect(event.currency).toBe(price.currency); expect(instance.version()).toBe(0); }); + + test("Creating a transaction with a negative price is rejected by the domain", () => { + const transactionID = new TransactionId(FIXED_UUID); + expect(() => Transaction.create(transactionID, "product", new Price("-1", "EUR"))) + .toThrow(InvalidArgumentException); + }); + + test("Creating a transaction with an unknown currency is rejected by the domain", () => { + const transactionID = new TransactionId(FIXED_UUID); + expect(() => Transaction.create(transactionID, "product", new Price("10", "GBP"))) + .toThrow(InvalidArgumentException); + }); });