Integration testing with RSpec and RestClient

 

I’ve been working on an application that needs to retrieve data from a web service on a regular basis and then update models in my database based on that data.

Ruby has built in support for making HTTP requests but it is quite low level, so I’ve been using the RestClient gem to make things a little easier for myself.

However I needed to be able to test this code, and I needed to make my web services queries deterministic so that I could create assertions based on the results of the processing.

The easiest way I could find to do that was to mock out RestClient with an RSpec mock. Then when the code under test made a query to the web service, the mock would instead return the contents of a file as the web service response.  I could then write assertions for the system under test. Here’s the code snippets that make it all work.

 

 

Advertisements
Posted in Uncategorized | Tagged , , , , | Leave a comment

Determining the current path in Ember.js

Do you want to know the current path in your Ember.js app? This was asked on Stack Overflow recently and I thought it was a neat trick.

Now you can access your current path from anywhere with:

Posted in Uncategorized | Tagged , , | Leave a comment

Getting started with integration testing ember.js using ember-testing and qunit-rails

Ember-testing is a recent addition to the Ember.js framework that allows you to create integration tests for your app using a custom DSL for interacting with your async Ember.js app. We’re going to walk through how to write integration tests with ember-testing using the qunit-rails gem.

Lets all take a moment to thank Erik Bryn  who did the lions share of the work on ember-testing. You can see him talking about it over here with slides and an example app

Lets assume that we have a small library of books and we’ve written an app to keep track of them. The app simply allows us to save some basic details about each book and allocate tags. It didn’t take long to get the app up and running but we’re in the wild west of coding with no tests and the librarian is concerned that the app might have bugs in it. We need to prove it works.

One of the best things about the qunit-rails gem is that you can see the integration tests being run right in front of you. Not only will you see the library app in the bottom right corner of the page but you will see integration tests being run against that instance.  You can see the tests in action below or run them yourself here. Excited yet? I know I was.

emberTesting_converted

To get the started you need to add the qunit-rails to your Gemfile, install your bundle and run the following generator to create the qunit test-helper. You can add a -c param if you’re into coffeescript.

This will generate a test_helper.js file in /test/javascripts but we are going to replace that default with the following one that I ripped off from Eriks example app

This prepares the Ember.js app for testing and renders it into a div in the bottom right corner of the test page as well as declaring a useful helper function to determine whether elements exist in the application.

Lets create very simple test file at /test/javascripts/integration/booksTest.js

This declares a module with one test, which loads the root url of the app and checks that something/anything is returned.

If you’re following along you can fire up your rails server now and browse to localhost:3000/qunit . You should see a single test that has been run and your app in the bottom right hand corner.

Thats all the setup done. Now lets build up the suite of integration tests but first lets talk about that simple test. Qunit allows you to define a module which groups similar tests together. At the moment we have one module and one test. The setup and teardown functions are called by qunit before and after EACH test in the module. In the setup function we  tell the Ember.js app to move into a ready state and in the teardown function we reset Ember.App after each test as described here.

The actual test calls visit(“/”) to retrieve the home page and then asserts that the app has indeed returned something, but what are all these functions?

  • The visit function belongs to the ember-testing DSL, It tells the test to load a url in the app. There a few other ember-testing DSL functions…I’ll talk about them later.
  • The ok function is a qunit assertion which checks that the boolean condition passed to it evaluates to true. You can find more qunit assertions here
  • The exists function takes a jQuery selector and returns true if it exists and throws an exception if it doesn’t. We defined it in the test_helper.js class up above

On line 12 in the simple test above we use the visit function to retrieve the root url of the app. This is followed by a call to the then function with an anonymous function describing the test. The visit function is a promise. This means that once the contents of that url have been retrieved or the promise fulfilled, then the anonymous function will be executed. We will continue to use this pattern for the tests.

The Ember-testing DSL currently consists of the following functions:

  • visit (url): This will point the ember application to the specified url
  • click (selector, context): This will click the element described by the jQuery selector. A context for the jQuery selector can also optionally be supplied
  • fillIn (selector, context, text): This will update the value of the element described by the jQuery selector with the supplied text. A context for the selector can be optionally supplied.
  • find (selector, context):  This will retrieve the element identifie by the jQuery selector. A context for the selector can be optionally supplied.

So.. we have an ember-testing DSL for interacting with the app under test and some qunit assertions to check that the behaviour is as expected. Lets write some tests!… We’ll start off with a test to make sure that the contents of the Library is as expected:

The first thing we do in this test is we tell qunit to expect 6 assertions. Then we vist the root url / home pag and check that the Nav bar div element is present and that the search button was rendered.

Next up we click the search button and pass in an anonymous function to continue testing the results page once the App is ready. Note how easy it is to deal with th async nature of our Ember.js applications.

We then confirm that the library has three books in it and that the three titles correspond to our seed data, which is really just the set of fixtures being accessed via the ember-data fixture adapter.

So far we’ve used the visit, click and find functions from the ember-testing DSL. Lets write a test to edit the title of a book in the library so that we can use the fillIn function.

In this test, we search for all the books in the library and then check that there is no book called ‘The Great Modification’. We use the qunit throws assertion to ensure that an exception is thrown when we attempt to find a search result with this title.

We then click the link on the book ‘The Great Gatsby’ and load up the show page where we check that the book has the correct tags associated with it and then click the link to edit the book.

Now, on the edit page we check that the book still has the correct title ‘The Great Gatsby’. This is contained in the input box with class ‘titleInputBox’ in the div with class ‘editBook’

We then use the fillIn function to change the value of the input box to the new title ‘The Great Modification’, and for the sake of rigour we validate that this input box now has been indeed been changed to the new title. Happy with this we click the button to save changes to the book and then click the search button again.

Lastly we confirm that ‘The Great Gatsby’ is no longer in the search results, but ‘The Great Modification is.

Success! If you haven’t done so yet, why not try and interact with the application in the bottom right hand corner. You will see the modified book there. The app is fully functional just scaled down in size.

In case you are wondering why the modified title is still there, despite us calling App.reset() in the teardown() function.. it is because only the Ember app is reset. This example has been configured to use the FixtureAdapter from ember-data which is not reset. If you reload the page, the results will revert to the seed defined as fixtures and the tests will pass again.

Ember-data is completely optional for creating ember-testing integration tests. I just found it useful to use the FixtureAdapter to create the seed data. You could use the RestAdapter if you wanted your integration tests to go all the way down to the server and database, but then you would need to come up with a mechanism for ensuring that your data is in a consistent state when you start running the tests.

Hopefully this will get you up and running with ember-testing. Good luck!

The source code for the rails app and tests is available here

Posted in Uncategorized | Tagged , , , , , , , , | 8 Comments

Filtering a set of objects for display in Ember.js

A pretty standard use case in web development in to display a list of objects filtered by some kind of criteria. This is really easy to do in Ember.js using the filterProperty function from the Ember.Enumerable mixin, which is mixed into the DS.RecordArray and DS.AdapterPopulatedRecordArray classes. These are the array implementations returned by DS.Model.find() and DS.Model.find({key: value}) respectively, as well as DS.hasMany associations.

So lets assume that you have a CategoriesRoute which retrieves the array of all Categories from the server in the model function. Something like:

A simplistic implementation would simply list all of the categories on the page, but we would like to filter the result set in the browser based on the name of the category. Our handlebars template for these two cases would look like:

Now we need to add the function to the controller which will sort the categories. We have decided that we want to filter by the name of the category. 

We are calling the filterProperty function on the model for this controller, which was set to App.Category.find() by the route. We are passing in two parameters:

  1. The name of the property on the App.Category object that we are going to filter against, we are filtering against the nameLowerCase property.
  2. The actual value to filter against. Any App.Category instances with a nameLowerCase property matching the filter string will be part of the filtered results. 

In addition we have defined the filteredCategories function to be a property of the App.Categories controller. Since it is observing ‘model.@each.nameLowerCase’, this filtered result set will be re-evaluated everytime the lowerCaseName of an App.Category in the controller model changes.

However we have one complication. Our App.Category models only have a name property, which can be a mix of uppercase or lowercase, so we define a nameLowerCase property on the App.Category model which we can filter against. Note that you filter against any property of an Ember.Object or DS.Model..

 

 

 

 

Posted in Uncategorized | Tagged , , | 3 Comments

Ensure your Ember templates get the correct name when pre-compiling in the Rake pipeline using Barber

I’ve been using Rake Pipeline as the build tool of choice for my Ember Phonegap Starter kit and making use of the Barber gem to pre-compile my Ember templates.

Today I ran into a problem where my templates were being compiled but they weren’t being given relative names if they were located in folders, so a template found at post/details.hbs was being inserted into Ember.TEMPLATES[‘details’] instead of Ember.TEMPLATES[‘post/details’]

Luckily, Adam Hawkins, was able to help me out, pointing out that I needed to supply a template name proc. The default is to use the absolute file name as shown here

My template files are all located in the ‘templates’ folder, so I modified my Assetfile to match handlebars templates and pre-compile them using the following instruction

And here is the proc that will ensure your Ember templates are named correctly, stripping out the top level ‘templates’ folder but keeping the rest of the structure in the template name if it is present

Posted in Uncategorized | Tagged , , , , , , , , , | Leave a comment

Getting google maps to work in a PhoneGap app on iOS

The Google maps guides should be enough to enable you to get a PhoneGap up and running with a Google Map however there are two gotchas that you should be aware of:

1) The div that hosts your map needs to have a real size. Initially I had set my div to have a height of 50% and width of 50% and although the map was being created it was 0 x 0 pixels so I couldn’t see it. Set your width or height on the containing div so that the map actually has space to render into.

2) Once I had the map running in my browser, I tried it out the iOS emulator and although the initial map would load, I was unable to interact with… No scrolling, zooming or swiping. Turns out that by default iOS will block access to external hosts so you need to add the following three hosts to the ExternalHosts property of your iOS project plist file.

Open your plist file, located in the Resources folder of your iOS wrapper app. If you don’t have a key called ‘ExternalHosts’ then add one. It should be of type Array. The three hosts should be added as entries in the Array. See the screenshot below of what my plist file looks like.

Image

Once I’d added this I was able to interact with the map through my iOS device.

Posted in Uncategorized | Tagged , , , , | 2 Comments

Clickable table rows in Ember.js

As pointed out in this Github issue, it is quite easy to wrap a make a table row clickable in Ember.js. https://github.com/jonnii  supplied this code snippet which allows you to make a whole row clickable for a {{#linkTo}} destination while still including buttons or links in that row with other targets. Check it out:

According to the guides, the {#action}} helper will propagate the event by default to the parent DOM nodes, so you need to add bubbles=false to the button, if you only want that button action to be executed.

Posted in Uncategorized | Leave a comment

Configuring Ember-Data to sideload relationships

When you first start using Ember-Data its pretty nifty to see your application making JSON requests to create/read/update your entities but at some point you might want to cut down on the number of requests that your Ember app is making to the server. One technique for doing this is to sideload your associations.

So if you’ve got a User entity which has many opinons, you can include the opinions in the /users/<id> response, instead of simply returning the user with ids for the opinions which would cause your application to create new requests for each of the opinions.

First you need to configure your RESTAdapter to expect these opinions in sideloaded form:

Your Ember-data User model should look like:

Now, if you have a Rails back-end and you’re using the Active Model Serializers gem, you can simply modify the UserSerializer to include the Opinions in the User response.

assuming that you have a User Model with a has_many association to the Opinion model.

Posted in Uncategorized | Tagged , , , , | Leave a comment

Ember.js commit starlog

I’ve been heavily inspired by Ember.js recently, so I was thrilled to see that you can catch up on the Ember.js github commits in a unique format inspired by Star wars.

Ember.js commit starlog

Posted in Uncategorized | Tagged , | Leave a comment

Problems deploying to Heroku with ember-rails

I’m using ember rails on one of my projects. Its a great way to build a ember.js based application with a Rails back-end. 

This morning I was trying to deploy to my efforts to Heroku but was running into the following error message:

Running: rake assets:precompile
rake aborted!
couldn’t find file ‘handlebars’
(in /tmp/build_ygdi06vxs1tz/app/assets/javascripts/application.js:15)
/tmp/build_ygdi06vxs1tz/vendor/bundle/ruby/1.9.1/gems/sprockets-2.2.2/lib/sprockets/context.rb:102:in `resolve’

 

Turns out the problem is because I hadn’t specified the ember variant. So if you run into something similar  make sure that your development.rb file contains:

config.ember.variant = :development

And your production.rb files contains:

config.ember.variant = :production

 

Problem solved

Posted in Uncategorized | Leave a comment