Merge pull request #11513 from marshmalien/10241-test-locator

Add test locators to OUIA-compliant components
This commit is contained in:
Sarah Akus
2022-01-10 13:10:08 -05:00
committed by GitHub
125 changed files with 682 additions and 138 deletions

View File

@@ -128,6 +128,7 @@ function AdHocCommands({
component="button" component="button"
aria-label={t`Run Command`} aria-label={t`Run Command`}
onClick={() => setIsWizardOpen(true)} onClick={() => setIsWizardOpen(true)}
ouiaId="run-command-dropdown-item"
> >
{t`Run Command`} {t`Run Command`}
</DropdownItem> </DropdownItem>

View File

@@ -207,6 +207,7 @@ function AdHocDetailsStep({ verbosityOptions, moduleOptions }) {
onChange={() => { onChange={() => {
diffModeHelpers.setValue(!diffModeField.value); diffModeHelpers.setValue(!diffModeField.value);
}} }}
ouiaId="diff-mode-switch"
aria-label={t`toggle changes`} aria-label={t`toggle changes`}
/> />
</FormGroup> </FormGroup>
@@ -236,6 +237,7 @@ function AdHocDetailsStep({ verbosityOptions, moduleOptions }) {
</span> </span>
} }
id="become_enabled" id="become_enabled"
ouiaId="become_enabled"
isChecked={becomeEnabledField.value} isChecked={becomeEnabledField.value}
onChange={(checked) => { onChange={(checked) => {
becomeEnabledHelpers.setValue(checked); becomeEnabledHelpers.setValue(checked);

View File

@@ -42,6 +42,7 @@ function AddDropDownButton({ dropdownItems, ouiaId }) {
/> />
} }
dropdownItems={dropdownItems} dropdownItems={dropdownItems}
ouiaId="add-dropdown"
/> />
</div> </div>
); );

View File

@@ -26,6 +26,7 @@ function CheckboxCard(props) {
onChange={onSelect} onChange={onSelect}
aria-label={name} aria-label={name}
id={`checkbox-card-${itemId}`} id={`checkbox-card-${itemId}`}
ouiaId={`checkbox-card-${itemId}`}
label={ label={
<> <>
<div style={{ fontWeight: 'bold' }}>{name}</div> <div style={{ fontWeight: 'bold' }}>{name}</div>

View File

@@ -77,6 +77,7 @@ function AlertModal({
isOpen={Boolean(isOpen)} isOpen={Boolean(isOpen)}
variant="small" variant="small"
title={title} title={title}
ouiaId="alert-modal"
{...props} {...props}
> >
{children} {children}

View File

@@ -31,6 +31,7 @@ function AnsibleSelect({
return ( return (
<FormSelect <FormSelect
id={id} id={id}
ouiaId={id}
value={value} value={value}
onChange={onSelectChange} onChange={onSelectChange}
onBlur={onBlur} onBlur={onBlur}

View File

@@ -91,7 +91,11 @@ function AppContainer({ navRouteConfig = [], children }) {
<PageSidebar <PageSidebar
theme="dark" theme="dark"
nav={ nav={
<Nav aria-label={t`Navigation`} theme="dark"> <Nav
aria-label={t`Navigation`}
theme="dark"
ouiaId="sidebar-navigation"
>
<NavList> <NavList>
{navRouteConfig.map(({ groupId, groupTitle, routes }) => ( {navRouteConfig.map(({ groupId, groupTitle, routes }) => (
<NavExpandableGroup <NavExpandableGroup

View File

@@ -20,7 +20,12 @@ function NavExpandableGroup(props) {
if (routes.length === 1 && groupId === 'settings') { if (routes.length === 1 && groupId === 'settings') {
const [{ path }] = routes; const [{ path }] = routes;
return ( return (
<NavItem itemId={groupId} isActive={isActivePath(path)} key={path}> <NavItem
itemId={groupId}
isActive={isActivePath(path)}
key={path}
// ouiaId={path}
>
<Link to={path}>{groupTitle}</Link> <Link to={path}>{groupTitle}</Link>
</NavItem> </NavItem>
); );
@@ -31,10 +36,16 @@ function NavExpandableGroup(props) {
isActive={isActive} isActive={isActive}
isExpanded isExpanded
groupId={groupId} groupId={groupId}
ouiaId={groupId}
title={groupTitle} title={groupTitle}
> >
{routes.map(({ path, title }) => ( {routes.map(({ path, title }) => (
<NavItem groupId={groupId} isActive={isActivePath(path)} key={path}> <NavItem
groupId={groupId}
isActive={isActivePath(path)}
key={path}
// ouiaId={path}
>
<Link to={path}>{title}</Link> <Link to={path}>{title}</Link>
</NavItem> </NavItem>
))} ))}

View File

@@ -101,8 +101,13 @@ function PageHeaderToolbar({
isOpen={isHelpOpen} isOpen={isHelpOpen}
position={DropdownPosition.right} position={DropdownPosition.right}
onSelect={handleHelpSelect} onSelect={handleHelpSelect}
ouiaId="toolbar-info-dropdown"
toggle={ toggle={
<DropdownToggle onToggle={setIsHelpOpen} aria-label={t`Info`}> <DropdownToggle
onToggle={setIsHelpOpen}
aria-label={t`Info`}
ouiaId="toolbar-info-dropdown-toggle"
>
<QuestionCircleIcon /> <QuestionCircleIcon />
</DropdownToggle> </DropdownToggle>
} }
@@ -111,6 +116,7 @@ function PageHeaderToolbar({
key="help" key="help"
target="_blank" target="_blank"
href={`${getDocsBaseUrl(config)}/html/userguide/index.html`} href={`${getDocsBaseUrl(config)}/html/userguide/index.html`}
ouiaId="help-dropdown-item"
> >
{t`Help`} {t`Help`}
</DropdownItem>, </DropdownItem>,
@@ -119,6 +125,7 @@ function PageHeaderToolbar({
component="button" component="button"
isDisabled={isAboutDisabled} isDisabled={isAboutDisabled}
onClick={onAboutClick} onClick={onAboutClick}
ouiaId="about-dropdown-item"
> >
{t`About`} {t`About`}
</DropdownItem>, </DropdownItem>,
@@ -128,12 +135,16 @@ function PageHeaderToolbar({
<PageHeaderToolsItem> <PageHeaderToolsItem>
<Dropdown <Dropdown
id="toolbar-user-dropdown" id="toolbar-user-dropdown"
ouiaId="toolbar-user-dropdown"
isPlain isPlain
isOpen={isUserOpen} isOpen={isUserOpen}
position={DropdownPosition.right} position={DropdownPosition.right}
onSelect={handleUserSelect} onSelect={handleUserSelect}
toggle={ toggle={
<DropdownToggle onToggle={setIsUserOpen}> <DropdownToggle
onToggle={setIsUserOpen}
ouiaId="toolbar-user-dropdown-toggle"
>
<UserIcon /> <UserIcon />
{loggedInUser && ( {loggedInUser && (
<span style={{ marginLeft: '10px' }}> <span style={{ marginLeft: '10px' }}>
@@ -149,6 +160,7 @@ function PageHeaderToolbar({
href={ href={
loggedInUser ? `#/users/${loggedInUser.id}/details` : '#/home' loggedInUser ? `#/users/${loggedInUser.id}/details` : '#/home'
} }
ouiaId="user-dropdown-item"
> >
{t`User Details`} {t`User Details`}
</DropdownItem>, </DropdownItem>,
@@ -157,6 +169,7 @@ function PageHeaderToolbar({
component="button" component="button"
onClick={onLogoutClick} onClick={onLogoutClick}
id="logout-button" id="logout-button"
ouiaId="logout-dropdown-item"
> >
{t`Logout`} {t`Logout`}
</DropdownItem>, </DropdownItem>,

View File

@@ -44,12 +44,21 @@ const CheckboxListItem = ({
{columns?.length > 0 ? ( {columns?.length > 0 ? (
columns.map((col) => ( columns.map((col) => (
<Td aria-label={col.name} dataLabel={col.key} key={col.key}> <Td
aria-label={col.name}
data-cy={`item-${itemId}-${col.name}`}
dataLabel={col.key}
key={col.key}
>
{item[col.key]} {item[col.key]}
</Td> </Td>
)) ))
) : ( ) : (
<Td aria-labelledby={itemId} dataLabel={label}> <Td
aria-labelledby={itemId}
data-cy={`item-${itemId}`}
dataLabel={label}
>
<b>{label}</b> <b>{label}</b>
</Td> </Td>
)} )}

View File

@@ -109,6 +109,7 @@ function VariablesDetail({
<Modal <Modal
variant="xlarge" variant="xlarge"
title={label} title={label}
ouiaId={`${dataCy}-modal`}
isOpen={isExpanded} isOpen={isExpanded}
onClose={() => setIsExpanded(false)} onClose={() => setIsExpanded(false)}
actions={[ actions={[

View File

@@ -131,6 +131,7 @@ function VariablesField({
<Modal <Modal
variant="xlarge" variant="xlarge"
title={label} title={label}
ouiaId={`${id}-modal`}
isOpen={isExpanded} isOpen={isExpanded}
onClose={() => setIsExpanded(false)} onClose={() => setIsExpanded(false)}
actions={[ actions={[
@@ -214,7 +215,7 @@ function VariablesFieldInternals({
return ( return (
<div className="pf-c-form__group"> <div className="pf-c-form__group">
<FieldHeader> <FieldHeader data-cy={`${id}-label`}>
<Split hasGutter> <Split hasGutter>
<SplitItem> <SplitItem>
<label htmlFor={id} className="pf-c-form__label"> <label htmlFor={id} className="pf-c-form__label">
@@ -246,7 +247,7 @@ function VariablesFieldInternals({
variant="plain" variant="plain"
aria-label={t`Expand input`} aria-label={t`Expand input`}
onClick={onExpand} onClick={onExpand}
ouiaId={`${id}-variables-expand`} ouiaId={`${id}-expand`}
> >
<ExpandArrowsAltIcon /> <ExpandArrowsAltIcon />
</Button> </Button>

View File

@@ -80,6 +80,7 @@ function DataListToolbar({
return ( return (
<Toolbar <Toolbar
id={`${qsConfig.namespace}-list-toolbar`} id={`${qsConfig.namespace}-list-toolbar`}
ouiaId={`${qsConfig.namespace}-list-toolbar`}
clearAllFilters={clearAllFilters} clearAllFilters={clearAllFilters}
collapseListedFiltersBreakpoint="lg" collapseListedFiltersBreakpoint="lg"
clearFiltersButtonText={Boolean(search) && t`Clear all filters`} clearFiltersButtonText={Boolean(search) && t`Clear all filters`}
@@ -113,6 +114,7 @@ function DataListToolbar({
onChange={onSelectAll} onChange={onSelectAll}
aria-label={t`Select all`} aria-label={t`Select all`}
id="select-all" id="select-all"
ouiaId="select-all"
/> />
</ToolbarItem> </ToolbarItem>
</ToolbarGroup> </ToolbarGroup>
@@ -177,6 +179,7 @@ function DataListToolbar({
position={dropdownPosition} position={dropdownPosition}
isPlain isPlain
dropdownItems={additionalControls} dropdownItems={additionalControls}
ouiaId="actions-dropdown"
/> />
</KebabifiedProvider> </KebabifiedProvider>
</ToolbarItem> </ToolbarItem>

View File

@@ -27,7 +27,7 @@ function FieldWithPrompt({
isDisabled, isDisabled,
}) { }) {
return ( return (
<div className="pf-c-form__group"> <div className="pf-c-form__group" data-cy={`${fieldId}-form-group`}>
<FieldHeader> <FieldHeader>
<div> <div>
<label className="pf-c-form__label" htmlFor={fieldId}> <label className="pf-c-form__label" htmlFor={fieldId}>
@@ -45,6 +45,7 @@ function FieldWithPrompt({
id={promptId} id={promptId}
label={t`Prompt on launch`} label={t`Prompt on launch`}
name={promptName} name={promptName}
ouiaId={`${promptId}-checkbox`}
/> />
</FieldHeader> </FieldHeader>
{children} {children}

View File

@@ -18,6 +18,7 @@ function CheckboxField({
<Checkbox <Checkbox
isDisabled={isDisabled} isDisabled={isDisabled}
aria-label={label} aria-label={label}
ouiaId={id}
label={ label={
<span> <span>
{label} {label}

View File

@@ -26,6 +26,7 @@ function FormField(props) {
{(type === 'textarea' && ( {(type === 'textarea' && (
<FormGroup <FormGroup
fieldId={id} fieldId={id}
data-cy={`${id}-form-group`}
helperText={helperText} helperText={helperText}
helperTextInvalid={meta.error} helperTextInvalid={meta.error}
isRequired={isRequired} isRequired={isRequired}
@@ -48,6 +49,7 @@ function FormField(props) {
)) || ( )) || (
<FormGroup <FormGroup
fieldId={id} fieldId={id}
data-cy={`${id}-form-group`}
helperText={helperText} helperText={helperText}
helperTextInvalid={meta.error} helperTextInvalid={meta.error}
isRequired={isRequired} isRequired={isRequired}

View File

@@ -27,6 +27,7 @@ function FormSubmitError({ error }) {
<Alert <Alert
variant="danger" variant="danger"
isInline isInline
ouiaId="form-submit-error-alert"
title={ title={
Array.isArray(errorMessage) Array.isArray(errorMessage)
? errorMessage.map((msg) => <div key={msg}>{msg}</div>) ? errorMessage.map((msg) => <div key={msg}>{msg}</div>)

View File

@@ -66,6 +66,7 @@ function HostToggle({
!host.summary_fields.user_capabilities.edit !host.summary_fields.user_capabilities.edit
} }
onChange={toggleHost} onChange={toggleHost}
ouiaId={`host-${host.id}-toggle`}
aria-label={t`Toggle host`} aria-label={t`Toggle host`}
/> />
</Tooltip> </Tooltip>

View File

@@ -57,6 +57,7 @@ function InstanceToggle({ className, fetchInstances, instance, onToggle }) {
isChecked={isEnabled} isChecked={isEnabled}
isDisabled={isLoading || !me?.is_superuser} isDisabled={isLoading || !me?.is_superuser}
onChange={toggleInstance} onChange={toggleInstance}
ouiaId={`host-${instance.id}-toggle`}
aria-label={t`Toggle instance`} aria-label={t`Toggle instance`}
/> />
</Tooltip> </Tooltip>

View File

@@ -115,6 +115,7 @@ function JobListCancelButton({ jobsToCancel, onCancel }) {
component="button" component="button"
aria-labelledby="jobs-list-cancel-button" aria-labelledby="jobs-list-cancel-button"
onClick={toggleModal} onClick={toggleModal}
ouiaId="cancel-job-dropdown-item"
> >
{cancelJobText} {cancelJobText}
</DropdownItem> </DropdownItem>

View File

@@ -60,7 +60,7 @@ function JobListItem({
return ( return (
<> <>
<Tr id={`job-row-${job.id}`}> <Tr id={`job-row-${job.id}`} ouiaId={`job-row-${job.id}`}>
<Td <Td
expand={{ expand={{
rowIndex: job.id, rowIndex: job.id,
@@ -147,7 +147,11 @@ function JobListItem({
</ActionItem> </ActionItem>
</ActionsTd> </ActionsTd>
</Tr> </Tr>
<Tr isExpanded={isExpanded} id={`expanded-job-row-${job.id}`}> <Tr
isExpanded={isExpanded}
id={`expanded-job-row-${job.id}`}
ouiaId={`expanded-job-row-${job.id}`}
>
<Td colSpan={2} /> <Td colSpan={2} />
<Td colSpan={showTypeColumn ? 6 : 5}> <Td colSpan={showTypeColumn ? 6 : 5}>
<ExpandableRowContent> <ExpandableRowContent>
@@ -235,10 +239,20 @@ function JobListItem({
<Detail <Detail
fullWidth fullWidth
label={t`Credentials`} label={t`Credentials`}
dataCy={`job-${job.id}-credentials`}
value={ value={
<ChipGroup numChips={5} totalChips={credentials.length}> <ChipGroup
numChips={5}
totalChips={credentials.length}
ouiaId={`job-${job.id}-credential-chips`}
>
{credentials.map((c) => ( {credentials.map((c) => (
<CredentialChip key={c.id} credential={c} isReadOnly /> <CredentialChip
credential={c}
isReadOnly
key={c.id}
ouiaId={`credential-${c.id}-chip`}
/>
))} ))}
</ChipGroup> </ChipGroup>
} }
@@ -249,9 +263,17 @@ function JobListItem({
fullWidth fullWidth
label={t`Labels`} label={t`Labels`}
value={ value={
<ChipGroup numChips={5} totalChips={labels.results.length}> <ChipGroup
numChips={5}
totalChips={labels.results.length}
ouiaId={`job-${job.id}-label-chips`}
>
{labels.results.map((l) => ( {labels.results.map((l) => (
<Chip key={l.id} isReadOnly> <Chip
key={l.id}
isReadOnly
ouiaId={`label-${l.id}-chip`}
>
{l.name} {l.name}
</Chip> </Chip>
))} ))}

View File

@@ -77,6 +77,7 @@ function ReLaunchDropDown({
aria-label={t`relaunch jobs`} aria-label={t`relaunch jobs`}
id={id} id={id}
isPrimary isPrimary
ouiaId="relaunch-job-toggle"
> >
{t`Relaunch`} {t`Relaunch`}
</DropdownToggle> </DropdownToggle>
@@ -98,6 +99,7 @@ function ReLaunchDropDown({
onToggle={onToggle} onToggle={onToggle}
aria-label={t`relaunch jobs`} aria-label={t`relaunch jobs`}
id={id} id={id}
ouiaId="relaunch-job-toggle"
> >
<RocketIcon /> <RocketIcon />
</DropdownToggle> </DropdownToggle>

View File

@@ -127,6 +127,7 @@ function CredentialsStep({
onClick={() => removeItem(item)} onClick={() => removeItem(item)}
isReadOnly={!canDelete} isReadOnly={!canDelete}
credential={item} credential={item}
ouiaId={`credential-chip-${item.id}`}
/> />
); );

View File

@@ -186,6 +186,7 @@ function ShowChangesToggle() {
labelOff={t`Off`} labelOff={t`Off`}
isChecked={field.value} isChecked={field.value}
onChange={helpers.setValue} onChange={helpers.setValue}
ouiaId="prompt-show-changes"
/> />
</FormGroup> </FormGroup>
); );

View File

@@ -96,6 +96,7 @@ function ListHeader(props) {
id={`${qsConfig.namespace}-list-toolbar`} id={`${qsConfig.namespace}-list-toolbar`}
clearAllFilters={handleRemoveAll} clearAllFilters={handleRemoveAll}
collapseListedFiltersBreakpoint="lg" collapseListedFiltersBreakpoint="lg"
ouiaId={`${qsConfig.namespace}-list-toolbar`}
> >
<ToolbarContent> <ToolbarContent>
<EmptyStateControlsWrapper> <EmptyStateControlsWrapper>

View File

@@ -275,6 +275,7 @@ function HostFilterLookup({
key={name} key={name}
numChips={5} numChips={5}
totalChips={chips[key]?.chips?.length || 0} totalChips={chips[key]?.chips?.length || 0}
ouiaId="host-filter-search-chips"
> >
{chips[key]?.chips?.map((chip) => ( {chips[key]?.chips?.map((chip) => (
<Chip key={chip.key} isReadOnly> <Chip key={chip.key} isReadOnly>
@@ -296,6 +297,7 @@ function HostFilterLookup({
key={chips[leftoverKey].key} key={chips[leftoverKey].key}
numChips={5} numChips={5}
totalChips={chips[leftoverKey]?.chips?.length || 0} totalChips={chips[leftoverKey]?.chips?.length || 0}
ouiaId="host-filter-advanced-search-chips"
> >
{chips[leftoverKey]?.chips?.map((chip) => ( {chips[leftoverKey]?.chips?.map((chip) => (
<Chip key={chip.key} isReadOnly> <Chip key={chip.key} isReadOnly>

View File

@@ -135,6 +135,7 @@ function Lookup(props) {
<Button <Button
aria-label={t`Search`} aria-label={t`Search`}
id={`${id}-open`} id={`${id}-open`}
ouiaId={`${id}-open`}
onClick={() => dispatch({ type: 'TOGGLE_MODAL' })} onClick={() => dispatch({ type: 'TOGGLE_MODAL' })}
variant={ButtonVariant.control} variant={ButtonVariant.control}
isDisabled={isLoading || isDisabled} isDisabled={isLoading || isDisabled}
@@ -143,7 +144,11 @@ function Lookup(props) {
</Button> </Button>
{multiple ? ( {multiple ? (
<ChipHolder isDisabled={isDisabled} className="pf-c-form-control"> <ChipHolder isDisabled={isDisabled} className="pf-c-form-control">
<ChipGroup numChips={5} totalChips={items.length}> <ChipGroup
numChips={5}
totalChips={items.length}
ouiaId={`${id}-chips`}
>
{items.map((item) => {items.map((item) =>
renderItemChip({ renderItemChip({
item, item,
@@ -156,6 +161,7 @@ function Lookup(props) {
) : ( ) : (
<TextInput <TextInput
id={id} id={id}
ouiaId={`${id}-input`}
value={typedText} value={typedText}
onChange={(inputValue) => { onChange={(inputValue) => {
setTypedText(inputValue); setTypedText(inputValue);
@@ -175,6 +181,7 @@ function Lookup(props) {
isOpen={isModalOpen} isOpen={isModalOpen}
onClose={closeModal} onClose={closeModal}
description={state?.selectedItems?.length > 0 && modalDescription} description={state?.selectedItems?.length > 0 && modalDescription}
ouiaId={`${id}-modal`}
actions={[ actions={[
<Button <Button
ouiaId="modal-select-button" ouiaId="modal-select-button"

View File

@@ -152,6 +152,7 @@ function MultiCredentialsLookup({
isInline isInline
css="margin-bottom: 20px;" css="margin-bottom: 20px;"
title={t`You cannot select multiple vault credentials with the same vault ID. Doing so will automatically deselect the other with the same vault ID.`} title={t`You cannot select multiple vault credentials with the same vault ID. Doing so will automatically deselect the other with the same vault ID.`}
ouiaId="multi-credentials-lookup-alert"
/> />
)} )}
{credentialTypes && credentialTypes.length > 0 && ( {credentialTypes && credentialTypes.length > 0 && (

View File

@@ -58,6 +58,7 @@ function TagMultiSelect({ onChange, value }) {
isOpen={isExpanded} isOpen={isExpanded}
typeAheadAriaLabel={t`Select tags`} typeAheadAriaLabel={t`Select tags`}
noResultsFoundText={t`No results found`} noResultsFoundText={t`No results found`}
ouiaId="tag-multiselect"
> >
{renderOptions(options)} {renderOptions(options)}
</Select> </Select>

View File

@@ -21,7 +21,10 @@ function NotificationListItem({
showApprovalsToggle, showApprovalsToggle,
}) { }) {
return ( return (
<Tr id={`notification-row-${notification.id}`}> <Tr
id={`notification-row-${notification.id}`}
ouiaId={`notification-row-${notification.id}`}
>
<Td id={`notification-${notification.id}`} dataLabel={t`Name`}> <Td id={`notification-${notification.id}`} dataLabel={t`Name`}>
<Link to={`${detailUrl}`}> <Link to={`${detailUrl}`}>
<b>{notification.name}</b> <b>{notification.name}</b>
@@ -32,6 +35,7 @@ function NotificationListItem({
<ActionItem visible={showApprovalsToggle}> <ActionItem visible={showApprovalsToggle}>
<Switch <Switch
id={`notification-${notification.id}-approvals-toggle`} id={`notification-${notification.id}-approvals-toggle`}
ouiaId={`notification-${notification.id}-approvals-toggle`}
label={t`Approval`} label={t`Approval`}
labelOff={t`Approval`} labelOff={t`Approval`}
isChecked={approvalsTurnedOn} isChecked={approvalsTurnedOn}
@@ -49,6 +53,7 @@ function NotificationListItem({
<ActionItem visible> <ActionItem visible>
<Switch <Switch
id={`notification-${notification.id}-started-toggle`} id={`notification-${notification.id}-started-toggle`}
ouiaId={`notification-${notification.id}-started-toggle`}
label={t`Start`} label={t`Start`}
labelOff={t`Start`} labelOff={t`Start`}
isChecked={startedTurnedOn} isChecked={startedTurnedOn}
@@ -62,6 +67,7 @@ function NotificationListItem({
<ActionItem visible> <ActionItem visible>
<Switch <Switch
id={`notification-${notification.id}-success-toggle`} id={`notification-${notification.id}-success-toggle`}
ouiaId={`notification-${notification.id}-success-toggle`}
label={t`Success`} label={t`Success`}
labelOff={t`Success`} labelOff={t`Success`}
isChecked={successTurnedOn} isChecked={successTurnedOn}
@@ -75,6 +81,7 @@ function NotificationListItem({
<ActionItem visible> <ActionItem visible>
<Switch <Switch
id={`notification-${notification.id}-error-toggle`} id={`notification-${notification.id}-error-toggle`}
ouiaId={`notification-${notification.id}-error-toggle`}
label={t`Failure`} label={t`Failure`}
labelOff={t`Failure`} labelOff={t`Failure`}
isChecked={errorTurnedOn} isChecked={errorTurnedOn}

View File

@@ -38,7 +38,7 @@ export default function HeaderRow({
// empty first Th aligns with checkboxes in table rows // empty first Th aligns with checkboxes in table rows
return ( return (
<Thead> <Thead>
<Tr> <Tr ouiaId="paginated-table-header-row">
{isExpandable && <Th />} {isExpandable && <Th />}
{isSelectable && <Th />} {isSelectable && <Th />}
{React.Children.map( {React.Children.map(

View File

@@ -128,6 +128,7 @@ function PaginatedTable({
} }
onSetPage={handleSetPage} onSetPage={handleSetPage}
onPerPageSelect={handleSetPageSize} onPerPageSelect={handleSetPageSize}
ouiaId="top-pagination"
titles={{ titles={{
paginationTitle: t`Top Pagination`, paginationTitle: t`Top Pagination`,
}} }}
@@ -165,6 +166,7 @@ function PaginatedTable({
} }
onSetPage={handleSetPage} onSetPage={handleSetPage}
onPerPageSelect={handleSetPageSize} onPerPageSelect={handleSetPageSize}
ouiaId="bottom-pagination"
/> />
) : null} ) : null}
</> </>

View File

@@ -108,19 +108,33 @@ function PromptDetail({
return ( return (
<> <>
<DetailList gutter="sm"> <DetailList gutter="sm">
<Detail label={t`Name`} value={buildResourceLink(resource)} /> <Detail
<Detail label={t`Description`} value={details.description} /> label={t`Name`}
dataCy="prompt-detail-name"
value={buildResourceLink(resource)}
/>
<Detail
label={t`Description`}
dataCy="prompt-detail-description"
value={details.description}
/>
<Detail <Detail
label={t`Type`} label={t`Type`}
dataCy="prompt-detail-type"
value={toTitleCase(details.unified_job_type || details.type)} value={toTitleCase(details.unified_job_type || details.type)}
/> />
{workflowNode && ( {workflowNode && (
<Detail <Detail
label={t`Convergence`} label={t`Convergence`}
dataCy="prompt-detail-convergence"
value={workflowNode?.all_parents_must_converge ? t`All` : t`Any`} value={workflowNode?.all_parents_must_converge ? t`All` : t`Any`}
/> />
)} )}
<Detail label={t`Timeout`} value={formatTimeout(details?.timeout)} /> <Detail
label={t`Timeout`}
dataCy="prompt-detail-timeout"
value={formatTimeout(details?.timeout)}
/>
{details?.type === 'project' && ( {details?.type === 'project' && (
<PromptProjectDetail resource={details} /> <PromptProjectDetail resource={details} />
)} )}
@@ -153,10 +167,10 @@ function PromptDetail({
rows={4} rows={4}
value={overrides.extra_vars} value={overrides.extra_vars}
name="extra_vars" name="extra_vars"
dataCy="prompt-detail-variables"
/> />
)} )}
</DetailList> </DetailList>
{details?.type !== 'system_job_template' && {details?.type !== 'system_job_template' &&
hasPromptData(launchConfig) && hasPromptData(launchConfig) &&
hasOverrides && ( hasOverrides && (
@@ -179,12 +193,14 @@ function PromptDetail({
<ChipGroup <ChipGroup
numChips={5} numChips={5}
totalChips={overrides.credentials.length} totalChips={overrides.credentials.length}
ouiaId="prompt-credential-chips"
> >
{overrides.credentials.map((cred) => ( {overrides.credentials.map((cred) => (
<CredentialChip <CredentialChip
key={cred.id} key={cred.id}
credential={cred} credential={cred}
isReadOnly isReadOnly
ouiaId={`credential-${cred.id}-chip`}
/> />
))} ))}
</ChipGroup> </ChipGroup>
@@ -220,6 +236,7 @@ function PromptDetail({
value={ value={
<ChipGroup <ChipGroup
numChips={5} numChips={5}
ouiaId="prompt-job-tag-chips"
totalChips={ totalChips={
!overrides.job_tags || overrides.job_tags === '' !overrides.job_tags || overrides.job_tags === ''
? 0 ? 0
@@ -228,7 +245,11 @@ function PromptDetail({
> >
{overrides.job_tags.length > 0 && {overrides.job_tags.length > 0 &&
overrides.job_tags.split(',').map((jobTag) => ( overrides.job_tags.split(',').map((jobTag) => (
<Chip key={jobTag} isReadOnly> <Chip
key={jobTag}
isReadOnly
ouiaId={`job-tag-${jobTag}-chip`}
>
{jobTag} {jobTag}
</Chip> </Chip>
))} ))}
@@ -248,10 +269,15 @@ function PromptDetail({
? 0 ? 0
: overrides.skip_tags.split(',').length : overrides.skip_tags.split(',').length
} }
ouiaId="prompt-skip-tag-chips"
> >
{overrides.skip_tags.length > 0 && {overrides.skip_tags.length > 0 &&
overrides.skip_tags.split(',').map((skipTag) => ( overrides.skip_tags.split(',').map((skipTag) => (
<Chip key={skipTag} isReadOnly> <Chip
key={skipTag}
isReadOnly
ouiaId={`skip-tag-${skipTag}-chip`}
>
{skipTag} {skipTag}
</Chip> </Chip>
))} ))}
@@ -268,6 +294,7 @@ function PromptDetail({
{(launchConfig.survey_enabled || {(launchConfig.survey_enabled ||
launchConfig.ask_variables_on_launch) && ( launchConfig.ask_variables_on_launch) && (
<VariablesDetail <VariablesDetail
dataCy="prompt-detail-variables"
label={t`Variables`} label={t`Variables`}
rows={4} rows={4}
value={overrides.extra_vars} value={overrides.extra_vars}

View File

@@ -137,6 +137,7 @@ function PromptInventorySourceDetail({ resource }) {
<ChipGroup <ChipGroup
numChips={5} numChips={5}
totalChips={source_regions.split(',').length} totalChips={source_regions.split(',').length}
ouiaId="prompt-region-chips"
> >
{source_regions.split(',').map((region) => ( {source_regions.split(',').map((region) => (
<Chip key={region} isReadOnly> <Chip key={region} isReadOnly>
@@ -155,6 +156,7 @@ function PromptInventorySourceDetail({ resource }) {
<ChipGroup <ChipGroup
numChips={5} numChips={5}
totalChips={instance_filters.split(',').length} totalChips={instance_filters.split(',').length}
ouiaId="prompt-instance-filter-chips"
> >
{instance_filters.split(',').map((filter) => ( {instance_filters.split(',').map((filter) => (
<Chip key={filter} isReadOnly> <Chip key={filter} isReadOnly>
@@ -170,7 +172,11 @@ function PromptInventorySourceDetail({ resource }) {
fullWidth fullWidth
label={t`Only Group By`} label={t`Only Group By`}
value={ value={
<ChipGroup numChips={5} totalChips={group_by.split(',').length}> <ChipGroup
numChips={5}
totalChips={group_by.split(',').length}
ouiaId="prompt-only-group-by-chips"
>
{group_by.split(',').map((group) => ( {group_by.split(',').map((group) => (
<Chip key={group} isReadOnly> <Chip key={group} isReadOnly>
{group} {group}
@@ -185,6 +191,7 @@ function PromptInventorySourceDetail({ resource }) {
)} )}
{source_vars && ( {source_vars && (
<VariablesDetail <VariablesDetail
dataCy="prompt-inventory-source-detail-source-variables"
label={t`Source Variables`} label={t`Source Variables`}
rows={4} rows={4}
value={source_vars} value={source_vars}

View File

@@ -195,6 +195,7 @@ function PromptJobTemplateDetail({ resource }) {
<ChipGroup <ChipGroup
numChips={5} numChips={5}
totalChips={summary_fields.credentials.length} totalChips={summary_fields.credentials.length}
ouiaId="prompt-jt-credential-chips"
> >
{summary_fields.credentials.map((cred) => ( {summary_fields.credentials.map((cred) => (
<CredentialChip key={cred.id} credential={cred} isReadOnly /> <CredentialChip key={cred.id} credential={cred} isReadOnly />
@@ -211,6 +212,7 @@ function PromptJobTemplateDetail({ resource }) {
<ChipGroup <ChipGroup
numChips={5} numChips={5}
totalChips={summary_fields.labels.results.length} totalChips={summary_fields.labels.results.length}
ouiaId="prompt-jt-label-chips"
> >
{summary_fields.labels.results.map((label) => ( {summary_fields.labels.results.map((label) => (
<Chip key={label.id} isReadOnly> <Chip key={label.id} isReadOnly>
@@ -226,7 +228,11 @@ function PromptJobTemplateDetail({ resource }) {
fullWidth fullWidth
label={t`Instance Groups`} label={t`Instance Groups`}
value={ value={
<ChipGroup numChips={5} totalChips={instance_groups.length}> <ChipGroup
numChips={5}
totalChips={instance_groups.length}
ouiaId="prompt-jt-instance-group-chips"
>
{instance_groups.map((ig) => ( {instance_groups.map((ig) => (
<Chip key={ig.id} isReadOnly> <Chip key={ig.id} isReadOnly>
{ig.name} {ig.name}
@@ -241,7 +247,11 @@ function PromptJobTemplateDetail({ resource }) {
fullWidth fullWidth
label={t`Job Tags`} label={t`Job Tags`}
value={ value={
<ChipGroup numChips={5} totalChips={job_tags.split(',').length}> <ChipGroup
numChips={5}
totalChips={job_tags.split(',').length}
ouiaId="prompt-jt-job-tag-chips"
>
{job_tags.split(',').map((jobTag) => ( {job_tags.split(',').map((jobTag) => (
<Chip key={jobTag} isReadOnly> <Chip key={jobTag} isReadOnly>
{jobTag} {jobTag}
@@ -256,7 +266,11 @@ function PromptJobTemplateDetail({ resource }) {
fullWidth fullWidth
label={t`Skip Tags`} label={t`Skip Tags`}
value={ value={
<ChipGroup numChips={5} totalChips={skip_tags.split(',').length}> <ChipGroup
numChips={5}
totalChips={skip_tags.split(',').length}
ouiaId="prompt-jt-skip-tag-chips"
>
{skip_tags.split(',').map((skipTag) => ( {skip_tags.split(',').map((skipTag) => (
<Chip key={skipTag} isReadOnly> <Chip key={skipTag} isReadOnly>
{skipTag} {skipTag}
@@ -272,6 +286,7 @@ function PromptJobTemplateDetail({ resource }) {
rows={4} rows={4}
value={extra_vars} value={extra_vars}
name="extra_vars" name="extra_vars"
dataCy="prompt-jt-detail-extra-vars"
/> />
)} )}
</> </>

View File

@@ -69,11 +69,13 @@ function PromptProjectDetail({ resource }) {
); );
} }
const prefixCy = 'prompt-project-detail';
return ( return (
<> <>
{summary_fields?.organization ? ( {summary_fields?.organization ? (
<Detail <Detail
label={t`Organization`} label={t`Organization`}
dataCy={`${prefixCy}-organization`}
value={ value={
<Link <Link
to={`/organizations/${summary_fields.organization.id}/details`} to={`/organizations/${summary_fields.organization.id}/details`}
@@ -92,14 +94,28 @@ function PromptProjectDetail({ resource }) {
/> />
<Detail <Detail
label={t`Source Control Type`} label={t`Source Control Type`}
dataCy={`${prefixCy}-source-control-type`}
value={scm_type === '' ? t`Manual` : toTitleCase(scm_type)} value={scm_type === '' ? t`Manual` : toTitleCase(scm_type)}
/> />
<Detail label={t`Source Control URL`} value={scm_url} /> <Detail
<Detail label={t`Source Control Branch`} value={scm_branch} /> label={t`Source Control URL`}
<Detail label={t`Source Control Refspec`} value={scm_refspec} /> dataCy={`${prefixCy}-source-control-url`}
value={scm_url}
/>
<Detail
label={t`Source Control Branch`}
dataCy={`${prefixCy}-source-control-branch`}
value={scm_branch}
/>
<Detail
label={t`Source Control Refspec`}
dataCy={`${prefixCy}-source-control-refspec`}
value={scm_refspec}
/>
{summary_fields?.credential?.id && ( {summary_fields?.credential?.id && (
<Detail <Detail
label={t`Source Control Credential`} label={t`Source Control Credential`}
dataCy={`${prefixCy}-source-control-credential`}
value={ value={
<CredentialChip <CredentialChip
key={resource.summary_fields.credential.id} key={resource.summary_fields.credential.id}
@@ -109,17 +125,32 @@ function PromptProjectDetail({ resource }) {
} }
/> />
)} )}
{optionsList && <Detail label={t`Enabled Options`} value={optionsList} />} {optionsList && (
<Detail
label={t`Enabled Options`}
dataCy={`${prefixCy}-enabled-options`}
value={optionsList}
/>
)}
<Detail <Detail
label={t`Cache Timeout`} label={t`Cache Timeout`}
dataCy={`${prefixCy}-cache-timeout`}
value={`${scm_update_cache_timeout} ${t`Seconds`}`} value={`${scm_update_cache_timeout} ${t`Seconds`}`}
/> />
<Config> <Config>
{({ project_base_dir }) => ( {({ project_base_dir }) => (
<Detail label={t`Project Base Path`} value={project_base_dir} /> <Detail
label={t`Project Base Path`}
dataCy={`${prefixCy}-project-base-path`}
value={project_base_dir}
/>
)} )}
</Config> </Config>
<Detail label={t`Playbook Directory`} value={local_path} /> <Detail
label={t`Playbook Directory`}
dataCy={`${prefixCy}-playbook-directory`}
value={local_path}
/>
</> </>
); );
} }

View File

@@ -116,6 +116,7 @@ function PromptWFJobTemplateDetail({ resource }) {
<ChipGroup <ChipGroup
numChips={5} numChips={5}
totalChips={summary_fields.labels.results.length} totalChips={summary_fields.labels.results.length}
ouiaId="prompt-wf-jt-label-chips"
> >
{summary_fields.labels.results.map((label) => ( {summary_fields.labels.results.map((label) => (
<Chip key={label.id} isReadOnly> <Chip key={label.id} isReadOnly>
@@ -132,6 +133,7 @@ function PromptWFJobTemplateDetail({ resource }) {
rows={4} rows={4}
value={extra_vars} value={extra_vars}
name="extra_vars" name="extra_vars"
dataCy="prompt-wf-jt-detail-variables"
/> />
)} )}
</> </>

View File

@@ -51,7 +51,10 @@ function ResourceAccessListItem({ accessRecord, onRoleDelete }) {
const [teamRoles, userRoles] = getRoleLists(); const [teamRoles, userRoles] = getRoleLists();
return ( return (
<Tr id={`access-item-row-${accessRecord.id}`}> <Tr
id={`access-item-row-${accessRecord.id}`}
ouiaId={`access-item-row-${accessRecord.id}`}
>
<Td id={`access-record-${accessRecord.id}`} dataLabel={t`Name`}> <Td id={`access-record-${accessRecord.id}`} dataLabel={t`Name`}>
{accessRecord.id ? ( {accessRecord.id ? (
<Link to={{ pathname: `/users/${accessRecord.id}/details` }}> <Link to={{ pathname: `/users/${accessRecord.id}/details` }}>
@@ -69,7 +72,11 @@ function ResourceAccessListItem({ accessRecord, onRoleDelete }) {
<Detail <Detail
label={t`User Roles`} label={t`User Roles`}
value={ value={
<ChipGroup numChips={5} totalChips={userRoles.length}> <ChipGroup
numChips={5}
totalChips={userRoles.length}
ouiaId="user-role-chips"
>
{userRoles.map(renderChip)} {userRoles.map(renderChip)}
</ChipGroup> </ChipGroup>
} }
@@ -79,7 +86,11 @@ function ResourceAccessListItem({ accessRecord, onRoleDelete }) {
<Detail <Detail
label={t`Team Roles`} label={t`Team Roles`}
value={ value={
<ChipGroup numChips={5} totalChips={teamRoles.length}> <ChipGroup
numChips={5}
totalChips={teamRoles.length}
ouiaId="team-role-chips"
>
{teamRoles.map(renderChip)} {teamRoles.map(renderChip)}
</ChipGroup> </ChipGroup>
} }

View File

@@ -29,7 +29,11 @@ function RoutedTabs({ tabsArray }) {
} }
return ( return (
<Tabs activeKey={getActiveTabId()} onSelect={handleTabSelect}> <Tabs
activeKey={getActiveTabId()}
onSelect={handleTabSelect}
ouiaId="routed-tabs"
>
{tabsArray.map((tab) => ( {tabsArray.map((tab) => (
<Tab <Tab
aria-label={typeof tab.name === 'string' ? tab.name : null} aria-label={typeof tab.name === 'string' ? tab.name : null}
@@ -38,6 +42,7 @@ function RoutedTabs({ tabsArray }) {
link={tab.link} link={tab.link}
title={<TabTitleText>{tab.name}</TabTitleText>} title={<TabTitleText>{tab.name}</TabTitleText>}
aria-controls="" aria-controls=""
ouiaId={`${tab.name}-tab`}
/> />
))} ))}
</Tabs> </Tabs>

View File

@@ -330,9 +330,18 @@ function ScheduleDetail({ hasDaysToKeepField, schedule, surveyConfig }) {
fullWidth fullWidth
label={t`Credentials`} label={t`Credentials`}
value={ value={
<ChipGroup numChips={5} totalChips={credentials.length}> <ChipGroup
numChips={5}
totalChips={credentials.length}
ouiaId="schedule-credential-chips"
>
{credentials.map((c) => ( {credentials.map((c) => (
<CredentialChip key={c.id} credential={c} isReadOnly /> <CredentialChip
key={c.id}
credential={c}
isReadOnly
ouiaId={`credential-${c.id}-chip`}
/>
))} ))}
</ChipGroup> </ChipGroup>
} }
@@ -346,9 +355,14 @@ function ScheduleDetail({ hasDaysToKeepField, schedule, surveyConfig }) {
<ChipGroup <ChipGroup
numChips={5} numChips={5}
totalChips={job_tags.split(',').length} totalChips={job_tags.split(',').length}
ouiaId="schedule-job-tag-chips"
> >
{job_tags.split(',').map((jobTag) => ( {job_tags.split(',').map((jobTag) => (
<Chip key={jobTag} isReadOnly> <Chip
key={jobTag}
isReadOnly
ouiaId={`job-tag-${jobTag}-chip`}
>
{jobTag} {jobTag}
</Chip> </Chip>
))} ))}
@@ -364,9 +378,14 @@ function ScheduleDetail({ hasDaysToKeepField, schedule, surveyConfig }) {
<ChipGroup <ChipGroup
numChips={5} numChips={5}
totalChips={skip_tags.split(',').length} totalChips={skip_tags.split(',').length}
ouiaId="schedule-skip-tag-chips"
> >
{skip_tags.split(',').map((skipTag) => ( {skip_tags.split(',').map((skipTag) => (
<Chip key={skipTag} isReadOnly> <Chip
key={skipTag}
isReadOnly
ouiaId={`skip-tag-${skipTag}-chip`}
>
{skipTag} {skipTag}
</Chip> </Chip>
))} ))}
@@ -380,6 +399,7 @@ function ScheduleDetail({ hasDaysToKeepField, schedule, surveyConfig }) {
rows={4} rows={4}
label={t`Variables`} label={t`Variables`}
name="extra_vars" name="extra_vars"
dataCy="schedule-detail-variables"
/> />
)} )}
</PromptDetailList> </PromptDetailList>

View File

@@ -64,7 +64,10 @@ function ScheduleListItem({
const isDisabled = Boolean(isMissingInventory || isMissingSurvey); const isDisabled = Boolean(isMissingInventory || isMissingSurvey);
return ( return (
<Tr id={`schedule-row-${schedule.id}`}> <Tr
id={`schedule-row-${schedule.id}`}
ouiaId={`schedule-row-${schedule.id}`}
>
<Td <Td
select={{ select={{
rowIndex, rowIndex,

View File

@@ -64,6 +64,7 @@ function ScheduleToggle({ schedule, onToggle, className, isDisabled }) {
} }
onChange={toggleSchedule} onChange={toggleSchedule}
aria-label={t`Toggle schedule`} aria-label={t`Toggle schedule`}
ouiaId={`schedule-${schedule.id}-toggle`}
/> />
</Tooltip> </Tooltip>
{showError && error && !isLoading && ( {showError && error && !isLoading && (

View File

@@ -249,6 +249,7 @@ const FrequencyDetailSubform = () => {
}} }}
aria-label={t`Sunday`} aria-label={t`Sunday`}
id="schedule-days-of-week-sun" id="schedule-days-of-week-sun"
ouiaId="schedule-days-of-week-sun"
name="daysOfWeek" name="daysOfWeek"
/> />
<Checkbox <Checkbox
@@ -259,6 +260,7 @@ const FrequencyDetailSubform = () => {
}} }}
aria-label={t`Monday`} aria-label={t`Monday`}
id="schedule-days-of-week-mon" id="schedule-days-of-week-mon"
ouiaId="schedule-days-of-week-mon"
name="daysOfWeek" name="daysOfWeek"
/> />
<Checkbox <Checkbox
@@ -269,6 +271,7 @@ const FrequencyDetailSubform = () => {
}} }}
aria-label={t`Tuesday`} aria-label={t`Tuesday`}
id="schedule-days-of-week-tue" id="schedule-days-of-week-tue"
ouiaId="schedule-days-of-week-tue"
name="daysOfWeek" name="daysOfWeek"
/> />
<Checkbox <Checkbox
@@ -279,6 +282,7 @@ const FrequencyDetailSubform = () => {
}} }}
aria-label={t`Wednesday`} aria-label={t`Wednesday`}
id="schedule-days-of-week-wed" id="schedule-days-of-week-wed"
ouiaId="schedule-days-of-week-wed"
name="daysOfWeek" name="daysOfWeek"
/> />
<Checkbox <Checkbox
@@ -289,6 +293,7 @@ const FrequencyDetailSubform = () => {
}} }}
aria-label={t`Thursday`} aria-label={t`Thursday`}
id="schedule-days-of-week-thu" id="schedule-days-of-week-thu"
ouiaId="schedule-days-of-week-thu"
name="daysOfWeek" name="daysOfWeek"
/> />
<Checkbox <Checkbox
@@ -299,6 +304,7 @@ const FrequencyDetailSubform = () => {
}} }}
aria-label={t`Friday`} aria-label={t`Friday`}
id="schedule-days-of-week-fri" id="schedule-days-of-week-fri"
ouiaId="schedule-days-of-week-fri"
name="daysOfWeek" name="daysOfWeek"
/> />
<Checkbox <Checkbox
@@ -309,6 +315,7 @@ const FrequencyDetailSubform = () => {
}} }}
aria-label={t`Saturday`} aria-label={t`Saturday`}
id="schedule-days-of-week-sat" id="schedule-days-of-week-sat"
ouiaId="schedule-days-of-week-sat"
name="daysOfWeek" name="daysOfWeek"
/> />
</div> </div>
@@ -499,6 +506,7 @@ const FrequencyDetailSubform = () => {
event.target.value = 'never'; event.target.value = 'never';
end.onChange(event); end.onChange(event);
}} }}
ouiaId="end-never-radio-button"
/> />
<Radio <Radio
id="end-after" id="end-after"
@@ -510,6 +518,7 @@ const FrequencyDetailSubform = () => {
event.target.value = 'after'; event.target.value = 'after';
end.onChange(event); end.onChange(event);
}} }}
ouiaId="end-after-radio-button"
/> />
<Radio <Radio
id="end-on-date" id="end-on-date"
@@ -521,6 +530,7 @@ const FrequencyDetailSubform = () => {
event.target.value = 'onDate'; event.target.value = 'onDate';
end.onChange(event); end.onChange(event);
}} }}
ouiaId="end-on-radio-button"
/> />
</FormGroup> </FormGroup>
{end?.value === 'after' && ( {end?.value === 'after' && (

View File

@@ -33,7 +33,7 @@ const ScreenHeader = ({ breadcrumbConfig, streamType }) => {
> >
<div> <div>
{!isOnlyOneCrumb && ( {!isOnlyOneCrumb && (
<Breadcrumb> <Breadcrumb ouiaId="breadcrumb-list">
<Route path="/:path"> <Route path="/:path">
<Crumb breadcrumbConfig={breadcrumbConfig} /> <Crumb breadcrumbConfig={breadcrumbConfig} />
</Route> </Route>
@@ -103,7 +103,7 @@ const Crumb = ({ breadcrumbConfig, showDivider }) => {
const crumb = breadcrumbConfig[match.url]; const crumb = breadcrumbConfig[match.url];
let crumbElement = ( let crumbElement = (
<BreadcrumbItem key={match.url} showDivider={showDivider}> <BreadcrumbItem key={match.url} showDivider={showDivider} data-cy={crumb}>
<Link to={match.url}>{crumb}</Link> <Link to={match.url}>{crumb}</Link>
</BreadcrumbItem> </BreadcrumbItem>
); );
@@ -119,7 +119,11 @@ const Crumb = ({ breadcrumbConfig, showDivider }) => {
<> <>
{crumbElement} {crumbElement}
<Route path={`${match.url}/:path`}> <Route path={`${match.url}/:path`}>
<Crumb breadcrumbConfig={breadcrumbConfig} showDivider /> <Crumb
breadcrumbConfig={breadcrumbConfig}
showDivider
data-cy={crumb}
/>
</Route> </Route>
</> </>
); );

View File

@@ -109,7 +109,12 @@ function Search({
const searchOptions = columns const searchOptions = columns
.filter(({ key }) => key !== searchKey) .filter(({ key }) => key !== searchKey)
.map(({ key, name }) => ( .map(({ key, name }) => (
<SelectOption key={key} value={name} id={`select-option-${key}`}> <SelectOption
data-cy={`select-option-${key}`}
id={`select-option-${key}`}
key={key}
value={name}
>
{name} {name}
</SelectOption> </SelectOption>
)); ));

View File

@@ -32,7 +32,11 @@ function SelectedList(props) {
<Split> <Split>
<SplitLabelItem>{label}</SplitLabelItem> <SplitLabelItem>{label}</SplitLabelItem>
<SplitItem> <SplitItem>
<ChipGroup numChips={5} totalChips={selected.length}> <ChipGroup
numChips={5}
totalChips={selected.length}
ouiaId="selected-list-chips"
>
{selected.map((item) => {selected.map((item) =>
renderChip({ renderChip({
item, item,

View File

@@ -92,7 +92,11 @@ function Sort({ columns, qsConfig, onSort }) {
const sortDropdownItems = columns const sortDropdownItems = columns
.filter(({ key }) => key !== sortKey) .filter(({ key }) => key !== sortKey)
.map(({ key, name }) => ( .map(({ key, name }) => (
<DropdownItem key={key} component="button"> <DropdownItem
key={key}
component="button"
ouiaId={`${name}-dropdown-item`}
>
{name} {name}
</DropdownItem> </DropdownItem>
)); ));
@@ -115,8 +119,13 @@ function Sort({ columns, qsConfig, onSort }) {
onSelect={handleDropdownSelect} onSelect={handleDropdownSelect}
direction={up} direction={up}
isOpen={isSortDropdownOpen} isOpen={isSortDropdownOpen}
ouiaId="sort-dropdown"
toggle={ toggle={
<DropdownToggle id="awx-sort" onToggle={handleDropdownToggle}> <DropdownToggle
id="awx-sort"
onToggle={handleDropdownToggle}
ouiaId="sort-dropdown-toggle"
>
{sortedColumnName} {sortedColumnName}
</DropdownToggle> </DropdownToggle>
} }
@@ -128,6 +137,7 @@ function Sort({ columns, qsConfig, onSort }) {
variant={ButtonVariant.control} variant={ButtonVariant.control}
aria-label={t`Sort`} aria-label={t`Sort`}
onClick={handleSort} onClick={handleSort}
ouiaId="sort-button"
> >
<SortIcon /> <SortIcon />
</Button> </Button>

View File

@@ -115,7 +115,10 @@ function TemplateListItem({
return ( return (
<> <>
<Tr id={`template-row-${template.id}`}> <Tr
id={`template-row-${template.id}`}
ouiaId={`template-row-${template.id}`}
>
<Td <Td
expand={{ expand={{
rowIndex, rowIndex,
@@ -242,7 +245,10 @@ function TemplateListItem({
</ActionItem> </ActionItem>
</ActionsTd> </ActionsTd>
</Tr> </Tr>
<Tr isExpanded={isExpanded}> <Tr
isExpanded={isExpanded}
ouiaId={`template-row-${template.id}-expanded`}
>
<Td colSpan={2} /> <Td colSpan={2} />
<Td colSpan={4}> <Td colSpan={4}>
<ExpandableRowContent> <ExpandableRowContent>
@@ -317,9 +323,15 @@ function TemplateListItem({
<ChipGroup <ChipGroup
numChips={5} numChips={5}
totalChips={summaryFields.credentials.length} totalChips={summaryFields.credentials.length}
ouiaId={`template-${template.id}-credential-chips`}
> >
{summaryFields.credentials.map((c) => ( {summaryFields.credentials.map((c) => (
<CredentialChip key={c.id} credential={c} isReadOnly /> <CredentialChip
key={c.id}
credential={c}
isReadOnly
ouiaId={`credential-${c.id}-chip`}
/>
))} ))}
</ChipGroup> </ChipGroup>
} }
@@ -334,9 +346,14 @@ function TemplateListItem({
<ChipGroup <ChipGroup
numChips={5} numChips={5}
totalChips={summaryFields.labels.results.length} totalChips={summaryFields.labels.results.length}
ouiaId={`template-${template.id}-label-chips`}
> >
{summaryFields.labels.results.map((l) => ( {summaryFields.labels.results.map((l) => (
<Chip key={l.id} isReadOnly> <Chip
key={l.id}
isReadOnly
ouiaId={`label-${l.id}-chip`}
>
{l.name} {l.name}
</Chip> </Chip>
))} ))}

View File

@@ -32,6 +32,7 @@ function WorkflowActionTooltipItem({
return ( return (
<TooltipItem <TooltipItem
id={id} id={id}
data-cy={id}
onClick={onClick} onClick={onClick}
onMouseEnter={onMouseEnter} onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave} onMouseLeave={onMouseLeave}

View File

@@ -132,6 +132,7 @@ function ActivityStream() {
isOpen={isTypeDropdownOpen} isOpen={isTypeDropdownOpen}
isGrouped isGrouped
noResultsFoundText={t`No results found`} noResultsFoundText={t`No results found`}
ouiaId="activity-type-select"
> >
<SelectGroup label={t`Views`} key="views"> <SelectGroup label={t`Views`} key="views">
<SelectOption key="all_activity" value="all"> <SelectOption key="all_activity" value="all">

View File

@@ -56,6 +56,7 @@ function ActivityStreamDetailButton({ streamItem, user, description }) {
streamItem?.changes ? JSON.stringify(streamItem.changes) : '' streamItem?.changes ? JSON.stringify(streamItem.changes) : ''
} }
name="changes" name="changes"
dataCy="activity-stream-detail-changes"
/> />
)} )}
</DetailList> </DetailList>

View File

@@ -37,7 +37,7 @@ function ActivityStreamListItem({ streamItem }) {
const description = <ActivityStreamDescription activity={streamItem} />; const description = <ActivityStreamDescription activity={streamItem} />;
return ( return (
<Tr id={streamItem.id} aria-labelledby={labelId}> <Tr id={streamItem.id} ouiaId={streamItem.id} aria-labelledby={labelId}>
<Td /> <Td />
<Td dataLabel={t`Time`}> <Td dataLabel={t`Time`}>
{streamItem.timestamp ? formatDateString(streamItem.timestamp) : ''} {streamItem.timestamp ? formatDateString(streamItem.timestamp) : ''}

View File

@@ -16,7 +16,7 @@ function ApplicationTokenListItem({
rowIndex, rowIndex,
}) { }) {
return ( return (
<Tr id={`token-row-${token.id}`}> <Tr id={`token-row-${token.id}`} ouiaId={`token-row-${token.id}`}>
<Td <Td
select={{ select={{
rowIndex, rowIndex,

View File

@@ -18,7 +18,10 @@ function ApplicationListItem({
}) { }) {
const labelId = `check-action-${application.id}`; const labelId = `check-action-${application.id}`;
return ( return (
<Tr id={`application-row-${application.id}`}> <Tr
id={`application-row-${application.id}`}
ouiaId={`application-row-${application.id}`}
>
<Td <Td
select={{ select={{
rowIndex, rowIndex,

View File

@@ -110,9 +110,14 @@ function CredentialDetail({ credential }) {
fullWidth fullWidth
label={<span>{label} *</span>} label={<span>{label} *</span>}
value={ value={
<ChipGroup numChips={1} totalChips={1}> <ChipGroup
numChips={1}
totalChips={1}
ouiaId={`credential-${id}-chips`}
>
<CredentialChip <CredentialChip
credential={inputSources[id].summary_fields.source_credential} credential={inputSources[id].summary_fields.source_credential}
ouiaId={`credential-${id}-chip`}
isReadOnly isReadOnly
/> />
</ChipGroup> </ChipGroup>

View File

@@ -43,7 +43,7 @@ function CredentialListItem({
}, []); }, []);
return ( return (
<Tr id={`${credential.id}`}> <Tr id={`${credential.id}`} ouiaId={`${credential.id}`}>
<Td <Td
select={{ select={{
rowIndex, rowIndex,

View File

@@ -65,6 +65,7 @@ function CredentialPluginTestAlert({
</> </>
} }
variant={testVariant} variant={testVariant}
ouiaId="credential-plugin-test-alert"
/> />
)} )}
</AlertGroup> </AlertGroup>

View File

@@ -75,12 +75,14 @@ function CredentialTypeDetails({ credentialType }) {
value={jsonToYaml(JSON.stringify(inputs))} value={jsonToYaml(JSON.stringify(inputs))}
rows={6} rows={6}
name="input" name="input"
dataCy="credential-type-detail-input"
/> />
<VariablesDetail <VariablesDetail
label={t`Injector configuration`} label={t`Injector configuration`}
value={jsonToYaml(JSON.stringify(injectors))} value={jsonToYaml(JSON.stringify(injectors))}
rows={6} rows={6}
name="injector" name="injector"
dataCy="credential-type-detail-injector"
/> />
<UserDateDetail <UserDateDetail
label={t`Created`} label={t`Created`}

View File

@@ -18,7 +18,10 @@ function CredentialTypeListItem({
const labelId = `check-action-${credentialType.id}`; const labelId = `check-action-${credentialType.id}`;
return ( return (
<Tr id={`credential-type-row-${credentialType.id}`}> <Tr
id={`credential-type-row-${credentialType.id}`}
ouiaId={`credential-type-row-${credentialType.id}`}
>
<Td <Td
select={{ select={{
rowIndex, rowIndex,

View File

@@ -117,11 +117,13 @@ function Dashboard() {
aria-label={t`Tabs`} aria-label={t`Tabs`}
activeKey={activeTabId} activeKey={activeTabId}
onSelect={(key, eventKey) => setActiveTabId(eventKey)} onSelect={(key, eventKey) => setActiveTabId(eventKey)}
ouiaId="dashboard-tabs"
> >
<Tab <Tab
aria-label={t`Job status graph tab`} aria-label={t`Job status graph tab`}
eventKey={0} eventKey={0}
title={<TabTitleText>{t`Job status`}</TabTitleText>} title={<TabTitleText>{t`Job status`}</TabTitleText>}
ouiaId="job-status-graph-tab"
> >
<DashboardGraph /> <DashboardGraph />
</Tab> </Tab>
@@ -129,6 +131,7 @@ function Dashboard() {
aria-label={t`Recent Jobs list tab`} aria-label={t`Recent Jobs list tab`}
eventKey={1} eventKey={1}
title={<TabTitleText>{t`Recent Jobs`}</TabTitleText>} title={<TabTitleText>{t`Recent Jobs`}</TabTitleText>}
ouiaId="recent-jobs-list-tab"
> >
<div> <div>
{activeTabId === 1 && ( {activeTabId === 1 && (
@@ -140,6 +143,7 @@ function Dashboard() {
aria-label={t`Recent Templates list tab`} aria-label={t`Recent Templates list tab`}
eventKey={2} eventKey={2}
title={<TabTitleText>{t`Recent Templates`}</TabTitleText>} title={<TabTitleText>{t`Recent Templates`}</TabTitleText>}
ouiaId="recent-templates-list-tab"
> >
<div> <div>
{activeTabId === 2 && ( {activeTabId === 2 && (

View File

@@ -104,6 +104,7 @@ function DashboardGraph() {
selections={periodSelection} selections={periodSelection}
isOpen={isPeriodDropdownOpen} isOpen={isPeriodDropdownOpen}
noResultsFoundText={t`No results found`} noResultsFoundText={t`No results found`}
ouiaId="dashboard-period-select"
> >
<SelectOption key="month" value="month"> <SelectOption key="month" value="month">
{t`Past month`} {t`Past month`}
@@ -130,6 +131,7 @@ function DashboardGraph() {
}} }}
selections={jobTypeSelection} selections={jobTypeSelection}
isOpen={isJobTypeDropdownOpen} isOpen={isJobTypeDropdownOpen}
ouiaId="dashboard-job-type-select"
> >
<SelectOption key="all" value="all"> <SelectOption key="all" value="all">
{t`All job types`} {t`All job types`}

View File

@@ -43,7 +43,10 @@ function ExecutionEnvironmentListItem({
}, []); }, []);
return ( return (
<Tr id={`ee-row-${executionEnvironment.id}`}> <Tr
id={`ee-row-${executionEnvironment.id}`}
ouiaId={`ee-row-${executionEnvironment.id}`}
>
<Td <Td
select={{ select={{
rowIndex, rowIndex,

View File

@@ -5,7 +5,10 @@ import { Tr, Td } from '@patternfly/react-table';
function ExecutionEnvironmentTemplateListItem({ template, detailUrl }) { function ExecutionEnvironmentTemplateListItem({ template, detailUrl }) {
return ( return (
<Tr id={`template-row-${template.id}`}> <Tr
id={`template-row-${template.id}`}
ouiaId={`template-row-${template.id}`}
>
<Td dataLabel={t`Name`}> <Td dataLabel={t`Name`}>
<Link to={`${detailUrl}`}>{template.name}</Link> <Link to={`${detailUrl}`}>{template.name}</Link>
</Td> </Td>

View File

@@ -91,6 +91,7 @@ function HostDetail({ host }) {
rows={4} rows={4}
value={variables} value={variables}
name="variables" name="variables"
dataCy="host-detail-variables"
/> />
</DetailList> </DetailList>
<CardActionsRow> <CardActionsRow>

View File

@@ -46,6 +46,7 @@ function HostFacts({ host }) {
rows="auto" rows="auto"
value={facts} value={facts}
name="facts" name="facts"
dataCy="host-facts-detail"
/> />
</DetailList> </DetailList>
</CardBody> </CardBody>

View File

@@ -16,7 +16,7 @@ function HostGroupItem({ group, inventoryId, isSelected, onSelect, rowIndex }) {
const editUrl = `/inventories/inventory/${inventoryId}/groups/${group.id}/edit`; const editUrl = `/inventories/inventory/${inventoryId}/groups/${group.id}/edit`;
return ( return (
<Tr id={`group-row-${group.id}`}> <Tr id={`group-row-${group.id}`} ouiaId={`group-row-${group.id}`}>
<Td <Td
select={{ select={{
rowIndex, rowIndex,

View File

@@ -30,7 +30,7 @@ function HostListItem({
return ( return (
<> <>
<Tr id={`host-row-${host.id}`}> <Tr id={`host-row-${host.id}`} ouiaId={`host-row-${host.id}`}>
<Td <Td
expand={{ expand={{
rowIndex, rowIndex,
@@ -79,7 +79,7 @@ function HostListItem({
</ActionItem> </ActionItem>
</ActionsTd> </ActionsTd>
</Tr> </Tr>
<Tr isExpanded={isExpanded}> <Tr ouiaId={`host-row-${host.id}-expanded`} isExpanded={isExpanded}>
<Td colSpan={2} /> <Td colSpan={2} />
<Td colSpan={4}> <Td colSpan={4}>
<ExpandableRowContent> <ExpandableRowContent>

View File

@@ -26,6 +26,7 @@ function SmartInventoryButton({ onClick, isDisabled, hasInvalidKeys }) {
isDisabled={isDisabled} isDisabled={isDisabled}
component="button" component="button"
onClick={onClick} onClick={onClick}
ouiaId="smart-inventory-dropdown-item"
> >
{t`Smart Inventory`} {t`Smart Inventory`}
</DropdownItem> </DropdownItem>

View File

@@ -82,6 +82,7 @@ function ContainerGroupDetails({ instanceGroup, defaultExecution }) {
} }
rows={6} rows={6}
name="pod_spec_override" name="pod_spec_override"
dataCy="container-group-detail-pod-spec-override"
/> />
)} )}
</DetailList> </DetailList>

View File

@@ -49,7 +49,7 @@ function InstanceGroupListItem({
} }
return ( return (
<Tr id={`ig-row-${instanceGroup.id}`}> <Tr id={`ig-row-${instanceGroup.id}`} ouiaId={`ig-row-${instanceGroup.id}`}>
<Td <Td
select={{ select={{
rowIndex, rowIndex,

View File

@@ -110,7 +110,10 @@ function InstanceListItem({
return ( return (
<> <>
<Tr id={`instance-row-${instance.id}`}> <Tr
id={`instance-row-${instance.id}`}
ouiaId={`instance-row-${instance.id}`}
>
<Td <Td
expand={{ expand={{
rowIndex, rowIndex,
@@ -186,7 +189,10 @@ function InstanceListItem({
</ActionItem> </ActionItem>
</ActionsTd> </ActionsTd>
</Tr> </Tr>
<Tr isExpanded={isExpanded}> <Tr
ouiaId={`instance-row-${instance.id}-expanded`}
isExpanded={isExpanded}
>
<Td colSpan={2} /> <Td colSpan={2} />
<Td colSpan={7}> <Td colSpan={7}>
<ExpandableRowContent> <ExpandableRowContent>

View File

@@ -83,9 +83,17 @@ function InventoryDetail({ inventory }) {
fullWidth fullWidth
label={t`Instance Groups`} label={t`Instance Groups`}
value={ value={
<ChipGroup numChips={5} totalChips={instanceGroups.length}> <ChipGroup
numChips={5}
totalChips={instanceGroups.length}
ouiaId="instance-group-chips"
>
{instanceGroups.map((ig) => ( {instanceGroups.map((ig) => (
<Chip key={ig.id} isReadOnly> <Chip
key={ig.id}
isReadOnly
ouiaId={`instance-group-${ig.id}-chip`}
>
{ig.name} {ig.name}
</Chip> </Chip>
))} ))}
@@ -98,6 +106,7 @@ function InventoryDetail({ inventory }) {
value={inventory.variables} value={inventory.variables}
rows={4} rows={4}
name="variables" name="variables"
dataCy="inventory-detail-variables"
/> />
<UserDateDetail <UserDateDetail
label={t`Created`} label={t`Created`}

View File

@@ -38,6 +38,7 @@ function InventoryGroupDetail({ inventoryGroup }) {
value={variables} value={variables}
rows={4} rows={4}
name="variables" name="variables"
dataCy="inventory-group-detail-variables"
/> />
<UserDateDetail label={t`Created`} date={created} user={created_by} /> <UserDateDetail label={t`Created`} date={created} user={created_by} />
<UserDateDetail <UserDateDetail

View File

@@ -161,6 +161,7 @@ function InventoryGroupHostList() {
onClick={() => setIsModalOpen(true)} onClick={() => setIsModalOpen(true)}
key={addExistingHost} key={addExistingHost}
aria-label={addExistingHost} aria-label={addExistingHost}
ouiaId="add-existing-host-dropdown-item"
> >
{addExistingHost} {addExistingHost}
</DropdownItem>, </DropdownItem>,
@@ -169,6 +170,7 @@ function InventoryGroupHostList() {
to={`${addFormUrl}`} to={`${addFormUrl}`}
key={addNewHost} key={addNewHost}
aria-label={addNewHost} aria-label={addNewHost}
ouiaId="add-new-host-dropdown-item"
> >
{addNewHost} {addNewHost}
</DropdownItem>, </DropdownItem>,

View File

@@ -28,7 +28,11 @@ function InventoryGroupHostListItem({
const labelId = `check-action-${host.id}`; const labelId = `check-action-${host.id}`;
return ( return (
<Tr id={host.id} arialabelledby={labelId}> <Tr
id={host.id}
ouiaId={`inventory-group-host-row-${host.id}`}
arialabelledby={labelId}
>
<Td <Td
select={{ select={{
rowIndex, rowIndex,

View File

@@ -22,7 +22,7 @@ function InventoryGroupItem({
const editUrl = `/inventories/inventory/${inventoryId}/groups/${group.id}/edit`; const editUrl = `/inventories/inventory/${inventoryId}/groups/${group.id}/edit`;
return ( return (
<Tr id={`group-row-${group.id}`}> <Tr id={`group-row-${group.id}`} ouiaId={`group-row-${group.id}`}>
<Td <Td
data-cy={labelId} data-cy={labelId}
select={{ select={{

View File

@@ -90,6 +90,7 @@ function InventoryHostDetail({ host }) {
rows={4} rows={4}
value={variables} value={variables}
name="variables" name="variables"
dataCy="inventory-host-detail-variables"
/> />
</DetailList> </DetailList>
<CardActionsRow> <CardActionsRow>

View File

@@ -40,6 +40,7 @@ function InventoryHostFacts({ host }) {
rows="auto" rows="auto"
value={result} value={result}
name="facts" name="facts"
dataCy="inventory-host-facts-detail"
/> />
</DetailList> </DetailList>
</CardBody> </CardBody>

View File

@@ -21,7 +21,10 @@ function InventoryHostGroupItem({
const editUrl = `/inventories/inventory/${inventoryId}/groups/${group.id}/edit`; const editUrl = `/inventories/inventory/${inventoryId}/groups/${group.id}/edit`;
return ( return (
<Tr id={`inventory-host-group-row-${group.id}`}> <Tr
id={`inventory-host-group-row-${group.id}`}
ouiaId={`inventory-host-group-row-${group.id}`}
>
<Td <Td
data-cy={labelId} data-cy={labelId}
select={{ select={{

View File

@@ -21,7 +21,7 @@ function InventoryHostItem({
const labelId = `check-action-${host.id}`; const labelId = `check-action-${host.id}`;
return ( return (
<Tr id={`host-row-${host.id}`}> <Tr id={`host-row-${host.id}`} ouiaId={`inventory-host-row-${host.id}`}>
<Td <Td
data-cy={labelId} data-cy={labelId}
select={{ select={{

View File

@@ -72,7 +72,11 @@ function InventoryListItem({
} }
return ( return (
<Tr id={inventory.id} aria-labelledby={labelId}> <Tr
id={inventory.id}
aria-labelledby={labelId}
ouiaId={`inventory-row-${inventory.id}`}
>
<Td <Td
select={{ select={{
rowIndex, rowIndex,
@@ -142,6 +146,7 @@ function InventoryListItem({
onCopyStart={handleCopyStart} onCopyStart={handleCopyStart}
onCopyFinish={handleCopyFinish} onCopyFinish={handleCopyFinish}
errorMessage={t`Failed to copy inventory.`} errorMessage={t`Failed to copy inventory.`}
ouiaId={`${inventory.id}-copy-button`}
/> />
</ActionItem> </ActionItem>
</ActionsTd> </ActionsTd>

View File

@@ -148,6 +148,7 @@ function InventoryRelatedGroupList() {
key={addExistingGroup} key={addExistingGroup}
onClick={() => setIsModalOpen(true)} onClick={() => setIsModalOpen(true)}
aria-label={addExistingGroup} aria-label={addExistingGroup}
ouiaId="add-existing-group-dropdown-item"
> >
{addExistingGroup} {addExistingGroup}
</DropdownItem>, </DropdownItem>,

View File

@@ -23,7 +23,11 @@ function InventoryRelatedGroupListItem({
const labelId = `check-action-${group.id}`; const labelId = `check-action-${group.id}`;
return ( return (
<Tr id={group.id} aria-labelledby={labelId}> <Tr
id={group.id}
ouiaId={`group-row-${group.id}`}
aria-labelledby={labelId}
>
<Td <Td
select={{ select={{
rowIndex, rowIndex,

View File

@@ -255,6 +255,7 @@ function InventorySourceDetail({ inventorySource }) {
rows={4} rows={4}
value={source_vars} value={source_vars}
name="source_vars" name="source_vars"
dataCy="inventory-source-detail-variables"
/> />
)} )}
<UserDateDetail date={created} label={t`Created`} user={created_by} /> <UserDateDetail date={created} label={t`Created`} user={created_by} />

View File

@@ -58,7 +58,7 @@ function InventorySourceListItem({
return ( return (
<> <>
<Tr id={`source-row-${source.id}`}> <Tr id={`source-row-${source.id}`} ouiaId={`source-row-${source.id}`}>
<Td <Td
data-cy={`check-action-${source.id}`} data-cy={`check-action-${source.id}`}
select={{ select={{

View File

@@ -121,9 +121,17 @@ function SmartInventoryDetail({ inventory }) {
fullWidth fullWidth
label={t`Instance groups`} label={t`Instance groups`}
value={ value={
<ChipGroup numChips={5} totalChips={instanceGroups.length}> <ChipGroup
numChips={5}
totalChips={instanceGroups.length}
ouiaId="instance-group-chips"
>
{instanceGroups.map((ig) => ( {instanceGroups.map((ig) => (
<Chip key={ig.id} isReadOnly> <Chip
key={ig.id}
isReadOnly
ouiaId={`instance-group-${ig.id}-chip`}
>
{ig.name} {ig.name}
</Chip> </Chip>
))} ))}
@@ -136,6 +144,7 @@ function SmartInventoryDetail({ inventory }) {
value={variables} value={variables}
rows={4} rows={4}
name="variables" name="variables"
dataCy="smart-inventory-detail-variables"
/> />
<UserDateDetail label={t`Created`} date={created} user={created_by} /> <UserDateDetail label={t`Created`} date={created} user={created_by} />
<UserDateDetail <UserDateDetail

View File

@@ -55,6 +55,7 @@ function SmartInventoryHostDetail({ host }) {
rows={4} rows={4}
value={variables} value={variables}
name="variables" name="variables"
dataCy="smart-inventory-host-detail-variables"
/> />
</DetailList> </DetailList>
</CardBody> </CardBody>

View File

@@ -22,7 +22,7 @@ function SmartInventoryHostListItem({
})); }));
return ( return (
<Tr id={`host-row-${host.id}`}> <Tr id={`host-row-${host.id}`} ouiaId={`host-row-${host.id}`}>
<Td <Td
select={{ select={{
rowIndex, rowIndex,

View File

@@ -63,6 +63,7 @@ const InventoryGroupsDeleteModal = ({ onAfterDelete, isDisabled, groups }) => {
component="button" component="button"
aria-label={t`Delete`} aria-label={t`Delete`}
onClick={() => setIsModalOpen(true)} onClick={() => setIsModalOpen(true)}
ouiaId="group-delete-dropdown-item"
> >
{t`Delete`} {t`Delete`}
</DropdownItem> </DropdownItem>
@@ -72,6 +73,7 @@ const InventoryGroupsDeleteModal = ({ onAfterDelete, isDisabled, groups }) => {
aria-label={t`Delete`} aria-label={t`Delete`}
onClick={() => setIsModalOpen(true)} onClick={() => setIsModalOpen(true)}
isDisabled={isDisabled || isDeleteLoading} isDisabled={isDisabled || isDeleteLoading}
ouiaId="group-delete-button"
> >
{t`Delete`} {t`Delete`}
</Button> </Button>
@@ -95,6 +97,7 @@ const InventoryGroupsDeleteModal = ({ onAfterDelete, isDisabled, groups }) => {
variant="danger" variant="danger"
key="delete" key="delete"
isDisabled={radioOption === null} isDisabled={radioOption === null}
ouiaId="delete-modal-confirm-button"
> >
{t`Delete`} {t`Delete`}
</Button>, </Button>,
@@ -103,6 +106,7 @@ const InventoryGroupsDeleteModal = ({ onAfterDelete, isDisabled, groups }) => {
onClick={() => setIsModalOpen(false)} onClick={() => setIsModalOpen(false)}
variant="link" variant="link"
key="cancel" key="cancel"
ouiaId="delete-modal-cancel-button"
> >
{t`Cancel`} {t`Cancel`}
</Button>, </Button>,
@@ -126,6 +130,7 @@ const InventoryGroupsDeleteModal = ({ onAfterDelete, isDisabled, groups }) => {
label={t`Delete All Groups and Hosts`} label={t`Delete All Groups and Hosts`}
name="option" name="option"
onChange={() => setRadioOption('delete')} onChange={() => setRadioOption('delete')}
ouiaId="delete-all-radio-button"
/> />
<Radio <Radio
css="margin-top: 5px;" css="margin-top: 5px;"
@@ -134,6 +139,7 @@ const InventoryGroupsDeleteModal = ({ onAfterDelete, isDisabled, groups }) => {
label={t`Promote Child Groups and Hosts`} label={t`Promote Child Groups and Hosts`}
name="option" name="option"
onChange={() => setRadioOption('promote')} onChange={() => setRadioOption('promote')}
ouiaId="promote-radio-button"
/> />
</div> </div>
</AlertModal> </AlertModal>

View File

@@ -315,11 +315,16 @@ function JobDetail({ job, inventorySourceLabels }) {
dataCy="job-machine-credential" dataCy="job-machine-credential"
label={t`Machine Credential`} label={t`Machine Credential`}
value={ value={
<ChipGroup numChips={5} totalChips={1}> <ChipGroup
numChips={5}
totalChips={1}
ouiaId="job-machine-credential-chips"
>
<CredentialChip <CredentialChip
key={credential.id} key={credential.id}
credential={credential} credential={credential}
isReadOnly isReadOnly
ouiaId={`job-machine-credential-${credential.id}-chip`}
/> />
</ChipGroup> </ChipGroup>
} }
@@ -331,9 +336,18 @@ function JobDetail({ job, inventorySourceLabels }) {
fullWidth fullWidth
label={t`Credentials`} label={t`Credentials`}
value={ value={
<ChipGroup numChips={5} totalChips={credentials.length}> <ChipGroup
numChips={5}
totalChips={credentials.length}
ouiaId="job-credential-chips"
>
{credentials.map((c) => ( {credentials.map((c) => (
<CredentialChip key={c.id} credential={c} isReadOnly /> <CredentialChip
key={c.id}
credential={c}
isReadOnly
ouiaId={`job-credential-${c.id}-chip`}
/>
))} ))}
</ChipGroup> </ChipGroup>
} }
@@ -345,9 +359,13 @@ function JobDetail({ job, inventorySourceLabels }) {
fullWidth fullWidth
label={t`Labels`} label={t`Labels`}
value={ value={
<ChipGroup numChips={5} totalChips={labels.results.length}> <ChipGroup
numChips={5}
totalChips={labels.results.length}
ouiaId="job-label-chips"
>
{labels.results.map((l) => ( {labels.results.map((l) => (
<Chip key={l.id} isReadOnly> <Chip key={l.id} isReadOnly ouiaId={`job-label-${l.id}-chip`}>
{l.name} {l.name}
</Chip> </Chip>
))} ))}
@@ -364,9 +382,14 @@ function JobDetail({ job, inventorySourceLabels }) {
<ChipGroup <ChipGroup
numChips={5} numChips={5}
totalChips={job.job_tags.split(',').length} totalChips={job.job_tags.split(',').length}
ouiaId="job-tag-chips"
> >
{job.job_tags.split(',').map((jobTag) => ( {job.job_tags.split(',').map((jobTag) => (
<Chip key={jobTag} isReadOnly> <Chip
key={jobTag}
isReadOnly
ouiaId={`job-tag-${jobTag}-chip`}
>
{jobTag} {jobTag}
</Chip> </Chip>
))} ))}
@@ -383,9 +406,14 @@ function JobDetail({ job, inventorySourceLabels }) {
<ChipGroup <ChipGroup
numChips={5} numChips={5}
totalChips={job.skip_tags.split(',').length} totalChips={job.skip_tags.split(',').length}
ouiaId="job-skip-tag-chips"
> >
{job.skip_tags.split(',').map((skipTag) => ( {job.skip_tags.split(',').map((skipTag) => (
<Chip key={skipTag} isReadOnly> <Chip
key={skipTag}
isReadOnly
ouiaId={`job-skip-tag-${skipTag}-chip`}
>
{skipTag} {skipTag}
</Chip> </Chip>
))} ))}
@@ -418,6 +446,7 @@ function JobDetail({ job, inventorySourceLabels }) {
rows={4} rows={4}
label={t`Variables`} label={t`Variables`}
name="extra_vars" name="extra_vars"
dataCy="job-detail-extra-variables"
/> />
)} )}
{job.artifacts && ( {job.artifacts && (
@@ -429,6 +458,7 @@ function JobDetail({ job, inventorySourceLabels }) {
rows={4} rows={4}
label={t`Artifacts`} label={t`Artifacts`}
name="artifacts" name="artifacts"
dataCy="job-detail-artifacts"
/> />
)} )}
</DetailList> </DetailList>

View File

@@ -99,14 +99,17 @@ function HostEventModal({ onClose, hostEvent = {}, isOpen = false }) {
title={t`Host Details`} title={t`Host Details`}
aria-label={t`Host details modal`} aria-label={t`Host details modal`}
width="75%" width="75%"
ouiaId="host-event-modal"
> >
<Tabs <Tabs
aria-label={t`Tabs`} aria-label={t`Tabs`}
activeKey={activeTabKey} activeKey={activeTabKey}
onSelect={handleTabClick} onSelect={handleTabClick}
ouiaId="host-event-tabs"
> >
<Tab <Tab
aria-label={t`Details tab`} aria-label={t`Details tab`}
ouiaId="details-tab"
eventKey={0} eventKey={0}
title={<TabTitleText>{t`Details`}</TabTitleText>} title={<TabTitleText>{t`Details`}</TabTitleText>}
> >
@@ -139,6 +142,7 @@ function HostEventModal({ onClose, hostEvent = {}, isOpen = false }) {
eventKey={1} eventKey={1}
title={<TabTitleText>{t`JSON`}</TabTitleText>} title={<TabTitleText>{t`JSON`}</TabTitleText>}
aria-label={t`JSON tab`} aria-label={t`JSON tab`}
ouiaId="json-tab"
> >
{activeTabKey === 1 && jsonObj ? ( {activeTabKey === 1 && jsonObj ? (
<CodeEditor <CodeEditor
@@ -157,6 +161,7 @@ function HostEventModal({ onClose, hostEvent = {}, isOpen = false }) {
eventKey={2} eventKey={2}
title={<TabTitleText>{t`Standard Out`}</TabTitleText>} title={<TabTitleText>{t`Standard Out`}</TabTitleText>}
aria-label={t`Standard out tab`} aria-label={t`Standard out tab`}
ouiaId="standard-out-tab"
> >
{activeTabKey === 2 && stdOut ? ( {activeTabKey === 2 && stdOut ? (
<CodeEditor <CodeEditor
@@ -175,6 +180,7 @@ function HostEventModal({ onClose, hostEvent = {}, isOpen = false }) {
eventKey={3} eventKey={3}
title={<TabTitleText>{t`Standard Error`}</TabTitleText>} title={<TabTitleText>{t`Standard Error`}</TabTitleText>}
aria-label={t`Standard error tab`} aria-label={t`Standard error tab`}
ouiaId="standard-error-tab"
> >
{activeTabKey === 3 && stdErr ? ( {activeTabKey === 3 && stdErr ? (
<CodeEditor <CodeEditor

View File

@@ -140,6 +140,7 @@ function JobOutputSearch({
clearAllFilters={handleRemoveAllSearchTerms} clearAllFilters={handleRemoveAllSearchTerms}
collapseListedFiltersBreakpoint="lg" collapseListedFiltersBreakpoint="lg"
clearFiltersButtonText={t`Clear all filters`} clearFiltersButtonText={t`Clear all filters`}
ouiaId="job-output-toolbar"
> >
<SearchToolbarContent> <SearchToolbarContent>
<ToolbarToggleGroup toggleIcon={<SearchIcon />} breakpoint="lg"> <ToolbarToggleGroup toggleIcon={<SearchIcon />} breakpoint="lg">

View File

@@ -73,7 +73,7 @@ function WorkflowOutputToolbar({ job }) {
); );
}; };
return ( return (
<Toolbar id="workflow-output-toolbar"> <Toolbar id="workflow-output-toolbar" ouiaId="workflow-output-toolbar">
<ToolbarJob> <ToolbarJob>
<StatusIconWithMargin status={job.status} /> <StatusIconWithMargin status={job.status} />
<b>{job.name}</b> <b>{job.name}</b>

View File

@@ -152,6 +152,7 @@ function AWXLogin({ alt, isAuthenticated }) {
variant="warning" variant="warning"
isInline isInline
title={t`Your session has expired. Please log in to continue where you left off.`} title={t`Your session has expired. Please log in to continue where you left off.`}
ouiaId="session-expired-warning-alert"
/> />
) : null} ) : null}
<Formik <Formik

View File

@@ -59,9 +59,10 @@ function ManagementJobListItem({
} }
}; };
const rowId = `mgmt-jobs-row-${jobType ? jobType.replace('_', '-') : ''}`;
return ( return (
<> <>
<Tr id={`mgmt-jobs-row-${jobType ? jobType.replace('_', '-') : ''}`}> <Tr id={rowId} ouiaId={rowId}>
<Td /> <Td />
<Td dataLabel={t`Name`}> <Td dataLabel={t`Name`}>
<Link to={`${detailsUrl}`}> <Link to={`${detailsUrl}`}>

View File

@@ -181,7 +181,7 @@ function Metrics() {
<PageSection> <PageSection>
<Card> <Card>
<CardHeader> <CardHeader>
<Toolbar> <Toolbar ouiaId="metrics-toolbar">
<ToolbarContent> <ToolbarContent>
<ToolbarGroup> <ToolbarGroup>
<ToolbarItem>{t`Instance`}</ToolbarItem> <ToolbarItem>{t`Instance`}</ToolbarItem>

View File

@@ -97,7 +97,10 @@ function NotificationTemplateListItem({
return ( return (
<> <>
<Tr id={`notification-template-row-${template.id}`}> <Tr
id={`notification-template-row-${template.id}`}
ouiaId={`notification-template-row-${template.id}`}
>
<Td <Td
select={{ select={{
rowIndex, rowIndex,

View File

@@ -116,10 +116,18 @@ function OrganizationDetail({ organization }) {
fullWidth fullWidth
label={t`Instance Groups`} label={t`Instance Groups`}
value={ value={
<ChipGroup numChips={5} totalChips={instanceGroups.length}> <ChipGroup
numChips={5}
totalChips={instanceGroups.length}
ouiaId="instance-group-chips"
>
{instanceGroups.map((ig) => ( {instanceGroups.map((ig) => (
<Link to={`${buildLinkURL(ig)}${ig.id}/details`} key={ig.id}> <Link to={`${buildLinkURL(ig)}${ig.id}/details`} key={ig.id}>
<Chip key={ig.id} isReadOnly> <Chip
key={ig.id}
isReadOnly
ouiaId={`instance-group-${ig.id}-chip`}
>
{ig.name} {ig.name}
</Chip> </Chip>
</Link> </Link>
@@ -133,7 +141,11 @@ function OrganizationDetail({ organization }) {
fullWidth fullWidth
label={t`Galaxy Credentials`} label={t`Galaxy Credentials`}
value={ value={
<ChipGroup numChips={5} totalChips={galaxy_credentials.length}> <ChipGroup
numChips={5}
totalChips={galaxy_credentials.length}
ouiaId="galaxy-credential-chips"
>
{galaxy_credentials.map((credential) => ( {galaxy_credentials.map((credential) => (
<Link <Link
key={credential.id} key={credential.id}
@@ -143,6 +155,7 @@ function OrganizationDetail({ organization }) {
credential={credential} credential={credential}
key={credential.id} key={credential.id}
isReadOnly isReadOnly
ouiaId={`galaxy-credential-${credential.id}-chip`}
/> />
</Link> </Link>
))} ))}

View File

@@ -9,7 +9,10 @@ import { ExecutionEnvironment } from 'types';
function OrganizationExecEnvListItem({ executionEnvironment, detailUrl }) { function OrganizationExecEnvListItem({ executionEnvironment, detailUrl }) {
return ( return (
<Tr id={`ee-row-${executionEnvironment.id}`}> <Tr
id={`ee-row-${executionEnvironment.id}`}
ouiaId={`ee-row-${executionEnvironment.id}`}
>
<Td dataLabel={t`Name`}> <Td dataLabel={t`Name`}>
<Link to={`${detailUrl}`}>{executionEnvironment.name}</Link> <Link to={`${detailUrl}`}>{executionEnvironment.name}</Link>
</Td> </Td>

View File

@@ -32,7 +32,7 @@ function OrganizationListItem({
organization.custom_virtualenv && !organization.default_environment; organization.custom_virtualenv && !organization.default_environment;
return ( return (
<Tr id={`org-row-${organization.id}`}> <Tr id={`org-row-${organization.id}`} ouiaId={`org-row-${organization.id}`}>
<Td <Td
select={{ select={{
rowIndex, rowIndex,

Some files were not shown because too many files have changed in this diff Show More