vite-plugin-vue-testid 1.1.0 → 1.1.2

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.en.md DELETED
@@ -1,377 +0,0 @@
1
- # vite-plugin-vue-testid
2
-
3
- A Vite plugin that auto-injects `data-testid` into Vue component templates via compile-time + runtime transforms, tailored for ant-design-vue 4.x. Dramatically reduces the effort of locating elements in E2E tests.
4
-
5
- ## Features
6
-
7
- - **Compile-time injection** — Automatically adds `data-testid` to component templates via Vue compiler `nodeTransform`
8
- - **Runtime injection** — Dynamically injects testIds into ant-design-vue teleported overlays (DatePicker, Cascader, Select, TreeSelect, etc.)
9
- - **`<a-table>` support** — bodyCell slot components receive unique testIds in the format `columnName + rowIndex + componentName + counter`
10
- - **Auto index destructuring** — If `#bodyCell="{ column, record }"` is missing `index`, the plugin patches it automatically
11
- - **Preserves existing testIds** — Elements with manually assigned `data-testid` are skipped
12
- - **Dual injection for teleport components** — DatePicker / RangePicker / Modal receive both `id` + `data-testid`
13
- - **Date panel mode awareness** — date / month / year / decade panels are distinguished automatically
14
- - **MutationObserver re-injection** — New DOM elements from panel switching, tree node expand/collapse are detected and injected automatically
15
- - **Extensible** — Custom component lists, testId generation rules, and overlay injection strategies are supported
16
-
17
- ---
18
-
19
- ## Installation
20
-
21
- ```bash
22
- pnpm add -D vite-plugin-vue-testid
23
- ```
24
-
25
- > Requirements: `vite >= 5.0.0`, `vue >= 3.3.0`, `@vue/compiler-core >= 3.5.0`
26
-
27
- ---
28
-
29
- ## Quick Start
30
-
31
- ### 1. Compile-time injection (`vite.config.ts`)
32
-
33
- ```ts
34
- // vite.config.ts
35
- import { defineConfig } from 'vite'
36
- import vue from '@vitejs/plugin-vue'
37
- import { createVueTestIdTransform } from 'vite-plugin-vue-testid'
38
-
39
- export default defineConfig({
40
- plugins: [
41
- vue({
42
- template: {
43
- compilerOptions: {
44
- nodeTransforms: [createVueTestIdTransform()]
45
- }
46
- }
47
- })
48
- ]
49
- })
50
- ```
51
-
52
- ### 2. Runtime injection (`main.ts`)
53
-
54
- ```ts
55
- // main.ts
56
- import { createApp } from 'vue'
57
- import App from './App.vue'
58
- import { setupAntDropdownTestIds } from 'vite-plugin-vue-testid/runtime'
59
-
60
- const app = createApp(App)
61
- app.mount('#app')
62
-
63
- // Call after mount to observe teleported panels and auto-inject testIds
64
- setupAntDropdownTestIds()
65
- ```
66
-
67
- ---
68
-
69
- ## Generated testId Examples
70
-
71
- ### Regular Components
72
-
73
- ```html
74
- <!-- Source -->
75
- <a-input />
76
- <a-select />
77
- <a-button />
78
-
79
- <!-- Compiled -->
80
- <a-input data-testid="a-input-0" />
81
- <a-select data-testid="a-select-1" />
82
- <a-button data-testid="a-button-2" />
83
- ```
84
-
85
- ### Teleport Components (Dual Injection)
86
-
87
- ```html
88
- <!-- Source -->
89
- <a-date-picker />
90
- <a-modal v-model:visible="show" title="Notice" />
91
-
92
- <!-- Compiled -->
93
- <a-date-picker id="a-date-picker-0" data-testid="a-date-picker-0" />
94
- <a-modal id="a-modal-1" data-testid="a-modal-1" />
95
- ```
96
-
97
- ### `<a-table>` bodyCell Components
98
-
99
- ```
100
- Format: ${column.dataIndex}-${index}-${componentName}-${counter}
101
-
102
- Examples:
103
- - label-0-a-input-4 (label column, row 0)
104
- - value-2-a-input-5 (value column, row 2)
105
- ```
106
-
107
- ### Runtime DatePicker Panel
108
-
109
- ```
110
- a-date-picker-0-dropdown # panel container
111
- a-date-picker-0-dropdown-prev # previous month
112
- a-date-picker-0-dropdown-next # next month
113
- a-date-picker-0-dropdown-header-date # header container
114
- a-date-picker-0-dropdown-header-month-btn # header month button
115
- a-date-picker-0-dropdown-header-year-btn # header year button
116
- a-date-picker-0-dropdown-date-2026-06-15 # date cell
117
- a-date-picker-0-dropdown-ok # OK button
118
- ```
119
-
120
- After switching to month/year panel (auto re-injected by MutationObserver):
121
-
122
- ```
123
- a-date-picker-0-dropdown-header-month # month panel header
124
- a-date-picker-0-dropdown-month-06 # June
125
- a-date-picker-0-dropdown-header-year # year panel header
126
- a-date-picker-0-dropdown-year-2026 # year 2026
127
- a-date-picker-0-dropdown-decade-2020-2029 # decade 2020-2029
128
- ```
129
-
130
- ### Runtime RangePicker Panel
131
-
132
- ```
133
- a-range-picker-0-dropdown-prev-left # left panel prev month
134
- a-range-picker-0-dropdown-date-2026-05-15-left # left panel date
135
- a-range-picker-0-dropdown-date-2026-06-20-right # right panel date
136
- ```
137
-
138
- ### Runtime TimePicker
139
-
140
- ```
141
- a-time-picker-0-dropdown-time-column-0 # hour column
142
- a-time-picker-0-dropdown-time-08 # 08 hour
143
- a-time-picker-0-dropdown-time-column-1 # minute column
144
- a-time-picker-0-dropdown-time-30 # 30 minutes
145
- ```
146
-
147
- ### Runtime Cascader
148
-
149
- ```
150
- a-cascader-0-dropdown # panel container
151
- a-cascader-0-dropdown-menu-0 # level 1 menu
152
- a-cascader-0-dropdown-item-Zhejiang # Zhejiang option
153
- a-cascader-0-dropdown-menu-1 # level 2 menu
154
- a-cascader-0-dropdown-item-Hangzhou # Hangzhou option
155
- ```
156
-
157
- ### Runtime Select
158
-
159
- ```
160
- a-select-0-dropdown # dropdown container
161
- a-select-0-dropdown-option-Option1 # option
162
- a-select-0-dropdown-option-Option2 # option
163
- ```
164
-
165
- ### Runtime TreeSelect
166
-
167
- ```
168
- a-tree-select-0-dropdown # dropdown container
169
- a-tree-select-0-dropdown-tree-root-1 # root node
170
- a-tree-select-0-dropdown-tree-switcher-expand-root-1 # expand icon (collapsed)
171
- a-tree-select-0-dropdown-tree-switcher-collapse-root-1 # expand icon (expanded)
172
- a-tree-select-0-dropdown-tree-parent-1 # parent node (injected after expand)
173
- a-tree-select-0-dropdown-tree-my-leaf # leaf node
174
- ```
175
-
176
- ### Compile-time + Runtime Menu
177
-
178
- ```
179
- a-menu-0 # menu container (compile-time)
180
- a-menu-item-Menu-Item-1 # menu item (runtime, text-based)
181
- a-menu-item-Sub-Item-3 # submenu item
182
- a-sub-menu-Submenu # submenu (runtime)
183
- a-menu-item-group-Group # menu item group (runtime)
184
- ```
185
-
186
- ---
187
-
188
- ## Configuration
189
-
190
- ### Compile-time Options
191
-
192
- ```ts
193
- import { createVueTestIdTransform } from 'vite-plugin-vue-testid'
194
-
195
- createVueTestIdTransform({
196
- /**
197
- * Component tag names to inject testIds into (kebab-case)
198
- * @default see "Default Supported Components" below
199
- */
200
- components: ['a-input', 'a-select', 'my-button'],
201
-
202
- /**
203
- * Custom testId generation function
204
- * @param tagName component tag name
205
- * @param count global increment counter
206
- * @returns testId string
207
- */
208
- generateId: (tagName, count) => `myapp-${tagName}-${count}`,
209
-
210
- /**
211
- * testId attribute name (use 'data-cy' for Cypress)
212
- * @default 'data-testid'
213
- */
214
- attributeName: 'data-cy',
215
-
216
- /**
217
- * Components that also receive an id attribute
218
- * @default ['a-date-picker', 'a-range-picker', 'a-time-picker', 'a-modal']
219
- */
220
- idComponents: ['a-date-picker', 'a-modal'],
221
-
222
- /**
223
- * id attribute name
224
- * @default 'id'
225
- */
226
- idAttributeName: 'id',
227
- })
228
- ```
229
-
230
- ### Runtime Options
231
-
232
- ```ts
233
- import { setupAntDropdownTestIds } from 'vite-plugin-vue-testid/runtime'
234
-
235
- // Default config
236
- const cleanup = setupAntDropdownTestIds()
237
-
238
- // Custom config
239
- const cleanup = setupAntDropdownTestIds({
240
- /**
241
- * testId attribute name, must match compile-time config
242
- * @default 'data-testid'
243
- */
244
- attributeName: 'data-testid',
245
-
246
- /**
247
- * Custom panel selector → injection strategy mapping
248
- * key: CSS selector
249
- * value: injection function; set to undefined to disable a built-in panel
250
- */
251
- panels: {
252
- '.ant-picker-dropdown': undefined, // disable built-in Picker panel injection
253
- '.my-custom-dropdown': (ctx) => {
254
- // ctx.container — panel container HTMLElement
255
- // ctx.trigger — trigger HTMLElement | null
256
- // ctx.triggerTestId — the trigger's testId value
257
- // ctx.attrName — testId attribute name
258
- const prefix = `${ctx.triggerTestId}-dropdown`
259
- ctx.container.setAttribute(ctx.attrName, prefix)
260
- // ... custom injection logic
261
- },
262
- },
263
- })
264
-
265
- // Clean up observer on component unmount
266
- onUnmounted(cleanup)
267
- ```
268
-
269
- ### One-off Manual Injection
270
-
271
- ```ts
272
- import { injectCurrentDropdowns } from 'vite-plugin-vue-testid/runtime'
273
-
274
- // For SSR / hydration scenarios where MutationObserver is not desired
275
- injectCurrentDropdowns({ attributeName: 'data-testid' })
276
- ```
277
-
278
- ---
279
-
280
- ## Default Supported Components
281
-
282
- | Component | Compile-time | Runtime |
283
- |-----------|:------------:|:-------:|
284
- | `a-input` | ✅ | — |
285
- | `a-textarea` | ✅ | — |
286
- | `a-input-number` | ✅ | — |
287
- | `a-select` | ✅ | ✅ dropdown |
288
- | `a-cascader` | ✅ | ✅ cascader panel |
289
- | `a-tree-select` | ✅ | ✅ tree select panel |
290
- | `a-radio-group` | ✅ | — |
291
- | `a-checkbox-group` | ✅ | — |
292
- | `a-date-picker` | ✅ id+testid | ✅ date panel |
293
- | `a-range-picker` | ✅ id+testid | ✅ dual panel |
294
- | `a-time-picker` | ✅ id+testid | ✅ time panel |
295
- | `a-switch` | ✅ | — |
296
- | `a-slider` | ✅ | — |
297
- | `a-rate` | ✅ | — |
298
- | `a-upload` | ✅ | — |
299
- | `a-form-item` | ✅ | — |
300
- | `a-button` | ✅ | — |
301
- | `a-modal` | ✅ id+testid | — |
302
- | `a-menu` | ✅ | — |
303
- | `a-menu-item` | ✅ id | 🔧 runtime (text) |
304
- | `a-sub-menu` | ✅ id | 🔧 runtime (text) |
305
- | `a-menu-item-group` | ✅ id | 🔧 runtime (text) |
306
-
307
- ---
308
-
309
- ## Custom Panel Injection Strategies
310
-
311
- Support overlays from other UI libraries by providing custom strategies:
312
-
313
- ```ts
314
- import type { PanelInjectStrategy } from 'vite-plugin-vue-testid/runtime'
315
-
316
- // Example: inject testIds into Element Plus overlays
317
- const injectElDropdown: PanelInjectStrategy = (ctx) => {
318
- const { container, triggerTestId, attrName } = ctx
319
- const prefix = `${triggerTestId}-dropdown`
320
-
321
- container.setAttribute(attrName, prefix)
322
-
323
- container.querySelectorAll('.el-select-dropdown__item').forEach((item) => {
324
- const el = item as HTMLElement
325
- const text = el.textContent?.trim() || ''
326
- el.setAttribute(attrName, `${prefix}-option-${text}`)
327
- })
328
- }
329
-
330
- setupAntDropdownTestIds({
331
- panels: {
332
- '.el-select-dropdown': injectElDropdown,
333
- '.el-cascader-dropdown': injectElDropdown,
334
- },
335
- })
336
- ```
337
-
338
- ---
339
-
340
- ## API Reference
341
-
342
- ### Compile-time
343
-
344
- | Export | Type | Description |
345
- |--------|------|-------------|
346
- | `createVueTestIdTransform(opts?)` | `(node: RootNode \| TemplateChildNode) => void` | Creates a Vue compiler nodeTransform |
347
- | `VueTestIdTransformOptions` | `interface` | Compile-time options type |
348
-
349
- ### Runtime (`/runtime` subpath)
350
-
351
- | Export | Type | Description |
352
- |--------|------|-------------|
353
- | `setupAntDropdownTestIds(opts?)` | `() => void` | Starts MutationObserver to auto-inject overlay testIds, returns cleanup function |
354
- | `injectCurrentDropdowns(opts?)` | `void` | One-off manual injection of currently visible overlays |
355
- | `RuntimeOptions` | `interface` | Runtime options type |
356
- | `PanelContext` | `interface` | Panel injection context type |
357
- | `PanelInjectStrategy` | `(ctx: PanelContext) => void` | Panel injection strategy function type |
358
-
359
- ---
360
-
361
- ## How It Works
362
-
363
- ### Compile-time
364
-
365
- Uses Vue's compiler `nodeTransform` hook to traverse template nodes at AST stage. When target component tags are matched, `data-testid` attribute nodes are appended directly. Since injection happens at compile time, there is zero runtime performance impact.
366
-
367
- ### Runtime
368
-
369
- ant-design-vue 4.x components like DatePicker, Select, and Cascader use Teleport to render overlays into `document.body`, making them unreachable at compile time. The runtime module uses `MutationObserver` to watch DOM changes under `body`, matches ant-design panel CSS classes, and automatically injects trigger-associated testIds into panel elements.
370
-
371
- For components like DatePicker with `inheritAttrs: false`, `data-testid` injected at compile time cannot reach the DOM. The plugin works around this by also injecting an `id` attribute (which ant-design-vue explicitly forwards to the internal `<input>`) as a fallback identifier.
372
-
373
- ---
374
-
375
- ## License
376
-
377
- MIT