-
Notifications
You must be signed in to change notification settings - Fork 0
Add automated visual testing with Claude vision validation #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6e8416c
8bc8972
18482a4
8e13ae3
b5e99f7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,270 @@ | ||||||
| name: Visual Tests | ||||||
|
|
||||||
| on: | ||||||
| # Manual trigger with options | ||||||
| workflow_dispatch: | ||||||
| inputs: | ||||||
| run_claude_validation: | ||||||
| description: 'Run Claude vision validation' | ||||||
| required: false | ||||||
| default: true | ||||||
| type: boolean | ||||||
| python_version: | ||||||
| description: 'Python version' | ||||||
| required: false | ||||||
| default: '3.11' | ||||||
| type: string | ||||||
|
|
||||||
| # Also run on PRs that touch overlay code | ||||||
| pull_request: | ||||||
| paths: | ||||||
| - 'sage/overlay.py' | ||||||
| - 'scripts/visual_test_overlay.py' | ||||||
| - 'scripts/validate_screenshots.py' | ||||||
| - 'tests/**/test_overlay*.py' | ||||||
|
|
||||||
| jobs: | ||||||
| visual-test: | ||||||
| name: Capture & Validate Screenshots | ||||||
| runs-on: ubuntu-latest | ||||||
|
|
||||||
| steps: | ||||||
| - name: Checkout code | ||||||
| uses: actions/checkout@v4 | ||||||
|
|
||||||
| - name: Set up Python ${{ inputs.python_version || '3.11' }} | ||||||
| uses: actions/setup-python@v5 | ||||||
| with: | ||||||
| python-version: ${{ inputs.python_version || '3.11' }} | ||||||
| cache: 'pip' | ||||||
|
|
||||||
| - name: Install system dependencies | ||||||
| run: | | ||||||
| sudo apt-get update | ||||||
| sudo apt-get install -y \ | ||||||
| libdbus-1-dev \ | ||||||
| libxcb-cursor0 \ | ||||||
| libxcb-icccm4 \ | ||||||
| libxcb-image0 \ | ||||||
| libxcb-keysyms1 \ | ||||||
| libxcb-randr0 \ | ||||||
| libxcb-render-util0 \ | ||||||
| libxcb-shape0 \ | ||||||
| libxcb-xinerama0 \ | ||||||
| libxcb-xfixes0 \ | ||||||
| libxkbcommon-x11-0 \ | ||||||
| x11-utils \ | ||||||
| xvfb \ | ||||||
| libegl1 \ | ||||||
| libgl1 \ | ||||||
| libglib2.0-0 \ | ||||||
| scrot \ | ||||||
| imagemagick | ||||||
|
|
||||||
| - name: Install Python dependencies | ||||||
| run: | | ||||||
| python -m pip install --upgrade pip | ||||||
| # Install without dbus extra to avoid build issues in CI | ||||||
| pip install pydantic pyyaml PySide6 watchdog | ||||||
| pip install pytest pytest-cov pytest-qt ruff mypy types-PyYAML | ||||||
| pip install anthropic | ||||||
| pip install -e . --no-deps | ||||||
|
|
||||||
| - name: Run visual tests (capture screenshots) | ||||||
| id: capture | ||||||
| run: | | ||||||
| # Create screenshots directory | ||||||
| mkdir -p screenshots | ||||||
|
|
||||||
| # Run visual test script under xvfb with xcb platform | ||||||
| xvfb-run -a --server-args="-screen 0 1920x1080x24" \ | ||||||
| python scripts/visual_test_overlay.py | ||||||
|
|
||||||
| # List captured screenshots | ||||||
| echo "Captured screenshots:" | ||||||
| ls -la screenshots/ | ||||||
|
|
||||||
| # Count screenshots for summary | ||||||
| SCREENSHOT_COUNT=$(ls -1 screenshots/overlay_test_*.png 2>/dev/null | wc -l) | ||||||
| echo "screenshot_count=$SCREENSHOT_COUNT" >> $GITHUB_OUTPUT | ||||||
|
|
||||||
| # Require all 5 screenshots | ||||||
| if [ "$SCREENSHOT_COUNT" -lt 5 ]; then | ||||||
| echo "::error::Expected 5 screenshots, only captured $SCREENSHOT_COUNT" | ||||||
| exit 1 | ||||||
| fi | ||||||
| env: | ||||||
| QT_QPA_PLATFORM: xcb | ||||||
| DISPLAY: ':99' | ||||||
|
|
||||||
| - name: Generate screenshot montage | ||||||
| if: success() | ||||||
| run: | | ||||||
| # Create a montage of all screenshots for easy review | ||||||
| if ls screenshots/overlay_test_*.png 1> /dev/null 2>&1; then | ||||||
| montage screenshots/overlay_test_*.png -tile 2x3 -geometry +5+5 \ | ||||||
| -background '#1a1a1a' -title 'Overlay Visual Tests' \ | ||||||
| screenshots/montage.png || echo "Montage creation skipped" | ||||||
| fi | ||||||
|
|
||||||
| - name: Validate screenshots with Claude | ||||||
| id: validate | ||||||
| if: ${{ (github.event_name == 'workflow_dispatch' && inputs.run_claude_validation == true) || (github.event_name == 'pull_request' && secrets.ANTHROPIC_API_KEY != '') }} | ||||||
| run: | | ||||||
|
Comment on lines
+110
to
+113
|
||||||
| echo "Running Claude vision validation..." | ||||||
|
|
||||||
| # Run validation and capture exit code | ||||||
| set +e | ||||||
| python scripts/validate_screenshots.py screenshots/ \ | ||||||
| --output screenshots/validation_report.json | ||||||
| VALIDATION_EXIT_CODE=$? | ||||||
| set -e | ||||||
|
|
||||||
| # Store result for later steps | ||||||
| if [ $VALIDATION_EXIT_CODE -eq 0 ]; then | ||||||
| echo "validation_passed=true" >> $GITHUB_OUTPUT | ||||||
| echo "✅ All visual validations passed!" | ||||||
| elif [ $VALIDATION_EXIT_CODE -eq 1 ]; then | ||||||
| echo "validation_passed=false" >> $GITHUB_OUTPUT | ||||||
| echo "❌ Some visual validations failed" | ||||||
| else | ||||||
| echo "validation_passed=error" >> $GITHUB_OUTPUT | ||||||
| echo "⚠️ Validation encountered an error" | ||||||
| fi | ||||||
|
|
||||||
| exit 0 # Don't fail here, we'll check in a later step | ||||||
| env: | ||||||
| ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} | ||||||
|
|
||||||
| - name: Skip validation notice | ||||||
| if: ${{ !((github.event_name == 'workflow_dispatch' && inputs.run_claude_validation == true) || (github.event_name == 'pull_request' && secrets.ANTHROPIC_API_KEY != '')) }} | ||||||
| run: | | ||||||
|
Comment on lines
+110
to
+141
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 3. Has_api_key used in if The workflow’s if: conditions reference env.HAS_API_KEY, but HAS_API_KEY is only defined inside step env: blocks; this is fragile and can cause unexpected skipping depending on evaluation timing. Gate directly on secrets.ANTHROPIC_API_KEY != '' or set HAS_API_KEY at job level. Agent Prompt
|
||||||
| echo "⚠️ Claude validation skipped" | ||||||
| echo "" | ||||||
| echo "To enable automated visual validation:" | ||||||
| echo "1. Go to Settings → Secrets and variables → Actions" | ||||||
| echo "2. Click 'New repository secret'" | ||||||
| echo "3. Name: ANTHROPIC_API_KEY" | ||||||
| echo "4. Value: Your Anthropic API key" | ||||||
|
|
||||||
| - name: Upload screenshots | ||||||
| if: always() | ||||||
| uses: actions/upload-artifact@v4 | ||||||
| with: | ||||||
| name: overlay-screenshots-${{ github.sha }} | ||||||
|
||||||
| name: overlay-screenshots-${{ github.sha }} | |
| name: overlay-screenshots-${{ github.run_number }} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -62,3 +62,6 @@ config/*.local.yaml | |
|
|
||
| # DBus temp files | ||
| *.pyc | ||
|
|
||
| # Screenshots (generated by visual tests) | ||
| screenshots/ | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The condition checking
secrets.ANTHROPIC_API_KEY != ''will always evaluate to false when the secret doesn't exist, as GitHub Actions treats non-existent secrets as empty strings. However, the expressionsecrets.ANTHROPIC_API_KEY != ''in a conditional context actually checks if the secret has a non-empty value, which is the intended behavior. This is correct, but for clarity and better practice, consider usingsecrets.ANTHROPIC_API_KEYalone, which evaluates to true if the secret exists and has a value.