This is an automated email from the ASF dual-hosted git repository.
pierrejeambrun 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 1353ad406ba Add tests for dag filtering in home page and dag
documentation modal (#45607)
1353ad406ba is described below
commit 1353ad406baac944612cfd1aa4df801bd4859695
Author: Karthikeyan Singaravelan <[email protected]>
AuthorDate: Fri Jan 24 23:54:31 2025 +0530
Add tests for dag filtering in home page and dag documentation modal
(#45607)
* Add tests for dags list page filter and dag documentation button.
* Reorganize handlers to separate mock directory for reuse.
* Rename test data to avoid laptop file paths.
* Refactor mock setup and wrapper.
* Rebase and fix conflicts.
---
airflow/ui/package.json | 1 +
airflow/ui/pnpm-lock.yaml | 348 ++++++++++++++++++++-
.../ui/src/components/DisplayMarkdownButton.tsx | 9 +-
airflow/ui/src/mocks/handlers/config.ts | 59 ++++
airflow/ui/src/mocks/handlers/dag.ts | 66 ++++
airflow/ui/src/mocks/handlers/dags.ts | 193 ++++++++++++
.../{testsSetup.ts => src/mocks/handlers/index.ts} | 9 +-
airflow/ui/src/pages/Dag/Dag.test.tsx | 47 +++
airflow/ui/src/pages/DagsList/DagsFilters.tsx | 21 +-
airflow/ui/src/pages/DagsList/DagsList.test.tsx | 37 +++
airflow/ui/src/router.tsx | 177 ++++++-----
.../ui/{testsSetup.ts => src/utils/AppWrapper.tsx} | 25 +-
airflow/ui/src/utils/Wrapper.tsx | 16 +-
airflow/ui/testsSetup.ts | 16 +-
14 files changed, 905 insertions(+), 119 deletions(-)
diff --git a/airflow/ui/package.json b/airflow/ui/package.json
index 34592143802..a2dd2006525 100644
--- a/airflow/ui/package.json
+++ b/airflow/ui/package.json
@@ -74,6 +74,7 @@
"eslint-plugin-unicorn": "^55.0.0",
"globals": "^15.9.0",
"happy-dom": "^15.10.2",
+ "msw": "^2.7.0",
"prettier": "^3.3.3",
"typescript": "~5.5.4",
"typescript-eslint": "^8.5.0",
diff --git a/airflow/ui/pnpm-lock.yaml b/airflow/ui/pnpm-lock.yaml
index 3096fd332d3..99663d535ed 100644
--- a/airflow/ui/pnpm-lock.yaml
+++ b/airflow/ui/pnpm-lock.yaml
@@ -143,7 +143,7 @@ importers:
version: 3.7.0(@swc/[email protected])([email protected](@types/[email protected]))
'@vitest/coverage-v8':
specifier: ^2.1.1
- version: 2.1.1([email protected](@types/[email protected])([email protected]))
+ version:
2.1.1([email protected](@types/[email protected])([email protected])([email protected](@types/[email protected])([email protected])))
eslint:
specifier: ^9.10.0
version: 9.10.0([email protected])
@@ -177,6 +177,9 @@ importers:
happy-dom:
specifier: ^15.10.2
version: 15.10.2
+ msw:
+ specifier: ^2.7.0
+ version: 2.7.0(@types/[email protected])([email protected])
prettier:
specifier: ^3.3.3
version: 3.3.3
@@ -194,7 +197,7 @@ importers:
version: 3.5.2([email protected](@types/[email protected]))
vitest:
specifier: ^2.1.1
- version: 2.1.1(@types/[email protected])([email protected])
+ version:
2.1.1(@types/[email protected])([email protected])([email protected](@types/[email protected])([email protected]))
web-worker:
specifier: ^1.3.0
version: 1.3.0
@@ -325,6 +328,15 @@ packages:
'@bcoe/[email protected]':
resolution: {integrity:
sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
+ '@bundled-es-modules/[email protected]':
+ resolution: {integrity:
sha512-8o+5fRPLNbjbdGRRmJj3h6Hh1AQJf2dk3qQ/5ZFb+PXkRNiSoMGGUKlsgLfrxneb72axVJyIYji64E2+nNfYyw==}
+
+ '@bundled-es-modules/[email protected]':
+ resolution: {integrity:
sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==}
+
+ '@bundled-es-modules/[email protected]':
+ resolution: {integrity:
sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==}
+
'@chakra-ui/[email protected]':
resolution: {integrity:
sha512-MV6D4VLRIHr4PkW4zMyqfrNS1mPlCTiCXwvYGtDFQYr+xHFfonhAuf9WjsSc0nyp2m0OdkSLnzmVKkZFLo25Tg==}
@@ -619,6 +631,26 @@ packages:
resolution: {integrity:
sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==}
engines: {node: '>=18.18'}
+ '@inquirer/[email protected]':
+ resolution: {integrity:
sha512-VKgaKxw2I3cu2smedeMFyxuYyI+HABlFY1Px4j8NueA7xDskKAo9hxEQemTpp1Fu4OiTtOCgU4eK91BVuBKH3g==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@types/node': '>=18'
+
+ '@inquirer/[email protected]':
+ resolution: {integrity:
sha512-+7/dCYwDku2xfcWJWX6Urxb8aRz6d0K+4lRgIBM08ktE84dm++RPROgnVfWq4hLK5FVu/O4rbO9HnJtaz3pt2w==}
+ engines: {node: '>=18'}
+
+ '@inquirer/[email protected]':
+ resolution: {integrity:
sha512-BXvGj0ehzrngHTPTDqUoDT3NXL8U0RxUk2zJm2A66RhCEIWdtU1v6GuUqNAgArW4PQ9CinqIWyHdQgdwOj06zQ==}
+ engines: {node: '>=18'}
+
+ '@inquirer/[email protected]':
+ resolution: {integrity:
sha512-ZhQ4TvhwHZF+lGhQ2O/rsjo80XoZR5/5qhOY3t6FJuX5XBg5Be8YzYTvaUGJnc12AUGI2nr4QSUE4PhKSigx7g==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@types/node': '>=18'
+
'@internationalized/[email protected]':
resolution: {integrity:
sha512-jLxQjefH9VI5P9UQuqB6qNKnvFt1Ky1TPIzHGsIlCi7sZZoMR8SdYbBGRvM0y+Jtb+ez4ieBzmiAUcpmPYpyOw==}
@@ -669,6 +701,10 @@ packages:
'@lezer/[email protected]':
resolution: {integrity:
sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==}
+ '@mswjs/[email protected]':
+ resolution: {integrity:
sha512-AAwRb5vXFcY4L+FvZ7LZusDuZ0vEe0Zm8ohn1FM6/X7A3bj4mqmkAcGRWuvC2JwSygNwHAAmMnAI73vPHeqsHA==}
+ engines: {node: '>=18'}
+
'@nodelib/[email protected]':
resolution: {integrity:
sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
@@ -681,6 +717,15 @@ packages:
resolution: {integrity:
sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'}
+ '@open-draft/[email protected]':
+ resolution: {integrity:
sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==}
+
+ '@open-draft/[email protected]':
+ resolution: {integrity:
sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==}
+
+ '@open-draft/[email protected]':
+ resolution: {integrity:
sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==}
+
'@pandacss/[email protected]':
resolution: {integrity:
sha512-BE6h6CsJk14ugIRrsazJtN3fcg+KDFRat1Bs93YFKH6jd4DOb1yUyVvC70jKqPVvg70zEcV8acZ7VdcU5TLu+w==}
@@ -937,6 +982,9 @@ packages:
'@types/[email protected]':
resolution: {integrity:
sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==}
+ '@types/[email protected]':
+ resolution: {integrity:
sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
+
'@types/[email protected]':
resolution: {integrity:
sha512-Reoy+pKnvsksN0lQUlcH6dOGjRZ/3WRwXR//m+/8lt1BXeI4xyaUZoqULNjyXXRuh0Mj4LNpkCvhUpQlY3X5xQ==}
@@ -1045,6 +1093,12 @@ packages:
'@types/[email protected]':
resolution: {integrity:
sha512-WeqMfGJLGuLCqHGYRGHxnKrXcTitc6L/nBUWfWPcTarG3t9PsquqUMuVeXZeca+mglY4Vo5GZjCi0A3Or2lnxA==}
+ '@types/[email protected]':
+ resolution: {integrity:
sha512-jmIUGWrAiwu3dZpxntxieC+1n/5c3mjrImkmOSQ2NC5uP6cYO4aAZDdSmRcI5C1oiTmqlZGHC+/NmJrKogbP5A==}
+
+ '@types/[email protected]':
+ resolution: {integrity:
sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==}
+
'@types/[email protected]':
resolution: {integrity:
sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==}
@@ -1567,6 +1621,10 @@ packages:
[email protected]:
resolution: {integrity:
sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
+ [email protected]:
+ resolution: {integrity:
sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
+ engines: {node: '>=8'}
+
[email protected]:
resolution: {integrity:
sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
@@ -1812,6 +1870,14 @@ packages:
resolution: {integrity:
sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==}
engines: {node: '>=4'}
+ [email protected]:
+ resolution: {integrity:
sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==}
+ engines: {node: '>= 12'}
+
+ [email protected]:
+ resolution: {integrity:
sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
+ engines: {node: '>=12'}
+
[email protected]:
resolution: {integrity:
sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==}
@@ -1858,6 +1924,10 @@ packages:
[email protected]:
resolution: {integrity:
sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}
+ [email protected]:
+ resolution: {integrity:
sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
+ engines: {node: '>= 0.6'}
+
[email protected]:
resolution: {integrity:
sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==}
@@ -2367,6 +2437,10 @@ packages:
[email protected]:
resolution: {integrity:
sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
+ [email protected]:
+ resolution: {integrity:
sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
+ engines: {node: 6.* || 8.* || >= 10.*}
+
[email protected]:
resolution: {integrity:
sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==}
@@ -2429,6 +2503,10 @@ packages:
[email protected]:
resolution: {integrity:
sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
+ [email protected]:
+ resolution: {integrity:
sha512-AjqGKbDGUFRKIRCP9tCKiIGHyriz2oHEbPIbEtcSLSs4YjReZOIPQQWek4+6hjw62H9QShXHyaGivGiYVLeYFQ==}
+ engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0}
+
[email protected]:
resolution: {integrity:
sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==}
engines: {node: '>=0.4.7'}
@@ -2480,6 +2558,9 @@ packages:
[email protected]:
resolution: {integrity:
sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==}
+ [email protected]:
+ resolution: {integrity:
sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==}
+
[email protected]:
resolution: {integrity:
sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==}
@@ -2626,6 +2707,9 @@ packages:
resolution: {integrity:
sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==}
engines: {node: '>= 0.4'}
+ [email protected]:
+ resolution: {integrity:
sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==}
+
[email protected]:
resolution: {integrity:
sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==}
engines: {node: '>= 0.4'}
@@ -3046,6 +3130,20 @@ packages:
[email protected]:
resolution: {integrity:
sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+ [email protected]:
+ resolution: {integrity:
sha512-BIodwZ19RWfCbYTxWTUfTXc+sg4OwjCAgxU1ZsgmggX/7S3LdUifsbUPJs61j0rWb19CZRGY5if77duhc0uXzw==}
+ engines: {node: '>=18'}
+ hasBin: true
+ peerDependencies:
+ typescript: '>= 4.8.x'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ [email protected]:
+ resolution: {integrity:
sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==}
+ engines: {node: ^18.17.0 || >=20.5.0}
+
[email protected]:
resolution: {integrity:
sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -3140,6 +3238,9 @@ packages:
resolution: {integrity:
sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
engines: {node: '>= 0.8.0'}
+ [email protected]:
+ resolution: {integrity:
sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==}
+
[email protected]:
resolution: {integrity:
sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
engines: {node: '>=6'}
@@ -3206,6 +3307,9 @@ packages:
resolution: {integrity:
sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==}
engines: {node: 20 || >=22}
+ [email protected]:
+ resolution: {integrity:
sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==}
+
[email protected]:
resolution: {integrity:
sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
@@ -3295,6 +3399,9 @@ packages:
[email protected]:
resolution: {integrity:
sha512-VDdG/VYtOgdGkWJx7y0o7p+zArSf2383Isci8C+BP3YXgMYDoPd3cCBjw0JdWb6YBb9sFiOPbAADDVTPJnh+9g==}
+ [email protected]:
+ resolution: {integrity:
sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==}
+
[email protected]:
resolution: {integrity:
sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
@@ -3302,6 +3409,9 @@ packages:
[email protected]:
resolution: {integrity:
sha512-QFADYnsVoBMw1srW7OVKEYjG+MbIa49s54w1MA1EDY6r2r/sTcKKYqRX1f4GYvnXP7eN/Pe9HFcX+hwzmrXRHA==}
+ [email protected]:
+ resolution: {integrity:
sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
+
[email protected]:
resolution: {integrity:
sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
@@ -3444,6 +3554,13 @@ packages:
[email protected]:
resolution: {integrity:
sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==}
+ [email protected]:
+ resolution: {integrity:
sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
+ engines: {node: '>=0.10.0'}
+
+ [email protected]:
+ resolution: {integrity:
sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
+
[email protected]:
resolution: {integrity:
sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
@@ -3562,6 +3679,10 @@ packages:
[email protected]:
resolution: {integrity:
sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
+ [email protected]:
+ resolution: {integrity:
sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
+ engines: {node: '>= 0.8'}
+
[email protected]:
resolution: {integrity:
sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==}
@@ -3569,6 +3690,9 @@ packages:
resolution: {integrity:
sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==}
engines: {node: '>= 0.4'}
+ [email protected]:
+ resolution: {integrity:
sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==}
+
[email protected]:
resolution: {integrity:
sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
@@ -3686,6 +3810,10 @@ packages:
resolution: {integrity:
sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
+ [email protected]:
+ resolution: {integrity:
sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==}
+ engines: {node: '>=6'}
+
[email protected]:
resolution: {integrity:
sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
@@ -3711,6 +3839,10 @@ packages:
resolution: {integrity:
sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
+ [email protected]:
+ resolution: {integrity:
sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
+ engines: {node: '>=10'}
+
[email protected]:
resolution: {integrity:
sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==}
engines: {node: '>=8'}
@@ -3719,6 +3851,10 @@ packages:
resolution: {integrity:
sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==}
engines: {node: '>=8'}
+ [email protected]:
+ resolution: {integrity:
sha512-rfgpoi08xagF3JSdtJlCwMq9DGNDE0IMh3Mkpc1wUypg9vPi786AiqeBBKcqvIkq42azsBM85N490fyZjeUftw==}
+ engines: {node: '>=16'}
+
[email protected]:
resolution: {integrity:
sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==}
engines: {node: '>= 0.4'}
@@ -3785,6 +3921,10 @@ packages:
[email protected]:
resolution: {integrity:
sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==}
+ [email protected]:
+ resolution: {integrity:
sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
+ engines: {node: '>= 4.0.0'}
+
[email protected]:
resolution: {integrity:
sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==}
hasBin: true
@@ -3797,6 +3937,9 @@ packages:
[email protected]:
resolution: {integrity:
sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+ [email protected]:
+ resolution: {integrity:
sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
+
[email protected]:
resolution: {integrity:
sha512-djviaxuOOh7wkj0paeO1Q/4wMZ8Zrnag5H6yBvzN7AKKe8beOaED9SF5/ByLqsku8NP4zQqsvM2u3ew/tJK8/w==}
peerDependencies:
@@ -3968,6 +4111,10 @@ packages:
[email protected]:
resolution: {integrity:
sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==}
+ [email protected]:
+ resolution: {integrity:
sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
+ engines: {node: '>=8'}
+
[email protected]:
resolution: {integrity:
sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
engines: {node: '>=10'}
@@ -3980,6 +4127,10 @@ packages:
resolution: {integrity:
sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
engines: {node: '>=0.4'}
+ [email protected]:
+ resolution: {integrity:
sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
+ engines: {node: '>=10'}
+
[email protected]:
resolution: {integrity:
sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
@@ -3987,10 +4138,22 @@ packages:
resolution: {integrity:
sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
engines: {node: '>= 6'}
+ [email protected]:
+ resolution: {integrity:
sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
+ engines: {node: '>=12'}
+
+ [email protected]:
+ resolution: {integrity:
sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
+ engines: {node: '>=12'}
+
[email protected]:
resolution: {integrity:
sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
+ [email protected]:
+ resolution: {integrity:
sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==}
+ engines: {node: '>=18'}
+
[email protected]:
resolution: {integrity:
sha512-+0PALYNJNgK6hldkgDq2vLrw5f6g/jCInz52n9RTpropGgeAf/ioFUCdtsjCqu4gNhW9D01rUQBROoRjdzyn2Q==}
engines: {node: '>=12.7.0'}
@@ -4217,6 +4380,19 @@ snapshots:
'@bcoe/[email protected]': {}
+ '@bundled-es-modules/[email protected]':
+ dependencies:
+ cookie: 0.7.2
+
+ '@bundled-es-modules/[email protected]':
+ dependencies:
+ statuses: 2.0.1
+
+ '@bundled-es-modules/[email protected]':
+ dependencies:
+ '@types/tough-cookie': 4.0.5
+ tough-cookie: 4.1.4
+
'@chakra-ui/[email protected]': {}
'@chakra-ui/[email protected](@emotion/[email protected](@types/[email protected])([email protected]))([email protected]([email protected]))([email protected])':
@@ -4509,6 +4685,32 @@ snapshots:
'@humanwhocodes/[email protected]': {}
+ '@inquirer/[email protected](@types/[email protected])':
+ dependencies:
+ '@inquirer/core': 10.1.3(@types/[email protected])
+ '@inquirer/type': 3.0.2(@types/[email protected])
+ '@types/node': 22.5.4
+
+ '@inquirer/[email protected](@types/[email protected])':
+ dependencies:
+ '@inquirer/figures': 1.0.9
+ '@inquirer/type': 3.0.2(@types/[email protected])
+ ansi-escapes: 4.3.2
+ cli-width: 4.1.0
+ mute-stream: 2.0.0
+ signal-exit: 4.1.0
+ strip-ansi: 6.0.1
+ wrap-ansi: 6.2.0
+ yoctocolors-cjs: 2.1.2
+ transitivePeerDependencies:
+ - '@types/node'
+
+ '@inquirer/[email protected]': {}
+
+ '@inquirer/[email protected](@types/[email protected])':
+ dependencies:
+ '@types/node': 22.5.4
+
'@internationalized/[email protected]':
dependencies:
'@swc/helpers': 0.5.13
@@ -4565,6 +4767,15 @@ snapshots:
dependencies:
'@lezer/common': 1.2.3
+ '@mswjs/[email protected]':
+ dependencies:
+ '@open-draft/deferred-promise': 2.2.0
+ '@open-draft/logger': 0.3.0
+ '@open-draft/until': 2.1.0
+ is-node-process: 1.2.0
+ outvariant: 1.4.3
+ strict-event-emitter: 0.5.1
+
'@nodelib/[email protected]':
dependencies:
'@nodelib/fs.stat': 2.0.5
@@ -4577,6 +4788,15 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.17.1
+ '@open-draft/[email protected]': {}
+
+ '@open-draft/[email protected]':
+ dependencies:
+ is-node-process: 1.2.0
+ outvariant: 1.4.3
+
+ '@open-draft/[email protected]': {}
+
'@pandacss/[email protected]': {}
'@pkgjs/[email protected]':
@@ -4788,6 +5008,8 @@ snapshots:
'@types/[email protected]': {}
+ '@types/[email protected]': {}
+
'@types/[email protected]': {}
'@types/[email protected]': {}
@@ -4898,6 +5120,10 @@ snapshots:
'@types/prop-types': 15.7.12
csstype: 3.1.3
+ '@types/[email protected]': {}
+
+ '@types/[email protected]': {}
+
'@types/[email protected]': {}
'@types/[email protected]': {}
@@ -5440,7 +5666,7 @@ snapshots:
transitivePeerDependencies:
- '@swc/helpers'
-
'@vitest/[email protected]([email protected](@types/[email protected])([email protected]))':
+
'@vitest/[email protected]([email protected](@types/[email protected])([email protected])([email protected](@types/[email protected])([email protected])))':
dependencies:
'@ampproject/remapping': 2.3.0
'@bcoe/v8-coverage': 0.2.3
@@ -5454,7 +5680,7 @@ snapshots:
std-env: 3.7.0
test-exclude: 7.0.1
tinyrainbow: 1.2.0
- vitest: 2.1.1(@types/[email protected])([email protected])
+ vitest:
2.1.1(@types/[email protected])([email protected])([email protected](@types/[email protected])([email protected]))
transitivePeerDependencies:
- supports-color
@@ -5465,12 +5691,13 @@ snapshots:
chai: 5.1.1
tinyrainbow: 1.2.0
- '@vitest/[email protected](@vitest/[email protected])([email protected](@types/[email protected]))':
+
'@vitest/[email protected](@vitest/[email protected])([email protected](@types/[email protected])([email protected]))([email protected](@types/[email protected]))':
dependencies:
'@vitest/spy': 2.1.1
estree-walker: 3.0.3
magic-string: 0.30.11
optionalDependencies:
+ msw: 2.7.0(@types/[email protected])([email protected])
vite: 5.4.12(@types/[email protected])
'@vitest/[email protected]':
@@ -6025,6 +6252,10 @@ snapshots:
json-schema-traverse: 0.4.1
uri-js: 4.4.1
+ [email protected]:
+ dependencies:
+ type-fest: 0.21.3
+
[email protected]: {}
[email protected]: {}
@@ -6296,6 +6527,14 @@ snapshots:
dependencies:
escape-string-regexp: 1.0.5
+ [email protected]: {}
+
+ [email protected]:
+ dependencies:
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+ wrap-ansi: 7.0.0
+
[email protected]: {}
[email protected](@lezer/[email protected]):
@@ -6340,6 +6579,8 @@ snapshots:
[email protected]: {}
+ [email protected]: {}
+
[email protected]:
dependencies:
browserslist: 4.23.3
@@ -7014,6 +7255,8 @@ snapshots:
[email protected]: {}
+ [email protected]: {}
+
[email protected]: {}
[email protected]:
@@ -7095,6 +7338,8 @@ snapshots:
[email protected]: {}
+ [email protected]: {}
+
[email protected]:
dependencies:
minimist: 1.2.8
@@ -7166,6 +7411,8 @@ snapshots:
property-information: 5.6.0
space-separated-tokens: 1.1.5
+ [email protected]: {}
+
[email protected]: {}
[email protected]: {}
@@ -7292,6 +7539,8 @@ snapshots:
[email protected]: {}
+ [email protected]: {}
+
[email protected]:
dependencies:
has-tostringtag: 1.0.2
@@ -7893,6 +8142,33 @@ snapshots:
[email protected]: {}
+ [email protected](@types/[email protected])([email protected]):
+ dependencies:
+ '@bundled-es-modules/cookie': 2.0.1
+ '@bundled-es-modules/statuses': 1.0.1
+ '@bundled-es-modules/tough-cookie': 0.1.6
+ '@inquirer/confirm': 5.1.2(@types/[email protected])
+ '@mswjs/interceptors': 0.37.5
+ '@open-draft/deferred-promise': 2.2.0
+ '@open-draft/until': 2.1.0
+ '@types/cookie': 0.6.0
+ '@types/statuses': 2.0.5
+ graphql: 16.10.0
+ headers-polyfill: 4.0.3
+ is-node-process: 1.2.0
+ outvariant: 1.4.3
+ path-to-regexp: 6.3.0
+ picocolors: 1.1.1
+ strict-event-emitter: 0.5.1
+ type-fest: 4.32.0
+ yargs: 17.7.2
+ optionalDependencies:
+ typescript: 5.5.4
+ transitivePeerDependencies:
+ - '@types/node'
+
+ [email protected]: {}
+
[email protected]: {}
[email protected]: {}
@@ -7988,6 +8264,8 @@ snapshots:
type-check: 0.4.0
word-wrap: 1.2.5
+ [email protected]: {}
+
[email protected]:
dependencies:
p-try: 2.2.0
@@ -8061,6 +8339,8 @@ snapshots:
lru-cache: 11.0.2
minipass: 7.1.2
+ [email protected]: {}
+
[email protected]: {}
[email protected]: {}
@@ -8135,10 +8415,16 @@ snapshots:
dependencies:
proxy-compare: 3.0.0
+ [email protected]:
+ dependencies:
+ punycode: 2.3.1
+
[email protected]: {}
[email protected]: {}
+ [email protected]: {}
+
[email protected]: {}
[email protected]:
@@ -8355,6 +8641,10 @@ snapshots:
mdast-util-to-markdown: 2.1.2
unified: 11.0.5
+ [email protected]: {}
+
+ [email protected]: {}
+
[email protected]: {}
[email protected]:
@@ -8488,12 +8778,16 @@ snapshots:
[email protected]: {}
+ [email protected]: {}
+
[email protected]: {}
[email protected]:
dependencies:
internal-slot: 1.0.7
+ [email protected]: {}
+
[email protected]:
dependencies:
emoji-regex: 8.0.0
@@ -8629,6 +8923,13 @@ snapshots:
dependencies:
is-number: 7.0.0
+ [email protected]:
+ dependencies:
+ psl: 1.15.0
+ punycode: 2.3.1
+ universalify: 0.2.0
+ url-parse: 1.5.10
+
[email protected]: {}
[email protected]: {}
@@ -8650,10 +8951,14 @@ snapshots:
dependencies:
prelude-ls: 1.2.1
+ [email protected]: {}
+
[email protected]: {}
[email protected]: {}
+ [email protected]: {}
+
[email protected]:
dependencies:
call-bind: 1.0.7
@@ -8748,6 +9053,8 @@ snapshots:
unist-util-is: 6.0.0
unist-util-visit-parents: 6.0.1
+ [email protected]: {}
+
[email protected]([email protected]):
dependencies:
browserslist: 4.23.3
@@ -8760,6 +9067,11 @@ snapshots:
dependencies:
punycode: 2.3.1
+ [email protected]:
+ dependencies:
+ querystringify: 2.2.0
+ requires-port: 1.0.0
+
[email protected](@types/[email protected])([email protected]):
dependencies:
react: 18.3.1
@@ -8837,10 +9149,10 @@ snapshots:
'@types/node': 22.5.4
fsevents: 2.3.3
- [email protected](@types/[email protected])([email protected]):
+
[email protected](@types/[email protected])([email protected])([email protected](@types/[email protected])([email protected])):
dependencies:
'@vitest/expect': 2.1.1
- '@vitest/mocker':
2.1.1(@vitest/[email protected])([email protected](@types/[email protected]))
+ '@vitest/mocker':
2.1.1(@vitest/[email protected])([email protected](@types/[email protected])([email protected]))([email protected](@types/[email protected]))
'@vitest/pretty-format': 2.1.1
'@vitest/runner': 2.1.1
'@vitest/snapshot': 2.1.1
@@ -8938,6 +9250,12 @@ snapshots:
[email protected]: {}
+ [email protected]:
+ dependencies:
+ ansi-styles: 4.3.0
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+
[email protected]:
dependencies:
ansi-styles: 4.3.0
@@ -8952,12 +9270,28 @@ snapshots:
[email protected]: {}
+ [email protected]: {}
+
[email protected]: {}
[email protected]: {}
+ [email protected]: {}
+
+ [email protected]:
+ dependencies:
+ cliui: 8.0.1
+ escalade: 3.2.0
+ get-caller-file: 2.0.5
+ require-directory: 2.1.1
+ string-width: 4.2.3
+ y18n: 5.0.8
+ yargs-parser: 21.1.1
+
[email protected]: {}
+ [email protected]: {}
+
[email protected](@types/[email protected])([email protected]):
dependencies:
use-sync-external-store: 1.2.2([email protected])
diff --git a/airflow/ui/src/components/DisplayMarkdownButton.tsx
b/airflow/ui/src/components/DisplayMarkdownButton.tsx
index e844f25da64..667366c725f 100644
--- a/airflow/ui/src/components/DisplayMarkdownButton.tsx
+++ b/airflow/ui/src/components/DisplayMarkdownButton.tsx
@@ -38,11 +38,16 @@ const DisplayMarkdownButton = ({
return (
<Box>
- <Button onClick={() => setIsDocsOpen(true)} variant="outline">
+ <Button data-testid="markdown-button" onClick={() =>
setIsDocsOpen(true)} variant="outline">
{icon}
{text}
</Button>
- <Dialog.Root onOpenChange={() => setIsDocsOpen(false)} open={isDocsOpen}
size="md">
+ <Dialog.Root
+ data-testid="markdown-modal"
+ onOpenChange={() => setIsDocsOpen(false)}
+ open={isDocsOpen}
+ size="md"
+ >
<Dialog.Content backdrop>
<Dialog.Header bg="blue.muted">
<Heading size="xl">{header}</Heading>
diff --git a/airflow/ui/src/mocks/handlers/config.ts
b/airflow/ui/src/mocks/handlers/config.ts
new file mode 100644
index 00000000000..f962a04001b
--- /dev/null
+++ b/airflow/ui/src/mocks/handlers/config.ts
@@ -0,0 +1,59 @@
+/*!
+ * 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 { http, HttpResponse, type HttpHandler } from "msw";
+
+export const handlers: Array<HttpHandler> = [
+ http.get("/ui/config", () =>
+ HttpResponse.json({
+ audit_view_excluded_events:
"gantt,landing_times,tries,duration,calendar,graph,grid,tree,tree_data",
+ audit_view_included_events: "",
+ auto_refresh_interval: 3,
+ default_ui_timezone: "UTC",
+ default_wrap: false,
+ enable_swagger_ui: true,
+ hide_paused_dags_by_default: false,
+ instance_name: "Airflow",
+ instance_name_has_markup: false,
+ is_k8s: false,
+ navbar_color: "#fff",
+ navbar_hover_color: "#eee",
+ navbar_logo_text_color: "#51504f",
+ navbar_text_color: "#51504f",
+ navbar_text_hover_color: "#51504f",
+ page_size: 15,
+ require_confirmation_dag_change: false,
+ state_color_mapping: {
+ deferred: "mediumpurple",
+ failed: "red",
+ queued: "gray",
+ removed: "lightgrey",
+ restarting: "violet",
+ running: "lime",
+ scheduled: "tan",
+ skipped: "hotpink",
+ success: "green",
+ up_for_reschedule: "turquoise",
+ up_for_retry: "gold",
+ upstream_failed: "orange",
+ },
+ test_connection: "Disabled",
+ warn_deployment_exposure: true,
+ }),
+ ),
+];
diff --git a/airflow/ui/src/mocks/handlers/dag.ts
b/airflow/ui/src/mocks/handlers/dag.ts
new file mode 100644
index 00000000000..ede31088a94
--- /dev/null
+++ b/airflow/ui/src/mocks/handlers/dag.ts
@@ -0,0 +1,66 @@
+/*!
+ * 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.
+ */
+
+/* eslint-disable unicorn/no-null */
+import { http, HttpResponse, type HttpHandler } from "msw";
+
+export const handlers: Array<HttpHandler> = [
+ http.get("/public/dags/tutorial_taskflow_api/details", () =>
+ HttpResponse.json({
+ asset_expression: null,
+ catchup: false,
+ concurrency: 16,
+ dag_display_name: "tutorial_taskflow_api",
+ dag_id: "tutorial_taskflow_api",
+ dag_run_timeout: null,
+ default_view: "grid",
+ description: null,
+ doc_md:
+ "\n ### TaskFlow API Tutorial Documentation\n This is a simple
data pipeline example which demonstrates the use of\n the TaskFlow API using
three simple tasks for Extract, Transform, and Load.\n Documentation that
goes along with the Airflow TaskFlow API tutorial is\n located\n
[here](https://airflow.apache.org/docs/apache-airflow/stable/tutorial_taskflow_api.html)\n
",
+ end_date: null,
+ file_token:
+
".eJw9yUsOgCAMBcC7cAB7JPISizR82kCJcnvjxtUsJlDWxlQwPEvhjU7TV0pk27N2goxU9f7lB80qxxPXJF-uQ1CjY5avI0wO2-EFouohiw.fhdU5u0Pb7lElEd-AUUXqjHSsdo",
+ fileloc: "/airflow/dags/tutorial_taskflow_api.py",
+ has_import_errors: false,
+ has_task_concurrency_limits: false,
+ is_active: true,
+ is_paused: false,
+ is_paused_upon_creation: null,
+ last_expired: null,
+ last_parsed: "2025-01-13T04:33:54.141792Z",
+ last_parsed_time: "2025-01-13T04:34:13.543097Z",
+ max_active_runs: 16,
+ max_active_tasks: 16,
+ max_consecutive_failed_dag_runs: 0,
+ next_dagrun: null,
+ next_dagrun_create_after: null,
+ next_dagrun_data_interval_end: null,
+ next_dagrun_data_interval_start: null,
+ owners: ["airflow"],
+ params: {},
+ render_template_as_native_obj: false,
+ start_date: "2021-01-01T00:00:00Z",
+ tags: [{ dag_id: "tutorial_taskflow_api", name: "example" }],
+ template_search_path: null,
+ timetable_description: "Never, external triggers only",
+ timetable_summary: null,
+ timezone: "UTC",
+ }),
+ ),
+];
diff --git a/airflow/ui/src/mocks/handlers/dags.ts
b/airflow/ui/src/mocks/handlers/dags.ts
new file mode 100644
index 00000000000..c66d4aef2ee
--- /dev/null
+++ b/airflow/ui/src/mocks/handlers/dags.ts
@@ -0,0 +1,193 @@
+/*!
+ * 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.
+ */
+
+/* eslint-disable unicorn/no-null */
+import { http, HttpResponse, type HttpHandler } from "msw";
+
+export const handlers: Array<HttpHandler> = [
+ http.get("/ui/dags/recent_dag_runs", ({ request }) => {
+ const url = new URL(request.url);
+ const lastDagRunState = url.searchParams.get("last_dag_run_state");
+ const successDag = {
+ dag_display_name: "tutorial_taskflow_api_success",
+ dag_id: "tutorial_taskflow_api_success",
+ default_view: "grid",
+ file_token:
+
".eJw9yUsOgCAMBcC7cAB7JPISizR82kCJcnvjxtUsJlDWxlQwPEvhjU7TV0pk27N2goxU9f7lB80qxxPXJF-uQ1CjY5avI0wO2-EFouohiw.fhdU5u0Pb7lElEd-AUUXqjHSsdo",
+ fileloc: "/airflow/dags/tutorial_taskflow_api.py",
+ has_import_errors: false,
+ has_task_concurrency_limits: false,
+ is_active: true,
+ is_paused: false,
+ last_parsed_time: "2025-01-13T07:34:01.593459Z",
+ latest_dag_runs: [
+ {
+ conf: {},
+ dag_id: "tutorial_taskflow_api",
+ dag_run_id: "manual__2025-01-13T04:33:58.387988+00:00",
+ data_interval_end: "2025-01-13T04:33:58.396323Z",
+ data_interval_start: "2025-01-13T04:33:58.396323Z",
+ end_date: "2025-01-13T04:34:12.143831Z",
+ external_trigger: true,
+ last_scheduling_decision: "2025-01-13T04:34:12.137382Z",
+ logical_date: "2025-01-13T04:33:58.396323Z",
+ queued_at: "2025-01-13T04:33:58.404628Z",
+ run_type: "manual",
+ start_date: "2025-01-13T04:33:58.496197Z",
+ state: "success",
+ triggered_by: "rest_api",
+ },
+ ],
+ max_active_runs: 16,
+ max_active_tasks: 16,
+ max_consecutive_failed_dag_runs: 0,
+ owners: ["airflow"],
+ tags: [{ dag_id: "tutorial_taskflow_api_success", name: "example" }],
+ timetable_description: "Never, external triggers only",
+ };
+ const failedDag = {
+ dag_display_name: "tutorial_taskflow_api_failed",
+ dag_id: "tutorial_taskflow_api_failed",
+ default_view: "grid",
+ file_token:
+
".eJw9yUsOgCAMBcC7cAB7JPISizR82kCJcnvjxtUsJlDWxlQwPEvhjU7TV0pk27N2goxU9f7lB80qxxPXJF-uQ1CjY5avI0wO2-EFouohiw.fhdU5u0Pb7lElEd-AUUXqjHSsdo",
+ fileloc: "/airflow/dags/tutorial_taskflow_api_failed.py",
+ has_import_errors: false,
+ has_task_concurrency_limits: false,
+ is_active: true,
+ is_paused: false,
+ last_parsed_time: "2025-01-13T07:34:01.593459Z",
+ latest_dag_runs: [
+ {
+ conf: {},
+ dag_id: "tutorial_taskflow_api",
+ dag_run_id: "manual__2025-01-13T04:33:58.387988+00:00",
+ data_interval_end: "2025-01-13T04:33:58.396323Z",
+ data_interval_start: "2025-01-13T04:33:58.396323Z",
+ end_date: "2025-01-13T04:34:12.143831Z",
+ external_trigger: true,
+ last_scheduling_decision: "2025-01-13T04:34:12.137382Z",
+ logical_date: "2025-01-13T04:33:58.396323Z",
+ queued_at: "2025-01-13T04:33:58.404628Z",
+ run_type: "manual",
+ start_date: "2025-01-13T04:33:58.496197Z",
+ state: "success",
+ triggered_by: "rest_api",
+ },
+ ],
+ max_active_runs: 16,
+ max_active_tasks: 16,
+ max_consecutive_failed_dag_runs: 0,
+ owners: ["airflow"],
+ tags: [{ dag_id: "tutorial_taskflow_api_failed", name: "example" }],
+ timetable_description: "Never, external triggers only",
+ };
+
+ if (lastDagRunState === "success") {
+ return HttpResponse.json({
+ dags: [successDag],
+ total_entries: 1,
+ });
+ } else if (lastDagRunState === "failed") {
+ return HttpResponse.json({
+ dags: [failedDag],
+ total_entries: 1,
+ });
+ } else {
+ return HttpResponse.json({
+ dags: [failedDag],
+ total_entries: 1,
+ });
+ }
+ }),
+ http.get("/public/dags", ({ request }) => {
+ const url = new URL(request.url);
+ const lastDagRunState = url.searchParams.get("last_dag_run_state");
+ const failedDag = {
+ dag_display_name: "tutorial_taskflow_api_failed",
+ dag_id: "tutorial_taskflow_api_failed",
+ default_view: "grid",
+ description: null,
+ file_token:
+
".eJw9yUsOgCAMBcC7cAB7JPISizR82kCJcnvjxtUsJlDWxlQwPEvhjU7TV0pk27N2goxU9f7lB80qxxPXJF-uQ1CjY5avI0wO2-EFouohiw.fhdU5u0Pb7lElEd-AUUXqjHSsdo",
+ fileloc: "/airflow/dags/tutorial_taskflow_api_failed.py",
+ has_import_errors: false,
+ has_task_concurrency_limits: false,
+ is_active: true,
+ is_paused: false,
+ last_expired: null,
+ last_parsed_time: "2025-01-13T06:45:33.009609Z",
+ max_active_runs: 16,
+ max_active_tasks: 16,
+ max_consecutive_failed_dag_runs: 0,
+ next_dagrun: null,
+ next_dagrun_create_after: null,
+ next_dagrun_data_interval_end: null,
+ next_dagrun_data_interval_start: null,
+ owners: ["airflow"],
+ tags: [{ dag_id: "tutorial_taskflow_api_failed", name: "example" }],
+ timetable_description: "Never, external triggers only",
+ timetable_summary: null,
+ };
+
+ const successDag = {
+ dag_display_name: "tutorial_taskflow_api_success",
+ dag_id: "tutorial_taskflow_api_success",
+ default_view: "grid",
+ description: null,
+ file_token:
+
".eJw9yUsOgCAMBcC7cAB7JPISizR82kCJcnvjxtUsJlDWxlQwPEvhjU7TV0pk27N2goxU9f7lB80qxxPXJF-uQ1CjY5avI0wO2-EFouohiw.fhdU5u0Pb7lElEd-AUUXqjHSsdo",
+ fileloc: "/airflow/dags/tutorial_taskflow_api_success.py",
+ has_import_errors: false,
+ has_task_concurrency_limits: false,
+ is_active: true,
+ is_paused: false,
+ last_expired: null,
+ last_parsed_time: "2025-01-13T06:45:33.009609Z",
+ max_active_runs: 16,
+ max_active_tasks: 16,
+ max_consecutive_failed_dag_runs: 0,
+ next_dagrun: null,
+ next_dagrun_create_after: null,
+ next_dagrun_data_interval_end: null,
+ next_dagrun_data_interval_start: null,
+ owners: ["airflow"],
+ tags: [{ dag_id: "tutorial_taskflow_api_success", name: "example" }],
+ timetable_description: "Never, external triggers only",
+ timetable_summary: null,
+ };
+
+ if (lastDagRunState === "failed") {
+ return HttpResponse.json({
+ dags: [failedDag],
+ total_entries: 1,
+ });
+ } else if (lastDagRunState === "success") {
+ return HttpResponse.json({
+ dags: [successDag],
+ total_entries: 1,
+ });
+ } else {
+ return HttpResponse.json({
+ dags: [failedDag, successDag],
+ total_entries: 2,
+ });
+ }
+ }),
+];
diff --git a/airflow/ui/testsSetup.ts b/airflow/ui/src/mocks/handlers/index.ts
similarity index 77%
copy from airflow/ui/testsSetup.ts
copy to airflow/ui/src/mocks/handlers/index.ts
index 042cf57e630..06294e8ee3c 100644
--- a/airflow/ui/testsSetup.ts
+++ b/airflow/ui/src/mocks/handlers/index.ts
@@ -16,9 +16,8 @@
* specific language governing permissions and limitations
* under the License.
*/
-import * as matchers from "@testing-library/jest-dom/matchers";
-import "@testing-library/jest-dom/vitest";
-import { expect } from "vitest";
+import { handlers as configHandlers } from "./config";
+import { handlers as dagHandlers } from "./dag";
+import { handlers as dagsHandlers } from "./dags";
-// extends vitest matchers with react-testing-library's ones
-expect.extend(matchers);
+export const handlers = [...configHandlers, ...dagHandlers, ...dagsHandlers];
diff --git a/airflow/ui/src/pages/Dag/Dag.test.tsx
b/airflow/ui/src/pages/Dag/Dag.test.tsx
new file mode 100644
index 00000000000..71a0561f540
--- /dev/null
+++ b/airflow/ui/src/pages/Dag/Dag.test.tsx
@@ -0,0 +1,47 @@
+/*!
+ * 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 "@testing-library/jest-dom";
+import { render, screen, waitFor } from "@testing-library/react";
+import { setupServer, type SetupServerApi } from "msw/node";
+import { afterEach, describe, it, expect, beforeAll, afterAll } from "vitest";
+
+import { handlers } from "src/mocks/handlers";
+import { AppWrapper } from "src/utils/AppWrapper";
+
+let server: SetupServerApi;
+
+beforeAll(() => {
+ server = setupServer(...handlers);
+ server.listen({ onUnhandledRequest: "bypass" });
+});
+
+afterEach(() => server.resetHandlers());
+afterAll(() => server.close());
+
+describe("Dag Documentation Modal", () => {
+ it("Display documentation button only when docs_md is present", async () => {
+ render(<AppWrapper initialEntries={["/dags/tutorial_taskflow_api"]} />);
+
+ await waitFor(() =>
expect(screen.getByTestId("markdown-button")).toBeInTheDocument());
+ await waitFor(() => screen.getByTestId("markdown-button").click());
+ await waitFor(() =>
+ expect(screen.getByText(/taskflow api tutorial
documentation/iu)).toBeInTheDocument(),
+ );
+ });
+});
diff --git a/airflow/ui/src/pages/DagsList/DagsFilters.tsx
b/airflow/ui/src/pages/DagsList/DagsFilters.tsx
index 6128380609a..36c7ae1c919 100644
--- a/airflow/ui/src/pages/DagsList/DagsFilters.tsx
+++ b/airflow/ui/src/pages/DagsList/DagsFilters.tsx
@@ -148,13 +148,28 @@ export const DagsFilters = () => {
<QuickFilterButton isActive={isAll} onClick={handleStateChange}
value="all">
All
</QuickFilterButton>
- <QuickFilterButton isActive={isFailed} onClick={handleStateChange}
value="failed">
+ <QuickFilterButton
+ data-testid="dags-failed-filter"
+ isActive={isFailed}
+ onClick={handleStateChange}
+ value="failed"
+ >
<Status state="failed">Failed</Status>
</QuickFilterButton>
- <QuickFilterButton isActive={isRunning} onClick={handleStateChange}
value="running">
+ <QuickFilterButton
+ data-testid="dags-running-filter"
+ isActive={isRunning}
+ onClick={handleStateChange}
+ value="running"
+ >
<Status state="running">Running</Status>
</QuickFilterButton>
- <QuickFilterButton isActive={isSuccess} onClick={handleStateChange}
value="success">
+ <QuickFilterButton
+ data-testid="dags-success-filter"
+ isActive={isSuccess}
+ onClick={handleStateChange}
+ value="success"
+ >
<Status state="success">Success</Status>
</QuickFilterButton>
</HStack>
diff --git a/airflow/ui/src/pages/DagsList/DagsList.test.tsx
b/airflow/ui/src/pages/DagsList/DagsList.test.tsx
new file mode 100644
index 00000000000..39608f4a745
--- /dev/null
+++ b/airflow/ui/src/pages/DagsList/DagsList.test.tsx
@@ -0,0 +1,37 @@
+/*!
+ * 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 "@testing-library/jest-dom";
+import { render, screen, waitFor } from "@testing-library/react";
+import { describe, it, expect } from "vitest";
+
+import { AppWrapper } from "src/utils/AppWrapper";
+
+describe("Dag Filters", () => {
+ it("Filter by selected last run state", async () => {
+ render(<AppWrapper initialEntries={["/dags"]} />);
+
+ await waitFor(() =>
expect(screen.getByTestId("dags-success-filter")).toBeInTheDocument());
+ await waitFor(() => screen.getByTestId("dags-success-filter").click());
+ await waitFor(() =>
expect(screen.getByText("tutorial_taskflow_api_success")).toBeInTheDocument());
+
+ await waitFor(() =>
expect(screen.getByTestId("dags-failed-filter")).toBeInTheDocument());
+ await waitFor(() => screen.getByTestId("dags-failed-filter").click());
+ await waitFor(() =>
expect(screen.getByText("tutorial_taskflow_api_failed")).toBeInTheDocument());
+ });
+});
diff --git a/airflow/ui/src/router.tsx b/airflow/ui/src/router.tsx
index 63a0be23171..5e5f1b3a576 100644
--- a/airflow/ui/src/router.tsx
+++ b/airflow/ui/src/router.tsx
@@ -43,96 +43,93 @@ import { Pools } from "./pages/Pools";
import { Variables } from "./pages/Variables";
import { queryClient } from "./queryClient";
-export const router = createBrowserRouter(
- [
- {
- children: [
- {
- element: <Dashboard />,
- index: true,
- },
- {
- element: <DagsList />,
- path: "dags",
- },
- {
- element: <Events />,
- path: "events",
- },
- {
- element: <XCom />,
- path: "xcoms",
- },
- {
- element: <Variables />,
- path: "variables",
- },
- {
- element: <Pools />,
- path: "pools",
- },
- {
- children: [
- { element: <Overview />, index: true },
- { element: <Runs />, path: "runs" },
- { element: <Tasks />, path: "tasks" },
- { element: <Events />, path: "events" },
- { element: <Code />, path: "code" },
- ],
- element: <Dag />,
- path: "dags/:dagId",
- },
- {
- children: [
- { element: <TaskInstances />, index: true },
- { element: <Events />, path: "events" },
- { element: <Code />, path: "code" },
- { element: <DagRunDetails />, path: "details" },
- ],
- element: <Run />,
- path: "dags/:dagId/runs/:runId",
- },
- {
- children: [
- { element: <Logs />, index: true },
- { element: <Events />, path: "events" },
- { element: <XCom />, path: "xcom" },
- { element: <Code />, path: "code" },
- { element: <Details />, path: "details" },
- ],
- element: <TaskInstance />,
- path: "dags/:dagId/runs/:runId/tasks/:taskId",
- },
- {
- children: [
- { element: <Instances />, index: true },
- { element: <Events />, path: "events" },
- ],
- element: <Task />,
- path: "dags/:dagId/tasks/:taskId",
- },
- ],
- element: <BaseLayout />,
- errorElement: (
- <BaseLayout>
- <ErrorPage />
- </BaseLayout>
- ),
- // Use react router loader to ensure we have the config before any other
requests are made
- loader: async () => {
- const data = await queryClient.ensureQueryData(
- queryOptions({
- queryFn: ConfigService.getConfigs,
- queryKey: UseConfigServiceGetConfigsKeyFn(),
- }),
- );
-
- return data;
+export const routerConfig = [
+ {
+ children: [
+ {
+ element: <Dashboard />,
+ index: true,
+ },
+ {
+ element: <DagsList />,
+ path: "dags",
+ },
+ {
+ element: <Events />,
+ path: "events",
+ },
+ {
+ element: <XCom />,
+ path: "xcoms",
+ },
+ {
+ element: <Variables />,
+ path: "variables",
+ },
+ {
+ element: <Pools />,
+ path: "pools",
},
- path: "/",
+ {
+ children: [
+ { element: <Overview />, index: true },
+ { element: <Runs />, path: "runs" },
+ { element: <Tasks />, path: "tasks" },
+ { element: <Events />, path: "events" },
+ { element: <Code />, path: "code" },
+ ],
+ element: <Dag />,
+ path: "dags/:dagId",
+ },
+ {
+ children: [
+ { element: <TaskInstances />, index: true },
+ { element: <Events />, path: "events" },
+ { element: <Code />, path: "code" },
+ { element: <DagRunDetails />, path: "details" },
+ ],
+ element: <Run />,
+ path: "dags/:dagId/runs/:runId",
+ },
+ {
+ children: [
+ { element: <Logs />, index: true },
+ { element: <Events />, path: "events" },
+ { element: <XCom />, path: "xcom" },
+ { element: <Code />, path: "code" },
+ { element: <Details />, path: "details" },
+ ],
+ element: <TaskInstance />,
+ path: "dags/:dagId/runs/:runId/tasks/:taskId",
+ },
+ {
+ children: [
+ { element: <Instances />, index: true },
+ { element: <Events />, path: "events" },
+ ],
+ element: <Task />,
+ path: "dags/:dagId/tasks/:taskId",
+ },
+ ],
+ element: <BaseLayout />,
+ errorElement: (
+ <BaseLayout>
+ <ErrorPage />
+ </BaseLayout>
+ ),
+ // Use react router loader to ensure we have the config before any other
requests are made
+ loader: async () => {
+ const data = await queryClient.ensureQueryData(
+ queryOptions({
+ queryFn: ConfigService.getConfigs,
+ queryKey: UseConfigServiceGetConfigsKeyFn(),
+ }),
+ );
+
+ return data;
},
- ],
- {
- basename: "/webapp",
+ path: "/",
},
-);
+];
+
+export const router = createBrowserRouter(routerConfig, { basename: "/webapp"
});
diff --git a/airflow/ui/testsSetup.ts b/airflow/ui/src/utils/AppWrapper.tsx
similarity index 58%
copy from airflow/ui/testsSetup.ts
copy to airflow/ui/src/utils/AppWrapper.tsx
index 042cf57e630..5e5e1c01aa8 100644
--- a/airflow/ui/testsSetup.ts
+++ b/airflow/ui/src/utils/AppWrapper.tsx
@@ -16,9 +16,24 @@
* specific language governing permissions and limitations
* under the License.
*/
-import * as matchers from "@testing-library/jest-dom/matchers";
-import "@testing-library/jest-dom/vitest";
-import { expect } from "vitest";
+import { RouterProvider, createMemoryRouter } from "react-router-dom";
-// extends vitest matchers with react-testing-library's ones
-expect.extend(matchers);
+import { TimezoneProvider } from "src/context/timezone";
+import { routerConfig } from "src/router";
+import { BaseWrapper } from "src/utils/Wrapper";
+
+type Props = {
+ readonly initialEntries: Array<string>;
+};
+
+export const AppWrapper = ({ initialEntries }: Props) => {
+ const router = createMemoryRouter(routerConfig, { basename: "/",
initialEntries });
+
+ return (
+ <BaseWrapper>
+ <TimezoneProvider>
+ <RouterProvider router={router} />
+ </TimezoneProvider>
+ </BaseWrapper>
+ );
+};
diff --git a/airflow/ui/src/utils/Wrapper.tsx b/airflow/ui/src/utils/Wrapper.tsx
index 9f3ec308bfb..88f4ecb176e 100644
--- a/airflow/ui/src/utils/Wrapper.tsx
+++ b/airflow/ui/src/utils/Wrapper.tsx
@@ -23,7 +23,7 @@ import { MemoryRouter } from "react-router-dom";
import { TimezoneProvider } from "src/context/timezone";
-export const Wrapper = ({ children }: PropsWithChildren) => {
+export const BaseWrapper = ({ children }: PropsWithChildren) => {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
@@ -34,11 +34,15 @@ export const Wrapper = ({ children }: PropsWithChildren) =>
{
return (
<ChakraProvider value={defaultSystem}>
- <QueryClientProvider client={queryClient}>
- <MemoryRouter>
- <TimezoneProvider>{children}</TimezoneProvider>
- </MemoryRouter>
- </QueryClientProvider>
+ <QueryClientProvider
client={queryClient}>{children}</QueryClientProvider>
</ChakraProvider>
);
};
+
+export const Wrapper = ({ children }: PropsWithChildren) => (
+ <BaseWrapper>
+ <MemoryRouter>
+ <TimezoneProvider>{children}</TimezoneProvider>
+ </MemoryRouter>
+ </BaseWrapper>
+);
diff --git a/airflow/ui/testsSetup.ts b/airflow/ui/testsSetup.ts
index 042cf57e630..24fd9a44ad0 100644
--- a/airflow/ui/testsSetup.ts
+++ b/airflow/ui/testsSetup.ts
@@ -18,7 +18,21 @@
*/
import * as matchers from "@testing-library/jest-dom/matchers";
import "@testing-library/jest-dom/vitest";
-import { expect } from "vitest";
+import type { HttpHandler } from "msw";
+import { setupServer, type SetupServerApi } from "msw/node";
+import { afterEach, expect, beforeAll, afterAll } from "vitest";
+
+import { handlers } from "src/mocks/handlers";
+
+let server: SetupServerApi;
// extends vitest matchers with react-testing-library's ones
expect.extend(matchers);
+
+beforeAll(() => {
+ server = setupServer(...(handlers as Array<HttpHandler>));
+ server.listen({ onUnhandledRequest: "bypass" });
+});
+
+afterEach(() => server.resetHandlers());
+afterAll(() => server.close());