However, the page object frameworks have placed an item on the backburner. I'm not sure why it is, but the concept of repeating items inside of a page has been ignored at this point. Let's say you have a website like Google Finance. The list of news items is a great example of a what I'm calling a PagePart.
PageParts are items that repeat themselves on a page in terms of content types. They repeat with different content depending upon the user who is logged in, but they all look the same semantically. Here's what a Google Finance News item looks like:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="cluster"> | |
<div> | |
<a class="title" href="http://www.smh.com.au/world/us-not-out-of-the-woods-yet-despite-deal-to-avert-default-20110801-1i8bt.html?from=smh_sb" rel="nofollow" id="n-hp-">US not out of the woods yet, despite deal to avert default</a> | |
</div> | |
<div class="byline"> | |
<span class="src">Sydney Morning Herald</span> | |
<span class="date" tm="1312209001"> - 17 minutes ago</span></div> | |
<!-- google_ad_section_end --> | |
<div class="snippet">A deal may have been reached but the US still faces some tough economic hurdles. Photo: AFP THE US could still lose its coveted AAA credit rating in coming months despite a last-minute deal struck yesterday between the White House and Republicans that ...</div> | |
<!-- google_ad_section_start --> | |
</div> | |
</div> |
There are four of these items wrapped in a div with market-news-stream as it's id.
Without PageParts you might do this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'watir-page-helper' | |
class GoogleFinance | |
include WatirPageHelper | |
div :news_items, :id => "market-news-stream" | |
def initialize(browser) | |
@browser = browser | |
end | |
def news_item(index) | |
news_items_div.divs[index] | |
end | |
def news_link(index) | |
news_link_link(index).click | |
end | |
def news_link_link(index) | |
news_item(index).a | |
end | |
def news_snippet_div_div(index) | |
news_item(index).div(:class, "snippet") | |
end | |
def news_snippet_div(index) | |
news_snippet_div_div(index).text | |
end | |
end |
So how do we identify these items in the tests? When I first started tackling this sort of problem on my current project I had pass through methods inside my PageObject that went to a simple PagePart. This worked, but didn't give me the cool features of the PageObject frameworks, and wasn't that the whole point of adopting the framework?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'watir-page-helper' | |
class GoogleFinance | |
include WatirPageHelper | |
div :news_items, :id => "market-news-stream" | |
def initialize(browser) | |
@browser = browser | |
end | |
def news_item(index) | |
GoogleFinancePart.new(news_items_div.divs[index]) | |
end | |
def news_link(index) | |
news_link_link(index).click | |
end | |
def news_link_link(index) | |
news_item(index).a | |
end | |
def news_snippet_div_div(index) | |
news_item(index).div(:class, "snippet") | |
end | |
def news_snippet_div(index) | |
news_snippet_div_div(index).text | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class GoogleFinancePart | |
def initialize(div) | |
@news_item = div | |
end | |
def news_link | |
news_link_link.click | |
end | |
def news_link_link | |
@news_item.a | |
end | |
def news_snippet_div_div | |
@news_item.div(:class, "snippet") | |
end | |
def news_snippet_div | |
news_snippet_div_div.text | |
end | |
end |
Wow, this is more complex than not using page parts.
So, how exactly is this better? It's better when you convert your page parts to use the PageObject framework. Caveat, I do not know how you would do this in Cheezy's PageObjects gem, but it works just fine in the watir-page-helper gem:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'watir-page-helper' | |
class BasePart | |
include WatirPageHelper | |
attr_reader :part_key | |
def initialize(browser, part_key) | |
@part_key = part_key | |
@browser = part_div(browser, part_key) | |
end | |
def part_div(browser, part_key) | |
raise 'this method should be overridden and return the HTML element that holds the page part' | |
end | |
end |
Every PagePart extends the BasePart. You'll select your container div in your PagePart object using the part_div method. Obviously this could be any HTML element, but it's most likely to be a div. Since the BasePart will redefine @browser with the div, we'll be able to use the cool shorthand, rather than define every method we might need:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class GoogleFinancePart < BasePart | |
link :news_link, :index => 0 | |
div :news_snippet, :class => "snippet" | |
def initialize(browser, index) | |
super(browser, index) | |
end | |
def part_div(browser, index) | |
browser.div(:id, "market-news-stream").divs[index] | |
end | |
end |
The example may seem a bit contrived, but, maybe you're not working with an interface as clean as Google Finance. If you are, you might get some benefit out of using PageParts.