@testid/antd-testid-runtime 1.0.8 → 1.0.9

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/dist/index.d.mts CHANGED
@@ -1,3 +1,52 @@
1
+ /**
2
+ * UI 库适配器接口 — adapters/types.ts
3
+ *
4
+ * 将 UI 库相关的 CSS class 命名、标签前缀、交互元素识别等逻辑
5
+ * 从核心 Observer 中解耦,实现可插拔的 UI 库支持。
6
+ *
7
+ * 每个适配器描述一个 UI 库的浮层组件识别规则,
8
+ * 多个适配器可组合使用 (如同时使用 Ant Design Vue + Element UI)。
9
+ */
10
+ /**
11
+ * 支持的浮层类型
12
+ */
13
+ type PopupType = 'modal' | 'drawer' | 'select' | 'datePicker' | 'popconfirm' | 'dropdown' | 'tooltip' | 'message';
14
+ /**
15
+ * UI 库适配器接口
16
+ *
17
+ * 实现此接口即可让 Observer 自动识别该 UI 库的浮层组件。
18
+ */
19
+ interface UiAdapter {
20
+ /** 适配器名称 (调试用) */
21
+ readonly name: string;
22
+ /** CSS 类名前缀数组 (如 AntD: ['ant'], Element: ['el']) */
23
+ readonly cssPrefixes: string[];
24
+ /**
25
+ * 浮层 CSS class 后缀映射
26
+ *
27
+ * 结构: PopupType → string[][],两层数组含义:
28
+ * - 外层: OR 关系,任一内层命中即匹配
29
+ * - 内层: AND 关系,所有 class 必须同时出现
30
+ *
31
+ * 后缀不含前缀,由 buildPopupClassMap 动态拼接。
32
+ */
33
+ readonly popupClassSuffixMap: Record<PopupType, string[][]>;
34
+ /**
35
+ * 交互标签名列表 (用于 onlyInteractive 模式)
36
+ *
37
+ * 包含 UI 库的组件标签名 (如 'a-button', 'el-input') 和原生标签 (如 'button', 'input')。
38
+ * Observer 会合并所有适配器的 interactiveTags 进行判断。
39
+ */
40
+ readonly interactiveTags: string[];
41
+ /**
42
+ * 标签前缀正则 (用于 getSimpleTag 去除 UI 库前缀)
43
+ *
44
+ * 例: AntD → /^a-/, Element → /^el-/
45
+ * 多个适配器的正则用 | 合并。
46
+ */
47
+ readonly tagPrefixPattern: RegExp;
48
+ }
49
+
1
50
  /**
2
51
  * 全局配置模块 — testMark.ts
3
52
  *
@@ -6,11 +55,9 @@
6
55
  * - 黑白名单
7
56
  * - 开关
8
57
  * - 浮层前缀映射
58
+ * - UI 库适配器
9
59
  */
10
- /**
11
- * 支持的浮层类型
12
- */
13
- type PopupType = 'modal' | 'drawer' | 'select' | 'datePicker' | 'popconfirm' | 'dropdown' | 'tooltip' | 'message';
60
+
14
61
  /**
15
62
  * 全量配置接口
16
63
  */
@@ -28,17 +75,27 @@ interface TestIdMarkConfig {
28
75
  compilePrefix: string;
29
76
  /** 页面内动态节点统一前缀 (默认 "dynamic_") */
30
77
  runtimePagePrefix: string;
31
- /** Antd 浮层组件专属前缀映射 */
78
+ /** 浮层组件专属前缀映射 */
32
79
  popupPrefixMap: Record<PopupType, string>;
33
80
  /**
34
- * Ant Design Vue CSS 类名前缀 (对应 ConfigProvider 的 prefixCls)
81
+ * UI 库适配器列表 (默认为 [antdAdapter])
82
+ *
83
+ * 每个适配器定义了一个 UI 库的浮层 CSS class 识别规则、
84
+ * 交互标签列表和标签前缀。Observer 自动合并所有适配器的规则。
35
85
  *
36
- * 支持数组,可同时匹配多个前缀体系:
37
- * 默认: ['ant'] → 匹配 .ant-modal, .ant-picker-dropdown 等
38
- * 若项目使用 <a-config-provider prefixCls="my-ui"> 则设为 ['my-ui']
39
- * 混合使用: ['ant', 'my-ui'] → 同时匹配两个体系的所有浮层组件
86
+ * 仅使用 Ant Design Vue:
87
+ * adapters: [antdAdapter]
88
+ *
89
+ * 仅使用 Element UI:
90
+ * adapters: [elementAdapter]
91
+ *
92
+ * 同时使用两种 UI 库:
93
+ * adapters: [antdAdapter, elementAdapter]
94
+ *
95
+ * 自定义 Ant Design Vue CSS 前缀 (如 <a-config-provider prefixCls="my-ui">):
96
+ * adapters: [{ ...antdAdapter, cssPrefixes: ['my-ui'] }]
40
97
  */
41
- antdClassPrefix: string[];
98
+ adapters: UiAdapter[];
42
99
  /** 忽略不打标的 HTML 标签名 */
43
100
  ignoreTags: string[];
44
101
  /** 包含此 class 的 DOM 跳过打标 */
@@ -50,10 +107,6 @@ interface TestIdMarkConfig {
50
107
  /** 路由切换时是否重置全部浮层计数器 */
51
108
  resetPopupCounterOnRouteChange: boolean;
52
109
  }
53
- /**
54
- * 交互控件白名单 (onlyInteractive === true 时生效)
55
- */
56
- declare const INTERACTIVE_TAGS: Set<string>;
57
110
  /**
58
111
  * 默认配置对象 (enable 默认为 true,由调用方传入 DEV 判断)
59
112
  */
@@ -74,6 +127,34 @@ declare function initConfig(custom?: Partial<TestIdMarkConfig>): void;
74
127
  */
75
128
  declare function getConfig(): Readonly<TestIdMarkConfig>;
76
129
 
130
+ /**
131
+ * Ant Design Vue 适配器 — adapters/antd.ts
132
+ *
133
+ * 识别 Ant Design Vue 的浮层组件:
134
+ * - ant-modal, ant-drawer, ant-select-dropdown, ant-picker-dropdown,
135
+ * ant-popover+ant-popconfirm, ant-dropdown, ant-tooltip, ant-message
136
+ *
137
+ * 支持多版本兼容:
138
+ * - Ant Design Vue 4.x: ant-picker-dropdown
139
+ * - Ant Design Vue 1.x: ant-calendar-picker-container
140
+ */
141
+
142
+ declare const antdAdapter: UiAdapter;
143
+
144
+ /**
145
+ * Element UI 适配器 — adapters/element.ts
146
+ *
147
+ * 识别 Element UI / Element Plus 的浮层组件:
148
+ * - el-dialog, el-drawer, el-select-dropdown, el-picker-panel,
149
+ * el-message-box, el-popconfirm, el-dropdown-menu,
150
+ * el-tooltip__popper, el-message
151
+ *
152
+ * 注意: el-popper 被多种组件共用 (select/dropdown/tooltip 等),
153
+ * 不单独作为识别依据,避免误匹配。
154
+ */
155
+
156
+ declare const elementAdapter: UiAdapter;
157
+
77
158
  /**
78
159
  * 锚点局部计数器 — testIdAnchorCounter.ts
79
160
  *
@@ -205,8 +286,12 @@ declare function buildPopupTestId(type: PopupType, tag: string, counterId: numbe
205
286
  */
206
287
  declare class TestIdObserver {
207
288
  private state;
208
- /** 浮层 class 匹配映射 (根据 antdClassPrefix 动态构建) */
289
+ /** 浮层 class 匹配映射 ( adapters 动态构建) */
209
290
  private popupClassMap;
291
+ /** 合并后的交互标签列表 (来自所有适配器) */
292
+ private interactiveTags;
293
+ /** 合并后的标签前缀正则 (用于 getSimpleTag) */
294
+ private tagPrefixPattern;
210
295
  constructor();
211
296
  /**
212
297
  * 启动 MutationObserver
@@ -330,17 +415,19 @@ declare class TestIdObserver {
330
415
  /**
331
416
  * 获取元素的简化标签名
332
417
  *
333
- * 处理 Antd 组件前缀: a-button → button, a-input → input
418
+ * 去除所有适配器注册的 UI 库标签前缀:
419
+ * AntD: a-button → button, a-input → input
420
+ * Element: el-button → button, el-input → input
334
421
  */
335
422
  private getSimpleTag;
336
423
  /**
337
424
  * 判断是否可交互元素
338
425
  *
339
426
  * 可交互特征:
340
- * - 交互类标签: button, input, select, textarea
427
+ * - 匹配任意适配器的交互标签 (含原生 + UI 库前缀)
341
428
  * - onclick 属性
342
- * - role="button" / role="checkbox" / role="radio"
343
- * - cursor:pointer (不检测,因为可能从 CSS 继承,误判率高)
429
+ * - role="button" / role="checkbox" / role="radio" / role="switch"
430
+ * - tabindex 属性
344
431
  */
345
432
  private isInteractive;
346
433
  /**
@@ -397,4 +484,4 @@ declare class TestIdChecker {
397
484
  private static reportGroupDuplicates;
398
485
  }
399
486
 
400
- export { INTERACTIVE_TAGS, type ParsedBaseKey, type PopupType, TestIdChecker, type TestIdMarkConfig, TestIdObserver, buildAnchorTestId, buildPopupTestId, defaultConfig, getAnchorCounterMap, getConfig, getNextAnchorLocalIndex, getNextPopupId, getPopupCounterSnapshot, initConfig, mergeConfig, parseBaseKey, resetAllAnchorCounters, resetAllPopupCounters, resetPopupCounter };
487
+ export { type ParsedBaseKey, type PopupType, TestIdChecker, type TestIdMarkConfig, TestIdObserver, type UiAdapter, antdAdapter, buildAnchorTestId, buildPopupTestId, defaultConfig, elementAdapter, getAnchorCounterMap, getConfig, getNextAnchorLocalIndex, getNextPopupId, getPopupCounterSnapshot, initConfig, mergeConfig, parseBaseKey, resetAllAnchorCounters, resetAllPopupCounters, resetPopupCounter };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,52 @@
1
+ /**
2
+ * UI 库适配器接口 — adapters/types.ts
3
+ *
4
+ * 将 UI 库相关的 CSS class 命名、标签前缀、交互元素识别等逻辑
5
+ * 从核心 Observer 中解耦,实现可插拔的 UI 库支持。
6
+ *
7
+ * 每个适配器描述一个 UI 库的浮层组件识别规则,
8
+ * 多个适配器可组合使用 (如同时使用 Ant Design Vue + Element UI)。
9
+ */
10
+ /**
11
+ * 支持的浮层类型
12
+ */
13
+ type PopupType = 'modal' | 'drawer' | 'select' | 'datePicker' | 'popconfirm' | 'dropdown' | 'tooltip' | 'message';
14
+ /**
15
+ * UI 库适配器接口
16
+ *
17
+ * 实现此接口即可让 Observer 自动识别该 UI 库的浮层组件。
18
+ */
19
+ interface UiAdapter {
20
+ /** 适配器名称 (调试用) */
21
+ readonly name: string;
22
+ /** CSS 类名前缀数组 (如 AntD: ['ant'], Element: ['el']) */
23
+ readonly cssPrefixes: string[];
24
+ /**
25
+ * 浮层 CSS class 后缀映射
26
+ *
27
+ * 结构: PopupType → string[][],两层数组含义:
28
+ * - 外层: OR 关系,任一内层命中即匹配
29
+ * - 内层: AND 关系,所有 class 必须同时出现
30
+ *
31
+ * 后缀不含前缀,由 buildPopupClassMap 动态拼接。
32
+ */
33
+ readonly popupClassSuffixMap: Record<PopupType, string[][]>;
34
+ /**
35
+ * 交互标签名列表 (用于 onlyInteractive 模式)
36
+ *
37
+ * 包含 UI 库的组件标签名 (如 'a-button', 'el-input') 和原生标签 (如 'button', 'input')。
38
+ * Observer 会合并所有适配器的 interactiveTags 进行判断。
39
+ */
40
+ readonly interactiveTags: string[];
41
+ /**
42
+ * 标签前缀正则 (用于 getSimpleTag 去除 UI 库前缀)
43
+ *
44
+ * 例: AntD → /^a-/, Element → /^el-/
45
+ * 多个适配器的正则用 | 合并。
46
+ */
47
+ readonly tagPrefixPattern: RegExp;
48
+ }
49
+
1
50
  /**
2
51
  * 全局配置模块 — testMark.ts
3
52
  *
@@ -6,11 +55,9 @@
6
55
  * - 黑白名单
7
56
  * - 开关
8
57
  * - 浮层前缀映射
58
+ * - UI 库适配器
9
59
  */
10
- /**
11
- * 支持的浮层类型
12
- */
13
- type PopupType = 'modal' | 'drawer' | 'select' | 'datePicker' | 'popconfirm' | 'dropdown' | 'tooltip' | 'message';
60
+
14
61
  /**
15
62
  * 全量配置接口
16
63
  */
@@ -28,17 +75,27 @@ interface TestIdMarkConfig {
28
75
  compilePrefix: string;
29
76
  /** 页面内动态节点统一前缀 (默认 "dynamic_") */
30
77
  runtimePagePrefix: string;
31
- /** Antd 浮层组件专属前缀映射 */
78
+ /** 浮层组件专属前缀映射 */
32
79
  popupPrefixMap: Record<PopupType, string>;
33
80
  /**
34
- * Ant Design Vue CSS 类名前缀 (对应 ConfigProvider 的 prefixCls)
81
+ * UI 库适配器列表 (默认为 [antdAdapter])
82
+ *
83
+ * 每个适配器定义了一个 UI 库的浮层 CSS class 识别规则、
84
+ * 交互标签列表和标签前缀。Observer 自动合并所有适配器的规则。
35
85
  *
36
- * 支持数组,可同时匹配多个前缀体系:
37
- * 默认: ['ant'] → 匹配 .ant-modal, .ant-picker-dropdown 等
38
- * 若项目使用 <a-config-provider prefixCls="my-ui"> 则设为 ['my-ui']
39
- * 混合使用: ['ant', 'my-ui'] → 同时匹配两个体系的所有浮层组件
86
+ * 仅使用 Ant Design Vue:
87
+ * adapters: [antdAdapter]
88
+ *
89
+ * 仅使用 Element UI:
90
+ * adapters: [elementAdapter]
91
+ *
92
+ * 同时使用两种 UI 库:
93
+ * adapters: [antdAdapter, elementAdapter]
94
+ *
95
+ * 自定义 Ant Design Vue CSS 前缀 (如 <a-config-provider prefixCls="my-ui">):
96
+ * adapters: [{ ...antdAdapter, cssPrefixes: ['my-ui'] }]
40
97
  */
41
- antdClassPrefix: string[];
98
+ adapters: UiAdapter[];
42
99
  /** 忽略不打标的 HTML 标签名 */
43
100
  ignoreTags: string[];
44
101
  /** 包含此 class 的 DOM 跳过打标 */
@@ -50,10 +107,6 @@ interface TestIdMarkConfig {
50
107
  /** 路由切换时是否重置全部浮层计数器 */
51
108
  resetPopupCounterOnRouteChange: boolean;
52
109
  }
53
- /**
54
- * 交互控件白名单 (onlyInteractive === true 时生效)
55
- */
56
- declare const INTERACTIVE_TAGS: Set<string>;
57
110
  /**
58
111
  * 默认配置对象 (enable 默认为 true,由调用方传入 DEV 判断)
59
112
  */
@@ -74,6 +127,34 @@ declare function initConfig(custom?: Partial<TestIdMarkConfig>): void;
74
127
  */
75
128
  declare function getConfig(): Readonly<TestIdMarkConfig>;
76
129
 
130
+ /**
131
+ * Ant Design Vue 适配器 — adapters/antd.ts
132
+ *
133
+ * 识别 Ant Design Vue 的浮层组件:
134
+ * - ant-modal, ant-drawer, ant-select-dropdown, ant-picker-dropdown,
135
+ * ant-popover+ant-popconfirm, ant-dropdown, ant-tooltip, ant-message
136
+ *
137
+ * 支持多版本兼容:
138
+ * - Ant Design Vue 4.x: ant-picker-dropdown
139
+ * - Ant Design Vue 1.x: ant-calendar-picker-container
140
+ */
141
+
142
+ declare const antdAdapter: UiAdapter;
143
+
144
+ /**
145
+ * Element UI 适配器 — adapters/element.ts
146
+ *
147
+ * 识别 Element UI / Element Plus 的浮层组件:
148
+ * - el-dialog, el-drawer, el-select-dropdown, el-picker-panel,
149
+ * el-message-box, el-popconfirm, el-dropdown-menu,
150
+ * el-tooltip__popper, el-message
151
+ *
152
+ * 注意: el-popper 被多种组件共用 (select/dropdown/tooltip 等),
153
+ * 不单独作为识别依据,避免误匹配。
154
+ */
155
+
156
+ declare const elementAdapter: UiAdapter;
157
+
77
158
  /**
78
159
  * 锚点局部计数器 — testIdAnchorCounter.ts
79
160
  *
@@ -205,8 +286,12 @@ declare function buildPopupTestId(type: PopupType, tag: string, counterId: numbe
205
286
  */
206
287
  declare class TestIdObserver {
207
288
  private state;
208
- /** 浮层 class 匹配映射 (根据 antdClassPrefix 动态构建) */
289
+ /** 浮层 class 匹配映射 ( adapters 动态构建) */
209
290
  private popupClassMap;
291
+ /** 合并后的交互标签列表 (来自所有适配器) */
292
+ private interactiveTags;
293
+ /** 合并后的标签前缀正则 (用于 getSimpleTag) */
294
+ private tagPrefixPattern;
210
295
  constructor();
211
296
  /**
212
297
  * 启动 MutationObserver
@@ -330,17 +415,19 @@ declare class TestIdObserver {
330
415
  /**
331
416
  * 获取元素的简化标签名
332
417
  *
333
- * 处理 Antd 组件前缀: a-button → button, a-input → input
418
+ * 去除所有适配器注册的 UI 库标签前缀:
419
+ * AntD: a-button → button, a-input → input
420
+ * Element: el-button → button, el-input → input
334
421
  */
335
422
  private getSimpleTag;
336
423
  /**
337
424
  * 判断是否可交互元素
338
425
  *
339
426
  * 可交互特征:
340
- * - 交互类标签: button, input, select, textarea
427
+ * - 匹配任意适配器的交互标签 (含原生 + UI 库前缀)
341
428
  * - onclick 属性
342
- * - role="button" / role="checkbox" / role="radio"
343
- * - cursor:pointer (不检测,因为可能从 CSS 继承,误判率高)
429
+ * - role="button" / role="checkbox" / role="radio" / role="switch"
430
+ * - tabindex 属性
344
431
  */
345
432
  private isInteractive;
346
433
  /**
@@ -397,4 +484,4 @@ declare class TestIdChecker {
397
484
  private static reportGroupDuplicates;
398
485
  }
399
486
 
400
- export { INTERACTIVE_TAGS, type ParsedBaseKey, type PopupType, TestIdChecker, type TestIdMarkConfig, TestIdObserver, buildAnchorTestId, buildPopupTestId, defaultConfig, getAnchorCounterMap, getConfig, getNextAnchorLocalIndex, getNextPopupId, getPopupCounterSnapshot, initConfig, mergeConfig, parseBaseKey, resetAllAnchorCounters, resetAllPopupCounters, resetPopupCounter };
487
+ export { type ParsedBaseKey, type PopupType, TestIdChecker, type TestIdMarkConfig, TestIdObserver, type UiAdapter, antdAdapter, buildAnchorTestId, buildPopupTestId, defaultConfig, elementAdapter, getAnchorCounterMap, getConfig, getNextAnchorLocalIndex, getNextPopupId, getPopupCounterSnapshot, initConfig, mergeConfig, parseBaseKey, resetAllAnchorCounters, resetAllPopupCounters, resetPopupCounter };
package/dist/index.js CHANGED
@@ -20,12 +20,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
- INTERACTIVE_TAGS: () => INTERACTIVE_TAGS,
24
23
  TestIdChecker: () => TestIdChecker,
25
24
  TestIdObserver: () => TestIdObserver,
25
+ antdAdapter: () => antdAdapter,
26
26
  buildAnchorTestId: () => buildAnchorTestId,
27
27
  buildPopupTestId: () => buildPopupTestId,
28
28
  defaultConfig: () => defaultConfig,
29
+ elementAdapter: () => elementAdapter,
29
30
  getAnchorCounterMap: () => getAnchorCounterMap,
30
31
  getConfig: () => getConfig,
31
32
  getNextAnchorLocalIndex: () => getNextAnchorLocalIndex,
@@ -40,27 +41,50 @@ __export(index_exports, {
40
41
  });
41
42
  module.exports = __toCommonJS(index_exports);
42
43
 
44
+ // src/adapters/antd.ts
45
+ var popupClassSuffixMap = {
46
+ modal: [["-modal"]],
47
+ drawer: [["-drawer"]],
48
+ select: [["-select-dropdown"]],
49
+ datePicker: [
50
+ ["-picker-dropdown"],
51
+ // Ant Design Vue 4.x
52
+ ["-calendar-picker-container"]
53
+ // Ant Design Vue 1.x
54
+ ],
55
+ popconfirm: [["-popover", "-popconfirm"]],
56
+ dropdown: [["-dropdown"]],
57
+ tooltip: [["-tooltip"]],
58
+ message: [["-message"]]
59
+ };
60
+ var antdAdapter = {
61
+ name: "ant-design-vue",
62
+ cssPrefixes: ["ant"],
63
+ popupClassSuffixMap,
64
+ interactiveTags: [
65
+ "button",
66
+ "input",
67
+ "select",
68
+ "textarea",
69
+ "a-button",
70
+ "a-input",
71
+ "a-input-number",
72
+ "a-select",
73
+ "a-textarea",
74
+ "a-checkbox",
75
+ "a-radio",
76
+ "a-switch"
77
+ ],
78
+ tagPrefixPattern: /^a-/
79
+ };
80
+
43
81
  // src/config/testMark.ts
44
- var INTERACTIVE_TAGS = /* @__PURE__ */ new Set([
45
- "button",
46
- "a-button",
47
- "input",
48
- "a-input",
49
- "a-input-number",
50
- "select",
51
- "a-select",
52
- "textarea",
53
- "a-textarea",
54
- "a-checkbox",
55
- "a-radio",
56
- "a-switch"
57
- ]);
58
82
  var defaultConfig = {
59
83
  enable: true,
60
84
  globalPrefix: "",
61
85
  compilePrefix: "static_",
62
86
  runtimePagePrefix: "dynamic_",
63
- antdClassPrefix: ["ant"],
87
+ adapters: [antdAdapter],
64
88
  popupPrefixMap: {
65
89
  modal: "modal_",
66
90
  drawer: "drawer_",
@@ -116,6 +140,48 @@ function getConfig() {
116
140
  return globalConfig;
117
141
  }
118
142
 
143
+ // src/adapters/element.ts
144
+ var popupClassSuffixMap2 = {
145
+ modal: [["-dialog"]],
146
+ drawer: [["-drawer"]],
147
+ select: [["-select-dropdown"]],
148
+ datePicker: [
149
+ ["-picker-panel"],
150
+ // 日期/时间选择器面板
151
+ ["-date-range-picker__content"]
152
+ // 日期范围选择器内容区
153
+ ],
154
+ popconfirm: [
155
+ ["-message-box"],
156
+ // Element MessageBox
157
+ ["-popconfirm"]
158
+ // Element Popconfirm
159
+ ],
160
+ dropdown: [["-dropdown-menu"]],
161
+ tooltip: [["-tooltip__popper"]],
162
+ message: [["-message"]]
163
+ };
164
+ var elementAdapter = {
165
+ name: "element-ui",
166
+ cssPrefixes: ["el"],
167
+ popupClassSuffixMap: popupClassSuffixMap2,
168
+ interactiveTags: [
169
+ "button",
170
+ "input",
171
+ "select",
172
+ "textarea",
173
+ "el-button",
174
+ "el-input",
175
+ "el-input-number",
176
+ "el-select",
177
+ "el-textarea",
178
+ "el-checkbox",
179
+ "el-radio",
180
+ "el-switch"
181
+ ],
182
+ tagPrefixPattern: /^el-/
183
+ };
184
+
119
185
  // src/utils/testIdAnchorCounter.ts
120
186
  var anchorCounterMap = /* @__PURE__ */ new Map();
121
187
  function buildAnchorKey(anchorTestId, componentName, tagName) {
@@ -184,33 +250,46 @@ function buildPopupTestId(type, tag, counterId) {
184
250
  return `${config.runtimePagePrefix}${popupPrefix}${tag}_${counterId}`;
185
251
  }
186
252
 
253
+ // src/adapters/types.ts
254
+ function mergeInteractiveTags(adapters) {
255
+ const set = /* @__PURE__ */ new Set();
256
+ for (const a of adapters) {
257
+ for (const tag of a.interactiveTags) {
258
+ set.add(tag);
259
+ }
260
+ }
261
+ return [...set];
262
+ }
263
+ function mergeTagPrefixPattern(adapters) {
264
+ const patterns = adapters.map((a) => a.tagPrefixPattern.source).filter(Boolean);
265
+ if (patterns.length === 0) return null;
266
+ return new RegExp(patterns.join("|"), "gi");
267
+ }
268
+
187
269
  // src/utils/testIdObserver.ts
188
- var POPUP_CLASS_SUFFIX_MAP = {
189
- modal: [["-modal"]],
190
- drawer: [["-drawer"]],
191
- select: [["-select-dropdown"]],
192
- datePicker: [
193
- ["-picker-dropdown"],
194
- // Ant Design Vue 4.x (新)
195
- ["-calendar-picker-container"]
196
- // Ant Design Vue 1.x (旧)
197
- ],
198
- popconfirm: [["-popover", "-popconfirm"]],
199
- dropdown: [["-dropdown"]],
200
- tooltip: [["-tooltip"]],
201
- message: [["-message"]]
202
- };
203
- function buildPopupClassMap(prefixes) {
270
+ function buildPopupClassMap(adapters) {
204
271
  const result = {};
205
- const entries = Object.entries(POPUP_CLASS_SUFFIX_MAP);
206
- for (const [type, suffixGroups] of entries) {
207
- const selectorSets = [];
208
- for (const suffixGroup of suffixGroups) {
209
- for (const prefix of prefixes) {
210
- selectorSets.push(suffixGroup.map((suffix) => `${prefix}${suffix}`));
272
+ const seen = /* @__PURE__ */ new Map();
273
+ for (const adapter of adapters) {
274
+ const entries = Object.entries(adapter.popupClassSuffixMap);
275
+ for (const [type, suffixGroups] of entries) {
276
+ if (!seen.has(type)) {
277
+ seen.set(type, /* @__PURE__ */ new Set());
278
+ result[type] = [];
279
+ }
280
+ const typeSeen = seen.get(type);
281
+ const selectorSets = result[type];
282
+ for (const suffixGroup of suffixGroups) {
283
+ for (const prefix of adapter.cssPrefixes) {
284
+ const classCombo = suffixGroup.map((suffix) => `${prefix}${suffix}`);
285
+ const key = classCombo.join("|");
286
+ if (!typeSeen.has(key)) {
287
+ typeSeen.add(key);
288
+ selectorSets.push(classCombo);
289
+ }
290
+ }
211
291
  }
212
292
  }
213
- result[type] = selectorSets;
214
293
  }
215
294
  return result;
216
295
  }
@@ -233,7 +312,9 @@ var TestIdObserver = class {
233
312
  }
234
313
  };
235
314
  const config = getConfig();
236
- this.popupClassMap = buildPopupClassMap(config.antdClassPrefix);
315
+ this.popupClassMap = buildPopupClassMap(config.adapters);
316
+ this.interactiveTags = mergeInteractiveTags(config.adapters);
317
+ this.tagPrefixPattern = mergeTagPrefixPattern(config.adapters);
237
318
  this.state = {
238
319
  observer: null,
239
320
  isRunning: false,
@@ -534,34 +615,29 @@ var TestIdObserver = class {
534
615
  /**
535
616
  * 获取元素的简化标签名
536
617
  *
537
- * 处理 Antd 组件前缀: a-button → button, a-input → input
618
+ * 去除所有适配器注册的 UI 库标签前缀:
619
+ * AntD: a-button → button, a-input → input
620
+ * Element: el-button → button, el-input → input
538
621
  */
539
622
  getSimpleTag(node) {
540
- return node.tagName.toLowerCase().replace(/^a-/, "");
623
+ let tag = node.tagName.toLowerCase();
624
+ if (this.tagPrefixPattern) {
625
+ tag = tag.replace(this.tagPrefixPattern, "");
626
+ }
627
+ return tag;
541
628
  }
542
629
  /**
543
630
  * 判断是否可交互元素
544
631
  *
545
632
  * 可交互特征:
546
- * - 交互类标签: button, input, select, textarea
633
+ * - 匹配任意适配器的交互标签 (含原生 + UI 库前缀)
547
634
  * - onclick 属性
548
- * - role="button" / role="checkbox" / role="radio"
549
- * - cursor:pointer (不检测,因为可能从 CSS 继承,误判率高)
635
+ * - role="button" / role="checkbox" / role="radio" / role="switch"
636
+ * - tabindex 属性
550
637
  */
551
638
  isInteractive(node) {
552
639
  const tag = node.tagName.toLowerCase();
553
- const interactiveTags = [
554
- "button",
555
- "a-button",
556
- "input",
557
- "a-input",
558
- "a-input-number",
559
- "select",
560
- "a-select",
561
- "textarea",
562
- "a-textarea"
563
- ];
564
- if (interactiveTags.includes(tag)) return true;
640
+ if (this.interactiveTags.includes(tag)) return true;
565
641
  if (node.hasAttribute("onclick")) return true;
566
642
  const role = node.getAttribute("role");
567
643
  if (role === "button" || role === "checkbox" || role === "radio" || role === "switch") {
@@ -747,12 +823,13 @@ var TestIdChecker = class {
747
823
  };
748
824
  // Annotate the CommonJS export names for ESM import in node:
749
825
  0 && (module.exports = {
750
- INTERACTIVE_TAGS,
751
826
  TestIdChecker,
752
827
  TestIdObserver,
828
+ antdAdapter,
753
829
  buildAnchorTestId,
754
830
  buildPopupTestId,
755
831
  defaultConfig,
832
+ elementAdapter,
756
833
  getAnchorCounterMap,
757
834
  getConfig,
758
835
  getNextAnchorLocalIndex,
package/dist/index.mjs CHANGED
@@ -1,24 +1,47 @@
1
+ // src/adapters/antd.ts
2
+ var popupClassSuffixMap = {
3
+ modal: [["-modal"]],
4
+ drawer: [["-drawer"]],
5
+ select: [["-select-dropdown"]],
6
+ datePicker: [
7
+ ["-picker-dropdown"],
8
+ // Ant Design Vue 4.x
9
+ ["-calendar-picker-container"]
10
+ // Ant Design Vue 1.x
11
+ ],
12
+ popconfirm: [["-popover", "-popconfirm"]],
13
+ dropdown: [["-dropdown"]],
14
+ tooltip: [["-tooltip"]],
15
+ message: [["-message"]]
16
+ };
17
+ var antdAdapter = {
18
+ name: "ant-design-vue",
19
+ cssPrefixes: ["ant"],
20
+ popupClassSuffixMap,
21
+ interactiveTags: [
22
+ "button",
23
+ "input",
24
+ "select",
25
+ "textarea",
26
+ "a-button",
27
+ "a-input",
28
+ "a-input-number",
29
+ "a-select",
30
+ "a-textarea",
31
+ "a-checkbox",
32
+ "a-radio",
33
+ "a-switch"
34
+ ],
35
+ tagPrefixPattern: /^a-/
36
+ };
37
+
1
38
  // src/config/testMark.ts
2
- var INTERACTIVE_TAGS = /* @__PURE__ */ new Set([
3
- "button",
4
- "a-button",
5
- "input",
6
- "a-input",
7
- "a-input-number",
8
- "select",
9
- "a-select",
10
- "textarea",
11
- "a-textarea",
12
- "a-checkbox",
13
- "a-radio",
14
- "a-switch"
15
- ]);
16
39
  var defaultConfig = {
17
40
  enable: true,
18
41
  globalPrefix: "",
19
42
  compilePrefix: "static_",
20
43
  runtimePagePrefix: "dynamic_",
21
- antdClassPrefix: ["ant"],
44
+ adapters: [antdAdapter],
22
45
  popupPrefixMap: {
23
46
  modal: "modal_",
24
47
  drawer: "drawer_",
@@ -74,6 +97,48 @@ function getConfig() {
74
97
  return globalConfig;
75
98
  }
76
99
 
100
+ // src/adapters/element.ts
101
+ var popupClassSuffixMap2 = {
102
+ modal: [["-dialog"]],
103
+ drawer: [["-drawer"]],
104
+ select: [["-select-dropdown"]],
105
+ datePicker: [
106
+ ["-picker-panel"],
107
+ // 日期/时间选择器面板
108
+ ["-date-range-picker__content"]
109
+ // 日期范围选择器内容区
110
+ ],
111
+ popconfirm: [
112
+ ["-message-box"],
113
+ // Element MessageBox
114
+ ["-popconfirm"]
115
+ // Element Popconfirm
116
+ ],
117
+ dropdown: [["-dropdown-menu"]],
118
+ tooltip: [["-tooltip__popper"]],
119
+ message: [["-message"]]
120
+ };
121
+ var elementAdapter = {
122
+ name: "element-ui",
123
+ cssPrefixes: ["el"],
124
+ popupClassSuffixMap: popupClassSuffixMap2,
125
+ interactiveTags: [
126
+ "button",
127
+ "input",
128
+ "select",
129
+ "textarea",
130
+ "el-button",
131
+ "el-input",
132
+ "el-input-number",
133
+ "el-select",
134
+ "el-textarea",
135
+ "el-checkbox",
136
+ "el-radio",
137
+ "el-switch"
138
+ ],
139
+ tagPrefixPattern: /^el-/
140
+ };
141
+
77
142
  // src/utils/testIdAnchorCounter.ts
78
143
  var anchorCounterMap = /* @__PURE__ */ new Map();
79
144
  function buildAnchorKey(anchorTestId, componentName, tagName) {
@@ -142,33 +207,46 @@ function buildPopupTestId(type, tag, counterId) {
142
207
  return `${config.runtimePagePrefix}${popupPrefix}${tag}_${counterId}`;
143
208
  }
144
209
 
210
+ // src/adapters/types.ts
211
+ function mergeInteractiveTags(adapters) {
212
+ const set = /* @__PURE__ */ new Set();
213
+ for (const a of adapters) {
214
+ for (const tag of a.interactiveTags) {
215
+ set.add(tag);
216
+ }
217
+ }
218
+ return [...set];
219
+ }
220
+ function mergeTagPrefixPattern(adapters) {
221
+ const patterns = adapters.map((a) => a.tagPrefixPattern.source).filter(Boolean);
222
+ if (patterns.length === 0) return null;
223
+ return new RegExp(patterns.join("|"), "gi");
224
+ }
225
+
145
226
  // src/utils/testIdObserver.ts
146
- var POPUP_CLASS_SUFFIX_MAP = {
147
- modal: [["-modal"]],
148
- drawer: [["-drawer"]],
149
- select: [["-select-dropdown"]],
150
- datePicker: [
151
- ["-picker-dropdown"],
152
- // Ant Design Vue 4.x (新)
153
- ["-calendar-picker-container"]
154
- // Ant Design Vue 1.x (旧)
155
- ],
156
- popconfirm: [["-popover", "-popconfirm"]],
157
- dropdown: [["-dropdown"]],
158
- tooltip: [["-tooltip"]],
159
- message: [["-message"]]
160
- };
161
- function buildPopupClassMap(prefixes) {
227
+ function buildPopupClassMap(adapters) {
162
228
  const result = {};
163
- const entries = Object.entries(POPUP_CLASS_SUFFIX_MAP);
164
- for (const [type, suffixGroups] of entries) {
165
- const selectorSets = [];
166
- for (const suffixGroup of suffixGroups) {
167
- for (const prefix of prefixes) {
168
- selectorSets.push(suffixGroup.map((suffix) => `${prefix}${suffix}`));
229
+ const seen = /* @__PURE__ */ new Map();
230
+ for (const adapter of adapters) {
231
+ const entries = Object.entries(adapter.popupClassSuffixMap);
232
+ for (const [type, suffixGroups] of entries) {
233
+ if (!seen.has(type)) {
234
+ seen.set(type, /* @__PURE__ */ new Set());
235
+ result[type] = [];
236
+ }
237
+ const typeSeen = seen.get(type);
238
+ const selectorSets = result[type];
239
+ for (const suffixGroup of suffixGroups) {
240
+ for (const prefix of adapter.cssPrefixes) {
241
+ const classCombo = suffixGroup.map((suffix) => `${prefix}${suffix}`);
242
+ const key = classCombo.join("|");
243
+ if (!typeSeen.has(key)) {
244
+ typeSeen.add(key);
245
+ selectorSets.push(classCombo);
246
+ }
247
+ }
169
248
  }
170
249
  }
171
- result[type] = selectorSets;
172
250
  }
173
251
  return result;
174
252
  }
@@ -191,7 +269,9 @@ var TestIdObserver = class {
191
269
  }
192
270
  };
193
271
  const config = getConfig();
194
- this.popupClassMap = buildPopupClassMap(config.antdClassPrefix);
272
+ this.popupClassMap = buildPopupClassMap(config.adapters);
273
+ this.interactiveTags = mergeInteractiveTags(config.adapters);
274
+ this.tagPrefixPattern = mergeTagPrefixPattern(config.adapters);
195
275
  this.state = {
196
276
  observer: null,
197
277
  isRunning: false,
@@ -492,34 +572,29 @@ var TestIdObserver = class {
492
572
  /**
493
573
  * 获取元素的简化标签名
494
574
  *
495
- * 处理 Antd 组件前缀: a-button → button, a-input → input
575
+ * 去除所有适配器注册的 UI 库标签前缀:
576
+ * AntD: a-button → button, a-input → input
577
+ * Element: el-button → button, el-input → input
496
578
  */
497
579
  getSimpleTag(node) {
498
- return node.tagName.toLowerCase().replace(/^a-/, "");
580
+ let tag = node.tagName.toLowerCase();
581
+ if (this.tagPrefixPattern) {
582
+ tag = tag.replace(this.tagPrefixPattern, "");
583
+ }
584
+ return tag;
499
585
  }
500
586
  /**
501
587
  * 判断是否可交互元素
502
588
  *
503
589
  * 可交互特征:
504
- * - 交互类标签: button, input, select, textarea
590
+ * - 匹配任意适配器的交互标签 (含原生 + UI 库前缀)
505
591
  * - onclick 属性
506
- * - role="button" / role="checkbox" / role="radio"
507
- * - cursor:pointer (不检测,因为可能从 CSS 继承,误判率高)
592
+ * - role="button" / role="checkbox" / role="radio" / role="switch"
593
+ * - tabindex 属性
508
594
  */
509
595
  isInteractive(node) {
510
596
  const tag = node.tagName.toLowerCase();
511
- const interactiveTags = [
512
- "button",
513
- "a-button",
514
- "input",
515
- "a-input",
516
- "a-input-number",
517
- "select",
518
- "a-select",
519
- "textarea",
520
- "a-textarea"
521
- ];
522
- if (interactiveTags.includes(tag)) return true;
597
+ if (this.interactiveTags.includes(tag)) return true;
523
598
  if (node.hasAttribute("onclick")) return true;
524
599
  const role = node.getAttribute("role");
525
600
  if (role === "button" || role === "checkbox" || role === "radio" || role === "switch") {
@@ -704,12 +779,13 @@ var TestIdChecker = class {
704
779
  }
705
780
  };
706
781
  export {
707
- INTERACTIVE_TAGS,
708
782
  TestIdChecker,
709
783
  TestIdObserver,
784
+ antdAdapter,
710
785
  buildAnchorTestId,
711
786
  buildPopupTestId,
712
787
  defaultConfig,
788
+ elementAdapter,
713
789
  getAnchorCounterMap,
714
790
  getConfig,
715
791
  getNextAnchorLocalIndex,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testid/antd-testid-runtime",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
4
4
  "description": "运行时兜底打标模块 — MutationObserver + 锚点计数器 + 浮层计数器 + ID 重复检测",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",