@testid/antd-testid-runtime 1.0.18 → 1.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +365 -0
- package/dist/index.d.mts +30 -1
- package/dist/index.d.ts +30 -1
- package/dist/index.js +23 -0
- package/dist/index.mjs +22 -0
- package/package.json +7 -2
package/README.md
ADDED
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
# @testid/antd-testid-runtime
|
|
2
|
+
|
|
3
|
+
运行时兜底打标模块 — MutationObserver + 锚点计数器 + 浮层计数器 + ID 重复检测。
|
|
4
|
+
|
|
5
|
+
用于 Vue 2 / Vue 3 + Ant Design Vue / Element Plus 项目的 E2E 测试,为编译期无法覆盖的动态节点和浮层节点自动注入 `data-testid` 属性。
|
|
6
|
+
|
|
7
|
+
## 特性
|
|
8
|
+
|
|
9
|
+
- **MutationObserver 自动打标** — 监听 DOM 变化,对动态插入的节点自动注入 `data-testid`
|
|
10
|
+
- **公共组件锚点定位** — 基于父模板结构定位,解决公共组件多实例 ID 重复问题
|
|
11
|
+
- **浮层独立计数器** — Modal / Drawer / Select / DatePicker 等浮层类型各自维护独立计数器
|
|
12
|
+
- **UI 库适配器** — 可插拔的适配器架构,内置 Ant Design Vue 和 Element Plus 适配器
|
|
13
|
+
- **ID 重复检测** — 按前缀分组检测重复 `data-testid`,控制台格式化告警
|
|
14
|
+
- **Vue 插件桥接** — 绕过 UI 库组件 `inheritAttrs: false` 限制(同时提供 Vue 2 和 Vue 3 版本)
|
|
15
|
+
|
|
16
|
+
## 安装
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pnpm add @testid/antd-testid-runtime
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## 快速开始
|
|
23
|
+
|
|
24
|
+
### 1. 初始化配置
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
// main.ts
|
|
28
|
+
import { initConfig, TestIdObserver, TestIdVuePlugin } from '@testid/antd-testid-runtime';
|
|
29
|
+
import { createApp } from 'vue';
|
|
30
|
+
import App from './App.vue';
|
|
31
|
+
|
|
32
|
+
const app = createApp(App);
|
|
33
|
+
|
|
34
|
+
// 初始化全局配置(必须在 Observer 启动前调用)
|
|
35
|
+
initConfig({
|
|
36
|
+
enable: import.meta.env.DEV, // 生产环境关闭
|
|
37
|
+
globalPrefix: 'myapp', // 全局前缀(可选)
|
|
38
|
+
onlyInteractive: true, // 仅给可交互元素打标
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// 注册 Vue 3 插件(绕过 inheritAttrs: false)
|
|
42
|
+
app.use(TestIdVuePlugin);
|
|
43
|
+
|
|
44
|
+
app.mount('#app');
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 2. 启动 Observer
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
// 在 App.vue mounted 或路由守卫中启动
|
|
51
|
+
import { TestIdObserver } from '@testid/antd-testid-runtime';
|
|
52
|
+
|
|
53
|
+
const observer = new TestIdObserver();
|
|
54
|
+
observer.start();
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 3. 路由切换时重置计数器
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { resetAllAnchorCounters, resetAllPopupCounters } from '@testid/antd-testid-runtime';
|
|
61
|
+
|
|
62
|
+
router.afterEach((to) => {
|
|
63
|
+
observer.setRoute(to.name as string);
|
|
64
|
+
observer.resetPopupChildCounter();
|
|
65
|
+
resetAllAnchorCounters();
|
|
66
|
+
resetAllPopupCounters();
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 4. 调试:检测重复 ID
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import { TestIdChecker } from '@testid/antd-testid-runtime';
|
|
74
|
+
|
|
75
|
+
// 在浏览器控制台执行,输出格式化告警
|
|
76
|
+
TestIdChecker.check();
|
|
77
|
+
|
|
78
|
+
// 获取统计摘要(不输出控制台)
|
|
79
|
+
const stats = TestIdChecker.getStats();
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Vue 2 项目接入
|
|
83
|
+
|
|
84
|
+
Vue 2 项目中,运行时打标逻辑(Observer、计数器、适配器)与 Vue 3 完全一致,仅插件桥接 API 不同。
|
|
85
|
+
|
|
86
|
+
### 1. 初始化配置 + 注册插件
|
|
87
|
+
|
|
88
|
+
```js
|
|
89
|
+
// main.js
|
|
90
|
+
import Vue from 'vue';
|
|
91
|
+
import { initConfig, TestIdVue2Plugin } from '@testid/antd-testid-runtime';
|
|
92
|
+
import App from './App.vue';
|
|
93
|
+
|
|
94
|
+
// 初始化全局配置
|
|
95
|
+
initConfig({
|
|
96
|
+
enable: process.env.NODE_ENV !== 'production',
|
|
97
|
+
globalPrefix: 'myapp',
|
|
98
|
+
onlyInteractive: true,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// 注册 Vue 2 插件(绕过 inheritAttrs: false)
|
|
102
|
+
Vue.use(TestIdVue2Plugin);
|
|
103
|
+
|
|
104
|
+
new Vue({
|
|
105
|
+
render: (h) => h(App),
|
|
106
|
+
}).$mount('#app');
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### 2. 启动 Observer
|
|
110
|
+
|
|
111
|
+
```js
|
|
112
|
+
// 在 App.vue mounted 或路由守卫中启动
|
|
113
|
+
import { TestIdObserver } from '@testid/antd-testid-runtime';
|
|
114
|
+
|
|
115
|
+
const observer = new TestIdObserver();
|
|
116
|
+
observer.start();
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### 3. 路由切换时重置计数器
|
|
120
|
+
|
|
121
|
+
```js
|
|
122
|
+
import { resetAllAnchorCounters, resetAllPopupCounters } from '@testid/antd-testid-runtime';
|
|
123
|
+
|
|
124
|
+
router.afterEach((to) => {
|
|
125
|
+
observer.setRoute(to.name);
|
|
126
|
+
observer.resetPopupChildCounter();
|
|
127
|
+
resetAllAnchorCounters();
|
|
128
|
+
resetAllPopupCounters();
|
|
129
|
+
});
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
> **注意**:Vue 2 使用的编译插件为 `@testid/webpack-plugin-vue2-auto-testid`(Webpack),需要搭配使用。
|
|
133
|
+
|
|
134
|
+
## testid 生成规则
|
|
135
|
+
|
|
136
|
+
### 编译期节点(由编译插件注入)
|
|
137
|
+
|
|
138
|
+
编译期节点由 Vite/Webpack 插件负责注入,本模块不处理:
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
static_page_home_tag_div_3 # 页面内静态节点
|
|
142
|
+
static_page_home__BaseSearch_button_0 # 公共组件实例(锚点定位)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### 运行时节点(由本模块注入)
|
|
146
|
+
|
|
147
|
+
| 节点类型 | ID 格式 | 示例 |
|
|
148
|
+
|---------|--------|------|
|
|
149
|
+
| 页面动态节点 | `{runtimePagePrefix}{route}_{tag}_{counter}` | `dynamic_home_button_0` |
|
|
150
|
+
| Modal 浮层 | `{runtimePagePrefix}modal_{tag}_{counter}` | `dynamic_modal_div_0` |
|
|
151
|
+
| Drawer 浮层 | `{runtimePagePrefix}drawer_{tag}_{counter}` | `dynamic_drawer_div_0` |
|
|
152
|
+
| Select 下拉 | `{runtimePagePrefix}select_{tag}_{counter}` | `dynamic_select_div_2` |
|
|
153
|
+
| DatePicker 面板 | `{runtimePagePrefix}datePicker_{tag}_{counter}` | `dynamic_datePicker_div_1` |
|
|
154
|
+
| Popover 浮层 | `{runtimePagePrefix}popover_{tag}_{counter}` | `dynamic_popover_div_0` |
|
|
155
|
+
| Dropdown 菜单 | `{runtimePagePrefix}dropdown_{tag}_{counter}` | `dynamic_dropdown_li_0` |
|
|
156
|
+
| Tooltip 提示 | `{runtimePagePrefix}tooltip_{tag}_{counter}` | `dynamic_tooltip_div_0` |
|
|
157
|
+
| Message 消息 | `{runtimePagePrefix}message_{tag}_{counter}` | `dynamic_message_div_0` |
|
|
158
|
+
| SubMenu 子菜单 | `{runtimePagePrefix}submenu_{tag}_{counter}` | `dynamic_submenu_li_0` |
|
|
159
|
+
|
|
160
|
+
## 配置项
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
interface TestIdMarkConfig {
|
|
164
|
+
/** 总开关,生产环境强制设为 false */
|
|
165
|
+
enable: boolean;
|
|
166
|
+
|
|
167
|
+
/** 全局前缀,拼接到所有 testid 之前 */
|
|
168
|
+
globalPrefix: string;
|
|
169
|
+
|
|
170
|
+
/** 编译期静态节点前缀(默认 "static_") */
|
|
171
|
+
compilePrefix: string;
|
|
172
|
+
|
|
173
|
+
/** 页面内动态节点前缀(默认 "dynamic_") */
|
|
174
|
+
runtimePagePrefix: string;
|
|
175
|
+
|
|
176
|
+
/** 浮层组件专属前缀映射 */
|
|
177
|
+
popupPrefixMap: Record<PopupType, string>;
|
|
178
|
+
|
|
179
|
+
/** UI 库适配器列表(默认 [antdAdapter]) */
|
|
180
|
+
adapters: UiAdapter[];
|
|
181
|
+
|
|
182
|
+
/** 忽略不打标的 HTML 标签 */
|
|
183
|
+
ignoreTags: string[];
|
|
184
|
+
|
|
185
|
+
/** 包含此 class 的 DOM 跳过打标 */
|
|
186
|
+
ignoreClass: string[];
|
|
187
|
+
|
|
188
|
+
/** 是否仅给可交互控件打标 */
|
|
189
|
+
onlyInteractive: boolean;
|
|
190
|
+
|
|
191
|
+
/** 路由切换时是否清空锚点局部计数器 */
|
|
192
|
+
resetInstanceOnRouteChange: boolean;
|
|
193
|
+
|
|
194
|
+
/** 路由切换时是否重置全部浮层计数器 */
|
|
195
|
+
resetPopupCounterOnRouteChange: boolean;
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### 同时使用多个 UI 库
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
import { initConfig, antdAdapter, elementAdapter } from '@testid/antd-testid-runtime';
|
|
203
|
+
|
|
204
|
+
initConfig({
|
|
205
|
+
enable: true,
|
|
206
|
+
adapters: [antdAdapter, elementAdapter], // Ant Design Vue + Element Plus
|
|
207
|
+
});
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### 自定义 CSS 前缀
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
// 例如:使用 <a-config-provider prefixCls="my-ui">
|
|
214
|
+
initConfig({
|
|
215
|
+
enable: true,
|
|
216
|
+
adapters: [{ ...antdAdapter, cssPrefixes: ['my-ui'] }],
|
|
217
|
+
});
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## 处理器决策树
|
|
221
|
+
|
|
222
|
+
Observer 对每个新增 DOM 节点的处理按以下优先级执行:
|
|
223
|
+
|
|
224
|
+
```
|
|
225
|
+
0. 已有 data-testid → 跳过
|
|
226
|
+
1. 带 data-test-base-key → 公共组件实例 → 锚点定位 + 局部计数
|
|
227
|
+
2. 浮层内部子节点 → 先查祖先浮层类型 → 浮层子节点计数器
|
|
228
|
+
3. body 直系浮层根节点 → 匹配浮层 CSS class → 独立前缀 + 计数器
|
|
229
|
+
4. #app 内普通动态节点 → dynamic_ 前缀 + 页面计数器
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## 核心模块
|
|
233
|
+
|
|
234
|
+
| 模块 | 说明 |
|
|
235
|
+
|------|------|
|
|
236
|
+
| `TestIdObserver` | 基于 MutationObserver 的 DOM 监听与自动打标器,运行时核心 |
|
|
237
|
+
| `TestIdVuePlugin` | Vue 3 插件,绕过 `inheritAttrs: false` 传递属性到 DOM |
|
|
238
|
+
| `TestIdVue2Plugin` | Vue 2 插件,绕过 `inheritAttrs: false` 传递属性到 DOM |
|
|
239
|
+
| `TestIdChecker` | ID 重复检测调试工具,按前缀分组格式化告警 |
|
|
240
|
+
| `testIdAnchorCounter` | 锚点局部计数器,解决公共组件多实例 ID 重复 |
|
|
241
|
+
| `testIdPopupCounter` | 浮层独立计数器,每种浮层类型互不干扰 |
|
|
242
|
+
| `testMark` | 全局配置管理,提供 `initConfig` / `getConfig` / 默认配置 |
|
|
243
|
+
| `antdAdapter` | Ant Design Vue 适配器(CSS class 识别 + 交互标签) |
|
|
244
|
+
| `elementAdapter` | Element Plus 适配器(CSS class 识别 + 交互标签) |
|
|
245
|
+
|
|
246
|
+
## 锚点定位机制
|
|
247
|
+
|
|
248
|
+
公共组件(如 `BaseSearch`)在页面中多处使用,仅靠全局计数器无法保证 ID 稳定。锚点定位方案:
|
|
249
|
+
|
|
250
|
+
1. 编译期在组件根元素注入 `data-test-base-key="common_comp_BaseSearch_tag_button_0"`
|
|
251
|
+
2. 运行时向上查找最近带 `data-testid` 的祖先元素作为"锚点"
|
|
252
|
+
3. 在锚点下按 `(组件名, 标签名)` 维度维护局部计数器
|
|
253
|
+
4. 拼接最终 testid:`{anchorTestId}__{componentName}_{tagName}_{localIndex}`
|
|
254
|
+
|
|
255
|
+
这确保了不同位置的同一组件实例获得不同的 testid,且不因异步渲染顺序而变化。
|
|
256
|
+
|
|
257
|
+
## API 参考
|
|
258
|
+
|
|
259
|
+
### 配置
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
import { initConfig, getConfig } from '@testid/antd-testid-runtime';
|
|
263
|
+
|
|
264
|
+
// 初始化配置
|
|
265
|
+
initConfig({ enable: true, globalPrefix: 'app' });
|
|
266
|
+
|
|
267
|
+
// 获取只读配置
|
|
268
|
+
const config = getConfig();
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Observer
|
|
272
|
+
|
|
273
|
+
```ts
|
|
274
|
+
import { TestIdObserver } from '@testid/antd-testid-runtime';
|
|
275
|
+
|
|
276
|
+
const observer = new TestIdObserver();
|
|
277
|
+
|
|
278
|
+
observer.start(); // 启动 DOM 监听 + 全量扫描兜底
|
|
279
|
+
observer.stop(); // 停止监听
|
|
280
|
+
observer.setRoute('home'); // 更新当前路由名
|
|
281
|
+
observer.resetPopupChildCounter(); // 重置浮层子节点计数器
|
|
282
|
+
observer.fullScan(); // 手动全量扫描
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Vue 插件
|
|
286
|
+
|
|
287
|
+
**Vue 3:**
|
|
288
|
+
|
|
289
|
+
```ts
|
|
290
|
+
import { TestIdVuePlugin } from '@testid/antd-testid-runtime';
|
|
291
|
+
|
|
292
|
+
app.use(TestIdVuePlugin); // 必须在 app.mount() 之前调用
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
**Vue 2:**
|
|
296
|
+
|
|
297
|
+
```js
|
|
298
|
+
import Vue from 'vue';
|
|
299
|
+
import { TestIdVue2Plugin } from '@testid/antd-testid-runtime';
|
|
300
|
+
|
|
301
|
+
Vue.use(TestIdVue2Plugin); // 必须在 new Vue() 之前调用
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### 计数器
|
|
305
|
+
|
|
306
|
+
```ts
|
|
307
|
+
import {
|
|
308
|
+
getNextAnchorLocalIndex,
|
|
309
|
+
resetAllAnchorCounters,
|
|
310
|
+
parseBaseKey,
|
|
311
|
+
buildAnchorTestId,
|
|
312
|
+
getNextPopupId,
|
|
313
|
+
resetAllPopupCounters,
|
|
314
|
+
resetPopupCounter,
|
|
315
|
+
} from '@testid/antd-testid-runtime';
|
|
316
|
+
|
|
317
|
+
// 锚点计数器
|
|
318
|
+
const localIndex = getNextAnchorLocalIndex(anchorTestId, 'BaseSearch', 'button');
|
|
319
|
+
resetAllAnchorCounters();
|
|
320
|
+
const parsed = parseBaseKey('common_comp_BaseSearch_tag_button_0');
|
|
321
|
+
const testId = buildAnchorTestId('static_page_tag_div_3', 'BaseSearch', 'button', 0);
|
|
322
|
+
|
|
323
|
+
// 浮层计数器
|
|
324
|
+
const modalId = getNextPopupId('modal');
|
|
325
|
+
resetAllPopupCounters();
|
|
326
|
+
resetPopupCounter('select');
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### ID 检测
|
|
330
|
+
|
|
331
|
+
```ts
|
|
332
|
+
import { TestIdChecker } from '@testid/antd-testid-runtime';
|
|
333
|
+
|
|
334
|
+
TestIdChecker.check(); // 控制台格式化输出告警
|
|
335
|
+
const stats = TestIdChecker.getStats(); // 返回统计摘要
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
## 适配器
|
|
339
|
+
|
|
340
|
+
### 内置适配器
|
|
341
|
+
|
|
342
|
+
| 适配器 | UI 库 | CSS 前缀 |
|
|
343
|
+
|--------|------|---------|
|
|
344
|
+
| `antdAdapter` | Ant Design Vue | `ant` |
|
|
345
|
+
| `elementAdapter` | Element Plus | `el` |
|
|
346
|
+
|
|
347
|
+
### 自定义适配器
|
|
348
|
+
|
|
349
|
+
实现 `UiAdapter` 接口即可扩展支持其他 UI 库:
|
|
350
|
+
|
|
351
|
+
```ts
|
|
352
|
+
import type { UiAdapter } from '@testid/antd-testid-runtime';
|
|
353
|
+
|
|
354
|
+
const myAdapter: UiAdapter = {
|
|
355
|
+
name: 'my-ui-lib',
|
|
356
|
+
cssPrefixes: ['my'],
|
|
357
|
+
popupClassSuffixMap: { /* ... */ },
|
|
358
|
+
interactiveTags: ['my-button', 'my-input', 'button', 'input'],
|
|
359
|
+
tagPrefixPattern: /^my-/,
|
|
360
|
+
};
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
## 许可证
|
|
364
|
+
|
|
365
|
+
MIT
|
package/dist/index.d.mts
CHANGED
|
@@ -514,4 +514,33 @@ declare const TestIdVuePlugin: {
|
|
|
514
514
|
install(app: App): void;
|
|
515
515
|
};
|
|
516
516
|
|
|
517
|
-
|
|
517
|
+
/**
|
|
518
|
+
* Vue 2 插件桥接 — testIdVue2Plugin.ts
|
|
519
|
+
*
|
|
520
|
+
* 铁三角第二层 (Vue 2 版本):绕过 UI 库组件 inheritAttrs: false 的限制。
|
|
521
|
+
*
|
|
522
|
+
* 问题背景:
|
|
523
|
+
* 编译期在 <a-menu-item data-test-base-key="..."> 上注入属性,
|
|
524
|
+
* 但 Ant Design Vue 1.x 等 UI 库组件通常设置 inheritAttrs: false,
|
|
525
|
+
* 导致非 prop 属性不会自动传递到渲染后的 DOM 元素上。
|
|
526
|
+
*
|
|
527
|
+
* 解决方案:
|
|
528
|
+
* 通过 Vue.mixin({ mounted() }) 全局混入,在每个组件挂载后,
|
|
529
|
+
* 从 $attrs 中读取插件关注的属性并手动写入 $el。
|
|
530
|
+
*
|
|
531
|
+
* 对于 inheritAttrs: true (默认) 的组件,Vue 已自动应用属性到 $el,
|
|
532
|
+
* hasAttribute 检查会跳过避免重复写入。
|
|
533
|
+
*
|
|
534
|
+
* 使用方式:
|
|
535
|
+
* import Vue from 'vue';
|
|
536
|
+
* import { TestIdVue2Plugin } from '@testid/antd-testid-runtime';
|
|
537
|
+
* Vue.use(TestIdVue2Plugin); // 必须在 new Vue() 之前调用
|
|
538
|
+
*/
|
|
539
|
+
/**
|
|
540
|
+
* Vue 2 插件对象(遵循 Vue.use() 规范)
|
|
541
|
+
*/
|
|
542
|
+
declare const TestIdVue2Plugin: {
|
|
543
|
+
install(_Vue: any): void;
|
|
544
|
+
};
|
|
545
|
+
|
|
546
|
+
export { type ParsedBaseKey, type PopupType, TestIdChecker, type TestIdMarkConfig, TestIdObserver, TestIdVue2Plugin, TestIdVuePlugin, type UiAdapter, antdAdapter, buildAnchorTestId, buildPopupTestId, defaultConfig, elementAdapter, getAnchorCounterMap, getConfig, getNextAnchorLocalIndex, getNextPopupId, getPopupCounterSnapshot, initConfig, mergeConfig, parseBaseKey, resetAllAnchorCounters, resetAllPopupCounters, resetPopupCounter };
|
package/dist/index.d.ts
CHANGED
|
@@ -514,4 +514,33 @@ declare const TestIdVuePlugin: {
|
|
|
514
514
|
install(app: App): void;
|
|
515
515
|
};
|
|
516
516
|
|
|
517
|
-
|
|
517
|
+
/**
|
|
518
|
+
* Vue 2 插件桥接 — testIdVue2Plugin.ts
|
|
519
|
+
*
|
|
520
|
+
* 铁三角第二层 (Vue 2 版本):绕过 UI 库组件 inheritAttrs: false 的限制。
|
|
521
|
+
*
|
|
522
|
+
* 问题背景:
|
|
523
|
+
* 编译期在 <a-menu-item data-test-base-key="..."> 上注入属性,
|
|
524
|
+
* 但 Ant Design Vue 1.x 等 UI 库组件通常设置 inheritAttrs: false,
|
|
525
|
+
* 导致非 prop 属性不会自动传递到渲染后的 DOM 元素上。
|
|
526
|
+
*
|
|
527
|
+
* 解决方案:
|
|
528
|
+
* 通过 Vue.mixin({ mounted() }) 全局混入,在每个组件挂载后,
|
|
529
|
+
* 从 $attrs 中读取插件关注的属性并手动写入 $el。
|
|
530
|
+
*
|
|
531
|
+
* 对于 inheritAttrs: true (默认) 的组件,Vue 已自动应用属性到 $el,
|
|
532
|
+
* hasAttribute 检查会跳过避免重复写入。
|
|
533
|
+
*
|
|
534
|
+
* 使用方式:
|
|
535
|
+
* import Vue from 'vue';
|
|
536
|
+
* import { TestIdVue2Plugin } from '@testid/antd-testid-runtime';
|
|
537
|
+
* Vue.use(TestIdVue2Plugin); // 必须在 new Vue() 之前调用
|
|
538
|
+
*/
|
|
539
|
+
/**
|
|
540
|
+
* Vue 2 插件对象(遵循 Vue.use() 规范)
|
|
541
|
+
*/
|
|
542
|
+
declare const TestIdVue2Plugin: {
|
|
543
|
+
install(_Vue: any): void;
|
|
544
|
+
};
|
|
545
|
+
|
|
546
|
+
export { type ParsedBaseKey, type PopupType, TestIdChecker, type TestIdMarkConfig, TestIdObserver, TestIdVue2Plugin, TestIdVuePlugin, type UiAdapter, antdAdapter, buildAnchorTestId, buildPopupTestId, defaultConfig, elementAdapter, getAnchorCounterMap, getConfig, getNextAnchorLocalIndex, getNextPopupId, getPopupCounterSnapshot, initConfig, mergeConfig, parseBaseKey, resetAllAnchorCounters, resetAllPopupCounters, resetPopupCounter };
|
package/dist/index.js
CHANGED
|
@@ -39,6 +39,7 @@ var index_exports = {};
|
|
|
39
39
|
__export(index_exports, {
|
|
40
40
|
TestIdChecker: () => TestIdChecker,
|
|
41
41
|
TestIdObserver: () => TestIdObserver,
|
|
42
|
+
TestIdVue2Plugin: () => TestIdVue2Plugin,
|
|
42
43
|
TestIdVuePlugin: () => TestIdVuePlugin,
|
|
43
44
|
antdAdapter: () => antdAdapter,
|
|
44
45
|
buildAnchorTestId: () => buildAnchorTestId,
|
|
@@ -904,10 +905,32 @@ var TestIdVuePlugin = {
|
|
|
904
905
|
});
|
|
905
906
|
}
|
|
906
907
|
};
|
|
908
|
+
|
|
909
|
+
// src/utils/testIdVue2Plugin.ts
|
|
910
|
+
var WATCHED_ATTRS2 = ["data-testid", "data-test-base-key"];
|
|
911
|
+
var TestIdVue2Plugin = {
|
|
912
|
+
install(_Vue) {
|
|
913
|
+
_Vue.mixin({
|
|
914
|
+
mounted() {
|
|
915
|
+
const el = this.$el;
|
|
916
|
+
if (!el) return;
|
|
917
|
+
const attrs = this.$attrs || {};
|
|
918
|
+
if (!attrs || typeof attrs !== "object") return;
|
|
919
|
+
for (const attr of WATCHED_ATTRS2) {
|
|
920
|
+
const value = attrs[attr];
|
|
921
|
+
if (value != null && !el.hasAttribute(attr)) {
|
|
922
|
+
el.setAttribute(attr, String(value));
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
};
|
|
907
929
|
// Annotate the CommonJS export names for ESM import in node:
|
|
908
930
|
0 && (module.exports = {
|
|
909
931
|
TestIdChecker,
|
|
910
932
|
TestIdObserver,
|
|
933
|
+
TestIdVue2Plugin,
|
|
911
934
|
TestIdVuePlugin,
|
|
912
935
|
antdAdapter,
|
|
913
936
|
buildAnchorTestId,
|
package/dist/index.mjs
CHANGED
|
@@ -863,9 +863,31 @@ var TestIdVuePlugin = {
|
|
|
863
863
|
});
|
|
864
864
|
}
|
|
865
865
|
};
|
|
866
|
+
|
|
867
|
+
// src/utils/testIdVue2Plugin.ts
|
|
868
|
+
var WATCHED_ATTRS2 = ["data-testid", "data-test-base-key"];
|
|
869
|
+
var TestIdVue2Plugin = {
|
|
870
|
+
install(_Vue) {
|
|
871
|
+
_Vue.mixin({
|
|
872
|
+
mounted() {
|
|
873
|
+
const el = this.$el;
|
|
874
|
+
if (!el) return;
|
|
875
|
+
const attrs = this.$attrs || {};
|
|
876
|
+
if (!attrs || typeof attrs !== "object") return;
|
|
877
|
+
for (const attr of WATCHED_ATTRS2) {
|
|
878
|
+
const value = attrs[attr];
|
|
879
|
+
if (value != null && !el.hasAttribute(attr)) {
|
|
880
|
+
el.setAttribute(attr, String(value));
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
});
|
|
885
|
+
}
|
|
886
|
+
};
|
|
866
887
|
export {
|
|
867
888
|
TestIdChecker,
|
|
868
889
|
TestIdObserver,
|
|
890
|
+
TestIdVue2Plugin,
|
|
869
891
|
TestIdVuePlugin,
|
|
870
892
|
antdAdapter,
|
|
871
893
|
buildAnchorTestId,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@testid/antd-testid-runtime",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.19",
|
|
4
4
|
"description": "运行时兜底打标模块 — MutationObserver + 锚点计数器 + 浮层计数器 + ID 重复检测",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -26,7 +26,12 @@
|
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {},
|
|
28
28
|
"peerDependencies": {
|
|
29
|
-
"vue": "^3.0.0"
|
|
29
|
+
"vue": "^2.6.0 || ^3.0.0"
|
|
30
|
+
},
|
|
31
|
+
"peerDependenciesMeta": {
|
|
32
|
+
"vue": {
|
|
33
|
+
"optional": true
|
|
34
|
+
}
|
|
30
35
|
},
|
|
31
36
|
"devDependencies": {
|
|
32
37
|
"tsup": "^8.0.0",
|