openclaw/TESTING.md
The fastest way to test the plugin is using the pre-built Docker E2E environment:
cd openclaw
# Automated test (builds, installs plugin on real OpenClaw, verifies everything)
./test-e2e.sh
# Interactive shell (for manual exploration)
./test-e2e.sh --interactive
# Just build the image
./test-e2e.sh --build-only
cd openclaw
npm test # compiles TypeScript, runs 17 tests
Tests plugin registration, service lifecycle, command handling, SSE integration, and all 6 channel types.
node test-sse-consumer.js
Quick check that the plugin loads and registers its service + command correctly.
./test-container.sh # Unit tests in clean Docker
./test-container.sh --full # Integration tests with mock worker
./test-e2e.sh
This is the most comprehensive test. It:
ghcr.io/openclaw/openclaw:main Docker imageopenclaw plugins install (same as a real user)openclaw plugins enableAll 16 checks must pass.
For manual walkthrough testing, use the interactive Docker mode:
./test-e2e.sh --interactive
This drops you into a fully-configured OpenClaw container with the plugin pre-installed.
node openclaw.mjs plugins list
node openclaw.mjs plugins info claude-mem
node openclaw.mjs plugins doctor
Expected:
claude-mem appears in the plugins list as "enabled" or "loaded"/home/node/.openclaw/extensions/claude-mem/ls -la /home/node/.openclaw/extensions/claude-mem/
cat /home/node/.openclaw/extensions/claude-mem/openclaw.plugin.json
cat /home/node/.openclaw/extensions/claude-mem/package.json
Expected:
dist/index.js exists (compiled plugin)openclaw.plugin.json has "id": "claude-mem" and "kind": "memory"package.json has openclaw.extensions field pointing to ./dist/index.jsnode /app/mock-worker.js &
Verify it's running:
curl -s http://localhost:37777/health
# → {"status":"ok"}
curl -s --max-time 3 http://localhost:37777/stream
# → data: {"type":"connected","message":"Mock worker SSE stream"}
# → data: {"type":"new_observation","observation":{...}}
cat > /home/node/.openclaw/openclaw.json << 'EOF'
{
"gateway": {
"mode": "local",
"auth": {
"mode": "token",
"token": "e2e-test-token"
}
},
"plugins": {
"slots": {
"memory": "claude-mem"
},
"entries": {
"claude-mem": {
"enabled": true,
"config": {
"workerPort": 37777,
"observationFeed": {
"enabled": true,
"channel": "telegram",
"to": "test-chat-id-12345"
}
}
}
}
}
}
EOF
node openclaw.mjs gateway --allow-unconfigured --verbose --token e2e-test-token
Expected in gateway logs:
[claude-mem] OpenClaw plugin loaded — v1.0.0[claude-mem] Observation feed starting — channel: telegram, target: test-chat-id-12345[claude-mem] Connecting to SSE stream at http://localhost:37777/stream[claude-mem] Connected to SSE streamFrom a second shell in the container (or after stopping the gateway):
/bin/bash /app/e2e-verify.sh
For testing with a real claude-mem worker and real messaging channel:
cd openclaw && npm run build# Build the plugin
cd openclaw && npm run build
# Install on OpenClaw (from the openclaw/ directory)
openclaw plugins install .
# Enable it
openclaw plugins enable claude-mem
Edit ~/.openclaw/openclaw.json to add plugin config:
{
"plugins": {
"entries": {
"claude-mem": {
"enabled": true,
"config": {
"workerPort": 37777,
"observationFeed": {
"enabled": true,
"channel": "telegram",
"to": "YOUR_CHAT_ID"
}
}
}
}
}
}
Supported channels: telegram, discord, signal, slack, whatsapp, line
openclaw restart
Look for in logs:
[claude-mem] OpenClaw plugin loaded — v1.0.0[claude-mem] Connected to SSE streamStart a Claude Code session with claude-mem enabled and perform any action. The worker will emit a new_observation SSE event.
Check the target messaging channel for:
🧠 Claude-Mem Observation
**Observation Title**
Optional subtitle
api.log is not a functionThe plugin was built against the wrong API. Ensure src/index.ts uses api.logger.info() not api.log(). Rebuild with npm run build.
SSE stream error: fetch failed. Reconnecting in 1scd /path/to/claude-mem && npm run build-and-syncworkerPort in config matches the worker's actual port (default: 37777)Observation feed misconfigured — channel or target missingchannel and to to observationFeed in configtelegram, discord, signal, slack, whatsapp, or lineObservation feed disabledobservationFeed.enabled: trueto) is correctFailed to send to <channel> in logsplugin disabled (memory slot set to "memory-core")"slots": { "memory": "claude-mem" } to plugins config