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

7.7 KiB

Tasks — surrealdb-integration-tests

1. Wiring scaffolding

  • 1.1 Add @suaveplan/testing-integration and @suaveplan/testing-integration-surrealdb as devDependencies (workspace:^) of @suaveplan/database/surrealdb. Verify peer-dep testcontainers resolves at the root.
  • 1.2 Create packages/database/surrealdb/tests/integration/ directory.
  • 1.3 Create packages/database/surrealdb/vitest.integration.config.ts:
    • Reuses createTestConfig() from @suaveplan/testing/config (pool: forks, polyfills loaded).
    • Registers SurrealDBFixture via createIntegrationSetup({ surrealdb: new SurrealDBFixture() }).
    • test.globalSetup points at the returned globalSetup path.
    • test.include scoped to tests/integration/**/*.integration.test.ts only.
    • test.exclude excludes src/** and tests/*.test.ts (unit suite stays untouched).
  • 1.4 Add "test:integration": "vitest run --config vitest.integration.config.ts" to packages/database/surrealdb/package.json scripts.
  • 1.5 Add test:integration to turbo.json pipeline at the repo root: dependsOn: ["^build"], outputs: [], cache: false (real-services tests are not cacheable).

2. Shared integration test utilities

  • 2.1 Create tests/integration/helpers/connect.ts:
    • Exports connectAdapter(inject) that calls skipIfUnavailable("surrealdb", inject), reads the injected SurrealDBConfig, instantiates SurrealAdapter, calls connect() + use({ namespace, database }) + signin({ username, password }), and returns { adapter, config }.
    • Each test wraps its work in a try/finally that calls adapter.close() so a failed assertion never leaks a WS.
  • 2.2 Create tests/integration/helpers/random-ns.ts:
    • Exports randomNamespace() returning test_${crypto.randomUUID().replace(/-/g, "_")} for per-test isolation against a shared SurrealDB container. Avoids cross-test bleed without container churn.

3. Adapter integration tests

  • 3.1 tests/integration/surreal-adapter.integration.test.ts:
    • connect → use → signin → query "SELECT 1 AS n" → close returns [{ n: 1 }].
    • Parameterised query ("SELECT $val AS v", { val: "abc" }) round-trips the param, proving passthrough is intact and not silently dropped (companion to the db.create() drop-content bug).
    • execute("DEFINE TABLE t SCHEMAFULL") followed by query("INFO FOR DB") confirms the DDL took effect on the live engine.
    • transaction(tx => …) commits when the callback resolves; rollback occurs when it throws (verified by reading the row back outside the transaction).
    • Calling any data method before connect() throws DB.NOT_CONNECTED.
  • 3.2 tests/integration/connection.integration.test.ts:
    • Pointing the adapter at ws://127.0.0.1:1 (an unbound port) surfaces an error matching error?.code === "ConnectionRefused" || error?.message?.includes("Unable to connect"). This is the exact branch the project-memory surrealdb-create-content-drop/connection-refused note documents.
    • The error is wrapped as DB.CONNECTION_FAILED via @suaveplan/error.

4. Lifecycle integration tests

  • 4.1 tests/integration/singleton.integration.test.ts:
    • getSingleton("a", factory, config, _, registry) returns the same connected DatabaseAdapter instance on the second call within the same registry Map.
    • closeSingleton("a", _, registry) closes the WS — verified by attempting adapter.query() on the previously-returned reference and observing DB.NOT_CONNECTED.
    • closeAllSingletons(_, registry) closes registered singletons in reverse insertion order (assert ordering via close-spies wrapping the adapter).
    • Two different registry maps stay isolated (passing the explicit Map per the public API).
  • 4.2 tests/integration/version-detector.integration.test.ts:
    • Detector returns a non-empty version string from the live INFO FOR ROOT (or equivalent); parsed major matches 3 for the pinned surrealdb:v3.0.4 image.
  • 4.3 tests/integration/init.integration.test.ts:
    • Initialise a fresh randomised namespace + database; insert a row via the documented INSERT INTO workaround (NOT db.create()), assert the row reads back unchanged. This is the regression test for the content-drop bug from feedback memory.
  • 4.4 tests/integration/discovery.integration.test.ts:
    • Define two tables with explicit fields, run schema discovery, assert returned shape lists both tables and every field with the expected type.

5. Skip / docker-down behaviour

  • 5.1 Each integration test's first line is if (skipIfUnavailable("surrealdb", inject)) return; so a fully-untouched developer machine (no docker, no env-bridge vars) sees SKIPPED instead of a hang or a failure.
  • 5.2 Manual verification: with the test stack down, bun run test:integration --filter=@suaveplan/database/surrealdb exits 0 with every test reporting skipped.
  • 5.3 With docker up (docker compose -f docker/docker-compose.test.yml up -d) and SURREALDB_URL=ws://localhost:7004 SURREALDB_USERNAME=root SURREALDB_PASSWORD=root exported, the suite runs against the compose container via env-bridge (no testcontainers spin-up).
  • 5.4 Without env-bridge vars, the suite spins up its own ephemeral container via testcontainers and tears it down on teardown.

6. CI integration

  • 6.1 Add a CI job step that runs before test:integration: docker compose -f docker/docker-compose.test.yml up -d --wait (relies on the existing healthchecks).
  • 6.2 Export the env-bridge variables in CI so testcontainers passthrough is taken (faster, single shared instance per job).
  • 6.3 Add a final docker compose -f docker/docker-compose.test.yml down -v step in if: always() to guarantee teardown.
  • 6.4 Confirm bunx turbo test:coverage --filter=@suaveplan/database/surrealdb is unchanged: integration tests are not counted toward Istanbul coverage of src/.

7. Documentation

  • 7.1 Add an "Integration tests" section to packages/database/surrealdb/README.md covering: how to run locally with docker up, how the env-bridge passthrough works, what skipping looks like.
  • 7.2 Co-located .md siblings for any new helper modules in tests/integration/helpers/ per the doc-coverage rule.

8. OpenSpec gate

  • 8.1 Run openspec validate surrealdb-integration-tests --strict; resolve any errors.
  • 8.2 On ship: fold specs/database-surrealdb-integration/spec.md into openspec/specs/database-surrealdb-integration/spec.md and move the change folder to openspec/archive/<yyyy-mm-dd>-surrealdb-integration-tests/.

Audit Note (2026-05-02)

Status: DEFERRED.

State at audit:

  • The bulk of the implementation has landed: packages/database/surrealdb/tests/integration/ contains surreal-adapter.integration.test.ts, connection.integration.test.ts, singleton.integration.test.ts, version-detector.integration.test.ts, init.integration.test.ts, discovery.integration.test.ts, global-setup.ts, integration-setup.ts, plus a helpers/ dir.
  • vitest.integration.config.ts exists; package.json carries the test:integration script and the two @suaveplan/testing-integration* devDependencies.
  • Unit-suite remains green (bunx turbo test --filter=@suaveplan/surrealdb → 167 tests across 10 files).

Outstanding to ship:

  1. Task 1.5 — wire test:integration into turbo.json (dependsOn: ["^build"], outputs: [], cache: false). Currently absent.
  2. Task 6 — add the CI job step (docker compose up -d --wait, env-bridge export, down -v on if: always()).
  3. Task 7.1 — add an "Integration tests" section to packages/database/surrealdb/README.md (current README has none).
  4. Task 8 — openspec validate surrealdb-integration-tests --strict, then fold spec deltas + archive.