Files
nanoclaw/setup/environment.test.ts
Gabi Simons 11c201088b refactor: CI optimization, logging improvements, and codebase formatting (#456)
* fix(db): remove unique constraint on folder to support multi-channel agents

* ci: implement automated skill drift detection and self-healing PRs

* fix: align registration logic with Gavriel's feedback and fix build/test issues from Daniel Mi

* style: conform to prettier standards for CI validation

* test: fix branch naming inconsistency in CI (master vs main)

* fix(ci): robust module resolution by removing file extensions in scripts

* refactor(ci): simplify skill validation by removing redundant combination tests

* style: conform skills-engine to prettier, unify logging in index.ts and cleanup unused imports

* refactor: extract multi-channel DB changes to separate branch

Move channel column, folder suffix logic, and related migrations
to feat/multi-channel-db-v2 for independent review. This PR now
contains only CI/CD optimizations, Prettier formatting, and
logging improvements.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 23:13:36 +02:00

122 lines
3.4 KiB
TypeScript

import { describe, it, expect, beforeEach } from 'vitest';
import fs from 'fs';
import Database from 'better-sqlite3';
/**
* Tests for the environment check step.
*
* Verifies: config detection, Docker/AC detection, DB queries.
*/
describe('environment detection', () => {
it('detects platform correctly', async () => {
const { getPlatform } = await import('./platform.js');
const platform = getPlatform();
expect(['macos', 'linux', 'unknown']).toContain(platform);
});
});
describe('registered groups DB query', () => {
let db: Database.Database;
beforeEach(() => {
db = new Database(':memory:');
db.exec(`CREATE TABLE IF NOT EXISTS registered_groups (
jid TEXT PRIMARY KEY,
name TEXT NOT NULL,
folder TEXT NOT NULL UNIQUE,
trigger_pattern TEXT NOT NULL,
added_at TEXT NOT NULL,
container_config TEXT,
requires_trigger INTEGER DEFAULT 1
)`);
});
it('returns 0 for empty table', () => {
const row = db
.prepare('SELECT COUNT(*) as count FROM registered_groups')
.get() as { count: number };
expect(row.count).toBe(0);
});
it('returns correct count after inserts', () => {
db.prepare(
`INSERT INTO registered_groups (jid, name, folder, trigger_pattern, added_at, requires_trigger)
VALUES (?, ?, ?, ?, ?, ?)`,
).run(
'123@g.us',
'Group 1',
'group-1',
'@Andy',
'2024-01-01T00:00:00.000Z',
1,
);
db.prepare(
`INSERT INTO registered_groups (jid, name, folder, trigger_pattern, added_at, requires_trigger)
VALUES (?, ?, ?, ?, ?, ?)`,
).run(
'456@g.us',
'Group 2',
'group-2',
'@Andy',
'2024-01-01T00:00:00.000Z',
1,
);
const row = db
.prepare('SELECT COUNT(*) as count FROM registered_groups')
.get() as { count: number };
expect(row.count).toBe(2);
});
});
describe('credentials detection', () => {
it('detects ANTHROPIC_API_KEY in env content', () => {
const content =
'SOME_KEY=value\nANTHROPIC_API_KEY=sk-ant-test123\nOTHER=foo';
const hasCredentials =
/^(CLAUDE_CODE_OAUTH_TOKEN|ANTHROPIC_API_KEY)=/m.test(content);
expect(hasCredentials).toBe(true);
});
it('detects CLAUDE_CODE_OAUTH_TOKEN in env content', () => {
const content = 'CLAUDE_CODE_OAUTH_TOKEN=token123';
const hasCredentials =
/^(CLAUDE_CODE_OAUTH_TOKEN|ANTHROPIC_API_KEY)=/m.test(content);
expect(hasCredentials).toBe(true);
});
it('returns false when no credentials', () => {
const content = 'ASSISTANT_NAME="Andy"\nOTHER=foo';
const hasCredentials =
/^(CLAUDE_CODE_OAUTH_TOKEN|ANTHROPIC_API_KEY)=/m.test(content);
expect(hasCredentials).toBe(false);
});
});
describe('Docker detection logic', () => {
it('commandExists returns boolean', async () => {
const { commandExists } = await import('./platform.js');
expect(typeof commandExists('docker')).toBe('boolean');
expect(typeof commandExists('nonexistent_binary_xyz')).toBe('boolean');
});
});
describe('WhatsApp auth detection', () => {
it('detects non-empty auth directory logic', () => {
// Simulate the check: directory exists and has files
const hasAuth = (authDir: string) => {
try {
return fs.existsSync(authDir) && fs.readdirSync(authDir).length > 0;
} catch {
return false;
}
};
// Non-existent directory
expect(hasAuth('/tmp/nonexistent_auth_dir_xyz')).toBe(false);
});
});