Files
lobehub/apps/cli/e2e/topic.e2e.test.ts
Arvin Xu aa8082d6b2 feat: lobehub cli for better agency agent (#12897)
* fix cli alias

* 🐛 fix(cli): fix gen text non-streaming mode and streaming SSE parsing

- Add `responseMode: 'json'` for non-streaming requests to get plain JSON instead of SSE
- Fix streaming SSE parser to handle LobeHub's JSON string format (e.g. `"Hello"`)
- Support both OpenAI and Anthropic response formats in non-streaming mode
- Add E2E tests for all generate commands (text, list, tts, asr, alias)
- Update skills knowledge.md docs with new kb commands

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

*  feat(cli): unify skill install command and add e2e tests

Merge import-github/import-url/import-market into a single `skill install <source>` command with auto-detection (GitHub URL/shorthand, ZIP URL, or marketplace identifier). Add alias `skill i`. Add comprehensive e2e and unit tests for skill commands.

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

* 🔨 chore: fix linter formatting in memory e2e test

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

* 🐛 fix: add vitest-environment node declaration to aiProvider test

Fix server-side env variable access error by declaring node environment.

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

* fix cli review

* fix test

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 11:06:52 +08:00

117 lines
3.7 KiB
TypeScript

import { execSync } from 'node:child_process';
import { describe, expect, it } from 'vitest';
/**
* E2E tests for `lh topic` conversation topic management commands.
*
* Prerequisites:
* - `lh` CLI is installed and linked globally
* - User is authenticated (`lh login` completed)
* - Network access to the LobeHub server
*
* These tests create a real topic, verify CRUD operations, then clean up.
*/
const CLI = process.env.LH_CLI_PATH || 'lh';
const TIMEOUT = 30_000;
function run(args: string): string {
return execSync(`${CLI} ${args}`, {
encoding: 'utf-8',
env: { ...process.env, PATH: `${process.env.HOME}/.bun/bin:${process.env.PATH}` },
timeout: TIMEOUT,
}).trim();
}
function runJson<T = any>(args: string): T {
const output = run(args);
return JSON.parse(output) as T;
}
describe('lh topic - E2E', () => {
const testTitle = `E2E-Topic-${Date.now()}`;
let createdId: string;
// ── create ────────────────────────────────────────────
describe('create', () => {
it('should create a topic', () => {
const output = run(`topic create -t "${testTitle}"`);
expect(output).toContain('Created topic');
const match = output.match(/Created topic\s+(\S+)/);
expect(match).not.toBeNull();
createdId = match![1];
});
});
// ── list ──────────────────────────────────────────────
describe('list', () => {
it('should list topics in table format', () => {
const output = run('topic list');
// Should show table headers or "No topics"
expect(output).toBeTruthy();
});
it('should output JSON', () => {
const list = runJson<any[]>('topic list --json id,title');
expect(Array.isArray(list)).toBe(true);
});
});
// ── search ────────────────────────────────────────────
describe('search', () => {
it('should search topics', () => {
const output = run(`topic search "${testTitle}"`);
expect(typeof output).toBe('string');
});
it('should output JSON', () => {
const list = runJson<any[]>(`topic search "${testTitle}" --json id,title`);
expect(Array.isArray(list)).toBe(true);
});
});
// ── edit ──────────────────────────────────────────────
describe('edit', () => {
const updatedTitle = `${testTitle}-Updated`;
it('should update topic title', () => {
const output = run(`topic edit ${createdId} -t "${updatedTitle}"`);
expect(output).toContain('Updated topic');
});
it('should error when no changes specified', () => {
expect(() => run(`topic edit ${createdId}`)).toThrow();
});
});
// ── recent ────────────────────────────────────────────
describe('recent', () => {
it('should list recent topics', () => {
const output = run('topic recent');
expect(output).toBeTruthy();
});
it('should output JSON', () => {
const list = runJson<any[]>('topic recent --json id,title');
expect(Array.isArray(list)).toBe(true);
});
});
// ── delete (cleanup) ──────────────────────────────────
describe('delete', () => {
it('should delete the topic', () => {
const output = run(`topic delete ${createdId} --yes`);
expect(output).toContain('Deleted');
expect(output).toContain('1 topic(s)');
});
});
});