Stubbing MQTT.js library in Ember.js tests with Sinon.JS

Sinon.JS

I took the opportunity to upgrade the ember-mqttjs support to Ember v4 for refactoring the addons tests. During last EmberFest (which happened in Rome on Sept. 30 and Oct. 1, 2021) I listened to a lot of brilliant talks. One of them caught my attention because it dealt with the testing topic and in particular of mocks and stubs.

Gonçalo Morais dove into this argument with some stunning hints during his talk “Mock & Roll” that opened my minds and let me wondering on how to improve my mqtt ember addon tests.

After some experiments with the mock-socket library I realized that this tool was not anymore mantained and combining some searchs into the Sinon.JS documentation I found a way to stub the MQTT.js dependency faking the connect method.

This method returns a client and triggers some events that are useful to understand the mqtt connection status. Joining the replace and fake methods from Sinon.JS I found a way to simulate the MQTT.js connect method behavior returning a client with the necessary methods and triggering the needed events.

As you can see next on the code sample attached to this post I need to add some tricks to the joke, because for example the connect event needs to be trigger after a delay while the fake client declares an event handler that must to be there when the event is fired. Or for example the subscribe and publish methods need to call a callback with the correct parameters.

Once I discovered this tricks the tests runs correctly and I can assume that my code is working fine relying on the MQTT.js client to be properly tested.

Code sample

This is the example for the connect test but you can find the whole code into the addon repository:

import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import sinon from 'sinon';
import mqttjs from 'mqtt/dist/mqtt';
import Service from '@ember/service';
import Evented from '@ember/object/evented';
import { later } from '@ember/runloop';

class MqttServiceStub extends Service.extend(Evented) {}

module('Unit | Service | mqtt', function (hooks) {
  let mqttHost = 'ws://localhost:8883';
  let mqttTopic = 'presence';
  let mqttMessage = 'Hello';

  let mqttServiceStub;

  setupTest(hooks);

  hooks.afterEach(() => {
    sinon.restore();
  });

  // ...

  //Testing mqtt connect
  test('mqtt connect success', async function (assert) {
    let service = this.owner.lookup('service:mqtt');
    let done = assert.async();
    assert.expect(3);
    mqttServiceStub = new MqttServiceStub();
    sinon.replace(
      mqttjs,
      'connect',
      sinon.fake(() => {
        later(() => {
          mqttServiceStub.trigger('connect');
        }, 100);
        return {
          on: (sEvent) => {
            mqttServiceStub.on(sEvent, () => {
              if (sEvent === 'connect') {
                return service.onConnect();
              }
            });
          },
        };
      })
    );
    try {
      service.on('mqtt-connected', () => {
        assert.ok(true);
      });
      await service.connect(mqttHost);
      assert.ok(service);
      assert.ok(service.isConnected);
    } catch {
      assert.ok(false);
      assert.ok(false);
      assert.ok(false);
    } finally {
      done();
    }
  });

If you notice some errors or you need more informations about the code I’m happy to hear from you. Reach me through my contact page.

MQTT in Ember.js

Ember Octane mqtt.js

Less than 2 years ago I started a new project with the company I work for that requires to an Ember Octane app to control several connected IoT devices around the world. We choosed the MQTT publish/subscribe network protocol to interact with our on-field devices for its lightweight message structure and its limited network bandwith requirements.

After googling for a javascript MQTT library I’ve found the MQTT.js client. At the moment of my search the asynchronous version was not yet released, so I had to wrap the event based client into an Ember service and transform it into a Promise based client.

This is a mandatory requirement because I need broker connection before subscribing to a topic or I need topic subscription before publishing on it. Sometimes you had retain messages on a topic for receiving last published value after the subscription. Other times you need publishing an empty value on a topic to request the status of a given device. So you need working subscribtion on a topic before sending a message. That said javascript Promises are the only way to accomplish this tasks.

When I wrote this service I didn’t find an Ember addon ready to do this things. Therefore I decided to dive into the docs and learn how to build an addon. The ember-mqttjs addon is my first Ember addon!

The code

This service extends the Evented Ember object for raising events on new messages as well as connect, disconnect events and many others you can find on its readme. In addition of raising this events it returns a Promise for connect, subscribe, unsubscribe and publish methods.

This is an example of another service that uses the ember-mqttjs service:

import Service, { inject as service } from '@ember/service';
import { bind } from '@ember/runloop';

export default class YourService extends Service {
  @service mqtt;
  constructor() {
    super(...arguments);
    //...
    let _fOnMessage = bind(this, this._onMessage);
    this.mqtt.on('mqtt-message', _fOnMessage); 
  }

  _onMessage(sTopic, sMessage) {
    //code to manage messages received on a certain topic
  }

  async subscribeAndPublish(sTopic, sMessage) {
    try {
      await this.mqtt.connect(HOST, USERNAME, PASSWORD)
    } catch (oError) {
      //code on connection error
    }
    try {
      await this.mqtt.subscribe(sTopic);
    } catch (oError) {
      //code for subscription error
    }
    try {
      await this.mqtt.publish(sTopic, sMessage);
    } catch (oError) {
      //code for message publish error
    }
    return Promise.resolve();
  }
//...
}

I’ve just refactored the addon code to use async/await features and I moved the CI from travis to github action (thanks to this Jeldrik Haschke’s repo).
Many improvements can be done in the future starting from writing more tests to cover other cases.
If you have any suggestions or proposal to improve the code as well as the tests you are welcome!

Contact me or start contributing on GitHub project repo!

Ember + Boostrap 5

Today I welcome a new template for my blog by returning to write a post after a very long time!

This WordPress theme is built on top of the latest Bootstrap release, Bootstrap 5 and with this post I would like to explain you how to use this hugely popular front-end framework in an Ember app.

With this major new release the developers have focused most of their efforts towards removing jQuery as a dependency of the framework to make it lighter and usable by a wider audience now interested in saving as much kb as possible.

For those who knows and uses the previous Bootstrap version (v4) I suggest to dive into the migration guide, to understand what breaking changes were made in this new update.

As an experiment (I will tell you later about what I am working on in my spare time) I’ve tried to use Bootstrap 5 in a new Ember Octane app and thank to the release of the bootstrap npm package this turned out to be tremendously simple.

Let’s see the steps:

First you have to install the bootstrap npm package:

npm install --save-dev bootstrap

Then you have to modify your ember-cli-build.js file:

'use strict';

const EmberApp = require('ember-cli/lib/broccoli/ember-app');

module.exports = function (defaults) {
  let app = new EmberApp(defaults, {
    // Add options here
    sassOptions: {
      includePaths: ['node_modules/bootstrap/scss'],
    },
  });
  app.import('node_modules/bootstrap/dist/js/bootstrap.bundle.min.js');
  return app.toTree();
};

The last few steps are required to be able to import bootstrap SCSS files.
First you have to install ember-cli-sass addon:

ember install ember-cli-sass

Then you have to rename your app style app.css to app.scss and insert the line to import the bootstrap files:

@import 'bootstrap';

You are now ready to use Bootstrap 5 in your Ember app!

Uno script Gulp per automatizzare la compilazione dei files Sass (scss)

Gulpjs

Gulp js è una libreria javascript che permette di automatizzare svariate tipologie di noiose procedure che gli sviluppatori normalmente fanno “a mano”.

Proprio in questa direzione ho deciso di scrivere un breve script gulp che consente di automatizzare la ricompilazione dei fogli di stile SASS (scss), per evitarmi di lanciare, ad ogni modifica dei files, il comando sass sorgente.scss destinazione.css.

L’unico prerequisito per utilizzare gulp è di aver installato Nodejs ed il suo package manager npm (che viene installato di default insieme a node). Una volta installato node e scaricati i sorgenti del mio script basterà lanciare:

sudo npm install

…ed npm installerà per voi tutte le dipendenze necessarie!

Lo script prevede due modalità di esecuzione tramite i seguenti comandi:

  • gulp: compila i vostri scss presenti nella sottocartella src in un unico css nella root directory minifizzato (sass –style compressed)
  • gulp dev: compila gli scss in modalità espansa (sass –style expanded)

Questi due comandi avviano un task che rimane “in ascolto” e ad ogni modifica di un file scss rilancia il comando evitando il noioso compito di lanciare ogni volta la compilazione dei files per vedere le modifiche allo stile delle vostre web app/siti. In questo modo potrete scrivere le direttive di stile come si faceva prima dell’avvento di SASS/LESS e vedere immediatamente le nuove modifiche “live”.

Ho previsto un repository github “gulp-for-sass” con questo mini-progetto, scaricabile e modificabile liberamente!

Ng-Cookies e cookies su localhost con AngularJs

AngularJS-largeOggi scrivo di una piccola scoperta fatta giocando con AngularJs e i cookies che potrebbe tornare utile a chi di voi si deve cimentare nell’utilizzo di questa funzionalità javascript con l’ormai noto framework.

Facendo dei test di scrittura/lettura di informazioni all’interno dei cookies sembrava che non fosse consentito utilizzarli da localhost, ossia in locale. Più precisamente il cookie settato in una pagina, spariva letteralmente passando in un’altra pagina (cambiando url).

Dopo aver perso tutte le speranze e mentre vagavo senza meta all’interno delle issues del repository Github di AngularJs mi si è aperto un modo: un utente che si era interessato al problema dei cookies diceva che dopo averne discusso con il team di sviluppo aveva scoperto che per far funzionare a dovere questa funzionalità era necessario impostare il tag html base.

Facciamo un esempio: se il vostro progetto risponde all’url http://localhost/tests/angularjs/cookies sarà necessario impostare il base tag nel seguente modo:

 <base href="http://localhost/tests/angularjs/cookies/"> 

In questo modo i cookies verranno salvati per tutte le url che inizieranno per l’indirizzo specificato nel tag.

Il particolare importante da notare è lo slash finale. Senza quello nulla funzionerà.