I recently had to write a small capybara helper:
def without_page_refresh page.execute_script("window._withoutPageRefresh = 'BAM'") yield page.evaluate_script("window._withoutPageRefresh").should == "BAM", "Page was navigated away" end
Ask for Help
"Pie-clearfix behaves differently on heroku vs. locally."
Compressing assets? Compressing locally? Try with a proxy? IE stylesheet limitations?
"Rails 3.1.1 asset pipeline not compiling images. Before the 3.1.1 upgrade, images were compiling correctly. After the upgrade, images do not compile"
"How can we test subdomain behavior in Selenium?"
Try lvh.me. lvh.me is a domain that points to your local virtual host. nslookup for lvh.me shows the address as 127.0.0.1.
- Dance party in design area sometime between 3-5pm
Ask for Help
"Anyone using Selenium 2 and Webdriver?"
One of our internal projects is using it.
"How to stop time in Jasmine?"
There were a couple suggestions:
- use a global function, such as 'now'
- send in your own clock object
"Whurl standalone, or more dynos?"
Apparently Whurl is running on a single dyno at Heroku, so a single bad request can tie up Whurl until the request times out. Where are you TildeWill?
"What's this called?"
Imagin these are records in a relational database, with the records on the left having a one to many relationship with the records on the right. How would you google this?
Is there a way to get MySql indexing to speed up queries involving greater and less than operators on date columns?
Postgres handles these operators a little bit better than MySql, but may not actually solve this problem.
Using millis instead of dates would give the DB the best chance of handling this scenario.
We are using Git's subtree merge facility instead of submodules to stay synced to a different repository for part of our project. How do we push changes back to that repo?
See Tim Connor's blog post "Git sub-tree merging back to the subtree for pushing to an upstream". Early in that post is a pointer to an article describing the the subtree merge operation. Tim goes on to explain how to push your changes back through the chain.
Some cloud environments leave the names of temp files visible even when their contents are not accessible. Be sure to use obfuscated names for your temporary files!
The "Headless" gem allows you to easily set up an alternate "display" that allows programs to execute in a headless environment. See this blog post about how to use Headless to run Selenium tests on a CI box: http://www.aentos.com/blog/easy-setup-your-cucumber-scenarios-using-headless-gem-run-selenium-your-ci-server
Ccrb will bog down to painfully slow levels if more than a couple of CC Tray clients are pinging it repeatedly during a build.
Cron will not honor your .rvmrc file unless you do some work to set up the environment. If you set up your cron job like this:
0 6 * * * /bin/bash -l -c 'echo /home/someuser/.rvm/bin/rvm rvmrc trust ... && cd ...
the -l & -c parameters cause bash to load your environment as if your were logging in before running the specified commands. Someone also mentioned that rvm-shell can be used as a solution to this problem.
Selenium removes the If-Modified-Since header. This gets in your way if you are testing ETags.
Speaking of ETags - they are awesome. See Ryan Daigle's article for code.
Just how slow is Mongrel when serving static images?
The answer is - pretty slow. The reason for the question was that Google's crawler tends to keep a single connection open and fire lots and lots of http requests over a period of several hours. With a standard Nginx/Mongrel setup, this would tie up a mongrel for this entire period.
A proposed solution to this problem is to use HAProxy between Nginx and Mongrel.
Here's the gist of this post: gist.github.com/58876
To use it with Cucumber, do like so:
World do |world| world.extend(SeleniumHelpers) world end
To use it with POS, do like so:
that it's always going to return a
String, so you may have to massage the output
While Webrat's DSL for traversing web apps is awesome, I've always found the
alternatives (Polonium for example) to not jive well with how I think. They're
way better than talking directly to Selenium, you're still locked in to a certain
fit your own style.
Now you can write your tests like so:
Credit should go to Brian Takita, since he did most of the hard work and I just wrote a method. Let me know if you have any issues or ideas with the helper, and may all your tests be green.
- Using 'require' explicitly interferes with class reloading in Rails
Frederick Cheung discusses this in more detail here. This might be related to the Selenium + class reloading issues some pivots have experienced in recent weeks. The alternative is to rely on Rails automagic loading or 'require_dependency'.
- acts_as_fu makes writing database independent tests for models is easier
Props to pivot Pat Nakajima for creating acts_as_fu.
Ask for Help
"How big should a typical mongrel be? Ours is starting out at over 200 megs but is not leaking from that point."
Everyone agreed that 50MB to 70MB is standard and anything over 100MB is considered pretty big. People suggested RubyProf for inspecting object counts and possibly tracking down the memory hogging code.
"What pattern does everyone use for non-model Reports with ActiveRecord? We are trying to create a report that counts a single model and groups by two associated models"
There was consensus around modeling a distinct report object and calling the referenced models. For example, FooReport and FooReportController fit nicely in a RESTful Rails world.
Regular Selenium tests (in Java) might look like:
selenium.open("/login"); selenium.type("id=username", "bob"); selenium.type("id=password", "password"); selenium.click("Login"); selenium.waitForPageToLoad(); selenium.click("My Account"); selenium.waitForPageToLoad(); assertEquals("bob", selenium.getText("//table/tr/td/");
After a few tests, this kind of thing becomes painful to manage. The typical solution is to create a bunch of constants for IDs and Xpaths, but that doesn't help too much.
Fellow Pivot Mike Grafton came up with a cool pattern for improving on this. The idea is to create a class representing each page of your web app. Each class contains two types of methods: a bunch of action methods (
typeUsername()), and a bunch of inspection commands (
When an action takes you to a new page, the corresponding action method returns a new class representing that page. When it stays on the same page, the method just returns "this". This allows methods to be chained to make the tests more readable.
Here's how that test would look using this new pattern:
MyAccountPage myAccountPage = new LoginPage(selenium) .typeUsername("bob") .typePassword("password") .clickLoginButton() .clickMyAccountLink(); assertEquals("bob", myAccountPage.getLoggedInUsername());
The constructor of each page class should validate that it's on the correct page (waiting if necessary, and perhaps asserting on the page title).
Ask for Help
It was suggested that perhaps this is a timing issue. Maybe some required JS for the form hasn't loaded before Selenium is trying the event.
One workaround would be to test only the form submission called by on-click instead of the click itself.