Data CY Generator
Расширение для VS Code / Cursor, которое автоматически добавляет и удаляет атрибуты data-cy в проектах Vue 2, Vue 3 и React.
Кратко как это работает
- Расширение определяет профиль проекта (
vue2, vue3, react) автоматически или по настройке.
- Находит теги по regex-паттерну профиля и/или вашего конфига.
- Берет источник имени из семантических полей (
v-model, model-value, value, name, id, label, placeholder, aria-label и т.д.).
- Формирует
data-cy в формате <file-name>-<source-value>.
- Если в одном контексте встречаются одинаковые шаблоны, добавляет суффиксы
-t1, -t2, ... для уникальности.
- Уже существующие
data-cy / :data-cy не перезаписываются.
Установка
Сборка VSIX
npm install
npm run package
После сборки в корне появится .vsix файл, например data-cy-generator-0.1.0.vsix.
Установка в VS Code / Cursor
- Через Command Palette:
Extensions: Install from VSIX...
- Или через терминал:
code --install-extension data-cy-generator-0.1.0.vsix
cursor --install-extension data-cy-generator-0.1.0.vsix
После установки перезагрузите окно редактора.
Быстрый старт
- Откройте проект.
- Выполните команду
Data CY: Init Components Config In Workspace.
- Отредактируйте
data-cy.components.json под ваш проект.
- Запустите:
Data CY: Add Attributes In Active File (для текущего файла), или
Data CY: Add Attributes In Project (для всего проекта).
Конфиг data-cy.components.json
Рекомендуемый формат:
{
"framework": "vue3",
"componentPatterns": ["AppInput", "AppButton", "UiInput", "UiButton"]
}
Важно
Если componentPatterns задан в data-cy.components.json, он считается источником истины (белым списком):
- обрабатываются только перечисленные компоненты (и
extraComponentPatterns, если они заданы);
- встроенные широкие паттерны профиля не подмешиваются.
Это позволяет строго контролировать, где добавляется data-cy.
Все команды расширения
Основные
Data CY: Add Attributes In Active File
Добавляет data-cy в текущем открытом файле.
Data CY: Add Attributes In Project
Добавляет data-cy во всех поддерживаемых файлах проекта.
Data CY: Remove Attributes In Active File
Удаляет data-cy / :data-cy в текущем файле.
Data CY: Remove Attributes In Project
Удаляет data-cy / :data-cy по всему проекту.
Data CY: Init Components Config In Workspace
Создает data-cy.components.json в корне workspace: поле framework определяется по package.json (react, vue2, vue3; при отсутствии зависимостей — vue3). Включает авто-добавление для новых файлов.
Data CY: Show Resolved Profile
Показывает текущий профиль, источник профиля и итоговый regex.
Data CY: Set Custom Regex Pattern
Сохраняет dataCy.customRegex и переключает dataCy.profile в custom.
Автодобавление в новые файлы
Data CY: Enable Auto Add In Created File
Включает автодобавление data-cy при создании нового поддерживаемого файла.
Data CY: Disable Auto Add In Created File
Отключает автодобавление.
Data CY: Toggle Auto Add In Created File
Переключает состояние (ON/OFF).
Data CY: Show Auto Add In Created File Status
Показывает текущий статус автодобавления.
Поддерживаемые типы файлов
Настройки (settings.json)
Пример workspace-настроек:
{
"dataCy.profile": "auto",
"dataCy.customRegex": "",
"dataCy.autoAddInCreatedFile": false,
"dataCy.extraComponentPatterns": [],
"dataCy.componentPatterns": {
"vue2": [],
"vue3": [],
"react": []
}
}
Описание ключевых настроек
dataCy.profile:
Профиль проекта: auto | vue2 | vue3 | react | custom.
dataCy.customRegex:
Кастомный regex для тегов (используется, когда dataCy.profile = custom).
dataCy.autoAddInCreatedFile:
Автоматическое добавление data-cy в новый файл при создании.
dataCy.componentPatterns и dataCy.extraComponentPatterns:
Дополнительные паттерны из настроек workspace (используются как fallback, если нет data-cy.components.json).
Приоритет источников компонентов
data-cy.components.json (приоритетный источник)
.vscode/settings.json (dataCy.*) как fallback
- Встроенные профили (
vue2, vue3, react)
Примеры до/после
1) Vue3: базовое добавление data-cy
До:
<template>
<InputField v-model="form.phone" label="Телефон" />
<Button @click="saveForm">Сохранить</Button>
</template>
После:
<template>
<InputField v-model="form.phone" label="Телефон" data-cy="user-form-phone" />
<Button @click="saveForm" data-cy="user-form-saveform">Сохранить</Button>
</template>
Где user-form — имя файла (например UserForm.vue -> user-form в составе итогового ключа по внутренней нормализации).
2) Vue2/Vue3: v-for с динамическим :data-cy
До:
<template #tableBody>
<tr v-for="(user, index) in users" :key="user.id">
<td>{{ index + 1 }}</td>
<td>{{ user.name }}</td>
</tr>
</template>
После:
<template #tableBody>
<tr v-for="(user, index) in users" :key="user.id">
<td :data-cy="`users-table-td-${index}`">{{ index + 1 }}</td>
<td :data-cy="`users-table-td-${index}-t1`">{{ user.name }}</td>
</tr>
</template>
Почему так:
- для элементов в одном контексте
v-for используется динамика ${index};
- если шаблон совпадает у соседних тегов, добавляются суффиксы
-t1, -t2, ... .
3) Vuetify / Vue2: работа по белому списку компонентов
Конфиг:
{
"framework": "vue2",
"componentPatterns": ["v-btn", "v-text-field", "v-select", "v-data-table", "td"]
}
Поведение:
v-btn, v-text-field, td будут обработаны;
- компонент вне списка (например
v-autocomplete) не будет затронут.
4) React: onClick / onclick и другие обработчики
Если у компонента нет name, id, aria-label и т.п., для профиля react в ключ добавляется имя функции из обработчика (onClick, onChange, onSubmit, … — регистр атрибута не важен).
До:
<Button type="button" onclick={dowvloadExcel} />
После:
<Button type="button" onclick={dowvloadExcel} data-cy="salary-button-dowvloadexcel" />
Поддерживаются формы: {save}, {save()}, {() => save()}, {form.save}, {save.bind(this)}.
5) React: .map() / .flatMap() с динамическим data-cy
До:
{tableData?.map((item, index) => (
<tr>
<td>{item?.id}</td>
<td>{item?.full_name}</td>
</tr>
))}
После (при componentPatterns, включающих tr и td):
{tableData?.map((item, index) => (
<tr data-cy={`compliance-table-tr-${index}`}>
<td data-cy={`compliance-table-td-${index}`}>{item?.id}</td>
<td data-cy={`compliance-table-td-${index}-t1`}>{item?.full_name}</td>
</tr>
))}
Поведение аналогично v-for в Vue:
- поддерживаются
array.map(...), array?.map(...), flatMap;
- для динамики в callback нужен второй аргумент:
(item, index) => (или function (item, index) { ... });
- вложенные
.map() дают несколько ${index} в шаблоне (снаружи внутрь);
- при совпадении шаблона у соседних тегов добавляются суффиксы
-t1, -t2, … .
6) React: Ant Design Table — автоматический onCell на колонках
Только для профиля react. Ищет массивы вида:
export const realStateColumns = [ { key: 'obj_code', dataIndex: 'obj_code', ... }, ... ];
Имя константы должно содержать column или columns (например cybernetListColumn, realStateColumns).
До:
{
key: 'obj_code',
dataIndex: 'obj_code',
render: (obj_code: string) => <span>{obj_code}</span>,
},
После (в файле real-state-columns.ts):
{
key: 'obj_code',
dataIndex: 'obj_code',
render: (obj_code: string) => <span>{obj_code}</span>,
onCell: (_record, index) => ({
'data-cy': `real-state-columns-obj-code-${index}`,
}),
},
Правила:
- источник имени:
key, иначе dataIndex;
- префикс — имя файла без расширения (
real-state-columns.ts → real-state-columns);
- динамика по строке:
`...-${index}` на <td> через API antd;
- при повторяющихся
key / dataIndex в одном массиве — суффиксы -t1, -t2, …;
- если
onCell уже есть — колонка не меняется;
- сложный
render (типы в параметрах, вложенный .map) поддерживается.
<Table columns={realStateColumns} /> менять не нужно — onCell уже в объектах колонок.
7) Если data-cy уже есть, тег не изменяется
До:
<Button data-cy="profile-save-btn" @click="save">Сохранить</Button>
После:
<Button data-cy="profile-save-btn" @click="save">Сохранить</Button>
Расширение не перезаписывает уже существующие data-cy / :data-cy.
До:
<v-file-input @change="onFileSelected" />
После:
<v-file-input @change="onFileSelected" data-cy="import-page-onfileselected" />
Если нет v-model/label, расширение может взять имя обработчика из @change.
Авторы и лицензия
- Правообладатель: АО «Asakabank»
- Разработка: команда Frontend Asakabank
- Лицензия: проприетарная, только для внутреннего использования (см.
LICENSE.txt)