Skip to content

chore(release): deploy version v0.7.119 #9065

chore(release): deploy version v0.7.119

chore(release): deploy version v0.7.119 #9065

name: Test and Report
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
# All jobs declare their required permissions explicitly.
permissions: {}
jobs:
prepare:
runs-on: ubuntu-26.04
# Only needs read permissions
permissions:
contents: read # Required to check out code
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
with:
egress-policy: audit
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: '.nvmrc'
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Run TypeScript check (source)
run: npm run check
- name: Run TypeScript check (tests)
run: npm run check:test
- name: Run ESLint
run: npm run lint
build-validation:
needs: prepare
runs-on: ubuntu-26.04
# Checkout is the only repository-token operation in this job.
permissions:
contents: read # Required to check out code
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
with:
egress-policy: audit
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: '.nvmrc'
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Cache Vite build cache
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: node_modules/.vite
key: v2-${{ runner.os }}-vite-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
v2-${{ runner.os }}-vite-
- name: Build application
run: npm run build
- name: Upload build artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: build-output
path: dist
if-no-files-found: error
unit-tests:
needs: [prepare, build-validation]
runs-on: ubuntu-26.04
# Checkout is the only repository-token operation in this job.
permissions:
contents: read # Required to check out code
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
with:
egress-policy: audit
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: '.nvmrc'
cache: "npm"
- name: Install dependencies
run: npm install
- name: Run unit tests with coverage
run: npm run coverage
env:
JEST_JUNIT_OUTPUT_DIR: "build/coverage"
JEST_JUNIT_OUTPUT_NAME: "junit.xml"
e2e-tests:
needs: [prepare, build-validation]
runs-on: ubuntu-26.04
# Use Cypress's official browsers image: ships Node + Chrome + Firefox + Edge + Xvfb
# + all GTK/NSS/font system libs preinstalled, removing the need for a custom
# apt-get + Google Chrome bootstrap step. Node is then normalised to the version
# in .nvmrc via actions/setup-node below.
container:
# Use cypress/browsers:latest β€” this keeps Chrome/Firefox/Edge/Xvfb on a
# rolling release, and `actions/setup-node` below normalises Node to the
# major pinned in .nvmrc (currently 26). We deliberately accept the
# rolling browser version over digest-pinning because .nvmrc is a Node
# major (26), not a patch, so attempting to also pin the container's Node
# patch would just be silently overridden by setup-node and create a
# misleading impression of full reproducibility.
image: cypress/browsers:latest
# Run as root so actions/setup-node cache writes and Cypress binary cache
# writes work without permission issues. The cypress/browsers image's
# default USER is non-root.
options: --user root
# Checkout is the only repository-token operation in this job.
permissions:
contents: read # Required to check out code
env:
CYPRESS_VIDEO: true
# Suppress X11 keyboard configuration warnings
XKB_DEFAULT_RULES: evdev
XKB_DEFAULT_MODEL: pc105
XKB_DEFAULT_LAYOUT: us
steps:
# NOTE: step-security/harden-runner does not support container jobs, so it
# is intentionally omitted here. Egress hardening for E2E browser traffic
# would block legitimate test traffic anyway.
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: '.nvmrc'
cache: "npm"
- name: Print browser versions
run: |
echo "Node: $(node --version)"
google-chrome --version || true
# cypress/browsers ships Xvfb (used by Cypress's bundled @cypress/xvfb).
command -v Xvfb >/dev/null 2>&1 && echo "Xvfb available" || echo "Xvfb missing"
- name: Cache Cypress binary
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.cache/Cypress
key: v2-cypress-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
restore-keys: |
v2-cypress-${{ runner.os }}-
- name: Install dependencies
run: npm ci
- name: Verify Cypress
run: npx cypress verify
- name: Start app and run Cypress tests with Three.js optimization
run: |
echo "πŸš€ Starting Three.js E2E test execution at $(date +%T)"
echo "πŸ“Š Configuration:"
echo " - Chrome: $(google-chrome --version)"
echo " - Node: $(node --version) (memory: 4GB heap)"
echo " - Display: $DISPLAY"
echo " - Target: 10-12 minute execution"
echo ""
START_TIME=$(date +%s) || START_TIME=0
# cypress/browsers image ships Xvfb but NOT xauth, so the xvfb-run
# wrapper fails with "xauth command not found". Cypress's bundled
# @cypress/xvfb spawns Xvfb directly (no xauth needed) when DISPLAY
# is unset, so we just call npm run test:e2e and let Cypress manage it.
NODE_OPTIONS="--max-old-space-size=4096" npm run test:e2e || TEST_EXIT_CODE=$?
END_TIME=$(date +%s) || END_TIME=$START_TIME
if [ "$START_TIME" -ne 0 ]; then
DURATION=$((END_TIME - START_TIME))
echo "βœ… E2E tests completed in ${DURATION} seconds"
echo "e2e_duration=${DURATION}" >> $GITHUB_OUTPUT
else
echo "⚠️ Could not measure test duration"
fi
# Exit with test exit code (0 if tests passed)
exit ${TEST_EXIT_CODE:-0}
env:
CYPRESS_VIDEO: true
TERM: dumb
id: e2e_tests
- name: Upload Cypress results
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: cypress-results
path: |
cypress/videos
cypress/screenshots
cypress/results
- name: Report E2E execution time
if: always()
run: |
if [ -n "${{ steps.e2e_tests.outputs.e2e_duration }}" ]; then
echo "πŸ“Š E2E Test Execution Metrics"
echo "================================"
echo "Total Duration: ${{ steps.e2e_tests.outputs.e2e_duration }} seconds"
echo "Previous baseline: 1500-1800 seconds (25-30 minutes)"
echo "Current target: 900-1200 seconds (15-20 minutes)"
echo "Final goal: 600-720 seconds (10-12 minutes)"
DURATION=${{ steps.e2e_tests.outputs.e2e_duration }}
if [ $DURATION -le 720 ]; then
echo "🎯 EXCELLENT: Test execution at final goal (≀12 minutes)"
elif [ $DURATION -le 1200 ]; then
echo "βœ… GOOD: Test execution within current target (≀20 minutes)"
elif [ $DURATION -le 1800 ]; then
echo "⚠️ NEEDS IMPROVEMENT: Test execution above target but below baseline (20-30 minutes)"
else
echo "❌ REGRESSION: Test execution above baseline (>30 minutes)"
fi
# Calculate improvement from baseline (assume 27 min = 1620 sec average)
BASELINE=1620
IMPROVEMENT=$((BASELINE - DURATION))
PERCENT=$((IMPROVEMENT * 100 / BASELINE))
if [ $IMPROVEMENT -gt 0 ]; then
echo "πŸ“ˆ Improvement: ${IMPROVEMENT} seconds (${PERCENT}% faster than baseline)"
else
REGRESSION=$((DURATION - BASELINE))
PERCENT=$((REGRESSION * 100 / BASELINE))
echo "πŸ“‰ Regression: ${REGRESSION} seconds (${PERCENT}% slower than baseline)"
fi
fi
report:
needs: [unit-tests, e2e-tests]
runs-on: ubuntu-26.04
if: always()
# Checkout is the only repository-token operation in this job.
permissions:
contents: read # Required to check out code
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
with:
egress-policy: audit
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: '.nvmrc'
cache: "npm"
- name: Cache APT packages
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: /var/cache/apt/archives
key: v2-${{ runner.os }}-apt-graphviz-${{ hashFiles('.github/workflows/test-and-report.yml') }}
restore-keys: |
v2-${{ runner.os }}-apt-graphviz-
- name: Install graphviz for reports
timeout-minutes: 5
run: sudo DEBIAN_FRONTEND=noninteractive apt-get update -qq && sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends graphviz
- name: Install dependencies
run: npm install
- name: Download all artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: artifacts
- name: Generate test reliability report
continue-on-error: true
run: |
# Copy Cypress results for analysis
if [ -d "artifacts/cypress-results" ]; then
mkdir -p build/cypress/mochawesome
find artifacts/cypress-results -name "*.json" -exec cp {} build/cypress/mochawesome/ \;
fi
# Generate reliability report
npm run test:reliability || echo "No test results to analyze"
- name: Upload combined reports
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: test-reports
path: |
coverage
artifacts/cypress-results
build/reports/test-reliability-report.html