Skip to content
Open
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
117 changes: 117 additions & 0 deletions .github/workflows/e2e-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# .github/workflows/playwright.yml
name: Playwright Tests

on:
pull_request:

jobs:
test:
runs-on: "ubuntu-latest"
permissions:
checks: write
pull-requests: write
contents: read
strategy:
fail-fast: false
matrix:
lts:
- name: "main"
apiEndpoint: "https://19d3c8.poc.isla-sorna.backend.ai/"
- name: "v25.15" # Please update according to the latest LTS versions
apiEndpoint: "https://19d3c8.poc.isla-sorna.backend.ai/"

name: E2E Playwright Tests for LTS ${{ matrix.lts.name }}
steps:
- name: Checkout code
uses: actions/checkout@v4

- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: latest
run_install: false

- uses: actions/setup-node@v4
name: Install Node.js
with:
node-version-file: ".nvmrc"
cache: "pnpm"

- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV

- uses: actions/cache@v4
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-

- name: Install dependencies
run: pnpm install

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

- name: Copy config.toml.sample to config.toml
run: |
awk '
/^[[:space:]]*$/ { next }
/^\[.*\]$/ { if (n++) print ""; print; next }
/^[[:space:]]*#[^=]/ { print; next }
{
line = $0
sub(/#.*/, "", line)
sub(/[[:space:]]+$/, "", line)
if (line != "") print line
}
' config.toml.sample > config-cleaned.toml

- name: Inject apiEndpoint and allowChangeSigninMode into config.toml
run: |
EP="${{ matrix.lts.apiEndpoint }}"
awk -v ep="$EP" '
{
if ($0 ~ /^apiEndpoint[[:space:]]*=/) {
print "apiEndpoint = \"" ep "\""
} else if ($0 ~ /^allowChangeSigninMode[[:space:]]*=/) {
print "allowChangeSigninMode = true"
} else {
print
}
}
' config-cleaned.toml > config.toml

# - name: Upload config.toml artifact
# uses: actions/upload-artifact@v4
# with:
# name: config-toml-${{ matrix.lts.name }}
# path: config.toml

- name: Build project
run: pnpm run build

- name: Serve build at port 9081 (background)
run: |
pnpm server:p -s -l 9081 > /dev/null 2>&1 &
echo "Waiting for server to start..."
for i in {1..30}; do
if curl -s http://127.0.0.1:9081 > /dev/null; then
echo "Server is up!"
break
fi
sleep 1
done

- name: Run Playwright Tests
run: pnpm playwright test

- name: Upload HTML report (on failure)
if: failure()
uses: actions/upload-artifact@v4
with:
name: playwright-report-${{ matrix.lts.name }}
path: playwright-report/
17 changes: 16 additions & 1 deletion e2e/utils/test-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,33 @@
export const webServerEndpoint = 'http://127.0.0.1:8090';
export const visualRegressionWebserverEndpoint = 'http://10.122.10.216:8090';

export const changeSigninInMode = async (page: Page, mode: 'IAM' | 'ID') => {
Copy link

Copilot AI Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected spelling of 'changeSigninInMode' to 'changeSignInMode' (capitalized 'I' in 'In').

Copilot uses AI. Check for mistakes.
const button = page.locator('#change-signin-area button');
if ((await button.textContent())?.includes(mode)) {
await button.click();
}
};

export async function login(
page: Page,
username: string,
password: string,
endpoint: string,
) {
await page.goto(webuiEndpoint);
await changeSigninInMode(page, 'ID');
Copy link

Copilot AI Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function call should use corrected name 'changeSignInMode' to match the function definition.

Copilot uses AI. Check for mistakes.
await page.getByLabel('Email or Username').fill(username);
await page.getByRole('textbox', { name: 'Password' }).fill(password);
await page.getByRole('textbox', { name: 'Endpoint' }).fill(endpoint);

const endpointInput = page.locator('#id_api_endpoint label');
try {
await endpointInput.waitFor({ state: 'visible', timeout: 1000 });
await page.getByRole('textbox', { name: 'Endpoint' }).fill(endpoint);
} catch (_e) {
// Endpoint input not visible, skip filling it
}
await page.getByLabel('Login', { exact: true }).click();
await page.waitForSelector('[data-testid="user-dropdown-button"]');

Check failure on line 34 in e2e/utils/test-util.ts

View workflow job for this annotation

GitHub Actions / E2E Playwright Tests for LTS v25.15

[chromium] › agent.test.ts:25:7 › Agent list › should have at least one connected agent

1) [chromium] › agent.test.ts:25:7 › Agent list › should have at least one connected agent ─────── Retry #2 ─────────────────────────────────────────────────────────────────────────────────────── Error: page.waitForSelector: Test timeout of 10000ms exceeded. Call log: - waiting for locator('[data-testid="user-dropdown-button"]') to be visible at utils/test-util.ts:34 32 | } 33 | await page.getByLabel('Login', { exact: true }).click(); > 34 | await page.waitForSelector('[data-testid="user-dropdown-button"]'); | ^ 35 | } 36 | 37 | export const userInfo = { at login (/home/runner/work/backend.ai-webui/backend.ai-webui/e2e/utils/test-util.ts:34:14) at loginAsAdmin (/home/runner/work/backend.ai-webui/backend.ai-webui/e2e/utils/test-util.ts:61:3) at /home/runner/work/backend.ai-webui/backend.ai-webui/e2e/agent.test.ts:6:3
}

export const userInfo = {
Expand Down
15 changes: 9 additions & 6 deletions playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default defineConfig({
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
// workers: process.env.CI ? 4 : undefined,
Copy link

Copilot AI Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commented-out code should be removed rather than left in the codebase. If parallel workers are intentionally disabled, consider adding a comment explaining why.

Suggested change
// workers: process.env.CI ? 4 : undefined,

Copilot uses AI. Check for mistakes.
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: process.env.CI
? [["html", { open: "never" }], ["github"]]
Expand All @@ -34,6 +34,7 @@ export default defineConfig({
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "on-first-retry",
},
timeout: process.env.CI ? 10 * 1000 : undefined,
Copy link

Copilot AI Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The 10-second timeout for CI might be too short for E2E tests. Consider documenting why this specific timeout was chosen or using a named constant to make the value more maintainable.

Copilot uses AI. Check for mistakes.

snapshotPathTemplate: `e2e/{testFileDir}/snapshot/{arg}{ext}`,
/* Configure projects for major browsers */
Expand Down Expand Up @@ -74,9 +75,11 @@ export default defineConfig({
// },
],
/* Run your local dev server before starting the tests */
// webServer: {
// command: 'npm run start',
// url: 'http://127.0.0.1:3000',
// reuseExistingServer: !process.env.CI,
// },
// webServer: process.env.CI
// ? {
// command: "pnpm run server:p -s -l 9081",
// url: "http://127.0.0.1:9081",
// timeout: 1000 * 60 * 5,
// }
// : undefined,
});
1 change: 1 addition & 0 deletions src/components/backend-ai-login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2140,6 +2140,7 @@ export default class BackendAILogin extends BackendAIPage {
? html`
<div
id="change-signin-area"
data-testid="change-login-mode-button"
class="vertical center-justified layout"
style="flex: 1; text-align: right;"
>
Expand Down
8 changes: 7 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,11 @@
"lib": ["es6", "dom", "es2016", "es2017", "es2020"],
"preserveWatchOutput": true
},
"include": ["src/components/*", "src/plugins/*", "src/reducers/*", "src/*"]
"include": [
"src/components/*",
"src/plugins/*",
"src/reducers/*",
"src/*",
"playwright.config.ts"
]
}
Loading