前言
最近接到一個測試同學的需求,為了方便UI自動化定位摸吠,他們希望給每個html元素添加一個唯一標示空凸。目前我們使用的是react,所以下面方法主要針對react用戶寸痢。
方案
對于SPA應用呀洲,在頁面加載的時候會執(zhí)行對應的打包js代碼,里面一般是這樣的:
image
那其實答案已經(jīng)有了啼止,只要改變一下React.createElement道逗,增加額外的props就能解決這個需求了;但需要明白一點族壳,每次頁面刷新同一個地方的元素為唯一屬性一定是不變的憔辫,否則就失去意義了。
代碼
import React, {
ReactHTML,
ClassAttributes,
ReactNode,
HTMLAttributes,
ReactSVG,
SVGAttributes,
DOMAttributes,
} from 'react';
import md5 from 'md5';
/**
* 封裝React.createElement方法
* 使頁面創(chuàng)建元素的時候都添加一個data-key的唯一屬性仿荆,方便做自動化測試
* data-key的生成過程會先拼接元素的所有string類型屬性,并且會 自動繼承上級的data-key
* 最終由md5創(chuàng)建一個不可逆的加密
* 其他:
* 1坏平、需要注意的是拢操,如果元素存在動態(tài)的屬性,比如className舶替,那他的data-key也會不同令境;
* 2、為了保證盡可能的唯一顾瞪,在自定義attribute的基礎上增加了{attribute}-url的屬性舔庶,為了盡可能存在一個唯一屬性抛蚁;
*/
export interface ReactUniqueKeyProps {
attribute?: string; // default data-key(注意這里的格式應是 data-*)
}
const reactUniqueKey = (props?: ReactUniqueKeyProps) => {
const { attribute = 'data-key' } = props || {};
const createEle = React.createElement;
const urlKeys = {};
React.createElement = function createElement<
P extends HTMLAttributes<T> | SVGAttributes<T> | DOMAttributes<T>,
T extends HTMLElement | SVGElement | Element
>(
type: keyof ReactHTML | keyof ReactSVG | string,
props?: (ClassAttributes<T> & P) | null,
...children: ReactNode[]
) {
const keyStrings = [];
if (typeof type === 'string') {
keyStrings.push(`[label=${type}]`);
}
// 這一步會自動添加上級的attribute生成新的
if (props) {
Object.keys(props).forEach(key => {
const value = props[key];
if (typeof value === 'string') {
keyStrings.push(`[${key}=${value}]`);
}
});
}
// 盡可能保證有個唯一屬性
const url = window.location.href;
const attributesWidthUrl = [`[url=${url}]`, ...keyStrings];
let attributeKey = md5(keyStrings.join(';'));
let attributeUrl = md5(attributesWidthUrl.join(';'));
// 同頁面下記錄并防重(li元素等情況)
if (!urlKeys[url]) {
urlKeys[url] = {
index: 0,
keys: [],
};
urlKeys[url].keys.push(attributeKey);
} else {
if (urlKeys[url].keys.includes(attributeKey)) {
urlKeys[url].index += 1;
attributeKey += urlKeys[url].index;
attributeUrl += urlKeys[url].index;
} else {
urlKeys[url].keys.push(attributeKey);
}
}
const newProps = {
...props,
[attribute]: attributeKey,
[`${attribute}-url`]: attributeUrl,
};
return createEle(type, newProps, ...children);
} as any;
};
export default reactUniqueKey;
使用
在配置文件中引入并執(zhí)行即可(如app.ts)
import reactUniqueKey from './utils/react-unique-key';
reactUniqueKey();
效果
image.png
data-key-url與data-key的區(qū)別:
data-key-url: 保證每個頁面的都不同
data-key: 每個頁面相同的部分還是不變的
這樣可以提供更多的UI定位方法
其他方案
還可以通過SSR的方式,ReactDOM.hydrate 會自動給每個節(jié)點添加data-reactid惕橙,有興趣可以自行研究一下瞧甩。