pierrejeambrun commented on code in PR #58548: URL: https://github.com/apache/airflow/pull/58548#discussion_r2569626566
########## airflow-core/src/airflow/ui/tests/e2e/specs/dag-trigger.spec.ts: ########## @@ -0,0 +1,60 @@ +/*! + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 + * + * http://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. + */ +import { test } from "@playwright/test"; + +import { testConfig } from "../../../playwright.config.ts"; +import { DagsPage } from "../pages/DagsPage.ts"; +import { LoginPage } from "../pages/LoginPage.ts"; Review Comment: Nit: We try to avoid relative imports like this. ########## airflow-core/src/airflow/ui/tests/e2e/specs/dag-trigger.spec.ts: ########## @@ -0,0 +1,60 @@ +/*! + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 + * + * http://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. + */ +import { test } from "@playwright/test"; + +import { testConfig } from "../../../playwright.config.ts"; +import { DagsPage } from "../pages/DagsPage.ts"; +import { LoginPage } from "../pages/LoginPage.ts"; + +/** + * DAG Trigger E2E Tests + */ + +test.describe("DAG Trigger Workflow", () => { + let loginPage: LoginPage; + let dagsPage: DagsPage; + + // Test configuration from centralized config + + const testCredentials = testConfig.credentials; + + const testDagId = testConfig.testDag.id; + + // eslint-disable-next-line @typescript-eslint/require-await Review Comment: You can probaly convert this to a sync function, so we can get rid of the eslint disable above. @ ########## airflow-core/src/airflow/ui/playwright.config.ts: ########## @@ -0,0 +1,104 @@ +/*! + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 + * + * http://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. + */ +import { defineConfig, devices } from "@playwright/test"; + +/** + * Playwright configuration for Airflow UI End-to-End Tests + */ +export const testConfig = { + credentials: { + password: process.env.TEST_PASSWORD ?? "admin", + username: process.env.TEST_USERNAME ?? "admin", + }, + testDag: { + id: process.env.TEST_DAG_ID ?? "example_bash_operator", + }, +}; + +export default defineConfig({ + expect: { + timeout: 5000, + }, + forbidOnly: process.env.CI !== undefined && process.env.CI !== "", + fullyParallel: true, + projects: [ + { + name: "chromium", + use: { + ...devices["Desktop Chrome"], + launchOptions: { + args: [ + "--start-maximized", + "--disable-web-security", + "--disable-features=VizDisplayCompositor", + "--window-size=1920,1080", + "--window-position=0,0", + ], + channel: "chrome", + ignoreDefaultArgs: ["--enable-automation"], + }, + }, + }, + { + name: "firefox", + use: { + ...devices["Desktop Firefox"], + launchOptions: { + args: [ + "--width=1920", + "--height=1080", + "--no-sandbox", + "--disable-dev-shm-usage", + "--disable-web-security", + ], + }, + }, + }, + { + name: "webkit", + use: { + ...devices["Desktop Safari"], + launchOptions: { + args: [], + }, + }, + }, + ], + reporter: [ + ["html", { outputFolder: "playwright-report" }], + ["json", { outputFile: "test-results/results.json" }], + process.env.CI !== undefined && process.env.CI !== "" ? ["github"] : ["list"], + ], + + retries: process.env.CI !== undefined && process.env.CI !== "" ? 2 : 0, + + testDir: "./tests/e2e/specs", + + timeout: 30_000, Review Comment: That timeout value might be too long no? Similarly above i've seen a 30_000 somewhere else. ########## airflow-core/src/airflow/ui/tests/e2e/specs/dag-trigger.spec.ts: ########## Review Comment: I would be for running this by default as a workflow to all UI PRs, so we're sure this doesn't get broken and very hard to maintain. As long as those tests are lightweight and doesn't require too much time / resources that would be my recommendation. ########## airflow-core/src/airflow/ui/tests/e2e/README.md: ########## @@ -0,0 +1,91 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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 + + http://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. + --> + +# Airflow UI End-to-End Tests + +UI automation tests using Playwright for critical Airflow workflows. + +## Prerequisites + +**Requires running Airflow with example DAGs:** + +- Airflow running on `http://localhost:28080` (default) +- Admin user: `admin/admin` +- Example DAGs loaded (uses `example_bash_operator`) + +## Running Tests + +### Using Breeze + +```bash +# Basic run +breeze testing ui-e2e-tests + +# Specific test with browser visible +breeze testing ui-e2e-tests --test-pattern "dag-trigger.spec.ts" --headed + +# Different browsers +breeze testing ui-e2e-tests --browser firefox --headed +breeze testing ui-e2e-tests --browser webkit --headed +``` + +### Using pnpm directly + +```bash +cd airflow-core/src/airflow/ui + +# Install dependencies +pnpm install +pnpm exec playwright install + +# Run tests +pnpm test:e2e:headed # Show browser +pnpm test:e2e:ui # Interactive debugging +``` + +## Test Structure + +``` +tests/e2e/ +├── pages/ # Page Object Models +└── specs/ # Test files +``` + +## Configuration + +Set environment variables if needed: + +```bash +export AIRFLOW_UI_BASE_URL=http://localhost:28080 +export TEST_USERNAME=admin +export TEST_PASSWORD=admin +export TEST_DAG_ID=example_bash_operator +``` + +## Debugging + +```bash +# Step through tests +breeze testing ui-e2e-tests --debug-e2e + +# View test report +pnpm exec playwright show-report Review Comment: maybe replace by `test:e2e:report` ########## airflow-core/src/airflow/ui/tests/e2e/README.md: ########## @@ -0,0 +1,91 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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 + + http://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. + --> + +# Airflow UI End-to-End Tests + +UI automation tests using Playwright for critical Airflow workflows. + +## Prerequisites + +**Requires running Airflow with example DAGs:** + +- Airflow running on `http://localhost:28080` (default) Review Comment: ```suggestion - Airflow UI running on `http://localhost:28080` (default) ``` ########## airflow-core/src/airflow/ui/playwright.config.ts: ########## @@ -0,0 +1,104 @@ +/*! + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 + * + * http://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. + */ +import { defineConfig, devices } from "@playwright/test"; + +/** + * Playwright configuration for Airflow UI End-to-End Tests + */ +export const testConfig = { + credentials: { + password: process.env.TEST_PASSWORD ?? "admin", + username: process.env.TEST_USERNAME ?? "admin", + }, + testDag: { + id: process.env.TEST_DAG_ID ?? "example_bash_operator", + }, +}; + +export default defineConfig({ + expect: { + timeout: 5000, + }, + forbidOnly: process.env.CI !== undefined && process.env.CI !== "", + fullyParallel: true, + projects: [ + { + name: "chromium", + use: { + ...devices["Desktop Chrome"], + launchOptions: { + args: [ + "--start-maximized", + "--disable-web-security", + "--disable-features=VizDisplayCompositor", + "--window-size=1920,1080", + "--window-position=0,0", + ], + channel: "chrome", + ignoreDefaultArgs: ["--enable-automation"], + }, + }, + }, + { + name: "firefox", + use: { + ...devices["Desktop Firefox"], + launchOptions: { + args: [ + "--width=1920", + "--height=1080", + "--no-sandbox", + "--disable-dev-shm-usage", + "--disable-web-security", + ], + }, + }, + }, + { + name: "webkit", + use: { + ...devices["Desktop Safari"], + launchOptions: { + args: [], + }, + }, + }, + ], + reporter: [ + ["html", { outputFolder: "playwright-report" }], + ["json", { outputFile: "test-results/results.json" }], + process.env.CI !== undefined && process.env.CI !== "" ? ["github"] : ["list"], + ], + + retries: process.env.CI !== undefined && process.env.CI !== "" ? 2 : 0, + + testDir: "./tests/e2e/specs", + + timeout: 30_000, + use: { + actionTimeout: 10_000, Review Comment: Same here, that's almost 3 hours ########## airflow-core/src/airflow/ui/tests/e2e/pages/LoginPage.ts: ########## @@ -0,0 +1,93 @@ +/*! + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 + * + * http://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. + */ +import { expect } from "@playwright/test"; +import type { Locator, Page } from "@playwright/test"; + +import { BasePage } from "./BasePage.ts"; + +/** + * Login Page Object + */ +export class LoginPage extends BasePage { + // Page URLs + public static get loginUrl(): string { + return "/auth/login"; + } + + public readonly errorMessage: Locator; + public readonly loginButton: Locator; + public readonly passwordInput: Locator; + public readonly usernameInput: Locator; + + public constructor(page: Page) { + super(page); + + this.usernameInput = page.locator('input[name="username"]'); + this.passwordInput = page.locator('input[name="password"]'); + this.loginButton = page.locator('button[type="submit"]'); Review Comment: Could be great to handle both `SimpleAuthManager` and `FabAuthManager`. The button is not found with `FabAuthManager` at the moment. I think it's a small adjustment to make to the selector. (if else) ########## airflow-core/src/airflow/ui/tests/e2e/specs/dag-trigger.spec.ts: ########## @@ -0,0 +1,60 @@ +/*! + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 + * + * http://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. + */ +import { test } from "@playwright/test"; + +import { testConfig } from "../../../playwright.config.ts"; +import { DagsPage } from "../pages/DagsPage.ts"; +import { LoginPage } from "../pages/LoginPage.ts"; + +/** + * DAG Trigger E2E Tests + */ + +test.describe("DAG Trigger Workflow", () => { + let loginPage: LoginPage; + let dagsPage: DagsPage; + + // Test configuration from centralized config + + const testCredentials = testConfig.credentials; + + const testDagId = testConfig.testDag.id; + + // eslint-disable-next-line @typescript-eslint/require-await + test.beforeEach(async ({ page }) => { + loginPage = new LoginPage(page); + + dagsPage = new DagsPage(page); + }); + + test("should successfully trigger a DAG run", async () => { + test.setTimeout(7 * 60 * 1000); + + await loginPage.navigateAndLogin(testCredentials.username, testCredentials.password); + + await loginPage.expectLoginSuccess(); + + const dagRunId = await dagsPage.triggerDag(testDagId); + + // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions + if (dagRunId) { Review Comment: Here you need an actual boolean check I believe. It will remove the eslint warning. `Boolean(...)` -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
