This is an automated email from the ASF dual-hosted git repository.
rahulvats pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new e6cdee07f54 Feat : Verify DAG source codetab functionality(#59546)
(#62290)
e6cdee07f54 is described below
commit e6cdee07f54ffe9e7a5300d4976424cce1332ea7
Author: Harsh Thakur <[email protected]>
AuthorDate: Wed Feb 25 12:25:44 2026 +0530
Feat : Verify DAG source codetab functionality(#59546) (#62290)
---
.../src/airflow/ui/tests/e2e/pages/DagCodePage.ts | 102 +++++++++++++++++++++
.../ui/tests/e2e/specs/dag-code-tab.spec.ts | 49 ++++++++++
2 files changed, 151 insertions(+)
diff --git a/airflow-core/src/airflow/ui/tests/e2e/pages/DagCodePage.ts
b/airflow-core/src/airflow/ui/tests/e2e/pages/DagCodePage.ts
new file mode 100644
index 00000000000..7895b4ceb78
--- /dev/null
+++ b/airflow-core/src/airflow/ui/tests/e2e/pages/DagCodePage.ts
@@ -0,0 +1,102 @@
+/*!
+ * 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, type Locator, type Page } from "@playwright/test";
+import { BasePage } from "tests/e2e/pages/BasePage";
+
+export class DagCodePage extends BasePage {
+ public readonly editorContainer: Locator;
+ public readonly editorScrollable: Locator;
+ public readonly lineNumbers: Locator;
+ public readonly syntaxTokens: Locator;
+
+ public constructor(page: Page) {
+ super(page);
+ this.editorContainer = page.locator('[role="code"]');
+ this.lineNumbers = page.locator(".monaco-editor .line-numbers");
+ this.editorScrollable = page.locator(".monaco-scrollable-element");
+ this.syntaxTokens = page.locator(".monaco-editor .view-line span span");
+ }
+
+ public async navigateToCodeTab(dagId: string): Promise<void> {
+ await this.navigateTo(`/dags/${dagId}/code`);
+ await this.waitForCodeReady();
+ }
+ public async verifyCodeIsScrollable(): Promise<void> {
+ await this.waitForCodeReady();
+
+ const scrollable = this.editorScrollable.first();
+
+ await expect(scrollable).toBeVisible({ timeout: 30_000 });
+
+ // For a sufficiently long file the scroll-height exceeds the client-height
+ const isScrollable = await scrollable.evaluate((el) => el.scrollHeight >
el.clientHeight);
+
+ expect(isScrollable).toBe(true);
+ }
+
+ public async verifyLineNumbersDisplayed(): Promise<void> {
+ await this.waitForCodeReady();
+
+ await expect(this.lineNumbers.first()).toBeVisible({ timeout: 30_000 });
+
+ const lineNumberCount = await this.lineNumbers.count();
+
+ expect(lineNumberCount).toBeGreaterThan(0);
+
+ const firstLineText = await this.lineNumbers.first().textContent();
+
+ expect(firstLineText?.trim()).toBe("1");
+ }
+
+ public async verifySourceCodeDisplayed(): Promise<void> {
+ await this.waitForCodeReady();
+
+ const viewLines = this.page.locator(".monaco-editor .view-line");
+
+ await expect(viewLines.first()).toBeVisible({ timeout: 30_000 });
+
+ const lineCount = await viewLines.count();
+
+ expect(lineCount).toBeGreaterThan(0);
+ }
+
+ public async verifySyntaxHighlighting(): Promise<void> {
+ await this.waitForCodeReady();
+
+ const tokens = this.syntaxTokens;
+
+ await expect(tokens.first()).toBeVisible({ timeout: 30_000 });
+
+ const tokenCount = await tokens.count();
+
+ expect(tokenCount).toBeGreaterThan(1);
+
+ const classNames = await tokens.first().getAttribute("class");
+
+ expect(classNames).toMatch(/mtk\d+/);
+ }
+
+ private async waitForCodeReady(): Promise<void> {
+ await this.editorContainer.waitFor({ state: "visible", timeout: 60_000 });
+
+ const viewLines = this.page.locator(".monaco-editor .view-line");
+
+ await viewLines.first().waitFor({ state: "visible", timeout: 30_000 });
+ }
+}
diff --git a/airflow-core/src/airflow/ui/tests/e2e/specs/dag-code-tab.spec.ts
b/airflow-core/src/airflow/ui/tests/e2e/specs/dag-code-tab.spec.ts
new file mode 100644
index 00000000000..f4577873e42
--- /dev/null
+++ b/airflow-core/src/airflow/ui/tests/e2e/specs/dag-code-tab.spec.ts
@@ -0,0 +1,49 @@
+/*!
+ * 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";
+
+import { DagCodePage } from "../pages/DagCodePage";
+
+test.describe("DAG Code Tab", () => {
+ test.setTimeout(60_000);
+ const dagId = testConfig.testDag.id;
+ let codePage: DagCodePage;
+
+ test.beforeEach(async ({ page }) => {
+ codePage = new DagCodePage(page);
+ await codePage.navigateToCodeTab(dagId);
+ });
+
+ test("Verify DAG source code is displayed", async () => {
+ await codePage.verifySourceCodeDisplayed();
+ });
+
+ test("Verify syntax highlighting is applied", async () => {
+ await codePage.verifySyntaxHighlighting();
+ });
+
+ test("Verify code is scrollable for long files", async () => {
+ await codePage.verifyCodeIsScrollable();
+ });
+
+ test("Verify line numbers are displayed", async () => {
+ await codePage.verifyLineNumbersDisplayed();
+ });
+});