Protractor/Jasmine drag and drop only grabbing text not the element - automation

I have a Protractor/Jasmine E2E Automation test that is to drag and drop a couple of collapsible panels to change the order and just verify they the elements have been moved.
I'm currently running latest versions of Protractor, Jasmine, and webdrivers (tests run in IE 11)
EDIT: Found out we're using ng-dragula to perform the drag and drops. I'm assuming protractor just isn't playing nicely with this. I'll do more digging about it, but still curious to know if there's a work around.
/end edit
This function used to work, and I have since tried a handful of variations of it:
browser.actions().
mouseMove(dragFromElement).
mouseDown().
mouseMove(dropToElement).
mouseUp().
perform();
browser.actions().
dragAndDrop(dragFromElement, dropToElement).
perform();
I've also tried with .getWebElement() appended to the element tag, getting each elements location and doing a mouse click, move, drop to those locations, and trying various actionSequences instead of actions().
Basically all of the above will highlight the text of the elements like it's clicking behind the panels and does not actually grab the element and drag/drop it.
Curious to know if this is a known problem or if there's a possible solution for my issue.
What i'm working with is:
<core-drag-and-drop-panel _nghost-wod-4="">
<div class="sortable-panels" _ngcontent-wod-4="">
<div id="elementId_10" class="draggableDiv" _ngcontent-wod-4="" aria-dropeffect="move" aria-grabbed="false">
<div id="elementId_12" class="draggableDiv" _ngcontent-wod-4="" aria-dropeffect="move" aria-grabbed="false">
<div id="elementId_1" class="draggableDiv" _ngcontent-wod-4="" aria-dropeffect="move" aria-grabbed="false">
</div>
</core-drag-and-drop-panel>

Related

Using Selenium with Java on Salesforce Lightning / Javascript problems

We had Selenium tests running on Sales Force non Lightning. Now I am converting to Lightning. There is a chain of menus to go through. I have successfully navigated to a certain menu, but now I have run into a problem. This is not the standard question about new element names. Here is the question. This is a small piece of what the page looks like (see below).
When using inspect with Chrome I can find the elements. This is what it looks like (a small cross section corresponding to above). The SPAN tag has the label ("Original Agreement") and the DIV below it will contain the box for the input value.
<div class="slds-form-element__control" data-aura-rendered-by="228:1224;a">
<div data-aura-rendered-by="1108:0" class="uiInput forceSearchInputLookupDesktop uiInput--default" data-aura-class="uiInput forceSearchInputLookupDesktop uiInput--default">
<label class="label inputLabel uiLabel-left form-element__label uiLabel" for="157:1224;a" data-aura-rendered-by="1103:0" data-aura-class="uiLabel">
<span class="" data-aura-rendered-by="1104:0">Original Agreement</span>
<!--render facet: 1106:0--><!--render facet: 1107:0--></label>
<div data-aura-rendered-by="161:1224;a"><div class="contentWrapper slds-box--border" data-aura-rendered-by="162:1224;a">
However, Selenium can not find the elements (though inspect does). When I did a "View Page Source instead of an
inspect, almost the entire thing is in JavaScript like this:
function rewriteAndInjectCss(linkEl, source, varLookup) {
var css = rewriteCssVars(source, varLookup);
injectStyles(linkEl, css);
}
but a lot more. Almost all functions, with maybe only a couple elements.
In the past when I have seen something similar there is often an iframe to switch to to get the elements. But there is no iframe to switch to. So I am stuck how to get these. Can anyone shed some light?
OK. Found it. I needed to do a driver.switchTo().defaultContent()

Bootstrap tooltip not showing in ASP.Net MVC application

I've got a rather weird scenario going on here. I am trying to add tooltips to an existing ASP.Net MVC application in which I'm upgrading Bootstrap to 4.6.2. The upgrade was very smooth with no complications; I just want to replace the default display of titles with the nicer looking tooltips, but for some reason they're not appearing. I tried to simplify things by creating a new view to isolate the problem, and still no tooltip. I tried again with completely new solution, and wouldn't you know it, it works! So my question isn't "how do I create tooltips", but "how can I debug what's going on in the failing project?"
Here's what I've discovered so far. I believe you can see everything that's relevant in this screenshot of the nearly-empty view. All the included script files are there in the right order, my script is there, initializing the tooltip, and there are no messages in the console. When I hover over the link, a new <div> element is added to the DOM. In DevTools, I use the arrows to expand the tree, showing everything in the tooltip. The .fade:not(.show) CSS selector is the reason I don't see it. In the working solution, the show class is properly added to the tooltip's <div>.
So, could there be some setting in the existing application preventing the addition of the show class? Is something failing in the tooltip code,causing it to never add the show class without reporting errors? How should I continue debugging this? I tried stepping through the bootstap.js file, but being a JS noob, I'm getting a little lost. The screenshot is from Chrome, but I see the same behavior in Firefox.
This turned out to be one of those embarrassing oversights. My BundleConfig.cs file was still pointing to old Javascript files that were still hanging around after the upgrade. I should have seen it in the version numbers in the <script> tags.

How can I change the styleClass of a control while also doing a partial refresh on another component?

I have a straightforward XPage that lets a user answer a question with a simple Yes/No/NA response using radio buttons. I have restyled the radio buttons to look like a bootstrap button group to make it visually more interesting for the user. If the user chooses "Fail" then they are informed that they need to do something else - easily done with a simple partial refresh to a div further down the page.
This all works fine.
The problem I'm having is that I'd like it so that when the user selects an option, I would like to add a new class of "active" to the selected option so that it highlights in a pretty colour. But for the life of me I can't get this to work and though I'm sure it's a straight forward problem, I can no longer see the wood for the trees.
My current (abridged) iteration of the radio button code is this:
<xp:div styleClass="btn-group item-result" id="edit-result" loaded="${Question.open}">
<xp:radio text="${lbl.kwPass1}" id="itemPass"
styleClass="btn btn-pass #{(item.itemResult eq '0')?'active':''}" groupName="itemResult"
selectedValue="1">
<xp:eventHandler event="onchange" submit="true"
refreshMode="partial" refreshId="actionAlert">
<xp:this.script><![CDATA[XSP.partialRefreshPost('#{id:edit-result}');]]></xp:this.script>
</xp:eventHandler>
</xp:radio>
<!-- other radio buttons -->
</xp:div>
<!-- other page compenents -->
<xp:panel id="actionAlert">
<!-- panel content and appropriate rendered value -->
</xp:panel>
This was attempting to do a chained partial refresh on the radio button container so that the EL would evaluate and apply/remove the 'active' style based on the document datasource ('item') value. I have also tried using dojo.addClass, dojo.removeClass, XSP.partialRefreshGet and other options. I don't mind what the solution is as long as it's efficient and works. I'd prefer not to move the actionAlert panel to within the same container as the radio buttons and I can't do a full page refresh because there are other fields which will lose their values.
Some notes:
I'm not using a RadioGroup control because it outputs a table and I haven't got around to writing my own renderer for it yet. Single Radio button controls work fine for what I need them to do.
I originally tried using the full Bootstrap solution of using "data-toggle='buttons'" (source) which sorts out applying the "active" style fine but then, inevitably, prevents the partial refresh from working.
the radio button styles are clearly not Bootstrap standard
Any assistance pointers or, preferably, working solutions would be appreciated.
You need to aim your partial refresh at the div containing all your radio buttons. Give it an id, so you can address it.
Partial refresh, as the name implies, refreshes one element and its content only. So you target the element that covers all of the items you need to recompute.
Stepping away from the problem, a couple of beers and an episode of iZombie later, I realized what I was doing wrong and sorted it out. So, for posterity, here is the simple solution that I swear I tried earlier but clearly works now:
<xp:div styleClass="btn-group item-result" id="edit-result" loaded="${Question.open}">
<xp:radio text="${lbl.kwPass1}" id="itemPass" value="#{item.ItemResult}"
styleClass="btn btn-pass" groupName="itemResult" selectedValue="1">
<xp:eventHandler event="onchange" submit="true" refreshMode="partial" refreshId="actionAlert">
<xp:this.script><![CDATA[dojo.query('.item-result > .btn').removeClass('active');
dojo.query('.btn-pass').addClass('active');]]></xp:this.script>
</xp:eventHandler>
</xp:radio>
<!-- et cetera -->
The many places I was going wrong:
In my code in the question, I was calling XSP.partialRefreshPost in the CSJS script of the radio button when it should have been in the onComplete of the eventHandler. It has to be chained to another partial refresh so that it runs after it, not at the same time. I did end up getting this right - but overlooked something I'll come to in point 3.
In my original attempt to use Dojo, my first mistake was to try and target the ID of the radio button, something like:
dojo.addClass(dojo.byId('#{id:radio2}'),'active');
This actually works as expected, so long as you remember that the ID of the radio button on the XPage refers to the actual radio button control and not the label wrapping; and the label is what I wanted to style. So the class "active" was being actually being added, just not to the element I thought it was. I should have spotted this in my browser code inspector except for the third thing I got wrong:
Ironically, I sorted out the first issue, remembering to put the XSP.partialRefreshPost into the onComplete - and then didn't remove it when trying to run the Dojo.addClass(). So I didn't notice the mistake with the addClass targeting the wrong element because after it ran, the partial refresh updated the container and removed the class I had just added which made me think that nothing was working.
So now I have some neatly styled radio buttons that don't look like radio buttons and it's all managed client side without any unnecessary partial refresh trips to the server barring the one where I actually need to look stuff up from the server. And the vital lesson is - sometimes you just need to step away from a problem and come back to it with fresh eyes later on.

Identifying the same Web Elements with Selenium

I am an Automation Engineer, I am currently trying to create test cases for a webpage that are sustainable ( that I can run at a later time and have still pass)
Here is my problem:
I am trying to select multiple web buttons that have the same exact class name. Now I can 'select' these buttons but these are only temporary x paths that are subject to change.
I need UNIQUE ID's (or some way of distinguishing them) for the same web elements. The only difference in the x paths are:
HTML format code that I can find each button, however if one button is moved my tests will fail.
HTML code that is the class name + nth of the button. But again my tests will fail if a button is taken out of the webpage.
//*[#id="tenant-details-accordion"]/div[1]/div[2]/div/div[2]/div[1]/div/a/div
//*[#id="tenant-details-accordion"]/div[1]/div[2]/div/div[2]/div[2]/div/a/div
//*[#id="tenant-details-accordion"]/div[1]/div[2]/div/div[2]/div[3]/div/a/div
^^The above code is how I currently find each button with Selenium
If I copy each classes x path this is what I get
<div class="src-js-components-DateControl-___DateControl__dateControl___2nYAL"><a tabindex="0"><div class="src-js-components-DateControl-___DateControl__icon___2z6Ak null"></div><!-- react-text: 392 -->Set +<!-- /react-text --></a></div>
<div class="src-js-components-DateControl-___DateControl__dateControl___2nYAL"><a tabindex="0"><div class="src-js-components-DateControl-___DateControl__icon___2z6Ak null"></div><!-- react-text: 386 -->Set +<!-- /react-text --></a></div>
<div class="src-js-components-DateControl-___DateControl__dateControl___2nYAL"><a tabindex="0"><div class="src-js-components-DateControl-___DateControl__icon___2z6Ak null"></div><!-- react-text: 398 -->Set +<!-- /react-text --></a></div>
I have talked to the Development team about this issue however they tell me that assigning Unique ID's to these web elements is a big no-no. (something to do with globalization of the project when we go to production) Even if they did assign Unique Id's they tell me that they would have to strip them before the project can be sent to production. Which ultimately would render my tests useless in the end...
I now come to Stack Overflow for help, everything I look up online cannot give me an answer, however this does seem to be a valid question between QA and Development departments.
Is there a way to assign Id's to a web element so that a tester using selenium can identify them and yet it will not affect a Developers ability to use that element through an entire project?
Edit:
With the framework that my company uses, I am not actually writing any code in selenium. I save the Xpath to an object and then later in a manual test call that object with a pre-existing method. I can ONLY select Xpaths to be saved in an object.
I'll talk to Dev later to have them explain the big 'no-no' so that I may be able to communicate that with all of you..Thank you for your time and input
For example:
BirthDateSet= someXpath
Click() using {BirthDateSet}
Here are some pictures to help give you a visual
You can simplify your XPathto make it less sensitive to possible changes in DOM:
//div[#class="src-js-components-DateControl-___DateControl__icon___2z6Ak null"][N] # Where N is button index
If this part 2z6Ak of class name is dinamically generated, try:
//div[starts-with(#class, "src-js-components-DateControl-___DateControl__icon___")][N] # Where N is button index
Another way of reaching to the required button using xpath is following:
//*[#id='tenant-details-accordion']/descendant::div[contains(#class, 'DateControl__icon')][1]
Above xpath should be able to select the first occurring button. Similarly, for the second occurring button, the xpath will become:
//*[#id='tenant-details-accordion']/descendant::div[contains(#class, 'DateControl__icon')][2]
Hence, you can continue to replace the predicate([2]) based on occurrence level of the required button on page.
you can ask devs to add attribute to those buttons
so instead of:
<button class="common_class_name">
<button class="common_class_name">
<button class="common_class_name">
for each button you will see
<button class="common_class_name" test-id="uniqueAttributeForButton1">
<button class="common_class_name" test-id="uniqueAttributeForButton2">
<button class="common_class_name" test-id="uniqueAttributeForButton3">
etc
And in your tests you can find those buttons using css selector
e.g. C# code:
var buttonLocator = "[test-id=\"uniqueAttributeForButton1\"]";
WebElement button = driver.FindElement(By.CssSelector(buttonLocator));
if devs doesnt want to add unique IDs or attributes (it's weird why they don't want to do that) you could try something like this:
//return div class 'col-sm-4' which contain text 'Activation Date'
var parentDiv = driver.FindElement(By.XPath("//div[contains(#class, 'col-sm-4') and contains(., 'Activation Date')]"));
//should return div with icon you want e.g. Click
var childElement = parentDiv.FindElement(By.CssSelector(".DateControl__icon"));
childElement.Click();
You can go with the nth approach to find your unique element or with another, that won't solve your real problem which is that your colleague developers aren't cooperating with you. The automated tests are supposed to be (among other things) a service for the developers to know they haven't broken anything as fast as possible, but if they aren't giving any effort, then WHY should you invest in it at all..?
They probably won't even look at the results. Especially when your locators are in the form of div[2]/div[3]... which would break very often and you'll lose their trust in the automation.
I'm no front-end expert but I've seen enterprise products in production with G10N and L10N and other long words, that have id's in their HTML, so if I were you I'd dig deeper to understand why? that big no-no, which sounds very odd to me...
So you asked the wrong question, it should be something like ~ How to add unique id's to the HTML using React in a global web application? and the ones who should be asking it are the developers.
As a side note, as many people tend to think, automation is not mainly about moving manual tests to automated it also finds "bugs" in the communication inside the company. To quote a great blog post on this subject:
Counter-intuitively, the bigger obstacles when developing automation
are either low priority bugs or even things that are not bugs
whatsoever. These obstacles can be symptoms of a bad design, bad
development practices and even symptoms of inefficient communication
patterns in the organization (that are usually caused by the
organizational structure! Conway’s law is a classic example for this).
Good luck!
EDIT:
Thanks for the code.. So if you look at your code, you can see that although what you're after have similar attributes, there are elements in the page that would allow you to identify what you're after. So let's say you want the SET link after Birth Date, then use:
//div[contains(text(),'Birth Date')]/div/a/div
So to reuse this xpath, just replace the text String.format("//div[contains(text(),'%s')]/div/a/div", labelName);
OLD: if you want to temporarily assign the elements an attribute, I believe you can do that through javascript element.setAttribute() which you can run through the executeScript() function.
Don't the buttons have text? Are you saying that the buttons swap places with one another? or don't you want to use the index of the buttons?
I understand you want to select the "Set +" buttons, correct?
If so you can try to find all buttons under the #id="tenant-details-accordion" element with a specific text like that:
//*[#id="tenant-details-accordion"]//*[text()='Set +']

How to remove this border from tooltipdialog that shows up on mouse click?

Whenever I click inside a tooltipdialog, this border shows up around it.
Is there an easy way to remove this?
EDIT: After trying in different browsers, it seems to affect only Chrome, the outline doesn't appear in Firefox or IE.
I faces the similar issue when i started working on Dojo. To fix this basically you need to add the following css for dijit's dijitTooltipDialog class
.dijitTooltipDialog {
outline : none
}
See this for example.