diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml new file mode 100644 index 0000000000..49cea4a2f0 --- /dev/null +++ b/.github/workflows/e2e-test.yml @@ -0,0 +1,147 @@ +# .github/workflows/playwright.yml +name: Playwright Tests + +on: + pull_request: + +jobs: + test: + runs-on: [self-hosted, linux, x64] + permissions: + checks: write + pull-requests: write + contents: read + strategy: + fail-fast: false + matrix: + lts: + - name: "v25.6" + apiEndpoint: "http://10.122.10.224:8090" + - name: "v24.09" + apiEndpoint: "http://10.122.10.224:8090" + + 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: Run Relay + # run: pnpm run relay + + # - name: Build project + # run: pnpm run build + + # - name: Serve build at port 9081 (background) + # run: | + # npx serve -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: Prepare .env.playwright with local server URL + # run: | + # cp e2e/envs/.env.playwright.sample e2e/envs/.env.playwright + # if grep -q '^BASE_URL=' e2e/envs/.env.playwright; then + # sed -i 's|^BASE_URL=.*|BASE_URL=http://127.0.0.1:9081|' e2e/envs/.env.playwright + # else + # echo 'BASE_URL=http://127.0.0.1:9081' >> e2e/envs/.env.playwright + # fi + + - name: Run Relay + run: pnpm run relay + + - 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 e2e/agent.test.ts + + - name: Upload HTML report (on failure) + if: failure() + uses: actions/upload-artifact@v4 + with: + name: playwright-report-${{ matrix.lts.name }} + path: playwright-report/ diff --git a/e2e/utils/test-util.ts b/e2e/utils/test-util.ts index 19fef4faff..001322af6e 100644 --- a/e2e/utils/test-util.ts +++ b/e2e/utils/test-util.ts @@ -5,6 +5,13 @@ export const webuiEndpoint = 'http://127.0.0.1:9081'; 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') => { + 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, @@ -12,9 +19,17 @@ export async function login( endpoint: string, ) { await page.goto(webuiEndpoint); + await changeSigninInMode(page, 'ID'); 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"]'); } diff --git a/playwright.config.ts b/playwright.config.ts index 0ba8a57213..ab717286a9 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -23,7 +23,7 @@ export default defineConfig({ /* 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", + reporter: process.env.CI ? [["html", { open: "never" }], ["list"]] : "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('/')`. */ @@ -72,9 +72,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: 'concurrently "npm run build:d" "npm run server:d"', + // url: "http://127.0.0.1:9081", + // timeout: 1000 * 60 * 5, + // } + // : undefined, }); diff --git a/src/components/backend-ai-login.ts b/src/components/backend-ai-login.ts index 5cc3053acf..18c8da8f0d 100644 --- a/src/components/backend-ai-login.ts +++ b/src/components/backend-ai-login.ts @@ -2130,6 +2130,7 @@ export default class BackendAILogin extends BackendAIPage { ? html`