I'm using Java, Selenium, and Chrome for test automation. Our developers recently upgraded our UI from AngularJS to Angular2 (not sure if that matters). But since then, sendKeys is inputting incomplete characters in to the text field. Here's an example:
public void enterCustomerDetails()
{
txtFirstName.sendKeys("Joh201605130947AM");
txtSurname.sendKeys("Doe201605130947AM");
txtEmail.sendKeys("johndoe#gmail.com");
}
I also tried using executeScript. It didn't work. It can enter complete characters but the form thinks the field is null.
public void forceSendKeys(WebElement element, String text)
{
if (element != null)
((JavascriptExecutor) this.webDriver).executeScript("arguments[0].value=arguments[1]", element, text);
}
public void enterCustomerDetails()
{
forceSendKeys(txtFirstName, "Joh201605130947AM");
forceSendKeys(txtSurname, "Doe201605130947AM");
forceSendKeys(txtEmail, "johndoe#gmail.com");
}
I also tried using .click() before .sendKeys and adding in sleep time. They didn't work too.
I got an idea to enter the characters 1 by 1 from this post: How to enter characters one by one in to a text field in selenium webdriver?
It worked but that means I have to rewrite all my codes from sendKeys to the new function:
public void sendChar(WebElement element, String value)
{
element.clear();
for (int i = 0; i < value.length(); i++){
char c = value.charAt(i);
String s = new StringBuilder().append(c).toString();
element.sendKeys(s);
}
}
public void enterCustomerDetails()
{
sendChar(txtFirstName, "Joh201605130947AM");
sendChar(txtSurname, "Doe201605130947AM");
sendChar(txtEmail, "johndoe#gmail.com");
}
If you guys know a better way, please help! :)
I assume this is caused by this Angular2 issue https://github.com/angular/angular/issues/5808
Angular can't process input events when they arrive too fast.
As a workaround you would need to send single characters with a small delay between each.
I stumbled upon this error when doing integration tests with NightwatchJS (which uses selenium).
So I'm writing this for people coming here in the future.
I wrote this extension command for nightwatch:
exports.command = function (selector, value, using) {
var self = this;
self.elements(using || 'css selector', selector, function (elems) {
elems.value.forEach(function (element) {
for (var c of value.split('')) {
self.elementIdValue(element.ELEMENT, c);
}
});
});
return this;
};
Which can be used in this way:
var username = 'integration#test.com';
browser.setValueSlow('input[ngcontrol=username]', username); //Works with ng2!
This issue was also discussed on NightwatchJS's github here
By using Actions class, this issue solved for me
Tried many ways as mentioned above. Also tried to setvalue by js executescript
Finally, found this code and it worked well for grid component built on angular
actions.sendKeys(webElement,
modifiedValue).perform();
I was getting this error too in Java, Selenium. You might also be getting this error too while writing your codes - "sendKeys (CharSequence) from the type Webelement refers to the missing type charSequence"
I tried varying the wait time and even typing extra characters before the main characters, they did not work.
The simple trick I used was to change the Java Compiler version from JRE 9 to JRE 10.
This is due to a bug in Angular apps. Workaround is to put a sleep function.
public void setText(By element, String text) {
sleep(100); // Angular version < 2 apps require this sleep due to a bug
driver.findElement(element).clear();
driver.findElement(element).sendKeys(text);
}
i had the same problem, if you see it carefully selenium is changing the characters, some numbers perform a backspace or other symbols, i read it happens when using selenium with vncserver, i changed to firefox.... and it worked.
if that's not your problem, maybe sending the data in parts:
input1="Joh201605130947AM"
txtFirstName.sendKeys(input1[0:7])
txtFirstName.sendKeys(input1[8:end])
Using
Chromium 78.0.3904.70,
Vaadin Flow Framework 14.1.3,
Selenium 3.141.59
and OpenJDK 11.0.5
the behavior also occurs and is even worse:
I see that the character is typed in and suddenly after that it disappears.
A workaround is to be persistent and just try it again. And again. Until the character is finally typed in.
// Type in every single character
for (int i = 0; i < textToType.length(); i++) {
boolean typingCharacterWasSuccessful = false;
// If typing was not successful before, just type again
while (!typingCharacterWasSuccessful) {
// Type in the character
char singleCharacterToType = textToType.charAt(i);
htmlTextfeld.sendKeys(Character.toString(singleCharacterToType));
// Wait a little. Maybe alternatively/additionally wait.until(...)
Thread.sleep(200);
// Check typed in string.
String inputValueAfterTyping = htmlTextfeld.getAttribute("value");
if (inputValueAfterTyping.length() > i + 1) {
// Alternatively: delete everything and start all over
throw new Exception("Input value too long. Maybe character typed in twice!?");
}
// Typing was successful if the value in the input field is as expected (up to now)
typingCharacterWasSuccessful
= inputValueAfterTyping.equals(textToType.substring(0, i + 1));
}
}
I had a similar issue for big texts in Java.
I overcome the issue using the copy and paste of the text in the keyboard-related methods, as in the following method:
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
public static void clickAndSetMultilineText(WebElement element, String text) {
/** click on element **/
element.click();
/** clear older content of the text using keyboard functionality **/
element.sendKeys(Keys.CONTROL + "a"); // select all text
element.sendKeys(Keys.DELETE); // delete old text
StringSelection stringSelection= new StringSelection(text);
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents(stringSelection, null); // copy text to the keyboard
element.sendKeys(Keys.CONTROL+"v"); // paste text to the field
}
Hope this is helpful.
try this code.. other way to set values using javascript
WebDriver driver = new FirefoxDriver();
JavascriptExecutor jse = (JavascriptExecutor)driver;
jse.executeScript("document.getElementsByName('body')[0].setAttribute('type', 'text');");
driver.findElement(By.xpath("//input[#name='body']")).clear();
driver.findElement(By.xpath("//input[#name='body']")).sendKeys("Ripon: body text");
Related
How to enter characters one by one in to a text field in selenium webdriver? I have used the below code but it's not working
getDriver().findElement(By.id("PhoneNumber")).sendKeys(Keys.chord("9876544322"));
Can anybody suggest how to resolve this?
Here is how I am sending character by character using Selenium Webdriver (in Java). This way in the back-end, I verify at each letter press if the character exists in the input. Normal element.sendKeys() is not working well for me 2 out of 5 times - the last letter is missing, I guess something is buggy with Selenium Webdriver, I don't know. Try the code below, it works 100% of the time for me.
public void TypeInField(String xpath, String value){
String val = value;
WebElement element = driver.findElement(By.xpath(xpath));
element.clear();
for (int i = 0; i < val.length(); i++){
char c = val.charAt(i);
String s = new StringBuilder().append(c).toString();
element.sendKeys(s);
}
}
As you see, I get the value needed to be typed and in the for loop, I take each character, convert it to string and send it to textbox. Also, I have a search for xpath, you can change that to id, or classname, or whatever you want.
If you want to make your sendKeys more human like, I've used something like this:
private static void sendHumanKeys(WebElement element, String text) {
Random r = new Random();
for(int i = 0; i < text.length(); i++) {
try {
Thread.sleep((int)(r.nextGaussian() * 15 + 100));
} catch(InterruptedException e) {}
String s = new StringBuilder().append(text.charAt(i)).toString();
element.sendKeys(s);
}
}
It sends the keys with a 100ms delay, but only an average of 100ms. It creates a normal distribution with average 100ms and std. deviation 15ms.
sendKeys() does enter characters in sequence, but it can at times run quickly enough to be perceived as a copy/paste action. Though, it is in fact intended to simulate a user entering text by typing. Per the sendKeys() JavaDoc:
/** Use this method to simulate typing into an element, which may set its value. */
If you wanted to slow it down, you could make a method that accepts WebElement and String args, convert the String to charsequence[], then use a for loop and enter each index of the array in the .sendKeys() followed by a Thread.sleep(). This seems horribly inefficient, though, as sendKeys() recognizes Strings as charsequence[] (String is a charsequence[] in Java). Adding the Thread.sleep() will only slow your test needlessly.
Honestly, sendKeys() fits your described needs. It's the best way to simulate a user at a keyboard, it just does it really fast.
.chord() will press all keys simultaneously. Not very well suited for field input.
The .sendKeys() method will accept a String. Simply pass your input as such and have a go with it.
driver.findElement(By.id("element")).sendKeys("Field Input Text");
I created a Python function of the Java Selenium code.
Find attached below and tweak based on the elements you want to use:
def TypeInField(xpath, myValue):
val = myValue
elem = driver.find_element_by_xpath(xpath)
c = ""
for i in range(0, len(val)):
c += val[i]
elem.send_keys(c)
time.sleep(3)
elem.send_keys(Keys.ENTER)
I use this function in my test when I want to type a string letter by letter.
public void typeOnLetterByLetter(WebElement webElement, String value, long waitBetweenLetters, ChronoUnit unitTime) {
clear(webElement);
Arrays.asList(value.toCharArray()).forEach(letter -> {
typeOn(webElement, String.valueOf(letter));
pause(waitBetweenLetters, unitTime);
});
}
private void pause(long time, ChronoUnit unitTime) {
try {
Thread.sleep(Duration.of(time, unitTime).toMillis());
} catch (InterruptedException ignore) {
}
}
Here is how I did it in C#
public void TypeInFieldCharByChar(IWebElement element,string text)
{
var strBuilder = new StringBuilder();
for (int i = 0; i < text.Length; i++)
{
Thread.Sleep(100);
strBuilder.Append(text[i]);
element.SendKeys(strBuilder.ToString());
strBuilder.Clear();
}
}
I have an issue with windowlicker on OS X ( everything works ok on Windows ).
The issue is that when I try to simulate user input to any text field the data is not inserted properly ( some letters are cut out ).
For instance:
JTextFieldDriver txField = new JTextFieldDriver(this,
JTextField.class,
named(fieldName));
txField.focusWithMouse();
txField.typeText(input);
Preceding code will result in that I will observe windowlicker inserting input to a text field named fieldName and the input will be incomplete ( Peter will be Peer or Fred will be Fre and so on ). Everything works properly on windows.
I am not sure if all that has anything to do with a warning. I get similar on windows. The warning is:
"WARNING: could not load keyboard layout Mac-, using fallback layout with reduced capabilities (JAR entry com/objogate/wl/keyboard/Mac- not found in /Users/odo/.m2/repository/com/googlecode/windowlicker/windowlicker-core/r268/windowlicker-core-r268.jar)"
Windowlicker seems not to be very popular tool. Nevertheless I managed to figure out the root cause. The warning stating that keyboard layout can't be set is displayed because I am not using english locale. It looks like windowlicker supports only Mac-GB keyboard layout.
The warning will go away if an appropriate system property is set.
For instance:
System.setProperty("com.objogate.wl.keyboard", "Mac-GB");
However this will not solve the main problem. After couple trials I figured out that only 'a' and 'd' characters are trimmed. This is because windowlicker inserts them as if user would hold the 'a' or 'd' key for a bit. Holding those keys results in a helper menu invocation which allows to select special characters. In order to fix that I played with the JTextComponentDriver and found a workaround. The solution is not to use driver's typeText to insert text. JTextComponentDriver's component() method can be used to retrieve the actual guy component and then having an instance setText() can be invoked to set the text.
Below I present my helper class which is using described solution:
public class TextTyper {
private final String inputText;
privte TextTyper(String inputText) {
this.inputText = inputText;
}
public static TextTyper typeText( final String inputText ){
return new TextTyper( inputText );
}
public void into( JTextComponentDriver<?> driver ) throws Exception{
driver.focusWithMouse();
driver.clearText();
Component cmp = driver.component().component();
if(cmp instanceof JPasswordField ){
JPasswordField pwField = (JPasswordField) cmp;
pwField.setText(this.inputText);
}
else if( cmp instanceof JTextField){
JTextField txField = (JTextField) cmp;
txField.setText(this.inputText);
}
else
throw new Exception("Component is not an instance of JTextField or JPasswordField");
}
}
I am new to java and android development and I am working on an application that takes input from the user through an EditText. However, sometimes the input data has some characters with an encoding that is different from what the app expects.
I have created a hashmap with all the possible mapping (about 460 elements) and whenever the user types in (or paste) something I use the afterTextChanged method to go through the text and swap the ones that matches the incorrect encoding with the correct ones that displays correctly.
My code works fine for small sized entry, however the longer it is the slower it gets because afterTextChanged will be called recursively after every swap I do. And when pasting a text that has about 30+ characters with incorrect encoding the application will crash.
here is my code:
public void afterTextChanged(Editable editable) {
substituteText(editable);
}
public CharSequence substituteText(Editable txt) {
if (txt.length() == 0) {
return txt;
}
for (int i = 0; i < txt.length(); i++) {
char ch = txt.charAt(i);
CharSequence ret = myHashMap.get(ch);
if (ret != null) {
txt.replace(i, i + 1, ret);
}
}
return txt;
}
I thought about cloning "editable" to some, change it and then copy it back to the edittext editable variable so it will only see it as one change but I failed to do it since I couldn't find an easy way to clone it.
Is there a more efficient way to do this?
If you use onTextChanged instead of afterTextChanged, you'll get passed the new character(s) the user typed and where they are, and you'd only need to check those.
I use Selenium Webdriver with Java and I've found a problem. When I try to send some text to the textfield, it only sends first char of two. I tried setting it with JavaScriptExecutor, but same thing happened. ChromeDriver is running and working fine. Code below:
public void sendNumberToChrome (int number){
textfield.clear(); // textfield is already set, it's classic input field with max. 10 characters
System.out.println(String.valueOf(number)); // This prints for example 94
textfield.sendKeys(String.valueOf(number)); // But only "9" appears in the browser
}
I also tried to send it character by character:
String[] arr = String.valueOf(number).split("(?<!^)"); // splits number character by character
for (String s : arr){
System.out.println(s); // Prints 9 and then 4
textfield.sendKeys(s); // Also only 9 appears
Thread.sleep(100); // Maybe browser can not work too fast, so I will wait before sending next character
}
JavascriptExecutor also send only one character and every few minutes crashes (don't know why), so I am not using it.
But what is interesting - when I do this:
textfield.sendKeys(String.valueOf(94));
It sends 94 to Chrome! I don't know where the problem is, can someone help me?
EDIT: Chrome version: 29.0.1547.76 m, Selenium Server Standalone 2.35.0, Chromedriver v2.3
Javascript on the page is messing with your input
try this code
static boolean sendKeyIntoElement(WebElement webElement, String value){
webElement.click();
webElement.sendKeys(value);
while(!webElement.getAttribute("value").equals(value)){
webElement.click();
webElement.sendKeys(Keys.CONTROL + "a");
webElement.sendKeys(Keys.DELETE);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return webElement.getAttribute("value").equals(value);
}
Hi I would like to count how many times a text Ex: "VIM LIQUID MARATHI" appears on a page using selenium webdriver(java). Please help.
I have used the following to check if a text appears in the page using the following in the main class
assertEquals(true,isTextPresent("VIM LIQUID MARATHI"));
and a function to return a boolean
protected boolean isTextPresent(String text){
try{
boolean b = driver.getPageSource().contains(text);
System.out.println(b);
return b;
}
catch(Exception e){
return false;
}
}
... but do not know how to count the number of occurrences...
The problem with using getPageSource(), is there could be id's, classnames, or other parts of the code which match your String, but those don't actually appear on the page. I suggest just using getText() on the body element, which will only return the page's content, and not HTML. If I'm understanding your question correctly, I think that is more what you are looking for.
// get the text of the body element
WebElement body = driver.findElement(By.tagName("body"));
String bodyText = body.getText();
// count occurrences of the string
int count = 0;
// search for the String within the text
while (bodyText.contains("VIM LIQUID MARATHI")){
// when match is found, increment the count
count++;
// continue searching from where you left off
bodyText = bodyText.substring(bodyText.indexOf("VIM LIQUID MARATHI") + "VIM LIQUID MARATHI".length());
}
System.out.println(count);
The variable count contains the number of occurrences.
There are two different ways to do this:
int size = driver.findElements(By.xpath("//*[text()='text to match']")).size();
This will tell the driver to find all of the elements that have the text, and then output the size.
The second way is to search the HTML, like you said.
int size = driver.getPageSource().split("text to match").length-1;
This will get the page source, the split the string whenever it finds the match, then counts the number of splits it made.
You can try to execute javascript expression using webdriver:
((JavascriptExecutor)driver).executeScript("yourScript();");
If you are using jQuery on your page you can use jQuery's selectors:
((JavascriptExecutor)driver).executeScript("return jQuery([proper selector]).size()");
[proper selector] - this should be selector that will match text you are searching for.
Try
int size = driver.findElements(By.partialLinkText("VIM MARATHI")).size();