hydra-tests
v1.1.0
Published
Reusable e2e test infrastructure for `@guestyci/hydra` NestJS services. Provides a `Testkit` class that manages Docker containers (PostgreSQL, MongoDB, RabbitMQ, Redis, Kafka) and boots Hydra HTTP services in-process for integration testing.
Downloads
101
Readme
hydra-tests
Reusable e2e test infrastructure for @guestyci/hydra NestJS services. Provides a Testkit class that manages Docker containers (PostgreSQL, MongoDB, RabbitMQ, Redis, Kafka) and boots Hydra HTTP services in-process for integration testing.
Prerequisites
- Node.js 24+
- Docker (running)
- npm
Quick Start
npm install
npm testThis starts Docker containers (PostgreSQL, MongoDB, RabbitMQ, Kafka), boots the sample Hydra app, runs all e2e tests, and tears everything down.
Project Layout
src/testsDriver/ # The library (portable to other projects)
├── testkit.ts # Core Testkit class
├── types.ts # TypeScript interfaces & conditional types
├── index.ts # Public exports
└── docker-compose.yml # Docker service definitions
exec/httpService/hydra-tests/ # Sample consumer (mimics a real Hydra project)
├── app.module.ts # NestJS root module
├── app.e2e-spec.ts # E2E smoke tests
├── items/ # PostgreSQL CRUD
├── tasks/ # MongoDB CRUD
├── notifications/ # RabbitMQ producer
├── events/ # RabbitMQ consumer
├── orders/ # Kafka producer
├── stream/ # Kafka consumer
├── cache/ # Redis get/set
├── audit/ # MongoDB business events (Buddy outbox)
├── invoices/ # Prisma business events (_outbox pattern)
└── greetings/ # Jest mocking example
prisma/
└── schema.prisma # Prisma schema (items + _outbox)Testkit Usage
Basic setup
import { Testkit } from "../../../src/testsDriver";
const testkit = new Testkit({
postgres: true,
mongodb: true,
rabbitmq: true,
redis: true,
kafka: { topics: ["my-topic"] },
app: { entrypoint: "./app.module" },
});
const { getDrivers } = testkit.beforeAndAfter();
describe("My tests", () => {
it("should work", async () => {
const { app, postgres, mongodb, rabbitmq, redis, kafka } = getDrivers();
await request(app.getHttpServer()).get("/health").expect(200);
});
});All options are optional -- only requested services are started.
Available services
| Option | Docker image | Host port | Driver type |
|--------|-------------|-----------|-------------|
| postgres: true | postgres:16 | 5433 | PrismaClient |
| mongodb: true | mongodb/mongodb-atlas-local:8.0 | 27018 | Mongoose Connection |
| rabbitmq: true | rabbitmq:3-management | 5673 | RabbitDriver |
| redis: true | redis:7-alpine | 6380 | RedisDriver |
| kafka: true or kafka: { topics: [...] } | apache/kafka:latest | 9094 | KafkaDriver |
App mode
Pass app: { entrypoint: "./app.module" } to boot a Hydra HTTP service in-process. The entrypoint is a relative path from the test file to the NestJS module. The Testkit handles dynamic import, sets IDENTITY, LOAD_ENV, HYDRA_NO_AUTH, and all database connection URLs automatically.
Jest mocking
Place jest.mock() calls before new Testkit() so mocks are registered before the app module is dynamically imported:
jest.mock("./utils/myHelper", () => ({
myHelper: jest.fn(() => "mocked"),
}));
const testkit = new Testkit({ app: { entrypoint: "./app.module" } });Redis driver
const { redis } = getDrivers();
// Set a value for your app to read
await redis.set("key", "value");
await redis.set("key", "value", 60); // with TTL in seconds
// Read a value your app stored
const value = await redis.get("key");
// Delete
await redis.del("key");
// Raw node-redis client for advanced operations
await redis.client.hSet("hash", "field", "value");RabbitMQ driver
const { rabbitmq } = getDrivers();
// Publish a message for your app to consume
await rabbitmq.publish("queue-name", { key: "value" });
// Consume messages your app produced
const messages = await rabbitmq.consume("queue-name");Kafka driver
const { kafka } = getDrivers();
// Produce a message for your app to consume
await kafka.produce("topic-name", { key: "value" });
// Consume messages your app produced
const messages = await kafka.consume("topic-name");Pre-create topics via config to avoid race conditions:
new Testkit({ kafka: { topics: ["topic-a", "topic-b"] } });Business events
MongoDB (Buddy) -- uses BusinessEventsModule.register() from Hydra. Events land in a MongoDB outbox collection. Requires uberctx-accountid header in test requests:
await request(app.getHttpServer())
.post("/api/audit")
.set("uberctx-accountid", "acc-123")
.send(body)
.expect(201);
const docs = await mongodb.collection("audit_outbox").find().toArray();Prisma (_outbox) -- uses a BusinessEvent model mapped to _outbox. Written via tx.businessEvent.create() inside a Prisma transaction:
const rows = await postgres.businessEvent.findMany({
where: { partitionId: "Invoice.inv-789" },
});Scripts
| Script | Description |
|--------|-------------|
| npm test | Run e2e tests (starts Docker, runs tests, tears down) |
| npm run test:e2e | Same as npm test |
| npm run lint | Run ESLint on all TypeScript files |
| npm run lint:fix | Run ESLint with auto-fix |
CI
actuator.yaml-- Runs on push via the sharedguestyorg/actuatorHydra workflow (tests skipped in coverage).actuator-release.yaml-- Publishes the package on pushes tomasteror alpha tags.
