Files
2026-05-27 23:29:53 +01:00

6.7 KiB

testing-integration-surrealdb

Purpose

SurrealDB v3.0.4 ServiceFixture for integration tests. Provides env-bridge passthrough (SURREALDB_URL, SURREALDB_USERNAME, SURREALDB_PASSWORD), HTTP health checking on /health, a random password per run, and an injectable container factory. Enables real SurrealDB integration tests without mocks. Depends on @suaveplan/testing-integration and testcontainers.

Requirements

Requirement: SurrealDBFixture implements ServiceFixture

The package SHALL export SurrealDBFixture with name === "surrealdb". SurrealDBConfig SHALL be { url: string; namespace: string; database: string; username: string; password: string }.

Scenario: name property is "surrealdb"

  • WHEN an instance's .name is read
  • THEN the value is the literal "surrealdb"

Verified by: src/fixture/surrealdb-fixture.test.ts::"name property returns surrealdb"


Requirement: Env-bridge passthrough mode (3 vars)

When SURREALDB_URL, SURREALDB_USERNAME, AND SURREALDB_PASSWORD are all set and non-empty, start() MUST return the config directly without starting a container. Namespace/database fall back to SURREALDB_DEFAULT_NAMESPACE/SURREALDB_DEFAULT_DATABASE unless overridden via options. In passthrough mode stop() MUST be a no-op and healthCheck() MUST return false (no container to probe).

Scenario: returns config from env vars

  • WHEN all three env vars are set
  • THEN start() returns the config without invoking testcontainers

Scenario: stop is a no-op in passthrough mode

  • WHEN the fixture started in passthrough mode and stop() is called
  • THEN no container is touched

Scenario: healthCheck returns false in passthrough mode

  • WHEN healthCheck() is called after a passthrough start
  • THEN the result is false

Verified by: src/fixture/surrealdb-fixture.test.ts::"passthrough mode: returns config from env vars" AND src/fixture/surrealdb-fixture.test.ts::"passthrough mode: stop is a no-op" AND src/fixture/surrealdb-fixture.test.ts::"passthrough mode: healthCheck returns false when no container"


Requirement: Container mode

When env vars are partially or unset, start() MUST start a SurrealDB v3 container via the injected containerFactory (or GenericContainer), pass start --auth --user <root> --pass <generated> as the command, expose SURREALDB_CONTAINER_PORT, and return { url: "ws://localhost:<port>", namespace, database, username: SURREALDB_DEFAULT_USERNAME, password: <generated> }. Image MUST be overridable. Namespace/database MUST be overridable via constructor options.

Scenario: container mode happy path returns correct config

  • WHEN start() completes container boot
  • THEN result.url, namespace, database, username, password are populated

Scenario: stop calls container.stop()

  • WHEN stop() follows start() in container mode
  • THEN the container's stop() is invoked exactly once

Scenario: image override: factory called with custom image

  • WHEN the fixture is constructed with image: "x"
  • THEN the container factory is invoked with "x"

Scenario: namespace and database overrides reflected in config

  • WHEN the fixture is constructed with custom namespace/database
  • THEN the returned config uses those overrides

Scenario: factory falls back to dynamic GenericContainer import

  • WHEN no containerFactory is injected
  • THEN the fixture dynamically imports testcontainers and uses GenericContainer

Scenario: start() stops container if getMappedPort throws

  • WHEN getMappedPort() throws after the container has booted
  • THEN start() calls container.stop() and clears the reference before re-throwing

Verified by: src/fixture/surrealdb-fixture.test.ts::"container mode happy path: returns correct config" AND src/fixture/surrealdb-fixture.test.ts::"container mode: stop calls container.stop()" AND src/fixture/surrealdb-fixture.test.ts::"image override: factory called with custom image" AND src/fixture/surrealdb-fixture.test.ts::"namespace and database overrides reflected in config" AND src/fixture/surrealdb-fixture.test.ts::"resolveContainerFactory: returns factory from dynamic import when no containerFactory" AND src/fixture/surrealdb-fixture.test.ts::"start(): stops container and clears reference when getMappedPort throws"


Requirement: HTTP /health probe

In container mode, healthCheck() MUST GET http://localhost:<mappedPort>/health via the injected fetchFn (default globalThis.fetch) and return res.ok. Network errors MUST be swallowed and return false. Without a started container, healthCheck() MUST return false.

Scenario: returns true when fetchFn returns ok

  • WHEN the injected fetch returns { ok: true }
  • THEN healthCheck() resolves to true

Scenario: returns false when fetchFn throws

  • WHEN the injected fetch throws
  • THEN healthCheck() resolves to false

Scenario: returns false when no container

  • WHEN healthCheck() is called before start()
  • THEN the result is false

Verified by: src/fixture/surrealdb-fixture.test.ts::"container mode: healthCheck returns true when fetchFn returns ok" AND src/fixture/surrealdb-fixture.test.ts::"container mode: healthCheck returns false when fetchFn throws" AND src/fixture/surrealdb-fixture.test.ts::"healthCheck returns false when no container"


Requirement: Random per-run password

In container mode, start() MUST generate the SurrealDB root password via crypto.randomUUID() and use it as both the container start arg and the returned config field. Password reuse across runs MUST NOT occur.

Scenario: generated password matches UUID format

  • WHEN start() runs in container mode
  • THEN result.password matches the UUID v4 regex

Verified by: src/fixture/surrealdb-fixture.test.ts::"generated password matches UUID format"


Requirement: stop() is idempotent

stop() MUST be safe to call when no container has been started.

Scenario: stop without start is a no-op

  • WHEN stop() is called on a freshly-constructed fixture
  • THEN no error is thrown

Verified by: src/fixture/surrealdb-fixture.test.ts::"stop when no container is a no-op"


Requirement: testing-integration is a peer dependency

The package's package.json MUST list @suaveplan/testing-integration and testcontainers in peerDependencies, NOT in dependencies.

Scenario: variant does not bundle the core or testcontainers

  • WHEN the published package.json is inspected
  • THEN dependencies does not contain either symbol

Verified by: src/fixture/surrealdb-fixture.test.ts::"name property returns surrealdb"