by

Upgrading to Ember 2.x

As part of my effort to learn Ember.js, I built a relatively simple app that used the TFL API to fetch bus arrival times at nearby stops. It can also do tube, DLR and overground, and eventually I may include other means of transport. It’s called London Waits.

All this was built in Ember 1.13, and only now I decided to upgrade it to Ember 2. It wasn’t trivial, but in the process I gathered some notes that may help others.

Ember 2.0: initial upgrades

I started by upgrading Ember proper to 2.0.x. This can be done with Bower:

1$ bower install ember#2.0.x --save

There was immediately a problem. When I run the app, it complained that it required a more recent version of jQuery:

1Error: Assertion Failed: Ember Views require jQuery between 1.7 and 2.1

I did as told:

1$ bower install jquery#2.1.x --save

This got my tests passing again, so I proceeded to upgrade Ember Data. Now, before version 2.3, Ember Data had both an npm module and a Bower component, and both were required. I’m not entirely sure, but I think the npm module provided CLI tools, whereas the Bower package provided the library proper. In fact, try upgrading the npm package only first:

1$ npm install [email protected] --save-dev

My tests pass after that, but the debug messages in the console reveal that I’m still using an old version of Ember Data:

1DEBUG: -------------------------------
2DEBUG: Ember      : 2.0.3
3DEBUG: Ember Data : 1.13.15
4DEBUG: jQuery     : 2.1.4
5DEBUG: -------------------------------

This is fixed by installing the Bower package. Pay special attention to the fact that the version comes after a ‘#’, not an ‘@’, and that the dependency is saved with runtime packages --save, instead of development packages --save-dev. Easy to miss!

1$ bower install ember-data#2.0.x --save

My tests were passing and I was on Ember 2. Yay!

Ember 2.1: problems with error routes

Carrying on with the upgrade, I went for Ember 2.1. It should be just a matter of upgrading the package, right?

1$ bower install ember#2.1.x --save

However, one of my tests stopped working: one that ensured that the app rendered an error route correctly. After some online research, I discovered that this indeed stopped working in the run up to 2.1, and there seems to be no official support. I was rather bummed by this, but fortunately I found a workaround in a thread discussing this issue on GitHub.

I generalised the workaround into a helper and published it as a GitHub Gist, although the example provided has some additional changes that we’ll get to later in this writeup. Right now, for the code just as it was upgraded from 1.13, the example should look like this:

 1/// tests/acceptance/errors-test.js
 2import Ember from 'ember';
 3import { module, test } from 'qunit';
 4import startApp from 'london-waits/tests/helpers/start-app';
 5import errorStateWorkaround from 'london-waits/tests/helpers/error-state-workaround';
 6
 7module("Acceptance | errors", {
 8  beforeEach: function() {
 9    this.application = startApp();
10    errorStateWorkaround.setup(err => {
11      // Return `true` if `err` is the error
12      // we expect, and `false` otherwise
13    });
14  },
15
16  afterEach: function() {
17    errorStateWorkaround.teardown();
18    Ember.run(this.application, 'destroy');
19  },
20});
21
22test("Something that lands an error", function(assert) {
23  // Do something that would get the user to
24  // an error route or substate
25
26  andThen(function() {
27    // Assert that the error has ocurred as expected
28  });
29});

After that, I got my tests passing. Now it’s time to upgrade Ember Data:

1$ npm install [email protected] --save-dev
2$ bower install ember-data#2.1.x --save

And that’s all for 2.1.

Ember 2.2: liquid-fire needs upgrading

A simpler one now. My app was using the liquid-fire addon at version 0.21.2. This was not compatible with Ember 2.2. The error I was getting was:

1TypeError: renderNode.state is undefined

Anyway, I upgraded liquid-fire along with Ember itself. These are the lines to run, and the ones for Ember Data 2.2:

1$ bower install ember#2.2.x --save
2$ npm install liquid-fire --save-dev
3$ npm install [email protected] --save-dev
4$ bower install ember-data#2.2.x --save

Ember 2.3: Ember Data is not in Bower any more

For Ember 2.3, just install Ember 2.3 (d’oh):

1$ bower install ember#2.3.x --save

The release notes for Ember 2.3 advise that we upgrade ember-qunit, which is a Bower package. I wasn’t getting any errors on my tests, but did it nonetheless:

1$ bower install ember-qunit --save

As for the release notes for Ember Data 2.3, these inform us that the Bower package is not required any more, as Ember Data is now a full-fledged Ember addon. Also, ember-cli-shims (npm) needs to be upgraded to 0.1.0. Manually remove any references to ember-data from bower.json:

 1diff --git a/bower.json b/bower.json
 2index 214ef1e..8f74eb7 100644
 3--- a/bower.json
 4+++ b/bower.json
 5@@ -4,7 +4,6 @@
 6     "ember": "2.3.x",
 7     "ember-cli-shims": "ember-cli/ember-cli-shims#0.0.3",
 8     "ember-cli-test-loader": "ember-cli-test-loader#0.1.3",
 9-    "ember-data": "2.2.x",
10     "ember-load-initializers": "ember-cli/ember-load-initializers#0.1.5",
11     "ember-qunit": "^0.4.20",
12     "ember-qunit-notifications": "0.0.7",
13@@ -19,7 +18,6 @@
14     "Faker": "~2.1.3"
15   },
16   "resolutions": {
17-    "ember-data": "2.2.x",
18     "ember": "2.3.x",
19     "jquery": "2.1.x",
20     "ember-qunit": "^0.4.20"

And upgrade the required packages at the command line:

1$ npm install [email protected] --save-dev
2$ bower install ember-cli-shims#0.1.0 --save

2.4: an easy one

1$ bower install ember#2.4.x --save
2$ npm install [email protected] --save-dev

Piece of cake.

2.5: changes to selectors in tests

So I upgraded Ember as usual:

1$ bower install ember#2.5.x --save

And tests started failing :-(

I’m not sure where exactly this comes from, but the semantics of jQuery selectors seem to have changed subtly between Ember 2.4 and 2.5, at least in acceptance tests. This affected all my acceptance tests because the click() helper started to fail.

My HTML contains something like this:

1<a href="...">
2  <p>Foo</p>
3  <p>Bar</p>
4</a>

And my acceptance tests would do this:

1click(':contains("Bar")');

Before 2.5, that would have sufficed to follow the link, but now the helper must be triggering the click event differently, so it’s necessary to be more specific. This works:

1click('a:contains("Bar")');

And since Ember Data is a proper Ember addon, I thought I would upgrade it as such from now on:

1$ ember install [email protected]

2.6: finally!

The last step was easy again:

1$ bower install ember --save
2$ ember install ember-data

Epilogue: updating ancillary files

After all the above, I got the app working on Ember(+Data) 2.6. Although this should be enough, there are still some differences with a proper 2.6 app as generated with ember new. These differences are in the files generated with the application. I decided to update these too to avoid any potential problems in the future.

What I did was generating a new app, then comparing the generated files with those in mine. There are a few differences, for example in app/app.js:

 1@@ -1,6 +1,6 @@
 2 import Ember from 'ember';
 3-import Resolver from './resolver';
 4-import loadInitializers from 'ember-load-initializers';
 5+import Resolver from 'ember/resolver';
 6+import loadInitializers from 'ember/load-initializers';
 7 import config from './config/environment';
 8
 9 var App;
10@@ -25,7 +25,7 @@ Ember.onerror = function(error) {
11 App = Ember.Application.extend({
12   modulePrefix: config.modulePrefix,
13   podModulePrefix: config.podModulePrefix,
14-  Resolver
15+  Resolver: Resolver
16 });
17
18 loadInitializers(App, config.modulePrefix);

Also there are new files, such as tests/helpers/module-for-acceptance.js, which is used in acceptance tests.

Differences too in package.json and bower.json. I updated the packages that were behind, leaving alone those for which my version was ahead. All in all, I tried to reduce differences with a 2.6 app as much as possible. This included:

This was a slow and annoying process, but it may spare me new problems in the future. Also, I avoided including the addon ember-welcome-page because it’s only useful in new installs, and expected to be removed by the developer after work starts.

After all these changes, my tests failed again, again because of a subtlety, this time in the test helper moduleForAcceptance. In two of my tests, I had a utility function defined as part of the test module:

 1/// tests/acceptance/my-test-test.js
 2module("Acceptance - my test", {
 3  // ...
 4  myUtilityFunction() {
 5    // do useful stuff...
 6  },
 7  // ...
 8});
 9
10test("Test case", function(assert) {
11  // ...
12  this.myUtilityFunction();
13  // ...
14});

Turns out this doesn’t work when using moduleForAcceptance instead of module. I had to define the utility function outside and bind it to the module at beforeEach:

 1/// tests/acceptance/my-test-test.js
 2function myUtilityFunction() {
 3  // do useful stuff...
 4}
 5
 6moduleForAcceptance("Acceptance - my test", {
 7  // ...
 8  beforeEach() {
 9    this.myUtilityFunction = myUtilityFunction;
10  },
11  // ...
12});
13
14test("Test case", function(assert) {
15  // ...
16  this.myUtilityFunction();
17  // ...
18});

This got me back on green tests.

After all this, I still have a deprecation notice coming from liquid-fire. There doesn’t seem to be anything I can do about that, so I’ll just leave it there and wait until a new release of the addon fixes it.