From 8eb165fe2dad16d98bc2cc8854983c617945503f Mon Sep 17 00:00:00 2001 From: Benoit CIVEL Date: Wed, 23 Oct 2024 08:36:43 +0200 Subject: [PATCH] Add offset on all mouse action. Add number of element retreived for actions type and click (will be extended to all elements) --- .../core/engine/gwt/impl/ActionService.java | 121 +++++++++--------- .../cerberus/core/enums/MessageEventEnum.java | 6 +- .../core/service/appium/IAppiumService.java | 2 +- .../service/appium/impl/AppiumService.java | 40 ++++-- .../robotextension/impl/SikuliService.java | 2 + .../service/webdriver/IWebDriverService.java | 10 +- .../webdriver/impl/WebDriverService.java | 59 ++++----- .../main/webapp/js/testcase/testcaseStatic.js | 17 ++- 8 files changed, 135 insertions(+), 122 deletions(-) diff --git a/source/src/main/java/org/cerberus/core/engine/gwt/impl/ActionService.java b/source/src/main/java/org/cerberus/core/engine/gwt/impl/ActionService.java index 751480073..82cf8f83c 100644 --- a/source/src/main/java/org/cerberus/core/engine/gwt/impl/ActionService.java +++ b/source/src/main/java/org/cerberus/core/engine/gwt/impl/ActionService.java @@ -26,6 +26,9 @@ import java.util.Date; import java.util.HashMap; import java.util.Optional; + +import lombok.Getter; +import lombok.Setter; import org.apache.commons.codec.binary.Base64; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -570,11 +573,6 @@ private TestCaseStepActionExecution cleanValues(TestCaseStepActionExecution acti actionExecution.setValue3Init(""); break; // Only Value1 - case TestCaseStepAction.ACTION_CLICK: - case TestCaseStepAction.ACTION_MOUSELEFTBUTTONPRESS: - case TestCaseStepAction.ACTION_MOUSELEFTBUTTONRELEASE: - case TestCaseStepAction.ACTION_DOUBLECLICK: - case TestCaseStepAction.ACTION_RIGHTCLICK: case TestCaseStepAction.ACTION_MOUSEMOVE: case TestCaseStepAction.ACTION_OPENURLWITHBASE: case TestCaseStepAction.ACTION_FOCUSTOIFRAME: @@ -600,6 +598,11 @@ private TestCaseStepActionExecution cleanValues(TestCaseStepActionExecution acti actionExecution.setValue3Init(""); break; // Only Value 1 and Value 2 + case TestCaseStepAction.ACTION_CLICK: + case TestCaseStepAction.ACTION_MOUSELEFTBUTTONPRESS: + case TestCaseStepAction.ACTION_MOUSELEFTBUTTONRELEASE: + case TestCaseStepAction.ACTION_DOUBLECLICK: + case TestCaseStepAction.ACTION_RIGHTCLICK: case TestCaseStepAction.ACTION_LONGPRESS: case TestCaseStepAction.ACTION_EXECUTECOMMAND: case TestCaseStepAction.ACTION_OPENAPP: @@ -929,9 +932,10 @@ private MessageEvent doActionExecuteCerberusCommand(TestCaseExecution tCExecutio } } - private MessageEvent doActionClick(TestCaseExecution tCExecution, String value1, String value2) { + private MessageEvent doActionClick(TestCaseExecution tCExecution, String value1, String offsetString) { String element; try { + Offset offset = new Offset(offsetString); /** * Get element to use String object if not empty, String property if * object empty, throws Exception if both empty) @@ -946,7 +950,7 @@ private MessageEvent doActionClick(TestCaseExecution tCExecution, String value1, if (tCExecution.getApplicationObj().getType().equalsIgnoreCase(Application.TYPE_GUI)) { if (tCExecution.getRobotObj().getPlatform().equalsIgnoreCase(Platform.ANDROID.toString())) { identifierService.checkWebElementIdentifier(identifier.getIdentifier()); - return webdriverService.doSeleniumActionClick(tCExecution.getSession(), identifier, false, false); + return webdriverService.doSeleniumActionClick(tCExecution.getSession(), identifier, offset.getHOffset(), offset.getVOffset(), false, false); } else { if (identifier.getIdentifier().equals(SikuliService.SIKULI_IDENTIFIER_PICTURE)) { return sikuliService.doSikuliActionClick(tCExecution.getSession(), identifier.getLocator(), ""); @@ -954,17 +958,17 @@ private MessageEvent doActionClick(TestCaseExecution tCExecution, String value1, return sikuliService.doSikuliActionClick(tCExecution.getSession(), "", identifier.getLocator()); } else { identifierService.checkWebElementIdentifier(identifier.getIdentifier()); - return webdriverService.doSeleniumActionClick(tCExecution.getSession(), identifier, true, true); + return webdriverService.doSeleniumActionClick(tCExecution.getSession(), identifier, offset.getHOffset(), offset.getVOffset(), true, true); } } } else if (tCExecution.getApplicationObj().getType().equalsIgnoreCase(Application.TYPE_APK)) { identifierService.checkWebElementIdentifier(identifier.getIdentifier()); - return androidAppiumService.click(tCExecution.getSession(), identifier); + return androidAppiumService.click(tCExecution.getSession(), identifier, offset.getHOffset(), offset.getVOffset()); } else if (tCExecution.getApplicationObj().getType().equalsIgnoreCase(Application.TYPE_IPA)) { identifierService.checkWebElementIdentifier(identifier.getIdentifier()); - return iosAppiumService.click(tCExecution.getSession(), identifier); + return iosAppiumService.click(tCExecution.getSession(), identifier, offset.getHOffset(), offset.getVOffset()); } else if (tCExecution.getApplicationObj().getType().equalsIgnoreCase(Application.TYPE_FAT)) { if (StringUtil.isEmptyOrNull(identifier.getLocator())) { @@ -1017,27 +1021,23 @@ private MessageEvent doActionExecuteJS(TestCaseExecution tCExecution, String val } } - private MessageEvent doActionMouseLeftButtonPress(TestCaseExecution tCExecution, String value1, String value2) { + private MessageEvent doActionMouseLeftButtonPress(TestCaseExecution tCExecution, String value1, String offsetString) { MessageEvent message; - String element; + try { if (tCExecution.getApplicationObj().getType().equalsIgnoreCase(Application.TYPE_FAT) || StringUtil.isEmptyOrNull(value1)) { // If value1 is empty, the Sikuli engine must be used in order to click without element to click. return sikuliService.doSikuliActionLeftButtonPress(tCExecution.getSession()); } else if (tCExecution.getApplicationObj().getType().equalsIgnoreCase(Application.TYPE_GUI)) { - /** - * Get element to use String object if not empty, String - * property if object empty, throws Exception if both empty) - */ - element = getElementToUse(value1, value2, "mouseLeftButtonPress", tCExecution); + Offset offset = new Offset(offsetString); /** * Get Identifier (identifier, locator) */ Identifier identifier = identifierService.convertStringToIdentifier(value1); identifierService.checkWebElementIdentifier(identifier.getIdentifier()); - return webdriverService.doSeleniumActionMouseDown(tCExecution.getSession(), identifier, true, true); + return webdriverService.doSeleniumActionMouseDown(tCExecution.getSession(), identifier, offset.getHOffset(), offset.getVOffset(), true, true); } message = new MessageEvent(MessageEventEnum.ACTION_NOTEXECUTED_NOTSUPPORTED_FOR_APPLICATION); message.setDescription(message.getDescription().replace("%ACTION%", TestCaseStepAction.ACTION_MOUSELEFTBUTTONPRESS)); @@ -1049,19 +1049,15 @@ private MessageEvent doActionMouseLeftButtonPress(TestCaseExecution tCExecution, } } - private MessageEvent doActionRightClick(TestCaseExecution tCExecution, String value1, String value2) { + private MessageEvent doActionRightClick(TestCaseExecution tCExecution, String value1, String offsetString) { MessageEvent message; String element; try { - /** - * Get element to use String object if not empty, String property if - * object empty, throws Exception if both empty) - */ - element = value1; + Offset offset = new Offset(offsetString); /** * Get Identifier (identifier, locator) */ - Identifier identifier = identifierService.convertStringToIdentifier(element); + Identifier identifier = identifierService.convertStringToIdentifier(value1); if (tCExecution.getApplicationObj().getType().equalsIgnoreCase(Application.TYPE_GUI)) { if (identifier.getIdentifier().equals(SikuliService.SIKULI_IDENTIFIER_PICTURE)) { @@ -1070,7 +1066,7 @@ private MessageEvent doActionRightClick(TestCaseExecution tCExecution, String va return sikuliService.doSikuliActionRightClick(tCExecution.getSession(), "", identifier.getLocator()); } else { identifierService.checkWebElementIdentifier(identifier.getIdentifier()); - return webdriverService.doSeleniumActionRightClick(tCExecution.getSession(), identifier); + return webdriverService.doSeleniumActionRightClick(tCExecution.getSession(), identifier, offset.getHOffset(), offset.getVOffset()); } } else if (tCExecution.getApplicationObj().getType().equalsIgnoreCase(Application.TYPE_FAT)) { if (StringUtil.isEmptyOrNull(identifier.getLocator())) { @@ -1093,26 +1089,21 @@ private MessageEvent doActionRightClick(TestCaseExecution tCExecution, String va } } - private MessageEvent doActionMouseLeftButtonRelease(TestCaseExecution tCExecution, String value1, String value2) { + private MessageEvent doActionMouseLeftButtonRelease(TestCaseExecution tCExecution, String value1, String offsetString) { MessageEvent message; - String element; try { if (tCExecution.getApplicationObj().getType().equalsIgnoreCase(Application.TYPE_FAT) || StringUtil.isEmptyOrNull(value1)) { // If value1 is empty, the Sikuli engine must be used in order to click without element to click. return sikuliService.doSikuliActionLeftButtonRelease(tCExecution.getSession()); } else if (tCExecution.getApplicationObj().getType().equalsIgnoreCase(Application.TYPE_GUI)) { - /** - * Get element to use String object if not empty, String - * property if object empty, throws Exception if both empty) - */ - element = getElementToUse(value1, value2, "mouseLeftButtonRelease", tCExecution); + Offset offset = new Offset(offsetString); /** * Get Identifier (identifier, locator) */ - Identifier identifier = identifierService.convertStringToIdentifier(element); + Identifier identifier = identifierService.convertStringToIdentifier(value1); identifierService.checkWebElementIdentifier(identifier.getIdentifier()); - return webdriverService.doSeleniumActionMouseUp(tCExecution.getSession(), identifier, true, true); + return webdriverService.doSeleniumActionMouseUp(tCExecution.getSession(), identifier, offset.getHOffset(), offset.getVOffset(), true, true); } message = new MessageEvent(MessageEventEnum.ACTION_NOTEXECUTED_NOTSUPPORTED_FOR_APPLICATION); message.setDescription(message.getDescription().replace("%ACTION%", TestCaseStepAction.ACTION_MOUSELEFTBUTTONRELEASE)); @@ -1242,10 +1233,11 @@ private MessageEvent doActionManageDialogKeyPress(TestCaseExecution tCExecution, } } - private MessageEvent doActionDoubleClick(TestCaseExecution tCExecution, String value1, String value2) { + private MessageEvent doActionDoubleClick(TestCaseExecution tCExecution, String value1, String offsetString) { MessageEvent message; String element; try { + Offset offset = new Offset(offsetString); /** * Get element to use String object if not empty, String property if * object empty, throws Exception if both empty) @@ -1259,7 +1251,7 @@ private MessageEvent doActionDoubleClick(TestCaseExecution tCExecution, String v if (tCExecution.getApplicationObj().getType().equalsIgnoreCase(Application.TYPE_GUI)) { if (tCExecution.getRobotObj().getPlatform().equalsIgnoreCase(Platform.ANDROID.toString())) { identifierService.checkWebElementIdentifier(identifier.getIdentifier()); - return webdriverService.doSeleniumActionDoubleClick(tCExecution.getSession(), identifier, false, false); + return webdriverService.doSeleniumActionDoubleClick(tCExecution.getSession(), identifier, offset.getHOffset(), offset.getVOffset(), false, false); } else { if (identifier.getIdentifier().equals(SikuliService.SIKULI_IDENTIFIER_PICTURE)) { return sikuliService.doSikuliActionDoubleClick(tCExecution.getSession(), identifier.getLocator(), ""); @@ -1267,13 +1259,13 @@ private MessageEvent doActionDoubleClick(TestCaseExecution tCExecution, String v return sikuliService.doSikuliActionDoubleClick(tCExecution.getSession(), "", identifier.getLocator()); } else { identifierService.checkWebElementIdentifier(identifier.getIdentifier()); - return webdriverService.doSeleniumActionDoubleClick(tCExecution.getSession(), identifier, true, true); + return webdriverService.doSeleniumActionDoubleClick(tCExecution.getSession(), identifier, offset.getHOffset(), offset.getVOffset(), true, true); } } } else if (tCExecution.getApplicationObj().getType().equalsIgnoreCase(Application.TYPE_APK) || tCExecution.getApplicationObj().getType().equalsIgnoreCase(Application.TYPE_IPA)) { identifierService.checkWebElementIdentifier(identifier.getIdentifier()); - return webdriverService.doSeleniumActionDoubleClick(tCExecution.getSession(), identifier, true, false); + return webdriverService.doSeleniumActionDoubleClick(tCExecution.getSession(), identifier, offset.getHOffset(), offset.getVOffset(), true, false); } else if (tCExecution.getApplicationObj().getType().equalsIgnoreCase(Application.TYPE_FAT)) { if (StringUtil.isEmptyOrNull(identifier.getLocator())) { return sikuliService.doSikuliActionDoubleClick(tCExecution.getSession(), "", ""); @@ -1355,25 +1347,11 @@ private MessageEvent doActionType(TestCaseExecution tCExecution, String value1, } } - private MessageEvent doActionMouseOver(TestCaseExecution tCExecution, String element, String offset) { + private MessageEvent doActionMouseOver(TestCaseExecution tCExecution, String element, String offsetString) { MessageEvent message; try { - /** - * Check offset format - */ - Integer hOffset = 0; - Integer vOffset = 0; - - try { - if (!StringUtil.isEmptyOrNull(offset)) { - String[] soffsets = offset.split(","); - hOffset = Integer.valueOf(soffsets[0]); - vOffset = Integer.valueOf(soffsets[1]); - } - } catch (Exception ex){ - LOG.warn("Error decoding offset. It must be in two integers splited by comma. Continue with 0,0. Details :" +ex); - } + Offset offset = new Offset(offsetString); /** * Get Identifier (identifier, locator) */ @@ -1382,23 +1360,23 @@ private MessageEvent doActionMouseOver(TestCaseExecution tCExecution, String ele if (tCExecution.getApplicationObj().getType().equalsIgnoreCase(Application.TYPE_GUI)) { if (tCExecution.getRobotObj().getPlatform().equalsIgnoreCase(Platform.ANDROID.toString())) { identifierService.checkWebElementIdentifier(identifier.getIdentifier()); - return webdriverService.doSeleniumActionMouseOver(tCExecution.getSession(), identifier, hOffset, vOffset, false, false); + return webdriverService.doSeleniumActionMouseOver(tCExecution.getSession(), identifier, offset.getHOffset(), offset.getVOffset(), false, false); } else { if (identifier.getIdentifier().equals(SikuliService.SIKULI_IDENTIFIER_PICTURE)) { - return sikuliService.doSikuliActionMouseOver(tCExecution.getSession(), identifier.getLocator(), "", offset); + return sikuliService.doSikuliActionMouseOver(tCExecution.getSession(), identifier.getLocator(), "", offsetString); } else if (identifier.getIdentifier().equals(SikuliService.SIKULI_IDENTIFIER_TEXT)) { - return sikuliService.doSikuliActionMouseOver(tCExecution.getSession(), "", identifier.getLocator(), offset); + return sikuliService.doSikuliActionMouseOver(tCExecution.getSession(), "", identifier.getLocator(), offsetString); } else { identifierService.checkWebElementIdentifier(identifier.getIdentifier()); - return webdriverService.doSeleniumActionMouseOver(tCExecution.getSession(), identifier, hOffset, vOffset, true, true); + return webdriverService.doSeleniumActionMouseOver(tCExecution.getSession(), identifier, offset.getHOffset(), offset.getVOffset(), true, true); } } } else if (tCExecution.getApplicationObj().getType().equalsIgnoreCase(Application.TYPE_FAT)) { identifierService.checkSikuliIdentifier(identifier.getIdentifier()); if (identifier.getIdentifier().equals(SikuliService.SIKULI_IDENTIFIER_PICTURE)) { - return sikuliService.doSikuliActionMouseOver(tCExecution.getSession(), identifier.getLocator(), "", offset); + return sikuliService.doSikuliActionMouseOver(tCExecution.getSession(), identifier.getLocator(), "", offsetString); } else { - return sikuliService.doSikuliActionMouseOver(tCExecution.getSession(), "", identifier.getLocator(), offset); + return sikuliService.doSikuliActionMouseOver(tCExecution.getSession(), "", identifier.getLocator(), offsetString); } } @@ -2467,4 +2445,25 @@ private MessageEvent doActionForwardNextPage(TestCaseExecution tCExecution) { } } + + @Getter + @Setter + private class Offset{ + Integer hOffset = 0; + Integer vOffset = 0; + + public Offset(String offsetString){ + try { + if (!StringUtil.isEmptyOrNull(offsetString)) { + String[] soffsets = offsetString.split(","); + hOffset = Integer.valueOf(soffsets[0]); + vOffset = Integer.valueOf(soffsets[1]); + } + } catch (Exception ex){ + LOG.warn("Error decoding offset. It must be in two integers splited by comma. Continue with 0,0. Details :" +ex); + } + } + } + + } diff --git a/source/src/main/java/org/cerberus/core/enums/MessageEventEnum.java b/source/src/main/java/org/cerberus/core/enums/MessageEventEnum.java index 6f86cf493..b0771defb 100644 --- a/source/src/main/java/org/cerberus/core/enums/MessageEventEnum.java +++ b/source/src/main/java/org/cerberus/core/enums/MessageEventEnum.java @@ -182,18 +182,18 @@ public enum MessageEventEnum { ACTION_SUCCESS_UNLOCKDEVICE_GENERIC(200, "OK", "Device unlocked.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), ACTION_SUCCESS_LOCKDEVICE_GENERIC(200, "OK", "Device locked.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), ACTION_SUCCESS_ROTATEDEVICE_GENERIC(200, "OK", "Device rotated.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), - ACTION_SUCCESS_CLICK(200, "OK", "Element '%ELEMENT%' clicked.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), + ACTION_SUCCESS_CLICK(200, "OK", "%ELEMENTFOUND%. Element '%ELEMENT%' clicked.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), ACTION_SUCCESS_CLICKANDWAIT(200, "OK", "Element '%ELEMENT%' clicked and waited %TIME% ms.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), ACTION_SUCCESS_CLICKANDNOWAIT(200, "OK", "Element '%ELEMENT%' clicked and waited for page to load", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), - ACTION_SUCCESS_TYPE(200, "OK", "Element '%ELEMENT%' feeded with '%DATA%'.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), + ACTION_SUCCESS_TYPE(200, "OK", "%ELEMENTFOUND%. Element '%ELEMENT%' feeded with '%DATA%'.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), ACTION_SUCCESS_DOUBLECLICK(200, "OK", "Element '%ELEMENT%' double clicked.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), ACTION_SUCCESS_RIGHTCLICK(200, "OK", "Right click has been done on Element '%ELEMENT%'.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), ACTION_SUCCESS_URLLOGIN(200, "OK", "Opened '%URL%'.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), ACTION_SUCCESS_MOUSEOVER(200, "OK", "Mouse moved over '%ELEMENT%' with an offset %OFFSET%.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), - ACTION_SUCCESS_MOUSEOVERANDWAIT(200, "OK", "Mouse moved over '%ELEMENT%' and waited %TIME% ms.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), ACTION_SUCCESS_WAIT_TIME(200, "OK", "Waited %TIME% ms.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), ACTION_SUCCESS_WAIT_TIME_WITHWARNINGS(200, "OK", "Waited %TIME% ms with warning : %MESSAGE%", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), ACTION_SUCCESS_WAIT_ELEMENT(200, "OK", "Waited for %ELEMENT%.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), + ACTION_SUCCESS_FOUND_ELEMENT(200, "OK", "%NUMBER% Element(s) identified by '%ELEMENT%' found. Used the first one.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), ACTION_SUCCESS_WAITVANISH_ELEMENT(200, "OK", "Waited for %ELEMENT% to disappear.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), ACTION_SUCCESS_KEYPRESS(200, "OK", "Key '%KEY%' pressed with success with modifier '%MODIFIER%' on element '%ELEMENT%'.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), ACTION_SUCCESS_KEYPRESS_NO_ELEMENT_NO_MODIFIER(200, "OK", "Key '%KEY%' pressed with success.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), diff --git a/source/src/main/java/org/cerberus/core/service/appium/IAppiumService.java b/source/src/main/java/org/cerberus/core/service/appium/IAppiumService.java index 2fe8427ad..6e5b81aef 100644 --- a/source/src/main/java/org/cerberus/core/service/appium/IAppiumService.java +++ b/source/src/main/java/org/cerberus/core/service/appium/IAppiumService.java @@ -64,7 +64,7 @@ public interface IAppiumService { * @param identifier * @return */ - MessageEvent click(Session session, Identifier identifier); + MessageEvent click(Session session, Identifier identifier, Integer hOffset, Integer vOffset); /** * @param session diff --git a/source/src/main/java/org/cerberus/core/service/appium/impl/AppiumService.java b/source/src/main/java/org/cerberus/core/service/appium/impl/AppiumService.java index f7e27e190..bd21949af 100644 --- a/source/src/main/java/org/cerberus/core/service/appium/impl/AppiumService.java +++ b/source/src/main/java/org/cerberus/core/service/appium/impl/AppiumService.java @@ -146,9 +146,14 @@ public MessageEvent wait(Session session, Identifier identifier) { @Override public MessageEvent type(Session session, Identifier identifier, String valueToType, String propertyName) { MessageEvent message; + MessageEvent foundElementMsg = new MessageEvent(MessageEventEnum.ACTION_FAILED_TYPE_NO_SUCH_ELEMENT); try { if (!StringUtil.isEmptyOrNULLString(valueToType)) { WebElement elmt = this.getElement(session, identifier, false, false); + Integer numberOfElement = this.getNumberOfElements(session, identifier); + foundElementMsg = new MessageEvent(MessageEventEnum.ACTION_SUCCESS_FOUND_ELEMENT); + foundElementMsg.resolveDescription("NUMBER", numberOfElement.toString()); + foundElementMsg.resolveDescription("ELEMENT", identifier.toString()); if (elmt instanceof MobileElement) { ((MobileElement) this.getElement(session, identifier, false, false)).setValue(valueToType); } else { // FIXME See if we can delete it ?? @@ -163,7 +168,7 @@ public MessageEvent type(Session session, Identifier identifier, String valueToT } } message = new MessageEvent(MessageEventEnum.ACTION_SUCCESS_TYPE); - message.setDescription(message.getDescription().replace("%ELEMENT%", identifier.getIdentifier() + "=" + identifier.getLocator())); + message.setDescription(message.getDescription().replace("%ELEMENT%", identifier.getIdentifier() + "=" + identifier.getLocator()).replace("ELEMENTFOUND", foundElementMsg.getDescription())); if (!StringUtil.isEmptyOrNULLString(valueToType)) { message.setDescription(message.getDescription().replace("%DATA%", ParameterParserUtil.securePassword(valueToType, propertyName))); } else { @@ -182,16 +187,27 @@ public MessageEvent type(Session session, Identifier identifier, String valueToT } @Override - public MessageEvent click(final Session session, final Identifier identifier) { + public MessageEvent click(final Session session, final Identifier identifier, Integer hOffset, Integer vOffset) { try { + MessageEvent foundElementMsg; final TouchAction action = new TouchAction(session.getAppiumDriver()); + if (identifier.isSameIdentifier(Identifier.Identifiers.COORDINATE)) { final Coordinates coordinates = getCoordinates(identifier); - action.tap(PointOption.point(coordinates.getX(), coordinates.getY())).perform(); + Point offset = new Point(coordinates.getX(), coordinates.getY()); + foundElementMsg = new MessageEvent(MessageEventEnum.ACTION_SUCCESS_FOUND_ELEMENT); + foundElementMsg.resolveDescription("NUMBER", "1"); + foundElementMsg.resolveDescription("ELEMENT", identifier.toString()); + action.tap(PointOption.point(offset)).perform(); } else { - action.tap(ElementOption.element(getElement(session, identifier, false, false))).perform(); + WebElement element = getElement(session, identifier, false, false); + Integer numberOfElement = this.getNumberOfElements(session, identifier); + foundElementMsg = new MessageEvent(MessageEventEnum.ACTION_SUCCESS_FOUND_ELEMENT); + foundElementMsg.resolveDescription("NUMBER", numberOfElement.toString()); + foundElementMsg.resolveDescription("ELEMENT", identifier.toString()); + action.tap(ElementOption.element(element, hOffset, vOffset)).perform(); } - return new MessageEvent(MessageEventEnum.ACTION_SUCCESS_CLICK).resolveDescription("ELEMENT", identifier.toString()); + return new MessageEvent(MessageEventEnum.ACTION_SUCCESS_CLICK).resolveDescription("ELEMENT", identifier.toString()).resolveDescription("ELEMENTFOUND", foundElementMsg.getDescription()); } catch (NoSuchElementException e) { if (LOG.isDebugEnabled()) { LOG.debug(e.getMessage()); @@ -486,13 +502,9 @@ public MessageEvent clearField(final Session session, final Identifier identifie final TouchAction action = new TouchAction(session.getAppiumDriver()); if (identifier.isSameIdentifier(Identifier.Identifiers.COORDINATE)) { final Coordinates coordinates = getCoordinates(identifier); - click(session, identifier); + click(session, identifier,0, 0); } else { - click(session, identifier); - //action.press(ElementOption.element(getElement(session, identifier, false, false))).waitAction(WaitOptions.waitOptions(Duration.ofMillis(8000))).release().perform(); - //MobileElement element = (MobileElement) session.getAppiumDriver().findElementByAccessibilityId("SomeAccessibilityID"); - //element.clear(); - // WebElement elmt = this.getElement(session, identifier, false, false); + click(session, identifier, 0 ,0); this.getElement(session, identifier, false, false).clear(); } @@ -508,4 +520,10 @@ public MessageEvent clearField(final Session session, final Identifier identifie } } + + private Integer getNumberOfElements(Session session, Identifier identifier) { + By locator = this.getBy(identifier); + AppiumDriver driver = session.getAppiumDriver(); + return driver.findElements(locator).size(); + } } diff --git a/source/src/main/java/org/cerberus/core/service/robotextension/impl/SikuliService.java b/source/src/main/java/org/cerberus/core/service/robotextension/impl/SikuliService.java index 3e8b8b5cb..179c102f5 100644 --- a/source/src/main/java/org/cerberus/core/service/robotextension/impl/SikuliService.java +++ b/source/src/main/java/org/cerberus/core/service/robotextension/impl/SikuliService.java @@ -504,6 +504,7 @@ public MessageEvent doSikuliActionClick(Session session, String locator, String if (actionResult.getResultMessage().getCodeString().equals(new MessageEvent(MessageEventEnum.ACTION_SUCCESS).getCodeString())) { MessageEvent message = new MessageEvent(MessageEventEnum.ACTION_SUCCESS_CLICK); + message.setDescription(message.getDescription().replace("%ELEMENTFOUND%", "At least 1 element found")); message.setDescription(message.getDescription().replace("%ELEMENT%", locator)); return message; } @@ -630,6 +631,7 @@ public MessageEvent doSikuliActionType(Session session, String locator, String t if (actionResult.getResultMessage().getCodeString().equals(new MessageEvent(MessageEventEnum.ACTION_SUCCESS).getCodeString())) { MessageEvent message = new MessageEvent(MessageEventEnum.ACTION_SUCCESS_TYPE); + message.setDescription(message.getDescription().replace("%ELEMENTFOUND%", "At least 1 element found")); message.setDescription(message.getDescription().replace("%ELEMENT%", locator)); message.setDescription(message.getDescription().replace("%DATA%", text)); return message; diff --git a/source/src/main/java/org/cerberus/core/service/webdriver/IWebDriverService.java b/source/src/main/java/org/cerberus/core/service/webdriver/IWebDriverService.java index a4d4e0ff6..e2694800a 100644 --- a/source/src/main/java/org/cerberus/core/service/webdriver/IWebDriverService.java +++ b/source/src/main/java/org/cerberus/core/service/webdriver/IWebDriverService.java @@ -111,11 +111,11 @@ public interface IWebDriverService { MessageEvent scrollTo(Session session, Identifier identifier, String text, String offsets); - MessageEvent doSeleniumActionClick(Session session, Identifier identifier, boolean waitForVisibility, boolean waitForClickability); + MessageEvent doSeleniumActionClick(Session session, Identifier identifier, Integer hOffset, Integer vOffset, boolean waitForVisibility, boolean waitForClickability); - MessageEvent doSeleniumActionMouseDown(Session session, Identifier identifier, boolean waitForVisibility, boolean waitForClickability); + MessageEvent doSeleniumActionMouseDown(Session session, Identifier identifier, Integer hOffset, Integer vOffset, boolean waitForVisibility, boolean waitForClickability); - MessageEvent doSeleniumActionMouseUp(Session session, Identifier identifier, boolean waitForVisibility, boolean waitForClickability); + MessageEvent doSeleniumActionMouseUp(Session session, Identifier identifier, Integer hOffset, Integer vOffset, boolean waitForVisibility, boolean waitForClickability); MessageEvent doSeleniumActionSwitchToWindow(Session session, Identifier identifier); @@ -123,7 +123,7 @@ public interface IWebDriverService { MessageEvent doSeleniumActionManageDialogKeyPress(Session session, String valueToPress); - MessageEvent doSeleniumActionDoubleClick(Session session, Identifier identifier, boolean waitForVisibility, boolean waitForClickability); + MessageEvent doSeleniumActionDoubleClick(Session session, Identifier identifier, Integer hOffset, Integer vOffset, boolean waitForVisibility, boolean waitForClickability); MessageEvent doSeleniumActionType(Session session, Identifier identifier, String valueToType, String propertyName, boolean waitForVisibility, boolean waitForClickability); @@ -145,7 +145,7 @@ public interface IWebDriverService { MessageEvent doSeleniumActionFocusDefaultIframe(Session session); - MessageEvent doSeleniumActionRightClick(Session session, Identifier identifier); + MessageEvent doSeleniumActionRightClick(Session session, Identifier identifier, Integer hOffset, Integer vOffset); MessageEvent doSeleniumActionDragAndDrop(Session session, Identifier object, Identifier property, boolean waitForVisibility, boolean waitForClickability) throws IOException; diff --git a/source/src/main/java/org/cerberus/core/service/webdriver/impl/WebDriverService.java b/source/src/main/java/org/cerberus/core/service/webdriver/impl/WebDriverService.java index 524bfe785..30dfb86af 100644 --- a/source/src/main/java/org/cerberus/core/service/webdriver/impl/WebDriverService.java +++ b/source/src/main/java/org/cerberus/core/service/webdriver/impl/WebDriverService.java @@ -407,7 +407,9 @@ private AnswerItem getSeleniumElement(Session session, Identifier id element = wait.until(ExpectedConditions.presenceOfElementLocated(locator)); } answer.setItem(element); - msg = new MessageEvent(MessageEventEnum.ACTION_SUCCESS_WAIT_ELEMENT); + Integer numberOfElement = this.getNumberOfElements(session, identifier); + msg = new MessageEvent(MessageEventEnum.ACTION_SUCCESS_FOUND_ELEMENT); + msg.resolveDescription("NUMBER", numberOfElement.toString()); msg.resolveDescription("ELEMENT", identifier.getIdentifier() + "=" + identifier.getLocator() + erratumMessage); /** @@ -427,7 +429,12 @@ private AnswerItem getSeleniumElement(Session session, Identifier id } catch (TimeoutException exception) { LOG.warn("Exception waiting for element :" + exception); - //throw new NoSuchElementException(identifier.getIdentifier() + "=" + identifier.getLocator()); + Integer numberOfElement = 0; + try { + numberOfElement = this.getNumberOfElements(session, identifier); + } catch(Exception ex){ + //No element found + } msg = new MessageEvent(MessageEventEnum.ACTION_FAILED_WAIT_NO_SUCH_ELEMENT); msg.resolveDescription("ELEMENT", identifier.getIdentifier() + "=" + identifier.getLocator() + erratumMessage); } @@ -909,12 +916,13 @@ public boolean isElementClickable(Session session, Identifier identifier) { } @Override - public MessageEvent doSeleniumActionClick(Session session, final Identifier identifier, boolean waitForVisibility, boolean waitForClickability) { + public MessageEvent doSeleniumActionClick(Session session, final Identifier identifier, Integer hOffset, Integer vOffset, boolean waitForVisibility, boolean waitForClickability) { MessageEvent message; try { AnswerItem answer = this.getSeleniumElement(session, identifier, waitForVisibility, waitForClickability); - if (answer.isCodeEquals(MessageEventEnum.ACTION_SUCCESS_WAIT_ELEMENT.getCode())) { + if (answer.isCodeEquals(MessageEventEnum.ACTION_SUCCESS_FOUND_ELEMENT.getCode())) { + final WebElement webElement = answer.getItem(); if (webElement != null) { @@ -927,18 +935,12 @@ public MessageEvent doSeleniumActionClick(Session session, final Identifier iden || Platform.IOS.equals(session.getDesiredCapabilities().getPlatform())) { webElement.click(); } else { - /** - * webElement.click(); did not provide good result for - * generating Selenium error : Element is not clickable - * at point - * https://github.com/cerberustesting/cerberus-source/issues/2030 - */ - // webElement.click(); Actions actions = new Actions(session.getDriver()); - actions.click(webElement); + actions.moveToElement(webElement, hOffset, vOffset).click(); actions.build().perform(); } message = new MessageEvent(MessageEventEnum.ACTION_SUCCESS_CLICK); + message.setDescription(message.getDescription().replace("%ELEMENTFOUND%", answer.getResultMessage().getDescription())); message.setDescription(message.getDescription().replace("%ELEMENT%", identifier.getIdentifier() + "=" + identifier.getLocator())); return message; } @@ -960,7 +962,7 @@ public MessageEvent doSeleniumActionClick(Session session, final Identifier iden } @Override - public MessageEvent doSeleniumActionMouseDown(Session session, Identifier identifier, boolean waitForVisibility, boolean waitForClickability) { + public MessageEvent doSeleniumActionMouseDown(Session session, Identifier identifier, Integer hOffset, Integer vOffset, boolean waitForVisibility, boolean waitForClickability) { MessageEvent message; try { @@ -969,7 +971,7 @@ public MessageEvent doSeleniumActionMouseDown(Session session, Identifier identi WebElement webElement = (WebElement) answer.getItem(); if (webElement != null) { Actions actions = new Actions(session.getDriver()); - actions.clickAndHold(webElement); + actions.moveToElement(webElement, hOffset, vOffset).clickAndHold(); actions.build().perform(); message = new MessageEvent(MessageEventEnum.ACTION_SUCCESS_MOUSEDOWN); message.setDescription(message.getDescription().replace("%ELEMENT%", identifier.getIdentifier() + "=" + identifier.getLocator())); @@ -995,7 +997,7 @@ public MessageEvent doSeleniumActionMouseDown(Session session, Identifier identi } @Override - public MessageEvent doSeleniumActionMouseUp(Session session, Identifier identifier, boolean waitForVisibility, boolean waitForClickability) { + public MessageEvent doSeleniumActionMouseUp(Session session, Identifier identifier, Integer hOffset, Integer vOffset, boolean waitForVisibility, boolean waitForClickability) { MessageEvent message; try { AnswerItem answer = this.getSeleniumElement(session, identifier, waitForVisibility, waitForClickability); @@ -1003,7 +1005,7 @@ public MessageEvent doSeleniumActionMouseUp(Session session, Identifier identifi WebElement webElement = (WebElement) answer.getItem(); if (webElement != null) { Actions actions = new Actions(session.getDriver()); - actions.release(webElement); + actions.moveToElement(webElement, hOffset, vOffset).release(); actions.build().perform(); message = new MessageEvent(MessageEventEnum.ACTION_SUCCESS_MOUSEUP); message.setDescription(message.getDescription().replace("%ELEMENT%", identifier.getIdentifier() + "=" + identifier.getLocator())); @@ -1203,7 +1205,7 @@ private boolean checkIfExpectedWindow(Session session, String identifier, String } @Override - public MessageEvent doSeleniumActionDoubleClick(Session session, Identifier identifier, boolean waitForVisibility, boolean waitForClickability) { + public MessageEvent doSeleniumActionDoubleClick(Session session, Identifier identifier, Integer hOffset, Integer vOffset, boolean waitForVisibility, boolean waitForClickability) { MessageEvent message; try { AnswerItem answer = this.getSeleniumElement(session, identifier, waitForVisibility, waitForClickability); @@ -1211,7 +1213,7 @@ public MessageEvent doSeleniumActionDoubleClick(Session session, Identifier iden WebElement webElement = (WebElement) answer.getItem(); if (webElement != null) { Actions actions = new Actions(session.getDriver()); - actions.doubleClick(webElement); + actions.moveToElement(webElement, hOffset, vOffset).doubleClick(); actions.build().perform(); message = new MessageEvent(MessageEventEnum.ACTION_SUCCESS_DOUBLECLICK); message.setDescription(message.getDescription().replace("%ELEMENT%", identifier.getIdentifier() + "=" + identifier.getLocator())); @@ -1241,7 +1243,7 @@ public MessageEvent doSeleniumActionType(Session session, Identifier identifier, MessageEvent message; try { AnswerItem answer = this.getSeleniumElement(session, identifier, waitForVisibility, waitForClickability); - if (answer.isCodeEquals(MessageEventEnum.ACTION_SUCCESS_WAIT_ELEMENT.getCode())) { + if (answer.isCodeEquals(MessageEventEnum.ACTION_SUCCESS_FOUND_ELEMENT.getCode())) { WebElement webElement = (WebElement) answer.getItem(); if (webElement != null) { webElement.clear(); @@ -1249,6 +1251,7 @@ public MessageEvent doSeleniumActionType(Session session, Identifier identifier, webElement.sendKeys(valueToType); } message = new MessageEvent(MessageEventEnum.ACTION_SUCCESS_TYPE); + message.setDescription(message.getDescription().replace("%ELEMENTFOUND%", answer.getResultMessage().getDescription())); message.setDescription(message.getDescription().replace("%ELEMENT%", identifier.getIdentifier() + "=" + identifier.getLocator())); if (!StringUtil.isEmptyOrNULLString(valueToType)) { message.setDescription(message.getDescription().replace("%DATA%", ParameterParserUtil.securePassword(valueToType, propertyName))); @@ -1316,20 +1319,6 @@ public MessageEvent doSeleniumActionWait(Session session, Identifier identifier) AnswerItem answer = this.getSeleniumElement(session, identifier, false, false); return answer.getResultMessage(); - -// MessageEvent message; -// try { -// WebDriverWait wait = new WebDriverWait(session.getDriver(), TimeUnit.MILLISECONDS.toSeconds(session.getCerberus_selenium_wait_element())); -// wait.until(ExpectedConditions.presenceOfElementLocated(this.getBy(identifier))); -// message = new MessageEvent(MessageEventEnum.ACTION_SUCCESS_WAIT_ELEMENT); -// message.setDescription(message.getDescription().replace("%ELEMENT%", identifier.getIdentifier() + "=" + identifier.getLocator())); -// return message; -// } catch (TimeoutException exception) { -// message = new MessageEvent(MessageEventEnum.ACTION_FAILED_WAIT_NO_SUCH_ELEMENT); -// message.setDescription(message.getDescription().replace("%ELEMENT%", identifier.getIdentifier() + "=" + identifier.getLocator())); -// LOG.debug(exception.toString()); -// return message; -// } } @Override @@ -1995,7 +1984,7 @@ public JSONArray getJSONConsoleLog(Session session) { } @Override - public MessageEvent doSeleniumActionRightClick(Session session, Identifier identifier) { + public MessageEvent doSeleniumActionRightClick(Session session, Identifier identifier, Integer hOffset, Integer vOffset) { MessageEvent message; try { AnswerItem answer = this.getSeleniumElement(session, identifier, true, true); @@ -2003,7 +1992,7 @@ public MessageEvent doSeleniumActionRightClick(Session session, Identifier ident WebElement webElement = (WebElement) answer.getItem(); if (webElement != null) { Actions actions = new Actions(session.getDriver()); - actions.contextClick(webElement); + actions.moveToElement(webElement, hOffset, vOffset).contextClick(); actions.build().perform(); message = new MessageEvent(MessageEventEnum.ACTION_SUCCESS_RIGHTCLICK); message.setDescription(message.getDescription().replace("%ELEMENT%", identifier.getIdentifier() + "=" + identifier.getLocator())); diff --git a/source/src/main/webapp/js/testcase/testcaseStatic.js b/source/src/main/webapp/js/testcase/testcaseStatic.js index 6c01f6fdd..2c41c54a2 100644 --- a/source/src/main/webapp/js/testcase/testcaseStatic.js +++ b/source/src/main/webapp/js/testcase/testcaseStatic.js @@ -36,21 +36,26 @@ var actionOptGroupList = [ var actionOptList = { "unknown":{"group":"none","value":"Unknown","label_en": "None","label":{"en":"Define an action","fr":"Choisir une action"},"application_types":["GUI","SRV","IPA","APK","BAT","FAT","NONE"]}, "click":{"group":"mouse_action","value":"click","label":{"en":"Click","fr":"Cliquer"},"application_types":["GUI","IPA","APK","FAT"], - "field1":{"label":{"en": "Element path", "fr": "Chemin vers l'élement à cliquer"},"picto":"images/action-html.png","class": "col-lg-12 crb-autocomplete-element crb-contextual-button"},"documentation":{"en":"...","fr":"..."}}, + "field1":{"label":{"en": "Element path", "fr": "Chemin vers l'élement à cliquer"},"picto":"images/action-html.png","class": "col-lg-12 crb-autocomplete-element crb-contextual-button"},"documentation":{"en":"...","fr":"..."}, + "field2":{"label":{"en": "[Optional] Offset. (ex : 50,100) [GUI,APK,IPA only]", "fr": "[Optionnel] Offset (ex : 50,100) [seulement GUI,APK,IPA]"},"picto":"images/action-numeric.png", "class": "col-lg-12 crb-autocomplete-element crb-contextual-button"}}, "longPress":{"group":"mouse_action","value":"longPress","label":{"en":"longPress","fr":"Cliquer x secondes"},"application_types":["GUI","IPA","APK","FAT"], "field1":{"label": {"en":"Element path","fr":"Chemin vers l'élement à cliquer"},"picto":"images/action-html.png", "class": "col-lg-9 crb-autocomplete-element crb-contextual-button"}, "field2":{"label":{"en":"[opt] Duration (ms) : 8000 by default","fr":"[opt] Valeur (ms) : 8000 par défaut"},"picto":"images/action-time-left.png", "class": "col-lg-3 crb-autocomplete-variable"},"documentation":{"en":"...","fr":"..."}}, "mouseLeftButtonPress":{"group":"mouse_action","value": "mouseLeftButtonPress","label":{"en":"Press and keep left button","fr":"Presser et maintenir le bouton gauche"}, "application_types":["GUI","FAT"], - "field1":{"label":{"en": "Element path", "fr": "Chemin vers l'élement à cibler"},"picto":"images/action-html.png", "class": "col-lg-12 crb-autocomplete-element crb-contextual-button"}}, + "field1":{"label":{"en": "Element path", "fr": "Chemin vers l'élement à cibler"},"picto":"images/action-html.png", "class": "col-lg-12 crb-autocomplete-element crb-contextual-button"}, + "field2":{"label":{"en": "[Optional] Offset. (ex : 50,100) [GUI only]", "fr": "[Optionnel] Offset (ex : 50,100) [seulement GUI]"},"picto":"images/action-numeric.png", "class": "col-lg-12 crb-autocomplete-element crb-contextual-button"}}, "mouseLeftButtonRelease":{"group":"mouse_action","value": "mouseLeftButtonRelease","label":{"en":"Release left button","fr":"Relacher le bouton gauche"}, "application_types":["GUI","FAT"], - "field1":{"label":{"en": "Element path", "fr": "Chemin vers l'élement"},"picto":"images/action-html.png", "class": "col-lg-12 crb-autocomplete-element crb-contextual-button"}}, + "field1":{"label":{"en": "Element path", "fr": "Chemin vers l'élement"},"picto":"images/action-html.png", "class": "col-lg-12 crb-autocomplete-element crb-contextual-button"}, + "field2":{"label":{"en": "[Optional] Offset. (ex : 50,100) [GUI only]", "fr": "[Optionnel] Offset (ex : 50,100) [seulement GUI]"},"picto":"images/action-numeric.png", "class": "col-lg-12 crb-autocomplete-element crb-contextual-button"}}, "doubleClick":{"group":"mouse_action", "value": "doubleClick","label":{"en":"Double Click","fr":"Double Clic"}, "application_types":["GUI","FAT"], - "field1":{"label":{"en": "Element path", "fr": "Chemin vers l'élement à double-cliquer"},"picto":"images/action-html.png", "class": "col-lg-12 crb-autocomplete-element crb-contextual-button"}}, + "field1":{"label":{"en": "Element path", "fr": "Chemin vers l'élement à double-cliquer"},"picto":"images/action-html.png", "class": "col-lg-12 crb-autocomplete-element crb-contextual-button"}, + "field2":{"label":{"en": "[Optional] Offset. (ex : 50,100)", "fr": "[Optionnel] Offset (ex : 50,100)"},"picto":"images/action-numeric.png", "class": "col-lg-12 crb-autocomplete-element crb-contextual-button"}}, "rightClick":{"group":"mouse_action", "value": "rightClick", "label":{"en":"Right Click","fr":"Clic droit"}, "application_types":["GUI","FAT"], - "field1":{"label":{"en": "Element path", "fr": "Chemin vers l'élement à clicker avec le bouton droit"},"picto":"images/action-html.png", "class": "col-lg-12 crb-autocomplete-element crb-contextual-button"}}, + "field1":{"label":{"en": "Element path", "fr": "Chemin vers l'élement à clicker avec le bouton droit"},"picto":"images/action-html.png", "class": "col-lg-12 crb-autocomplete-element crb-contextual-button"}, + "field2":{"label":{"en": "[Optional] Offset. (ex : 50,100) [GUI only]", "fr": "[Optionnel] Offset (ex : 50,100) [seulement GUI]"},"picto":"images/action-numeric.png", "class": "col-lg-12 crb-autocomplete-element crb-contextual-button"}}, "mouseOver":{"group":"mouse_action", "value": "mouseOver", "label":{"en":"Mouse Over","fr":"Souris sur l'élément"}, "application_types":["GUI","FAT"], "field1":{"label":{"en": "Element path", "fr": "Chemin vers l'élement"},"picto":"images/action-html.png", "class": "col-lg-12 crb-autocomplete-element crb-contextual-button"}, - "field2":{"label":{"en": "[Optional] Relative coord. (ex : 50,100)", "fr": "[Optionnel] Coordonnées relatives (ex : 50,100)"},"picto":"images/action-numeric.png", "class": "col-lg-12 crb-autocomplete-element crb-contextual-button"}}, + "field2":{"label":{"en": "[Optional] Offset. (ex : 50,100) [GUI, FAT only]", "fr": "[Optionnel] Offset (ex : 50,100) [seulement GUI,FAT]"},"picto":"images/action-numeric.png", "class": "col-lg-12 crb-autocomplete-element crb-contextual-button"}}, "mouseMove":{"group":"mouse_action", "value": "mouseMove", "label":{"en":"Move Mouse","fr":"Déplacer la souris"}, "application_types":["GUI","FAT"], "field1":{"label":{"en": "Relative coord. (ex : 50,100 ; 200,50)", "fr": "Coordonnées relatives (ex : 50,100 ; 200,50)"}, "class": "col-lg-12 crb-autocomplete-element crb-contextual-button"}}, "openUrlWithBase":{"group":"access_application","value": "openUrlWithBase","label":{"en":"openUrlWithBase","fr":"Appeler l'URI"},"application_types":["GUI","IPA","APK"],