@lvce-editor/test-worker 13.27.0 → 14.0.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/dist/api.d.ts +25 -4
- package/dist/testWorkerMain.js +122 -21
- package/package.json +1 -1
package/dist/api.d.ts
CHANGED
|
@@ -28,15 +28,36 @@ interface ILocatorExternal {
|
|
|
28
28
|
readonly type: (text: string) => Promise<void>;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
interface ParsedCssSelectorPart {
|
|
32
|
+
readonly selector: string;
|
|
33
|
+
readonly type: "css";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface ParsedTextSelectorPart {
|
|
37
|
+
readonly text: string;
|
|
38
|
+
readonly type: "text";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface ParsedHasTextSelectorPart {
|
|
42
|
+
readonly text: string;
|
|
43
|
+
readonly type: "has-text";
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
interface ParsedNthSelectorPart {
|
|
47
|
+
readonly index: number;
|
|
48
|
+
readonly type: "nth";
|
|
49
|
+
}
|
|
50
|
+
export type ParsedSelectorPart = ParsedCssSelectorPart | ParsedTextSelectorPart | ParsedHasTextSelectorPart | ParsedNthSelectorPart;
|
|
51
|
+
export type ParsedCssSelector = readonly ParsedSelectorPart[];
|
|
52
|
+
|
|
31
53
|
interface ILocatorCreateOptions {
|
|
32
54
|
readonly hasText?: string;
|
|
33
55
|
readonly nth?: number;
|
|
34
56
|
}
|
|
35
57
|
export declare class Locator implements ILocatorExternal {
|
|
36
|
-
readonly _selector:
|
|
37
|
-
readonly
|
|
38
|
-
|
|
39
|
-
constructor(selector: any, options?: ILocatorCreateOptions);
|
|
58
|
+
readonly _selector: string;
|
|
59
|
+
readonly _parsed: ParsedCssSelector;
|
|
60
|
+
constructor(selector: string, options?: ILocatorCreateOptions, parsed?: ParsedCssSelector);
|
|
40
61
|
click({ button }?: {
|
|
41
62
|
readonly button?: string;
|
|
42
63
|
}): Promise<void>;
|
package/dist/testWorkerMain.js
CHANGED
|
@@ -1235,22 +1235,40 @@ const locatorInvoke = async (locator, method, ...params) => {
|
|
|
1235
1235
|
};
|
|
1236
1236
|
|
|
1237
1237
|
const printLocator = locator => {
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1238
|
+
let result = '';
|
|
1239
|
+
for (const part of locator._parsed) {
|
|
1240
|
+
if (part.type === 'css') {
|
|
1241
|
+
if (!result) {
|
|
1242
|
+
result = part.selector;
|
|
1243
|
+
continue;
|
|
1244
|
+
}
|
|
1245
|
+
result = `${result} >> ${part.selector}`;
|
|
1246
|
+
continue;
|
|
1247
|
+
}
|
|
1248
|
+
if (part.type === 'text') {
|
|
1249
|
+
if (!result) {
|
|
1250
|
+
result = `text=${part.text}`;
|
|
1251
|
+
continue;
|
|
1252
|
+
}
|
|
1253
|
+
result = `${result} text=${part.text}`;
|
|
1254
|
+
continue;
|
|
1255
|
+
}
|
|
1256
|
+
if (part.type === 'has-text') {
|
|
1257
|
+
result = `${result} "${part.text}"`;
|
|
1258
|
+
continue;
|
|
1259
|
+
}
|
|
1260
|
+
result = `${result}:nth(${part.index})`;
|
|
1243
1261
|
}
|
|
1244
|
-
return
|
|
1262
|
+
return result;
|
|
1245
1263
|
};
|
|
1246
1264
|
|
|
1247
1265
|
const toBeVisible = locator => {
|
|
1248
|
-
return `expected selector to be visible ${locator
|
|
1266
|
+
return `expected selector to be visible ${printLocator(locator)}`;
|
|
1249
1267
|
};
|
|
1250
1268
|
const toHaveValue = (locator, {
|
|
1251
1269
|
value
|
|
1252
1270
|
}) => {
|
|
1253
|
-
return `expected selector ${locator
|
|
1271
|
+
return `expected selector ${printLocator(locator)} to have value ${value}`;
|
|
1254
1272
|
};
|
|
1255
1273
|
const toHaveText = async (locator, options) => {
|
|
1256
1274
|
const locatorString = printLocator(locator);
|
|
@@ -1545,6 +1563,72 @@ const setMockRpc = mockRpc => {
|
|
|
1545
1563
|
state.mockRpcs[mockRpc.name] = mockRpc;
|
|
1546
1564
|
};
|
|
1547
1565
|
|
|
1566
|
+
class CssParsingError extends Error {
|
|
1567
|
+
constructor(message) {
|
|
1568
|
+
super(message);
|
|
1569
|
+
this.name = 'CssParsingError';
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
const startTokenRegex = /^[a-z][a-z0-9-]*/;
|
|
1574
|
+
const getStartToken = selector => {
|
|
1575
|
+
const match = selector.match(startTokenRegex);
|
|
1576
|
+
return match ? match[0] : '';
|
|
1577
|
+
};
|
|
1578
|
+
|
|
1579
|
+
const htmlElements = ['a', 'abbr', 'address', 'area', 'article', 'aside', 'audio', 'b', 'base', 'bdo', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'command', 'datalist', 'dd', 'del', 'details', 'dfn', 'dialog', 'div', 'dl', 'dt', 'em', 'embed', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'hr', 'html', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'link', 'map', 'mark', 'menu', 'meta', 'meter', 'nav', 'noscript', 'object', 'ol', 'optgroup', 'option', 'output', 'p', 'param', 'pre', 'progress', 'q', 'rp', 'rt', 's', 'samp', 'script', 'section', 'select', 'small', 'source', 'span', 'strong', 'sub', 'sup', 'table', 'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'time', 'title', 'tr', 'track', 'u', 'ul', 'var', 'video', 'wbr'];
|
|
1580
|
+
|
|
1581
|
+
const isElement = selector => {
|
|
1582
|
+
return htmlElements.includes(selector);
|
|
1583
|
+
};
|
|
1584
|
+
|
|
1585
|
+
const isCssSelector = selector => {
|
|
1586
|
+
if (!selector) {
|
|
1587
|
+
return false;
|
|
1588
|
+
}
|
|
1589
|
+
if (selector.startsWith('.') || selector.startsWith('#') || selector.startsWith('[') || selector.startsWith('*') || selector.startsWith(':')) {
|
|
1590
|
+
return true;
|
|
1591
|
+
}
|
|
1592
|
+
const startToken = getStartToken(selector);
|
|
1593
|
+
if (!startToken) {
|
|
1594
|
+
return false;
|
|
1595
|
+
}
|
|
1596
|
+
return isElement(startToken);
|
|
1597
|
+
};
|
|
1598
|
+
|
|
1599
|
+
const parseCssSelector = selector => {
|
|
1600
|
+
if (typeof selector !== 'string') {
|
|
1601
|
+
throw new TypeError('selector must be of type string');
|
|
1602
|
+
}
|
|
1603
|
+
if (selector.startsWith('text=')) {
|
|
1604
|
+
return [{
|
|
1605
|
+
text: selector.slice('text='.length),
|
|
1606
|
+
type: 'text'
|
|
1607
|
+
}];
|
|
1608
|
+
}
|
|
1609
|
+
if (selector.includes('text=')) {
|
|
1610
|
+
const index = selector.indexOf('text=');
|
|
1611
|
+
const cssSelector = selector.slice(0, index).trimEnd();
|
|
1612
|
+
if (!isCssSelector(cssSelector)) {
|
|
1613
|
+
throw new CssParsingError(`unsupported selector: ${selector}`);
|
|
1614
|
+
}
|
|
1615
|
+
return [{
|
|
1616
|
+
selector: cssSelector,
|
|
1617
|
+
type: 'css'
|
|
1618
|
+
}, {
|
|
1619
|
+
text: selector.slice(index + 'text='.length),
|
|
1620
|
+
type: 'text'
|
|
1621
|
+
}];
|
|
1622
|
+
}
|
|
1623
|
+
if (isCssSelector(selector)) {
|
|
1624
|
+
return [{
|
|
1625
|
+
selector,
|
|
1626
|
+
type: 'css'
|
|
1627
|
+
}];
|
|
1628
|
+
}
|
|
1629
|
+
throw new CssParsingError(`unsupported selector: ${selector}`);
|
|
1630
|
+
};
|
|
1631
|
+
|
|
1548
1632
|
const performAction = async (locator, action, options) => {
|
|
1549
1633
|
const invoke = getLocatorInvoke(locator);
|
|
1550
1634
|
return invoke('TestFrameWork.performAction', locator, action, options);
|
|
@@ -1564,7 +1648,7 @@ const toButtonNumber = buttonType => {
|
|
|
1564
1648
|
};
|
|
1565
1649
|
|
|
1566
1650
|
class Locator {
|
|
1567
|
-
constructor(selector, options = {}) {
|
|
1651
|
+
constructor(selector, options = {}, parsed) {
|
|
1568
1652
|
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
|
1569
1653
|
throw new TypeError('options must be of type object');
|
|
1570
1654
|
}
|
|
@@ -1575,8 +1659,7 @@ class Locator {
|
|
|
1575
1659
|
string(hasText, 'options.hasText must be of type string');
|
|
1576
1660
|
number(nth, 'options.nth must be of type number');
|
|
1577
1661
|
this._selector = selector;
|
|
1578
|
-
this.
|
|
1579
|
-
this._hasText = hasText;
|
|
1662
|
+
this._parsed = parsed || applyLocatorOptions(parseCssSelector(selector), options);
|
|
1580
1663
|
}
|
|
1581
1664
|
async click({
|
|
1582
1665
|
button = 'left'
|
|
@@ -1597,20 +1680,15 @@ class Locator {
|
|
|
1597
1680
|
return performAction(this, 'hover', options);
|
|
1598
1681
|
}
|
|
1599
1682
|
first() {
|
|
1600
|
-
return new Locator(this._selector, {
|
|
1601
|
-
nth: 0
|
|
1602
|
-
});
|
|
1683
|
+
return new Locator(this._selector, {}, withNth(this._parsed, 0));
|
|
1603
1684
|
}
|
|
1604
1685
|
locator(subSelector) {
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
}
|
|
1608
|
-
return new Locator(`${this._selector} ${subSelector}`);
|
|
1686
|
+
const selector = `${this._selector} ${subSelector}`;
|
|
1687
|
+
return new Locator(selector, {}, [...this._parsed, ...parseCssSelector(subSelector)]);
|
|
1609
1688
|
}
|
|
1610
1689
|
nth(nth) {
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
});
|
|
1690
|
+
number(nth, 'nth must be of type number');
|
|
1691
|
+
return new Locator(this._selector, {}, withNth(this._parsed, nth));
|
|
1614
1692
|
}
|
|
1615
1693
|
async type(text) {
|
|
1616
1694
|
const options = {
|
|
@@ -1625,6 +1703,29 @@ class Locator {
|
|
|
1625
1703
|
});
|
|
1626
1704
|
}
|
|
1627
1705
|
}
|
|
1706
|
+
const applyLocatorOptions = (parsed, {
|
|
1707
|
+
hasText = '',
|
|
1708
|
+
nth = -1
|
|
1709
|
+
}) => {
|
|
1710
|
+
let nextParsed = parsed;
|
|
1711
|
+
if (hasText) {
|
|
1712
|
+
nextParsed = [...nextParsed, {
|
|
1713
|
+
text: hasText,
|
|
1714
|
+
type: 'has-text'
|
|
1715
|
+
}];
|
|
1716
|
+
}
|
|
1717
|
+
if (nth !== -1) {
|
|
1718
|
+
nextParsed = withNth(nextParsed, nth);
|
|
1719
|
+
}
|
|
1720
|
+
return nextParsed;
|
|
1721
|
+
};
|
|
1722
|
+
const withNth = (parsed, nth) => {
|
|
1723
|
+
const filtered = parsed.filter(part => part.type !== 'nth');
|
|
1724
|
+
return [...filtered, {
|
|
1725
|
+
index: nth,
|
|
1726
|
+
type: 'nth'
|
|
1727
|
+
}];
|
|
1728
|
+
};
|
|
1628
1729
|
|
|
1629
1730
|
const createLocator = (selector, options = {}) => {
|
|
1630
1731
|
string(selector, 'selector must be of type string');
|