@cypress/unique-selector 1.1.0 → 1.2.0
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/lib/getAttribute.js +11 -19
- package/lib/getAttributes.js +4 -2
- package/lib/getClasses.js +14 -8
- package/lib/getID.js +3 -2
- package/lib/getName.js +3 -2
- package/lib/getNthChild.js +3 -2
- package/lib/getTag.js +9 -2
- package/lib/index.js +80 -29
- package/package.json +1 -1
package/lib/getAttribute.js
CHANGED
|
@@ -5,29 +5,21 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
/**
|
|
7
7
|
* Returns the {attr} selector of the element
|
|
8
|
-
* @param {
|
|
9
|
-
* @param { String }
|
|
8
|
+
* @param { Element } el - The element.
|
|
9
|
+
* @param { String } attribute - The attribute name.
|
|
10
10
|
* @return { String | null } - The {attr} selector of the element.
|
|
11
11
|
*/
|
|
12
|
+
var getAttributeSelector = exports.getAttributeSelector = function getAttributeSelector(el, attribute) {
|
|
13
|
+
var attributeValue = el.getAttribute(attribute);
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
var _attributes$i = attributes[i],
|
|
17
|
-
nodeName = _attributes$i.nodeName,
|
|
18
|
-
value = _attributes$i.value;
|
|
19
|
-
|
|
20
|
-
// if this matches our selector
|
|
21
|
-
|
|
22
|
-
if (nodeName === selectorType) {
|
|
23
|
-
if (value) {
|
|
24
|
-
// if we have value that needs quotes
|
|
25
|
-
return "[" + nodeName + "=\"" + value + "\"]";
|
|
26
|
-
}
|
|
15
|
+
if (attributeValue === null) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
27
18
|
|
|
28
|
-
|
|
29
|
-
|
|
19
|
+
if (attributeValue) {
|
|
20
|
+
// if we have value that needs quotes
|
|
21
|
+
return "[" + attribute + "=\"" + attributeValue + "\"]";
|
|
30
22
|
}
|
|
31
23
|
|
|
32
|
-
return
|
|
24
|
+
return "[" + attribute + "]";
|
|
33
25
|
};
|
package/lib/getAttributes.js
CHANGED
|
@@ -9,18 +9,20 @@ function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr
|
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Returns the Attribute selectors of the element
|
|
12
|
-
* @param {
|
|
12
|
+
* @param { Element } element
|
|
13
13
|
* @param { Array } array of attributes to ignore
|
|
14
|
+
* @param { Function } filter
|
|
14
15
|
* @return { Array }
|
|
15
16
|
*/
|
|
16
17
|
function getAttributes(el) {
|
|
17
18
|
var attributesToIgnore = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ['id', 'class', 'length'];
|
|
19
|
+
var filter = arguments[2];
|
|
18
20
|
var attributes = el.attributes;
|
|
19
21
|
|
|
20
22
|
var attrs = [].concat(_toConsumableArray(attributes));
|
|
21
23
|
|
|
22
24
|
return attrs.reduce(function (sum, next) {
|
|
23
|
-
if (!(attributesToIgnore.indexOf(next.nodeName) > -1)) {
|
|
25
|
+
if (!(attributesToIgnore.indexOf(next.nodeName) > -1) && (!filter || filter('attributes', next.nodeName, next.value))) {
|
|
24
26
|
sum.push('[' + next.nodeName + '="' + next.value + '"]');
|
|
25
27
|
}
|
|
26
28
|
return sum;
|
package/lib/getClasses.js
CHANGED
|
@@ -11,34 +11,40 @@ require('css.escape');
|
|
|
11
11
|
/**
|
|
12
12
|
* Get class names for an element
|
|
13
13
|
*
|
|
14
|
-
* @
|
|
14
|
+
* @param { Element } el
|
|
15
|
+
* @param { Function } filter
|
|
15
16
|
* @return { Array }
|
|
16
17
|
*/
|
|
17
|
-
function getClasses(el) {
|
|
18
|
+
function getClasses(el, filter) {
|
|
18
19
|
if (!el.hasAttribute('class')) {
|
|
19
20
|
return [];
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
try {
|
|
23
|
-
return Array.prototype.slice.call(el.classList)
|
|
24
|
+
return Array.prototype.slice.call(el.classList).filter(function (cls) {
|
|
25
|
+
return !filter || filter('class', 'class', cls);
|
|
26
|
+
});
|
|
24
27
|
} catch (e) {
|
|
25
28
|
var className = el.getAttribute('class');
|
|
26
29
|
|
|
27
30
|
// remove duplicate and leading/trailing whitespaces
|
|
28
|
-
className = className.trim()
|
|
31
|
+
className = className.trim();
|
|
29
32
|
|
|
30
|
-
// split into separate classnames
|
|
31
|
-
return className.split(
|
|
33
|
+
// split into separate classnames, perform filtering
|
|
34
|
+
return className.split(/\s+/g).filter(function (cls) {
|
|
35
|
+
return !filter || filter('class', 'class', cls);
|
|
36
|
+
});
|
|
32
37
|
}
|
|
33
38
|
}
|
|
34
39
|
|
|
35
40
|
/**
|
|
36
41
|
* Returns the Class selectors of the element
|
|
37
42
|
* @param { Object } element
|
|
43
|
+
* @param { Function } filter
|
|
38
44
|
* @return { Array }
|
|
39
45
|
*/
|
|
40
|
-
function getClassSelectors(el) {
|
|
41
|
-
var classList = getClasses(el).filter(Boolean);
|
|
46
|
+
function getClassSelectors(el, filter) {
|
|
47
|
+
var classList = getClasses(el, filter).filter(Boolean);
|
|
42
48
|
return classList.map(function (cl) {
|
|
43
49
|
return '.' + CSS.escape(cl);
|
|
44
50
|
});
|
package/lib/getID.js
CHANGED
|
@@ -10,12 +10,13 @@ require('css.escape');
|
|
|
10
10
|
/**
|
|
11
11
|
* Returns the Tag of the element
|
|
12
12
|
* @param { Object } element
|
|
13
|
+
* @param { Function } filter
|
|
13
14
|
* @return { String }
|
|
14
15
|
*/
|
|
15
|
-
function getID(el) {
|
|
16
|
+
function getID(el, filter) {
|
|
16
17
|
var id = el.getAttribute('id');
|
|
17
18
|
|
|
18
|
-
if (id !== null && id !== '') {
|
|
19
|
+
if (id !== null && id !== '' && (!filter || filter('id', 'id', id))) {
|
|
19
20
|
return '#' + CSS.escape(id);
|
|
20
21
|
}
|
|
21
22
|
return null;
|
package/lib/getName.js
CHANGED
|
@@ -7,12 +7,13 @@ exports.getName = getName;
|
|
|
7
7
|
/**
|
|
8
8
|
* Returns the `name` attribute of the element (if one exists)
|
|
9
9
|
* @param { Object } element
|
|
10
|
+
* @param { Function } filter
|
|
10
11
|
* @return { String }
|
|
11
12
|
*/
|
|
12
|
-
function getName(el) {
|
|
13
|
+
function getName(el, filter) {
|
|
13
14
|
var name = el.getAttribute('name');
|
|
14
15
|
|
|
15
|
-
if (name !== null && name !== '') {
|
|
16
|
+
if (name !== null && name !== '' && (!filter || filter('name', 'name', name))) {
|
|
16
17
|
return '[name="' + name + '"]';
|
|
17
18
|
}
|
|
18
19
|
return null;
|
package/lib/getNthChild.js
CHANGED
|
@@ -10,9 +10,10 @@ var _isElement = require('./isElement');
|
|
|
10
10
|
/**
|
|
11
11
|
* Returns the selectors based on the position of the element relative to its siblings
|
|
12
12
|
* @param { Object } element
|
|
13
|
+
* @param { Function } filter
|
|
13
14
|
* @return { Array }
|
|
14
15
|
*/
|
|
15
|
-
function getNthChild(element) {
|
|
16
|
+
function getNthChild(element, filter) {
|
|
16
17
|
var counter = 0;
|
|
17
18
|
var k = void 0;
|
|
18
19
|
var sibling = void 0;
|
|
@@ -27,7 +28,7 @@ function getNthChild(element) {
|
|
|
27
28
|
sibling = childNodes[k];
|
|
28
29
|
if ((0, _isElement.isElement)(sibling)) {
|
|
29
30
|
counter++;
|
|
30
|
-
if (sibling === element) {
|
|
31
|
+
if (sibling === element && (!filter || filter('nth-child', 'nth-child', counter))) {
|
|
31
32
|
return ':nth-child(' + counter + ')';
|
|
32
33
|
}
|
|
33
34
|
}
|
package/lib/getTag.js
CHANGED
|
@@ -7,8 +7,15 @@ exports.getTag = getTag;
|
|
|
7
7
|
/**
|
|
8
8
|
* Returns the Tag of the element
|
|
9
9
|
* @param { Object } element
|
|
10
|
+
* @param { Function } filter
|
|
10
11
|
* @return { String }
|
|
11
12
|
*/
|
|
12
|
-
function getTag(el) {
|
|
13
|
-
|
|
13
|
+
function getTag(el, filter) {
|
|
14
|
+
var tagName = el.tagName.toLowerCase().replace(/:/g, '\\:');
|
|
15
|
+
|
|
16
|
+
if (filter && !filter('tag', 'tag', tagName)) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return tagName;
|
|
14
21
|
}
|
package/lib/index.js
CHANGED
|
@@ -37,21 +37,62 @@ var attrRegex = /^attribute:(.+)/m;
|
|
|
37
37
|
* @param { Object } element
|
|
38
38
|
* @return { Object }
|
|
39
39
|
*/
|
|
40
|
-
function getAllSelectors(el, selectors, attributesToIgnore) {
|
|
40
|
+
function getAllSelectors(el, selectors, attributesToIgnore, filters) {
|
|
41
|
+
var consolidatedAttributesToIgnore = [].concat(_toConsumableArray(attributesToIgnore));
|
|
42
|
+
var nonAttributeSelectors = [];
|
|
43
|
+
var _iteratorNormalCompletion = true;
|
|
44
|
+
var _didIteratorError = false;
|
|
45
|
+
var _iteratorError = undefined;
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
for (var _iterator = selectors[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
49
|
+
var selectorType = _step.value;
|
|
50
|
+
|
|
51
|
+
if (dataRegex.test(selectorType)) {
|
|
52
|
+
consolidatedAttributesToIgnore.push(selectorType);
|
|
53
|
+
} else if (attrRegex.test(selectorType)) {
|
|
54
|
+
consolidatedAttributesToIgnore.push(selectorType.replace(attrRegex, '$1'));
|
|
55
|
+
} else {
|
|
56
|
+
nonAttributeSelectors.push(selectorType);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
} catch (err) {
|
|
60
|
+
_didIteratorError = true;
|
|
61
|
+
_iteratorError = err;
|
|
62
|
+
} finally {
|
|
63
|
+
try {
|
|
64
|
+
if (!_iteratorNormalCompletion && _iterator.return) {
|
|
65
|
+
_iterator.return();
|
|
66
|
+
}
|
|
67
|
+
} finally {
|
|
68
|
+
if (_didIteratorError) {
|
|
69
|
+
throw _iteratorError;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
41
74
|
var funcs = {
|
|
42
|
-
'tag':
|
|
43
|
-
|
|
75
|
+
'tag': function tag(elem) {
|
|
76
|
+
return (0, _getTag.getTag)(elem, filters.tag);
|
|
77
|
+
},
|
|
78
|
+
'nth-child': function nthChild(elem) {
|
|
79
|
+
return (0, _getNthChild.getNthChild)(elem, filters.nthChild);
|
|
80
|
+
},
|
|
44
81
|
'attributes': function attributes(elem) {
|
|
45
|
-
return (0, _getAttributes.getAttributes)(elem,
|
|
82
|
+
return (0, _getAttributes.getAttributes)(elem, consolidatedAttributesToIgnore, filters.attributes);
|
|
83
|
+
},
|
|
84
|
+
'class': function _class(elem) {
|
|
85
|
+
return (0, _getClasses.getClassSelectors)(elem, filters.class);
|
|
86
|
+
},
|
|
87
|
+
'id': function id(elem) {
|
|
88
|
+
return (0, _getID.getID)(elem, filters.id);
|
|
46
89
|
},
|
|
47
|
-
'
|
|
48
|
-
|
|
49
|
-
|
|
90
|
+
'name': function name(elem) {
|
|
91
|
+
return (0, _getName.getName)(elem, filters.name);
|
|
92
|
+
}
|
|
50
93
|
};
|
|
51
94
|
|
|
52
|
-
return
|
|
53
|
-
return !dataRegex.test(selector) && !attrRegex.test(selector);
|
|
54
|
-
}).reduce(function (res, next) {
|
|
95
|
+
return nonAttributeSelectors.reduce(function (res, next) {
|
|
55
96
|
res[next] = funcs[next](el);
|
|
56
97
|
return res;
|
|
57
98
|
}, {});
|
|
@@ -119,20 +160,18 @@ function getUniqueCombination(element, items, tag) {
|
|
|
119
160
|
* @param { Array } options
|
|
120
161
|
* @return { String }
|
|
121
162
|
*/
|
|
122
|
-
function getUniqueSelector(element, selectorTypes, attributesToIgnore) {
|
|
163
|
+
function getUniqueSelector(element, selectorTypes, attributesToIgnore, filters) {
|
|
123
164
|
var foundSelector = void 0;
|
|
124
165
|
|
|
125
|
-
var
|
|
126
|
-
|
|
127
|
-
var elementSelectors = getAllSelectors(element, selectorTypes, attributesToIgnore);
|
|
166
|
+
var elementSelectors = getAllSelectors(element, selectorTypes, attributesToIgnore, filters);
|
|
128
167
|
|
|
129
|
-
var
|
|
130
|
-
var
|
|
131
|
-
var
|
|
168
|
+
var _iteratorNormalCompletion2 = true;
|
|
169
|
+
var _didIteratorError2 = false;
|
|
170
|
+
var _iteratorError2 = undefined;
|
|
132
171
|
|
|
133
172
|
try {
|
|
134
|
-
for (var
|
|
135
|
-
var selectorType =
|
|
173
|
+
for (var _iterator2 = selectorTypes[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
|
|
174
|
+
var selectorType = _step2.value;
|
|
136
175
|
|
|
137
176
|
var selector = elementSelectors[selectorType];
|
|
138
177
|
|
|
@@ -141,11 +180,12 @@ function getUniqueSelector(element, selectorTypes, attributesToIgnore) {
|
|
|
141
180
|
var isAttributeSelectorType = !isDataAttributeSelectorType && attrRegex.test(selectorType);
|
|
142
181
|
if (isDataAttributeSelectorType || isAttributeSelectorType) {
|
|
143
182
|
var attributeToQuery = isDataAttributeSelectorType ? selectorType : selectorType.replace(attrRegex, '$1');
|
|
144
|
-
var
|
|
183
|
+
var attributeValue = element.getAttribute(attributeToQuery);
|
|
184
|
+
var attributeFilter = filters[selectorType];
|
|
145
185
|
|
|
146
186
|
// if we found a selector via attribute
|
|
147
|
-
if (
|
|
148
|
-
selector =
|
|
187
|
+
if (attributeValue !== null && (!attributeFilter || attributeFilter(selectorType, attributeToQuery, attributeValue))) {
|
|
188
|
+
selector = (0, _getAttribute.getAttributeSelector)(element, attributeToQuery);
|
|
149
189
|
selectorType = 'attribute';
|
|
150
190
|
}
|
|
151
191
|
}
|
|
@@ -179,16 +219,16 @@ function getUniqueSelector(element, selectorTypes, attributesToIgnore) {
|
|
|
179
219
|
}
|
|
180
220
|
}
|
|
181
221
|
} catch (err) {
|
|
182
|
-
|
|
183
|
-
|
|
222
|
+
_didIteratorError2 = true;
|
|
223
|
+
_iteratorError2 = err;
|
|
184
224
|
} finally {
|
|
185
225
|
try {
|
|
186
|
-
if (!
|
|
187
|
-
|
|
226
|
+
if (!_iteratorNormalCompletion2 && _iterator2.return) {
|
|
227
|
+
_iterator2.return();
|
|
188
228
|
}
|
|
189
229
|
} finally {
|
|
190
|
-
if (
|
|
191
|
-
throw
|
|
230
|
+
if (_didIteratorError2) {
|
|
231
|
+
throw _iteratorError2;
|
|
192
232
|
}
|
|
193
233
|
}
|
|
194
234
|
}
|
|
@@ -200,6 +240,15 @@ function getUniqueSelector(element, selectorTypes, attributesToIgnore) {
|
|
|
200
240
|
* Generate unique CSS selector for given DOM element
|
|
201
241
|
*
|
|
202
242
|
* @param {Element} el
|
|
243
|
+
* @param {Object} options (optional) Customize various behaviors of selector generation
|
|
244
|
+
* @param {String[]} options.selectorTypes Specify the set of traits to leverage when building selectors in precedence order
|
|
245
|
+
* @param {String[]} options.attributesToIgnore Specify a set of attributes to *not* leverage when building selectors
|
|
246
|
+
* @param {Object} options.filters Specify a set of filter functions to conditionally reject various traits when building selectors. Keys correspond to a `selectorTypes` entry, values should be a function accepting three parameters:
|
|
247
|
+
* * selectorType: The selector type/category being generated
|
|
248
|
+
* * key: The key being evaluated - this will typically match the `selectorType` except in aggregate types like `attributes`
|
|
249
|
+
* * value: The value to consider. Returning `true` will allow its use in selector generation, `false` will prevent.
|
|
250
|
+
* @param {Map<Element, String>} options.selectorCache Provide a cache to improve performance of repeated selector generation - it is the responsibility of the caller to handle cache invalidation. Caching is performed using the input Element as key. This cache handles Element -> Selector caching.
|
|
251
|
+
* @param {Map<String, Boolean>} options.isUniqueCache Provide a cache to improve performance of repeated selector generation - it is the responsibility of the caller to handle cache invalidation. Caching is performed using the input Element as key. This cache handles Selector -> isUnique caching.
|
|
203
252
|
* @return {String}
|
|
204
253
|
* @api private
|
|
205
254
|
*/
|
|
@@ -210,6 +259,8 @@ function unique(el) {
|
|
|
210
259
|
selectorTypes = _options$selectorType === undefined ? ['id', 'name', 'class', 'tag', 'nth-child'] : _options$selectorType,
|
|
211
260
|
_options$attributesTo = options.attributesToIgnore,
|
|
212
261
|
attributesToIgnore = _options$attributesTo === undefined ? ['id', 'class', 'length'] : _options$attributesTo,
|
|
262
|
+
_options$filters = options.filters,
|
|
263
|
+
filters = _options$filters === undefined ? {} : _options$filters,
|
|
213
264
|
selectorCache = options.selectorCache,
|
|
214
265
|
isUniqueCache = options.isUniqueCache;
|
|
215
266
|
|
|
@@ -220,7 +271,7 @@ function unique(el) {
|
|
|
220
271
|
var selector = selectorCache ? selectorCache.get(currentElement) : undefined;
|
|
221
272
|
|
|
222
273
|
if (!selector) {
|
|
223
|
-
selector = getUniqueSelector(currentElement, selectorTypes, attributesToIgnore);
|
|
274
|
+
selector = getUniqueSelector(currentElement, selectorTypes, attributesToIgnore, filters);
|
|
224
275
|
if (selectorCache) {
|
|
225
276
|
selectorCache.set(currentElement, selector);
|
|
226
277
|
}
|
package/package.json
CHANGED