how to instantly set/send_keys a textarea in capybara - selenium

I need to instantly fill a textarea with a very long string for testing purposes.
set/send_keys simulates typing and is too slow for Sauce Labs causing time outs.
Is there a way to instantly fill a textarea in Capybara?

The only way to instantly do it would be using execute_script to set the value via JS
element = find('textarea') # however you locate the element
execute_script('arguments[0].value = arguments[1]', element, text_to_set)
Note: this won't trigger all the events a user would generate when inputting into the textarea

TL;DR: Use Javascript/JQuery (.val() function) to set the field's value via the .execute_script()/.evaluate_script() function. It will automatically send the full string. You have more details bellow.
Example:
def execute_script(script)
browser.execute(function() {
$('<yourSelectorHere>').val("blablabla");
})
nil
end
Selenium team decided a LOOOONG way back to make it work this way, because it will actually simulate the real way a user would fill that input/textarea/field/etc.
Note: I wrote the command in WebdriverIO, but now have updated to Capybara as well.
Indeed, using the .setValue()/.set(), or the .keys()/.send_keys() methods will issue a POST action on the target element (presumably an <input>) in the form of an array of characters. See example:
Command: browser.setValue('input[connectqa-input="rename-device"]','stackoverflowstackoverflowstack');
Output:
> browser.setValue('input[connectqa-input="rename-device"]','stackoverflowstackoverflowstack')
{ state: 'pending' }
> [21:52:25] COMMAND POST "/wd/hub/session/3d830ffd-21c6-4e5f-a6b3-4f8a03821991/elements"
[21:52:25] DATA {"using":"css selector","value":"input[connectqa-input=\"rename-device\"]"}
[21:52:25] RESULT [{"ELEMENT":"6"}]
[21:52:25] COMMAND POST "/wd/hub/session/3d830ffd-21c6-4e5f-a6b3-4f8a03821991/element/6/clear"
[21:52:25] DATA {}
[21:52:25] COMMAND POST "/wd/hub/session/3d830ffd-21c6-4e5f-a6b3-4f8a03821991/element/6/value"
[21:52:25] DATA {"value":["s","t","a","c","k","o","v","e","r","f","(21 more items)"],"text":"stackoverflowstackoverflowstack"}
One quick and easy way to escape this is to go ahead and abuse the .val() JQuery function via the .execute()/.executeScript() methods:
Command: browser.execute(function() { $('input[connectqa-input="rename-device"]').val("dwadawdawdawdawdawdwadawawdadawdawdaw"); }) (WebdriverIO)
For Capybara syntax, see this question. It covers both .execute_script() & .evaluate_script(). (I don't want to mooch-off their views). Also you should document on the methods before-hand here.
Output:
> [21:59:38] COMMAND POST "/wd/hub/session/3d830ffd-21c6-4e5f-a6b3-4f8a03821991/execute"
[21:59:38] DATA {"script":"return (function () { $('input[connectqa-input=\"rename-device\"]').val(\"dwadawdawdawdawdawdwadawawdadawdawdaw\"); }).apply(null, arguments)","args":[]}
Hope it helped!

Related

How to test window scroll event with vue-testing-library?

I want to trigger user interaction for window scroll to change the isScrolled data so that the div class can change. Right now I just test the component when the isScrolled data is changed. Is this the right way to test?
This is acceptable way to test. However, instead of directly setting the isScrolled to true, call the method using the vm as (ensure that you have mocked the document.documentElement.topScroll to something other than zero):
wrapper.vm.onScrollHandler();
Finally, if you need to really test for scroll event, you can manually fire one using the dispatchEvent() method as following:
window.dispatchEvent(new CustomEvent('scroll', { detail: 'anything' }));
You use this and then run your assertion.
On a side note, instead of pictures of your code, paste actual snippets so that they are easy to copy and paste. And, you onScrollHandler can be shortened to:
onScrollHandler() {
this.isScrolled = document.documentElement.topScroll > 0;
}

How to input the value of a hidden field into a textbox with Test Cafe Studio?

I am attempting to input the value of a hidden field into a textbox in Testcafe, ideally in some sort of manner that simulates typing. Is there a way to do that? Every time I try to do it via javascript it just throws a javascript error.
Essentially I am testing a pretty standard web app - I fill out a form, go page to page, and then must type in a value that is kept in a hidden html input field on the page. I honestly have no idea where to start - every time I've tried to do this with javascript via the "Run Test Cafe Script" it has thrown a javascript error - I really don't know where to start if javascript can't be used.
TestCafe cannot type text in a zero-size input element. I suggest you try the Run TestCafe Script action with ClientFunction that puts a value to the input element directly:
const setValue = ClientFunction(() => {
document.querySelector('input[type="hidden"]').value = 'John Smith';
});
await setValue();

Protractor sendKeys issue with scripted input fields

I'm automating e2e tests with Protractor on an angular app.
However, I have an issue when sending keys on input fields.
The sendKeys would miss few characters everytime so I found a workaround :
static sendKeys(value, element){
value.split('').forEach((c) => element.sendKeys(c));
}
This works well but it takes more than 3 times the time the original sendKeys function would.
Well no problem my tests are still functionnal right ?
My app now has new fields with scripts behind them.
One of them is a datepicker input, you can either choose from the datePicker or type it manually. However, for today's date you would type 09022018 and the slashes are automatically appended at the right place (like so 09/02/2018). If you were to enter a wrong date the field is cleared.
Now back to the problem : it seems that both my implementation of sendKeys and the original one loose focus after each submitted key. This means that I can't enter a valid date in the input field as it's cleared after each simulated keypress.
I could use browser.executeScript to fix it but I wouldn't be able to test the functionnality adding slashes. Also, as you type, the datepicker is still open and refreshes after each keypress, you can select a date from it at any time and that is also a feature I want to test.
Thanks in advance
Use executeScript to set the date in backgrond, then use sendKeys to enter a space or Tab at the end to trigger the Keyborad event which will check the input and format the input with slash
function enterDate(date) {
var script = 'arguments[0].value=arguments[1]';
// input box for date
var dateBox = element(by.xxx(yyy));
browser.executeScript(script, dateBox, date);
dateBox.sendKeys(" ");
// or try send Tab
dateBox.sendKeys(protractor.Key.TAB);
}
enterDate('09022018');
You can try this solution on other fields you fixed but take 3 more time.

Copy-paste using Capybara?

I would love to do something like this:
div = find '#some-div'
copy_to_clipboard(div)
input = find '#my-input'
paste_from_clipboard(input)
I do not want to simulate this with send_keys and using Ctrl+C and Ctrl+V; I want this to work cross-browser (especially on mobile).
Does this API exist?
The most simple way I've found:
element.send_keys [:control, 'c']
element.send_keys [:control, 'v']
There is no Capybara copy/paste API - If all you want to do is copy the visible text into an input then you could do
div_text = find('#some-div').text()
find('#my-input').set(div_text)
If that's not correct for what you want, then you could use #execute_script to create a selection range like
var range = document.createRange();
range.setStart( <start node>, <start node character offset> );
range.setEnd( <end node>, <end node character offset> );
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
then find your target element and set it's value to window.getSelection().toString(). Note that's not really emulating what a user would do, so if you are actually using this for testing an app I would still recommend using the ctrl/cmd-c/v after setting the selection range for browsers that support it since it emulates user behavior better.
It's an old one, however you don't need to use capybara however the workaround would to use this incredibly simple gem:
https://github.com/janlelis/clipboard
There is no API to do it.
You can get element from one browser
div = page.find('#some-div')
Then you can pass it to another browser
fill_in '#some-other-div' with => div
You can read more about capybara here: https://github.com/jnicklas/capybara

web2py SQLFORM accepting too fast

I have a web2py SQLFORM that gets generated and returned by an AJAX call and the form is put in a DIV I defined.. I want that SQLFORM to be an update form, not an insert form. The problem is the form immediately runs it's accept function once it is written to that DIV. This doesn't happen if the form is for inserting, only updating. That initial accept fails and hitting the submit button does not allow for a second accept.
I don't know why the accept fails or why it happens immediately.
heres the JavaScript function that makes the AJAX call
function displayForm(currID){
//Remove everything from the DIV we want to use
$('#window').empty();
//Call the ajax to bring down the form to update the series
ajax('{{=URL('newForm')}}/'+currID,
[], 'window');
}
And here is the newForm controller
def newSerForm():
record = db.myTable(request.args[0])
form = SQLFORM(db.myTable, record, fields=['series_name','image_thumbnail'])
if form.accepts(request.vars,session):
print 'Series update successful!'
else:
print 'Series update Failed...'
return form
displayForm is fired by clicking a button and once you do the form accepts and fails and the submit button doesn't work again. Is there a way to make an SQLFORM do this? The weird thing is if I change this to make inserts into myTable, it works fine. It behaves exactly as it should. But doing it this way doesn't work.
Ok now this is where it gets weird.
I tried to achieve the same functionality here with a totally different approach, an iFrame. I made new functions in my controllers that create the form based on request.args[0]. looks like this
def editEntry():
print request.args[0]
record = db.myTable(request.args[0])
form = SQLFORM(db.CC_user_submission, record, fields=['series_name', 'image_thumbnail']).process()
return dict(form=form)
And then a corresponding HTML page that just displays form. What could be simpler right? I go to that page based on a link that gives the correct argument. Take me to a page with a form for updating. Updating works perfect. Great, now lets put it in an iFrame instead of linking to it. I put it in an iFrame on the original page. Open up the iFrame. Doesn't work. I have no idea what is going is there any part of an explanation to this?
By using the iFrame method I actually got this one to work. Since it required an iFrame to be appended with jQuery which needs quotes and the iFrame URL which also needs quotes, the notation got pretty confusing but it's doable. Looked like this:
var myURL = "{{=URL('editEntry')}}/"+idArg.toString();
$('#window').append("<iframe src = " + myURL + " width='450' height='400'> </iframe>");
It's not pretty but it works.