mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-29 18:48:45 +08:00
feat: action select nav dialog input-text input-file 增加 testid (#9462)
This commit is contained in:
parent
59145cc2e8
commit
0c59ce4f12
@ -144,4 +144,4 @@
|
||||
"printBasicPrototype": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import {compile} from 'path-to-regexp';
|
||||
|
||||
import type {Schema, PlainObject, FunctionPropertyNames} from '../types';
|
||||
|
||||
import {evalExpression} from './tpl';
|
||||
import {evalExpression, filter} from './tpl';
|
||||
import {IIRendererStore} from '../store';
|
||||
import {IFormStore} from '../store/form';
|
||||
import {autobindMethod} from './autobind';
|
||||
@ -2285,3 +2285,21 @@ export function replaceUrlParams(path: string, params: Record<string, any>) {
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
const TEST_ID_KEY: 'data-testid' = 'data-testid';
|
||||
|
||||
export function buildTestId(testid?: string, data?: PlainObject) {
|
||||
if (!testid) {
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
[TEST_ID_KEY]: filter(testid, data)
|
||||
};
|
||||
}
|
||||
|
||||
export function getTestId(testid?: string, data?: PlainObject) {
|
||||
if (!testid) {
|
||||
return undefined;
|
||||
}
|
||||
return buildTestId(testid, data)[TEST_ID_KEY];
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {Html, render, TooltipWrapper, hasIcon} from 'amis';
|
||||
import {Html, render, TooltipWrapper, buildTestId} from 'amis';
|
||||
import {observer} from 'mobx-react';
|
||||
import React from 'react';
|
||||
import cx from 'classnames';
|
||||
@ -173,6 +173,7 @@ export default class RenderersPanel extends React.Component<
|
||||
{items.map((item: any) => {
|
||||
const key = `${index}_${item.id}`;
|
||||
const usePluginIcon = isHasPluginIcon(item);
|
||||
const testid = `editor-renderer-${item.plugin.rendererName}`;
|
||||
|
||||
return (
|
||||
<div
|
||||
@ -188,6 +189,7 @@ export default class RenderersPanel extends React.Component<
|
||||
onDragStart={(e: React.DragEvent) =>
|
||||
this.handleDragStart(e, item.name)
|
||||
}
|
||||
{...buildTestId(testid)}
|
||||
>
|
||||
<div
|
||||
className="icon-box"
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
import React from 'react';
|
||||
import {mapTree} from 'amis-core';
|
||||
import {ClassNamesFn, themeable} from 'amis-core';
|
||||
import {ClassNamesFn, themeable, buildTestId} from 'amis-core';
|
||||
|
||||
export type LinkItem = LinkItemProps;
|
||||
interface LinkItemProps {
|
||||
@ -19,6 +19,7 @@ interface LinkItemProps {
|
||||
children?: Array<LinkItem>;
|
||||
path?: string;
|
||||
icon?: string;
|
||||
testid?: string;
|
||||
component?: React.ElementType;
|
||||
}
|
||||
|
||||
@ -54,7 +55,9 @@ interface AsideNavState {
|
||||
|
||||
export class AsideNav extends React.Component<AsideNavProps, AsideNavState> {
|
||||
static defaultProps = {
|
||||
renderLink: (item: LinkItemProps) => <a>{item.label}</a>,
|
||||
renderLink: (item: LinkItemProps) => (
|
||||
<a {...buildTestId(item.testid, item)}>{item.label}</a>
|
||||
),
|
||||
renderSubLinks: (
|
||||
link: LinkItemProps,
|
||||
renderLink: Function,
|
||||
|
@ -6,7 +6,7 @@
|
||||
import React from 'react';
|
||||
import TooltipWrapper, {TooltipObject, Trigger} from './TooltipWrapper';
|
||||
import {pickEventsProps} from 'amis-core';
|
||||
import {ClassNamesFn, themeable} from 'amis-core';
|
||||
import {ClassNamesFn, themeable, buildTestId} from 'amis-core';
|
||||
import Spinner, {SpinnerExtraProps} from './Spinner';
|
||||
|
||||
export interface ButtonProps
|
||||
@ -14,6 +14,7 @@ export interface ButtonProps
|
||||
SpinnerExtraProps {
|
||||
id?: string;
|
||||
className?: string;
|
||||
testid?: string;
|
||||
style?: any;
|
||||
href?: string;
|
||||
title?: string;
|
||||
@ -77,6 +78,7 @@ export class Button extends React.Component<ButtonProps> {
|
||||
loadingClassName,
|
||||
overrideClassName,
|
||||
loadingConfig,
|
||||
testid,
|
||||
...rest
|
||||
} = this.props;
|
||||
|
||||
@ -92,6 +94,7 @@ export class Button extends React.Component<ButtonProps> {
|
||||
{...pickEventsProps(rest)}
|
||||
onClick={rest.onClick && disabled ? () => {} : rest.onClick}
|
||||
href={href}
|
||||
{...buildTestId(testid)}
|
||||
className={cx(
|
||||
overrideClassName
|
||||
? ''
|
||||
|
@ -9,7 +9,8 @@ import {
|
||||
getOptionValue,
|
||||
getOptionValueBindField,
|
||||
labelToString,
|
||||
uncontrollable
|
||||
uncontrollable,
|
||||
buildTestId
|
||||
} from 'amis-core';
|
||||
import React from 'react';
|
||||
import isInteger from 'lodash/isInteger';
|
||||
@ -322,6 +323,7 @@ export interface SelectProps
|
||||
LocaleProps,
|
||||
SpinnerExtraProps {
|
||||
className?: string;
|
||||
testid?: string;
|
||||
popoverClassName?: string;
|
||||
showInvalidMatch?: boolean;
|
||||
creatable: boolean;
|
||||
@ -1319,6 +1321,7 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
||||
borderMode,
|
||||
mobileUI,
|
||||
hasError,
|
||||
testid,
|
||||
loadingConfig
|
||||
} = this.props;
|
||||
|
||||
@ -1350,6 +1353,7 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
||||
onClick={this.toggle}
|
||||
onFocus={this.onFocus}
|
||||
onBlur={this.onBlur}
|
||||
{...buildTestId(testid)}
|
||||
className={cx(
|
||||
`Select`,
|
||||
{
|
||||
|
@ -7,7 +7,7 @@
|
||||
import React from 'react';
|
||||
import pick from 'lodash/pick';
|
||||
import {Item as RcItem, MenuItemProps as RcMenuItemProps} from 'rc-menu';
|
||||
import {ClassNamesFn, themeable, createObject} from 'amis-core';
|
||||
import {ClassNamesFn, themeable, createObject, buildTestId} from 'amis-core';
|
||||
|
||||
import {Badge} from '../Badge';
|
||||
import {getIcon} from '../icons';
|
||||
@ -29,6 +29,7 @@ export interface MenuItemProps
|
||||
tooltipContainer?: HTMLElement | (() => HTMLElement);
|
||||
tooltipTrigger?: Trigger | Array<Trigger>;
|
||||
renderLink: Function;
|
||||
testid?: string;
|
||||
extra?: React.ReactNode;
|
||||
}
|
||||
|
||||
@ -90,6 +91,7 @@ export class MenuItem extends React.Component<MenuItemProps> {
|
||||
renderLink,
|
||||
extra,
|
||||
disabled,
|
||||
testid,
|
||||
id,
|
||||
data: defaultData
|
||||
} = this.props;
|
||||
@ -166,6 +168,7 @@ export class MenuItem extends React.Component<MenuItemProps> {
|
||||
data-id={link?.__id || id}
|
||||
data-depth={depth}
|
||||
onDragStart={onDragStart?.(link)}
|
||||
{...buildTestId(testid, link)}
|
||||
>
|
||||
{isCollapsedNode ? (
|
||||
<>{iconNode || labelNode}</>
|
||||
|
@ -7,7 +7,14 @@
|
||||
import React from 'react';
|
||||
import pick from 'lodash/pick';
|
||||
import {SubMenu as RcSubMenu, SubMenuProps as RcSubMenuProps} from 'rc-menu';
|
||||
import {ClassNamesFn, themeable, autobind, createObject} from 'amis-core';
|
||||
import {
|
||||
ClassNamesFn,
|
||||
themeable,
|
||||
autobind,
|
||||
createObject,
|
||||
filter,
|
||||
buildTestId
|
||||
} from 'amis-core';
|
||||
|
||||
import {getIcon, Icon} from '../icons';
|
||||
import {Badge} from '../Badge';
|
||||
@ -104,6 +111,7 @@ export class SubMenu extends React.Component<SubMenuProps> {
|
||||
disabled,
|
||||
data: defaultData,
|
||||
extra,
|
||||
testid,
|
||||
renderLink
|
||||
} = this.props;
|
||||
const isCollapsedNode = collapsed && depth === 1;
|
||||
@ -197,6 +205,7 @@ export class SubMenu extends React.Component<SubMenuProps> {
|
||||
data-id={link?.__id || id}
|
||||
data-depth={depth}
|
||||
onDragStart={onDragStart?.(link)}
|
||||
{...buildTestId(testid, link)}
|
||||
>
|
||||
{renderContent()}
|
||||
</a>
|
||||
|
@ -63,6 +63,8 @@ export interface MenuProps extends Omit<RcMenuProps, 'mode'> {
|
||||
*/
|
||||
navigations: Array<NavigationItem>;
|
||||
|
||||
testid?: string;
|
||||
|
||||
/**
|
||||
* 导航排列方式 stacked为true垂直 默认为false
|
||||
*/
|
||||
@ -577,7 +579,8 @@ export class Menu extends React.Component<MenuProps, MenuState> {
|
||||
collapsed,
|
||||
overflowedIndicator,
|
||||
overflowMaxCount,
|
||||
popupClassName
|
||||
popupClassName,
|
||||
testid
|
||||
} = this.props;
|
||||
|
||||
return list.map((item: NavigationItem, index: number) => {
|
||||
@ -613,6 +616,7 @@ export class Menu extends React.Component<MenuProps, MenuState> {
|
||||
badge={badge}
|
||||
renderLink={renderLink}
|
||||
depth={level || 1}
|
||||
testid={testid}
|
||||
popupClassName={popupClassName}
|
||||
>
|
||||
{this.renderMenuContent(item.children || [], item.depth + 1)}
|
||||
@ -634,6 +638,7 @@ export class Menu extends React.Component<MenuProps, MenuState> {
|
||||
renderLink={renderLink}
|
||||
badge={badge}
|
||||
data={data}
|
||||
testid={testid}
|
||||
depth={level || 1}
|
||||
order={index}
|
||||
overflowedIndicator={overflowedIndicator}
|
||||
|
@ -10,7 +10,8 @@ import {
|
||||
RendererProps,
|
||||
ScopedContext,
|
||||
uuid,
|
||||
setThemeClassName
|
||||
setThemeClassName,
|
||||
getTestId
|
||||
} from 'amis-core';
|
||||
import {filter} from 'amis-core';
|
||||
import {BadgeObject, Button, SpinnerExtraProps} from 'amis-ui';
|
||||
@ -23,6 +24,8 @@ export interface ButtonSchema extends BaseSchema {
|
||||
*/
|
||||
id?: string;
|
||||
|
||||
testid?: string;
|
||||
|
||||
/**
|
||||
* 是否为块状展示,默认为内联。
|
||||
*/
|
||||
@ -736,6 +739,7 @@ export class Action extends React.Component<ActionProps, ActionState> {
|
||||
wrapperCustomStyle,
|
||||
css,
|
||||
id,
|
||||
testid,
|
||||
env
|
||||
} = this.props;
|
||||
|
||||
@ -815,6 +819,7 @@ export class Action extends React.Component<ActionProps, ActionState> {
|
||||
[activeClassName || 'is-active']: isActive
|
||||
}
|
||||
)}
|
||||
testid={getTestId(testid, data)}
|
||||
style={style}
|
||||
size={size}
|
||||
level={
|
||||
|
@ -7,7 +7,8 @@ import {
|
||||
resolveVariableAndFilter,
|
||||
setVariable,
|
||||
setThemeClassName,
|
||||
ValidateError
|
||||
ValidateError,
|
||||
getTestId
|
||||
} from 'amis-core';
|
||||
import {Renderer, RendererProps} from 'amis-core';
|
||||
import {SchemaNode, Schema, ActionObject} from 'amis-core';
|
||||
@ -48,6 +49,8 @@ export interface DialogSchema extends BaseSchema {
|
||||
*/
|
||||
actions?: Array<ActionSchema>;
|
||||
|
||||
testid?: string;
|
||||
|
||||
/**
|
||||
* 内容区域
|
||||
*/
|
||||
@ -231,7 +234,7 @@ export default class Dialog extends React.Component<DialogProps> {
|
||||
}
|
||||
|
||||
buildActions(): Array<ActionSchema> {
|
||||
const {actions, confirm, translate: __} = this.props;
|
||||
const {actions, confirm, testid, translate: __} = this.props;
|
||||
|
||||
if (typeof actions !== 'undefined') {
|
||||
return actions;
|
||||
@ -240,6 +243,7 @@ export default class Dialog extends React.Component<DialogProps> {
|
||||
let ret: Array<ActionSchema> = [];
|
||||
ret.push({
|
||||
type: 'button',
|
||||
testid: getTestId(testid && `${testid}-cancel`),
|
||||
actionType: 'cancel',
|
||||
label: __('cancel')
|
||||
});
|
||||
@ -247,6 +251,7 @@ export default class Dialog extends React.Component<DialogProps> {
|
||||
if (confirm) {
|
||||
ret.push({
|
||||
type: 'button',
|
||||
testid: getTestId(testid && `${testid}-confirm`),
|
||||
actionType: 'confirm',
|
||||
label: __('confirm'),
|
||||
primary: true
|
||||
|
@ -6,7 +6,8 @@ import {
|
||||
isPureVariable,
|
||||
resolveVariableAndFilter,
|
||||
setThemeClassName,
|
||||
ValidateError
|
||||
ValidateError,
|
||||
getTestId
|
||||
} from 'amis-core';
|
||||
import {Renderer, RendererProps} from 'amis-core';
|
||||
import {SchemaNode, Schema, ActionObject} from 'amis-core';
|
||||
@ -142,6 +143,8 @@ export interface DrawerSchema extends BaseSchema {
|
||||
* 是否显示错误信息
|
||||
*/
|
||||
showErrorMsg?: boolean;
|
||||
|
||||
testid?: string;
|
||||
}
|
||||
|
||||
export type DrawerSchemaBase = Omit<DrawerSchema, 'type'>;
|
||||
@ -257,7 +260,7 @@ export default class Drawer extends React.Component<DrawerProps> {
|
||||
}
|
||||
|
||||
buildActions(): Array<ActionSchema> {
|
||||
const {actions, confirm, translate: __} = this.props;
|
||||
const {actions, confirm, testid, translate: __} = this.props;
|
||||
|
||||
if (typeof actions !== 'undefined') {
|
||||
return actions;
|
||||
@ -266,6 +269,7 @@ export default class Drawer extends React.Component<DrawerProps> {
|
||||
let ret: Array<ActionSchema> = [];
|
||||
ret.push({
|
||||
type: 'button',
|
||||
testid: getTestId(testid && `${testid}-cancel`),
|
||||
actionType: 'close',
|
||||
label: __('cancel')
|
||||
});
|
||||
@ -274,6 +278,7 @@ export default class Drawer extends React.Component<DrawerProps> {
|
||||
ret.push({
|
||||
type: 'button',
|
||||
actionType: 'confirm',
|
||||
testid: getTestId(testid && `${testid}-confirm`),
|
||||
label: __('confirm'),
|
||||
primary: true
|
||||
});
|
||||
|
@ -4,7 +4,7 @@ import {Overlay} from 'amis-core';
|
||||
import {PopOver} from 'amis-core';
|
||||
import {TooltipWrapper} from 'amis-ui';
|
||||
import {isDisabled, isVisible, noop, filterClassNameObject} from 'amis-core';
|
||||
import {filter} from 'amis-core';
|
||||
import {filter, buildTestId, getTestId} from 'amis-core';
|
||||
import {Icon, hasIcon} from 'amis-ui';
|
||||
import {
|
||||
BaseSchema,
|
||||
@ -52,6 +52,8 @@ export interface DropdownButtonSchema extends BaseSchema {
|
||||
*/
|
||||
buttons?: Array<DropdownButton>;
|
||||
|
||||
testid?: string;
|
||||
|
||||
/**
|
||||
* 内容区域
|
||||
*/
|
||||
@ -249,7 +251,7 @@ export default class DropDownButton extends React.Component<
|
||||
button: DropdownButton,
|
||||
index: number | string
|
||||
): React.ReactNode {
|
||||
const {render, classnames: cx, data, ignoreConfirm} = this.props;
|
||||
const {render, classnames: cx, data, testid, ignoreConfirm} = this.props;
|
||||
index = typeof index === 'number' ? index.toString() : index;
|
||||
|
||||
if (typeof button !== 'string' && Array.isArray(button?.children)) {
|
||||
@ -296,6 +298,9 @@ export default class DropDownButton extends React.Component<
|
||||
`button/${index}`,
|
||||
{
|
||||
type: 'button',
|
||||
testid:
|
||||
testid &&
|
||||
`${getTestId(testid, data)}-${button.testid || index}`,
|
||||
...(button as any),
|
||||
className: ''
|
||||
},
|
||||
@ -417,6 +422,7 @@ export default class DropDownButton extends React.Component<
|
||||
trigger,
|
||||
data,
|
||||
hideCaret,
|
||||
testid,
|
||||
env
|
||||
} = this.props;
|
||||
|
||||
@ -434,6 +440,7 @@ export default class DropDownButton extends React.Component<
|
||||
className
|
||||
)}
|
||||
style={style}
|
||||
{...buildTestId(testid, data)}
|
||||
onMouseEnter={trigger === 'hover' ? this.open : () => {}}
|
||||
onMouseLeave={trigger === 'hover' ? this.close : () => {}}
|
||||
ref={this.domRef}
|
||||
|
@ -3,7 +3,8 @@ import {
|
||||
FormItem,
|
||||
FormControlProps,
|
||||
prettyBytes,
|
||||
resolveEventData
|
||||
resolveEventData,
|
||||
buildTestId
|
||||
} from 'amis-core';
|
||||
import find from 'lodash/find';
|
||||
import isPlainObject from 'lodash/isPlainObject';
|
||||
@ -246,6 +247,8 @@ export interface FileControlSchema extends FormBaseControlSchema {
|
||||
* 是否为拖拽上传
|
||||
*/
|
||||
drag?: boolean;
|
||||
|
||||
testid?: string;
|
||||
}
|
||||
|
||||
export interface FileProps
|
||||
@ -1355,6 +1358,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
data,
|
||||
documentation,
|
||||
documentLink,
|
||||
testid,
|
||||
env,
|
||||
container
|
||||
} = this.props;
|
||||
@ -1415,6 +1419,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
disabled={disabled}
|
||||
{...getInputProps()}
|
||||
capture={capture as any}
|
||||
{...buildTestId(testid && `${testid}-input`)}
|
||||
/>
|
||||
|
||||
{drag || isDragActive ? (
|
||||
@ -1453,6 +1458,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
'is-disabled':
|
||||
multiple && !!maxLength && files.length >= maxLength
|
||||
})}
|
||||
testid={testid}
|
||||
tooltip={
|
||||
multiple && maxLength && files.length >= maxLength
|
||||
? __('File.maxLength', {maxLength})
|
||||
|
@ -19,7 +19,9 @@ import {
|
||||
createObject,
|
||||
setVariable,
|
||||
ucFirst,
|
||||
isEffectiveApi
|
||||
isEffectiveApi,
|
||||
getTestId,
|
||||
buildTestId
|
||||
} from 'amis-core';
|
||||
import {Icon, SpinnerExtraProps, Input, Spinner, OverflowTpl} from 'amis-ui';
|
||||
import {ActionSchema} from '../Action';
|
||||
@ -117,6 +119,8 @@ export interface TextControlSchema extends FormOptionsSchema {
|
||||
|
||||
/** 在内容为空的时候清除值 */
|
||||
clearValueOnEmpty?: boolean;
|
||||
|
||||
testid?: string;
|
||||
}
|
||||
|
||||
export type InputTextRendererEvent =
|
||||
@ -721,6 +725,7 @@ export default class TextControl extends React.PureComponent<
|
||||
themeCss,
|
||||
css,
|
||||
id,
|
||||
testid,
|
||||
nativeAutoComplete
|
||||
} = this.props;
|
||||
let type = this.props.type?.replace(/^(?:native|input)\-/, '');
|
||||
@ -794,6 +799,7 @@ export default class TextControl extends React.PureComponent<
|
||||
}
|
||||
)}
|
||||
onClick={this.handleClick}
|
||||
{...buildTestId(testid, data)}
|
||||
>
|
||||
<>
|
||||
{filteredPlaceholder &&
|
||||
@ -971,6 +977,7 @@ export default class TextControl extends React.PureComponent<
|
||||
themeCss,
|
||||
css,
|
||||
id,
|
||||
testid,
|
||||
nativeAutoComplete
|
||||
} = this.props;
|
||||
|
||||
@ -993,6 +1000,7 @@ export default class TextControl extends React.PureComponent<
|
||||
inputControlClassName,
|
||||
inputOnly ? className : ''
|
||||
)}
|
||||
{...buildTestId(testid, data)}
|
||||
>
|
||||
{prefix ? (
|
||||
<span className={cx('TextControl-inputPrefix')}>
|
||||
@ -1020,6 +1028,7 @@ export default class TextControl extends React.PureComponent<
|
||||
className={cx(nativeInputClassName, {
|
||||
'TextControl-input-password': type === 'password' && revealPassword
|
||||
})}
|
||||
{...buildTestId(testid && `${testid}-input`)}
|
||||
/>
|
||||
{clearable && !disabled && !readOnly && value ? (
|
||||
<a onClick={this.clearValue} className={cx('TextControl-clear')}>
|
||||
|
@ -175,6 +175,8 @@ export interface NavSchema extends BaseSchema {
|
||||
*/
|
||||
source?: SchemaApi;
|
||||
|
||||
testid?: string;
|
||||
|
||||
/**
|
||||
* 懒加载 api,如果不配置复用 source 接口。
|
||||
*/
|
||||
@ -852,6 +854,7 @@ export class Navigation extends React.Component<
|
||||
render,
|
||||
popOverContainer,
|
||||
env,
|
||||
testid,
|
||||
searchable
|
||||
} = this.props;
|
||||
const {dropIndicator, filteredLinks} = this.state;
|
||||
@ -916,6 +919,7 @@ export class Navigation extends React.Component<
|
||||
isOpen={(item: NavigationItem) => !!item.open}
|
||||
stacked={!!stacked}
|
||||
mode={mode}
|
||||
testid={testid}
|
||||
themeColor={themeColor}
|
||||
onSelect={this.handleClick}
|
||||
onToggle={this.toggleLink}
|
||||
|
Loading…
Reference in New Issue
Block a user