@appium/images-plugin 1.2.3 → 1.2.4
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/README.md +1 -3
- package/build/lib/compare.js +31 -36
- package/build/lib/finder.js +215 -230
- package/build/lib/image-element.js +100 -113
- package/build/lib/plugin.js +27 -46
- package/build/test/e2e/plugin-e2e-specs.js +28 -43
- package/build/test/unit/finder-specs.js +228 -303
- package/build/test/unit/image-element-specs.js +118 -163
- package/build/test/unit/plugin-specs.js +91 -141
- package/build/tsconfig.tsbuildinfo +1 -0
- package/lib/compare.js +9 -4
- package/package.json +6 -5
- package/build/test/unit/basic-specs.js +0 -16
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
4
|
};
|
|
@@ -127,87 +118,85 @@ class ImageElement {
|
|
|
127
118
|
*
|
|
128
119
|
* @param {BaseDriver} driver - driver for calling actions with
|
|
129
120
|
*/
|
|
130
|
-
click(driver) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
121
|
+
async click(driver) {
|
|
122
|
+
// before we click we need to make sure the element is actually still there
|
|
123
|
+
// where we expect it to be
|
|
124
|
+
let newImgEl;
|
|
125
|
+
const settings = Object.assign({}, finder_1.DEFAULT_SETTINGS, driver.settings.getSettings());
|
|
126
|
+
const { autoUpdateImageElementPosition: updatePos, checkForImageElementStaleness, imageElementTapStrategy, } = settings;
|
|
127
|
+
// validate tap strategy
|
|
128
|
+
if (!IMAGE_TAP_STRATEGIES.includes(imageElementTapStrategy)) {
|
|
129
|
+
throw new Error(`Incorrect imageElementTapStrategy setting ` +
|
|
130
|
+
`'${imageElementTapStrategy}'. Must be one of ` +
|
|
131
|
+
JSON.stringify(IMAGE_TAP_STRATEGIES));
|
|
132
|
+
}
|
|
133
|
+
if (checkForImageElementStaleness || updatePos) {
|
|
134
|
+
logger_1.default.info('Checking image element for staleness before clicking');
|
|
135
|
+
try {
|
|
136
|
+
newImgEl = await this.finder.findByImage(this.template, {
|
|
137
|
+
shouldCheckStaleness: true,
|
|
138
|
+
// Set ignoreDefaultImageTemplateScale because this.template is device screenshot based image
|
|
139
|
+
// managed inside Appium after finidng image by template which managed by a user
|
|
140
|
+
ignoreDefaultImageTemplateScale: true
|
|
141
|
+
});
|
|
142
142
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
try {
|
|
146
|
-
newImgEl = yield this.finder.findByImage(this.template, {
|
|
147
|
-
shouldCheckStaleness: true,
|
|
148
|
-
// Set ignoreDefaultImageTemplateScale because this.template is device screenshot based image
|
|
149
|
-
// managed inside Appium after finidng image by template which managed by a user
|
|
150
|
-
ignoreDefaultImageTemplateScale: true
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
catch (err) {
|
|
154
|
-
throw new base_driver_1.errors.StaleElementReferenceError();
|
|
155
|
-
}
|
|
156
|
-
if (!this.equals(newImgEl)) {
|
|
157
|
-
logger_1.default.warn(`When trying to click on an image element, the image changed ` +
|
|
158
|
-
`position from where it was originally found. It is now at ` +
|
|
159
|
-
`${JSON.stringify(newImgEl.rect)} and was originally at ` +
|
|
160
|
-
`${JSON.stringify(this.rect)}.`);
|
|
161
|
-
if (updatePos) {
|
|
162
|
-
logger_1.default.warn('Click will proceed at new coordinates');
|
|
163
|
-
this.rect = lodash_1.default.clone(newImgEl.rect);
|
|
164
|
-
}
|
|
165
|
-
else {
|
|
166
|
-
logger_1.default.warn('Click will take place at original coordinates. If you ' +
|
|
167
|
-
'would like Appium to automatically click the new ' +
|
|
168
|
-
"coordinates, set the 'autoUpdateImageElementPosition' " +
|
|
169
|
-
'setting to true');
|
|
170
|
-
}
|
|
171
|
-
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
throw new base_driver_1.errors.StaleElementReferenceError();
|
|
172
145
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
]
|
|
188
|
-
};
|
|
189
|
-
// check if the driver has the appropriate performActions method
|
|
190
|
-
if (driver.performActions) {
|
|
191
|
-
return yield driver.performActions([action]);
|
|
146
|
+
if (!this.equals(newImgEl)) {
|
|
147
|
+
logger_1.default.warn(`When trying to click on an image element, the image changed ` +
|
|
148
|
+
`position from where it was originally found. It is now at ` +
|
|
149
|
+
`${JSON.stringify(newImgEl.rect)} and was originally at ` +
|
|
150
|
+
`${JSON.stringify(this.rect)}.`);
|
|
151
|
+
if (updatePos) {
|
|
152
|
+
logger_1.default.warn('Click will proceed at new coordinates');
|
|
153
|
+
this.rect = lodash_1.default.clone(newImgEl.rect);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
logger_1.default.warn('Click will take place at original coordinates. If you ' +
|
|
157
|
+
'would like Appium to automatically click the new ' +
|
|
158
|
+
"coordinates, set the 'autoUpdateImageElementPosition' " +
|
|
159
|
+
'setting to true');
|
|
192
160
|
}
|
|
193
|
-
// if not, warn and fall back to the other method
|
|
194
|
-
logger_1.default.warn('Driver does not seem to implement W3C actions, falling back ' +
|
|
195
|
-
'to TouchActions');
|
|
196
161
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
162
|
+
}
|
|
163
|
+
const { x, y } = this.center;
|
|
164
|
+
logger_1.default.info(`Will tap on image element at coordinate [${x}, ${y}]`);
|
|
165
|
+
if (imageElementTapStrategy === IMAGE_EL_TAP_STRATEGY_W3C) {
|
|
166
|
+
// set up a W3C action to click on the image by position
|
|
167
|
+
logger_1.default.info('Will tap using W3C actions');
|
|
200
168
|
const action = {
|
|
201
|
-
|
|
202
|
-
|
|
169
|
+
type: 'pointer',
|
|
170
|
+
id: 'mouse',
|
|
171
|
+
parameters: { pointerType: 'touch' },
|
|
172
|
+
actions: [
|
|
173
|
+
{ type: 'pointerMove', x, y, duration: 0 },
|
|
174
|
+
{ type: 'pointerDown', button: 0 },
|
|
175
|
+
{ type: 'pause', duration: TAP_DURATION_MS },
|
|
176
|
+
{ type: 'pointerUp', button: 0 },
|
|
177
|
+
]
|
|
203
178
|
};
|
|
204
|
-
if
|
|
205
|
-
|
|
179
|
+
// check if the driver has the appropriate performActions method
|
|
180
|
+
if (driver.performActions) {
|
|
181
|
+
return await driver.performActions([action]);
|
|
206
182
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
183
|
+
// if not, warn and fall back to the other method
|
|
184
|
+
logger_1.default.warn('Driver does not seem to implement W3C actions, falling back ' +
|
|
185
|
+
'to TouchActions');
|
|
186
|
+
}
|
|
187
|
+
// if the w3c strategy was not requested, do the only other option (mjsonwp
|
|
188
|
+
// touch actions)
|
|
189
|
+
logger_1.default.info('Will tap using MJSONWP TouchActions');
|
|
190
|
+
const action = {
|
|
191
|
+
action: 'tap',
|
|
192
|
+
options: { x, y }
|
|
193
|
+
};
|
|
194
|
+
if (driver.performTouch) {
|
|
195
|
+
return await driver.performTouch([action]);
|
|
196
|
+
}
|
|
197
|
+
throw new Error("Driver did not implement the 'performTouch' command. " +
|
|
198
|
+
'For drivers to support finding image elements, they ' +
|
|
199
|
+
"should support 'performTouch' and 'performActions'");
|
|
211
200
|
}
|
|
212
201
|
/**
|
|
213
202
|
* Handle various Appium commands that involve an image element
|
|
@@ -219,37 +208,35 @@ class ImageElement {
|
|
|
219
208
|
*
|
|
220
209
|
* @returns {Object} - the result of running a command
|
|
221
210
|
*/
|
|
222
|
-
static execute(driver, imgEl, cmd, ...args) {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
}
|
|
250
|
-
});
|
|
211
|
+
static async execute(driver, imgEl, cmd, ...args) {
|
|
212
|
+
switch (cmd) {
|
|
213
|
+
case 'click':
|
|
214
|
+
return await imgEl.click(driver);
|
|
215
|
+
case 'elementDisplayed':
|
|
216
|
+
return true;
|
|
217
|
+
case 'getSize':
|
|
218
|
+
return imgEl.size;
|
|
219
|
+
case 'getLocation':
|
|
220
|
+
case 'getLocationInView':
|
|
221
|
+
return imgEl.location;
|
|
222
|
+
case 'getElementRect':
|
|
223
|
+
return imgEl.rect;
|
|
224
|
+
case 'getAttribute':
|
|
225
|
+
// /session/:sessionId/element/:elementId/attribute/:name
|
|
226
|
+
// /session/:sessionId/element/:elementId/attribute/visual should retun the visual data
|
|
227
|
+
// e.g. ["content-desc","appium-image-element-xxxxx","xxxxx"], ["visual","appium-image-element-xxxxx","xxxxx"]
|
|
228
|
+
switch (args[0]) {
|
|
229
|
+
case 'visual':
|
|
230
|
+
return imgEl.matchedImage;
|
|
231
|
+
case 'score':
|
|
232
|
+
return imgEl.score;
|
|
233
|
+
default:
|
|
234
|
+
throw new base_driver_1.errors.NotYetImplementedError();
|
|
235
|
+
}
|
|
236
|
+
default: throw new base_driver_1.errors.NotYetImplementedError();
|
|
237
|
+
}
|
|
251
238
|
}
|
|
252
239
|
}
|
|
253
240
|
exports.default = ImageElement;
|
|
254
241
|
exports.ImageElement = ImageElement;
|
|
255
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
242
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1hZ2UtZWxlbWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL2xpYi9pbWFnZS1lbGVtZW50LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLG9EQUF1QjtBQUN2QixxREFBNkM7QUFDN0Msc0RBQTJCO0FBQzNCLDZDQUF1QztBQUN2QyxxQ0FBNEM7QUFFNUMsTUFBTSxvQkFBb0IsR0FBRyx1QkFBdUIsQ0FBQztBQTRQckIsb0RBQW9CO0FBM1BwRCxNQUFNLGVBQWUsR0FBRyxHQUFHLENBQUM7QUFDNUIsTUFBTSx5QkFBeUIsR0FBRyxZQUFZLENBQUM7QUF5UEEsOERBQXlCO0FBeFB4RSxNQUFNLDZCQUE2QixHQUFHLGNBQWMsQ0FBQztBQXdQckMsc0VBQTZCO0FBdlA3QyxNQUFNLG9CQUFvQixHQUFHO0lBQzNCLDZCQUE2QjtJQUM3Qix5QkFBeUI7Q0FDMUIsQ0FBQztBQUNGLE1BQU0sNEJBQTRCLEdBQUcsR0FBRyxDQUFDO0FBb1B2QyxvRUFBNEI7QUFsUDlCOzs7Ozs7R0FNRztBQUVIOzs7O0dBSUc7QUFFSDs7OztHQUlHO0FBRUg7OztHQUdHO0FBQ0gsTUFBcUIsWUFBWTtJQUUvQjs7Ozs7Ozs7Ozs7T0FXRztJQUNILFlBQWEsV0FBVyxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsU0FBUyxHQUFHLElBQUksRUFBRSxNQUFNLEdBQUcsSUFBSTtRQUNwRSxJQUFJLENBQUMsUUFBUSxHQUFHLFdBQVcsQ0FBQztRQUM1QixJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQztRQUNqQixJQUFJLENBQUMsRUFBRSxHQUFHLEdBQUcsb0JBQW9CLEdBQUcsY0FBSSxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUM7UUFDcEQsSUFBSSxDQUFDLGVBQWUsR0FBRyxTQUFTLENBQUM7UUFDakMsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUM7UUFDbkIsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7SUFDdkIsQ0FB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
|
package/build/lib/plugin.js
CHANGED
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/* eslint-disable no-case-declarations */
|
|
3
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
4
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
5
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
6
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
7
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
8
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
9
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
10
|
-
});
|
|
11
|
-
};
|
|
12
3
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
13
4
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
14
5
|
};
|
|
@@ -35,47 +26,37 @@ class ImageElementPlugin extends base_plugin_1.default {
|
|
|
35
26
|
super(pluginName);
|
|
36
27
|
this.finder = new finder_1.default();
|
|
37
28
|
}
|
|
38
|
-
compareImages(next, driver, ...args) {
|
|
39
|
-
return
|
|
40
|
-
return yield (0, compare_1.compareImages)(...args);
|
|
41
|
-
});
|
|
29
|
+
async compareImages(next, driver, ...args) {
|
|
30
|
+
return await (0, compare_1.compareImages)(...args);
|
|
42
31
|
}
|
|
43
|
-
findElement(next, driver, ...args) {
|
|
44
|
-
return
|
|
45
|
-
return yield this._find(false, next, driver, ...args);
|
|
46
|
-
});
|
|
32
|
+
async findElement(next, driver, ...args) {
|
|
33
|
+
return await this._find(false, next, driver, ...args);
|
|
47
34
|
}
|
|
48
|
-
findElements(next, driver, ...args) {
|
|
49
|
-
return
|
|
50
|
-
return yield this._find(true, next, driver, ...args);
|
|
51
|
-
});
|
|
35
|
+
async findElements(next, driver, ...args) {
|
|
36
|
+
return await this._find(true, next, driver, ...args);
|
|
52
37
|
}
|
|
53
|
-
_find(multiple, next, driver, ...args) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
return yield this.finder.findByImage(selector, { multiple });
|
|
62
|
-
});
|
|
38
|
+
async _find(multiple, next, driver, ...args) {
|
|
39
|
+
const [strategy, selector] = args;
|
|
40
|
+
// if we're not actually finding by image, just do the normal thing
|
|
41
|
+
if (strategy !== IMAGE_STRATEGY) {
|
|
42
|
+
return await next();
|
|
43
|
+
}
|
|
44
|
+
this.finder.setDriver(driver);
|
|
45
|
+
return await this.finder.findByImage(selector, { multiple });
|
|
63
46
|
}
|
|
64
|
-
handle(next, driver, cmdName, ...args) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (imgElId) {
|
|
70
|
-
|
|
71
|
-
throw new base_driver_1.errors.NoSuchElementError();
|
|
72
|
-
}
|
|
73
|
-
const imgEl = this.finder.imgElCache.get(imgElId);
|
|
74
|
-
return yield image_element_1.ImageElement.execute(driver, imgEl, cmdName, ...args);
|
|
47
|
+
async handle(next, driver, cmdName, ...args) {
|
|
48
|
+
// if we have a command that involves an image element id, attempt to find the image element
|
|
49
|
+
// and execute the command on it
|
|
50
|
+
const imgElId = getImgElFromArgs(args);
|
|
51
|
+
if (imgElId) {
|
|
52
|
+
if (!this.finder.imgElCache.has(imgElId)) {
|
|
53
|
+
throw new base_driver_1.errors.NoSuchElementError();
|
|
75
54
|
}
|
|
76
|
-
|
|
77
|
-
return
|
|
78
|
-
}
|
|
55
|
+
const imgEl = this.finder.imgElCache.get(imgElId);
|
|
56
|
+
return await image_element_1.ImageElement.execute(driver, imgEl, cmdName, ...args);
|
|
57
|
+
}
|
|
58
|
+
// otherwise just do the normal thing
|
|
59
|
+
return await next();
|
|
79
60
|
}
|
|
80
61
|
}
|
|
81
62
|
exports.default = ImageElementPlugin;
|
|
@@ -93,4 +74,4 @@ ImageElementPlugin.newMethodMap = {
|
|
|
93
74
|
}
|
|
94
75
|
},
|
|
95
76
|
};
|
|
96
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
77
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vbGliL3BsdWdpbi5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEseUNBQXlDOzs7Ozs7QUFFekMsb0RBQXVCO0FBQ3ZCLHFEQUE2QztBQUM3QyxzRUFBNkM7QUFDN0MsdUNBQTBDO0FBQzFDLHNEQUEwQztBQUMxQyxtREFBcUU7QUFFckUsTUFBTSxjQUFjLEdBQUcsUUFBUSxDQUFDO0FBd0VlLHdDQUFjO0FBdEU3RCxTQUFTLGdCQUFnQixDQUFFLElBQUk7SUFDN0IsS0FBSyxJQUFJLEdBQUcsSUFBSSxJQUFJLEVBQUU7UUFDcEIsSUFBSSxnQkFBQyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsSUFBSSxHQUFHLENBQUMsVUFBVSxDQUFDLG9DQUFvQixDQUFDLEVBQUU7WUFDM0QsT0FBTyxHQUFHLENBQUM7U0FDWjtLQUNGO0FBQ0gsQ0FBQztBQWdFNEIsNENBQWdCO0FBOUQ3QyxNQUFxQixrQkFBbUIsU0FBUSxxQkFBVTtJQUV4RCxZQUFhLFVBQVU7UUFDckIsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ2xCLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxnQkFBa0IsRUFBRSxDQUFDO0lBQ3pDLENBQUM7SUFnQkQsS0FBSyxDQUFDLGFBQWEsQ0FBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLEdBQUcsSUFBSTtRQUN4QyxPQUFPLE1BQU0sSUFBQSx1QkFBYSxFQUFDLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDdEMsQ0FBQztJQUVELEtBQUssQ0FBQyxXQUFXLENBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxHQUFHLElBQUk7UUFDdEMsT0FBTyxNQUFNLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsQ0FBQztJQUN4RCxDQUFDO0lBRUQsS0FBSyxDQUFDLFlBQVksQ0FBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLEdBQUcsSUFBSTtRQUN2QyxPQUFPLE1BQU0sSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDO0lBQ3ZELENBQUM7SUFFRCxLQUFLLENBQUMsS0FBSyxDQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLEdBQUcsSUFBSTtRQUMxQyxNQUFNLENBQUMsUUFBUSxFQUFFLFFBQVEsQ0FBQyxHQUFHLElBQUksQ0FBQztRQUVsQyxtRUFBbUU7UUFDbkUsSUFBSSxRQUFRLEtBQUssY0FBYyxFQUFFO1lBQy9CLE9BQU8sTUFBTSxJQUFJLEVBQUUsQ0FBQztTQUNyQjtRQUVELElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQzlCLE9BQU8sTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxRQUFRLEVBQUUsRUFBQyxRQUFRLEVBQUMsQ0FBQyxDQUFDO0lBQzdELENBQUM7SUFFRCxLQUFLLENBQUMsTUFBTSxDQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLEdBQUcsSUFBSTtRQUMxQyw0RkFBNEY7UUFDNUYsZ0NBQWdDO1FBQ2hDLE1BQU0sT0FBTyxHQUFHLGdCQUFnQixDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3ZDLElBQUksT0FBTyxFQUFFO1lBQ1gsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsRUFBRTtnQkFDeEMsTUFBTSxJQUFJLG9CQUFNLENBQUMsa0JBQWtCLEVBQUUsQ0FBQzthQUN2QztZQUNELE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUNsRCxPQUFPLE1BQU0sNEJBQVksQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsR0FBRyxJQUFJLENBQUMsQ0FBQztTQUNwRTtRQUVELHFDQUFxQztRQUNyQyxPQUFPLE1BQU0sSUFBSSxFQUFFLENBQUM7SUFDdEIsQ0FBQzs7QUEzREgscUNBNERDO0FBRVEsZ0RBQWtCO0FBdkR6QiwrREFBK0Q7QUFDeEQsK0JBQVksR0FBRztJQUNwQiwyQ0FBMkMsRUFBRTtRQUMzQyxJQUFJLEVBQUU7WUFDSixPQUFPLEVBQUUsZUFBZTtZQUN4QixhQUFhLEVBQUU7Z0JBQ2IsUUFBUSxFQUFFLENBQUMsTUFBTSxFQUFFLFlBQVksRUFBRSxhQUFhLENBQUM7Z0JBQy9DLFFBQVEsRUFBRSxDQUFDLFNBQVMsQ0FBQzthQUN0QjtZQUNELFVBQVUsRUFBRSxJQUFJO1NBQ2pCO0tBQ0Y7Q0FDRixDQUFDIn0=
|
|
@@ -1,20 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
4
|
};
|
|
14
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const path_1 = __importDefault(require("path"));
|
|
7
|
+
const APPIUM_HOME = path_1.default.resolve(__dirname, '..', '..', '..', 'local_appium_home');
|
|
8
|
+
// need to assign this before appium is imported via e2eSetup
|
|
9
|
+
process.env.APPIUM_HOME = APPIUM_HOME;
|
|
15
10
|
const chai_1 = __importDefault(require("chai"));
|
|
16
11
|
const chai_as_promised_1 = __importDefault(require("chai-as-promised"));
|
|
17
|
-
const path_1 = __importDefault(require("path"));
|
|
18
12
|
const webdriverio_1 = require("webdriverio");
|
|
19
13
|
const compare_1 = require("../../lib/compare");
|
|
20
14
|
const fixtures_1 = require("../fixtures");
|
|
@@ -22,10 +16,8 @@ const helpers_1 = require("@appium/base-plugin/build/test/helpers");
|
|
|
22
16
|
chai_1.default.use(chai_as_promised_1.default);
|
|
23
17
|
chai_1.default.should();
|
|
24
18
|
const THIS_PLUGIN_DIR = path_1.default.resolve(__dirname, '..', '..', '..');
|
|
25
|
-
const APPIUM_HOME = path_1.default.resolve(__dirname, '..', '..', '..', 'local_appium_home');
|
|
26
19
|
const TEST_HOST = 'localhost';
|
|
27
|
-
const
|
|
28
|
-
const TEST_FAKE_APP = path_1.default.resolve(APPIUM_HOME, 'appium-fake-driver', 'node_modules', 'appium-fake-driver', 'test', 'fixtures', 'app.xml');
|
|
20
|
+
const TEST_FAKE_APP = path_1.default.resolve(APPIUM_HOME, '@appium', 'fake-driver', 'node_modules', '@appium', 'fake-driver', 'test', 'fixtures', 'app.xml');
|
|
29
21
|
const TEST_CAPS = {
|
|
30
22
|
platformName: 'Fake',
|
|
31
23
|
'appium:automationName': 'Fake',
|
|
@@ -34,44 +26,37 @@ const TEST_CAPS = {
|
|
|
34
26
|
};
|
|
35
27
|
const WDIO_OPTS = {
|
|
36
28
|
hostname: TEST_HOST,
|
|
37
|
-
port: TEST_PORT,
|
|
38
29
|
connectionRetryCount: 0,
|
|
39
30
|
capabilities: TEST_CAPS
|
|
40
31
|
};
|
|
41
32
|
describe('ImageElementPlugin', function () {
|
|
42
33
|
let server, driver = null;
|
|
43
|
-
after(function () {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
});
|
|
34
|
+
after(async function () {
|
|
35
|
+
if (driver) {
|
|
36
|
+
await driver.deleteSession();
|
|
37
|
+
}
|
|
49
38
|
});
|
|
50
39
|
(0, helpers_1.e2eSetup)({
|
|
51
|
-
before, after, server,
|
|
52
|
-
|
|
53
|
-
|
|
40
|
+
before, after, server, host: TEST_HOST, driverName: 'fake', driverSource: 'npm',
|
|
41
|
+
driverSpec: '@appium/fake-driver', pluginName: 'images', pluginSource: 'local',
|
|
42
|
+
pluginSpec: THIS_PLUGIN_DIR,
|
|
54
43
|
});
|
|
55
|
-
it('should add the compareImages route', function () {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
comparison.score.should.be.above(0.2);
|
|
62
|
-
});
|
|
44
|
+
it('should add the compareImages route', async function () {
|
|
45
|
+
driver = await (0, webdriverio_1.remote)({ ...WDIO_OPTS, port: this.port });
|
|
46
|
+
let comparison = await driver.compareImages(compare_1.MATCH_FEATURES_MODE, fixtures_1.TEST_IMG_1_B64, fixtures_1.TEST_IMG_2_B64, {});
|
|
47
|
+
comparison.count.should.eql(0);
|
|
48
|
+
comparison = await driver.compareImages(compare_1.GET_SIMILARITY_MODE, fixtures_1.TEST_IMG_1_B64, fixtures_1.TEST_IMG_2_B64, {});
|
|
49
|
+
comparison.score.should.be.above(0.2);
|
|
63
50
|
});
|
|
64
|
-
it('should find and interact with image elements', function () {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
yield imageEl.click();
|
|
74
|
-
});
|
|
51
|
+
it('should find and interact with image elements', async function () {
|
|
52
|
+
const imageEl = await driver.$(fixtures_1.APPSTORE_IMG_PATH);
|
|
53
|
+
const { x, y } = await imageEl.getLocation();
|
|
54
|
+
const { width, height } = await imageEl.getSize();
|
|
55
|
+
x.should.eql(28);
|
|
56
|
+
y.should.eql(72);
|
|
57
|
+
width.should.eql(80);
|
|
58
|
+
height.should.eql(91);
|
|
59
|
+
await imageEl.click();
|
|
75
60
|
});
|
|
76
61
|
});
|
|
77
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
62
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLWUyZS1zcGVjcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Rlc3QvZTJlL3BsdWdpbi1lMmUtc3BlY3MuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxnREFBd0I7QUFDeEIsTUFBTSxXQUFXLEdBQUcsY0FBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsbUJBQW1CLENBQUMsQ0FBQztBQUNuRiw2REFBNkQ7QUFDN0QsT0FBTyxDQUFDLEdBQUcsQ0FBQyxXQUFXLEdBQUcsV0FBVyxDQUFDO0FBRXRDLGdEQUF3QjtBQUN4Qix3RUFBOEM7QUFDOUMsNkNBQTZDO0FBQzdDLCtDQUE2RTtBQUM3RSwwQ0FBZ0Y7QUFDaEYsb0VBQWtFO0FBRWxFLGNBQUksQ0FBQyxHQUFHLENBQUMsMEJBQWMsQ0FBQyxDQUFDO0FBQ3pCLGNBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztBQUVkLE1BQU0sZUFBZSxHQUFHLGNBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUM7QUFDbEUsTUFBTSxTQUFTLEdBQUcsV0FBVyxDQUFDO0FBQzlCLE1BQU0sYUFBYSxHQUFHLGNBQUksQ0FBQyxPQUFPLENBQUMsV0FBVyxFQUFFLFNBQVMsRUFBRSxhQUFhLEVBQUUsY0FBYyxFQUN0RixTQUFTLEVBQUUsYUFBYSxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsU0FBUyxDQUFDLENBQUM7QUFDM0QsTUFBTSxTQUFTLEdBQUc7SUFDaEIsWUFBWSxFQUFFLE1BQU07SUFDcEIsdUJBQXVCLEVBQUUsTUFBTTtJQUMvQixtQkFBbUIsRUFBRSxNQUFNO0lBQzNCLFlBQVksRUFBRSxhQUFhO0NBQzVCLENBQUM7QUFDRixNQUFNLFNBQVMsR0FBRztJQUNoQixRQUFRLEVBQUUsU0FBUztJQUNuQixvQkFBb0IsRUFBRSxDQUFDO0lBQ3ZCLFlBQVksRUFBRSxTQUFTO0NBQ3hCLENBQUM7QUFFRixRQUFRLENBQUMsb0JBQW9CLEVBQUU7SUFDN0IsSUFBSSxNQUFNLEVBQUUsTUFBTSxHQUFHLElBQUksQ0FBQztJQUUxQixLQUFLLENBQUMsS0FBSztRQUNULElBQUksTUFBTSxFQUFFO1lBQ1YsTUFBTSxNQUFNLENBQUMsYUFBYSxFQUFFLENBQUM7U0FDOUI7SUFDSCxDQUFDLENBQUMsQ0FBQztJQUVILElBQUEsa0JBQVEsRUFBQztRQUNQLE1BQU0sRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQUUsS0FBSztRQUMvRSxVQUFVLEVBQUUscUJBQXFCLEVBQUUsVUFBVSxFQUFFLFFBQVEsRUFBRSxZQUFZLEVBQUUsT0FBTztRQUM5RSxVQUFVLEVBQUUsZUFBZTtLQUM1QixDQUFDLENBQUM7SUFFSCxFQUFFLENBQUMsb0NBQW9DLEVBQUUsS0FBSztRQUM1QyxNQUFNLEdBQUcsTUFBTSxJQUFBLG9CQUFJLEVBQUMsRUFBQyxHQUFHLFNBQVMsRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUksRUFBQyxDQUFDLENBQUM7UUFDckQsSUFBSSxVQUFVLEdBQUcsTUFBTSxNQUFNLENBQUMsYUFBYSxDQUFDLDZCQUFtQixFQUFFLHlCQUFjLEVBQUUseUJBQWMsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUNyRyxVQUFVLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDL0IsVUFBVSxHQUFHLE1BQU0sTUFBTSxDQUFDLGFBQWEsQ0FBQyw2QkFBbUIsRUFBRSx5QkFBYyxFQUFFLHlCQUFjLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDakcsVUFBVSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUN4QyxDQUFDLENBQUMsQ0FBQztJQUVILEVBQUUsQ0FBQyw4Q0FBOEMsRUFBRSxLQUFLO1FBQ3RELE1BQU0sT0FBTyxHQUFHLE1BQU0sTUFBTSxDQUFDLENBQUMsQ0FBQyw0QkFBaUIsQ0FBQyxDQUFDO1FBQ2xELE1BQU0sRUFBQyxDQUFDLEVBQUUsQ0FBQyxFQUFDLEdBQUcsTUFBTSxPQUFPLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDM0MsTUFBTSxFQUFDLEtBQUssRUFBRSxNQUFNLEVBQUMsR0FBRyxNQUFNLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNoRCxDQUFDLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNqQixDQUFDLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNqQixLQUFLLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNyQixNQUFNLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUN0QixNQUFNLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUN4QixDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDIn0=
|