-
Notifications
You must be signed in to change notification settings - Fork 31
chore: Run browser contract tests in CI. #1001
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
base: main
Are you sure you want to change the base?
Changes from all commits
a6948c6
9f12319
7d20d35
af08f94
e035f91
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 |
|---|---|---|
|
|
@@ -42,3 +42,89 @@ jobs: | |
| package_name: '@launchdarkly/js-client-sdk' | ||
| pr_number: ${{ github.event.number }} | ||
| size_limit: 25000 | ||
|
|
||
| # Contract Tests | ||
| - name: Install Playwright browsers | ||
| run: npx playwright install --with-deps chromium | ||
|
|
||
| - name: Install contract test dependencies | ||
| run: yarn workspaces focus browser-contract-test-adapter browser-contract-test-service | ||
|
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. Bug: Fix Playwright Workflow Installation OrderThe workflow installs Playwright browsers before installing the contract test dependencies that include the |
||
|
|
||
| - name: Build contract test adapter | ||
| run: yarn workspace browser-contract-test-adapter run build | ||
|
|
||
| - name: Build contract test entity (browser app) | ||
| run: yarn workspace browser-contract-test-service run build | ||
|
|
||
| - name: Start contract test adapter in background | ||
| run: | | ||
| yarn workspace browser-contract-test-adapter run start > /tmp/adapter.log 2>&1 & | ||
| echo $! > /tmp/adapter.pid | ||
|
|
||
| - name: Serve browser app with http-server | ||
| run: | | ||
| npx http-server packages/sdk/browser/contract-tests/entity/dist -p 5173 --cors > /tmp/http-server.log 2>&1 & | ||
| echo $! > /tmp/http-server.pid | ||
|
|
||
| - name: Wait for services to be ready | ||
| run: | | ||
| echo "Waiting for adapter on port 8001..." | ||
| for i in {1..30}; do | ||
| if nc -z localhost 8001; then | ||
| echo "Adapter WebSocket ready" | ||
| break | ||
| fi | ||
| if [ $i -eq 30 ]; then | ||
| echo "Timeout waiting for adapter" | ||
| cat /tmp/adapter.log | ||
| exit 1 | ||
| fi | ||
| sleep 1 | ||
| done | ||
|
|
||
| echo "Waiting for HTTP server on port 5173..." | ||
| for i in {1..30}; do | ||
| if curl -s http://localhost:5173 > /dev/null; then | ||
| echo "HTTP server ready" | ||
| break | ||
| fi | ||
| if [ $i -eq 30 ]; then | ||
| echo "Timeout waiting for HTTP server" | ||
| cat /tmp/http-server.log | ||
| exit 1 | ||
| fi | ||
| sleep 1 | ||
| done | ||
|
|
||
| - name: Open browser app in headless Chromium | ||
| run: | | ||
| node packages/sdk/browser/contract-tests/entity/open-browser.mjs http://localhost:5173 > /tmp/playwright.log 2>&1 & | ||
| echo $! > /tmp/playwright.pid | ||
| sleep 5 # Give the browser time to initialize and connect via WebSocket | ||
|
|
||
| - name: Run contract tests | ||
| uses: launchdarkly/gh-actions/actions/contract-tests@21174f3a7f3aa3e3121227ec91842e8a1ebeec6e | ||
| with: | ||
| test_service_port: 8000 | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| extra_params: '--skip-from=${{ github.workspace }}/packages/sdk/browser/contract-tests/suppressions.txt --stop-service-at-end' | ||
|
|
||
| - name: Print logs on failure | ||
| if: failure() | ||
| run: | | ||
| echo "=== Adapter Log ===" | ||
| cat /tmp/adapter.log || echo "No adapter log" | ||
| echo "=== HTTP Server Log ===" | ||
| cat /tmp/http-server.log || echo "No http-server log" | ||
| echo "=== Playwright Log ===" | ||
| cat /tmp/playwright.log || echo "No playwright log" | ||
|
|
||
| - name: Cleanup contract test services | ||
| if: always() | ||
| run: | | ||
| [ -f /tmp/playwright.pid ] && kill $(cat /tmp/playwright.pid) || true | ||
| [ -f /tmp/http-server.pid ] && kill $(cat /tmp/http-server.pid) || true | ||
| [ -f /tmp/adapter.pid ] && kill $(cat /tmp/adapter.pid) || true | ||
| pkill -f "playwright" || true | ||
| pkill -f "http-server" || true | ||
| pkill -f "browser-contract-test-adapter" || true | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| # Browser SDK Contract Tests | ||
|
|
||
| This directory contains the contract test implementation for the LaunchDarkly Browser SDK using the [SDK Test Harness](https://github.com/launchdarkly/sdk-test-harness). | ||
|
|
||
| ## Architecture | ||
|
|
||
| The browser contract tests consist of three components: | ||
|
|
||
| 1. **Adapter** (`adapter/`): A Node.js server that: | ||
| - Exposes a REST API on port 8000 for the test harness | ||
| - Runs a WebSocket server on port 8001 for browser communication | ||
| - Translates REST commands to WebSocket messages | ||
|
|
||
| 2. **Entity** (`entity/`): A browser application (Vite app) that: | ||
| - Connects to the adapter via WebSocket | ||
| - Implements the actual SDK test logic | ||
| - Runs the Browser SDK in a real browser environment | ||
|
|
||
| 3. **Test Harness**: The SDK test harness that: | ||
| - Sends test commands via REST API to the adapter (port 8000) | ||
| - Validates SDK behavior across different scenarios | ||
|
|
||
| ## Running Locally | ||
|
|
||
| ### Prerequisites | ||
|
|
||
| - Node.js 18 or later | ||
| - Yarn | ||
| - A modern browser (for manual testing) | ||
|
|
||
| ### Quick Start | ||
|
|
||
| ```bash | ||
| # From the repository root | ||
| ./packages/sdk/browser/contract-tests/run-test-service.sh | ||
| ``` | ||
|
|
||
| This script will: | ||
| 1. Start the adapter (WebSocket bridge) | ||
| 2. Start the entity (browser app with Vite dev server) | ||
| 3. Open the browser app in your default browser | ||
|
|
||
| The services will be available at: | ||
| - Adapter REST API: http://localhost:8000 | ||
| - Adapter WebSocket: ws://localhost:8001 | ||
| - Browser App: http://localhost:5173 | ||
|
|
||
| You then run the `sdk-test-harness`. More information is available here: https://github.com/launchdarkly/sdk-test-harness | ||
|
|
||
| Example with local clone of the test harness: | ||
| ```bash | ||
| go run . --url http://localhost:8123 -skip-from path-to-your-js-core-clone/packages/sdk/browser/contract-tests/suppressions.txt | ||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| #!/usr/bin/env node | ||
|
|
||
| /** | ||
| * Opens a headless browser and navigates to the contract test entity page. | ||
| * Keeps the browser open until the process is terminated. | ||
| * | ||
| * Usage: node open-browser.mjs [url] | ||
| * Default URL: http://localhost:5173 | ||
| */ | ||
|
|
||
| import { chromium } from 'playwright'; | ||
|
|
||
| const url = process.argv[2] || 'http://localhost:5173'; | ||
|
|
||
| console.log(`Opening headless browser at ${url}...`); | ||
|
|
||
| const browser = await chromium.launch({ | ||
| headless: true, | ||
| args: ['--no-sandbox', '--disable-setuid-sandbox'] | ||
| }); | ||
|
|
||
| const context = await browser.newContext(); | ||
| const page = await context.newPage(); | ||
|
|
||
| // Log console messages from the browser | ||
| page.on('console', (msg) => { | ||
| console.log(`[Browser Console] ${msg.type()}: ${msg.text()}`); | ||
| }); | ||
|
|
||
| // Log page errors | ||
| page.on('pageerror', (error) => { | ||
| console.error(`[Browser Error] ${error.message}`); | ||
| }); | ||
|
|
||
| await page.goto(url); | ||
|
|
||
| console.log('Browser is open and running. Press Ctrl+C to close.'); | ||
|
|
||
| // Keep the process alive | ||
| await new Promise(() => { | ||
| // Intentionally never resolve - keeps browser open until process is killed | ||
| }); |
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.
I think playwright doesn't like this, but it works fine. Probably could re-order things.