Move docs/ package mirror into document-navigator plugin

Relocate the ~6k-file docs tree from the repo root into
plugins/document-navigator/docs/ so the plugin is self-contained and
portable. docs/superpowers/ (specs and plans) stays at the repo root.

Moved via cp+rm rather than git mv because directory rename() fails with
EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the
identical-content files at commit time.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-30 01:10:00 +01:00
parent fe3fedf42e
commit 9bf56a806b
6022 changed files with 12437 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
# @suaveplan/testing-integration-redis - Redis 7 testcontainers fixture for @suaveplan/testing-integration
## Summary
Redis 7 testcontainers fixture for `@suaveplan/testing-integration`.
Implements `ServiceFixture<RedisConfig>` — manages a Redis container lifecycle with env-bridge passthrough and TCP PING health checks. Returns a plain config; consumers bring their own Redis client.
<!-- begin:auto-docs -->
## Documentation tree
- [fixture](./src/fixture/redis-fixture.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [redis-fixture](./src/fixture/redis-fixture.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
<!-- end:auto-docs --> - [redis-fixture](./src/fixture/redis-fixture.md) — <!-- begin:auto-docs --> _(no submodules)_- [redis-fixture](./src/fixture/redis-fixture.md) — <!-- begin:auto-docs --> _(no submodules)_- [redis-fixture](./src/fixture/redis-fixture.md) — <!-- begin:auto-docs --> _(no submodules)_- [redis-fixture](./src/fixture/redis-fixture.md) — <!-- begin:auto-docs --> _(no submodules)_
## Install
```bash
bun add -D @suaveplan/testing-integration-redis
```
## Quick Start
```typescript
import { RedisFixture } from "@suaveplan/testing-integration-redis";
const fixture = new RedisFixture();
const config = await fixture.start();
// config.url, config.host, config.port
await fixture.stop();
```
## Env-bridge passthrough
Set the env var to skip container startup:
```text
REDIS_URL=redis://localhost:6379
```
## Docs
- [RedisFixture](src/fixture/redis-fixture.md)

View File

@@ -0,0 +1,117 @@
# RedisFixture
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`RedisFixture` is an integration test fixture that manages the full lifecycle of a Redis 7 container using testcontainers. It implements the `ServiceFixture<RedisConfig>` interface from `@suaveplan/testing-integration`, enabling consistent startup, health checking via TCP PING, and teardown as part of a `TestEnvironment` or standalone usage.
The fixture intentionally keeps `ioredis` and other Redis clients out of its dependencies — it returns a plain `RedisConfig` object with `url`, `host`, and `port`. Consumers bring their own Redis client library, keeping the fixture lightweight and framework-agnostic.
## Features
- **Env-bridge passthrough**: when `REDIS_URL` is set and non-empty, container startup is bypassed and the URL is parsed into a `RedisConfig` directly.
- **TCP PING health check**: connects to Redis via `node:net`, sends `PING\r\n`, and verifies the response starts with `+PONG`. No Redis client dependency required.
- **Injectable TCP ping function**: the `tcpPingFn` option allows unit tests to substitute the health check without a real network connection.
- **Injectable container factory**: the `containerFactory` option allows unit tests to swap in a fake container without starting Docker.
- **URL parsing for passthrough**: `new URL(url)` extracts `hostname` and `port` from the `REDIS_URL` env var, ensuring `RedisConfig.host` and `RedisConfig.port` are always consistent with `RedisConfig.url`.
- **Idempotent stop**: calling `stop()` on an already-stopped or passthrough fixture is safe and does not throw.
## Usage: Basic Example
```typescript
import { RedisFixture } from "@suaveplan/testing-integration-redis";
const fixture = new RedisFixture();
const config = await fixture.start();
// config.url → "redis://localhost:<randomPort>"
// config.host → "localhost"
// config.port → random ephemeral port
// Use with ioredis:
// const redis = new Redis(config.url);
await fixture.stop();
```
## Usage: Advanced Example
```typescript
import { RedisFixture } from "@suaveplan/testing-integration-redis";
import { createClient } from "redis";
const fixture = new RedisFixture({
image: "redis:7-alpine",
tcpPingFn: async (port, host) => {
// Custom health check — connect and verify
const client = createClient({ socket: { host, port } });
try {
await client.connect();
const pong = await client.ping();
return pong === "PONG";
} catch {
return false;
} finally {
await client.disconnect();
}
},
});
const config = await fixture.start();
const client = createClient({ url: config.url });
await client.connect();
await client.set("key", "value");
await client.disconnect();
await fixture.stop();
```
## API Reference
### `class RedisFixture`
Implements `ServiceFixture<RedisConfig>`.
#### `constructor(options?: RedisFixtureOptions)`
Creates a new fixture instance. All options are optional.
#### `name: string`
Always `"redis"`. Used by `TestEnvironment` as the registry key.
#### `start(): Promise<RedisConfig>`
Starts the service. Returns the runtime configuration. In passthrough mode (when `REDIS_URL` env var is set), returns immediately with parsed config. Otherwise starts a testcontainers container.
#### `stop(): Promise<void>`
Stops the container. No-op in passthrough mode or when not started.
#### `healthCheck(): Promise<boolean>`
Returns `true` when a TCP PING to `localhost:<mappedPort>` returns `+PONG`. Returns `false` if no container is active or the TCP connection fails.
### `interface RedisConfig`
| Field | Type | Description |
|-------|------|-------------|
| `url` | `string` | Full Redis URL: `redis://localhost:<port>` |
| `host` | `string` | Hostname parsed from the URL |
| `port` | `number` | Port number parsed from the URL |
### `interface RedisFixtureOptions`
| Field | Type | Description |
|-------|------|-------------|
| `image?` | `string` | Docker image override. Defaults to `redis:7-alpine`. |
| `containerFactory?` | `(image: string) => GenericContainer` | Injectable factory for unit testing. |
| `tcpPingFn?` | `(port: number, host: string) => Promise<boolean>` | Injectable TCP ping for health check unit testing. |
## Implementation Notes
- **Why TCP PING over Redis client**: including `ioredis` or `redis` in this fixture's dependencies would force consumers to use a specific client version. The TCP PING is protocol-level and works with any Redis server, requiring only Node.js's built-in `node:net` module.
- **Dynamic import of testcontainers**: the `GenericContainer` import is deferred to `start()` time so unit tests that provide a `containerFactory` do not trigger testcontainers initialization.
- **URL parsing for passthrough**: `new URL(url)` provides consistent host/port extraction. If the URL omits a port, the fixture defaults to `REDIS_CONTAINER_PORT` (6379).
- **Socket timeout**: the built-in `defaultTcpPing` uses a 2-second socket timeout to prevent health check hangs during container startup race conditions.