Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
da21255
Revert "Fix memory leak in remote logging connection cache (#56695)"
vatsrahul1001 Oct 28, 2025
54ce790
Merge branch 'main' of github.com:astronomer/airflow
vatsrahul1001 Oct 30, 2025
f62eb18
Merge branch 'main' of github.com:astronomer/airflow
vatsrahul1001 Nov 4, 2025
2895434
Merge branch 'main' of github.com:astronomer/airflow
vatsrahul1001 Nov 5, 2025
23aba98
Merge branch 'main' of github.com:astronomer/airflow
vatsrahul1001 Nov 11, 2025
3ac12ee
Merge branch 'main' of github.com:astronomer/airflow
vatsrahul1001 Nov 24, 2025
d4fef89
Merge branch 'main' of github.com:astronomer/airflow
vatsrahul1001 Nov 26, 2025
61fc383
Merge branch 'main' of github.com:astronomer/airflow
vatsrahul1001 Nov 28, 2025
785ff42
Merge branch 'main' of github.com:astronomer/airflow
vatsrahul1001 Nov 29, 2025
9879a3d
Merge branch 'main' of github.com:astronomer/airflow
vatsrahul1001 Dec 1, 2025
d6ef5cb
initiate airflow instance + ci workflow
vatsrahul1001 Dec 1, 2025
fbe667e
Remove temporary push trigger
vatsrahul1001 Dec 1, 2025
2d9271a
remove on push
vatsrahul1001 Dec 1, 2025
082d293
fix mypy
vatsrahul1001 Dec 1, 2025
560333c
Merge branch 'main' into ci-workflow-ui-e2e
vatsrahul1001 Dec 2, 2025
339435a
run workflow onevery PR
vatsrahul1001 Dec 9, 2025
0563e04
Merge branch 'ci-workflow-ui-e2e' of github.com:astronomer/airflow in…
vatsrahul1001 Dec 9, 2025
2078ba4
Merge branch 'main' of github.com:astronomer/airflow into ci-workflow…
vatsrahul1001 Dec 9, 2025
2000be6
update workflow to run from every PR using selective check
vatsrahul1001 Dec 9, 2025
3f8811c
Merge branch 'main' into ci-workflow-ui-e2e
vatsrahul1001 Dec 9, 2025
46877c9
add sperate UI jobs per browser
vatsrahul1001 Dec 9, 2025
6ee6218
Merge branch 'ci-workflow-ui-e2e' of github.com:astronomer/airflow in…
vatsrahul1001 Dec 9, 2025
ae2320f
Merge branch 'main' into ci-workflow-ui-e2e
vatsrahul1001 Dec 9, 2025
14ca2ab
Merge branch 'main' into ci-workflow-ui-e2e
vatsrahul1001 Dec 10, 2025
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
40 changes: 40 additions & 0 deletions .github/workflows/additional-prod-image-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ on: # yamllint disable-line rule:truthy
description: "Whether to use uv"
required: true
type: string
run-ui-e2e-tests:
description: "Whether to run UI e2e tests (true/false)"
required: true
type: string
permissions:
contents: read
jobs:
Expand Down Expand Up @@ -218,6 +222,42 @@ jobs:
use-uv: ${{ inputs.use-uv }}
e2e_test_mode: "remote_log"

test-ui-e2e-chromium:
name: "Chromium UI e2e tests with PROD image"
uses: ./.github/workflows/ui-e2e-tests.yml
with:
workflow-name: "Chromium UI e2e tests"
runners: ${{ inputs.runners }}
platform: ${{ inputs.platform }}
default-python-version: "${{ inputs.default-python-version }}"
use-uv: ${{ inputs.use-uv }}
browser: "chromium"
if: inputs.run-ui-e2e-tests == 'true'

test-ui-e2e-firefox:
name: "Firefox UI e2e tests with PROD image"
uses: ./.github/workflows/ui-e2e-tests.yml
with:
workflow-name: "Firefox UI e2e tests"
runners: ${{ inputs.runners }}
platform: ${{ inputs.platform }}
default-python-version: "${{ inputs.default-python-version }}"
use-uv: ${{ inputs.use-uv }}
browser: "firefox"
if: inputs.run-ui-e2e-tests == 'true'

test-ui-e2e-webkit:
name: "WebKit UI e2e tests with PROD image"
uses: ./.github/workflows/ui-e2e-tests.yml
with:
workflow-name: "WebKit UI e2e tests"
runners: ${{ inputs.runners }}
platform: ${{ inputs.platform }}
default-python-version: "${{ inputs.default-python-version }}"
use-uv: ${{ inputs.use-uv }}
browser: "webkit"
if: inputs.run-ui-e2e-tests == 'true'

airflow-ctl-integration-tests:
timeout-minutes: 60
name: "Airflow CTL integration tests with PROD image"
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/ci-amd-arm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ jobs:
run-task-sdk-integration-tests: ${{ steps.selective-checks.outputs.run-task-sdk-integration-tests }}
runner-type: ${{ steps.selective-checks.outputs.runner-type }}
run-ui-tests: ${{ steps.selective-checks.outputs.run-ui-tests }}
run-ui-e2e-tests: ${{ steps.selective-checks.outputs.run-ui-e2e-tests }}
run-unit-tests: ${{ steps.selective-checks.outputs.run-unit-tests }}
run-www-tests: ${{ steps.selective-checks.outputs.run-www-tests }}
selected-providers-list-as-string: >-
Expand Down Expand Up @@ -790,6 +791,7 @@ jobs:
run-task-sdk-integration-tests: ${{ needs.build-info.outputs.run-task-sdk-integration-tests }}
canary-run: ${{ needs.build-info.outputs.canary-run }}
use-uv: ${{ needs.build-info.outputs.use-uv }}
run-ui-e2e-tests: ${{ needs.build-info.outputs.run-ui-e2e-tests }}
if: needs.build-info.outputs.prod-image-build == 'true'

tests-kubernetes:
Expand Down
150 changes: 150 additions & 0 deletions .github/workflows/ui-e2e-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# 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.
#
---

name: UI End-to-End Tests

permissions:
contents: read
on: # yamllint disable-line rule:truthy
workflow_dispatch:
inputs:
workflow-name:
description: "Name of the test"
type: string
required: true
runners:
description: "The array of labels (in json form) determining runners."
type: string
default: '["ubuntu-24.04"]'
platform:
description: "Platform for the build - 'linux/amd64' or 'linux/arm64'"
type: string
default: 'linux/amd64'
default-python-version:
description: "Which version of python should be used by default"
type: string
default: '3.10'
use-uv:
description: "Whether to use uv to build the image (true/false)"
type: string
default: 'true'
docker-image-tag:
description: "Tag of the Docker image to test"
type: string
required: true
browser:
description: "Browser to test (chromium, firefox, webkit, all)"
type: string
default: "all"

workflow_call:
inputs:
workflow-name:
description: "Name of the test"
type: string
required: true
runners:
description: "The array of labels (in json form) determining runners."
required: true
type: string
platform:
description: "Platform for the build - 'linux/amd64' or 'linux/arm64'"
required: true
type: string
default-python-version:
description: "Which version of python should be used by default"
required: true
type: string
use-uv:
description: "Whether to use uv to build the image (true/false)"
required: true
type: string
docker-image-tag:
description: "Tag of the Docker image to test"
type: string
default: ""
browser:
description: "Browser to test (chromium, firefox, webkit, all)"
type: string
default: "all"

jobs:
test-ui-e2e-tests:
timeout-minutes: 90
name: ${{ inputs.workflow-name || 'UI E2E Tests' }}
runs-on: ${{ fromJSON(inputs.runners || '["ubuntu-24.04"]') }}
env:
PYTHON_MAJOR_MINOR_VERSION: "${{ inputs.default-python-version || '3.10' }}"
GITHUB_REPOSITORY: ${{ github.repository }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_USERNAME: ${{ github.actor }}
VERBOSE: "true"
BROWSER: "${{ inputs.browser || 'all' }}"
PLATFORM: "${{ inputs.platform || 'linux/amd64' }}"
USE_UV: "${{ inputs.use-uv || 'true' }}"
steps:
- name: "Cleanup repo"
shell: bash
run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*"
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 2
persist-credentials: false
- name: "Prepare breeze & PROD image: ${{ env.PYTHON_MAJOR_MINOR_VERSION }}"
uses: ./.github/actions/prepare_breeze_and_image
with:
platform: ${{ inputs.platform }}
image-type: "prod"
python: ${{ env.PYTHON_MAJOR_MINOR_VERSION }}
use-uv: ${{ inputs.use-uv }}
make-mnt-writeable-and-cleanup: true
id: breeze
if: github.event_name != 'workflow_dispatch'
- name: "Install Breeze (manual trigger)"
uses: ./.github/actions/breeze
if: github.event_name == 'workflow_dispatch'
- name: "Setup pnpm"
uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
with:
version: 9
run_install: false
- name: "Setup node"
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 21
- name: "Install Playwright browsers and dependencies"
run: |
cd airflow-core/src/airflow/ui
pnpm install --frozen-lockfile
pnpm exec playwright install --with-deps
- name: "Test UI e2e tests"
run: breeze testing ui-e2e-tests --browser "$BROWSER"
env:
DOCKER_IMAGE: "${{ inputs.docker-image-tag || '' }}"
- name: "Upload test results"
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: "playwright-report-${{ env.BROWSER }}"
path: |
airflow-core/src/airflow/ui/playwright-report/
airflow-core/src/airflow/ui/test-results/
retention-days: 7
if-no-files-found: 'warn'
if: always()
141 changes: 102 additions & 39 deletions airflow-core/src/airflow/ui/tests/e2e/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,75 +17,138 @@
under the License.
-->

# Airflow UI End-to-End Tests
# UI End-to-End Tests

UI automation tests using Playwright for critical Airflow workflows.

## Prerequisites

**Requires running Airflow with example DAGs:**

- Airflow UI running on `http://localhost:28080` (default)
- Admin user: `admin/admin`
- Example DAGs loaded (uses `example_bash_operator`)
End-to-end tests for the Airflow UI using Playwright.

## Running Tests

### Using Breeze
### Using Breeze (Recommended)

The easiest way to run the tests:

```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
# Run specific browser
breeze testing ui-e2e-tests --browser firefox

# Run specific test
breeze testing ui-e2e-tests --test-pattern "dag-trigger.spec.ts"

# Different browsers
breeze testing ui-e2e-tests --browser firefox --headed
breeze testing ui-e2e-tests --browser webkit --headed
# Debug mode
breeze testing ui-e2e-tests --debug-e2e

# See the browser
breeze testing ui-e2e-tests --headed
```

### Using pnpm directly
### Direct Execution

If you already have Airflow running on `http://localhost:8080`:

```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
pnpm test:e2e:install
pnpm test:e2e
```

## Test Structure
## CI Integration

Tests run in GitHub Actions via workflow dispatch. The workflow uses `breeze testing ui-e2e-tests` which handles starting Airflow with docker-compose, running the tests, and cleanup.

To run manually:

1. Go to Actions → UI End-to-End Tests
2. Click Run workflow
3. Select browser and other options

## Directory Structure

```
tests/e2e/
├── pages/ # Page Object Models
├── pages/ # Page objects
│ ├── BasePage.ts
│ ├── LoginPage.ts
│ └── DagsPage.ts
└── specs/ # Test files
└── dag-trigger.spec.ts
```

## Configuration
## Writing Tests

Set environment variables if needed:
We use the Page Object Model pattern:

```bash
export AIRFLOW_UI_BASE_URL=http://localhost:28080
export TEST_USERNAME=admin
export TEST_PASSWORD=admin
export TEST_DAG_ID=example_bash_operator
```typescript
// pages/DagPage.ts
export class DagPage extends BasePage {
readonly pauseButton: Locator;

constructor(page: Page) {
super(page);
this.pauseButton = page.locator('[data-testid="dag-pause"]');
}

async pause() {
await this.pauseButton.click();
}
}

// specs/dag.spec.ts
test('pause DAG', async ({ page }) => {
const dagPage = new DagPage(page);
await dagPage.goto();
await dagPage.pause();
await expect(dagPage.pauseButton).toHaveAttribute('aria-pressed', 'true');
});
```

## Configuration

Environment variables (with defaults):

- `AIRFLOW_UI_BASE_URL` - Airflow URL (default: `http://localhost:8080`)
- `TEST_USERNAME` - Username (default: `airflow`)
- `TEST_PASSWORD` - Password (default: `airflow`)
- `TEST_DAG_ID` - Test DAG ID (default: `example_bash_operator`)

## Debugging

```bash
# Step through tests
breeze testing ui-e2e-tests --debug-e2e
View test report after running locally:

# View test report
```bash
pnpm test:e2e:report
```

Find test artifacts in `test-results/` and reports in `playwright-report/`.
When tests fail in CI, check the uploaded artifacts for screenshots and HTML reports.

## Breeze Options

```bash
breeze testing ui-e2e-tests --help
```

Common options:

- `--browser` - chromium, firefox, webkit, or all
- `--headed` - Show browser window
- `--debug-e2e` - Enable Playwright inspector
- `--ui-mode` - Interactive UI mode
- `--test-pattern` - Run specific test file
- `--workers` - Number of parallel workers

## Test Coverage

Current tests:

- Login flow
- DAG triggering
- DAG run status

Planned tests:

- DAG pause/unpause
- Task details
- Connections
- Variables
Loading
Loading