Checking that CSS has been updated using capybara - css

I'm currently writing a web app that updates it's pages CSS based on user input. I've got it all working fine, but I'm having trouble getting my automated tests to confirm that the CSS has actually been updated.
Basically, I just want to verify that the contents of a <style> tag in the document <head> have been updated to a certain value. I'm using capybara (with the selenium driver) for my tests, with this code:
styles = page.all('style')
styles.length.should == 1
styles[0].text.should == style
It all works as expected, until the final line, which fails as it seems that styles[0].text is always "". I've also tried .value but it is always nil. I'm pretty sure the CSS is actually being updated, as I can see the changes in the firefox window that the tests are running in.
So, is there a way to get at the contents of the <style> tag using capybara?

It seems Capybara (with Selenium at least, I didn't try any other drivers) won't show you this, I presume because the style content is wrapped in an HTML comment so it gets ignored e.g.:
<STYLE type="text/css">
<!--
.newfont { color:red; font-style:italic }
-->
</STYLE>
You do, however, have access to the page's source with page.source, so you can use that to get at the style content. The source is just a big string, so one way to dig into it is to parse it with Nokogiri (which is required by Capybara so you'll have it already):
page = Nokogiri::HTML.parse(page.source)
page.css('style').first.text
# => "\n<!--\n.newfont { color:red; font-style:italic }\n-->\n"
If you're asserting against customisable styles, and you're using Selenium anyway, an alternative solution could involve using Javascript to determine the calculated style of an element, there seems to be no shortage of information on doing this. You could use Capybara's page.evaluate_script method to invoke a piece of Javascript that would tell you what a particular element actually looks like, and that may well be more robust than comparing the CSS text (e.g. if it gets minified by the app).

page.should have_css ".selector", :text => "Some Text"
page.should have_css ".selector", :value => "Some Value"
page.should have_css ".selector", :count => 1
Or
find('.selector').value
find('.selector:nth-child(1)').value
There are a couple ways to about what you are trying. I'd take a closer look at the documentation.
Also, one thing to note, if you are trying to access these changes after a javascript event, you'll need to run this in Selenium (or equivalent). Or you could try to use Jasmine.js for this as well.

Related

How do I locate elements in protractor that are in other views and are not visible when viewing page source

I am new to Angular & Protractor (and web development for that matter), so I apologize of this is an obvious question.
I am trying to test our angular app with protractor, and it appears that I can locate the first element on the page. But cannot find any of the other elements using (id, name, model, css). I have tried chaining off of the first element, but always get the element not found error on the second element in the chain. I've have triple check the spelling so I am confident everything is correct.
Our page is setup up with multiple sections and when I "view source" I only see the root div.
<head>
</head>
<body>
<div ng-app="app" id="wrap">
<div ui-view></div>
</div>
</body>
</html>
But when I inspect the elements using the developer tools (F12), they exist in the DOM, I just don't know how to get to them.
<input type="text" class="form-control ng-valid ng-dirty ng-valid-parse ng-touched" data-ng-model="vm.searchText" id="searchText" placeholder="(Account # / Name / Nickname / Phone #)">
I tried to access the control listed above using the following:
browser.element(by.id("searchText").sendKeys("test");
browser.element(by.model("vm.searchText").sendKeys("test");
element(by.id("searchText").sendKeys("test");
element(by.model("vm.searchText").sendKeys("test");
I also create a single button and used partialButtonText & buttonText, neither of which worked.
I also tried to add some async functionality with "then" but that didn't work either. How do I access these elements are are not contained in a single html file?
thanks.....
If an element is not visible, I believe protractor isnt able to interact with it. It can't click or get text or anything if it is not visible, that is actually checked before it can perform the action.
What you can do is check the element is present to ensure it is somewhere on the html.
var searchText = $('#searchText');
expect(searchText.isPresent()).toBeTruthy('Search Text element not present');
This will find an element with a css selector of id searchText, and then check if it is present(exists on the html).
If you want to interact with it, remember that protractor looks around like a human would. If a human cant click it, neither can protractor! Make sure it is on the page and visible.
Don't have the reputation points to add this in the comments to user2020347's response so...When you say not in "view source" I assume you're talking about dynamically generated content. Instead of using view source either use chrome or firefox developer tools to make sure you're using the right locators.
For example in chrome's console the following should return a result once the page is loaded:
$$('#searchText')
$$('input[data-ng-model="vm.searchText"]')
It also looks like you're sending keys to the same element.
Since you have an angular app protractor should wait for all elements to load, but just in case you might want to wait for the element to be present and/or visible on the page.
Same happened to me, because Protractor executed on the original (first) tab.
Try to switch between the tabs before accessing the elements:
browser.getAllWindowHandles().then(function (handles) {
browser.driver.switchTo().window(handles[1]);
});

Jquery Select Box not working on dynamically generated elements

I am with a problem. I am using jQuery.SelectBox for the select box and dropdowns.
It is working fine when the elements are loaded with the page load. But its not working when they are loaded by the ajax i.e on dynamicaly generated elements it is not working.
You can check the file here :- http://rvtechnologies.info/brad/jquery.selectBox.js
This line:
jQuery('<link rel="stylesheet" href="<?php echo DIVATEMPLATEPATH . "/css/jquery.selectBox.css"; ?>">').appendTo("head");
Is completely invalid. You cannot combine PHP and Javascript! PHP is executed on the server, not in the browser. Please learn about the fundamentals of web development. PHP gets run on the server, it generates code that gets sent to the client, which then in turn runs the code locally on the computer (HTML and JavaScript).
CSS codes are style declaration and stylesheets, once the element gets added to the DOM they will be loaded or applied.
Check the name of id, classes and attributes of the generated elements using tools like firebug and see the generated markup.
I have sorted it out.
I need to call the selecbox again on Ajax success.
I have done like this :-
success: function(html) {
jQuery('#loader').empty();
jQuery("#right_search").append(html);
jQuery("SELECT").selectBox(); //Just Added this
initdatepicker();
stat = 0;
}

JQuery load() function disables links and :hover effects?

I'm trying to load content from a different file into a div element within the current file using the jQuery load() function. Nothing fancy, just loading it and that's it. However the links that are contained in the loaded file become "disabled", you cannot click them, and pseudo-classes like :hover seem to be left out as well. Is there a solution to this?
$(document).ready(function() {
$("div.content").load("content.html");
});
let's say content.html contains just this line:
xxx
When it is loaded into the <div class="content"> the link is not clickable. It is colored according to the css, however the :hover effect doesn't work, and it behaves like normal text - not a link. This is a problem because the content I'm trying to load has a couple of links, and none of them work after being load()'ed.
I believe your issue is:
You use $('div.content').load('content.html') to send a request for content to (later) be inserted into the DOM.
You then run some code to specify handlers for nodes using $(document).click, $(document).bind etc - but this code runs before the new nodes have been added to the DOM.
New nodes are then added when the .load call completes.
The behaviour that you defined on all the origional nodes isn't being followed on the new nodes.
If that is the issue your're describing - then you need to add all the same bindings to the new nodes once they're created.
i.e. you need to provide a callback to add the bindings to the new elements:
function on_data_loaded() {
$('div.content ...').hover(.....);
// etc.
}
$('div.content').load('content.html', null, onloaded);
(note that's not a particularly clean way of doing it, but it should explain what needs to be done).

Watir - working with CSS elements

Hopefully someone can help me, either by telling me it cant be done or pointing me in the right direction.
I am trying to use Watir Ruby written tests to check a CSS element is being applied to my page when a check box is checked.
I can check the checkbox attribute fine and see that it is checked, but a differnt test i have to perform is to check that the image has been highlighted after the checking the checkbox.
Currently i have not been able to find anything useful around after a couple of hours of searching. Has anyone come across a problem liek this you ahve had to overcome, and if so how did you go about it.
Thanks in advance
If you're using vanilla Watir (meaning IE browser on Windows) then it is also possible to get style of the element from win32ole object:
irb(main):001:0> require "watir"
=> true
irb(main):002:0> b = Watir::Browser.new
=> #<Watir::IE:0x4bce118 url="about:blank" title="">
irb(main):003:0> b.goto "google.com"
=> 2.298132
irb(main):004:0> i = b.image(:alt => "Google")
=> #<Watir::Image:0x433fa28 located=false how={:alt=>"Google"} what=nil>
irb(main):005:0> i.style
=> #<WIN32OLE:0x431ca90>
irb(main):008:0> i.style.paddingTop
=> "26px"
This #style method also returns computed style, e.g. styles from CSS and not just from style tag.
You can check out all the possible style ole methods from msdn at http://msdn.microsoft.com/en-us/library/ms535870(v=vs.85).aspx under styles properties.
How do you apply the CSS element to image after checking the checkbox? If you add the class attribute for highlighting, I guess checking class attribute is the simplest way.
for example
browser.image.class_name =~ /foobar/
If using style attribute, I think you might need to check HTML itself, like
browser.image.html =~ /style=\"?foobar\"?/

How can I use a traditional HTML id attribute with an ASP.net runat='server' tag?

I am refactoring some CSS on a website. I have been working on, and noticed the absence of traditional HTML IDs in the code.
There is heavy use of CssClass='…', or sometimes just class='…', but I can't seem to find a way to say id='…' and not have it swapped out by the server.
Here is an example:
<span id='position_title' runat='server'>Manager</span>
When the response comes back from the server, I get:
<span id='$aspnet$crap$here$position_title'>Manager</span>
Any help here?
Use jQuery to select the element:
$("span[id$='position_title']")....
jQuery's flexible selectors, especially its 'begins with'/'ends with selectors' (the 'end with' selector is shown above, provide a great way around ASP.NET's dom id munge.
rp
The 'crap' placed in front of the id is related to the container(s) of the control and there is no way (as far as I know) to prevent this behavior, other than not putting it in any container.
If you need to refer to the id in script, you can use the ClientID of the control, like so:
<script type="text/javascript">
var theSpan = document.getElementById('<%= position_title.ClientID %>');
</script>
Most of the fixes suggested her are overkill for a very simple problem. Just have separate divs and spans that you target with CSS. Don't target the ASP.NET controls directly if you want to use IDs.
<span id="FooContainer">
<span runat="server" id="Foo" >
......
<span>
</span>
You can embed your CSS within the page, sprinkled with some server tags to overcome the problem. At runtime the code blocks will be replaced with the ASP.NET generated IDs.
For example:
[style type="text/css"]
#<%= AspNetId.ClientID %> {
... styles go here...
}
[/style]
[script type="text/javascript"]
document.getElementById("<%= AspNetId.ClientID %>");
[/script]
You could go a bit further and have some code files that generate CSS too, if you wanted to have your CSS contained within a separate file.
Also, I may be jumping the gun a bit here, but you could use the ASP.NET MVC stuff (not yet officially released as of this writing) which gets away from the Web Forms and gives you total control over the markup generated.
Ok, I guess the jury is out on this one.
#leddt, I already knew that the 'crap' was the containers surrounding it, but I thought maybe Microsoft would have left a backdoor to leave the ID alone. Regenerating CSS files on every use by including ClientIDs would be a horrible idea.
I'm either left with using classes everywhere, or some garbled looking IDs hardcoded in the css.
#Matt Dawdy: There are some great uses for IDs in CSS, primarily when you want to style an element that you know only appears once in either the website or a page, such as a logout button or masthead.
The best thing to do here is give it a unique class name.
You're likely going to have to remove the runat="server" from the span and then place a within the span so you can stylize the span and still have the dynamic internal content.
Not an elegant or easy solution (and it requires a recompile), but it works.
.Net will always replace your id values with some mangled (every so slightly predictable, but still don't count on it) value. Do you really NEED to have that id runat=server? If you don't put in runat=server, then it won't mangle it...
ADDED:
Like leddt said, you can reference the span (or any runat=server with an id) by using ClientID, but I don't think that works in CSS.
But I think that you have a larger problem if your CSS is using ID based selectors. You can't re-use an ID. You can't have multiple items on the same page with the same ID. .Net will complain about that.
So, with that in mind, is your job of refactoring the CSS getting to be a bit larger in scope?
I don't know of a way to stop .NET from mangling the ID, but I can think of a couple ways to work around it:
1 - Nest spans, one with runat="server", one without:
<style type="text/css">
#position_title { // Whatever
}
<span id="position_titleserver" runat="server"><span id="position_title">Manager</span></span>
2 - As Joel Coehoorn suggested, use a unique class name instead. Already using the class for something? Doesn't matter, you can use more than 1! This...
<style type="text/css">
.position_title { font-weight: bold; }
.foo { color: red; }
.bar { font-style: italic; }
</style>
<span id="thiswillbemangled" class="foo bar position_title" runat="server">Manager</span>
...will display this:
Manager
3 - Write a Javascript function to fix the IDs after the page loads
function fixIds()
{
var tagList = document.getElementsByTagName("*");
for(var i=0;i<tagList.length;i++)
{
if(tagList[i].id)
{
if(tagList[i].id.indexOf('$') > -1)
{
var tempArray = tagList[i].id.split("$");
tagList[i].id = tempArray[tempArray.length - 1];
}
}
}
}
If you're fearing classitus, try using an id on a parent or child selector that contains the element that you wish to style. This parent element should NOT have the runat server applied. Simply put, it's a good idea to plan your structural containers to not run code behind (ie. no runat), that way you can access major portions of your application/site using non-altered IDs. If it's too late to do so, add a wrapper div/span or use the class solution as mentioned.
Is there a particular reason that you want the controls to be runat="server"?
If so, I second the use of < asp : Literal > . . .
It should do the job for you as you will still be able to edit the data in code behind.
I usually make my own control that extends WebControl or HtmlGenericControl, and I override ClientID - returning the ID property instead of the generated ClientID. This will cause any transformation that .NET does to the ClientID because of naming containers to be reverted back to the original id that you specified in tag markup. This is great if you are using client side libraries like jQuery and need predictable unique ids, but tough if you rely on viewstate for anything server-side.
If you are accessing the span or whatever tag is giving you problems from the C# or VB code behind, then the runat="server" has to remain and you should use instead <span class="some_class" id="someID">. If you are not accessing the tag in the code behind, then remove the runat="server".

Resources