app/assets/javascripts
directory. The directory structure is similar to a
Rails application as you can see below.
controllers/
helpers/
components/
models/
routes/
templates/
templates/components
views/
The one thing that is strange when using the gem for a UI only application is
that your app/
directory in Rails is basically unused except for the
app/assets/java
scripts/
where all the actual work will happen. Another
project, EmberAppkitRails, solves this issue by putting the app/
directory
into asset pipeline. This is an interesting idea. The gem is pre-1.0 so the
API could change.
Ember-rails also provides configuration variables for using the development or
production version of Ember depending on your current enviroment. This is nice
so that your Ember debug information is automatically removed in production.
App.User.FIXTURES = [
{
id: 1
email: 'user@example.com'
posts: [1, 3]
}
{
id: 2
email: 'secondUser@example.com'
posts: [2,4]
}
]
App.Post.Fixtures = [
{
id: 1
title: 'The Art of Vim'
user: 1
}
{
id: 2
title: '15 Minute Blog in EmberJS'
user: 2
}
]
There are downsides to this approach. The first one is the backfill process. We
waited too long in the project to connect our API to Ember and ran into issues.
The other problem is that by having the applications in two seperate repos, you
can’t easily have a full integration test. In order to do this you would need to
run both applications on the same machine simultaneously. You would also need
some way to make sure that both of the applications were on the same revision
for the test.
We decided to test the apps seperately and trust that the API is what we’ve said it was.
This can be frustrating but in our case, it didn’t turn out to be a real
problem. Once you have wired your API to the UI, you should never change your UI without also
changing the API. This was enforced in code review only.
fullName: (->
"#{@get('firstName')} #{@get('lastName')}"
).property('firstName', 'lastName')
rake
for our UI
application was 32.770 seconds including starting the Rails environment. The
suite had a total of 71 examples, most of which were feature specs.
Ember.Object
and it was easy to grab a controller in a test and verify that a
property works as expected. Because we wanted to use Mocha with Chai BDD
matchers instead of QUnit, the initial test setup was a bit complex but
after using Konacha with a Mocha adapter, it was smooth sailing. The
extra setup time for Mocha over QUnit was definitely worth it. The syntax has a
much more readable format.
describe 'AggregateStatsController', ->
describe 'summed properties', ->
beforeEach ->
stats = []
stats.push Ember.Object.create
clicks: 2
cost: 1.99
stats.push Ember.Object.create
clicks: 4
cost: 2.00
model = Ember.Object.create(dailyStats: stats)
controller = App.__container__.lookup('controller:aggregate_stat')
controller.set('model', model)
it 'will sum the number of clicks in the model', ->
expect(controller.get('clicks')).to.equal(6)
it 'will sum the cost in the model', ->
expect(controller.get('cost')).to.equal(3.99)
Feature specs were also very easy to handle. Ember has built in integration
test helpers that worked for most of our needs and we used jQuery to augment
them in our expectations. The specs were fast enough that we could test small
details in the interface that we might otherwise want to omit. Being able to
test all the UI interactions gave us a lot of faith in our codebase.
describe 'Navigating SEM Campaigns', ->
before ->
App.DailyStat.FIXTURES = [
{
id: 1
clicks: 11
}
{
id: 2
clicks: 10
}
]
App.SemCampaign.FIXTURES = [
{
id: 1
name: 'Opening Campaign'
status: 'active'
dailystats: [1]
}
{
id: 2
name: 'Final Sale'
status: 'active'
dailyStats: [2]
}
]
it 'shows the daily stats information for campaign', ->
visit('/').then ->
clickLink('SEM Campaigns').then ->
expect(pageTitleText()).to.equal('SEM Campaigns')
expect(pageHasCampaignWithTitle('Opening Campaign')).to.be.true
expect(statusFor('Opening Campaign')).to.equal('icon-active')
expect(clicksFor('Opening Campaign')).to.equal('11')
expect(pageHasCampaignWithTitle('Final Sale')).to.be.true
des
cribe
docstring as the name of the file.
In the case above our file would be named
navigating_sem_
campaigns_spec.js.coffee
. This worked out great and made it
much easier to find a failing spec.