Features: - Add CLI with commands: start, add, remove, list, fetch, status, items - Auto-detect RSS format when adding feeds - Auto-run database migrations on startup - Extract full HTML content from RSS description field (NOS-style feeds) - Extract image URLs from RSS enclosure tags - Display images in terminal output with emoji - Include imageUrl in JSON formatter output Database: - Add image_url column to feed_items table - Update storage layer to persist imageUrl field Tests: - Add 10 CLI integration tests - Add 3 RSS parser tests for image/content extraction - Add 2 storage tests for imageUrl persistence Dependencies: - Add commander for CLI framework All 144 tests passing
128 lines
3.3 KiB
TypeScript
128 lines
3.3 KiB
TypeScript
/**
|
|
* CLI tests.
|
|
* Tests the Pulse CLI commands.
|
|
*/
|
|
|
|
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
import { execSync } from 'child_process';
|
|
import { existsSync, unlinkSync } from 'fs';
|
|
import { join } from 'path';
|
|
|
|
const TEST_DB_PATH = join(process.cwd(), 'test-cli.db');
|
|
const CLI_CMD = 'npx tsx cli.ts';
|
|
|
|
function runCli(args: string): string {
|
|
const env = {
|
|
...process.env,
|
|
PULSE_DATABASE_TYPE: 'sqlite',
|
|
PULSE_SQLITE_PATH: TEST_DB_PATH,
|
|
};
|
|
|
|
try {
|
|
return execSync(`${CLI_CMD} ${args}`, {
|
|
encoding: 'utf-8',
|
|
env,
|
|
stdio: 'pipe',
|
|
});
|
|
} catch (error) {
|
|
if (error instanceof Error && 'stdout' in error && error.stdout) {
|
|
return error.stdout as string;
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
describe('CLI', () => {
|
|
beforeEach(() => {
|
|
// Clean up test database before each test
|
|
if (existsSync(TEST_DB_PATH)) {
|
|
unlinkSync(TEST_DB_PATH);
|
|
}
|
|
});
|
|
|
|
afterEach(() => {
|
|
// Clean up test database after each test
|
|
if (existsSync(TEST_DB_PATH)) {
|
|
unlinkSync(TEST_DB_PATH);
|
|
}
|
|
});
|
|
|
|
describe('help', () => {
|
|
it('should display help', () => {
|
|
const output = runCli('--help');
|
|
expect(output).toContain('Usage: pulse');
|
|
expect(output).toContain('Commands:');
|
|
expect(output).toContain('start');
|
|
expect(output).toContain('add');
|
|
expect(output).toContain('list');
|
|
});
|
|
|
|
it('should display version', () => {
|
|
const output = runCli('--version');
|
|
expect(output.trim()).toBe('0.1.0');
|
|
});
|
|
});
|
|
|
|
describe('list', () => {
|
|
it('should show empty list when no feeds', () => {
|
|
const output = runCli('list');
|
|
expect(output).toContain('No feed sources configured');
|
|
});
|
|
});
|
|
|
|
describe('add', () => {
|
|
it('should add a feed source', () => {
|
|
const output = runCli('add "https://example.com/feed.xml" --name "Test Feed" --format rss');
|
|
expect(output).toContain('Added feed:');
|
|
expect(output).toContain('https://example.com/feed.xml');
|
|
expect(output).toContain('rss');
|
|
});
|
|
|
|
it('should reject invalid format', () => {
|
|
expect(() => {
|
|
runCli('add "https://example.com/feed.xml" --format invalid');
|
|
}).toThrow();
|
|
});
|
|
});
|
|
|
|
describe('remove', () => {
|
|
it('should remove a feed source', () => {
|
|
// First add a feed
|
|
runCli('add "https://example.com/feed.xml" --name "Test Feed" --format rss');
|
|
|
|
// Then remove it
|
|
const output = runCli('remove 9bb0a00b');
|
|
expect(output).toContain('Removed feed:');
|
|
});
|
|
|
|
it('should error when removing non-existent feed', () => {
|
|
expect(() => {
|
|
runCli('remove non-existent-id');
|
|
}).toThrow();
|
|
});
|
|
});
|
|
|
|
describe('status', () => {
|
|
it('should show status for no feeds', () => {
|
|
const output = runCli('status');
|
|
expect(output).toContain('No feed sources configured');
|
|
});
|
|
|
|
it('should show status for healthy feed', () => {
|
|
// Add a feed
|
|
runCli('add "https://example.com/feed.xml" --name "Test Feed" --format rss');
|
|
|
|
const output = runCli('status');
|
|
expect(output).toContain('Healthy');
|
|
expect(output).toContain('Test Feed');
|
|
});
|
|
});
|
|
|
|
describe('items', () => {
|
|
it('should show no items when database is empty', () => {
|
|
const output = runCli('items');
|
|
expect(output).toContain('No items found');
|
|
});
|
|
});
|
|
});
|