独选者
鉴于 DOM 节点, 返回唯一匹配该元素的 CSS 选择器 .
选择器的独特性根据给定元素的根节点来确定. 在Shadow DOM中渲染出元素,将在关联的ShadowRoot上下文中得出一个独有的选择器. 否则,将产生元素自有文档中独有的选择器.
安装
npm install @cypress/unique-selector
API 密码
unique(element, options)
为指定的 DOM 元素生成一个独特的 CSS 选择器.
参数
element(Element) - 用于生成唯一选择器的 DOM 元素options(对象,可选) - 选择器生成的配置选项
选项
-
selectorTypes(String [],可选) - 按偏好顺序排列选择器类型。 默认 :['id', 'name', 'class', 'tag', 'nth-child']可用的选择器类型 :
'id'- 使用元素的ID属性(例如,#myId(中文(简体) )'name'- 使用元素的名称属性(例如,[name="myName"](中文(简体) )'class'- 使用元素的类属性(例如,.myClass(中文(简体) )'tag'- 使用元素的标记名称(例如,div, (中文(简体) ),span(中文(简体) )'nth-child'- 使用非孩子位置(例如:,:nth-child(1)(中文(简体) )'attributes'- 使用所有属性,但不包括:attributesToIgnore'data-*'- 使用特定数据属性(例如,data-foo, (中文(简体) ),data-test-id(中文(简体) )'attribute:*'- 使用特定属性(例如,attribute:role, (中文(简体) ),attribute:aria-label(中文(简体) )
-
attributesToIgnore(String [],可选) - 生成选择器时要忽略的属性名称的组合. 默认 :['id', 'class', 'length'] -
filter(功能,可选) - 在构建选择器时有条件拒绝各种特性的过滤功能.function filter(type, key, value) { // type: 'attribute', 'class', 'tag', 'nth-child' // key: attribute name (for attributes), class name (for classes), etc. // value: attribute value, class name, tag name, nth-child position // Return true to allow this trait, false to reject it return true; } -
selectorCache(map<Element, String>,可选) - 缓存可以提高重复选择器生成的性能. 呼叫者负责缓存无效. -
isUniqueCache(map<String, Boolean>,可选) - 缓存可以提高重复的独特性检查的性能. 呼叫者负责缓存无效. -
requiredAttributes(Object,可选) - 指定必须出现在生成的选取器中的属性,无论这些属性是否需要独有性. 当提供时,匹配的属性选择器会被编织入每个元素的片段>链,而独有链上方的祖先则使用后人梳理器进行预作.此选项优先于
selectorTypes财务报告和审定财务报表filter对于它所命名的属性——如果一个元素具有需要的属性,则其属性[attr="value"]即使filter为了独特性的目的拒绝该属性,即使该属性未列入selectorTypes。 。 。 .这个
requiredAttributes对象的形状如下:attributeNames(String[]) - 向选择器注入的属性名(例如,['data-component', 'data-cy']) (中文(简体) ). 精确的属性名称只——而不是图案或正则名. 名称在生成的选取器中按规定使用,没有内部正常化,因此您提供的外壳是输出中出现的外壳. 当属性在attributeNames已经存在于基准选择器中(来自selectorTypes),去dup检测为对病例不敏感,所以无论病例差异如何,重复注射都会被正确压制.filter(功能,可选) - 一个过滤功能,其签名与顶级相同filter选项,独立用于控制哪个属性 数值 允许注射。 返回时false以跳过给定元素的注入。 此过滤器与顶层分离filter并服务于不同的目的:filter有资格建立 独一无二 选择器,同时requiredAttributes.filter属性值符合条件的控件 注射编辑key引用到此函数的参数将符合下列条件:attributeNames。 。 。 .elementCache(map<Element, (string-|null) [] >,可选) - 每元素所需的属性选择器缓存 。 每个缓存项是单个选择器字符串的阵列,与attributeNames(未显示或过滤出属性的空白). 呼叫者负责缓存无效.
unique(element, { requiredAttributes: { attributeNames: ['data-component', 'data-cy'], filter: (type, key, value) => { // Exclude auto-generated component names from injection if (type === 'attribute' && key === 'data-component') { return !value.startsWith('jss-'); } return true; }, elementCache: new Map(), } });
回返
- 字符串 - 该元素的独有CSS选择器,或
null如果无法生成唯一选择器
用法实例
基本用途
import unique from '@cypress/unique-selector';
// Get a unique selector for an element
const element = document.querySelector('.my-button');
const selector = unique(element);
// Returns: '#my-button' or '.my-button' or 'button' etc.
自定义选择器类型
// Use only ID and class selectors
const selector = unique(element, {
selectorTypes: ['id', 'class']
});
// Use only data attributes
const selector = unique(element, {
selectorTypes: ['data-test-id', 'data-cy']
});
// Use specific attributes
const selector = unique(element, {
selectorTypes: ['attribute:role', 'attribute:aria-label']
});
过滤选择器
// Filter out certain IDs
const selector = unique(element, {
filter: (type, key, value) => {
if (type === 'attribute' && key === 'id') {
// Only allow IDs that contain 'test'
return value.includes('test');
}
return true;
}
});
// Filter out certain classes
const selector = unique(element, {
filter: (type, key, value) => {
if (type === 'class') {
// Only allow classes that start with 'btn-'
return value.startsWith('btn-');
}
return true;
}
});
必需属性
使用 requiredAttributes 当您想要特定属性总是出现在生成的选择器中时,无论这些属性是否有助于独有性。 当应用程序使用语义元件属性(如:, data-component, (中文(简体) ), data-cy您想要在每个选择器中反映可读性或稳定性.
// Always include data-component in the selector, even when an ID alone would be unique
const selector = unique(element, {
requiredAttributes: {
attributeNames: ['data-component']
}
});
// '#submit-button' becomes '#submit-button[data-component="PrimaryButton"]'
// Ancestors with data-component are prepended with descendant combinators:
// '[data-component="Form"] #submit-button[data-component="PrimaryButton"]'
所需属性优先于 selectorTypes 财务报告和审定财务报表 filter。如果元素具有要求的属性,则将注入选择器,即使:
- 属性未在
selectorTypes - 高层
filter为了独特性而拒绝这种属性
// The top-level filter rejects data-component for uniqueness building,
// but requiredAttributes.filter allows it to still be injected.
const selector = unique(element, {
filter: (type, key) => key !== 'data-component',
requiredAttributes: {
attributeNames: ['data-component'],
// No requiredAttributes.filter — all values are injected
}
});
// data-component still appears in the output
使用 requiredAttributes.filter 独立控制哪个属性 数值 注射,但不影响确定独特性的方式:
// Inject data-component only when the value doesn't look auto-generated
const selector = unique(element, {
requiredAttributes: {
attributeNames: ['data-component'],
filter: (type, key, value) => {
if (type === 'attribute' && key === 'data-component') {
return !value.startsWith('jss-');
}
return true;
},
elementCache: new Map(), // reuse across calls for performance
}
});
当多个 attributeNames 指定,每个元素独立匹配:
const selector = unique(element, {
requiredAttributes: {
attributeNames: ['data-cy', 'data-region']
}
});
// '[data-region="main"] [data-cy="dashboard"] .widget[data-cy="widget-a"]'
用缓存优化性能
const selectorCache = new Map();
const isUniqueCache = new Map();
const selector = unique(element, {
selectorCache,
isUniqueCache
});
// Reuse the same caches for multiple calls
const selector2 = unique(anotherElement, {
selectorCache,
isUniqueCache
});
阴影 DOM 支持
// Works with Shadow DOM elements
const shadowHost = document.querySelector('#shadow-host');
const shadowRoot = shadowHost.attachShadow({ mode: 'open' });
const shadowElement = shadowRoot.querySelector('.shadow-button');
const selector = unique(shadowElement);
// Returns a selector unique within the shadow root context
选择生成策略
库遵循这个策略生成独特的选择器 :
- 元素级独有性: 首先尝试找到一个在母体中唯一识别元素的筛选器
- 双向: 如果元素级独有性失败, 则会穿过 DOM 树, 建立选择器路径
- 选择者类型优先: 使用
selectorTypes数组以决定要先尝试的选定者类型 - 组合后退: 对于类和属性,如果单个选择者不独有,请尝试多个选择者的组合
- Nth- child倒计时: 将非儿童定位作为最后手段
- 必需属性注射: 独一无二之后
>链被确定,任何requiredAttributes被编织入每个元素的链段。 在链上方带有所需要属性的祖先被准备为后人梳理. 必要的属性即使因独特性而不需要,甚至顶层也会被注入filter将这些人排除在考虑之外.
生成选择器实例
<!-- Element with ID -->
<div id="header">Header</div>
<!-- Selector: #header -->
<!-- Element with unique class -->
<button class="submit-btn">Submit</button>
<!-- Selector: .submit-btn -->
<!-- Element with multiple classes -->
<div class="card primary large">Card</div>
<!-- Selector: .card.primary.large -->
<!-- Element with data attributes -->
<div data-test-id="user-profile">Profile</div>
<!-- Selector: [data-test-id="user-profile"] -->
<!-- Element with custom attributes -->
<button role="button" aria-label="Close">×</button>
<!-- Selector: [role="button"] or [aria-label="Close"] -->
<!-- Element requiring nth-child -->
<div class="item">Item 1</div>
<div class="item">Item 2</div>
<!-- Selector: :nth-child(1) or :nth-child(2) -->
<!-- Complex nested element -->
<div class="container">
<div class="wrapper">
<span class="text">Hello</span>
</div>
</div>
<!-- Selector: .container > .wrapper > .text -->