UNPKG

5.36 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.findStrategy = void 0;
7
8var _constants = require("../constants");
9
10var _lodash = _interopRequireDefault(require("lodash.isplainobject"));
11
12function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
14const DEFAULT_STRATEGY = 'css selector';
15const DIRECT_SELECTOR_REGEXP = /^(id|css selector|xpath|link text|partial link text|name|tag name|class name|-android uiautomator|-android datamatcher|-android viewmatcher|-android viewtag|-ios uiautomation|-ios predicate string|-ios class chain|accessibility id):(.+)/;
16const XPATH_SELECTORS_START = ['/', '(', '../', './', '*/'];
17const NAME_MOBILE_SELECTORS_START = ['uia', 'xcuielementtype', 'android.widget', 'cyi'];
18const XPATH_SELECTOR_REGEXP = [/^([a-z0-9|-]*)/, /(?:(\.|#)(-?[_a-zA-Z]+[_a-zA-Z0-9-]*))?/, /(?:\[(-?[_a-zA-Z]+[_a-zA-Z0-9-]*)(?:=(?:"|')([a-zA-z0-9\-_. ]+)(?:"|'))?\])?/, /(\*)?=(.+)$/];
19
20const defineStrategy = function (selector) {
21 if ((0, _lodash.default)(selector)) {
22 if (JSON.stringify(selector).indexOf('test.espresso.matcher.ViewMatchers') < 0) return '-android datamatcher';
23 return '-android viewmatcher';
24 }
25
26 if (selector.match(DIRECT_SELECTOR_REGEXP)) {
27 return 'directly';
28 }
29
30 if (XPATH_SELECTORS_START.some(option => selector.startsWith(option))) {
31 return 'xpath';
32 }
33
34 if (selector.startsWith('=')) {
35 return 'link text';
36 }
37
38 if (selector.startsWith('*=')) {
39 return 'partial link text';
40 }
41
42 if (selector.startsWith('id=')) {
43 return 'id';
44 }
45
46 if (selector.startsWith('android=')) {
47 return '-android uiautomator';
48 }
49
50 if (selector.startsWith('ios=')) {
51 return '-ios uiautomation';
52 }
53
54 if (selector.startsWith('~')) {
55 return 'accessibility id';
56 }
57
58 if (NAME_MOBILE_SELECTORS_START.some(option => selector.toLowerCase().startsWith(option))) {
59 return 'class name';
60 }
61
62 if (selector.search(/<[0-9a-zA-Z-]+( \/)*>/g) >= 0) {
63 return 'tag name';
64 }
65
66 if (selector.search(/^\[name=("|')([a-zA-z0-9\-_.@=[\] ']+)("|')]$/) >= 0) {
67 return 'name';
68 }
69
70 if (selector === '..' || selector === '.') {
71 return 'xpath';
72 }
73
74 if (selector.match(new RegExp(XPATH_SELECTOR_REGEXP.map(rx => rx.source).join('')))) {
75 return 'xpath extended';
76 }
77};
78
79const findStrategy = function (selector, isW3C, isMobile) {
80 let using = DEFAULT_STRATEGY;
81 let value = selector;
82
83 switch (defineStrategy(selector)) {
84 case 'directly':
85 {
86 const match = selector.match(DIRECT_SELECTOR_REGEXP);
87
88 if (!isMobile && isW3C && !_constants.W3C_SELECTOR_STRATEGIES.includes(match[1])) {
89 throw new Error('InvalidSelectorStrategy');
90 }
91
92 using = match[1];
93 value = match[2];
94 break;
95 }
96
97 case 'xpath':
98 {
99 using = 'xpath';
100 break;
101 }
102
103 case 'id':
104 {
105 using = 'id';
106 value = selector.slice(3);
107 break;
108 }
109
110 case 'link text':
111 {
112 using = 'link text';
113 value = selector.slice(1);
114 break;
115 }
116
117 case 'partial link text':
118 {
119 using = 'partial link text';
120 value = selector.slice(2);
121 break;
122 }
123
124 case '-android uiautomator':
125 {
126 using = '-android uiautomator';
127 value = selector.slice(8);
128 break;
129 }
130
131 case '-android datamatcher':
132 {
133 using = '-android datamatcher';
134 value = JSON.stringify(value);
135 break;
136 }
137
138 case '-android viewmatcher':
139 {
140 using = '-android viewmatcher';
141 value = JSON.stringify(value);
142 break;
143 }
144
145 case '-ios uiautomation':
146 {
147 using = '-ios uiautomation';
148 value = selector.slice(4);
149 break;
150 }
151
152 case 'accessibility id':
153 {
154 using = 'accessibility id';
155 value = selector.slice(1);
156 break;
157 }
158
159 case 'class name':
160 {
161 using = 'class name';
162 break;
163 }
164
165 case 'tag name':
166 {
167 using = 'tag name';
168 value = selector.replace(/<|>|\/|\s/g, '');
169 break;
170 }
171
172 case 'name':
173 {
174 if (isMobile || !isW3C) {
175 using = 'name';
176 value = selector.match(/^\[name=("|')([a-zA-z0-9\-_.@=[\] ']+)("|')]$/)[2];
177 }
178
179 break;
180 }
181
182 case 'xpath extended':
183 {
184 using = 'xpath';
185 const match = selector.match(new RegExp(XPATH_SELECTOR_REGEXP.map(rx => rx.source).join('')));
186 const PREFIX_NAME = {
187 '.': 'class',
188 '#': 'id'
189 };
190 const conditions = [];
191 const [tag, prefix, name, attrName, attrValue, partial, query] = match.slice(1);
192
193 if (prefix) {
194 conditions.push(`contains(@${PREFIX_NAME[prefix]}, "${name}")`);
195 }
196
197 if (attrName) {
198 conditions.push(attrValue ? `contains(@${attrName}, "${attrValue}")` : `@${attrName}`);
199 }
200
201 conditions.push(partial ? `contains(., "${query}")` : `normalize-space() = "${query}"`);
202 value = `.//${tag || '*'}[${conditions.join(' and ')}]`;
203 break;
204 }
205 }
206
207 if (!isMobile && isW3C && !_constants.W3C_SELECTOR_STRATEGIES.includes(using)) {
208 throw new Error('InvalidSelectorStrategy');
209 }
210
211 return {
212 using,
213 value
214 };
215};
216
217exports.findStrategy = findStrategy;
\No newline at end of file