Description
Natritmeyer,
I started using SitePrism fairly recently to rewrite existing Capybara tests in order to abstract page element locators from the individual test cases. In the relatively short time I have been working with it, I have found myself working around a number of test failures as a result of SitePrism explicitly overriding capybara's implicit wait functionality, and not passing through a sufficient amount of Capybara behavior to implement various Capybara search options in the tests.
Given that SitePrism is a wrapper for Capybara, I would expect that SitePrism would do its best to mimic and/or passthrough the default Capybara behavior wherever possible rather than replace it.
The biggest issue I have seen with Prism is its override of the Capybara implicit wait in methods such as has_#{elementname}?
. This goes against the default Capybara behavior. See this article about why wait_until was removed from Capybara 2.0: http://www.elabs.se/blog/53-why-wait_until-was-removed-from-capybara Capybara's implicit waits are good and SitePrism shouldn't be overriding them without explicitly being told to by the tester.
Take for example this snippet of test code (this is a fabricated example to demonstrate a few different potential pitfalls of SitePrism):
feature 'My Index Page', js: true do
scenario 'displays a list of articles' do
my_index_page.load
# See Issue 1 below
campaigns_page.should have_articles
end
scenario 'displays multiple pages of articles' do
my_index_page.load
# This line does take advantage of capybara's implicit waits because current_page returns a capybara object:
my_index_page.pagination.current_page.should have_content "Page 1 of 3"
my_index_page.pagination.last_page_link.click
# See Issue #2 below
my_index_page.should be_displayed
# See Issue #3 below
my_index_page.articles.count.should eql 25
end
end
Issue 1
If an element or section takes time to appear after page load, the method page.has_element_name?
will fail because it explicitly sets capybara's wait for the block to 0, rather than allowing Capybara's implicit waiting behavior to pass through to SitePrism's behavior.
Issue 2
This issue is already addressed in PR #40 but is listed here for convenience.
page.displayed?
fails because displayed? has no implicit wait, so if an action causes the page to redirect, then displayed? fails on the next expected page because the method hits a race condition between when the prior action occurred and when the next page is actually loaded in the browser.
Issue 3
We are not able to pass advanced Capybara selectors through site prism objects when attempting to access them.
The common example for this is, as in the above example, expecting some count of an elements or sections array to be returned. In the above case, we expect the count to equal 25; however, this presumes that when the my_index_page.articles
array is returned that all 25 articles have already finished loading. With capybara we could tell it to expect 25 articles with the :count => 25
filter; however, with SitePrism this is not possible without predefining it in our page file; however, it is not always possible how many elements to expect in an array when the element object is created in the Page class, and it makes that element extremely inflexible when the number of elements returned are the dynamic result of something like a database query.
It would be ideal to be able to supply a base locator in the Page class when the element/section is defined, and when we later access that element/section to be able to supply additional capybara filters. For example:
page.should have_articles(:count => 25)
In this case the count filter should be appended to the default search parameters for the element and passed through to Capybara to ensure it implicitly waits for 25 articles to be displayed.