This is an automated email from the ASF dual-hosted git repository.
guanmingchiu pushed a commit to branch v3-1-test
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/v3-1-test by this push:
new 4e0c966be72 [v3-1-test] Add data-testid attributes to root UI
components for testing (#62182) (#62237)
4e0c966be72 is described below
commit 4e0c966be72f5f1f623d04b45c4ecd574ee74e3f
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Sat Feb 21 10:46:15 2026 +0800
[v3-1-test] Add data-testid attributes to root UI components for testing
(#62182) (#62237)
* Add data-testid attributes to root UI components for testing
Enhance testability by adding data-testid attributes to React components in
airflow-core/src/airflow/ui/src/components/:
- ErrorAlert (error-alert)
- BasicTooltip (basic-tooltip)
- StatsCard (stats-card)
- QuickFilterButton (quick-filter-button)
- HeaderCard (header-card)
- DAGWarningsModal (dag-warnings-modal)
- BreadcrumbStats (breadcrumb-stats)
- Stat (stat)
- DateTimeInput (datetime-input)
- NeedsReviewBadge (needs-review-badge)
- ConfigForm (config-form)
- LimitedItemsList (limited-items-list, limited-items-expand-button)
- DagVersion (dag-version)
- DagVersionDetails (dag-version-details)
These attributes enable reliable E2E testing selectors while maintaining
clean component interfaces.
Related: #43381
* Update ConfigForm.tsx
the unnecessary comment has been removed.
* static error check fix
(cherry picked from commit ef5608204c8d039f2ef30f6d78617c0db26ac94c)
Co-authored-by: Boubacar Ba <[email protected]>
---
airflow-core/src/airflow/ui/src/components/BasicTooltip.tsx | 1 +
airflow-core/src/airflow/ui/src/components/BreadcrumbStats.tsx | 2 +-
airflow-core/src/airflow/ui/src/components/ConfigForm.tsx | 1 +
airflow-core/src/airflow/ui/src/components/DagVersion.tsx | 4 +++-
airflow-core/src/airflow/ui/src/components/DagVersionDetails.tsx | 2 +-
airflow-core/src/airflow/ui/src/components/DateTimeInput.tsx | 1 +
airflow-core/src/airflow/ui/src/components/ErrorAlert.tsx | 2 +-
airflow-core/src/airflow/ui/src/components/HeaderCard.tsx | 2 +-
airflow-core/src/airflow/ui/src/components/LimitedItemsList.tsx | 3 ++-
airflow-core/src/airflow/ui/src/components/NeedsReviewBadge.tsx | 5 ++++-
airflow-core/src/airflow/ui/src/components/QuickFilterButton.tsx | 1 +
airflow-core/src/airflow/ui/src/components/Stat.tsx | 2 +-
airflow-core/src/airflow/ui/src/components/StatsCard.tsx | 1 +
.../src/airflow/ui/src/components/ui/DagWarningsModal.tsx | 8 +++++++-
14 files changed, 26 insertions(+), 9 deletions(-)
diff --git a/airflow-core/src/airflow/ui/src/components/BasicTooltip.tsx
b/airflow-core/src/airflow/ui/src/components/BasicTooltip.tsx
index 96400e5d5f0..8b071281a56 100644
--- a/airflow-core/src/airflow/ui/src/components/BasicTooltip.tsx
+++ b/airflow-core/src/airflow/ui/src/components/BasicTooltip.tsx
@@ -95,6 +95,7 @@ export const BasicTooltip = ({ children, content }: Props):
ReactElement => {
borderRadius="md"
boxShadow="md"
color="fg.inverted"
+ data-testid="basic-tooltip"
fontSize="sm"
left={`${rect.left + scrollX + rect.width / 2}px`}
paddingX="3"
diff --git a/airflow-core/src/airflow/ui/src/components/BreadcrumbStats.tsx
b/airflow-core/src/airflow/ui/src/components/BreadcrumbStats.tsx
index d6fa2066709..9cb068b666b 100644
--- a/airflow-core/src/airflow/ui/src/components/BreadcrumbStats.tsx
+++ b/airflow-core/src/airflow/ui/src/components/BreadcrumbStats.tsx
@@ -26,7 +26,7 @@ import { Breadcrumb } from "src/components/ui";
type Links = Array<{ label: ReactNode | string; labelExtra?: ReactNode;
title?: string; value?: string }>;
export const BreadcrumbStats = ({ links }: { readonly links: Links }) => (
- <Breadcrumb.Root separator={<LiaSlashSolid />}>
+ <Breadcrumb.Root data-testid="breadcrumb-stats" separator={<LiaSlashSolid
/>}>
{links.map((link, index) => (
// eslint-disable-next-line react/no-array-index-key
<Stat.Root gap={0} key={`${link.title}-${index}`}>
diff --git a/airflow-core/src/airflow/ui/src/components/ConfigForm.tsx
b/airflow-core/src/airflow/ui/src/components/ConfigForm.tsx
index 791ffd30ac9..52f8c279440 100644
--- a/airflow-core/src/airflow/ui/src/components/ConfigForm.tsx
+++ b/airflow-core/src/airflow/ui/src/components/ConfigForm.tsx
@@ -82,6 +82,7 @@ const ConfigForm = <T extends FieldValues = FieldValues>({
return (
<Accordion.Root
collapsible
+ data-testid="config-form"
defaultValue={[flexibleFormDefaultSection]}
mb={4}
overflow="visible"
diff --git a/airflow-core/src/airflow/ui/src/components/DagVersion.tsx
b/airflow-core/src/airflow/ui/src/components/DagVersion.tsx
index 2c65c3c09eb..3993dd4a419 100644
--- a/airflow-core/src/airflow/ui/src/components/DagVersion.tsx
+++ b/airflow-core/src/airflow/ui/src/components/DagVersion.tsx
@@ -33,7 +33,9 @@ export const DagVersion = ({ version }: { readonly version:
DagVersionResponse |
return (
<Tooltip content={<Time datetime={version.created_at} />}>
- <Text as="span">{translate("versionSelect.versionCode", { versionCode:
version.version_number })}</Text>
+ <Text as="span" data-testid="dag-version">
+ {translate("versionSelect.versionCode", { versionCode:
version.version_number })}
+ </Text>
</Tooltip>
);
};
diff --git a/airflow-core/src/airflow/ui/src/components/DagVersionDetails.tsx
b/airflow-core/src/airflow/ui/src/components/DagVersionDetails.tsx
index 00e8de73de2..e1917288dc6 100644
--- a/airflow-core/src/airflow/ui/src/components/DagVersionDetails.tsx
+++ b/airflow-core/src/airflow/ui/src/components/DagVersionDetails.tsx
@@ -30,7 +30,7 @@ export const DagVersionDetails = ({ dagVersion }: { readonly
dagVersion?: DagVer
}
return (
- <Table.Root striped>
+ <Table.Root data-testid="dag-version-details" striped>
<Table.Body>
<Table.Row>
<Table.Cell>{translate("versionDetails.versionId")}</Table.Cell>
diff --git a/airflow-core/src/airflow/ui/src/components/DateTimeInput.tsx
b/airflow-core/src/airflow/ui/src/components/DateTimeInput.tsx
index cd7bd6ca8c7..60fdf807916 100644
--- a/airflow-core/src/airflow/ui/src/components/DateTimeInput.tsx
+++ b/airflow-core/src/airflow/ui/src/components/DateTimeInput.tsx
@@ -41,6 +41,7 @@ export const DateTimeInput = forwardRef<HTMLInputElement,
Props>(({ onChange, va
return (
<Input
+ data-testid="datetime-input"
onChange={(event) =>
onChange?.({
...event,
diff --git a/airflow-core/src/airflow/ui/src/components/ErrorAlert.tsx
b/airflow-core/src/airflow/ui/src/components/ErrorAlert.tsx
index 434bbfda23e..932eae708b3 100644
--- a/airflow-core/src/airflow/ui/src/components/ErrorAlert.tsx
+++ b/airflow-core/src/airflow/ui/src/components/ErrorAlert.tsx
@@ -51,7 +51,7 @@ export const ErrorAlert = ({ error: err }: Props) => {
}
return (
- <Alert status="error">
+ <Alert data-testid="error-alert" status="error">
<HStack align="start" flexDirection="column" gap={2} mt={-1}>
{error.status} {error.message}
{detailMessage === error.message ? undefined : (
diff --git a/airflow-core/src/airflow/ui/src/components/HeaderCard.tsx
b/airflow-core/src/airflow/ui/src/components/HeaderCard.tsx
index 1899e1f8564..bc08d42b59d 100644
--- a/airflow-core/src/airflow/ui/src/components/HeaderCard.tsx
+++ b/airflow-core/src/airflow/ui/src/components/HeaderCard.tsx
@@ -37,7 +37,7 @@ export const HeaderCard = ({ actions, icon, state, stats,
subTitle, title }: Pro
const { t: translate } = useTranslation();
return (
- <Box borderColor="border.emphasized" borderRadius={8} borderWidth={1}
p={2}>
+ <Box borderColor="border.emphasized" borderRadius={8} borderWidth={1}
data-testid="header-card" p={2}>
<Flex alignItems="center" flexWrap="wrap" justifyContent="space-between"
mb={2}>
<Flex alignItems="center" flexWrap="wrap" gap={2}>
<Heading size="xl">{icon}</Heading>
diff --git a/airflow-core/src/airflow/ui/src/components/LimitedItemsList.tsx
b/airflow-core/src/airflow/ui/src/components/LimitedItemsList.tsx
index 5c37909d6c7..c23236cf336 100644
--- a/airflow-core/src/airflow/ui/src/components/LimitedItemsList.tsx
+++ b/airflow-core/src/airflow/ui/src/components/LimitedItemsList.tsx
@@ -47,7 +47,7 @@ export const LimitedItemsList = ({
}
return (
- <HStack align="center" gap={1}>
+ <HStack align="center" data-testid="limited-items-list" gap={1}>
{icon}
<Box fontSize="sm">
{displayItems.map((item, index) => (
@@ -69,6 +69,7 @@ export const LimitedItemsList = ({
<Button
colorPalette="brand"
cursor="pointer"
+ data-testid="limited-items-expand-button"
fontSize="sm"
minH="auto"
px={1}
diff --git a/airflow-core/src/airflow/ui/src/components/NeedsReviewBadge.tsx
b/airflow-core/src/airflow/ui/src/components/NeedsReviewBadge.tsx
index 5b7bd3f3899..7ab09137629 100644
--- a/airflow-core/src/airflow/ui/src/components/NeedsReviewBadge.tsx
+++ b/airflow-core/src/airflow/ui/src/components/NeedsReviewBadge.tsx
@@ -39,7 +39,10 @@ export const NeedsReviewBadge = ({ dagId, pendingActions }:
Props) => {
return (
<Tooltip content={translate("requiredActionCount", { count:
pendingActions.length })}>
- <RouterLink
to={`/dags/${dagId}/required_actions?${SearchParamsKeys.RESPONSE_RECEIVED}=false`}>
+ <RouterLink
+ data-testid="needs-review-badge"
+
to={`/dags/${dagId}/required_actions?${SearchParamsKeys.RESPONSE_RECEIVED}=false`}
+ >
<StateBadge colorPalette="deferred" fontSize="md" variant="solid">
<LuUserRoundPen />
{pendingActions.length}
diff --git a/airflow-core/src/airflow/ui/src/components/QuickFilterButton.tsx
b/airflow-core/src/airflow/ui/src/components/QuickFilterButton.tsx
index 4450e48e062..4fa8b855eda 100644
--- a/airflow-core/src/airflow/ui/src/components/QuickFilterButton.tsx
+++ b/airflow-core/src/airflow/ui/src/components/QuickFilterButton.tsx
@@ -30,6 +30,7 @@ export const QuickFilterButton = ({ children, isActive,
...rest }: QuickFilterBu
borderRadius={20}
borderWidth={1}
color="colorPalette.fg"
+ data-testid="quick-filter-button"
fontWeight="normal"
size="sm"
variant={isActive ? "solid" : "outline"}
diff --git a/airflow-core/src/airflow/ui/src/components/Stat.tsx
b/airflow-core/src/airflow/ui/src/components/Stat.tsx
index 7dec55d8e13..27506dbae27 100644
--- a/airflow-core/src/airflow/ui/src/components/Stat.tsx
+++ b/airflow-core/src/airflow/ui/src/components/Stat.tsx
@@ -24,7 +24,7 @@ type Props = {
} & StackProps;
export const Stat = ({ children, label, ...rest }: Props) => (
- <VStack align="flex-start" gap={1} {...rest}>
+ <VStack align="flex-start" data-testid="stat" gap={1} {...rest}>
<Heading color="fg.muted" fontSize="xs" lineHeight="1.25rem">
{label}
</Heading>
diff --git a/airflow-core/src/airflow/ui/src/components/StatsCard.tsx
b/airflow-core/src/airflow/ui/src/components/StatsCard.tsx
index cbade7d249d..12e75186f54 100644
--- a/airflow-core/src/airflow/ui/src/components/StatsCard.tsx
+++ b/airflow-core/src/airflow/ui/src/components/StatsCard.tsx
@@ -55,6 +55,7 @@ export const StatsCard = ({
borderWidth={1}
color="fg.emphasized"
cursor="pointer"
+ data-testid="stats-card"
p={2}
>
<StateBadge colorPalette={colorScheme} mr={2} state={state}>
diff --git a/airflow-core/src/airflow/ui/src/components/ui/DagWarningsModal.tsx
b/airflow-core/src/airflow/ui/src/components/ui/DagWarningsModal.tsx
index fd447b8e822..407cb368512 100644
--- a/airflow-core/src/airflow/ui/src/components/ui/DagWarningsModal.tsx
+++ b/airflow-core/src/airflow/ui/src/components/ui/DagWarningsModal.tsx
@@ -44,7 +44,13 @@ export const DAGWarningsModal:
React.FC<ImportDAGErrorModalProps> = ({ error, on
: "";
return (
- <Dialog.Root onOpenChange={onClose} open={open} scrollBehavior="inside"
size="xl">
+ <Dialog.Root
+ data-testid="dag-warnings-modal"
+ onOpenChange={onClose}
+ open={open}
+ scrollBehavior="inside"
+ size="xl"
+ >
<Dialog.Content backdrop>
<Dialog.Header>
<HStack fontSize="xl">