From 030a2b2bc5f5a7aadf638acd2980c96029f21c38 Mon Sep 17 00:00:00 2001 From: Cameron Date: Wed, 4 Feb 2026 17:13:18 -0800 Subject: [PATCH] feat: add CI test workflow and commands tests (#147) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Testing infrastructure improvements: 1. Add GitHub Actions workflow (.github/workflows/test.yml) - Runs on push/PR to main - Installs deps, builds, runs tests - Blocks merging broken code 2. Add tests for commands.ts (src/core/commands.test.ts) - Tests parseCommand() with valid/invalid inputs - Tests case insensitivity - Tests COMMANDS array and HELP_TEXT Now at 231 tests across 17 test files. Written by Cameron ◯ Letta Code "Test early, test often." - Software proverb --- .github/workflows/test.yml | 27 ++++++++++++ src/core/commands.test.ts | 86 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 .github/workflows/test.yml create mode 100644 src/core/commands.test.ts diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..82f03e8 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,27 @@ +name: Tests + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Build + run: npm run build + + - name: Run tests + run: npm run test:run diff --git a/src/core/commands.test.ts b/src/core/commands.test.ts new file mode 100644 index 0000000..0f8f360 --- /dev/null +++ b/src/core/commands.test.ts @@ -0,0 +1,86 @@ +import { describe, it, expect } from 'vitest'; +import { parseCommand, COMMANDS, HELP_TEXT } from './commands.js'; + +describe('parseCommand', () => { + describe('valid commands', () => { + it('returns "status" for /status', () => { + expect(parseCommand('/status')).toBe('status'); + }); + + it('returns "heartbeat" for /heartbeat', () => { + expect(parseCommand('/heartbeat')).toBe('heartbeat'); + }); + + it('returns "help" for /help', () => { + expect(parseCommand('/help')).toBe('help'); + }); + + it('returns "start" for /start', () => { + expect(parseCommand('/start')).toBe('start'); + }); + }); + + describe('invalid input', () => { + it('returns null for non-slash messages', () => { + expect(parseCommand('hello')).toBeNull(); + expect(parseCommand('status')).toBeNull(); + }); + + it('returns null for empty string', () => { + expect(parseCommand('')).toBeNull(); + }); + + it('returns null for null/undefined', () => { + expect(parseCommand(null)).toBeNull(); + expect(parseCommand(undefined)).toBeNull(); + }); + + it('returns null for unknown commands', () => { + expect(parseCommand('/unknown')).toBeNull(); + expect(parseCommand('/foo')).toBeNull(); + expect(parseCommand('/stats')).toBeNull(); // Similar but not exact + }); + }); + + describe('command parsing', () => { + it('handles commands with extra text after', () => { + expect(parseCommand('/status please')).toBe('status'); + expect(parseCommand('/help me')).toBe('help'); + }); + + it('is case insensitive', () => { + expect(parseCommand('/STATUS')).toBe('status'); + expect(parseCommand('/Help')).toBe('help'); + expect(parseCommand('/HEARTBEAT')).toBe('heartbeat'); + }); + + it('handles commands with leading/trailing whitespace in args', () => { + expect(parseCommand('/status ')).toBe('status'); + }); + }); +}); + +describe('COMMANDS', () => { + it('contains all expected commands', () => { + expect(COMMANDS).toContain('status'); + expect(COMMANDS).toContain('heartbeat'); + expect(COMMANDS).toContain('help'); + expect(COMMANDS).toContain('start'); + }); + + it('has exactly 4 commands', () => { + expect(COMMANDS).toHaveLength(4); + }); +}); + +describe('HELP_TEXT', () => { + it('contains command descriptions', () => { + expect(HELP_TEXT).toContain('/status'); + expect(HELP_TEXT).toContain('/heartbeat'); + expect(HELP_TEXT).toContain('/help'); + }); + + it('contains LettaBot branding', () => { + expect(HELP_TEXT).toContain('LettaBot'); + }); +});