Skip to main content
This guide covers testing approaches for the Rowboat Electron application, including unit tests, integration tests, and manual testing workflows.

Testing Overview

Rowboat’s testing strategy focuses on:
  • Type safety - TypeScript catches many errors at compile time
  • Linting - ESLint enforces code quality standards
  • Manual testing - Development mode for rapid iteration
  • Integration testing - Testing the full Electron app

Type Checking

TypeScript provides the first line of defense against bugs.

Running Type Checks

cd apps/x
npm run deps  # Compiles all packages, checking types

TypeScript Configuration

Each package has its own tsconfig.json:
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "declaration": true,
    "declarationMap": true
  }
}
Type definitions are generated during build. If you see “Cannot find module” errors in your IDE, run npm run deps to rebuild type definitions.

Linting

ESLint enforces code quality and catches common errors.

Running the Linter

cd apps/x
npm run lint  # Check all files

ESLint Configuration

The workspace uses ESLint 9 with flat config:
// apps/x/eslint.config.js
import js from '@eslint/js'
import tseslint from 'typescript-eslint'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'

export default [
  js.configs.recommended,
  ...tseslint.configs.recommended,
  {
    plugins: {
      'react-hooks': reactHooks,
      'react-refresh': reactRefresh
    },
    rules: {
      ...reactHooks.configs.recommended.rules,
      'react-refresh/only-export-components': 'warn'
    }
  }
]

Common Linting Issues

Unused Variables

// ❌ Error: 'foo' is defined but never used
const foo = 'bar'

// ✅ Fix: Use or remove
const foo = 'bar'
console.log(foo)

React Hooks Rules

// ❌ Error: React Hook used conditionally
if (condition) {
  useEffect(() => {}, [])
}

// ✅ Fix: Always call hooks at top level
useEffect(() => {
  if (condition) {
    // conditional logic inside
  }
}, [])

Manual Testing

Development mode enables rapid manual testing with hot reload.

Starting Development Mode

1

Build dependencies

cd apps/x
npm run deps
2

Start the app

npm run dev
This starts both the Vite dev server and Electron.
3

Test changes

  • Edit renderer code → hot reload (instant)
  • Edit main/preload → restart dev server (Ctrl+C, then npm run dev)

Testing Workflows

UI Changes (Renderer)

  1. Edit files in apps/renderer/src/
  2. Save - changes appear instantly via HMR
  3. Test in the Electron window
  4. Use React DevTools for debugging

Main Process Changes

  1. Edit files in apps/main/src/
  2. Stop dev server (Ctrl+C)
  3. Restart: npm run dev
  4. Test the changes
  5. Check Electron console for logs
Main process changes don’t hot-reload. Always restart the dev server after editing main process code.

Workspace Package Changes

  1. Edit files in packages/shared/src/ or packages/core/src/
  2. Rebuild dependencies: npm run deps
  3. Restart dev server: npm run dev
  4. Test the changes

Developer Tools

Chrome DevTools (Renderer)

Open DevTools in the Electron window:
  • macOS: Cmd + Option + I
  • Windows/Linux: Ctrl + Shift + I
Or programmatically:
// apps/main/src/main.ts
mainWindow.webContents.openDevTools()

Main Process Debugging

Log to the terminal:
// apps/main/src/main.ts
console.log('Main process log')
console.error('Error:', error)
Logs appear in the terminal where you ran npm run dev.

VS Code Debugging

Create .vscode/launch.json:
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Debug Main Process",
      "type": "node",
      "request": "launch",
      "cwd": "${workspaceFolder}/apps/x",
      "runtimeExecutable": "npm",
      "runtimeArgs": ["run", "dev"],
      "outputCapture": "std"
    }
  ]
}

Integration Testing

Test the full application flow from main process to renderer.

IPC Communication Testing

Test the bridge between main and renderer:
// apps/preload/src/preload.ts
contextBridge.exposeInMainWorld('api', {
  testFunction: () => {
    console.log('Preload test function called')
    return 'success'
  }
})

// apps/renderer/src/test.tsx
function TestComponent() {
  const handleTest = () => {
    const result = window.api.testFunction()
    console.log('Result:', result)  // Should log 'success'
  }
  
  return <button onClick={handleTest}>Test IPC</button>
}

Testing AI Providers

Test AI integrations with different providers:
1

Configure provider

Edit ~/.rowboat/config/models.json:
{
  "provider": {
    "flavor": "openai",
    "apiKey": "sk-..."
  },
  "model": "gpt-4"
}
2

Start the app

cd apps/x
npm run dev
3

Test interactions

  • Send a message
  • Verify response
  • Check terminal logs for API calls
4

Test other providers

Update config for Anthropic, Google, etc. and repeat

Testing File Operations

Test document parsing and file handling:
// Test with sample files
const testFiles = [
  'sample.pdf',
  'sample.docx',
  'sample.csv',
  'sample.xlsx'
]

// Drag and drop into the app
// Verify parsing and display

Production Testing

Test the packaged application before distribution.

Building for Testing

1

Create package

cd apps/x/apps/main
npm run package
2

Locate the app

  • macOS: out/rowboat-darwin-arm64/Rowboat.app
  • Windows: out/rowboat-win32-x64/Rowboat.exe
  • Linux: out/rowboat-linux-x64/rowboat
3

Test the packaged app

Run the app and verify:
  • Application launches
  • UI loads correctly
  • Features work as expected
  • No console errors

Testing Installers

1

Create installer

cd apps/x/apps/main
npm run make
2

Install on clean system

Test the installer on a machine without development dependencies:
  • Fresh VM or test machine
  • No Node.js or development tools
  • Standard user (not admin)
3

Verify installation

  • Installer completes successfully
  • App appears in Applications
  • App launches and works
  • Uninstaller works (if applicable)

Continuous Verification

Run these checks before committing:
cd apps/x

# 1. Build all packages
npm run deps

# 2. Run linter
npm run lint

# 3. Test the app
npm run dev
# Manual testing...

# 4. Verify production build
cd apps/main
npm run package
# Test the packaged app
Consider creating a shell script to automate these checks:
#!/bin/bash
set -e
cd apps/x
npm run deps
npm run lint
echo "✓ All checks passed"

Debugging Common Issues

App Won’t Start

1

Check dependencies

cd apps/x
npm run deps
2

Check for errors

Look for errors in the terminal output
3

Clear cache

rm -rf node_modules
rm -rf apps/*/dist
rm -rf packages/*/dist
pnpm install
npm run deps

Renderer Not Loading

  1. Check Vite dev server is running: http://localhost:5173
  2. Check for errors in Electron DevTools console
  3. Verify preload script is built: apps/preload/dist/preload.js exists

IPC Not Working

  1. Rebuild preload scripts: npm run preload
  2. Check contextBridge exposes the APIs correctly
  3. Verify renderer is calling the correct API methods
  4. Check main process is handling IPC events

Type Errors in IDE

  1. Rebuild packages: npm run deps
  2. Restart TypeScript server in IDE
  3. Check tsconfig.json includes correct paths

Best Practices

  • Type everything - Leverage TypeScript’s type system
  • Lint frequently - Run npm run lint before committing
  • Test across platforms - macOS, Windows, Linux behaviors differ
  • Test production builds - Don’t rely solely on dev mode
  • Use React DevTools - Profile performance and debug state
  • Check console logs - Both main process and renderer
  • Clean builds - When in doubt, clean and rebuild

Build docs developers (and LLMs) love