Trezor Keychain Port #83
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Trezor Emulator Tests | |
| permissions: | |
| contents: read | |
| on: | |
| pull_request: | |
| branches: [ main, develop ] | |
| paths: | |
| - 'src/utils/hardware/**' | |
| - 'src/pages/wallet/connect-hardware.tsx' | |
| - 'e2e/hardware/**' | |
| - '.github/workflows/trezor-emulator-tests.yml' | |
| push: | |
| branches: [ main, feature/trezor-hardware-wallet ] | |
| paths: | |
| - 'src/utils/hardware/**' | |
| - 'scripts/init-trezor-emulator.js' | |
| - 'e2e/hardware/**' | |
| - '.github/workflows/trezor-emulator-tests.yml' | |
| # Allow manual trigger | |
| workflow_dispatch: | |
| jobs: | |
| trezor-emulator-tests: | |
| name: Trezor Emulator Integration Tests | |
| runs-on: ubuntu-latest | |
| # Use the same Docker service configuration as Trezor's own tests | |
| # Reference: https://github.com/trezor/connect/blob/develop/.github/workflows/test_with_trezor-user-env.yml | |
| services: | |
| trezor-user-env: | |
| image: ghcr.io/trezor/trezor-user-env:1d12b626fdd4aab4b5c8e148e42a81c269e7e5b5 | |
| ports: | |
| - 9001:9001 | |
| - 21326:21326 | |
| - 21325:21326 | |
| env: | |
| SDL_VIDEODRIVER: dummy | |
| USE_TX_CACHE: 'true' | |
| USE_WS_CACHE: 'true' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Install xvfb for headless display | |
| run: sudo apt-get install -y xvfb | |
| - name: Wait for WebSocket controller | |
| timeout-minutes: 2 | |
| run: | | |
| echo "Waiting for WebSocket controller on port 9001..." | |
| for i in $(seq 1 40); do | |
| if nc -z localhost 9001 2>/dev/null; then | |
| echo "Controller is ready!" | |
| exit 0 | |
| fi | |
| echo "Attempt $i/40: Waiting..." | |
| sleep 3 | |
| done | |
| echo "Controller failed to start" | |
| exit 1 | |
| - name: Initialize Trezor emulator | |
| timeout-minutes: 2 | |
| run: | | |
| echo "Installing ws for WebSocket communication..." | |
| npm install ws | |
| echo "Starting emulator and bridge via WebSocket API..." | |
| node scripts/init-trezor-emulator.js | |
| # Wait for bridge to be ready and verify | |
| echo "" | |
| echo "Waiting for bridge to be ready..." | |
| for i in $(seq 1 30); do | |
| if curl -s -X POST http://localhost:21325 > /dev/null 2>&1; then | |
| echo "Bridge is responding!" | |
| curl -s -X POST http://localhost:21325/enumerate 2>&1 | head -50 | |
| break | |
| fi | |
| echo "Attempt $i/30: Bridge not ready yet..." | |
| sleep 2 | |
| done | |
| - name: Build extension | |
| env: | |
| TREZOR_TEST_MODE: 'true' | |
| run: npm run build | |
| - name: Install Playwright browsers | |
| run: npx playwright install chromium | |
| - name: Verify bridge before tests | |
| run: | | |
| echo "Checking bridge availability before tests..." | |
| echo "" | |
| echo "1. Checking if bridge is responding..." | |
| if curl -s -X POST http://localhost:21325 > /dev/null 2>&1; then | |
| echo " ✓ Bridge is responding" | |
| else | |
| echo " ✗ Bridge NOT responding" | |
| echo " Checking what's listening on port 21325..." | |
| netstat -tlnp 2>/dev/null || ss -tlnp 2>/dev/null || echo " Cannot check ports" | |
| echo "" | |
| echo " Checking container status..." | |
| docker ps 2>/dev/null || echo " Cannot check containers" | |
| fi | |
| echo "" | |
| echo "2. Enumerating devices..." | |
| DEVICES=$(curl -s -X POST http://localhost:21325/enumerate 2>&1) || DEVICES="Failed to enumerate" | |
| echo " $DEVICES" | |
| echo "" | |
| echo "3. Checking emulator HTTP API..." | |
| if curl -s http://localhost:9001/status > /dev/null 2>&1; then | |
| echo " ✓ Emulator HTTP API is responding" | |
| else | |
| echo " ✗ Emulator HTTP API NOT responding" | |
| fi | |
| echo "" | |
| - name: Run Node.js Integration Tests (TrezorConnect direct) | |
| id: node-tests | |
| timeout-minutes: 10 | |
| env: | |
| TREZOR_EMULATOR_URL: ws://localhost:9001 | |
| TREZOR_BRIDGE_URL: http://localhost:21325 | |
| TREZOR_EMULATOR_AVAILABLE: '1' | |
| NODE_OPTIONS: --max-old-space-size=4096 | |
| continue-on-error: true | |
| run: npx vitest run e2e/hardware/trezor-node-integration.test.ts --reporter=verbose | |
| - name: Run Trezor Direct API tests (emulator verification) | |
| id: direct-tests | |
| timeout-minutes: 5 | |
| env: | |
| TREZOR_EMULATOR_URL: ws://localhost:21326 | |
| TREZOR_BRIDGE_URL: http://localhost:21325 | |
| TREZOR_EMULATOR_AVAILABLE: '1' | |
| NODE_OPTIONS: --max-old-space-size=4096 | |
| CI: 'true' | |
| # Continue on error to run all test suites, but we'll check results at the end | |
| continue-on-error: true | |
| run: xvfb-run npx playwright test e2e/hardware/trezor-direct.spec.ts --reporter=list | |
| - name: Run Trezor UI E2E tests | |
| id: ui-tests | |
| timeout-minutes: 15 | |
| env: | |
| TREZOR_EMULATOR_URL: ws://localhost:21326 | |
| TREZOR_BRIDGE_URL: http://localhost:21325 | |
| TREZOR_EMULATOR_AVAILABLE: '1' | |
| NODE_OPTIONS: --max-old-space-size=4096 | |
| CI: 'true' | |
| continue-on-error: true | |
| run: xvfb-run npx playwright test e2e/hardware/trezor.spec.ts --reporter=list | |
| - name: Release device sessions before Operations tests | |
| run: | | |
| echo "Releasing any stale device sessions..." | |
| # Get devices and release any active sessions | |
| DEVICES=$(curl -s -X POST http://localhost:21325/enumerate 2>&1) || DEVICES="[]" | |
| echo "Current devices: $DEVICES" | |
| # Parse sessions and release them (using jq if available, or just wait) | |
| if command -v jq &> /dev/null; then | |
| echo "$DEVICES" | jq -r '.[] | select(.session != null) | .session' | while read session; do | |
| if [ -n "$session" ]; then | |
| echo "Releasing session: $session" | |
| curl -s -X POST "http://localhost:21325/release/$session" || true | |
| fi | |
| done | |
| fi | |
| # Wait a moment for sessions to clear | |
| sleep 2 | |
| echo "Sessions released" | |
| - name: Run Trezor Operations E2E tests | |
| id: ops-tests | |
| timeout-minutes: 15 | |
| env: | |
| TREZOR_EMULATOR_URL: ws://localhost:21326 | |
| TREZOR_BRIDGE_URL: http://localhost:21325 | |
| TREZOR_EMULATOR_AVAILABLE: '1' | |
| NODE_OPTIONS: --max-old-space-size=4096 | |
| CI: 'true' | |
| continue-on-error: true | |
| run: xvfb-run npx playwright test e2e/hardware/trezor-operations.spec.ts --reporter=list | |
| - name: Check test results | |
| if: always() | |
| run: | | |
| echo "=== Trezor E2E Test Results Summary ===" | |
| echo "" | |
| echo "Node.js Integration Tests: ${{ steps.node-tests.outcome }}" | |
| echo "Direct API Tests: ${{ steps.direct-tests.outcome }}" | |
| echo "UI Tests: ${{ steps.ui-tests.outcome }}" | |
| echo "Operations Tests: ${{ steps.ops-tests.outcome }}" | |
| echo "" | |
| # Node.js, Direct API and UI tests are required to pass | |
| # Operations tests pass if they complete (even with known limitation early return) | |
| REQUIRED_FAILURES=0 | |
| if [ "${{ steps.node-tests.outcome }}" == "failure" ]; then | |
| echo "❌ Node.js Integration tests failed (REQUIRED)" | |
| echo " These test actual device operations via @trezor/connect" | |
| REQUIRED_FAILURES=$((REQUIRED_FAILURES + 1)) | |
| else | |
| echo "✅ Node.js Integration tests: PASSED" | |
| echo " → Device communication works via BridgeTransport" | |
| fi | |
| if [ "${{ steps.direct-tests.outcome }}" == "failure" ]; then | |
| echo "❌ Direct API tests failed (REQUIRED)" | |
| REQUIRED_FAILURES=$((REQUIRED_FAILURES + 1)) | |
| else | |
| echo "✅ Direct API tests: PASSED" | |
| fi | |
| if [ "${{ steps.ui-tests.outcome }}" == "failure" ]; then | |
| echo "❌ UI tests failed (REQUIRED)" | |
| REQUIRED_FAILURES=$((REQUIRED_FAILURES + 1)) | |
| else | |
| echo "✅ UI E2E tests: PASSED" | |
| fi | |
| echo "" | |
| # Note about Operations tests | |
| if [ "${{ steps.ops-tests.outcome }}" == "failure" ]; then | |
| echo "⚠️ Browser Operations tests: Limited (expected)" | |
| echo " @trezor/connect-webextension uses popup architecture that" | |
| echo " cannot directly communicate with BridgeTransport." | |
| echo " Device operations are verified by Node.js tests above." | |
| else | |
| echo "✅ Browser Operations tests: PASSED" | |
| fi | |
| echo "" | |
| if [ $REQUIRED_FAILURES -gt 0 ]; then | |
| echo "❌ $REQUIRED_FAILURES required test suite(s) failed" | |
| echo "" | |
| echo "Review the test artifacts for details." | |
| exit 1 | |
| else | |
| echo "✅ All required test suites passed!" | |
| echo "" | |
| echo "Test Coverage Summary:" | |
| echo " • Device communication: Verified via Node.js @trezor/connect" | |
| echo " • Address derivation: All formats tested" | |
| echo " • Message signing: Verified with emulator" | |
| echo " • UI flow: Verified via Playwright E2E" | |
| fi | |
| - name: Upload Playwright test results | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: trezor-playwright-test-results | |
| path: | | |
| test-results/ | |
| playwright-report/ | |
| retention-days: 7 | |
| if-no-files-found: ignore | |
| hardware-unit-tests: | |
| name: Hardware Wallet Unit Tests | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Build extension | |
| run: npm run build | |
| - name: Run hardware wallet unit tests | |
| env: | |
| NODE_OPTIONS: --max-old-space-size=4096 | |
| run: npx vitest run src/utils/hardware --reporter=verbose | |
| - name: Upload test results | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: hardware-unit-test-results | |
| path: test-results/ | |
| retention-days: 7 | |
| if-no-files-found: ignore |