As I occasionally mention, the original reason I built Faye was so I could control web browsers with Ruby. The end result was Terminus, a Capybara driver that controls real browsers. Since the last release, various improvements in Faye – including the extracted WebSocket module, removal of the Redis dependency and overall performance gains – have made various improvements to Terminus possible. Since Faye’s 0.8 release, I’ve been working on Terminus on-and-off and can now finally release version 0.4.
Terminus is a driver designed to control any browser on any device. To that end,
this release adds support for the headless PhantomJS browser, as well as
Android and IE8. In combination with the performance improvements, this makes
Terminus a great option for headless and mobile testing. The interesting thing
about Android and IE is that they do not support the document.evaluate()
method for querying the DOM using XPath, and Capybara gives XPath queries to the
driver to execute. In order to support these browsers, I had to write an XPath
library, and in order to get that done quickly I wrote a PEG parser
compiler. So that’s now three separate side projects that have sprung out of
Terminus – talk about yak shaving.
But the big change in 0.4 is speed: Terminus 0.4 runs the Capybara test suite 3
to 5 times faster than 0.3 did. It does this using some trickery from Jon
Leighton’s excellent Poltergeist dirver, which just got to 1.0. Here’s how
Terminus usually talks to the browser: first, the browser connects to a running
terminus
server using Faye, and sends ping messages to advertise its presence:
+---------+
| Browser |
+---------+
|
| ping
V
+---------+
| Server |
+---------+
When you start your tests, the Terminus library connects to the server, discovers which browsers exist, and sends instructions to them. The browser executes the instructions and sends the results back to the Terminus library via the server.
+---------+
| Browser |
+---------+
^ |
commands | | results
| V
+---------+ +-------+
| Server |< -------->| Tests |
+---------+ +-------+
As you can guess, the overhead of two socket connections and a pub/sub messaging
protocol makes this a little slow. This is where the Poltergeist trick comes in.
If the browser supports WebSocket, the Terminus library will boot a blocking
WebSocket server in your test process, and wait for the browser to connect to
it. It can then use this socket to perform request/response to the browser – it
sends a message over the socket and blocks until the browser sends a response.
This turns out to be much faster than using Faye and running sleep()
in a loop
until a result arrives.
+---------+
| Browser |< -------------+
+---------+ |
^ | | queries
commands | | results |
| V V
+---------+ +-------+
| Server |< -------->| Tests |
+---------+ +-------+
The Faye connection is still used to advertise the browser’s existence and to bootstrap the connection, since it’s guaranteed to work whatever browser or network you’re on.
The cool thing about this is that Jon’s code reuses the Faye::WebSocket
protocol parser, supporting both hixie-76 and hybi protocols, on a totally
different I/O stack. Though Faye::WebSocket
is written for EventMachine, I did
try to keep the parser decoupled but had never actually tried to use it
elsewhere, so it’s really nice to see it used like this.
Anyway, if you’re curious about Terminus you can find out more on the website.