Skip to content

Commit

Permalink
Merge branch 'master' into fix-poa-fetch-capability
Browse files Browse the repository at this point in the history
  • Loading branch information
nilshah98 authored Aug 21, 2023
2 parents 6f109a1 + 61aa75b commit 6bcdd73
Show file tree
Hide file tree
Showing 10 changed files with 239 additions and 112 deletions.
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,44 @@ await percyScreenshotFlutter(driver, name[, {
>
> For other hybrid apps the `await driver.switchContext('FLUTTER');` would change to context that it uses like say WEBVIEW etc.
>
## Running Percy on Automate
`percyScreenshot(driver, name, options)` [ needs @percy/cli 1.27.0-beta.0+ ];
- `driver` (**required**) - A appium driver instance
- `name` (**required**) - The screenshot name; must be unique to each screenshot
- `options` (**optional**) - There are various options supported by percy_screenshot to server further functionality.
- `freezeAnimation` - Boolean value by default it falls back to `false`, you can pass `true` and percy will freeze image based animations.
- `percyCSS` - Custom CSS to be added to DOM before the screenshot being taken. Note: This gets removed once the screenshot is taken.
- `ignoreRegionXpaths` - elements in the DOM can be ignored using xpath
- `ignoreRegionSelectors` - elements in the DOM can be ignored using selectors.
- `ignoreRegionAppiumElements` - elements can be ignored using appium_elements.
- `customIgnoreRegions` - elements can be ignored using custom boundaries
- IgnoreRegion:-
- Description: This class represents a rectangular area on a screen that needs to be ignored for visual diff.

- Constructor:
```
init(self, top, bottom, left, right)
```
- Parameters:
`top` (int): Top coordinate of the ignore region.
`bottom` (int): Bottom coordinate of the ignore region.
`left` (int): Left coordinate of the ignore region.
`right` (int): Right coordinate of the ignore region.
- Raises:ValueError: If top, bottom, left, or right is less than 0 or top is greater than or equal to bottom or left is greater than or equal to right.
- valid: Ignore region should be within the boundaries of the screen.
### Creating Percy on automate build
Note: Automate Percy Token starts with `auto` keyword. The command can be triggered using `exec` keyword.
```sh-session
$ export PERCY_TOKEN=[your-project-token]
$ percy exec -- [python test command]
[percy] Percy has started!
[percy] [Python example] : Starting automate screenshot ...
[percy] Screenshot taken "Python example"
[percy] Stopping percy...
[percy] Finalized build #1: https://percy.io/[your-project]
[percy] Done!
```

Refer to docs here: [Percy on Automate](https://docs.percy.io/docs/integrate-functional-testing-with-visual-testing)
12 changes: 12 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ module.exports = async function percyScreenshot(driver, name, options = {}) {
ignoreRegionAccessibilityIds,
ignoreRegionAppiumElements,
customIgnoreRegions,
considerRegionXpaths,
considerRegionAccessibilityIds,
considerRegionAppiumElements,
customConsiderRegions,
scrollableXpath,
scrollableId
} = options;
Expand All @@ -39,6 +43,10 @@ module.exports = async function percyScreenshot(driver, name, options = {}) {
ignoreRegionAccessibilityIds = name.ignoreRegionAccessibilityIds;
ignoreRegionAppiumElements = name.ignoreRegionAppiumElements;
customIgnoreRegions = name.customIgnoreRegions;
considerRegionXpaths = name.considerRegionXpaths;
considerRegionAccessibilityIds = name.considerRegionAccessibilityIds;
considerRegionAppiumElements = name.considerRegionAppiumElements;
customConsiderRegions = name.customConsiderRegions;
scrollableXpath = name.scrollableXpath;
scrollableId = name.scrollableId;
options = name;
Expand Down Expand Up @@ -79,6 +87,10 @@ module.exports = async function percyScreenshot(driver, name, options = {}) {
ignoreRegionAccessibilityIds,
ignoreRegionAppiumElements,
customIgnoreRegions,
considerRegionXpaths,
considerRegionAccessibilityIds,
considerRegionAppiumElements,
customConsiderRegions,
scrollableXpath,
scrollableId
});
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@percy/appium-app",
"description": "Appium client library for visual testing with Percy",
"version": "2.0.0-beta.1",
"version": "2.0.0-beta.2",
"license": "MIT",
"author": "Perceptual Inc.",
"repository": {
Expand Down
21 changes: 18 additions & 3 deletions percy/percyOnAutomate.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,24 @@ module.exports = async function percyOnAutomate(driver, name, options) {
const capabilities = driver.type === 'wd' ? await driver.getCapabilities() : driver.driver.capabilities;
const commandExecutorUrl = driver.commandExecutorUrl;

if (options && 'ignore_region_appium_elements' in options) {
options.ignore_region_elements = await getElementIdFromElements(driver.type, options.ignore_region_appium_elements);
delete options.ignore_region_appium_elements;
/* istanbul ignore next */
if (options) {
if ('ignoreRegionAppiumElements' in options) {
options.ignore_region_appium_elements = options.ignoreRegionAppiumElements;
delete options.ignoreRegionAppiumElements;
}
if ('considerRegionAppiumElements' in options) {
options.consider_region_appium_elements = options.considerRegionAppiumElements;
delete options.considerRegionAppiumElements;
}
if ('ignore_region_appium_elements' in options) {
options.ignore_region_elements = await getElementIdFromElements(driver.type, options.ignore_region_appium_elements);
delete options.ignore_region_appium_elements;
}
if ('consider_region_appium_elements' in options) {
options.consider_region_elements = await getElementIdFromElements(driver.type, options.consider_region_appium_elements);
delete options.consider_region_appium_elements;
}
}

// Post the driver details to the automate screenshot endpoint with snapshot options and other info
Expand Down
8 changes: 8 additions & 0 deletions percy/providers/appAutomateProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ class AppAutomateProvider extends GenericProvider {
ignoreRegionAccessibilityIds,
ignoreRegionAppiumElements,
customIgnoreRegions,
considerRegionXpaths,
considerRegionAccessibilityIds,
considerRegionAppiumElements,
customConsiderRegions,
scrollableXpath,
scrollableId
} = {}) {
Expand All @@ -47,6 +51,10 @@ class AppAutomateProvider extends GenericProvider {
ignoreRegionAccessibilityIds,
ignoreRegionAppiumElements,
customIgnoreRegions,
considerRegionXpaths,
considerRegionAccessibilityIds,
considerRegionAppiumElements,
customConsiderRegions,
scrollableXpath,
scrollableId
});
Expand Down
58 changes: 33 additions & 25 deletions percy/providers/genericProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ class GenericProvider {
ignoreRegionAccessibilityIds,
ignoreRegionAppiumElements,
customIgnoreRegions,
considerRegionXpaths,
considerRegionAccessibilityIds,
considerRegionAppiumElements,
customConsiderRegions,
scrollableXpath,
scrollableId
}) {
Expand All @@ -61,9 +65,12 @@ class GenericProvider {

const tag = await this.getTag();
const tiles = await this.getTiles(fullscreen, fullPage, screenLengths, scrollableXpath, scrollableId);
const ignoreRegions = await this.findIgnoredRegions(
const ignoreRegions = await this.findRegions(
ignoreRegionXpaths, ignoreRegionAccessibilityIds, ignoreRegionAppiumElements, customIgnoreRegions
);
const considerRegions = await this.findRegions(
considerRegionXpaths, considerRegionAccessibilityIds, considerRegionAppiumElements, customConsiderRegions
);

log.debug(`${name} : Tag ${JSON.stringify(ignoreRegions)}`);
log.debug(`${name} : Tag ${JSON.stringify(tag)}`);
Expand All @@ -74,7 +81,12 @@ class GenericProvider {
tag,
tiles,
externalDebugUrl: await this.getDebugUrl(),
ignoredElementsData: ignoreRegions,
ignoredElementsData: {
ignoreElementsData: ignoreRegions
},
consideredElementsData: {
considerElementsData: considerRegions
},
environmentInfo: ENV_INFO,
clientInfo: CLIENT_INFO
});
Expand Down Expand Up @@ -149,21 +161,17 @@ class GenericProvider {
return this.debugUrl;
}

async findIgnoredRegions(ignoreRegionXpaths, ignoreRegionAccessibilityIds, ignoreRegionAppiumElements, customIgnoreRegions) {
const ignoredElementsArray = [];
await this.ignoreRegionsByXpaths(ignoredElementsArray, ignoreRegionXpaths || []);
await this.ignoreRegionsByIds(ignoredElementsArray, ignoreRegionAccessibilityIds || []);
await this.ignoreRegionsByElement(ignoredElementsArray, ignoreRegionAppiumElements || []);
await this.addCustomIgnoreRegions(ignoredElementsArray, customIgnoreRegions || []);

const ignoredElementsLocations = {
ignoreElementsData: ignoredElementsArray
};
async findRegions(xpaths, accessibilityIds, appiumElements, customLocations) {
const regionsArray = [];
await this.getRegionsByXpath(regionsArray, xpaths || []);
await this.getRegionsByIds(regionsArray, accessibilityIds || []);
await this.getRegionsByElements(regionsArray, appiumElements || []);
await this.getRegionsByLocation(regionsArray, customLocations || []);

return ignoredElementsLocations;
return regionsArray;
}

async ignoreElementObject(selector, element) {
async getRegionObject(selector, element) {
const scaleFactor = await this.metadata.scaleFactor();
const location = await element.getLocation();
const size = await element.getSize();
Expand All @@ -182,50 +190,50 @@ class GenericProvider {
return jsonObject;
}

async ignoreRegionsByXpaths(ignoredElementsArray, xpaths) {
async getRegionsByXpath(elementsArray, xpaths) {
for (const xpath of xpaths) {
try {
const element = await this.driver.elementByXPath(xpath);
const selector = `xpath: ${xpath}`;
const ignoredRegion = await this.ignoreElementObject(selector, element);
ignoredElementsArray.push(ignoredRegion);
const ignoredRegion = await this.getRegionObject(selector, element);
elementsArray.push(ignoredRegion);
} catch (e) {
log.info(`Appium Element with xpath: ${xpath} not found. Ignoring this xpath.`);
log.debug(e.toString());
}
}
}

async ignoreRegionsByIds(ignoredElementsArray, ids) {
async getRegionsByIds(elementsArray, ids) {
for (const id of ids) {
try {
const element = await this.driver.elementByAccessibilityId(id);
const selector = `id: ${id}`;
const ignoredRegion = await this.ignoreElementObject(selector, element);
ignoredElementsArray.push(ignoredRegion);
const ignoredRegion = await this.getRegionObject(selector, element);
elementsArray.push(ignoredRegion);
} catch (e) {
log.info(`Appium Element with id: ${id} not found. Ignoring this id.`);
log.debug(e.toString());
}
}
}

async ignoreRegionsByElement(ignoredElementsArray, elements) {
async getRegionsByElements(elementsArray, elements) {
for (let index = 0; index < elements.length; index++) {
try {
const type = await elements[index].getAttribute('class');
const selector = `element: ${index} ${type}`;

const ignoredRegion = await this.ignoreElementObject(selector, elements[index]);
ignoredElementsArray.push(ignoredRegion);
const ignoredRegion = await this.getRegionObject(selector, elements[index]);
elementsArray.push(ignoredRegion);
} catch (e) {
log.info(`Correct Mobile Element not passed at index ${index}.`);
log.debug(e.toString());
}
}
}

async addCustomIgnoreRegions(ignoredElementsArray, customLocations) {
async getRegionsByLocation(elementsArray, customLocations) {
const { width, height } = await this.metadata.screenSize();
for (let index = 0; index < customLocations.length; index++) {
const customLocation = customLocations[index];
Expand All @@ -240,7 +248,7 @@ class GenericProvider {
right: customLocation.right
}
};
ignoredElementsArray.push(ignoredRegion);
elementsArray.push(ignoredRegion);
} else {
log.info(`Values passed in custom ignored region at index: ${index} is not valid`);
}
Expand Down
29 changes: 2 additions & 27 deletions percy/util/ignoreRegion.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,6 @@
class IgnoreRegion {
constructor(top, bottom, left, right) {
if (top < 0 || bottom < 0 || left < 0 || right < 0) {
throw new Error('Only Positive integer is allowed!');
}
const { Region } = require('./region');

if (top >= bottom || left >= right) {
throw new Error('Invalid ignore region parameters!');
}

this.top = top;
this.bottom = bottom;
this.left = left;
this.right = right;
}

isValid(screenHeight, screenWidth) {
if (
this.top >= screenHeight ||
this.bottom > screenHeight ||
this.left >= screenWidth ||
this.right > screenWidth) {
return false;
}

return true;
}
}
class IgnoreRegion extends Region {}

module.exports = {
IgnoreRegion
Expand Down
32 changes: 32 additions & 0 deletions percy/util/region.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
class Region {
constructor(top, bottom, left, right) {
if (top < 0 || bottom < 0 || left < 0 || right < 0) {
throw new Error('Only Positive integer is allowed!');
}

if (top >= bottom || left >= right) {
throw new Error('Invalid ignore region parameters!');
}

this.top = top;
this.bottom = bottom;
this.left = left;
this.right = right;
}

isValid(screenHeight, screenWidth) {
if (
this.top >= screenHeight ||
this.bottom > screenHeight ||
this.left >= screenWidth ||
this.right > screenWidth) {
return false;
}

return true;
}
}

module.exports = {
Region
};
Loading

0 comments on commit 6bcdd73

Please sign in to comment.