Skip to content

Commit ec2c558

Browse files
fix: remove duplicated property (#243)
* fix: remove duplicated property * chore: setOrientation
1 parent f04bfc8 commit ec2c558

6 files changed

+91
-78
lines changed

lib/appium-driver.ts

+27-7
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import { LogType } from "./log-types";
4848
import { screencapture } from "./helpers/screenshot-manager";
4949
import { LogImageType } from "./enums/log-image-type";
5050
import { DeviceOrientation } from "./enums/device-orientation";
51+
import { NsCapabilities } from "./ns-capabilities";
5152

5253
export class AppiumDriver {
5354
private _defaultWaitTime: number = 5000;
@@ -546,13 +547,32 @@ export class AppiumDriver {
546547
logInfo(`Set device orientation: ${orientation}`)
547548
await this._driver.setOrientation(orientation);
548549

549-
if (orientation === DeviceOrientation.LANDSCAPE) {
550-
this.imageHelper.imageCropRect.x = this._imageHelper.options.cropRectangle.x;
551-
this.imageHelper.imageCropRect.y = this._imageHelper.options.cropRectangle.y;
552-
this.imageHelper.imageCropRect.width = this._imageHelper.options.cropRectangle.height;
553-
this.imageHelper.imageCropRect.height = this._imageHelper.options.cropRectangle.width;
554-
} else {
555-
this.imageHelper.imageCropRect = undefined;
550+
if (orientation === DeviceOrientation.LANDSCAPE && this.isAndroid) {
551+
if ((<NsCapabilities>this.nsCapabilities).tryGetApiLevel() < 6.0) {
552+
// HACK since the image is rotated and action bar is on the bottom of the image, it is needed to exclude action bar from bottom.
553+
const height = this._imageHelper.options.cropRectangle.width - this._imageHelper.options.cropRectangle.y;
554+
const width = this._imageHelper.options.cropRectangle.height + this._imageHelper.options.cropRectangle.y;
555+
this.imageHelper.options.cropRectangle.y = 0;
556+
this.imageHelper.options.cropRectangle.width = width;
557+
this.imageHelper.options.cropRectangle.height = height;
558+
} else if ((<NsCapabilities>this.nsCapabilities).tryGetApiLevel() >= 6.0) {
559+
const height = this._imageHelper.options.cropRectangle.width - this.imageHelper.options.cropRectangle.y;
560+
const width = this._imageHelper.options.cropRectangle.height + this.imageHelper.options.cropRectangle.y;
561+
this.imageHelper.options.cropRectangle.width = width;
562+
this.imageHelper.options.cropRectangle.height = height;
563+
}
564+
}
565+
else if (orientation === DeviceOrientation.LANDSCAPE && this.isIOS) {
566+
this.imageHelper.options.cropRectangle.x = 0;
567+
const height = this._imageHelper.options.cropRectangle.width;
568+
const width = this._imageHelper.options.cropRectangle.height + this._imageHelper.options.cropRectangle.y;
569+
this.imageHelper.options.cropRectangle.y = 0;
570+
571+
this.imageHelper.options.cropRectangle.width = width;
572+
this.imageHelper.options.cropRectangle.height = height;
573+
}
574+
else {
575+
this.imageHelper.resetDefaultOptions();
556576
}
557577
}
558578

lib/image-helper.d.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ export declare class ImageHelper {
6363
private _driver;
6464
private _blockOutAreas;
6565
private _imagesResults;
66-
private _imageCropRect;
6766
private _options;
6867
private _defaultOptions;
6968
constructor(_args: INsCapabilities, _driver: AppiumDriver);
@@ -80,7 +79,6 @@ export declare class ImageHelper {
8079
*/
8180
delta: number;
8281
options: IImageCompareOptions;
83-
imageCropRect: IRectangle;
8482
blockOutAreas: IRectangle[];
8583
compareScreen(options?: IImageCompareOptions): Promise<boolean>;
8684
compareElement(element: UIElement, options?: IImageCompareOptions): Promise<boolean>;
@@ -97,7 +95,7 @@ export declare class ImageHelper {
9795
getExpectedImagePathByDevice(imageName: string): string;
9896
getExpectedImagePathByPlatform(imageName: string): string;
9997
compare(options: IImageCompareOptions): Promise<boolean>;
100-
compareImages(actual: string, expected: string, output: string, tolerance: number, toleranceType: ImageOptions): Promise<boolean>;
98+
compareImages(options: IImageCompareOptions, actual: string, expected: string, output: string): Promise<boolean>;
10199
clipRectangleImage(rect: IRectangle, path: string): Promise<{}>;
102100
readImage(path: string): Promise<any>;
103101
private runDiff;

lib/image-helper.ts

+44-48
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { AppiumDriver } from "./appium-driver";
99
import { logError, checkImageLogType, resolvePath, copy, addExt, logWarn } from "./utils";
1010
import { unlinkSync, existsSync, mkdirSync } from "fs";
1111
import { basename, join } from "path";
12-
import { isObject } from "util";
12+
import { isObject, isNumber } from "util";
1313
import { logInfo } from "mobile-devices-controller/lib/utils";
1414

1515
export interface IImageCompareOptions {
@@ -82,7 +82,6 @@ export interface IImageCompareOptions {
8282
export class ImageHelper {
8383
private _blockOutAreas: IRectangle[];
8484
private _imagesResults = new Map<string, boolean>();
85-
private _imageCropRect: IRectangle;
8685
private _options: IImageCompareOptions = {};
8786
private _defaultOptions: IImageCompareOptions = {
8887
timeOutSeconds: 2,
@@ -101,12 +100,14 @@ export class ImageHelper {
101100
constructor(private _args: INsCapabilities, private _driver: AppiumDriver) {
102101
this._defaultOptions.cropRectangle = (this._args.appiumCaps && this._args.appiumCaps.viewportRect) || this._args.device.viewportRect;
103102
if (!this._defaultOptions.cropRectangle
104-
|| this._defaultOptions.cropRectangle.y === undefined
105-
|| this._defaultOptions.cropRectangle.y === null
106-
|| this._defaultOptions.cropRectangle.y === NaN) {
103+
|| !isNumber(this._defaultOptions.cropRectangle.y)) {
107104
this._defaultOptions.cropRectangle = this._defaultOptions.cropRectangle || {};
108105
this._defaultOptions.cropRectangle.y = this._args.device.config.offsetPixels || 0;
109106
this._defaultOptions.cropRectangle.x = 0;
107+
if (this._args.device.deviceScreenSize && this._args.device.deviceScreenSize.width && this._args.device.deviceScreenSize.height) {
108+
this._defaultOptions.cropRectangle.height = this._args.device.deviceScreenSize.height - this._defaultOptions.cropRectangle.y;
109+
this._defaultOptions.cropRectangle.width = this._args.device.deviceScreenSize.width - this._defaultOptions.cropRectangle.x;
110+
}
110111
}
111112
ImageHelper.fullClone(this._defaultOptions, this._options);
112113

@@ -137,14 +138,6 @@ export class ImageHelper {
137138
this._options = this.extendOptions(options);
138139
}
139140

140-
get imageCropRect(): IRectangle {
141-
return this._imageCropRect || this.options.cropRectangle;
142-
}
143-
144-
set imageCropRect(clipRectangle: IRectangle) {
145-
this._imageCropRect = clipRectangle;
146-
}
147-
148141
get blockOutAreas() {
149142
return this._blockOutAreas;
150143
}
@@ -257,7 +250,6 @@ export class ImageHelper {
257250
// First time capture
258251
if (!existsSync(pathExpectedImage)) {
259252
await captureFirstImage();
260-
261253
return false;
262254
}
263255

@@ -269,7 +261,7 @@ export class ImageHelper {
269261
const pathDiffImage = pathActualImage.replace("actual", "diff");
270262

271263
// await this.prepareImageToCompare(pathActualImage, options.cropRectangle);
272-
let result = await this.compareImages(pathActualImage, pathExpectedImage, pathDiffImage, options.tolerance, options.toleranceType);
264+
let result = await this.compareImages(options, pathActualImage, pathExpectedImage, pathDiffImage);
273265

274266
// Iterate
275267
if (!result) {
@@ -283,7 +275,7 @@ export class ImageHelper {
283275
await this.clipRectangleImage(options.cropRectangle, pathActualImage);
284276
}
285277
// await this.prepareImageToCompare(pathActualImage, this.imageCropRect);
286-
result = await this.compareImages(pathActualImage, pathExpectedImage, pathDiffImage, options.tolerance, options.toleranceType);
278+
result = await this.compareImages(options, pathActualImage, pathExpectedImage, pathDiffImage);
287279
if (!result && checkImageLogType(this._args.testReporter, LogImageType.everyImage)) {
288280
this._args.testReporterLog(`Actual image: ${basename(pathActualImage).replace(/\.\w{3,3}$/ig, "")}`);
289281
this._args.testReporterLog(join(this._args.reportsPath, basename(pathActualImage)));
@@ -314,12 +306,12 @@ export class ImageHelper {
314306
return result;
315307
}
316308

317-
public compareImages(actual: string, expected: string, output: string, tolerance: number, toleranceType: ImageOptions) {
309+
public compareImages(options: IImageCompareOptions, actual: string, expected: string, output: string) {
318310
const clipRect = {
319-
x: this.imageCropRect.x,
320-
y: this.imageCropRect.y,
321-
width: this.imageCropRect.width,
322-
height: this.imageCropRect.height
311+
x: this.options.cropRectangle.x,
312+
y: this.options.cropRectangle.y,
313+
width: this.options.cropRectangle.width,
314+
height: this.options.cropRectangle.height
323315
}
324316

325317
if (!this.options.keepOriginalImageSize) {
@@ -334,22 +326,22 @@ export class ImageHelper {
334326
imageBPath: expected,
335327
imageOutputPath: output,
336328
imageOutputLimit: this.imageOutputLimit,
337-
thresholdType: toleranceType,
338-
threshold: tolerance,
329+
thresholdType: options.toleranceType,
330+
threshold: options.tolerance,
339331
delta: this.delta,
340332
cropImageA: clipRect,
341333
cropImageB: clipRect,
342334
blockOut: this._blockOutAreas,
343335
verbose: this._args.verbose,
344336
});
345337

346-
if (toleranceType == ImageOptions.percent) {
347-
if (tolerance >= 1) {
338+
if (options.toleranceType == ImageOptions.percent) {
339+
if (options.tolerance >= 1) {
348340
logError("Tolerance range is from 0 to 1 -> percentage thresholds: 1 = 100%, 0.2 = 20%");
349341
}
350-
console.log(`Using ${tolerance * 100}% tolerance`);
342+
console.log(`Using ${options.tolerance * 100}% tolerance`);
351343
} else {
352-
console.log(`Using ${tolerance}px tolerance`);
344+
console.log(`Using ${options.tolerance}px tolerance`);
353345
}
354346

355347
const result = this.runDiff(diff, output);
@@ -361,26 +353,34 @@ export class ImageHelper {
361353
let imageToClip: PngJsImage;
362354
imageToClip = await this.readImage(path);
363355
let shouldExit = false;
364-
Object.getOwnPropertyNames(rect).forEach(prop => {
365-
if (rect[prop] === undefined || rect[prop] === null) {
366-
shouldExit = true;
367-
return;
368-
}
369-
});
356+
if (!isNumber(rect["x"])
357+
|| !isNumber(rect["y"])
358+
|| !isNumber(rect["width"])
359+
|| !isNumber(rect["height"])) {
360+
shouldExit = true;
361+
}
370362
if (shouldExit) {
371-
logError(`Could not crop the image. Not enough data`, rect);
372-
return
363+
logError(`Could not crop the image. Not enough data {x: ${rect["x"]}, y: ${rect["y"]}, width: ${rect["width"]}, height: ${rect["height"]}}`);
373364
}
374-
imageToClip.clip(rect.x, rect.y, rect.width, rect.height);
375-
return new Promise((resolve, reject) => {
376-
imageToClip.writeImage(path, (err) => {
377-
if (err) {
378-
return reject(err);
379-
}
380-
return resolve();
381-
});
382365

383-
})
366+
if (!shouldExit) {
367+
imageToClip.clip(rect.x, rect.y, rect.width, rect.height);
368+
} else {
369+
logWarn("Image will not be cropped!")
370+
return true;
371+
}
372+
return new Promise((resolve, reject) => {
373+
try {
374+
imageToClip.writeImage(path, (err) => {
375+
if (err) {
376+
return reject(err);
377+
}
378+
return resolve();
379+
});
380+
} catch (error) {
381+
logError(error);
382+
}
383+
});
384384
}
385385

386386
public readImage(path: string): Promise<any> {
@@ -471,10 +471,6 @@ export class ImageHelper {
471471
}
472472
});
473473

474-
if (!options.cropRectangle) {
475-
ImageHelper.fullClone(this.imageCropRect, options.cropRectangle);
476-
}
477-
478474
return options;
479475
}
480476

lib/ns-capabilities.d.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,9 @@ export declare class NsCapabilities implements INsCapabilities {
7474
extend(args: INsCapabilities): this;
7575
validateArgs(): Promise<void>;
7676
private isAndroidPlatform;
77-
shouldSetFullResetOption(): void;
77+
setResetOption(): void;
78+
tryGetApiLevel(): number;
7879
private setAutomationName;
79-
tryGetAndroidApiLevel(): number;
80-
tryGetIOSApiLevel(): number;
8180
private resolveApplication;
8281
private checkMandatoryCapabilities;
8382
private throwExceptions;

lib/ns-capabilities.ts

+15-15
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ export class NsCapabilities implements INsCapabilities {
263263
this.resolveApplication();
264264
this.checkMandatoryCapabilities();
265265
this.throwExceptions();
266-
this.shouldSetFullResetOption();
266+
this.setResetOption();
267267

268268
this.isValidated = true;
269269
} else {
@@ -275,7 +275,7 @@ export class NsCapabilities implements INsCapabilities {
275275
return this.appiumCaps && this.appiumCaps ? this.appiumCaps.platformName.toLowerCase().includes("android") : undefined;
276276
}
277277

278-
public shouldSetFullResetOption() {
278+
public setResetOption() {
279279
if (this.attachToDebug || this.devMode) {
280280
this.appiumCaps["fullReset"] = false;
281281
this.appiumCaps["noReset"] = true;
@@ -300,6 +300,18 @@ export class NsCapabilities implements INsCapabilities {
300300
}
301301
}
302302

303+
public tryGetApiLevel() {
304+
try {
305+
const apiLevel = this.appiumCaps["platformVersion"] || this.appiumCaps["apiLevel"];
306+
if (this.isAndroid && apiLevel) {
307+
return +apiLevel.split(".").splice(0, 2).join('.');
308+
}
309+
return +apiLevel;
310+
} catch (error) { }
311+
312+
return undefined;
313+
}
314+
303315
private setAutomationName() {
304316
if (this.appiumCaps["automationName"]) {
305317
switch (this.appiumCaps["automationName"].toLowerCase()) {
@@ -313,7 +325,7 @@ export class NsCapabilities implements INsCapabilities {
313325
this.automationName = AutomationName.UiAutomator1; break;
314326
}
315327
} else {
316-
const apiLevel = this.tryGetApiLevel();
328+
const apiLevel = +this.tryGetApiLevel();
317329
if (this.isAndroid) {
318330
if ((apiLevel >= 6 && apiLevel <= 17)
319331
|| apiLevel >= 23) {
@@ -341,18 +353,6 @@ export class NsCapabilities implements INsCapabilities {
341353
}
342354
}
343355

344-
tryGetApiLevel() {
345-
try {
346-
const apiLevel = this.appiumCaps["platformVersion"] || this.appiumCaps["apiLevel"];
347-
if (this.isAndroid && apiLevel) {
348-
return apiLevel.split(".").splice(0, 2).join('.');
349-
}
350-
return apiLevel;
351-
} catch (error) { }
352-
353-
return undefined;
354-
}
355-
356356
private resolveApplication() {
357357
if (this.isSauceLab) {
358358
if (this.appPath) {

test/device-manager.spec.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ describe("ios-devices", () => {
8383
deviceManager = new DeviceManager();
8484
appiumArgs = new NsCapabilities(<any>{});
8585
appiumArgs.extend(<any>{ appiumCaps: { platformName: Platform.IOS, fullReset: false, deviceName: /iPhone X/ } })
86-
appiumArgs.shouldSetFullResetOption();
86+
appiumArgs.setResetOption();
8787
});
8888

8989
after("Kill all simulators", () => {
@@ -101,7 +101,7 @@ describe("ios-devices", () => {
101101

102102
it("Start simulator fullReset: true, should kill device", async () => {
103103
appiumArgs.extend(<any>{ appiumCaps: { platformName: Platform.IOS, fullReset: true, deviceName: /iPhone X/ } });
104-
appiumArgs.shouldSetFullResetOption();
104+
appiumArgs.setResetOption();
105105
const device = await deviceManager.startDevice(appiumArgs);
106106
let foundBootedDevices = await DeviceController.getDevices({ platform: Platform.IOS, status: Status.BOOTED });
107107
assert.isTrue(foundBootedDevices.some(d => d.token === device.token));

0 commit comments

Comments
 (0)