Mouseover in cypress - cypress

I am a newbie in cypress and trying to create some basic scripts for my learning, Handling dropdown by clicking the elements is fine, but hovering on the element is not working in this case, I can see the required element is getting hovered but the sub-menu is not appearing.
it.only('Mouse hover using trigger ', () => {
cy.visit('https://www.puregrips.com/pages/custom-grips')
cy.contains("a", "Custom").trigger('mouseover')
})

You can use the cypress-real-events plugin and this worked with your webpage.
To install use the command:
npm i cypress-real-events
Then inside your cypress/support/index.{js,ts}, write:
import "cypress-real-events/support";
And in your code you can directly write:
cy.contains("a", "Custom").realHover('mouse')
Note: Since the above plugin uses Chrome DevTools Protocols to simulate native events, hence this will only work with Chromium-based browsers, so no firefox.
Things I tried that didn't work -
cy.contains("a", "Custom").trigger('mouseover')
cy.contains("a", "Custom").invoke('show')

Just try this, it should work:
cy.get('.locater').invoke('show').click({ force: true })

cy.get('[your selector]')
.eq(0).invoke('show')
.trigger('mouseenter')
.wait(1000)
.should('have.attr','your-selector','Active tooltip')
.trigger('mouseleave');

This worked for me for the above problem.
Issue:
Timed out retrying after 5000ms: cy.trigger() failed because this element is not visible: CUSTOM
This element <a.header__linklist-link.link--animated> is not visible because its parent <ul.header__linklist.list--unstyled.hidden-pocket.hidden-lap> has CSS property: display: none
it.only("Mouse hover using trigger ", () => {
cy.viewport(1440, 660); //setting viewport as site is responsive web design
cy.visit("https://www.puregrips.com/pages/custom-grips"); //visit url
//used within to get parent and children to get the desired web-element
//and used invoke("show") to show the hidden elements
cy.get(".header__linklist").within(() => {
cy.get("li").contains("CUSTOM").invoke("show");
});
});
Added final screenshot:

Related

How to force element state using cypress

i have a link which gets a text-decoration:underline when hovering. But i can´t reproduce it using cypress.
I´ve tried ex. cy.get('a').trigger('mouseover') but nothing happens.
Is there a way to force the element to have :hover state?
Cypress does not support hovering. But in a previous question this workaround has been suggested:
it('hovering over button', () => {
cy.visit("http://www.qaclickacademy.com/practice.php");
cy.get('.mouse-hover-content').should('be.hidden').invoke('show');
})

Custom child command in cypress doesn't perform click

Background:
I'm writing test automation for a React web application, using Cypress. In the application I have a dialog box in which there are elements I need to click. When I try to click any of these elements normally, Cypress gives me an error that the element in not visible because its content is being clipped by one of its parent elements, which has a CSS property of overflow: 'hidden', 'scroll' or 'auto'. Because these DOM elements are generated by some 3rd party React components, I cannot change this, and the only way I can work-around it is to use {force:true} in the click command.
The problem:
Because I have few of these elements and in order to keep the DRY principle, I wanted to create a custom child command named forceClick that simply wraps subject.click({force:true}). However, for some reason, when I do that, Cypress does not perform the click command at all!
Note: For debugging purposes I added a cy.log command to the custom command as well, and strangely enough, I see that this log command is executed and only the click command doesn't.
Here's the code:
Cypress.Commands.add('forceClick', {prevSubject:'element'}, subject => {
cy.log('forceClick was called!');
subject.click({force:true})});
And inside my test I have the following line:
cy.get("[data-test='panel-VALUES']").forceClick();
Note that if I change it to the following line, it works as expected:
cy.get("[data-test='panel-VALUES']").click({force:true});
Any idea why the click command isn't executed by the forceClick custom command?
You are almost there, you just missed that you have to wrap the subject if you want to work with it.
Cypress.Commands.add('forceClick', {prevSubject: 'element'}, (subject, options) => {
// wrap the existing subject and do something with it
cy.wrap(subject).click({force:true})
})
I never saw a solution with subject.click({force:true}), I'm not saying it won't work, but I just never saw it before. What works anyway is this:
Custom command:
Cypress.Commands.add('forceClick', {prevSubject:'element'}, subject => {
cy.log('forceClick was called!');
cy.get(subject)
.click({force:true})});
}
Test step:
cy.forceClick('[data-test="panel-VALUES"]');
If you only use the forceClick you could even shorten it further to this:
Custom command:
Cypress.Commands.add('forceClick', {prevSubject:'element'}, subject => {
cy.log('forceClick was called!');
cy.get(`[data-test=${subject}]`)
.click({force:true})});
}
Test step:
cy.forceClick('panel-VALUES');

Capybara with Selenium: Can't click on hidden element

I have a situation in my view where a clickable icon is only visible when it's containing div is hovered over (using Knockout JS, SCSS) . Something like this:
HTML
<div id="button_div">
<i id="icon" data-bind="click: dosomething"></i>
</div>
SCSS
i {
display: none;
}
#button_div:hover {
i {
display: block;
}
}
Everything works fine on the page, but I can't seem to figure out how to click the element in Capybara. I've tried adding the :visible symbol to the method, but with no luck:
find('#icon', visible: false).click
This gives me the a "Selenium::WebDriver::Error::ElementNotVisibleError" error.
Using:
Capybara.ignore_hidden_elements = false
Gives me the exact same error
I've also tried using a Selenium Action such as:
button_div_element = find('#button_div').native
button_element = find('#button', visible: false).native
page.driver.browser.action.move_to(button_div_element).click(button_element).perform
While this doesn't throw an error, it also doesn't click the button.
Does anyone have any idea what I might be doing wrong?
Capybara is designed to emulate a user so you can't click on a non-visible element because a user couldn't. You should, however, be able to replicate a users actions to make the element visible and then click it
find('#button_div').hover
find('#icon').click
if that doesn't raise an error but also doesn't appear to click the button try putting a short sleep between the two actions since you may have an animated appearance which can cause clicks to miss items
Try using .execute_script() as below :-
button_div_element = find('#button_div').native
button_element = find('#button', visible: false).native
page.driver.browser.action.move_to(button_div_element).perform
page.driver.browser.execute_script("arguments[0].click()", button_element)
Hope it will work...:)
After some painstaking trial and error, I managed to find a solution that worked
button_div = find("#button_div_id").native
icon = find("#icon_id").native
page.driver.browser.action.move_to(button_div, :right_by => -50).click.perform
icon.click
Not sure why I had to manually tell Capybara to go left by 50px, but that seems to have done the trick.
Also, I added the following line to my setup code:
page.driver.browser.manage.window.maximize
This makes sure the window is maximized before running the test. I'm not 100% sure, but this might have also had something to do with the fix.

The view area of ckEditor sometimes shows empty at the start

I am using the following directive to create a ckEditor view. There are other lines to the directive to save the data but these are not included as saving always works for me.
app.directive('ckEditor', [function () {
return {
require: '?ngModel',
link: function ($scope, elm, attr, ngModel) {
var ck = ck = CKEDITOR.replace(elm[0]);
ngModel.$render = function (value) {
ck.setData(ngModel.$modelValue);
setTimeout(function () {
ck.setData(ngModel.$modelValue);
}, 1000);
}; }
};
}])
The window appears but almost always the first time around it is empty. Then after clicking the [SOURCE] button to show the source and clicking it again the window is populated with data.
I'm very sure that the ck.setData works as I tried a ck.getData and then logged the output to the console. However it seems like ck.setData does not make the data visible at the start.
Is there some way to force the view window contents to appear?
You can call render on the model at any time and it will simply do whatever you've told it to do. In your case, calling ngModel.$render() will grab the $modelValue and pass it to ck.setData(). Angular will automatically call $render whenever it needs to during its digest cycle (i.e. whenever it notices that the model has been updated). However, I have noticed that there are times when Angular doesn't update properly, especially in instances where the $modelValue is set prior to the directive being compiled.
So, you can simply call ngModel.$render() when your modal object is set. The only problem with that is you have to have access to the ngModel object to do that, which you don't have in your controller. My suggestion would be to do the following:
In your controller:
$scope.editRow = function (row, entityType) {
$scope.modal.data = row;
$scope.modal.visible = true;
...
...
// trigger event after $scope.modal is set
$scope.$emit('modalObjectSet', $scope.modal); //passing $scope.modal is optional
}
In your directive:
ngModel.$render = function (value) {
ck.setData(ngModel.$modelValue);
};
scope.$on('modalObjectSet', function(e, modalData){
// force a call to render
ngModel.$render();
});
Its not a particularly clean solution, but it should allow you to call $render whenever you need to. I hope that helps.
UPDATE: (after your update)
I wasn't aware that your controllers were nested. This can get really icky in Angular, but I'll try to provide a few possible solutions (given that I'm not able to see all your code and project layout). Scope events (as noted here) are specific to the nesting of the scope and only emit events to child scopes. Because of that, I would suggest trying one of the three following solutions (listed in order of my personal preference):
1) Reorganize your code to have a cleaner layout (less nesting of controllers) so that your scopes are direct decendants (rather than sibling controllers).
2) I'm going to assume that 1) wasn't possible. Next I would try to use the $scope.$broadcast() function. The specs for that are listed here as well. The difference between $emit and $broadcast is that $emit only sends event to child $scopes, while $broadcast will send events to both parent and child scopes.
3) Forget using $scope events in angular and just use generic javascript events (using a framework such as jQuery or even just roll your own as in the example here)
There's a fairly simple answer to the question. I checked the DOM and found out the data was getting loaded in fact all of the time. However it was not displaying in the Chrome browser. So the problem is more of a display issue with ckEditor. Strange solution seems to be to do a resize of the ckEditor window which then makes the text visible.
This is a strange issue with ckeditor when your ckeditor is hidden by default. Trying to show the editor has a 30% chance of the editor being uneditable and the editor data is cleared. If you are trying to hide/show your editor, use a css trick like position:absolute;left-9999px; to hide the editor and just return it back by css. This way, the ckeditor is not being removed in the DOM but is just positioned elsewhere.
Use this java script code that is very simple and effective.Note editor1 is my textarea id
<script>
$(function () {
CKEDITOR.timestamp= new Date();
CKEDITOR.replace('editor1');
});
</script>
Second way In controller ,when your query is fetch data from database then use th
is code after .success(function().
$http.get(url).success(function(){
CKEDITOR.replace('editor1');
});
I know, that this thread is dead for a year, but I got the same problem and I found another (still ugly) solution to this problem:
instance.setData(html, function(){
instance.setData(html);
});

CasperJS click event having AJAX call

I am trying to fetch data from a site by simulating events using CasperJS with phantomJS 1.7.0.
I am able to simulate normal click events and select events. But my code fails in following scenario:
When I click on button / anchor etc on remote page, the click on remote page initiates an AJAX call / JS call(depending on how that page is implemented by programmer.).
In case of JS call, my code works and I get changed data. But for clicks where is AJAX call is initiated, I do not get updated data.
For debugging, I tried to get the page source of the element container(before and after), but I see no change in code.
I tried to set wait time from 10 sec to 1 ms range, but that to does not reflect any changes in behavior.
Below is my piece of code for clicking. I am using an array of CSS Paths, which represents which element(s) to click.
/*Click on array of clickable elements using CSS Paths.*/
fn_click = function(){
casper.each(G_TAGS,function(casper, cssPath, count1)
{
casper.then ( function() {
casper.click(cssPath);
this.echo('DEBUG AFTER CLICKING -START HTML ');
//this.echo(this.getHTML("CONTAINER WHERE DETAILS CHANGE"));
this.echo('DEBUG AFTER CLICKING -START HTML');
casper.wait(5000, function()
{
casper.then(fn_getData);
}
);
});
});
};
UPDATE:
I tried to use remote-debug option from phantomJS, to debug above script.
It is not working. I am on windows. I will try to run remote debugging on Ubuntu as well.
Please help me. I would appreciate any help on this.
UPDATE:
Please have a look at following code as a sample.
https://gist.github.com/4441570
Content before click and after click are same.
I am clicking on sorting options provided under tag (votes / activity etc.).
I had the same problem today. I found this post, which put me in the direction of jQuery.
After some testing I found out that there was already a jQuery loaded on that webpage. (A pretty old version though)
Loading another jQuery on top of that broke any js calls made, so also the link that does an Ajax call.
To solve this I found http://api.jquery.com/jQuery.noConflict/
and I added the following to my code:
this.evaluate(function () { jq = $.noConflict(true) } );
Anything that was formerly assigned to $ will be restored that way. And the jQuery that you injected is now available under 'jq'.
Hope this helps you guys.

Resources