Skip to content

Testing & Documentation #7

@ada-evorada

Description

@ada-evorada

Issue #9: Testing & Documentation

Epic: #1
Phase: 5 - Polish
Estimated Time: 4-5 days
Priority: High
Depends On: #2, #3, #4, #5, #6

Goal

Comprehensive testing suite and documentation for the Claude Code Mattermost plugin, ensuring reliability and ease of use.

Tasks

1. Unit Tests (Go Backend)

Plugin Core:

  • Slash command parsing and validation
  • Session management (create/stop/status)
  • Bot message posting
  • KV store operations

Bridge Client:

  • REST API calls
  • WebSocket message handling
  • Error handling and retries
  • Connection management

File Operations:

  • File path validation
  • Permission checks
  • Security filtering
// server/plugin_test.go
func TestExecuteCommand(t *testing.T) {
    tests := []struct {
        name    string
        command string
        want    *model.CommandResponse
        wantErr bool
    }{
        {
            name:    "claude without session",
            command: "/claude help me",
            want:    ephemeralResponse("No active session"),
            wantErr: false,
        },
        // ... more test cases
    }
    
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            // test implementation
        })
    }
}

2. Integration Tests (Go)

End-to-End Flows:

  • Start session → send message → receive response
  • File operations (browse → view → edit → save)
  • Interactive buttons (approve/reject)
  • Session lifecycle

Bridge Server Integration:

  • Mock bridge server for testing
  • Real bridge server tests (optional)
// server/integration_test.go
func TestSessionLifecycle(t *testing.T) {
    // Setup test environment
    plugin := setupTestPlugin(t)
    
    // Start session
    resp := plugin.ExecuteCommand(&model.CommandArgs{
        Command: "/claude-start /tmp/test-project",
    })
    assert.Nil(t, resp.Text)
    
    // Verify session created
    session := plugin.getActiveSession(testChannelID)
    assert.NotNil(t, session)
    
    // Send message
    resp = plugin.ExecuteCommand(&model.CommandArgs{
        Command: "/claude hello",
    })
    
    // Stop session
    resp = plugin.ExecuteCommand(&model.CommandArgs{
        Command: "/claude-stop",
    })
}

3. Frontend Tests (React)

Component Tests:

  • Message rendering
  • Interactive buttons
  • Dialogs
// webapp/src/components/test/MessageActions.test.tsx
import { render, fireEvent } from '@testing-library/react';
import MessageActions from '../MessageActions';

describe('MessageActions', () => {
  test('renders approve/reject buttons', () => {
    const { getByText } = render(
      <MessageActions changeId="test-123" />
    );
    
    expect(getByText('✅ Approve')).toBeInTheDocument();
    expect(getByText('❌ Reject')).toBeInTheDocument();
  });
  
  test('calls approve handler on click', () => {
    const onApprove = jest.fn();
    const { getByText } = render(
      <MessageActions changeId="test-123" onApprove={onApprove} />
    );
    
    fireEvent.click(getByText('✅ Approve'));
    expect(onApprove).toHaveBeenCalledWith('test-123');
  });
});

4. Bridge Server Tests (Node.js)

Unit Tests:

  • Session creation/deletion
  • Message handling
  • File operations
  • Database operations
// bridge-server/src/test/session.test.ts
import { SessionManager } from '../session-manager';

describe('SessionManager', () => {
  let manager: SessionManager;
  
  beforeEach(() => {
    manager = new SessionManager();
  });
  
  test('creates session with valid project path', async () => {
    const session = await manager.createSession({
      projectPath: '/tmp/test',
      userId: 'user123',
      channelId: 'channel456',
    });
    
    expect(session.id).toBeDefined();
    expect(session.status).toBe('active');
  });
  
  test('rejects invalid project path', async () => {
    await expect(
      manager.createSession({
        projectPath: '../../../etc/passwd',
        userId: 'user123',
        channelId: 'channel456',
      })
    ).rejects.toThrow('Invalid project path');
  });
});

5. E2E Tests (Optional)

Using Playwright or Cypress for full user flows:

// e2e/tests/basic-flow.spec.ts
import { test, expect } from '@playwright/test';

test('start session and send message', async ({ page }) => {
  // Login to Mattermost
  await page.goto('http://localhost:8065');
  await page.fill('input[name="loginId"]', 'testuser');
  await page.fill('input[name="password"]', 'testpass');
  await page.click('button[type="submit"]');
  
  // Execute slash command
  await page.fill('.post-textbox', '/claude-start /tmp/test-project');
  await page.keyboard.press('Enter');
  
  // Verify bot response
  await expect(page.locator('.post__body').last()).toContainText('Started Claude Code session');
  
  // Send message
  await page.fill('.post-textbox', '/claude add a hello world function');
  await page.keyboard.press('Enter');
  
  // Verify response
  await expect(page.locator('.post__body').last()).toContainText('I\'ll create');
});

6. User Documentation

README.md:

  • Quick start guide
  • Installation instructions
  • Basic usage examples
  • Troubleshooting

docs/USER_GUIDE.md:

# Claude Code Mattermost Plugin - User Guide

## Getting Started

### Starting a Session
1. Type `/claude-start` in any channel
2. Enter your project path
3. Wait for confirmation

### Sending Messages
Use `/claude <your message>` to interact:

/claude add authentication to the login page


### File Operations
Browse files with `/claude-files`:
1. Select a file from the list
2. Choose View, Edit, or Delete
3. Make changes in the dialog

### Interactive Actions
When Claude proposes changes:
- Click **✅ Approve** to accept
- Click **❌ Reject** to decline
- Click **✏️ Modify** to provide feedback

docs/TROUBLESHOOTING.md:

  • Common errors and solutions
  • Debug mode instructions
  • Bridge server issues
  • Permission problems

7. Developer Documentation

docs/DEVELOPMENT.md:

  • Development environment setup
  • Architecture overview
  • Code structure
  • Testing guidelines
  • Contributing workflow

docs/ARCHITECTURE.md:

  • System design
  • Component interactions
  • Data flow diagrams
  • Security considerations

docs/API.md:

  • Bridge server API reference
  • Plugin API endpoints
  • WebSocket protocol
  • Error codes

8. Test Coverage

Coverage Targets:

  • Go backend: ≥80%
  • TypeScript bridge: ≥70%
  • React frontend: ≥60%

Coverage Reports:

# Go coverage
make test-coverage
# Output: coverage.html

# TypeScript coverage
cd bridge-server && npm run test:coverage
# Output: coverage/index.html

# React coverage
cd webapp && npm run test:coverage
# Output: coverage/lcov-report/index.html

9. CI Integration

Add test stages to .github/workflows/ci.yml:

name: CI

on: [push, pull_request]

jobs:
  test-backend:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-go@v4
        with:
          go-version: '1.21'
      - name: Run tests
        run: |
          cd server
          go test -v -race -coverprofile=coverage.txt ./...
      - name: Upload coverage
        uses: codecov/codecov-action@v3
  
  test-bridge:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '22'
      - name: Run tests
        run: |
          cd bridge-server
          npm ci
          npm test
  
  test-frontend:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '22'
      - name: Run tests
        run: |
          cd webapp
          npm ci
          npm test

Acceptance Criteria

  • ≥80% backend test coverage
  • ≥70% bridge server test coverage
  • All critical paths have integration tests
  • User guide complete with examples
  • Developer documentation complete
  • API reference documented
  • Troubleshooting guide created
  • CI runs all tests automatically
  • Code coverage reports generated
  • All tests pass in CI

Related Issues

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions