is it possible to follow a link by it's class name instead of the id, text or title? Given I have (haha, cucumber insider he?) the following html code:
<div id="some_information_container">
Translation here
</div>
I do not want to match by text because I'd have to care about the translation values in my tests
I want to have my buttons look all the same style, so I will use the CSS class.
I don't want to assign a id to every single link, because some of them are perfectly identified through the container and the link class
Is there anything I missed in Cucumber/Webrat? Or do you have some advices to solve this in a better way?
Thanks for your help and best regards,
Joe
edit: I found an interesting discussion going on about this topic right here - seems to remain an open issue for now. Do you have any other solutions for this?
Here's how I did it with cucumber, hope it helps. The # in the step definition helps the CSS understand whats going on.
This only works with ID's not class names
Step Definition
Then /^(?:|I )should see ([^\"]*) within a div with id "([^\"]*)"$/ do |text, selector|
# checks for text within a specified div id
within "##{selector}" do |content|
if defined?(Spec::Rails::Matchers)
content.should contain(text)
else
hc = Webrat::Matchers::HasContent.new(text)
assert hc.matches?(content), hc.failure_message
end
end
end
Feature
Scenario Outline: Create Project
When I fill in name with <title>
And I select <data_type> from data_type
And I press "Create"
Then I should see <title> within a div with id "specifications"
Scenarios: Search Terms and Results
| data_type | title |
| Books | A Book Title |
Here is how to assert text within an element with the class name of "edit_botton"
Then I should see "Translation here" within "[#class='edit_button']"
How about find('a.some-class').click?
I'm not very familiar with the WebRat API, but what about using a DOM lookup to get the reference ID of the class that you are looking for then passing that to the click_link function?
Here's a link to some javascript to retrieve an item by class.
http://mykenta.blogspot.com/2007/10/getelementbyclass-revisited.html
Now that I think about it, what about using Javascript to just simply change it to some random ID then clicking that?
Either way, that should work until the frugal debate of a name to include the getbyclass function as is resolved.
Does have_tag work for you?
have_tag('a.edit_button')
Related
I need to extract a number from an HTML page and convert it into a variable in my test case.
The problem is that there is no ID directly to this element, here is the HTML code, I want to get the 54 (that number can change that's why I need to identificate him with another way), I tried Get Text by using "resultat" but I get "54 ligne(s) trouvée(s)" but I only want "54":
<div class="tab-interpage> == $0
<div class="resultat">
<b>54</b>
ligne(s) trouvée(s)
</div>
...
You have other options how to locate an element, see Locating elements section in Selenium Library.
This might be a situation that requires xPath, I can imagine this one works (but I don't see the whole DOM, so I can't be 100 % sure):
//div[#class="resultat"]/b
combined with the keyword:
${var}= Get Text //div[#class="resultat"]/b
Obviously if there're more div elements with class "resultat", you might run into problems here. In this case, explore the DOM a bit more and see what are some other ways you can get to the element you need.
I think it'd be much more readable if the HTML elements had proper attributes like:
form with class attribute
unique ids usually work best
I'm currently trying to do my first proper project outside of Codecademy/Baserails and could use some pointers. I'm using a scraper as part of one of the Baserails projects as a base to work from. My aim is to get the string "Palms Trax" and store it in array called DJ. I also wish to get the string "Solid Steel Radio Show" and store it in an array called source. My plan was to extract all the lines from the details section into a subarray and to then filter it into the DJ and Source arrays but if there is a better way of doing it please tell me. I've been trying various different combinations such as '.details none.li.div', 'ul details none.li.div.a' etc but can't seem to stumble on the right one. Also could someone please explain to me why the code
page.css('ol').each do |line|
subarray = line.text.strip.split(" - ")
end
only works if I declare the subarray earlier outside of the loop as in the Baserails project I am working from this did not seem to be the case.
Here is the relevant html:
<!-- Infos -->
<ul class="details none">
<li><span>Source</span><div> Solid Steel Radio Show</div></li>
<li><span>Date</span><div>2015.02.27</div></li>
<li><span>Artist</span><div>Palms Trax</div></li>
<li><span>Genres</span><div>Deep HouseExperimentalHouseMinimalTechno</div></li>
<li><span>Categories</span><div>Radio ShowsSolid Steel Radio Show</div></li>
<li><span>File Size</span><div> 135 MB</div></li>
<li><span>File Format</span><div> MP3 Stereo 44kHz 320Kbps</div></li>
</ul>
and my code so far:
require "open-uri"
require "nokogiri"
require "csv"
#store url to be scraped
url = "http://www.electronic-battle-weapons.com/mix/solid-steel-palms-trax/"
#parse the page
page = Nokogiri::HTML(open(url))
#initalize empty arrays
details = []
dj = []
source = []
artist = []
track = []
subarray =[]
#store data in arrays
page.css('ul details none.li.div').each do |line|
details = line.text.strip
end
puts details
page.css('ol').each do |line|
subarray = line.text.strip.split(" - ")
end
I'm Alex, one of the co-founders of BaseRails. Glad you're now starting to work on your own projects - that's the best way to start applying what you've learned. I thought I'd chip in and see if I can help out.
I'd try this:
page.css(ul.details.none li div a)
This will grab each of the <a> tags, and you'll be able to use .text to extract the text of the link (e.g. Solid Steel Radio Show, Palms Trax, etc). To understand the code above, remember that the . means "with a class called..." and a space means "that has the following nested inside".
So in English, "ul.details.none li div a" is translated to become "a <ul> tag with a class called "details" and another class called "none" that has an <li> tag nested inside, with a <div> tag nested inside that, with an <a> tag inside that. Try that out and see if you can then figure out how to filter the results into DJ, Source, etc.
Finally, I'm not sure why your subarray needs to be declared. It shouldn't need to be declared if that's the only context in which you're using it. FYI the reason why we don't need to declare it in the BaseRails course is because the .split function returns an array by default. It's unlike our name, price, and details arrays where we're using a different function (<<). The << function can be used in multiple contexts, so it's important that we make clear that we're using it to add elements to an array.
Hope that helps!
I'm looking to pull out all of the companies from this page (https://angel.co/finder#AL_claimed=true&AL_LocationTag=1849&render_tags=1) in plain text. I saw someone use the Chrome Developer Tools console to do this and was wondering if anyone could point me in the right direction?
TLDR; How do I use Chrome console to select and pull out some data from a URL?
Note: since jQuery is available on this page, I'll just go ahead and use it.
First of all, we need to select elements that we want, e.g. names of the companies. These are being kept on the list with ID startups_content, inside elements with class items in a field with class name. Therefore, selector for these can look like this:
$('#startups_content .items .name a')
As a result, we will get bunch of HTMLElements. Since we want a plain text we need to extract it from these HTMLElements by doing:
.map(function(idx, item){ return $(item).text(); }).toArray()
Which gives us an array of company names. However, lets make a single plain text list out of it:
.join('\n')
Connecting all the steps above we get:
$('#startups_content .items .name a').map(function(idx, item){ return $(item).text(); }).toArray().join('\n');
which should be executed in the DevTools console.
If you need some other data, e.g. company URLs, just follow the same steps as described above doing appropriate changes.
I am using selenium 2 (WebDriver).
I am locating a button and clicking by the script:
driver.findElement(By.cssSelector("button:contains('Run Query')"));
or
driver.findElement(By.cssSelector("css=.gwt-Button:contains('Run Query')"))
whose html is like :
<button type="button" class="gwt-Button" id="ext-gen362">Run Query</
button>
As the id is dynamically generated, I can't make use of the ID.
Is there any way to use cssSelector with something like contains ? Is this possible?
You can't do this with CSS selectors, because there is no such thing as :contains() in CSS. It was a proposal that was abandoned years ago.
If you want to select by the element text, you'll have use an XPath selector. Something like
driver.findelement(By.xpath("//button[contains(., 'Run Query']"))
or
driver.findelement(By.xpath("//[contains(concat(' ', #class, ' '), ' .gwt-Button ') and contains(., 'Run Query']"))
Another option is using jQuery, if it's present on the page, something like:
var webElement = ((JavascriptExecutor)driver).executeScript("return jQuery('button:contains(Run Query)')");
CSS alone will not get you what you need; you cannot filter by the text. You could either use js to get the id of the element, or loop through all the buttons in your code until you find the one with the right text. If this were in python:
[btn for btn in browser.find_elements_by_css_selector('button')
if 'Run Query' in btn.text]
You could easily generalize this and make a helper function, too.
I'm in the same boat, currently using XPath selectors with "contains" to find elements with specific text content. Some are <td> and some are <td><a> deep within large tables (specific columns, but row unknown in advance). It's very slow (4 to 5 seconds just to find such a table entry with Firefox 20), so I was hoping to use CSS to be faster. Often the text will be by itself (complete) and other times it will be a filename at the end of a path I'd like to ignore. Does anyone have suggestions for the fastest XPath search pattern, given that it's a known column but unknown row, and may be a <td> or <td><a> (sometimes in the same table). Would an equality comparison be much faster than contains(), for the majority of cases where the text I'm looking for is complete (not at the end of other text)? I think there's a "starts with" lookup, but is there an "ends with" lookup? I know that using an "id" would be even faster, but unfortunately this HTML doesn't have any IDs here, and they can't be added. I'm looking to find the <tr> containing this text so I can locate another element in the same row and get its text or click on a link. It doesn't hurt to locate a small subset of the rows and check their text, but I'd like to avoid doing separate searches for <td> and <td><a> if that's possible.
You cannot use contains but use a wild card instead.
driver.findElement(By.cssSelector("button:(*'Run Query'*)"));
driver.findElement("#ext-gen362").Where(webElement => webElement.Text.Contains("Run Query"))
We are using Specflow with Selenium Webdriver, using C# Step Definition files.
I am testing a web page where we have one h1 tag but multi h2 & h3 tags.
The test in Specflow is written thus:
Scenario Outline: The H1 displays the correct value
Given I view the page <page> at url <url>
Then the h1 will read h1
Examples:
| page| url | h1 |
| home| www.xyz.com | About xyz |
This test will be easy enough to run as there is only one h1 tag, and it should contain "About xyz".
But, the issue I have is that when testing for h2 & h3 tags, there are more than one of them, so am not sure how best to structure the test.
I could add multi h2 rows in the Examples table, but dont know how to code for this in the step definition file to assert the values. The test could fail as it cannot work out which h2 I need to validate, hence the question.
Any help is much appreciated.
I have searched in loads of places for this type of query but found nothing. It must be so easy that no-one else has a problem except me!!
Thanks
Steve
You could use the following to check if the h2 or h3 tag contains a certain phrase you're looking for:
driver.FindElement(By.XPath("//h2[contains(., 'TEXT')]"));
All you need to do is replace the 'TEXT' with the phrase you're looking for, and it will return the element you want to you.
For instance, if you wanted to find 'About xyz' in any h1 on the page:
driver.FindElement(By.XPath("//h1[contains(., 'About xyz')]"));
You could create a list of WebElements and use the driver.FindElements function so that you can create a collection of the headers on the page. At this point, you can reference which occurrence you want to interact with by including an index like [1] after the last ')' like so:
driver.FindElements(By.XPath("//h1[contains(., 'About xyz')]"))[3];
If you don't want to have multiple elements, you'll need to fine tune the details you're looking for.