Skip to content

Commit ad1bb15

Browse files
authored
fix: css to xpath backward compatibility (#4141)
1 parent 9a7991b commit ad1bb15

File tree

4 files changed

+36
-12
lines changed

4 files changed

+36
-12
lines changed

Diff for: .eslintignore

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
test/data/output
2+
lib/css2xpath/*

Diff for: lib/locator.js

+13-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const cssToXPath = require('csstoxpath');
1+
let cssToXPath;
22
const { sprintf } = require('sprintf-js');
33

44
const { xpathLocator } = require('./utils');
@@ -162,8 +162,17 @@ class Locator {
162162
* @returns {string}
163163
*/
164164
toXPath(pseudoSelector = '') {
165+
const locator = `${this.value}${pseudoSelector}`;
166+
const limitation = [':nth-of-type', ':first-of-type', ':last-of-type', ':nth-last-child', ':nth-last-of-type', ':checked', ':disabled', ':enabled', ':required', ':lang'];
167+
168+
if (limitation.some(item => locator.includes(item))) {
169+
cssToXPath = require('css-to-xpath');
170+
} else {
171+
cssToXPath = require('csstoxpath');
172+
}
173+
165174
if (this.isXPath()) return this.value;
166-
if (this.isCSS()) return cssToXPath(`${this.value}${pseudoSelector}`);
175+
if (this.isCSS()) return cssToXPath(locator);
167176

168177
throw new Error('Can\'t be converted to XPath');
169178
}
@@ -250,7 +259,7 @@ class Locator {
250259
*/
251260
withText(text) {
252261
text = xpathLocator.literal(text);
253-
const xpath = this.toXPath(`:text-contains-case(${text})`);
262+
const xpath = sprintf('%s[%s]', this.toXPath(), `contains(., ${text})`);
254263
return new Locator({ xpath });
255264
}
256265

@@ -261,7 +270,7 @@ class Locator {
261270
*/
262271
withTextEquals(text) {
263272
text = xpathLocator.literal(text);
264-
const xpath = this.toXPath(`:text-case(${text})`);
273+
const xpath = sprintf('%s[%s]', this.toXPath(), `.= ${text}`);
265274
return new Locator({ xpath });
266275
}
267276

Diff for: package.json

+8-7
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,15 @@
7676
"axios": "1.6.3",
7777
"chai": "4.3.8",
7878
"chai-deep-match": "1.2.1",
79-
"chai-exclude": "^2.1.0",
80-
"chai-json-schema": "^1.5.1",
81-
"chai-json-schema-ajv": "^5.2.4",
82-
"chai-match-pattern": "^1.3.0",
83-
"chai-string": "^1.5.0",
79+
"chai-exclude": "2.1.0",
80+
"chai-json-schema": "1.5.1",
81+
"chai-json-schema-ajv": "5.2.4",
82+
"chai-match-pattern": "1.3.0",
83+
"chai-string": "1.5.0",
8484
"chalk": "4.1.2",
8585
"commander": "11.1.0",
8686
"cross-spawn": "7.0.3",
87+
"css-to-xpath": "0.1.0",
8788
"csstoxpath": "1.6.0",
8889
"devtools": "8.27.2",
8990
"envinfo": "7.11.0",
@@ -92,7 +93,7 @@
9293
"fn-args": "4.0.0",
9394
"fs-extra": "11.2.0",
9495
"glob": "6.0.1",
95-
"html-minifier-terser": "^7.2.0",
96+
"html-minifier-terser": "7.2.0",
9697
"inquirer": "6.5.2",
9798
"joi": "17.11.0",
9899
"js-beautify": "1.14.11",
@@ -118,7 +119,7 @@
118119
"@faker-js/faker": "7.6.0",
119120
"@pollyjs/adapter-puppeteer": "6.0.6",
120121
"@pollyjs/core": "5.1.0",
121-
"@types/chai": "^4.3.7",
122+
"@types/chai": "4.3.7",
122123
"@types/inquirer": "9.0.3",
123124
"@types/node": "20.10.7",
124125
"@wdio/sauce-service": "8.27.0",

Diff for: test/unit/locator_test.js

+14-1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ const xml = `<body>
5050
</div>
5151
</fieldset>
5252
<label class="n-1">Hello<a href="#">Please click</a></label>
53+
<label class="n1">Hello no hyphen<a href="#">Please click</a></label>
5354
</div>
5455
<input type="hidden" name="return_url" value="" id="return_url" />
5556
@@ -197,7 +198,7 @@ describe('Locator', () => {
197198
.inside(Locator.build('label').withText('Hello'));
198199

199200
const nodes = xpath.select(l.toXPath(), doc);
200-
expect(nodes).to.have.length(1, l.toXPath());
201+
expect(nodes).to.have.length(2, l.toXPath());
201202
expect(nodes[0].firstChild.data).to.eql('Please click', l.toXPath());
202203
});
203204

@@ -301,4 +302,16 @@ describe('Locator', () => {
301302
expect(nodes).to.have.length(1, l.toXPath());
302303
expect(nodes[0].firstChild.data).to.eql('Authoring', l.toXPath());
303304
});
305+
306+
it('should find element with last of type with text', () => {
307+
const l = Locator.build('.p-confirm-popup:last-of-type button').withText('delete');
308+
const nodes = xpath.select(l.toXPath(), doc);
309+
expect(nodes).to.have.length(0, l.toXPath());
310+
});
311+
312+
it('should find element with last of type without text', () => {
313+
const l = Locator.build('.p-confirm-popup:last-of-type button');
314+
const nodes = xpath.select(l.toXPath(), doc);
315+
expect(nodes).to.have.length(0, l.toXPath());
316+
});
304317
});

0 commit comments

Comments
 (0)