Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 121 additions & 0 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -214,3 +214,124 @@ jobs:
name: integration-test-results
path: "**/build/reports/tests"
retention-days: 7

Comment thread
mnonnenmacher marked this conversation as resolved.
test-ui-e2e:
runs-on: ubuntu-24.04
steps:
- name: Checkout Repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0

- name: Setup Gradle
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0

- name: Generate OpenAPI spec
run: ./gradlew --stacktrace :core:generateOpenApiSpec

- name: Install pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
with:
version: 10

- name: Install Node
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: 24
cache: pnpm
cache-dependency-path: ui/pnpm-lock.yaml

- name: Install dependencies
run: pnpm -C ui install

- name: Generate API client and routes
run: pnpm -C ui generate:api && pnpm -C ui generate:routes

- name: Install Playwright Browsers
run: pnpm -C ui exec playwright install --with-deps

- name: Start core services
run: docker compose up -d core

- name: Wait for core readiness
run: |
echo "Waiting for core liveness endpoint..."
for i in {1..60}; do
if curl -fsS http://127.0.0.1:8080/api/v1/liveness >/dev/null; then
echo "Core liveness endpoint is available."
break
fi

if [ $i -eq 60 ]; then
echo "Core failed to report healthy within 120 seconds" >&2
docker compose logs core
exit 1
fi

sleep 2
done

- name: Run Playwright tests
env:
VITE_UI_URL: http://127.0.0.1:8082/
VITE_CLIENT_ID: ort-server-ui
run: |
# Exit on error, undefined variables, and pipe failures
set -euo pipefail

# Start the Vite dev server in the background
# The dev server is needed because Playwright tests run against a live server
pnpm -C ui dev --host 0.0.0.0 --port 8082 > ui-dev.log 2>&1 &
UI_DEV_PID=$!

# Set up cleanup to ensure the background dev server process is killed on exit
# This prevents process leaks even if the workflow fails or is cancelled
cleanup() {
if ps -p $UI_DEV_PID > /dev/null 2>&1; then
kill $UI_DEV_PID || true
fi
}
trap cleanup EXIT

echo "Waiting for UI dev server to be ready on http://localhost:8082 ..."
for i in {1..60}; do
# Fail fast if the dev server crashes - this provides better error messages
# than waiting for the timeout with no logs
if ! ps -p $UI_DEV_PID > /dev/null 2>&1; then
echo "UI dev server process exited unexpectedly. Recent logs:"
tail -n 200 ui-dev.log || true
exit 1
fi

# Check if Vite has finished building by looking for the ready message in the log
if grep -q "ready in" ui-dev.log 2>/dev/null; then
# Also verify the server actually returns HTML content
if curl -fsS http://127.0.0.1:8082 2>/dev/null | grep -q "<html"; then
echo "UI dev server is ready."
break
fi
fi
if [ $i -eq 60 ]; then
echo "UI dev server failed to become ready within 120 seconds" >&2
echo "Last 200 lines of UI dev log:"
tail -n 200 ui-dev.log || true
exit 1
fi
sleep 2
done

pnpm -C ui test:e2e

- name: Upload UI dev log
if: success() || failure()
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: ui-dev-log
path: ui-dev.log
retention-days: 7

- name: Upload Playwright report
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
if: success() || failure()
with:
name: playwright-report
path: ui/playwright-report
retention-days: 7
7 changes: 7 additions & 0 deletions ui/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,10 @@ src/routeTree.gen.ts

# AI Agent related files and directories
plans/

Comment thread
mnonnenmacher marked this conversation as resolved.
# Playwright
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
/playwright/.auth/
11 changes: 11 additions & 0 deletions ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,17 @@ $ ./gradlew :core:generateOpenApiSpec
$ pnpm -C ui generate:api
```

## e2e tests

To run the Playwright e2e tests locally, first start core service (also starts keycloak, postgres and rabbitmq) and dev UI, then run the tests:

```shell
$ docker compose up -d core
$ cd ui
$ pnpm dev
$ pnpm test:e2e
```

## Docker

The Docker image for the UI is built as part of the `buildAllImages` Gradle task.
Expand Down
2 changes: 2 additions & 0 deletions ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"scripts": {
"dev": "vite",
"test": "vitest",
"test:e2e": "playwright test",
"build": "pnpm generate:api && pnpm generate:routes && tsc && vite build",
"format": "prettier --write .",
"format:check": "prettier --check .",
Expand Down Expand Up @@ -66,6 +67,7 @@
"@eslint/js": "^9.37.0",
"@hey-api/openapi-ts": "0.87.5",
"@ianvs/prettier-plugin-sort-imports": "^4.2.1",
"@playwright/test": "^1.56.1",
"@tailwindcss/postcss": "^4.0.0",
"@tailwindcss/typography": "^0.5.15",
"@tanstack/router-cli": "^1.32.10",
Expand Down
71 changes: 71 additions & 0 deletions ui/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright (C) 2025 The ORT Server Authors (See <https://github.com/eclipse-apoapsis/ort-server/blob/main/NOTICE>)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
* License-Filename: LICENSE
*/

import { defineConfig, devices } from '@playwright/test';

/**
* Read environment variables from file.
* https://github.com/motdotla/dotenv
*/
// import dotenv from 'dotenv';
// import path from 'path';
// dotenv.config({ path: path.resolve(__dirname, '.env') });

/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: './tests',
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: 'html',
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: process.env.CI ? 'http://localhost:8082' : 'http://localhost:5173',

/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
},

/* Configure projects for major browsers */
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},

{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},

{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
],
});
38 changes: 38 additions & 0 deletions ui/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 38 additions & 0 deletions ui/tests/smoke-test.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2025 The ORT Server Authors (See <https://github.com/eclipse-apoapsis/ort-server/blob/main/NOTICE>)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
* License-Filename: LICENSE
*/

import { expect, test } from '@playwright/test';

test('test', async ({ page }) => {
await page.goto('/');
await expect(
page.getByRole('heading', { name: 'Sign in to your account' })
).toBeVisible();
await page.getByRole('textbox', { name: 'Username or email' }).click();
await page.getByRole('textbox', { name: 'Username or email' }).fill('admin');
await page.getByRole('textbox', { name: 'Username or email' }).press('Tab');
await page.getByRole('textbox', { name: 'Password' }).fill('admin');
await page.getByRole('button', { name: 'Sign In' }).click();
await expect(
page.getByText('Browse your organizations or create a new one')
).toBeVisible();
await expect(
page.getByRole('link', { name: 'Add organization' })
).toBeVisible();
});
5 changes: 3 additions & 2 deletions ui/tsconfig.node.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"strict": true
"strict": true,
"types": ["node"]
},
"include": ["vite.config.ts"]
"include": ["vite.config.ts", "playwright.config.ts"]
}
2 changes: 2 additions & 0 deletions ui/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export default defineConfig({
},
},
test: {
include: ['src/**/*.{test,spec}.{ts,tsx}'],
exclude: ['tests/**'],
includeSource: ['src/**/*.ts'],
},
});
Loading