Is it possible to use two objects: Force and Multiple in Cypress Test? - automation

I am using cypress test to check all the buttons in the page whether they can be clicked or not.
I have used this line of code:
cy.get('button').click({ force: true }).should('have.attr', 'href')
and gives error
CypressError: cy.click() can only be called on a single element. Your
subject contained 5 elements. Pass { multiple: true } if you want to
serially click each element.
After that changed code with:
cy.get('button').click({ multiple: true }).should('have.attr', 'href')
and got another error
CypressError: Timed out retrying: cy.click() failed because this
element is not visible:
...
This element
''
is not visible because it has CSS property: 'display: none'
Fix this problem, or use {force: true} to disable error checking.
https://on.cypress.io/element-cannot-be-interacted-with
Is there any way to use both object to solve the problem?

This should work (I don't have a situation to test it when both needed, but it doesn't result in an error):
cy.get('button')
.click({ multiple: true, force: true })
.should('have.attr', 'href')

Here is a generic way of doing it -
cy.get('button').each(($btn) => {
if ($btn.hasClass('disabled')) {
// logic to deal with disabled button
}
else {
// click button or do whatever
cy.wrap($btn).should('have.attr', 'href').click();
}
})
each will help you loop through every button, whatever may be the count. This allows you to not worry about force clicking an element (button in this case).

Related

Global variable is undefined if assign variable in the TargetConnected method in stimulus.js

This is the location controller file that is going to access by the html code.
export default class extends Controller {
static targets = [ "visible", "map" ]
mapTargetConnected(element) {
this.name = "aaa"
}
add(event) {
console.log(this.name) // this line is logged that variable is undefined.
}
}
here is the HTML code
<%= form_with(model: #location, local: false, url: location_path(), data: {controller: 'location', action: 'ajax:beforeSend->location#add'}) do |form| %>
....
<% end %>
This is the code regarding form submit via ajax request. if i access the this.name variable inside the add method or click event its says the variable is undefined… but if i same name variable assign it in connect() method than it’s working…
but i want to assign variable at targetConnected method and use it in the add action method.Please suggest any solution or let me know if i'm doing wrong.
Most likely the add event is being triggered before the mapTargetConnected has run.
Stimulus will go through the DOM and match elements and their targets and then trigger the relevant someTargetConnected and connect lifecycle methods once the controller is set up.
However, this is not instant and there may be some nuance to how the timing works when you are working with other events.
You will need to work out when the actual map target is being added to the DOM and possibly do some logging to check that timing compared to when the ajax:beforeSend event triggers.
Sometimes, adding a setTimeout can assist as it will ensure that the code provided to it runs 'last' (there is some nuance to this, technically it is the next event cycle).
For example
add(event) {
// here the mapTargetConnected may not have run
setTimeout(() => {
// by this point, mapTargetConnected has hopefully now run
console.log(this.name);
});
}
It is hard to offer more help without a bit more specifics on what ajax:beforeSend is and when it triggers, along with what actually adds the map target to the DOM. It may be more helpful to write this question with the initially rendered HTML output (with the minimum parts to help guide the question).
In general, it is good to remember that in the browser, things do not happen instantly, while they may be fast there can be timing issues to be aware of.

Capybara, Poltergeist, PhantomJS, evaluate_script, callback

I am using the following code, which uses the imagesLoaded package with a callback to tell me when an element with a particular csspath has finished loading all of its images:
imagesLoadedScript = "imagesLoaded( '#{csspath}', { background: true }, function(message) { console.log('PHANTOM CLIENT REPORTING: #{csspath} Images Loaded'); return message; })"
imagesLoadedScript = imagesLoadedScript.strip.gsub(/\s+/,' ')
#session.evaluate_script(imagesLoadedScript)
The timing of the console.log statement, on inspection of PhantomJS logs with debug on, indicates that Capybara/Poltergiest is not waiting for the images to load, as expected, before it moves on to the next statement. I also cannot return a true (or false) value from inside the callback as I would like.
Capybara responds with
{"command_id":"678f1e2e-4820-4631-8cd6-413ce6f4b66f","response":"(cyclic structure)"}
Anyone have any ideas on how to return a value from inside a callback in a function executed via evaluate_script?
Many thanks.
TLDR; You can't
evaluate_script doesn't support asynchronous functions - you must return the result you want from the function passed in. One way to do what you want would be to execute the imagesLoaded script and have the callback set a global variable, and then loop on an evaluate_script fetching the result of the global until it's what you want - A very basic implementation would be something like
imagesLoadedScript = "window.allImagesLoaded = false; imagesLoaded( '#{csspath}', { background: true }, function() { window.my_images_loaded = true })"
#session.execute_script(imagesLoadedScript)
while !#session.evaluate_script('window.allImagesLoaded')
sleep 0.05
end
Obviously this could be made more flexible with a timeout ability, etc.
A second option would to write a custom capybara selector type for images with a loaded filter, although with the need for background image checking it would become pretty complicated and probably too slow to be useful.
Just in case someone finds this later.
I did roughly what Thomas Walpole suggested in his answer, in a more roundabout fashion, but taking advantage of Poltergeist's inherent waiting capabilities;
#to check that the target has loaded its images, run images loaded
#after a small timeout to allow the page to get the images
#append a marker div to the dom if the images have successfully loaded
imagesLoadedScript = "var item = document.querySelector('#{csspath}');
window.scroll(0, item.offsetTop);
function imagesDone(path, fn) {
imagesLoaded( path, function(instance) {
console.log('PHANTOM CLIENT REPORTING: ' + path + ' Images Loaded');
fn(true);
})
}
setTimeout(function(){
imagesDone('#{csspath}', function(done) {
var markerDiv = document.createElement('div');
markerDiv.id = 'ImagesLoadedMarker';
document.getElementsByTagName('html')[0].appendChild(markerDiv);
});
}, 1000)"
#then we strip the new lines and spaces that we added to make it readable
imagesLoadedScript = imagesLoadedScript.strip.gsub(/\s+/,' ')
#now we just execute the script as we do not need a return value
#session.execute_script(imagesLoadedScript)
#then we check for the marker, using capybara's inbuilt waiting time
if #session.has_xpath? "//*[#id ='ImagesLoadedMarker']"
Rails.logger.debug "!!!!! PhantomClient: Images Loaded Reporting: #{csspath} Images Loaded: Check Time #{Time.now} !!!!!"
#session.save_screenshot(file_path, :selector => csspath)
else
Rails.logger.debug "!!!!! PhantomClient: Images Loaded Reporting: #{csspath} Images NOT Loaded: Check Time #{Time.now} !!!!!"
#session.save_screenshot(file_path, :selector => csspath)
end

protractor + cucumber - element not visible even though element is visible

this.When(/^the user clicks on login button$/, function () {
return browser.wait(wagLoginPage.loginPage.signIn.isPresent().then(function (visible) {
if(visible){
console.log("element is visible !!!!!!!");
wagLoginPage.loginPage.signIn.click().then(function(){
expect(visible).to.be.true;
});
}
else{
expect(visible).to.be.true;
}
}, function () { chai.assert.isFalse(true, "SingIn is not visible!") }));
});
My test randomly fails in the above step. For the above code, in console window protractor prints 'element is visible'. But if I perform click event on the element it throws element is not visible exception.
Update
Questions is answered here
Your element is present, but it's probably not visible.
Try this:
return browser.wait(wagLoginPage.loginPage.signIn.isDisplayed().then(function (visible){
//Your stuff
}
Note, I'm using isDisplayed() vs. isPresent().
isPresent() is useful if you are checking if an element is on the page, but may or may not be visible.
isDisplayed() is useful if you are checking if an element is visible on the page.

FileUploadField 'stuck' after submitting form with ExtJS4/DWR

im using extjs4 with dwr3 to upload a file
this is all i have in my form
{xtype: 'fileuploadfield',
name: 'file',
fieldLabel: 'Archivo',
allowBlank: false,
buttonText: 'Seleccionar...'
}, {
xtype: 'button',
text: 'Cargar',
action: 'cargarArchivo'
}
when i click the button (labeled Cargar) it submits the file and stays in the same page, so far so good. Problem is, when i choose another file, the text in the field stays the same instead of showing the new file chosen
this is what i have in my controller:
init: function() {
this.control({
'NciImport button[action=cargarArchivo]': {
click: this.cargaArchivo
}
});
},
cargaArchivo : function (button){
clickedButton = button;
bsNciNiv.cargaArchivoNci(dwr.util.getValue('file'), function(x,y,z){
clickedButton.up('form').down('fileuploadfield').createFileInput(); // funny solution
});
}
The bsNciNiv.cargaArchivoNci part is my DWR service
the line i commented as funny solution kind of works, after adding it the rest works as expected, but i really dont think it is the right solution, just added it as a hint in case its useful
can anyone confirm if this is a bug or if theres a way to fix this? thanks
(btw not sure if this has anything to do with dwr3, but i tagged it anyway)
I just ran into this same problem using Ext-JS 4.1.1 and DWR3. I debugged the DWR javascript and found the cause. When the dwr method parameters include a fileupload field, dwr constructs a multipart post message and a hidden iframe rather than using XmlHttpRequest. As part of this process, it replaces the original fileupload element (this itself is a hidden element, created and managed by the Ext FileUpload component) with a clone (same ID and properties). As a result, the Ext field's fileInputEl property is no longer referring to the replaced element and the component's onFileChange() event handler is not registered for the new element's 'change' event. So, it isn't a bug in Ext-JS.
I worked around it in my callback like this:
var fileInputId = uploadField.fileInputEl.dom.id;
MyDwrService.fileUpload(uploadField.fileInputEl.dom, arg2, function(results) {
uploadField.fileInputEl = Ext.get(document.getElementById(fileInputId));
uploadField.fileInputEl.on({
scope: uploadField,
change: uploadField.onFileChange
});
});
It worked for me in Firefox, Chrome and IE8
My guess is that this component was not designed to upload multiple files (in series).
The issue you are seeing is probably due to this hidden element not getting cleared: http://docs.sencha.com/ext-js/4-0/#!/api/Ext.form.field.File-property-fileInputEl
You can probably file this as a bug with Sencha although they might consider it a feature :)

Using dijit.InlineEditBox with dijit.form.Select

I'm trying to use a dijit.form.Select as the editor for my dijit.InlineEditBox. Two problems / unexpected behavior seem to occur:
Inconsistently, the InLineEditBox doesn't have the initial value set as selected
Consistently, after selecting a choice, the value that should be hidden is shown instead of the label.
The width isn't set to 130px
Here's working code: http://jsfiddle.net/mimercha/Vuet8/7/
The jist
<span dojoType="dijit.InlineEditBox" editor="dijit.form.Select"
editorParams="{
options: [
{label:'None',value:'none'},
{label:'Student',value:'stu'},
{label:'Professor',value:'prof',selected:true},
],
style:'width:1000px;',
}"
editorStyle="width: 1000px;"
>
</span>
Any help is greatly appreciated! Thanks!
Okay, after a few MORE hours struggling with the mess that is dijit.InlineEditBox, I think I have the solution to the remaining issue (#2).
EDIT: My first solution to #2 is still flawed; the implementation at http://jsfiddle.net/kfranqueiro/Vuet8/10/ will never return the actual internal value when get('value') is called.
EDIT #2: I've revamped the solution so that value still retains the real (hidden) value, keeping displayedValue separate. See if this works better:
http://jsfiddle.net/kfranqueiro/Vuet8/13/
First, to recap for those who weren't on IRC:
Issue #1 was happening due to value not being properly set as a top-level property of the InlineEditBox itself; it didn't pick it up properly from the wrapped widget.
Issue #3 was happening due to some pretty crazy logic that InlineEditBox executes to try to resolve styles. Turns out though that InlineEditBox makes setting width particularly easy by also exposing it as a top-level numeric attribute. (Though IINM you can also specify a percentage as a string e.g. "50%")
Now, issue #2...that was the killer. The problem is, while InlineEditBox seems to have some logic to account for widgets that have a displayedValue attribute, that logic is sometimes wrong (it expects a displayedValue property to actually exist on the widget, which isn't necessarily the case), and other times missing entirely (when the InlineEditBox initializes). I've worked around those as best I could in my own dojo.declared extensions to InlineEditBox and the internal widget it uses, _InlineEditor - since generally it's a good idea to leave the original distribution untouched.
It's not pretty (neither is the underlying code I dug through to understand and come up with this), but it seems to be doing its job.
But man, this was rather interesting. And potentially pertinent to my interests as well, as we have used this widget in our UIs as well, and will be using it more in the future.
Let me know if anything backfires.
hm...
<span dojoType="dijit.InlineEditBox" editor="dijit.form.Select"
editorParams="{
options: [
{label:'None',value:'none'},
{label:'Student',value:'stu'},
{label:'Professor',value:'prof',selected:true},**<<<<** and this comma is for?
],
style:'width:1000px;',**<<<<** and this comma is for?
}"
editorStyle="width: 1000px;"
>
</span>
Also, when using dijit.form.Select, selected value is not attr "selected" but value.
And if you enter prof inside <span ...blah > prof </span> than your proper selected option will be selected ;)
Dijit select checks for VALUE, not attr.
This may be fixed in recent Dojo - see http://bugs.dojotoolkit.org/ticket/15141 - but using 1.7.3 I found this worked:
In my app directory, at the same level as dojo, dijit and dojox, I created a file InlineSelectBox.js which extends InlineEditBox with code to set the HTML on the associated domNode from the value of the Dijit, and which wires up that code to the onChange() event:
define(["dijit/InlineEditBox",
"dijit/form/Select",
"dojo/on",
"dojo/_base/declare",
"dojo/_base/array"
],
function(InlineEditBox, Select, on, declare, array){
return declare(InlineEditBox, {
_setLabel: function() {
array.some(this.editorParams.options, function(option, i){
if (option.value == this.value) {
this.domNode.innerHTML = option.label;
return true;
}
return false;
}, this);
},
postMixInProperties: function(){
this.inherited(arguments);
this.connect(this, "onChange", "_setLabel");
},
postCreate: function(){
this.inherited(arguments);
this._setLabel();
}
});
});
Then, in my view script:
require(["dojo/ready",
"app/InlineSelectBox",
"dijit/form/Select"
],
function(ready, InlineSelectBox, Select){
ready(function(){
// Add code to set the options array
var options = [];
// Add code to set the initial value
var initialValue = '';
var inlineSelect = new InlineSelectBox({
editor: Select,
editorParams: {options: options},
autoSave: true,
value: initialValue
}, "domNodeToAttachTo");
});
});
I was dealing with this situation a few months ago, and not finding a resolution i made my own algorithm.
I put a div with an event on Onclick that build programatically a Filtering Select on that div with the store i want to use.
function create(id,value){
var name = dojo.byId(id).innerHTML;
dojo.byId(id).parentNode.innerHTML = '<div id="select"></div>';
new dijit.form.FilteringSelect({
store: store,
autoComplete: true,
invalidMessage:"Invalid Selection",
style: "width: 80px;",
onBlur: function(){ },
onChange: function(){ },
required: true,
value: value,
disabled: false,
searchAttr: "name",
id: "status"+id,
name: "status"
},"select");
dijit.byId('status'+id).focus();
}
I used the onBlur event to destroy the widget and the onchange to save by xhr the new value.
The focus is below because the onBlur was not working properly.
note: the function is not complete.