Files
wehub-resource-sync 7a0da7932b
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

376 lines
14 KiB
YAML

name: Responsive UI Tests
on:
workflow_call:
workflow_dispatch:
# No concurrency group — intentionally omitted.
# This workflow runs only via workflow_call (from release.yml's
# responsive-test-gate) and workflow_dispatch. The pull_request trigger
# was deliberately removed in #2248 to reduce PR CI load on what is a
# heavy ~20-minute matrix build (mobile + desktop). A shared concurrency
# key here previously caused workflow_call invocations to cancel each
# other mid-flight; see #3554 (reverted in #3599) for that history.
permissions:
contents: read
jobs:
ui-tests:
runs-on: ubuntu-latest
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
viewport: [mobile, desktop] # Test mobile and desktop on each PR
services:
postgres:
image: postgres:14@sha256:ca25035f7e6f74552655a1c5e4a9eb21f85e9d316f1f70371f790ef70095dd58 # v14
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: ldr_test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
with:
egress-policy: audit
- name: Checkout code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Set up PDM
uses: pdm-project/setup-pdm@973541a5febeafcfdadf8a51211435be6ecfd90f # v4.5
with:
python-version: '3.12'
- name: Set up Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: '24'
cache: 'npm'
cache-dependency-path: tests/ui_tests/package-lock.json
- name: Free up disk space
run: |
# Remove unnecessary large packages to prevent disk space issues during cache save
sudo rm -rf /usr/share/dotnet
sudo rm -rf /usr/local/lib/android
sudo rm -rf /opt/ghc
sudo rm -rf /opt/hostedtoolcache/CodeQL
df -h
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
wget \
gnupg \
ca-certificates \
fonts-liberation \
libasound2t64 \
libatk-bridge2.0-0 \
libatk1.0-0 \
libcups2 \
libdbus-1-3 \
libdrm2 \
libgbm1 \
libgtk-3-0 \
libnspr4 \
libnss3 \
libx11-xcb1 \
libxcomposite1 \
libxdamage1 \
libxrandr2 \
xdg-utils \
imagemagick
- name: Install Python dependencies
run: pdm install
- name: Install root frontend dependencies
run: npm ci
- name: Build Vite frontend bundle
# Generates src/local_deep_research/web/static/dist/, which the
# Flask app loads via vite_helper. Without this the responsive UI
# tests run against an unstyled page (no styles.css), which means
# any CSS source changes between PRs are invisible to the test
# baseline. See follow-up to PR #3985 for context.
run: npm run build
- name: Install Node test dependencies
working-directory: tests/ui_tests
run: |
npm ci
# Keep this version in sync with tests/ui_tests/package-lock.json's
# puppeteer entry. A mismatch makes npx fetch a second puppeteer
# that targets a different Chrome build, corrupting the browser
# cache ("folder exists but executable is missing"). Matching the
# locked version lets npx reuse the puppeteer just installed above.
npx puppeteer@25.1.0 browsers install chrome
- name: Set up test directories
run: |
mkdir -p ${{ github.workspace }}/data/encrypted_databases
mkdir -p tests/ui_tests/screenshots
echo "Created data and screenshots directories for tests"
- name: Start test server
env:
CI: true
FLASK_ENV: testing
TEST_ENV: true
SECRET_KEY: test-secret-key-for-ci # Security: CI test credential, not production secret
LDR_DISABLE_RATE_LIMITING: true
LDR_DATA_DIR: ${{ github.workspace }}/data
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/ldr_test # Security: CI test database credentials, not production secrets
run: |
cd src
# Start server and get its PID
pdm run python -m local_deep_research.web.app > server.log 2>&1 &
SERVER_PID=$!
echo "Server PID: $SERVER_PID"
# Persist the PID for the "Stop application server" step. That step
# runs at the workspace root (no working-directory) while we are in
# src/ here, so write an absolute path — otherwise the pidfile never
# lines up and cleanup is a silent no-op.
echo "$SERVER_PID" > "$GITHUB_WORKSPACE/server.pid"
# Wait for server to start
SERVER_READY=false
for i in {1..60}; do
# Probe the health endpoint, not bare `/`: `/` 302-redirects to
# /auth/login and `curl -f` treats a 302 as success the instant
# the socket binds — before DB/app init finishes — so it can pass
# while the app is still not ready. /api/v1/health is a true
# readiness signal and matches the docker-tests.yml gate.
if curl -fsS --connect-timeout 2 --max-time 5 http://127.0.0.1:5000/api/v1/health 2>/dev/null; then
echo "Server is ready after $i seconds"
SERVER_READY=true
break
fi
# Check if process is still running
if ! kill -0 "$SERVER_PID" 2>/dev/null; then
echo "Server process died!"
echo "Server log:"
cat server.log
exit 1
fi
echo "Waiting for server... ($i/60)"
sleep 1
done
# Fail fast if the server is alive but never became ready in time.
# Without this guard the loop fell through silently on a slow-but-
# not-crashed start, so "Register CI test user" and the UI tests ran
# against a server that was not yet listening and failed with a
# confusing `net::ERR_CONNECTION_REFUSED` in the *test* step instead
# of a clear startup failure here. Window was also bumped 30s -> 60s
# to match the proven puppeteer-e2e-tests.yml / docker-tests.yml
# startup gates (Postgres-backed boot can exceed 30s on a loaded
# runner).
if [ "$SERVER_READY" != "true" ]; then
echo "❌ Server did not become ready within 60 seconds"
echo "Server log:"
cat server.log
exit 1
fi
- name: Register CI test user
working-directory: tests/ui_tests
run: node register_ci_user.js http://127.0.0.1:5000
- name: Run responsive UI tests - ${{ matrix.viewport }}
id: run-tests
working-directory: tests/ui_tests
env:
VIEWPORT: ${{ matrix.viewport }}
run: |
set +e # Don't exit on test failure
# Run tests and capture output
HEADLESS=true node test_responsive_ui_comprehensive.js "$VIEWPORT" 2>&1 | tee test-output.log
TEST_EXIT_CODE="${PIPESTATUS[0]}"
# Extract summary for PR comment
echo "### 📱 $VIEWPORT Test Results" > test-summary.md
echo "" >> test-summary.md
# Extract pass/fail counts
PASSED=$(grep -oP '\d+(?= passed)' test-output.log | tail -1 || echo "0")
FAILED=$(grep -oP '\d+(?= failed)' test-output.log | tail -1 || echo "0")
WARNINGS=$(grep -oP '\d+(?= warnings)' test-output.log | tail -1 || echo "0")
if [ "$FAILED" -eq "0" ]; then
echo "✅ **All tests passed!**" >> test-summary.md
else
echo "❌ **$FAILED critical issues found**" >> test-summary.md
fi
{
echo ""
echo "- ✅ Passed: $PASSED"
echo "- ❌ Failed: $FAILED"
echo "- ⚠️ Warnings: $WARNINGS"
} >> test-summary.md
{
echo "test_exit_code=$TEST_EXIT_CODE"
echo "test_failed=$FAILED"
} >> "$GITHUB_OUTPUT"
# Only fail if critical failures
exit "$TEST_EXIT_CODE"
- name: Upload viewport test results
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ui-test-results-${{ matrix.viewport }}
path: |
tests/ui_tests/test-output.log
tests/ui_tests/test-summary.md
tests/ui_tests/screenshots/
tests/ui_tests/responsive/
src/server.log
retention-days: 7
if-no-files-found: ignore
# NOTE: Earlier screenshot generation/upload steps were removed to fix actionlint warnings
# caused by "if: false" disablement. Screenshots are now captured into the artifact above
# when they exist. Visual regression workflows can re-enable dedicated screenshot steps later.
- name: Upload to GitHub Pages (if available)
if: always() && github.event_name == 'pull_request'
continue-on-error: true
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
VIEWPORT: ${{ matrix.viewport }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPOSITORY: ${{ github.repository }}
GH_REPO_OWNER: ${{ github.repository_owner }}
GH_REPO_NAME: ${{ github.event.repository.name }}
run: |
# This requires GitHub Pages to be enabled for the repo
# Create a branch for the screenshots
BRANCH_NAME="pr-screenshots-$PR_NUMBER-$VIEWPORT"
# Check if screenshots directory exists
if [ ! -d "tests/ui_tests/responsive" ]; then
echo "No screenshots directory found, skipping upload"
exit 0
fi
cd tests/ui_tests/responsive
git init
git config user.name "GitHub Actions"
git config user.email "actions@github.com"
# Add all screenshots and gallery
git add responsive-ui-tests screenshot-gallery.html
git commit -m "Screenshots for PR #$PR_NUMBER"
# Push to a dedicated branch (requires write permissions)
git push --force "https://x-access-token:$GH_TOKEN@github.com/$GH_REPOSITORY.git" "HEAD:$BRANCH_NAME" 2>/dev/null || true
# The URL would be: https://[owner].github.io/[repo]/pr-screenshots-[number]-[viewport]/screenshot-gallery.html
echo "Screenshots available at: https://$GH_REPO_OWNER.github.io/$GH_REPO_NAME/$BRANCH_NAME/screenshot-gallery.html" || true
- name: Stop application server
if: always()
run: |
if [ -f server.pid ]; then
kill "$(cat server.pid)" || true
rm server.pid
fi
# `pdm run` stays alive as a wrapper, so the pidfile holds the
# wrapper PID and killing it can orphan the actual python server.
# Add the same pkill fallback the webkit workflow uses so the
# python process (and port 5000) is actually released.
pkill -f "python -m local_deep_research.web.app" || true
post-results:
needs: ui-tests
runs-on: ubuntu-latest
# Workflow has no pull_request trigger; gating on event_name == 'pull_request' kept this job
# from ever running. Always run so the combined report is built for workflow_dispatch / release.
if: always()
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
with:
egress-policy: audit
- name: Checkout code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Download all artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: test-artifacts/
- name: Generate combined report
run: |
# Create a combined markdown report with screenshot links
{
echo "# 📊 Responsive UI Test Report"
echo ""
echo "## Test Summary"
echo ""
} > combined-report.md
# Process each viewport's results
for dir in test-artifacts/ui-test-results-*/; do
if [ -d "$dir" ]; then
viewport=$(basename "$dir" | sed 's/ui-test-results-//')
echo "### $viewport" >> combined-report.md
if [ -f "$dir/test-summary.md" ]; then
cat "$dir/test-summary.md" >> combined-report.md
fi
# Count screenshots
screenshot_count=$(find "$dir" -name "*.png" 2>/dev/null | wc -l)
if [ "$screenshot_count" -gt "0" ]; then
{
echo ""
echo "📸 **$screenshot_count screenshots captured**"
} >> combined-report.md
fi
echo "" >> combined-report.md
fi
done
{
echo "## 📥 Download Options"
echo ""
echo "- [Download all test artifacts](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})"
echo "- View artifacts in the 'Artifacts' section below the workflow summary"
} >> combined-report.md
- name: Upload combined report
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: combined-test-report
path: combined-report.md
retention-days: 30