{"_id":"@akaoio/tester","name":"@akaoio/tester","dist-tags":{"latest":"1.1.0"},"versions":{"1.1.0":{"name":"@akaoio/tester","version":"1.1.0","publishConfig":{"access":"public"},"description":"Comprehensive terminal application testing framework with advanced assertions, deep state inspection, and test orchestration","main":"index.js","scripts":{"test":"go test -v ./...","test:self":"./test_runner.sh","test:comprehensive":"./run_all_framework_tests.sh","benchmark":"go test -bench=. -benchmem ./...","build":"go build -o tester .","clean":"rm -rf test_results_* tmp_*"},"keywords":["testing","terminal","tui","multiplexer","dex","pane","assertions","go","framework"],"author":{"name":"AKAO"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/akaoio/tester.git"},"bugs":{"url":"https://github.com/akaoio/tester/issues"},"homepage":"https://github.com/akaoio/tester#readme","engines":{"go":">=1.19"},"gitHead":"5933052233dbc5d20d5aeeb6565e6147128a092b","_id":"@akaoio/tester@1.1.0","_nodeVersion":"18.19.0","_npmVersion":"9.2.0","dist":{"integrity":"sha512-ud0wF7xL6ryYPUkzrf4apdOanH1WT7YmKohn8LIWbdS/On+Ixx3/smPZB2h5s7N+tbiMR7TnBjnPL1Sy684LoA==","shasum":"bddd737ee65401f4b778714fc1fa4e5de32d12b1","tarball":"https://registry.npmjs.org/@akaoio/tester/-/tester-1.1.0.tgz","fileCount":29,"unpackedSize":289765,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCICMBZR9SIAhKZ0uZ/bVVdbwcYD4qRMp1CX+qhAjSd+fMAiEAt9+e/ZmsbSYvI5vhKWM53YMF0/F1sZ75+1s8F69TL+w="}]},"_npmUser":{"name":"akaoio","email":"dev@akao.io"},"directories":{},"maintainers":[{"name":"akaoio","email":"dev@akao.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/tester_1.1.0_1755964676234_0.9422620474179124"},"_hasShrinkwrap":false}},"time":{"created":"2025-08-23T15:57:56.157Z","1.1.0":"2025-08-23T15:57:56.442Z","modified":"2025-08-23T15:57:56.691Z"},"maintainers":[{"name":"akaoio","email":"dev@akao.io"}],"description":"Comprehensive terminal application testing framework with advanced assertions, deep state inspection, and test orchestration","homepage":"https://github.com/akaoio/tester#readme","keywords":["testing","terminal","tui","multiplexer","dex","pane","assertions","go","framework"],"repository":{"type":"git","url":"git+https://github.com/akaoio/tester.git"},"author":{"name":"AKAO"},"bugs":{"url":"https://github.com/akaoio/tester/issues"},"license":"MIT","readme":"# Tester - Advanced Terminal Application Testing Framework\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/akaoio/tester.svg)](https://pkg.go.dev/github.com/akaoio/tester)\n[![Go Report Card](https://goreportcard.com/badge/github.com/akaoio/tester)](https://goreportcard.com/report/github.com/akaoio/tester)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![GitHub release](https://img.shields.io/github/release/akaoio/tester.svg)](https://github.com/akaoio/tester/releases)\n[![Go Version](https://img.shields.io/badge/Go-%3E%3D%201.21-blue)](https://go.dev/)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/akaoio/tester/pulls)\n\nA powerful Go framework for testing terminal applications (TUI) in real-time, with crash detection, performance monitoring, and visual verification.\n\n## Features\n\n### 🔍 **Comprehensive Testing**\n- **Virtual Terminal Emulation** - Run real terminal apps in PTY\n- **Keyboard Simulation** - Send any key combination\n- **Screen Capture** - ASCII screenshots of terminal state\n- **Layout Verification** - Check positioning, centering, borders\n\n### 🛡️ **Reliability Testing**\n- **Crash Detection** - Detect segfaults, panics, OOM kills\n- **Advanced Hang Detection** - Multi-layer hang prevention system\n- **Memory Leak Detection** - Monitor memory usage patterns\n- **Performance Monitoring** - Track CPU, memory, response times\n\n### 🚨 **Hang Prevention System** (NEW!)\n- **Watchdog Protection** - Prevents tester from hanging when apps hang\n- **Operation Timeouts** - Configurable timeouts for all operations\n- **Emergency Stop** - Force termination of problematic applications\n- **Graceful Recovery** - Automatic cleanup and restart capabilities\n\n### 🎨 **Visual Testing**\n- **Color/ANSI Verification** - Validate color output\n- **Responsive Testing** - Test different terminal sizes\n- **Theme Testing** - Verify theme changes\n- **Unicode Support** - Test international characters\n\n### 📊 **Reporting**\n- **Detailed Reports** - Markdown reports with metrics\n- **ASCII Screenshots** - Visual proof of UI states\n- **Performance Metrics** - Response times, resource usage\n- **Test Logs** - Complete execution traces\n\n## Installation\n\n```bash\ngo get github.com/akaoio/tester\n```\n\n## Quick Start\n\n```go\npackage main\n\nimport (\n    \"log\"\n    \"time\"\n    \"github.com/akaoio/tester\"\n)\n\nfunc main() {\n    // Create virtual terminal with built-in hang protection\n    term := tester.NewTerminal(80, 24)\n    defer term.Close()\n    \n    // Configure timeouts (optional - has sensible defaults)\n    term.SetTimeouts(30*time.Second, 5*time.Second) // global, operation\n    \n    // Start your app (protected against hanging)\n    err := term.Start(\"./myapp\")\n    if err != nil {\n        log.Fatal(err)\n    }\n    \n    // All operations are now hang-protected\n    term.Wait(500 * time.Millisecond)\n    term.SendKeys(\"hello world\")     // ✅ Won't hang\n    term.SendKeys(\"<Enter>\")         // ✅ Won't hang  \n    term.SendKeys(\"<Ctrl+C>\")        // ✅ Won't hang\n    \n    // Screenshot with protection\n    screenshot := term.Screenshot()\n    fmt.Println(screenshot)\n    \n    // Verify content\n    if term.Contains(\"expected text\") {\n        fmt.Println(\"Test passed!\")\n    }\n    \n    // Check health + hang status\n    health := term.Health()\n    if health.Crashed {\n        log.Fatalf(\"App crashed: %s\", health.CrashReason)\n    }\n    \n    if term.IsHanging() {\n        log.Println(\"App is hanging - watchdog will handle it\")\n    }\n}\n```\n\n## Advanced Usage\n\n### Stress Testing\n\n```go\n// Test crash scenarios\ntester := tester.NewStressTester(\"./myapp\")\n\n// Try various crash scenarios\ntester.TestCrash(tester.RapidInput)\ntester.TestCrash(tester.InvalidEscape)\ntester.TestCrash(tester.BufferOverflow)\ntester.TestCrash(tester.RapidResize)\n\n// Check for memory leaks\nleaks := tester.DetectMemoryLeaks()\nif len(leaks) > 0 {\n    log.Printf(\"Memory leak detected: %+v\", leaks)\n}\n\n// Monitor performance\nmetrics := tester.GetPerformanceMetrics()\nfmt.Printf(\"Avg Response Time: %v\\n\", metrics.AvgResponseTime)\nfmt.Printf(\"Peak Memory: %d MB\\n\", metrics.PeakMemory/1024/1024)\n```\n\n### Visual Testing\n\n```go\n// Test different screen sizes\nsizes := []tester.Size{\n    {30, 10},  // Watch\n    {50, 20},  // Mobile\n    {80, 24},  // Standard\n    {120, 40}, // Desktop\n}\n\nfor _, size := range sizes {\n    term := tester.NewTerminal(size.Width, size.Height)\n    term.Start(\"./myapp\")\n    \n    // Verify layout adapts\n    if !term.VerifyLayout(tester.Centered) {\n        log.Printf(\"Layout broken at %dx%d\", size.Width, size.Height)\n    }\n    \n    term.Close()\n}\n```\n\n### Color Verification\n\n```go\nterm := tester.NewTerminal(80, 24)\nterm.Start(\"./myapp\")\n\n// Get color report\ncolors := term.GetColorReport()\n\nif !colors.HasColors {\n    log.Fatal(\"No colors detected\")\n}\n\nif colors.Has256Colors {\n    fmt.Println(\"256 color support verified\")\n}\n\nfmt.Printf(\"ANSI sequences used: %d\\n\", colors.TotalSequences)\n```\n\n### Test Suite Builder\n\n```go\nsuite := tester.NewSuite(\"MyApp Tests\")\n\n// Add test cases\nsuite.AddTest(tester.TestCase{\n    Name: \"Startup Test\",\n    Steps: []tester.Step{\n        {Action: \"wait\", Duration: 500*time.Millisecond},\n        {Action: \"screenshot\"},\n    },\n    Assertions: []tester.Assertion{\n        {Type: \"contains\", Expected: \"Welcome\"},\n        {Type: \"no_crash\"},\n    },\n})\n\nsuite.AddTest(tester.TestCase{\n    Name: \"Keyboard Navigation\",\n    Steps: []tester.Step{\n        {Action: \"keys\", Input: \"<Tab>\"},\n        {Action: \"keys\", Input: \"<Enter>\"},\n        {Action: \"screenshot\"},\n    },\n    Assertions: []tester.Assertion{\n        {Type: \"contains\", Expected: \"Selected\"},\n    },\n})\n\n// Run all tests\nreport := suite.Run(\"./myapp\")\nreport.SaveMarkdown(\"test_report.md\")\nreport.SaveJSON(\"test_report.json\")\n```\n\n### Hang Prevention & Recovery\n\n```go\n// Configure aggressive hang protection for problematic apps\nterm := tester.NewTerminal(80, 24)\ndefer term.Close()\n\n// Set strict timeouts\nterm.SetTimeouts(10*time.Second, 2*time.Second) // global, operation\n\n// Configure watchdog behavior\nterm.ConfigureWatchdog(tester.WatchdogConfig{\n    MaxResponse:      1 * time.Second,   // Max response time\n    CheckInterval:    200 * time.Millisecond, // Check frequency  \n    ForceKillTimeout: 1 * time.Second,   // Time before force kill\n})\n\n// Start potentially problematic app\nerr := term.Start(\"./problematic-app\")\nif err != nil {\n    log.Fatal(err)\n}\n\n// All operations are protected - won't hang the tester\nerr = term.SendKeys(\"some input that might cause hang\")\nif err != nil {\n    log.Printf(\"Operation failed safely: %v\", err)\n}\n\n// Check if hang was detected\nif term.IsHanging() {\n    log.Println(\"App is hanging, but tester continues\")\n    \n    // Get watchdog statistics  \n    stats := term.GetWatchdogStats()\n    log.Printf(\"Watchdog interventions: %d timeouts, %d force kills\", \n        stats.TimeoutCount, stats.ForceKillCount)\n}\n\n// Emergency stop if needed\nif term.IsHanging() {\n    term.ForceStop(\"Manual intervention\")\n}\n\n// Use timeout wrapper for custom operations\nerr = term.WithTimeout(\"custom_operation\", 3*time.Second, func() error {\n    // Your custom operation that might hang\n    return doSomethingRisky()\n})\n```\n\n## Testing Hanging Applications\n\nThe tester framework now includes robust protection against hanging applications:\n\n### Problem Solved\n- **Before**: Testing hanging apps would freeze the entire test suite\n- **After**: Watchdog system detects and terminates hanging apps automatically\n- **Result**: Test suites never hang, always complete with results\n\n### Example: Testing Dex Project\n```go\n// Test the hanging dex project safely\nfunc TestDexWithHangProtection(t *testing.T) {\n    term := tester.NewTerminal(120, 40)\n    defer term.Close()\n    \n    // Configure for known problematic app\n    term.SetTimeouts(10*time.Second, 3*time.Second)\n    \n    // Start dex (known to hang)\n    err := term.Start(\"./dex\")\n    if err != nil {\n        t.Fatalf(\"Failed to start: %v\", err)\n    }\n    \n    // These operations won't hang the test\n    term.SendKeys(\"test input\")\n    screenshot := term.Screenshot()\n    \n    // Test completes even if dex hangs\n    stats := term.GetWatchdogStats()\n    t.Logf(\"Watchdog protected against %d hangs\", stats.HangCount)\n}\n```\n\n## Real-World Example - Testing a TUI App\n\n```go\nfunc TestTUIApp(t *testing.T) {\n    term := tester.NewTerminal(80, 24)\n    defer term.Close()\n    \n    // Start app\n    err := term.Start(\"./tui-app\")\n    require.NoError(t, err)\n    \n    // Test menu navigation\n    term.SendKeys(\"<Down>\")\n    term.SendKeys(\"<Down>\")\n    term.SendKeys(\"<Enter>\")\n    \n    // Verify we're in settings\n    assert.True(t, term.Contains(\"Settings\"))\n    \n    // Test form input\n    term.SendKeys(\"John Doe\")\n    term.SendKeys(\"<Tab>\")\n    term.SendKeys(\"john@example.com\")\n    term.SendKeys(\"<Enter>\")\n    \n    // Verify form submission\n    assert.True(t, term.Contains(\"Saved successfully\"))\n    \n    // Check no crashes\n    health := term.Health()\n    assert.False(t, health.Crashed)\n    assert.False(t, health.IsHanging)\n}\n```\n\n## API Reference\n\n### Terminal\n\n```go\ntype Terminal struct {\n    // Core methods\n    Start(cmd string, args ...string) error\n    Close() error\n    Wait(duration time.Duration)\n    \n    // Input methods\n    SendKeys(keys string) error\n    SendRaw(bytes []byte) error\n    \n    // Screen methods\n    Screenshot() string\n    GetScreen() string\n    Contains(text string) bool\n    \n    // Verification\n    VerifyLayout(layout LayoutType) bool\n    VerifyColors() ColorReport\n    \n    // Health monitoring\n    Health() HealthReport\n    IsRunning() bool\n    \n    // NEW: Hang prevention and control\n    SetTimeouts(global, operation time.Duration)\n    ConfigureWatchdog(config WatchdogConfig)\n    GetWatchdogStats() WatchdogStats\n    IsHanging() bool\n    ForceStop(reason string)\n    WithTimeout(operation string, timeout time.Duration, fn func() error) error\n}\n```\n\n### Key Notation\n\n```\n<Enter>     - Enter key\n<Tab>       - Tab key\n<Esc>       - Escape\n<Space>     - Space bar\n<Backspace> - Backspace\n\n<Ctrl+A>    - Control combinations\n<Alt+X>     - Alt combinations\n<Shift+Tab> - Shift combinations\n\n<Up>        - Arrow keys\n<Down>\n<Left>\n<Right>\n\n<F1>-<F12>  - Function keys\n<PgUp>      - Page up\n<PgDown>    - Page down\n<Home>      - Home\n<End>       - End\n```\n\n## Testing Patterns\n\n### 1. Smoke Test\n```go\nterm.Start(app)\nterm.Wait(1*time.Second)\nassert.False(t, term.Health().Crashed)\n```\n\n### 2. Navigation Test\n```go\nterm.SendKeys(\"<Tab><Tab><Enter>\")\nassert.True(t, term.Contains(\"Expected Screen\"))\n```\n\n### 3. Data Entry Test\n```go\nterm.SendKeys(\"test@example.com\")\nterm.SendKeys(\"<Tab>\")\nterm.SendKeys(\"password123\")\nterm.SendKeys(\"<Enter>\")\n```\n\n### 4. Responsive Test\n```go\nfor width := 20; width <= 200; width += 20 {\n    term.Resize(width, 24)\n    assert.True(t, term.VerifyLayout(tester.Responsive))\n}\n```\n\n### 5. Hang Prevention Test\n```go\n// Test apps that might hang\nterm.SetTimeouts(5*time.Second, 2*time.Second)\nterm.Start(problematicApp)\n\n// Won't hang the test\nerr := term.SendKeys(\"input\")\nif err != nil {\n    t.Logf(\"Operation failed safely: %v\", err)\n}\n\nassert.False(t, term.IsHanging())\n```\n\n### 6. Emergency Recovery Test  \n```go\nterm.Start(hangingApp)\ntime.Sleep(1*time.Second)\n\nif term.IsHanging() {\n    term.ForceStop(\"Test cleanup\")\n    time.Sleep(500*time.Millisecond)\n    assert.False(t, term.IsRunning())\n}\n```\n\n## CI/CD Integration\n\n### GitHub Actions\n\n```yaml\nname: TUI Tests\non: [push, pull_request]\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v3\n    \n    - uses: actions/setup-go@v4\n      with:\n        go-version: '1.21'\n    \n    - name: Install dependencies\n      run: go mod download\n    \n    - name: Run TUI tests\n      run: go test -v ./...\n    \n    - name: Upload screenshots\n      if: failure()\n      uses: actions/upload-artifact@v3\n      with:\n        name: screenshots\n        path: test_reports/\n```\n\n## Troubleshooting\n\n### \"PTY not available\"\n- Run in a real terminal or use `script` command\n- In Docker, use `-t` flag: `docker run -t`\n\n### \"Colors not detected\"\n- Ensure TERM environment variable is set\n- Try `TERM=xterm-256color`\n\n### \"Hanging tests\"\n- Increase timeouts for slow systems\n- Check if app requires specific environment\n\n## Contributing\n\nContributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details.\n\n## License\n\nMIT License - see [LICENSE](LICENSE) file for details.\n\n## Credits\n\nCreated by [AKAO.IO](https://akao.io) for testing terminal applications with confidence.","readmeFilename":"README.md","_rev":"1-9fc4b453bdc37eaa2dd98140314a1c00"}