5.4 KiB
SurrealDBFixture
(no submodules)
Purpose
SurrealDBFixture is an integration test fixture that manages the full lifecycle of a SurrealDB v3 container using testcontainers. It implements the ServiceFixture<SurrealDBConfig> interface from @suaveplan/testing-integration, enabling consistent startup, health checking, and teardown as part of a TestEnvironment or standalone usage.
The fixture supports an env-bridge passthrough mode so developer workstations with live SurrealDB instances can skip container startup entirely — just set the three required environment variables and tests run against the real service without Docker overhead.
Features
- Env-bridge passthrough: when
SURREALDB_URL,SURREALDB_USERNAME, andSURREALDB_PASSWORDare all set and non-empty, container startup is bypassed and env values are returned directly. - HTTP health check: polls
GET /healthon SurrealDB's HTTP port (same port as WebSocket) to verify the service is ready before returning fromstart(). - Random password per run: generates a new
crypto.randomUUID()password each time a container starts, preventing credential reuse across test suites. - Injectable container factory: the
containerFactoryoption allows unit tests to swap in a fake container without starting Docker, achieving 100% Istanbul coverage without integration dependencies. - Configurable namespace and database: override defaults via options to isolate test suites at the logical database level.
- Idempotent stop: calling
stop()on an already-stopped or passthrough fixture is safe and does not throw.
Usage: Basic Example
import { SurrealDBFixture } from "@suaveplan/testing-integration-surrealdb";
const fixture = new SurrealDBFixture();
const config = await fixture.start();
// config.url → "ws://localhost:<randomPort>"
// config.username → "root"
// config.password → auto-generated UUID
// config.namespace → "test"
// config.database → "test"
await fixture.stop();
Usage: Advanced Example
import { SurrealDBFixture } from "@suaveplan/testing-integration-surrealdb";
import Surreal from "surrealdb";
const fixture = new SurrealDBFixture({
image: "surrealdb/surrealdb:v3.0.4",
namespace: "myapp",
database: "integration",
});
const config = await fixture.start();
const db = new Surreal();
await db.connect(config.url);
await db.use({ namespace: config.namespace, database: config.database });
await db.signin({ username: config.username, password: config.password });
// run tests…
await db.close();
await fixture.stop();
API Reference
class SurrealDBFixture
Implements ServiceFixture<SurrealDBConfig>.
constructor(options?: SurrealDBFixtureOptions)
Creates a new fixture instance. All options are optional.
name: string
Always "surrealdb". Used by TestEnvironment as the registry key.
start(): Promise<SurrealDBConfig>
Starts the service. Returns the runtime configuration on success. If all three env vars are set, returns passthrough config immediately. Otherwise starts a testcontainers container and waits for the HTTP health endpoint.
stop(): Promise<void>
Stops the container. No-op in passthrough mode or when start() was never called.
healthCheck(): Promise<boolean>
Returns true when GET http://localhost:<port>/health returns an OK response. Returns false if no container is active or the request fails.
interface SurrealDBConfig
| Field | Type | Description |
|---|---|---|
url |
string |
WebSocket URL: ws://localhost:<port> |
namespace |
string |
SurrealDB namespace |
database |
string |
SurrealDB database name |
username |
string |
Auth username (always root in container mode) |
password |
string |
Auth password (random UUID in container mode) |
interface SurrealDBFixtureOptions
| Field | Type | Description |
|---|---|---|
image? |
string |
Docker image override. Defaults to surrealdb/surrealdb:v3.0.4. |
namespace? |
string |
Namespace override. Defaults to "test". |
database? |
string |
Database override. Defaults to "test". |
containerFactory? |
(image: string) => GenericContainer |
Injectable factory for unit testing. When provided, replaces the real GenericContainer constructor. |
Implementation Notes
- Why HTTP health over WebSocket: the
/healthHTTP endpoint is simpler to poll and does not require a SurrealDB client package in this fixture. WebSocket handshakes are stateful and require protocol negotiation; plain HTTP is sufficient for readiness signalling. - Why random password per run: reusing a static password across test runs creates a security surface for tests running in CI with shared Docker networks. UUID-generation via
crypto.randomUUID()(the Web Crypto API, universally available in modern Bun and Node.js) is both fast and cryptographically random. - Dynamic import of testcontainers:
GenericContaineris dynamically imported insidestart()to keep the module side-effect-free and to allow thecontainerFactoryinjection path to bypass the import entirely for unit tests that provide their own factory. - Port mapping: testcontainers allocates an ephemeral host port for each
withExposedPorts()declaration.getMappedPort(8000)retrieves the actual host port after the container starts.