Skip to content

Commit

Permalink
feat(amis): 增加部分testid,修改testid生成方式 (baidu#9506)
Browse files Browse the repository at this point in the history
  • Loading branch information
yangwei9012 committed Jan 24, 2024
1 parent 55a0618 commit 193df7c
Show file tree
Hide file tree
Showing 33 changed files with 207 additions and 139 deletions.
10 changes: 7 additions & 3 deletions packages/amis-core/src/SchemaRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {IScopedContext, ScopedContext} from './Scoped';
import {Schema, SchemaNode} from './types';
import {DebugWrapper} from './utils/debug';
import getExprProperties from './utils/filter-schema';
import {anyChanged, chainEvents, autobind} from './utils/helper';
import {anyChanged, chainEvents, autobind, TestIdBuilder} from './utils/helper';
import {SimpleMap} from './utils/SimpleMap';
import {bindEvent, dispatchEvent, RendererEvent} from './utils/renderer-event';
import {isAlive} from 'mobx-state-tree';
Expand Down Expand Up @@ -475,8 +475,12 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
(props as any).static = isStatic;
}

if (rest.env.enableTestid && props.id && !props.testid) {
props.testid = props.id;
// 优先使用组件自己的testid或者id,这个解决不了table行内的一些子元素
// 每一行都会出现这个testid的元素,只在测试工具中直接使用nth拿序号
if (props.testid || props.id || props.testIdBuilder == null) {
props.testIdBuilder = new TestIdBuilder(
rest.env.enableTestid ? props.testid || props.id : null
);
}

// 自动解析变量模式,主要是方便直接引入第三方组件库,无需为了支持变量封装一层
Expand Down
4 changes: 3 additions & 1 deletion packages/amis-core/src/factory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import {
qsparse,
string2regExp,
parseQuery,
isMobile
isMobile,
TestIdBuilder
} from './utils/helper';
import {
fetcherResult,
Expand Down Expand Up @@ -72,6 +73,7 @@ export interface RendererProps
env: RendererEnv;
$path: string; // 当前组件所在的层级信息
$schema: any; // 原始 schema 配置
testIdBuild: TestIdBuilder;
store?: IIRendererStore;
syncSuperStore?: boolean;
data: {
Expand Down
1 change: 0 additions & 1 deletion packages/amis-core/src/renderers/Item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,6 @@ export interface FormItemProps extends RendererProps {
// error string
error?: string;
showErrorMsg?: boolean;
testid?: string;
}

// 下发下去的属性
Expand Down
45 changes: 34 additions & 11 deletions packages/amis-core/src/utils/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2288,18 +2288,41 @@ export function replaceUrlParams(path: string, params: Record<string, any>) {

export const TEST_ID_KEY: 'data-testid' = 'data-testid';

export function buildTestId(testid?: string, data?: PlainObject) {
if (!testid) {
return {};
export class TestIdBuilder {
testId?: string;

static fast(testId: string) {
return {
[TEST_ID_KEY]: testId
};
}

// 为空就表示没有启用testId,后续一直返回都将是空
constructor(testId?: string) {
this.testId = testId;
}

// 生成子区域的testid生成器
getChild(childPath: string, data?: object) {
if (this.testId == null) {
return new TestIdBuilder();
}

return new TestIdBuilder(
data
? filter(`${this.testId}-${childPath}`, data)
: `${this.testId}-${childPath}`
);
}
return {
[TEST_ID_KEY]: filter(testid, data)
};
}

export function getTestId(testid?: string, data?: PlainObject) {
if (!testid) {
return undefined;
// 获取当前组件的testid
getTestId(data?: object) {
if (this.testId == null) {
return undefined;
}

return {
[TEST_ID_KEY]: data ? filter(this.testId, data) : this.testId
};
}
return buildTestId(testid, data)[TEST_ID_KEY];
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Html, render, TooltipWrapper, buildTestId} from 'amis';
import {Html, render, TestIdBuilder, TooltipWrapper} from 'amis';
import {observer} from 'mobx-react';
import React from 'react';
import cx from 'classnames';
Expand All @@ -18,6 +18,7 @@ type PanelProps = {
};
searchRendererType: string;
className?: string;
testIdBuilder?: TestIdBuilder;
};

type PanelStates = {
Expand Down Expand Up @@ -98,7 +99,7 @@ export default class RenderersPanel extends React.Component<
}

render() {
const {store, searchRendererType, className} = this.props;
const {store, searchRendererType, className, testIdBuilder} = this.props;
const grouped = this.props.groupedRenderers || {};
const keys = Object.keys(grouped);

Expand Down Expand Up @@ -189,7 +190,7 @@ export default class RenderersPanel extends React.Component<
onDragStart={(e: React.DragEvent) =>
this.handleDragStart(e, item.name)
}
{...buildTestId(testid)}
{...testIdBuilder?.getChild(testid).getTestId()}
>
<div
className="icon-box"
Expand Down
8 changes: 4 additions & 4 deletions packages/amis-ui/src/components/AsideNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
*/

import React from 'react';
import {mapTree} from 'amis-core';
import {ClassNamesFn, themeable, buildTestId} from 'amis-core';
import {TestIdBuilder, mapTree} from 'amis-core';
import {ClassNamesFn, themeable} from 'amis-core';

export type LinkItem = LinkItemProps;
interface LinkItemProps {
Expand All @@ -19,8 +19,8 @@ interface LinkItemProps {
children?: Array<LinkItem>;
path?: string;
icon?: string;
testid?: string;
component?: React.ElementType;
testIdBuilder?: TestIdBuilder;
}

export interface Navigation {
Expand Down Expand Up @@ -56,7 +56,7 @@ interface AsideNavState {
export class AsideNav extends React.Component<AsideNavProps, AsideNavState> {
static defaultProps = {
renderLink: (item: LinkItemProps) => (
<a {...buildTestId(item.testid, item)}>{item.label}</a>
<a {...item.testIdBuilder?.getTestId()}>{item.label}</a>
),
renderSubLinks: (
link: LinkItemProps,
Expand Down
10 changes: 5 additions & 5 deletions packages/amis-ui/src/components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,15 @@

import React from 'react';
import TooltipWrapper, {TooltipObject, Trigger} from './TooltipWrapper';
import {pickEventsProps} from 'amis-core';
import {ClassNamesFn, themeable, buildTestId} from 'amis-core';
import {TestIdBuilder, pickEventsProps} from 'amis-core';
import {ClassNamesFn, themeable} from 'amis-core';
import Spinner, {SpinnerExtraProps} from './Spinner';

export interface ButtonProps
extends React.DOMAttributes<HTMLButtonElement>,
SpinnerExtraProps {
id?: string;
className?: string;
testid?: string;
style?: any;
href?: string;
title?: string;
Expand All @@ -37,6 +36,7 @@ export interface ButtonProps
overrideClassName?: boolean;
loading?: boolean;
loadingClassName?: string;
testIdBuilder?: TestIdBuilder;
}

export class Button extends React.Component<ButtonProps> {
Expand Down Expand Up @@ -78,7 +78,7 @@ export class Button extends React.Component<ButtonProps> {
loadingClassName,
overrideClassName,
loadingConfig,
testid,
testIdBuilder,
...rest
} = this.props;

Expand All @@ -94,7 +94,7 @@ export class Button extends React.Component<ButtonProps> {
{...pickEventsProps(rest)}
onClick={rest.onClick && disabled ? () => {} : rest.onClick}
href={href}
{...buildTestId(testid)}
{...testIdBuilder?.getTestId()}
className={cx(
overrideClassName
? ''
Expand Down
7 changes: 5 additions & 2 deletions packages/amis-ui/src/components/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/

import React from 'react';
import {ThemeProps, themeable} from 'amis-core';
import {TestIdBuilder, ThemeProps, themeable} from 'amis-core';
import {autobind} from 'amis-core';

const preventEvent = (e: any) => e.stopPropagation();
Expand All @@ -28,6 +28,7 @@ interface CheckboxProps extends ThemeProps {
partial?: boolean;
optionType?: 'default' | 'button';
children?: React.ReactNode | Array<React.ReactNode>;
testIdBuilder?: TestIdBuilder;
}

export class Checkbox extends React.Component<CheckboxProps, any> {
Expand Down Expand Up @@ -72,7 +73,8 @@ export class Checkbox extends React.Component<CheckboxProps, any> {
name,
labelClassName,
optionType,
mobileUI
mobileUI,
testIdBuilder
} = this.props;
const _checked =
typeof checked !== 'undefined'
Expand All @@ -96,6 +98,7 @@ export class Checkbox extends React.Component<CheckboxProps, any> {
'is-mobile': mobileUI
})}
data-role="checkbox"
{...testIdBuilder?.getTestId()}
>
<input
type={type}
Expand Down
8 changes: 4 additions & 4 deletions packages/amis-ui/src/components/InputBox.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import {ThemeProps, buildTestId, themeable} from 'amis-core';
import {TestIdBuilder, ThemeProps, themeable} from 'amis-core';
import Input from './Input';
import {autobind, ucFirst} from 'amis-core';
import {Icon} from './icons';
Expand All @@ -18,7 +18,7 @@ export interface InputBoxProps
prefix?: JSX.Element;
children?: React.ReactNode | Array<React.ReactNode>;
borderMode?: 'full' | 'half' | 'none';
testid?: string;
testIdBuilder?: TestIdBuilder;
}

export interface InputBoxState {
Expand Down Expand Up @@ -85,7 +85,7 @@ export class InputBox extends React.Component<InputBoxProps, InputBoxState> {
borderMode,
onClick,
mobileUI,
testid,
testIdBuilder,
...rest
} = this.props;
const isFocused = this.state.isFocused;
Expand Down Expand Up @@ -113,7 +113,7 @@ export class InputBox extends React.Component<InputBoxProps, InputBoxState> {
onBlur={this.handleBlur}
size={12}
disabled={disabled}
{...buildTestId(testid)}
{...testIdBuilder?.getTestId()}
/>

{children}
Expand Down
23 changes: 15 additions & 8 deletions packages/amis-ui/src/components/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import {
getOptionValue,
getOptionValueBindField,
labelToString,
uncontrollable,
buildTestId
uncontrollable
} from 'amis-core';
import React from 'react';
import isInteger from 'lodash/isInteger';
Expand Down Expand Up @@ -41,7 +40,7 @@ import Checkbox from './Checkbox';
import Input from './Input';
import {LocaleProps, localeable} from 'amis-core';
import Spinner, {SpinnerExtraProps} from './Spinner';
import type {Option, Options} from 'amis-core';
import type {Option, Options, TestIdBuilder} from 'amis-core';
import {RemoteOptionsProps, withRemoteConfig} from './WithRemoteConfig';
import Picker from './Picker';
import PopUp from './PopUp';
Expand Down Expand Up @@ -95,6 +94,7 @@ export interface OptionProps {
onEdit?: (value: Option, origin?: Option, skipForm?: boolean) => void;
removable?: boolean;
onDelete?: (value: Option) => void;
testIdBuilder?: TestIdBuilder;
}

export type OptionValue = string | number | null | undefined | Option;
Expand Down Expand Up @@ -323,7 +323,6 @@ export interface SelectProps
LocaleProps,
SpinnerExtraProps {
className?: string;
testid?: string;
popoverClassName?: string;
showInvalidMatch?: boolean;
creatable: boolean;
Expand Down Expand Up @@ -1015,7 +1014,8 @@ export class Select extends React.Component<SelectProps, SelectState> {
mobileUI,
filterOption = defaultFilterOption,
overlay,
loading
loading,
testIdBuilder
} = this.props;
const {selection} = this.state;

Expand Down Expand Up @@ -1060,6 +1060,7 @@ export class Select extends React.Component<SelectProps, SelectState> {
}

let label = labelToString(item[labelField]);
let optTestIdBudr = testIdBuilder?.getChild('option');

return (
<div
Expand All @@ -1078,6 +1079,7 @@ export class Select extends React.Component<SelectProps, SelectState> {
'is-highlight': highlightedIndex === index,
'is-active': checked
})}
{...optTestIdBudr?.getTestId()}
>
{renderMenu ? (
multiple ? (
Expand All @@ -1088,6 +1090,7 @@ export class Select extends React.Component<SelectProps, SelectState> {
this.handleChange(item);
}}
disabled={item.disabled}
testIdBuilder={optTestIdBudr?.getChild('chekbx')}
>
{renderMenu(item, {
multiple,
Expand Down Expand Up @@ -1321,7 +1324,7 @@ export class Select extends React.Component<SelectProps, SelectState> {
borderMode,
mobileUI,
hasError,
testid,
testIdBuilder,
loadingConfig
} = this.props;

Expand Down Expand Up @@ -1353,7 +1356,7 @@ export class Select extends React.Component<SelectProps, SelectState> {
onClick={this.toggle}
onFocus={this.onFocus}
onBlur={this.onBlur}
{...buildTestId(testid)}
{...testIdBuilder?.getTestId()}
className={cx(
`Select`,
{
Expand Down Expand Up @@ -1383,7 +1386,11 @@ export class Select extends React.Component<SelectProps, SelectState> {
(Array.isArray(value)
? value.length
: value != null && value !== resetValue) ? (
<a onClick={this.clearValue} className={cx('Select-clear')}>
<a
onClick={this.clearValue}
className={cx('Select-clear')}
{...testIdBuilder?.getChild('clear').getTestId()}
>
<Icon icon="input-clear" className="icon" />
</a>
) : null}
Expand Down

0 comments on commit 193df7c

Please sign in to comment.