Skip to content

Commit

Permalink
feat: add nativeElementsSize options
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrei Kapustin authored and DudaGod committed Apr 8, 2024
1 parent c02ff2c commit 56a7091
Show file tree
Hide file tree
Showing 13 changed files with 311 additions and 43 deletions.
27 changes: 26 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@ Plugin has following configuration:
* **enabled** (optional) `Boolean` – enable/disable the plugin, by default plugin is enabled;
* **browsers** (required) `Object` - the list of browsers to use for wrap commands;
* **commands** (required) `Array` - commands which will be wrapped.
* **nativeElementsSize** (optional) `Object` - the map of native elements sizes for the browser. Sizes in pixels without counting the pixel ratio. Can be used in order to speed up taking screenshots;
* **topToolbar** (required) `Object` - the size of the top toolbar;
* **width** (required) `Number` - the width of the top toolbar;
* **height** (required) `Number` - the height of the top toolbar;
* **bottomToolbar** (required) `Object` - the size of the bottom toolbar;
* **width** (required) `Number` - the width of the bottom toolbar;
* **height** (required) `Number` - the height of the bottom toolbar;
* **webview** (required) `Object` - the size of the webview;
* **width** (required) `Number` - the width of the webview;
* **height** (required) `Number` - the height of the webview;


Also there is ability to override plugin parameters by CLI options or environment variables
(see [configparser](https://github.com/gemini-testing/configparser)).
Expand All @@ -44,7 +55,21 @@ module.exports = {
'swipe',
'touch',
'dragAndDrop'
]
],
nativeElementsSize: {
topToolbar: {
height: 47,
width: 390
},
bottomToolbar: {
height: 113,
width: 390
},
webview: {
height: 654,
width: 390
}
}
}
}
}
Expand Down
34 changes: 32 additions & 2 deletions lib/command-helpers/element-utils/common/index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
'use strict';

const {runInNativeContext} = require('../../context-switcher');
const {withExisting, withNativeCtx, withTestCtxMemo} = require('../decorators');
const {WEB_VIEW_SIZE, BOTTOM_TOOLBAR_LOCATION, PIXEL_RATIO} = require('../../test-context');

module.exports = class CommonUtils {
constructor(nativeLocators) {
constructor(nativeLocators, nativeElementsSize) {
this._nativeLocators = nativeLocators;
this._nativeElementsSize = nativeElementsSize;
}

async getLocation(browser, selector) {
Expand Down Expand Up @@ -62,7 +64,7 @@ module.exports = class CommonUtils {
return withTestCtxMemo.call(browser, action, PIXEL_RATIO);
}

async calcWebViewCoords(browser, {bodyWidth, pixelRatio = 1} = {}) {
async calcWebViewCoordsNative(browser, {bodyWidth, pixelRatio = 1} = {}) {
const [topToolbarHeight, bottomToolbarY, webViewSize] = await Promise.all([
this.getTopToolbarHeight(browser),
this.getBottomToolbarY(browser),
Expand All @@ -79,6 +81,34 @@ module.exports = class CommonUtils {
};
}

async calcWebViewCoords(browser, {bodyWidth, pixelRatio = 1} = {}) {
if (!this._nativeElementsSize) {
return runInNativeContext(browser, {
fn: this.calcWebViewCoordsNative.bind(this),
args: [browser, {bodyWidth, pixelRatio}]
});
}

let {
topToolbar: {height: topToolbarHeight},
bottomToolbar: {height: bottomToolbarHeight},
webview: {width: webviewWidth, height: webviewHeight}
} = this._nativeElementsSize;

if (await browser.getOrientation() === 'LANDSCAPE') {
[webviewWidth, webviewHeight] = [webviewHeight, webviewWidth];
topToolbarHeight = 0;
bottomToolbarHeight = 0;
}

return {
width: Math.ceil(Math.min(webviewWidth, bodyWidth) * pixelRatio),
height: Math.ceil((webviewHeight - topToolbarHeight - bottomToolbarHeight) * pixelRatio),
left: Math.max(Math.floor((webviewWidth - bodyWidth) / 2 * pixelRatio), 0),
top: Math.max(Math.floor(topToolbarHeight * pixelRatio), 0)
};
}

getTopToolbarHeight() {
throw new Error('Not implemented');
}
Expand Down
6 changes: 3 additions & 3 deletions lib/command-helpers/element-utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ const {NEW_SAFARI_VERSION} = require('../../constants');
const Safari15Utils = require('./v15.0');
const SafariOldUtils = require('./<v15.0');

exports.getElementUtils = (broConfig, nativeLocators) => {
exports.getElementUtils = (broConfig, nativeLocators, nativeElementsSize) => {
const currentVersion = getSafariVersion(broConfig);

if (currentVersion < NEW_SAFARI_VERSION) {
return new SafariOldUtils(nativeLocators);
return new SafariOldUtils(nativeLocators, nativeElementsSize);
}

return new Safari15Utils(nativeLocators);
return new Safari15Utils(nativeLocators, nativeElementsSize);
};
3 changes: 1 addition & 2 deletions lib/commands/screenshot.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
'use strict';

const sharp = require('sharp');
const {runInNativeContext} = require('../command-helpers/context-switcher');

module.exports = (browser, {elementUtils}) => {
browser.overwriteCommand('takeScreenshot', async (baseScreenshotFn) => {
const {width: bodyWidth} = await elementUtils.getElementSize(browser, 'body');
const pixelRatio = await elementUtils.getPixelRatio(browser);
const cropCoords = await runInNativeContext(browser, {fn: elementUtils.calcWebViewCoords.bind(elementUtils), args: [browser, {bodyWidth, pixelRatio}]});
const cropCoords = await elementUtils.calcWebViewCoords(browser, {bodyWidth, pixelRatio});
const screenshotResult = await baseScreenshotFn();

try {
Expand Down
3 changes: 2 additions & 1 deletion lib/config/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@

module.exports = {
enabled: true,
commands: null
commands: null,
nativeElementsSize: null
};
47 changes: 47 additions & 0 deletions lib/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ const assertArrayOfStrings = (value, name) => {
throw new Error(`"${name}" must be an array of strings but got ${JSON.stringify(value)}`);
}
};
const assertNumberProperty = (value, prop, propPath) => {
if (!_.isNumber(value[prop])) {
throw new Error(`Property "${propPath}.${prop}" must be a number but got ${value[prop] === null ? 'null' : typeof value[prop]}`);
}
};

const getParser = () => {
return root(section({
Expand All @@ -42,6 +47,48 @@ const getParser = () => {
? thr('Each browser must have "commands" option')
: assertArrayOfStrings(value, 'commands');
}
}),
nativeElementsSize: option({
defaultValue: defaults.nativeElementsSize,
parseEnv: JSON.parse,
parseCli: JSON.parse,
validate: (value) => {
if (_.isNull(value)) {
return;
}

if (!_.isPlainObject(value)) {
throw new Error('"nativeElementsSize" must be an object');
}
const valueProps = _.keys(value);

const requiredProps = ['topToolbar', 'bottomToolbar', 'webview'];
const missingProps = requiredProps.filter(prop => !valueProps.includes(prop));

if (missingProps.length) {
throw new Error(
`"nativeElementsSize" missing properties: ${missingProps}.`
);
}

_.forOwn(value, (size, key) => {
if (!_.isPlainObject(size)) {
throw new Error(`Property "${key}" of "nativeElementsSize" must be an object`);
}

assertNumberProperty(size, 'width', `nativeElementsSize.${key}`);
assertNumberProperty(size, 'height', `nativeElementsSize.${key}`);
});

const allowedProps = [...requiredProps];
const unknownProps = valueProps.filter(prop => !allowedProps.includes(prop));

if (unknownProps.length) {
throw new Error(
`"nativeElementsSize" contains unknown properties: ${unknownProps}. Allowed: ${allowedProps}.`
);
}
}
})
}))
}), {envPrefix: ENV_PREFIX, cliPrefix: CLI_PREFIX});
Expand Down
4 changes: 2 additions & 2 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ module.exports = (hermione, opts) => {
}

hermione.on(hermione.events.NEW_BROWSER, (browser, {browserId}) => {
const {commands = []} = getBrowserPluginCfg(pluginConfig, browserId);
const {commands = [], nativeElementsSize} = getBrowserPluginCfg(pluginConfig, browserId);

if (_.isEmpty(commands)) {
return;
Expand All @@ -51,7 +51,7 @@ module.exports = (hermione, opts) => {
}

const nativeLocators = getNativeLocators(broConfig);
const elementUtils = getElementUtils(broConfig, nativeLocators);
const elementUtils = getElementUtils(broConfig, nativeLocators, nativeElementsSize);
commands.forEach((commandName) => {
if (!browserCommands[commandName]) {
throw new TypeError(`Can not find "${commandName}" command`);
Expand Down
16 changes: 8 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
},
"homepage": "https://github.com/gemini-testing/hermione-safari-commands#readme",
"dependencies": {
"gemini-configparser": "^1.0.0",
"gemini-configparser": "^1.3.0",
"lodash": "^4.17.15",
"sharp": "~0.31.3"
},
Expand Down
Loading

0 comments on commit 56a7091

Please sign in to comment.