diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 5257c1c..e6f549a 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -7,13 +7,9 @@ on: branches: [ main, develop ] jobs: - e2e-tests: - timeout-minutes: 60 + build: + timeout-minutes: 30 runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - project: [chromium, firefox, webkit, "Mobile Chrome", "Mobile Safari"] steps: - uses: actions/checkout@v4 @@ -62,8 +58,6 @@ jobs: uses: actions/setup-node@v4 with: node-version: '20' - cache: 'npm' - cache-dependency-path: 'tests/e2e/package-lock.json' - name: Cache global npm packages uses: actions/cache@v4 @@ -90,21 +84,83 @@ jobs: npm install tailwindcss --no-save cd ../../tests/e2e && npm install - - name: Cache Playwright Browsers + + - name: Build backend (dev mode) + run: cargo build -p kiko-backend + + - name: Build frontend (release mode) + run: cd crates/kiko-frontend && RUSTFLAGS="-C target-feature=-nontrapping-fptoint" trunk build --release + + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: build-artifacts + path: | + target/debug/kiko-backend + crates/kiko-frontend/dist/ + retention-days: 1 + + e2e-tests: + needs: build + timeout-minutes: 30 + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + project: [chromium, firefox, webkit] + + steps: + - uses: actions/checkout@v4 + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: build-artifacts + + - name: Make backend executable + run: chmod +x target/debug/kiko-backend + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + with: + targets: wasm32-unknown-unknown + + - name: Cache Cargo binaries + uses: actions/cache@v4 + with: + path: ~/.cargo/bin/ + key: ${{ runner.os }}-cargo-bin-trunk-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo-bin-trunk- + ${{ runner.os }}-cargo-bin- + + - name: Install trunk + run: | + if ! command -v trunk &> /dev/null; then + cargo install trunk --locked + fi + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + cache-dependency-path: 'tests/e2e/package-lock.json' + + - name: Install E2E test dependencies + run: cd tests/e2e && npm install + + - name: Cache Playwright Browsers with deps uses: actions/cache@v4 with: path: ~/.cache/ms-playwright - key: ${{ runner.os }}-playwright-${{ hashFiles('tests/e2e/package-lock.json') }} + key: ${{ runner.os }}-playwright-${{ matrix.project }}-${{ hashFiles('tests/e2e/package-lock.json') }}-with-deps restore-keys: | + ${{ runner.os }}-playwright-${{ matrix.project }}- ${{ runner.os }}-playwright- - - name: Install Playwright Browsers - run: cd tests/e2e && npx playwright install --with-deps - - - name: Build Rust project - run: | - cargo build --release - cd crates/kiko-frontend && RUSTFLAGS="-C target-feature=-nontrapping-fptoint" trunk build --release + - name: Install Playwright browser with dependencies + run: cd tests/e2e && npx playwright install ${{ matrix.project }} --with-deps - name: Run E2E tests run: cd tests/e2e && npx playwright test --project="${{ matrix.project }}" @@ -115,7 +171,7 @@ jobs: uses: actions/upload-artifact@v4 if: failure() with: - name: playwright-report + name: playwright-report-${{ matrix.project }} path: tests/e2e/playwright-report/ retention-days: 30 @@ -123,6 +179,6 @@ jobs: uses: actions/upload-artifact@v4 if: failure() with: - name: test-screenshots + name: test-screenshots-${{ matrix.project }} path: tests/e2e/test-screenshots/ retention-days: 30 \ No newline at end of file diff --git a/bin/ci b/bin/ci new file mode 100755 index 0000000..51625c6 --- /dev/null +++ b/bin/ci @@ -0,0 +1,57 @@ +#!/bin/bash + +# Simple script to start pre-built servers for CI/E2E testing + +set -e + +# Kill any existing processes on our target ports +echo "๐Ÿงน Cleaning up existing processes..." +lsof -ti:3030 2>/dev/null | xargs kill -9 2>/dev/null || true +lsof -ti:8080 2>/dev/null | xargs kill -9 2>/dev/null || true + +# Start backend from pre-built binary +echo "๐Ÿ“ก Starting backend server..." +chmod +x ./target/debug/kiko-backend +./target/debug/kiko-backend & +BACKEND_PID=$! + +# Wait for backend to be ready +echo "โณ Waiting for backend to be ready..." +for i in {1..20}; do + if curl -s -f http://localhost:3030/health >/dev/null 2>&1; then + echo "โœ… Backend is ready!" + break + fi + if [ $i -eq 20 ]; then + echo "โŒ Backend failed to start" + kill $BACKEND_PID 2>/dev/null || true + exit 1 + fi + sleep 1 +done + +# Start frontend using trunk serve in release mode +echo "๐ŸŽจ Starting frontend server..." +cd crates/kiko-frontend +trunk serve --release --port 8080 & +FRONTEND_PID=$! + +# Wait a bit for frontend to start +sleep 2 + +echo "๐ŸŽ‰ Both servers are running!" +echo "๐Ÿ“ก Backend: http://localhost:3030" +echo "๐ŸŽจ Frontend: http://localhost:8080" + +# Function to cleanup on exit +cleanup() { + echo "๐Ÿ›‘ Shutting down servers..." + kill $BACKEND_PID 2>/dev/null || true + kill $FRONTEND_PID 2>/dev/null || true + exit 0 +} + +trap cleanup EXIT INT TERM + +# Keep script running +wait \ No newline at end of file diff --git a/crates/kiko-frontend/src/components/header.rs b/crates/kiko-frontend/src/components/header.rs index 842ef29..442bdeb 100644 --- a/crates/kiko-frontend/src/components/header.rs +++ b/crates/kiko-frontend/src/components/header.rs @@ -7,7 +7,10 @@ pub fn header() -> Html { html! {
-

{ "Kiko Pointing Poker" }

+ +
{"Kiko"}
+
{"๐Ÿซต"}
+
diff --git a/tests/e2e/package-lock.json b/tests/e2e/package-lock.json index b24bde2..4552b5e 100644 --- a/tests/e2e/package-lock.json +++ b/tests/e2e/package-lock.json @@ -7,7 +7,6 @@ "": { "name": "kiko-e2e-tests", "version": "1.0.0", - "hasInstallScript": true, "devDependencies": { "@playwright/test": "^1.40.0" } diff --git a/tests/e2e/package.json b/tests/e2e/package.json index 4ffee5e..de3e0dc 100644 --- a/tests/e2e/package.json +++ b/tests/e2e/package.json @@ -10,7 +10,7 @@ "test:e2e:debug": "playwright test --debug", "test:e2e:ui": "playwright test --ui", "test:report": "playwright show-report", - "postinstall": "playwright install" + "install:browsers": "playwright install" }, "devDependencies": { "@playwright/test": "^1.40.0" diff --git a/tests/e2e/playwright.config.js b/tests/e2e/playwright.config.js index 65803e5..561348b 100644 --- a/tests/e2e/playwright.config.js +++ b/tests/e2e/playwright.config.js @@ -12,8 +12,8 @@ module.exports = defineConfig({ forbidOnly: !!process.env.CI, /* Retry on CI only */ retries: process.env.CI ? 2 : 0, - /* Use more workers on CI for faster execution */ - workers: process.env.CI ? 4 : undefined, + /* Use single worker on CI to avoid resource contention */ + workers: process.env.CI ? 1 : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: [["html", { open: "never" }]], /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ @@ -39,25 +39,17 @@ module.exports = defineConfig({ use: { ...devices["Desktop Firefox"] }, }, { - name: "webkit", + name: "webkit", use: { ...devices["Desktop Safari"] }, }, - { - name: "Mobile Chrome", - use: { ...devices["Pixel 7"] }, - }, - { - name: "Mobile Safari", - use: { ...devices["iPhone 15"] }, - }, ], /* Run your local dev server before starting the tests */ webServer: { - command: "./bin/dev", + command: process.env.CI ? "./bin/ci" : "./bin/dev", cwd: "../..", url: "http://localhost:8080", reuseExistingServer: !process.env.CI, - timeout: 3 * 60 * 1000, // 3 minutes for server startup + timeout: process.env.CI ? 60 * 1000 : 3 * 60 * 1000, // 1 minute for CI, 3 minutes for dev }, }); diff --git a/tests/e2e/src/home-page.spec.js b/tests/e2e/src/home-page.spec.js index 07bd6f1..1e650d6 100644 --- a/tests/e2e/src/home-page.spec.js +++ b/tests/e2e/src/home-page.spec.js @@ -6,7 +6,8 @@ test.describe('Home Page', () => { }); test('should display the main heading', async ({ page }) => { - await expect(page.locator('h1')).toHaveText('Kiko Pointing Poker'); + await expect(page.locator('header a')).toContainText('Kiko'); + await expect(page.locator('header a')).toContainText('๐Ÿซต'); }); test('should display create session form', async ({ page }) => { diff --git a/tests/e2e/src/session-complete.spec.js b/tests/e2e/src/session-complete.spec.js index 0a6b2bc..5daffe1 100644 --- a/tests/e2e/src/session-complete.spec.js +++ b/tests/e2e/src/session-complete.spec.js @@ -49,7 +49,7 @@ test.describe("Complete Session Tests", () => { // Should show main header await expect( - page.getByRole("heading", { name: "Kiko Pointing Poker" }) + page.locator('header a') ).toBeVisible(); // Should show join form since we're not joined @@ -433,7 +433,7 @@ test.describe("Complete Session Tests", () => { // If no connection status visible, at least verify the page loaded if (!foundConnection) { await expect( - page.getByRole("heading", { name: "Kiko Pointing Poker" }) + page.locator('header a') ).toBeVisible(); } }); @@ -451,7 +451,7 @@ test.describe("Complete Session Tests", () => { // Session should still be functional await expect( - page.getByRole("heading", { name: "Kiko Pointing Poker" }) + page.locator('header a') ).toBeVisible(); }); }); diff --git a/tests/e2e/src/session-page.spec.js b/tests/e2e/src/session-page.spec.js index db17d62..684c4d7 100644 --- a/tests/e2e/src/session-page.spec.js +++ b/tests/e2e/src/session-page.spec.js @@ -32,7 +32,7 @@ test.describe("Session Page", () => { await page.goto("/session/nonexistent-session"); // The page should load with the main header - await expect(page.locator("h1")).toHaveText("Kiko Pointing Poker"); + await expect(page.locator('header a')).toContainText('Kiko'); }); test("should show loading state initially", async ({ page }) => { @@ -102,7 +102,7 @@ test.describe("Session Page", () => { // If no specific connection text found, at least check that the page loaded if (!foundConnectionText) { - await expect(page.locator("h1")).toHaveText("Kiko Pointing Poker"); + await expect(page.locator('header a')).toContainText('Kiko'); } });