Migration Jasmine
Il y a quelques temps, j’ai entamé un nouveau projet, il s’agissait de fournir un composant faisant le pont entre un environnement Jasmine 1 et Jasmine 2. Qu’est-ce que cela signifie ? En fait, dans les environnements de tests JavaScript, il existe plusieurs “moteurs” de tests, un des plus célèbres est Jasmine.
L’idée était la suivante : permettre à des milliers de tests écrits en Jasmine version 1 de tourner sur un environnement Jasmine version 2 sans les réécrire. En ligne de mire les applications legacy : vous possédez des tests en Jasmine1, vous voulez retirer la dette technique de votre projet en mettant à jour votre moteur de tests, mais vous vous rendez vite compte que cela vous obligerait à réécrire tous les tests d’un coup ! En effet la plupart des APIs entre Jasmine1 et Jasmine2 ne sont pas compatibles, c’est ici que le bridge intervient : pratiquement aucune réécriture ^[ l’API Clock et les CustomMatcher ne sont pas supportés par le bridge à l’heure où j’écris cette article] vous l’installez et le code est portable.
Code asynchrone
Mon premier objectif fût de supporter les fonctions runs/waitsFor/waits
, dans un environnement Jasmine 2, pour permettre de faire tourner les tests qui possèdent du code asynchrone.
En Jasmine 1, ca ressemble à ceci :
it("bridge should support runs/waits/waitsFor methods", function(){
var data;
runs(function(){
someMethodAsync.then(function(_data){
data=_data;
});
});
waitsFor(function(){
return typeof data!=="undefined";
}, "erratum", 1000 /*timeout*/);
runs(function(){
//asserts here.
});
});
Le code précédent en Jasmine 2 devrait être complétement réécrit :
it("bridge should support Jasmine2", function(done) {
someMethodAsync.then(function(data) {
//asserts here
//[...]
//Go to next test:
done();
});
});
Donc ne concernant que le code asynchrone il y a déjà beaucoup de boulot de portage entre Jasmine 1 et Jasmine 2, toute la structure du test doit être repensée. Vous me direz ce n’est pas un problème, prenons une branche de dev et portons les tests dessus un par un, mais voilà, ça prend du temps, vous n’avez pas forcément les ressources necessaires pour réécrire tous les tests, sachant qu’en plus il n’y a aucune valeur ajoutée.
Bref lorsqu’il s’agit de migrer de plateforme de tests ce n’est jamais évident puisque ca fait tourner vos tests, donc votre assurance que votre application tourne toujours correctement.
L’idée est toute simple : une fois le bridge installé, tous les tests fonctionnent déjà, vos tests Jasmine 1 tournent sur une plateforme jasmine 2, pour retirer la dette technique, il suffira alors de porter petit à petit un test Jasmine1 en Jasmine 2 et ainsi migrer lentement le code vers les nouvelles APIs de Jasmine puis à terme retirer le bridge une fois que tous les tests sont réécrits.
Un schéma pour avoir une meilleure idée :
Alors comment installer le bridge ? Rien de plus simple :)
Installation
Dans votre projet node vous utilisez tout simplement la commande npm install
:
npm install karma-jasmine-bridge --save-dev
Puis, vous modifiez votre fichier de configuration karma, pour ajouter dans la section frameworks le bridge tel que:
frameworks: ['jasmine-bridge', 'jasmine', ...]
si vous avez d’autres frameworks déclarés, ça n’a pas d’importance, ce qui compte c’est que le bridge jasmine-bridge
soit déclaré avant le framework jasmine
.
Ainsi une fois installé vous bénéficiez de la plupart des APIs jasmine 1 sur votre plateforme de tests Jasmine 2 par exemple :
runs(), waitsFor(), spy.andCallThrought(), spy.andCallFake() ...
Migration
Je fais part ici de mon expérience concernant la stratégie mise en oeuvre pour porter ses tests Jasmine 1 vers Jasmine2. Postulats:
- L’application comporte au minimum 3 branches actives, master, v2 et v1
La branche principale
master
contient les développements les plus récents, La branchev2
correspond à l’application qui tourne en dev La branchev1
correspond à l’application qui tourne en production.
L’installation du bridge est effectuée à partir de la HEAD (master), en créant une branche dédiée, tous les tests utilisant des customMatchers ou faisant appel à Clock seront en erreur il faudra les porter en Jasmine 2. Les différentes étapes:
- Création d’une branche dédiée à partir de la HEAD (master) appelons-la
jasmine2
- Installation du bridge dans le système (cf Installation)
- Lancement des tests pour constater l’étendue du travail
- Ré-écriture ou désactivation dans un premier temps des tests CustomMatchers et Clock (
xit
, ouxdescribe
) - Merger les nouveaux tests arrivés sur la HEAD (master) dans la branche
jasmine2
- Une fois le portage terminé, merger la branche
jasmine2
dans la branchemaster
Une version simplifiée des étapes:
A noter : durant la migration, de nouveaux tests sur les branches v1 et v2 peuvent apparaître, si possible toujours backporter ces tests sur la branche principale (master
, default
, trunk
… HEAD
), ils seront mergés dans la branche jasmine2
. Malheureusement en pratique, les tests sont le plus souvent non backportables comme tels entre les branches, donc pour éviter les déconvenues, il vous faudra créer des branches dédiées jasmine2_v2
et jasmine2_v1
et répéter les étapes ci-dessus.
Vous pouvez également décider, si les tests ne diffèrent pas trop entre les branches, de merger la branche jasmine2
dans la branche v2
et v1
et de fixer les erreurs de merge un par un.
La page de Jasmine dédiée à la migration entre la version 1 et version 2 est accessible ici:Upgrade Jasmine
Conclusion
Le projet est en production, il fait tourner plus d’un millier de tests Jasmine1 sur une plateforme 2, l’objectif est donc atteint. Le bridge en soi se teste avec lui-même (eat your own dog food) comme cela je suis sûr de ne rien rater. Le source du projet est disponible en opensource sur github