The webdriverIO docs say that the browser.keys command works like the sendKeys command, but it doesn't implicitly release the keys.
http://webdriver.io/api/protocol/keys.html
How are the keys released?
I tried writing code to navigate backwards through a form using the keyboard:
browser.keys(['Shift', 'Tab']);
But in the next input box it types into, the text is capitalized. It's like the shift key is still held down.
I think I figured it out. I just had to send the key twice like this
browser.keys(['Shift', 'Tab', 'Tab', 'Shift']);
I think webdriver must treat the first Shift like a keydown, and the second Shift like a key up.
So the sequence above would be the full keysDown/keysUp sequence to do a backwards form navigation using the keyboard.
Why do you not use .click for clicking on the form you want? It´s much easier to work with css selector than simulating key press.
Alternative you can also do stuff like this
.click('a[href*="contact"]')
Works also with placeholder and other stuff if you can´t find an unique id or class.
// .moveToObject(selector,xoffset,yoffset);
.moveToObject('#button', 0, -103)
.buttonDown()
.moveToObject('#button', 0, -104)
.buttonUp()
However this is what I use to press down mouse button and then release it, if you have no chance to find the right css selector to click on. You can make rightclick of webdriver io to see at which position you at and then you can create this workaround click anywhere without css selector.
Related
I'm trying to test a WebView using Espresso. The WebView contains some input fields and a button to continue to the next page. I am able to enter the text in the input fields. After leaving the input field a blur event should get called that performs some additional formatting and validation. However the blur event never gets called and therefore I cannot continue to the next page.
It looks like webKeys() is just injecting some text and that webClick() simply triggers a click event. That's probably why focus never changes and the blur event never gets called. When I physically press the input field myself the event does get triggered and I also see the Android input cursor. When the test case is running I don't see the cursor when text is entered in the input fields.
Is there a way to trigger the blur event programmatically or set focus to an element within the WebView using Espresso?
This is the code I'm using for inserting text.
public static void insertText(String label, String content)
{
onWebView().withElement(findElement(Locator.XPATH, "//div[preceding::span[.='" + label + "']]/input")).perform(clearElement()).perform(webClick())
.perform(webKeys(content));
}
Edit: Added relevant dependencies.
implementation "androidx.test.espresso:espresso-idling-resource:3.2.0"
androidTestImplementation "androidx.test.espresso:espresso-core:3.2.0"
androidTestImplementation "androidx.test.espresso:espresso-intents:3.2.0"
androidTestImplementation "androidx.test.espresso:espresso-web:3.2.0"
androidTestImplementation "androidx.test.espresso:espresso-contrib:3.2.0"
You can send any javascript to your Web view.
Every "atom" (webKeys is one of atoms) is just some javascript code, which is sent to your Web View. webKeys atom probably sends keypress events, which does not fire focus/blur/change events in browsers. This is sort of standard browsers behaviour for userspace code dispatched events.
As you can manually trigger keypress, you can trigger focus too etc. You can create and dispatch focus by using:
onWebView().withElement(...)
.perform(SimpleAtom("function(elem) {\n" +
"var e = document.createEvent('Event');\n" +
"e.initEvent('focus', true, true);\n" +
"elem.dispatchEvent(e);}"
))
This should set focus to given element. You are sending function, which is then invocated with yours element as first argument.
You should create some classes like SetFocusAtom or RemoveFocusAtom etc. which will extend SimpleAtom instead of copy&paste whole javascript everywhere.
Be aware:
You can send any javascript to WebView, but you probably don't want. You're free to edit values of currently invisible inputs etc. You're writing UI test, so you could test only visible parts of UI. Original atoms (webClick, webKeys etc.) are checking items for actual visibility. You should everytime use some of original atom or at least match for visibility.
You can do only what is possible in userspace Javascript. There are some limitations. Like current question for example. In projects with complex WebViews, you should consider using UIAutomator or some implementation of Selenium (using chromedriver). Espresso-web is not "acting as real user would". This is not achievable by javascript injections only. Chromedriver is much powerfull in user-like acting.
My answer is not generic. Sometimes you don't need to set focus/blur on inputs. Sometimes you want to send change event for example, which is also not triggered by webKeys.
I'm reading through this section of the guide. I'm testing the complex component in the tutorial.
What I'm not understanding is why these two lines exist together, I believe only the first one should.
fillIn('.list-filter input', 'Seattle');
keyEvent('.list-filter input', 'keyup', 69);
In the first line, we fill in the input field which should automatically trigger a filtering of the results. Why are we adding an extra e to the field (keycode 69)? It's like we're going to search Seattlee (note the two e's at the end). Is the keyEvent method necessary to activate the triggering of the refresh but it actually doesn't print to the input field?
I suppose the keyup event doesn't enter a char. It simply does for its name stands for: fires the key up event. You can press a char on the keyboard and see, that the char is being added before you release the key. I'm sure this is specified somewhere, but I don't know this. My reason is the common sense.
So in order to trigger some functionality in that example, one needs not only to fill the field, but to fire a specific event, to which a js-handler is bound
Problem:
I have many drop downs with dynamic changes going on at all times. The problem is I am having to use the blur() method to disable focus so that the class depending on the selected value can be applied.
Is there a way I can set the focus onto the next drop down element.
Tried:
Instead of blur(), I have tried this but it did not work.
this.next(".Element").focus();
Current code:
$('.Element').change(function () {
var colour = $(this).find('option:selected').attr('class');
$(this).removeClass().addClass(colour);
this.blur();
}).change
JS Fiddle:
jsfiddle of my code
try to make this a jQuery object to focus another element
$(this).next(".keyTechElement").focus();
EDIT 1:
Seeing your DOM, changes is needed. The .next() function selects siblings in the DOM and inside <td> there is no .Element sibling.
$(this).blur();
$(this).closest('td').next("td").find(".Element").focus();
http://jsfiddle.net/UXJZ7/2/
I think manipulating focus with focus() or blur() is terrible for keyboard users.
Users also detest auto-tabbing on forms they rarely use.
Onchange doesn't mean a selection has been made, a user could be stepping through the options with the keyboard (or with assistive technology that simulates the keyboard like speech recognition software), you get an onchange event for every step in their selection.
You can get quite elaborate to work around this, but it's rarely worth the effort.
For your example, I'd just leave things like this: http://jsfiddle.net/KWvMZ/ It looks like the only reason you have a focus state in your style is to display the text with sufficient contrast, so I just set the yellow background to have black text when focussed and left it like that.
.
is it possible to show/hid a div on a webpage if say three keys are pressed in the correct order on a normal keyboard....
Im trying to hide my login div in drupal and only want it to show if I press say three keys on the keyboard. Dosnt matter if it shows up in source.
any thoughts/links?
cheers
You can try js-hotkeys.
jQuery.Hotkeys plugin lets you easily add and remove handlers for keyboard events anywhere in your code supporting almost any key combination. It takes one line of code to bind/unbind a hot key combination.
Example: Binding 'Ctrl+c'
$(document).bind('keydown', 'ctrl+c', fn);
Next step is to show/hide your div in the function you pass in.
You have to intercept the keypress event (or keyup) and then check which key was pressed (see jQuery Event Keypress: Which key was pressed?)
To handle a key sequence you have to store the pressed key codes into an array and then check it against your defined sequence.
This "cheat code" jQuery plugin should make what you're asking especially simple.
If you poll for key presses and store them in array then match that with the correct array once this happens show the div then clear your stored array. Close the div and start the process again.
I'd like to have the browser act as if the user had pressed the Tab key when they click on something. In the click handler I've tried the following approaches:
var event = document.createEvent('KeyboardEvent');
event.initKeyEvent("keypress", true, true, null, false, false, false, false, 9, 0);
this.input.focus()[0].dispatchEvent(event);
And jQuery:
this.input.focus().trigger({ type : 'keypress', which : 9 });
...which I took from here.
The first approach seems to be the best bet, but doesn't quite work. If I change the last two parameters to 98, 98, indeed, a 'b' is typed into the input box. But 9, 0 and 9, 9 (the former of which I took right from the MDC web site) both give me these errors in firebug under FF3:
Permission denied to get property XULElement.popupOpen
[Break on this error] this.input.focus()[0].dispatchEvent(event);
Permission denied to get property XULElement.overrideValue
[Break on this error] this.input.focus()[0].dispatchEvent(event);
Permission denied to get property XULElement.selectedIndex
[Break on this error] this.input.focus()[0].dispatchEvent(event);
Permission denied to set property XULElement.selectedIndex
[Break on this error] this.input.focus()[0].dispatchEvent(event);
I've heard such (with no clear definition of 'such') events are 'untrusted', which might explain these errors.
The second approach causes whatever value I put as event.which to be passed as event.which, but to no effect (even if I use 98 instead of 9, no 'b' is typed in the box.) If I try setting event.data in the object I'm passing, it ends up undefined when the event is triggered. What follows is the code I'm using to view that:
$('#hi').keypress(function(e) {
console.log(e);
});
Any other ideas?
The solution I ended up going with is to create a "focus stealer" div (with tabindex = -1--can have the focus but can't be tabbed to initially) on either side of the area in which I want to manually manage the focus. Then I put a bubbling-true event listener for focus and blur on the whole area. When any focus occurs on the area, the tabindex values are changed to -1, and when any blur occurs, they're changed to 0. This means that while focused in the area, you can tab or shift-tab out of it and correctly end up on other page elements or browser UI elements, but as soon as you focus out of there, the focus stealers become tabbable, and on focus they set up the manual area correctly and shunt the focus over to the element at their end, as if you had clicked on one end or the other of the manual area.
This is the solution I used on our webapp for two custom controls, a pop-up calendar and a pop-up unit / value weight selector (clicking the text box pops up a div with two selects)
function tab_focus(elem)
var fields = elem.form.getElements()
for(var i=0;i<fields.length;i++) {
if(fields[i].id == elem.id){
for(i=i+1;i<fields.length;i++){
if(fields[i].type != 'hidden'){
fields[i].focus()
return
}
}
break;
}
}
elem.form.focusFirstElement();
}
This is using the Prototype framework and expects an extended element(ie $('thing_id')) as its parameter.
It gets the form the element belongs to, and loops through the elements of the form until it finds itself.
It then looks for the first element after it that is not hidden, and passes it the focus.
If there are no elements after it in the form, it moves the focus back the to first element in the form. I could instead find the next form on the page through document.forms, but most of our pages use a single form.
Actually, I guess there is a way, even if it's a major PITA. I can make sure that every element, even if naturally a tab-stop, has an Xtabindex, somehow in the proper order even though I'll be dropping in other people's widgets and so using jQuery to add these after the fact, rather than being able to specify it right in the HTML or other initial building code. Then, my entire form will have a real tabindex. While it has the focus, it will absorb keypresses, and if they're tab or shift+tab, move the fake focus based on Xtabindex. If tab is pressed on the last (or shift+tab on the first) element in the form, it won't gobble the keystroke, thus allowing the browser to properly focus on other page or browser UI elements outside the form using the keyboard.
I can only guess what kinds of unintended side-effects this approach will introduce.
Actually, it's not even a solution, because I still can't fake a tab on the last element using it.
I created a simple jQuery plugin which does solve this problem. It uses the ':tabbable' selector of jQuery UI to find the next 'tabbable' element and selects it.
Example usage:
// Simulate tab key when element is clicked
$('.myElement').bind('click', function(event){
$.tabNext();
return false;
});
I think those errors are from autocomplete. You might be able to turn them off by setting, before you dispatch the event, the autocomplete attribute to 'off'
setAttribute('autocomplete','off')