feat(amis): 增加tabs、table cell的testid (#9541)

This commit is contained in:
yangwei9012 2024-01-29 10:34:47 +08:00 committed by GitHub
parent da01d47b0e
commit 51131b64c0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 95 additions and 20 deletions

View File

@ -2325,4 +2325,12 @@ export class TestIdBuilder {
[TEST_ID_KEY]: data ? filter(this.testId, data) : this.testId
};
}
getTestIdValue(data?: object) {
if (this.testId == null) {
return undefined;
}
return data ? filter(this.testId, data) : this.testId;
}
}

View File

@ -5,7 +5,13 @@
*/
import React from 'react';
import {ClassName, localeable, LocaleProps, Schema} from 'amis-core';
import {
ClassName,
localeable,
LocaleProps,
Schema,
TestIdBuilder
} from 'amis-core';
import Transition, {ENTERED, ENTERING} from 'react-transition-group/Transition';
import {themeable, ThemeProps, noop} from 'amis-core';
import {uncontrollable} from 'amis-core';
@ -59,6 +65,7 @@ export interface TabProps extends ThemeProps {
children?: React.ReactNode | Array<React.ReactNode>;
swipeable?: boolean;
onSelect?: (eventKey: string | number) => void;
testIdBuilder?: TestIdBuilder;
}
class TabComponent extends React.PureComponent<TabProps> {
@ -113,7 +120,8 @@ class TabComponent extends React.PureComponent<TabProps> {
children,
className,
swipeable,
mobileUI
mobileUI,
testIdBuilder
} = this.props;
return (
@ -140,6 +148,7 @@ class TabComponent extends React.PureComponent<TabProps> {
onTouchMove={swipeable && mobileUI ? this.onTouchMove : noop}
onTouchEnd={swipeable && mobileUI ? this.onTouchEnd : noop}
onTouchCancel={swipeable && mobileUI ? this.onTouchEnd : noop}
{...testIdBuilder?.getTestId()}
>
{children}
</div>
@ -181,6 +190,7 @@ export interface TabsProps extends ThemeProps, LocaleProps {
collapseBtnLabel?: string;
popOverContainer?: any;
children?: React.ReactNode | Array<React.ReactNode>;
testIdBuilder?: TestIdBuilder;
}
export interface IDragInfo {
@ -586,7 +596,8 @@ export class Tabs extends React.Component<TabsProps, any> {
draggable,
showTip,
showTipClassName,
editable
editable,
testIdBuilder
} = this.props;
const {
@ -646,7 +657,9 @@ export class Tabs extends React.Component<TabsProps, any> {
)}
</a>
);
const tabTestIdBuidr = testIdBuilder?.getChild(
`tab-${typeof title === 'string' ? title : index}`
);
return (
<li
className={cx(
@ -662,6 +675,7 @@ export class Tabs extends React.Component<TabsProps, any> {
typeof title === 'string' &&
this.handleStartEdit(index, title);
}}
{...tabTestIdBuidr?.getChild('link').getTestId()}
>
{showTip ? (
<TooltipWrapper
@ -684,6 +698,7 @@ export class Tabs extends React.Component<TabsProps, any> {
this.props.onClose &&
this.props.onClose(index, eventKey ?? index);
}}
{...tabTestIdBuidr?.getChild('close').getTestId()}
>
<Icon icon="close" className={cx('Tabs-link-close-icon')} />
</span>
@ -722,7 +737,7 @@ export class Tabs extends React.Component<TabsProps, any> {
}
renderArrow(type: 'left' | 'right') {
const {mode: dMode, tabsMode} = this.props;
const {mode: dMode, tabsMode, testIdBuilder} = this.props;
const mode = tabsMode || dMode;
if (['vertical', 'sidebar'].includes(mode)) {
return;
@ -738,6 +753,7 @@ export class Tabs extends React.Component<TabsProps, any> {
'Tabs-linksContainer-arrow--' + type,
disabled && 'Tabs-linksContainer-arrow--disabled'
)}
{...testIdBuilder?.getChild(`arrow-${type}`).getTestId()}
>
<Icon icon="right-arrow-bold" className="icon" />
</div>
@ -835,7 +851,8 @@ export class Tabs extends React.Component<TabsProps, any> {
draggable,
sidePosition,
addBtnText,
mobileUI
mobileUI,
testIdBuilder
} = this.props;
const {isOverflow} = this.state;
@ -851,6 +868,7 @@ export class Tabs extends React.Component<TabsProps, any> {
<div
className={cx('Tabs-addable')}
onClick={() => this.handleAddBtn()}
{...testIdBuilder?.getChild('add-tab').getTestId()}
>
<Icon icon="plus" className={cx('Tabs-addable-icon')} />
{addBtnText}
@ -871,6 +889,7 @@ export class Tabs extends React.Component<TabsProps, any> {
className
)}
style={style}
{...testIdBuilder?.getTestId()}
>
{!['vertical', 'sidebar', 'chrome'].includes(mode) ? (
<div
@ -885,6 +904,7 @@ export class Tabs extends React.Component<TabsProps, any> {
'Tabs-linksContainer',
isOverflow && 'Tabs-linksContainer--overflow'
)}
{...testIdBuilder?.getChild('links').getTestId()}
>
{!mobileUI ? this.renderArrow('left') : null}
<div className={cx('Tabs-linksContainer-main')}>
@ -911,6 +931,7 @@ export class Tabs extends React.Component<TabsProps, any> {
'is-mobile': mobileUI
})}
role="tablist"
{...testIdBuilder?.getChild('links').getTestId()}
>
{this.renderNavs()}
{additionBtns}
@ -925,7 +946,11 @@ export class Tabs extends React.Component<TabsProps, any> {
})}
</div>
{draggable && (
<div className={cx('Tabs-drag-tip')} ref={this.dragTipRef} />
<div
className={cx('Tabs-drag-tip')}
ref={this.dragTipRef}
{...testIdBuilder?.getChild('drag').getTestId()}
/>
)}
</div>
);

View File

@ -7,7 +7,8 @@ import {
ThemeProps,
resolveVariable,
buildTrackExpression,
evalTrackExpression
evalTrackExpression,
TestIdBuilder
} from 'amis-core';
import {BadgeObject, Checkbox, Icon, Spinner} from 'amis-ui';
import React from 'react';
@ -33,6 +34,7 @@ export interface CellProps extends ThemeProps {
quickEditFormRef: any;
onImageEnlarge?: any;
translate: (key: string, ...args: Array<any>) => string;
testIdBuilder: TestIdBuilder;
}
export default function Cell({
@ -53,7 +55,8 @@ export default function Cell({
popOverContainer,
quickEditFormRef,
onImageEnlarge,
translate: __
translate: __,
testIdBuilder
}: CellProps) {
if (column.name && item.rowSpans[column.name] === 0) {
return null;
@ -77,6 +80,7 @@ export default function Cell({
<td
style={style}
className={cx(column.pristine.className, stickyClassName)}
{...testIdBuilder.getTestId()}
>
<Checkbox
classPrefix={ns}
@ -85,6 +89,7 @@ export default function Cell({
checked={item.checked || item.partial}
disabled={item.checkdisable || !item.checkable}
onChange={onCheckboxChange}
testIdBuilder={testIdBuilder.getChild('chekbx')}
/>
</td>
);
@ -95,6 +100,7 @@ export default function Cell({
className={cx(column.pristine.className, stickyClassName, {
'is-dragDisabled': !item.draggable
})}
{...testIdBuilder.getChild('drag').getTestId()}
>
{item.draggable ? <Icon icon="drag" className="icon" /> : null}
</td>
@ -111,6 +117,9 @@ export default function Cell({
// data-tooltip="展开/收起"
// data-position="top"
onClick={item.toggleExpanded}
{...testIdBuilder
.getChild(item.expanded ? 'fold' : 'expand')
.getTestId()}
>
<Icon icon="right-arrow-bold" className="icon" />
</a>
@ -142,6 +151,7 @@ export default function Cell({
key="retryBtn"
onClick={item.resetDefered}
data-tooltip={__('Options.retry', {reason: item.error})}
{...testIdBuilder.getChild('retry').getTestId()}
>
<Icon icon="retry" className="icon" />
</a>
@ -152,6 +162,9 @@ export default function Cell({
// data-tooltip="展开/收起"
// data-position="top"
onClick={item.toggleExpanded}
{...testIdBuilder
.getChild(item.expanded ? 'fold' : 'expand')
.getTestId()}
>
<Icon icon="right-arrow-bold" className="icon" />
</a>
@ -174,6 +187,7 @@ export default function Cell({
draggable
onDragStart={onDragStart}
className={cx('Table-dragBtn')}
{...testIdBuilder.getChild('drag').getTestId()}
>
<Icon icon="drag" className="icon" />
</a>
@ -245,7 +259,8 @@ export default function Cell({
{
...column.pristine,
column: column.pristine,
type: 'cell'
type: 'cell',
testid: testIdBuilder.getTestIdValue()
},
subProps
);

View File

@ -72,7 +72,8 @@ export class TableBody extends React.Component<TableBodyProps> {
renderRows(
rows: Array<any>,
columns = this.props.columns,
rowProps: any = {}
rowProps: any = {},
indexPath?: string
): any {
const {
rowClassName,
@ -99,16 +100,20 @@ export class TableBody extends React.Component<TableBodyProps> {
return rows.map((item: IRow, rowIndex: number) => {
const itemProps = buildItemProps ? buildItemProps(item, rowIndex) : null;
const rowPath = `${indexPath ? indexPath + '/' : ''}${rowIndex}`;
const rowTestBuidr = testIdBuilder?.getChild(`row-${rowPath}`);
const doms = [
<TableRow
{...itemProps}
testIdBuilder={testIdBuilder?.getChild(`row${rowIndex}`)}
testIdBuilder={rowTestBuidr}
store={store}
itemAction={itemAction}
classnames={cx}
checkOnItemClick={checkOnItemClick}
key={item.id}
itemIndex={rowIndex}
rowPath={rowPath}
item={item}
itemClassName={cx(
rowClassNameExpr
@ -147,6 +152,7 @@ export class TableBody extends React.Component<TableBodyProps> {
checkOnItemClick={checkOnItemClick}
key={`foot-${item.id}`}
itemIndex={rowIndex}
rowPath={rowPath}
item={item}
itemClassName={cx(
rowClassNameExpr
@ -167,16 +173,22 @@ export class TableBody extends React.Component<TableBodyProps> {
onQuickChange={onQuickChange}
ignoreFootableContent={ignoreFootableContent}
{...rowProps}
testIdBuilder={rowTestBuidr}
/>
);
}
} else if (item.children.length && item.expanded) {
// 嵌套表格
doms.push(
...this.renderRows(item.children, columns, {
...rowProps,
parent: item
})
...this.renderRows(
item.children,
columns,
{
...rowProps,
parent: item
},
rowPath
)
);
}
return doms;

View File

@ -45,6 +45,7 @@ interface TableRowProps extends Pick<RendererProps, 'render'> {
checkOnItemClick?: boolean;
ignoreFootableContent?: boolean;
testIdBuilder?: TestIdBuilder;
rowPath: string; // 整体行的路径,树形时需要父行序号/当前展开层级下的行序号
[propName: string]: any;
}
@ -205,6 +206,7 @@ export class TableRow extends React.PureComponent<
trRef,
isNested,
testIdBuilder,
rowPath,
...rest
} = this.props;
@ -267,6 +269,7 @@ export class TableRow extends React.PureComponent<
width: null,
rowIndex: itemIndex,
colIndex: column.index,
rowPath,
key: column.index,
onAction: this.handleAction,
onQuickChange: this.handleQuickChange,
@ -328,11 +331,11 @@ export class TableRow extends React.PureComponent<
...rest,
rowIndex: itemIndex,
colIndex: column.index,
rowPath,
key: column.id,
onAction: this.handleAction,
onQuickChange: this.handleQuickChange,
onChange: this.handleChange,
testIdBuilder: testIdBuilder?.getChild(`col${column.index}`)
onChange: this.handleChange
})
) : column.name && item.rowSpans[column.name] === 0 ? null : (
<td key={column.id}>

View File

@ -2076,7 +2076,8 @@ export default class Table extends React.Component<TableProps, object> {
classnames: cx,
canAccessSuperData,
itemBadge,
translate
translate,
testIdBuilder
} = this.props;
return (
@ -2100,6 +2101,9 @@ export default class Table extends React.Component<TableProps, object> {
quickEditFormRef={this.subFormRef}
onImageEnlarge={this.handleImageEnlarge}
translate={translate}
testIdBuilder={testIdBuilder.getChild(
`cell-${props.rowPath}-${column.index}`
)}
/>
);
}

View File

@ -763,7 +763,8 @@ export default class Tabs extends React.Component<TabsProps, TabsState> {
collapseBtnLabel,
disabled,
mobileUI,
swipeable
swipeable,
testIdBuilder
} = this.props;
const mode = tabsMode || dMode;
@ -809,6 +810,9 @@ export default class Tabs extends React.Component<TabsProps, TabsState> {
: unmountOnExit
}
onSelect={this.handleSelect}
testIdBuilder={testIdBuilder.getChild(
`tab-${typeof tab.title === 'string' ? tab.title : index}`
)}
>
{render(
`item/${index}`,
@ -850,6 +854,9 @@ export default class Tabs extends React.Component<TabsProps, TabsState> {
: unmountOnExit
}
onSelect={this.handleSelect}
testIdBuilder={testIdBuilder.getChild(
`tab-${typeof tab.title === 'string' ? tab.title : index}`
)}
>
{this.renderTab
? this.renderTab(tab, this.props, index)
@ -897,6 +904,7 @@ export default class Tabs extends React.Component<TabsProps, TabsState> {
collapseOnExceed={collapseOnExceed}
collapseBtnLabel={collapseBtnLabel}
mobileUI={mobileUI}
testIdBuilder={testIdBuilder}
>
{children}
</CTabs>