I'm working on an automation project, I need to find an element depending on the text it contains inside an IOS app, but MobileBy.IosUIAutomation no longer works with iOS 10 and higher, how can I replace this piece of code to make it do the same functionality.
`
listItem = element.findElement(MobileBy.IosUIAutomation(
"new UiScrollable(new UiSelector()).scrollIntoView(" + "new UiSelector().text(\"" + itemText + "\"));
`
Does anyone know of a replacement for MobileBy.IosUIAutomation or how it could perform the same functionality?
You can use XCUITest driver now for Automating iOS application.
So instead of iOSUiAutomation locator strategy, you can now use NS predicate string or iOS Class chain locator strategies.
Check out my blog on different locator strategies in Appium where you can get more details about the above mentioned locator strategies.
In your example, if you use NS predicate string, the locator will be,
listItem = element.findElement (MobileBy.iOSNsPredicateString ("label == \"" + itemText + "\"));
Note:
In iOS, you now don't need to do scrollIntoView because with XCUITest driver, it is able to find all the elements on the screen, even those which are not visible on the viewport.
Related
Hi am trying to populate value to text box (check image below) using xpath.
Actions actions = new Actions(driver);
actions.moveToElement(driver.findElement(By.xpath("//*[#class='CzI8E']")));
actions.click();
Thread.sleep(3000);
actions.moveToElement(driver.findElement(By.xpath("//*[#class='_2S1VP copyable-text selectable-text']")));//_2S1VP copyable-text selectable-text
actions.sendKeys(WhatsappConstants.TEXT_MESSAGE);
actions.build().perform();
But i am getting this exception
org.openqa.selenium.WebDriverException: unknown error: ChromeDriver only supports characters in the BMP
Other stackoverflow answers said to use firefox driver but in my case i need you use chrome only.
This is a known limitation of the Chromedriver, see http://crbug.com/chromedriver/2269 for the bug report in the official bug tracker.
What you could do is to only limit yourself to supported characters, basically those from: http://www.columbia.edu/kermit/ucs2.html
Alternatively, you could simulate input instead of really sending the keys using front-end JS snippet like the following:
(function (element, text) {
Array.prototype.forEach.call(text, function (char) {
element.value += char;
element.dispatchEvent(new KeyboardEvent("keydown"));
element.dispatchEvent(new KeyboardEvent("keypress"));
element.dispatchEvent(new KeyboardEvent("input"));
element.dispatchEvent(new KeyboardEvent("keyup"));
});
}).apply(null, arguments);
Which you then call using the JavascriptExecutor:
((JavascriptExecutor) driver).executeScript(JS_CODE, element, text);
The snippet works on elements with a writable .value property, it could be extended to support contenteditable elements.
Note that the fields of the events are set to their defaults, including key codes and such, see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/KeyboardEvent Also you might have to add additional events to be triggered to even better simulate user input.
I have a similar problem and I solve it in this way.
First, you should add any text to this div with JavascriptExecutor , and then clear this text and use selenium's sendKeys method
WebElement inputDiv = driver.findElement(By.xpath("your_path_to_div"));
JavascriptExecutor executor = (JavascriptExecutor) driver;
executor.executeScript("document.querySelector('your_selector_to_div').innerText='aaa'");
inputDiv.clear();
inputDiv.sendKeys(subject);
I am writing automated tests for mobile application in Java using Appium. I talked with developers to create AccessibilityIds for elements and in Android it works as intended with set String but in iOS AccessibilityId contains additional characters. For example, I have TextField Name - in Android AccessibilityId is txtName, but in iOS it is Name txtName.
That is why I think I need to use contains. With XPath I would write
driver.findElement(By.xpath("//*[contains(#name, 'txtName')]"));
But XPath is relatively slow. How can I do that using AccessibilityId? Rough example of what I'm looking for
driver.findElementByAccessibilityId(/*HERE 'CONTAINS' W\ 'txtName'*/);
It is really important for me to use same solution that works on both Android and iOS. I prefer AccessibilityId because code is easier to understand and fast
Any condition to check contain value for accessibility id?
Code snippet:
WebElement getpremiumbtn = new WebDriverWait(driver, 30).until(ExpectedConditions.refreshed(ExpectedConditions
.presenceOfElementLocated(ByAccessibilityId.AccessibilityId("get premium button"))));
Assert.assertTrue(getpremiumbtn != null && getpremiumbtn.isDisplayed(), "Get premium is not displayed");
I am trying to automate testing with Selenium Webdriver without the need of xpath. I'm facing problem when the site is modified then xpath is being changed. For elements(like buttons, drop downs etc) which needs some action to be performed any how it needs xpath or someother things to identify that element. If I want to fetch data(table contents) from site to validate its excecution,then here I will need lots of xpaths to do so.
Is there a better way to avoid some xpaths?
Instead of using xpath, you can map the elements by css selectors, like this:
driver.findElement(By.cssSelector("css selector"), OR
by ID, like this:
driver.findElement(By.id("coolestWidgetEvah")).
There are much more than these 2. See Selenium docomentation
Steven, you basically have 2 choices the way I see it. One is to inject your own attributes (i.e qa attrib for instance) into your web elements which will never change. Please see this post, on how you can achieve this:
Selenium: Can I set any of the attribute value of a WebElement in Selenium?
Alternatively you can still use 'naked' xpath in order to locate your elements.
By 'naked' i mean generic, so not so specific.
Consider this element sitting below this:
div id="username"
input class="usernameField"
button type='submit
So, instead of locating it like this (which is specific/aggresive):
//div[#id='username']//input[#class='usernameField']//button[#type='submit']
you can use a more mild approach, omitting the specific values, like so:
//div[#id]//input[#class]//button[#type]
Which is less likely to break upon change. However, beware you need to be 100% sure that with the 2nd approach you are locating a unique element. In other, words if there are more than 1 buttons you might select the wrong one or cause a Selenium exception.
I would recommend this Xpath helper add-on for Chrome which highlights on the screen when your xpath is correct and also shows you how many elements match you Xpath (i.e. unique or not?)
xpath Helper
Hope the above, makes sense, don't hesitate to ask if it does not!
Best of luck!
Ofcoarse there are certain other ways without using id/xpath/CSS and even "sendKeys". The solution is to do that via Sikuli.
Things to do:
You have to download the Sikuli exe jar (sikulixsetup-1.1.0). (from https://launchpad.net/sikuli/+download)
Install the Sikuli exe jar which extracts the "sikulixapi" and adds to the PATH variable.
Add the External jar "sikulixapi" at project level through Eclipse.
Now take images of the elements where you want to pass some text or click.
Use the reference of the images in Selenium Java code to write text & perform clicks.
Here is a simple code to browse to "https://www.google.co.in/" move on to Login page & enter Emailid & Password without any xpath or sendkeys.
package SikuliDemo;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.sikuli.script.Pattern;
import org.sikuli.script.Screen;
public class SikuliDemoScript {
public static void main(String[] args) throws Exception
{
Screen screen = new Screen();
Pattern image1 = new Pattern("C:\\Utility\\OP_Resources\\Sikuli_op_images\\gmailLogo.png");
Pattern image2 = new Pattern("C:\\Utility\\OP_Resources\\Sikuli_op_images\\gmailSignIn.png");
Pattern image3 = new Pattern("C:\\Utility\\OP_Resources\\Sikuli_op_images\\Email.png");
Pattern image4 = new Pattern("C:\\Utility\\OP_Resources\\Sikuli_op_images\\EmailNext.png");
Pattern image5 = new Pattern("C:\\Utility\\OP_Resources\\Sikuli_op_images\\Password.png");
Pattern image6 = new Pattern("C:\\Utility\\OP_Resources\\Sikuli_op_images\\SignIn.png");
System.setProperty("webdriver.chrome.driver", "C:\\Utility\\BrowserDrivers\\chromedriver.exe");
WebDriver driver = new ChromeDriver();
driver.manage().window().maximize();
driver.get("https://www.google.co.in/");
screen.wait(image1, 10);
screen.click(image1);
screen.wait(image2, 10);
screen.click(image2);
screen.type(image3, "selenium");
screen.click(image4);
screen.wait(image5, 10);
screen.type(image5, "admin123");
screen.click(image6);
driver.quit();
}
}
Let me know if this answers your question.
I'm currently testing an application using Appium on an android device (appium version: 1.2.4.1, java-client: 2.1.0). I'm using the following code to send some text in a textField:
driver.findElement(By.name("Name")).sendKeys("My Name");
and it works fine just it takes it too long to actually send the text on the textbox (usually 7 seconds). I was wondering does anybody know another way to send text on a textField that takes less?
Thanks!
I solved this issue by using adb to send text instead of appium!It is really fast!
try {
textElement.click();
new ProcessBuilder(new String[]{"adb", "-s", "YOURDEVICEUUID", "shell", "input", "text", "YOURTEXTASINPUT"})
.redirectErrorStream(true)
.start();
} catch (IOException e) {
e.printStackTrace();
}
Same way you may use this for Click,clear,install,uninstall etc.. there may be some need to sleep thread for sync issues but it is only 50ms which is too less than 5 seconds which appium takes!
You may use DDMLIB to make this adb call instead of ProcessBuilder!
Try :
driver.findElement(By.name("Name")).Click();
driver.Keyboard.SendKeys("My Name");
This should run faster then your method.
This capabilities helped me to reduce the time of inputs on Android
desiredCapabilities.setCapability("ignoreUnimportantViews", true);
desiredCapabilities.setCapability("disableAndroidWatchers", true);
You can find more here https://appium.io/docs/en/writing-running-appium/caps/#android-only
Experiencing slow automation on Appium is common because Appium is based on a client/server architecture. Network issues can influence the performance of a test (unless you are running your test in the same machine where Appium is installed).
I can tell you that I have also experienced problems with slow tests on Appium. It usually happens on simulators/emulators by the way.
Send keys as part of a UX scenario
If your test needs to send keys as part of a User Experience scenario, then SendKeys is your only option. This method does not simply set a value in a textbox, it actually behaves like a user pressing keys and sending keys to a textbox.
If this is what you need, then you need to understand what is happening a network level because this is what your problem is about. Also consider that this method can be slow on its own sometimes (this is my experience).
Setting a text is not important for the UX scenario being tested
In case the step of setting a textbox's value is not a core part of your automation for the specific test being considered, you an always do achieve this by means of ExecuteScript which lets you execute a Javascript code in your app. I am assuming you are automating the WebView context.
int result = driver.executeScript("
try {
var el = document.getElementById('<your-txtbox-id-here>');
el.value = '<your-text-here>';
return 0;
} catch {
return 1;
}
");
Java does not support multiline strings so the previous is a prettyprint of the following:
int result = driver.executeScript("try{var el = document.getElementById('<your-txtbox-id-here>');el.value = '<your-text-here>';return 0;}catch{return 1;}");
This method will return 0 in case the string was successfully set, otherwise 1. It should be faster because the driver will not send each key separately but execute the script in an anonymous function and get back its return value.
Try to add the following capabilities inorder to have appium keyboard(and not the physical keyboard)
capabilities.setCapability("resetKeyboard", true);
capabilities.setCapability("unicodeKeyboard", true);
Replace sendKeys with the setValue method available in later versions of appium:
driver.findElement(By.name("Name")).setValue("My Name");
It is much faster in my experience.
For new commer, in the Appium version 1.9~, both method executeJavaScript() & setValue() works so good, and you can consider to use it.
// use js
executeJavaScript("$('#" + fieldId + "').val(testData);
// use setValue
$(By.id(fieldId)).setValue(testData);
I improved the speed of my test (written in Python) using:
driver.set_value(myElement, "My Name")
instead of:
webElement.send_keys("My Name")
If you are using Java, it will be something similar to:
driver.setValue(driver.findElement(By.name("Name")), "My Name")
Another approach could be with adb... (This is the fastest one but you have to use another thing besides appium)
//1st - Click at your WebElement
driver.click(driver.findElement(By.name("Name")))
//2nd - Using adb send your text
//adb shell input text "My Name"
adb shell input keyboard text "My Name"
I am using Visualr http://googlevisualr.herokuapp.com/ with Rails and having a good amount of success creating dynamic charts. However, I am wondering if it's possible to allow the user to click on the column in a 'column chart' and be linked to a page? I am happy to know the java version if you aren't familiar with visualr.
Thanks!
It now is available!
There has recently been an update on this issue. Therefore I want to update this SO Q&A.
Resources:
Google Visualr Github Pull Request #39
Google Visualr Github Issue #36
Code example
xxx_controller.rb
#table = GoogleVisualr::Interactive::ColumnChart.new(g, options_g)
#table.add_listener("select", "function(e) {
EventHandler(e, chart, data_table)
}")
And then in a JS file e.g. app/assets/javascripts/application.js:
function EventHandler(e, chart, data) {
var selection = chart.getSelection();
if (selection.length > 0) {
var row = selection[0].row;
var department = data.getValue(row, 0);
alert(department + " | " + row)
}
}
Google Charts (whether you access them directly or via a wrapper gem like Visualr) are simple images, so the straight answer is "No", at least not without doing some work of your own. In order to achieve this you would need to place your own transparent clickable links (or divs or whatever) over the image, in the right place, to correspond to the columns that google generate in the image.
I'd imagine this would be tricky and error prone - it might actually be easier for you to just generate the columns yourself in html and css, using the data you would previously have sent to google to set the height (in %) of the columns. Then, each column would be a seperate html element and could link to whatever you want.
So, more control = more work. As usual :)