End-to-end Testing with firebase-server

Uri is a Firebase Expert based in Tel Aviv, Israel. He works at WatchDox, organizes the Tel Aviv Google Developers Group, and is an avid Angular fan.

I built an open-source project called firebase-server to implement end-to-end tests in my own application. With firebase-server, my end-to-end tests are now running 40% faster and I no longer depend on an Internet connection for running the tests in development.

Testing With Firebase

Because Firebase is a cloud service, it poses some challenges for performing automated tests. For unit tests, using a mock for the Firebase client library will work well. If you are writing a web application, you can quickly mock just the methods you use with either Sinon or Jasmine, or use MockFirebase, an open-source Firebase mock.

When it comes to writing end-to-end tests, however, you usually want to test the system as a whole, including the integration with the real Firebase client library to verify that the realtime synchronization between clients is functioning correctly. In addition, the end-to-end testing code runs outside the context of your application and you should make some assertions about the data it saves to Firebase.

Before building firebase-server, I used the Firebase client library in my end-to-end tests to talk directly to the Firebase cloud service. The issues with this method were that I needed an internet connection to run the tests and my tests ran slowly if my internet connection was lagging.

Running a Local Firebase Server

Frustrated with my end-to-end tests occasionally timing out, I started looking for a solution. MockFirebase would solve the problem only if my testing and app code lived within the same process, and even then, I would not be testing the real Firebase client library.

I decided that the best solution would be to put MockFirebase into a separate process, and make the Firebase client library connect to that process. This is when firebase-server was born!

firebase-server is a simple Node module which speaks the Firebase Wire Protocol, and can be used as a proper substitute for the real Firebase server in your e2e testing scenarios. You can also use it to develop code against Firebase in times when you don’t have an internet connection.

Getting started with firebase-server

First, install the package from npm:

npm install --save-dev firebase-server

Next, you can launch the firebase server by doing the following:

var FirebaseServer = require('firebase-server');

new FirebaseServer(5000, 'test.firebase.localhost', {
  /* You can put your initial data model here, or just leave it empty */
});

Before you can connect to your Firebase, there is one limitation of the client library we need to work around: it requires the hostname of your firebase to include exactly two dots. You can work around this by adding a hosts file entry pointing 'test.firebase.localhost' to the local IP 127.0.0.1.

Add the following line to your hosts file:

# Your hosts file can be found in:
# Linux: /etc/hosts
# Mac: /private/etc/hosts
# Windows: c:WindowsSystem32Driversetchosts
127.0.0.1 test.firebase.localhost

For more information about editing your hosts file, see this page.

Now, everything is ready and you can switch to your local Firebase server. Simply change the connection string from [https://myFirebase.firebaseio.com](https://myFirebase.firebaseio.com) to ws://test.firebase.localhost:5000. For instance:

var client = new Firebase('ws://test.firebase.localhost:5000');
client.on('value', function(snap) {
  console.log('Got value:', snap.val());
});

If you do not wish to edit your hosts file, you can also use ws://127.0.1:5000. This trick seems to work inside Chrome and Firefox. With Node.JS, you can use another trick: overriding the constructor of the faye-websocket Client. Check out the firebase-server unit testing code for an example.

I’d like to hear what you think!

I’d love to hear any suggestions you have on firebase-server. You can file an issue or submit a pull request on GitHub, or send me your feedback on Twitter, I’m @UriShaked.