Symbiont Now Supports Capybara

Since its inception my Symbiont framework has provided a wrapper for Watir WebDriver, which in turn provides a wrapper for Selenium WebDriver. One of the other major libraries out there that wraps Selenium is called Capybara. I wanted to see what kind of support I could provide for that. In this post I’ll cover these changes.

I will note that supporting both the Watir and Capybara APIs is an interesting exercise and perhaps even a questionable one from a design perspective. I’ve very cognizant of my findings in my previous, now defunct, Dialect experiment. Time will tell if I’ve learned anything or, once again, said “Screw you, experience!”

I have plenty of posts on Symbiont so if you haven’t already played around with it, likely this post will mean little to you. If you have played around with Symbiont already, then you definitely have the environment you need. Here I’ll take you through some working examples so feel free to play along.

Page Objects with Capybara

First, of course, make sure that you update your gem:

gem install symbiont

Now create a script file, symbiont-script.rb or whatever you want to name it. Just as you do with the Watir approach, you can simply require Symbiont in your script:

Symbiont is predicated upon the page object pattern and that is applied whether you are using Capybara or Watir. How you define the page objects is largely identical in structure but different in implementation. Here is what you can add to the script:

This is the same as the Watir approach structurally. But there are some differences. The Watir approach works by having Symbiont treated as a mix-in and thus gets included (or attached) to the page class. The Capybara approach, as you can see, requires you to make your page class an instance of Symbiont::Page.

For the element definitions, with the Watir approach while you could use element as shown there, you generally use the type of the element. Further, Capybara defaults to using CSS selectors although you can use XPath as well. So, for example, the open_form element definition could be done like this with Capybara:

Just to give you a comparison, here is how the page definition would look with the Watir approach:

The Browser Driver

To start things off you need to establish a browser driver. With the Watir approach you do this:

This defaults to using the built-in browser driver for Watir+Selenium, which is Firefox, but you can change that to do this:

The Capybara approach is initially a little more complicated but it also does offer a great deal of modularity. Capybara requires you to configure drivers. So to get the script to work, you would put this in place:

Here this defaults to using the built-in browser driver for Capybara+Selenium which, just like in the Watir case, is Firefox. In Capybara, I could change what browser the :selenium references by registering a driver like this:

I want to point out one thing here before moving on. As with the Watir version, with the Capybara version you can specify a URL for a page definition. If you’ve set Capybara’s app_host then you can set the URL as relative to that domain. For example, change the configuration accordingly:

Now you can change the url_is assertion to this:

Because the application host has been set, this means your page URLs can be stated relative to that host location.

Once you have you browser driver configured, you simply instantiate the page object.

Because I jumped around with code examples there between Watir and Capybar, here is what your script should look like:

As you can tell, it’s not terribly different from the Watir version. I’ve tried to keep the basic structural dynamics in place for how the page definition, and the element definitions within it, are set up.

Now let’s actually log in to the application. The code for this is identical to that which you would do for the Watir approach. Add the following to the end of your script:

Here I’m just showing how you can reference the elements on the page object but, as with the Watir approach, you can certainly call the handy login_as_admin method I placed on the page object, which wraps up all those individual actions. So change the executable portion of your script to:

You might notice that the view is a bit of an extraneous bit. You can remove that by calling a perform action on the page itself:

Just to be complete, you can also do something like this:

… or …

or even just this

Keep in mind here, however, that you are not capturing the @page instance variable in these last examples. If you don’t need it, then these various shortcuts can potentially be useful to you.

Context Factory for Page Objects

As with the Watir approach, you can use a context factory. You have to include it. So add the following line at the top of your script:

With that you can do this:

Now, this may look similar to what you saw before:

However you should notice that the context factory keeps the @page instance variable reference. You can also call the page object method directly from the factory, like this:

Another thing you can do is call blocks on the page object. Here’s an example:

As you can see there is a lot of flexibility in approach. Some of this is a bit more flexible than my current Watir-based approach.

State and Existence on Page Objects

As with the Watir approach, you can get information about the page or the state of the page. Consider the following:

You can check if the page is displayed and if it’s secure (should the latter be necessary for you):

All those statements will do is display true or false but won’t actually cause an exception of any sort. If you include RSpec as part of your script you can also use nice expectations with predicate methods like displayed? and secure?. For example, if you add the following to the top of your script:

Then you could do this:

Either one of those would work and do the same thing but notice how the second reads a bit nicer due to how RSpec handles predicate methods. You could also check for the opposite condition:

Now let’s play around with a page. We already have a page object so let’s get a representation for an element if that element exists on the page:

That simply returns an object representation of the open_form element. That’s not always terribly useful by itself but something that is useful is that you can check if an element exists:

Notice that because this is a predicate method (has_open_form?), you can use expectations to make the code read a little nicer:

You can also check for non-existence:

More To Come

What I showed you here is how you can use Symbiont with Capybara and have much of this look very similar to using the Watir approach. What I haven’t shown you here is that just as Symbiont delegates down to Watir, it also delegates down to Capybara. What this means is that you have the full power of both APIs available to you.

I’m pretty excited about this evolution of Symbiont but there’s a lot more work to do, including on documentation. All of that will be coming soon.

About Jeff Nyman

Anything I put here is an approximation of the truth. You're getting a particular view of myself ... and it's the view I'm choosing to present to you. If you've never met me before in person, please realize I'm not the same in person as I am in writing. That's because I can only put part of myself down into words. If you have met me before in person then I'd ask you to consider that the view you've formed that way and the view you come to by reading what I say here may, in fact, both be true. I'd advise that you not automatically discard either viewpoint when they conflict or accept either as truth when they agree.
This entry was posted in Automation, Symbiont. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *