Yoan Blanc’s weblog

Another swiss guy lost in Paris

June 2007

Test-Driven Development with JavaScript

Yoan BlancSun 24 June 2007, , ,

This Friday we were speaking about TDD a the work. As Web Developers our interest in in JavaScript tools for this purpose. Personnally, I did some with PHP stuff but not with JavaScript until today. Talking with Mr jQuery, John Resig, probably makes me choosing jQuery for this. As far as I know YUI for example doesn’t have any unit testing tools, but they are working on it. When you write code for lots of people, about myself it’s a few but for a company it can be millions. Having test for your code is one tool to guarantee quality for now, tomorrow and a far future. Unit test can, sometimes, be used in parallels with the documentation if it exists.

Let’s start. Download the empty files (one HTML, one CSS and two JS (jQuery and testrunner)) and start writing some tests.

test("myObj", function() {
 ok(myObj !== undefined, "myObj is undefined");
 ok(typeof myObj == "object", "myObj isn’t an object");
});

This says, I want to have an object called myObj. Now run the test and it will obviously fail. ok is like assertTrue, it test if the first expression is true. The second parameter is an optional label. If you’re familiar with TDD I’ll not repeat that this step is crucial. Write the test before writing the code, express what you want before saying how you’ll doing it. Say what you want not how you’ll do it the only advise I remember from my teacher of Software Engineering for the Analysis phase.

So after running this test, it’s really important too. It fails. Let’s fix it.

var myObj = (function(){
 return {};
})();

This syntax is one of the way to do OOP in JavaScript, use the one you like the more. Now re-run the tests, it should work. If it actually is, write more tests. For an example, the same old and boring example will be used, sorry for that.

test("myObj.add()", function() {
 expect(2);

 ok(typeof(myObj.add) == "function");
 equals(myObj.add(1,2), 3, "1 + 2 != 3");
});

We want a function called add that will do some addition. Here to new things: expect that says explicitly how many tests we have and equals which will compare the first and the second parameters. Run, the test, it fails, great. Sometimes you can do mistake during the writing of the tests, so this why this step is important. Let’s fix this red state to a green state that makes everyone happy again.

var myObj = (function(){
 return {
  add: function(a, b) {
   return (a + b);
  }
 }
})();

Run the test suite, if it’s green you’ve made it. Let’s do something more tricky now. In this html page, there is a place called main. The aim of this is to put HTML to manipulate in it. Often a JavaScript has the goal to add some behaviour or enrich the HTML. One of your test could be putting a sample HTML, running your JavaScript and afterwards checking that it worked. I’ll do it a slightly different way by putting test in to the HTML, maybe a bad idea.

<div id="test-addAnchors">
 <p class="test">
  Hello world! http://www.example.org this is an url
 </p>
 <p class="expected">
  Hello world! <a href="http://www.example.org">www.example.org</a> this is an url
 </p>
 <p class="test">
 Hello world! http://www.example.org/?foo this is an url
 </p>
 <p class="expected">
  Hello world! <a href="http://www.example.org/?foo">www.example.org/</a> this is an url
 </p>
</div>

The test class is the text before the action was called the expected the second one. This could be achieved via an array too.

test("myObj.addAnchors()", function() {
 ok(typeof(myObj.addAnchors) == "function");

 $("#test-addAnchors > .test").each(function(){
  $(this).html(myObj.addAnchors($(this).html()));
  var expected = $(this).next().get(0);

  equals(this.innerHTML, expected.innerHTML);
 });
});

It’s a function, allright. Next step, we take all the .test apply a function called addAnchors and see if it has the same content than the next sibling (here expected). Great, it fails. Let’s fix it.

addAnchors: function(text) {
 return text.replace(/(http:\/\/)([^ ?]+)(\?[^ ]+)?/g, ’<a href="$1$2$3">$2</a>’);
}

Hop a nice RegExp. Because regexp are unreadable, my advise is to write it by yourself, and try to fix the first test then the second one. This example is very quick and poor, but jQuery is full of test suites. Read them, read the testrunner.js as well and start from this to do test as often as you can: before adding a new feature, after fixing a bug (to be sure this won’t happen again). Find the final tests here.

Happy testing.

Vendredi passé lors du repas de midi entre collègues web dev nous parlions tests unitaires et JavaScript autour de délicieux sushis. L’idée est séduisante, j’en suis convaincu mais n’en ai jamais fait pour JavaScript, un peu en PHP uniquement. Chose corrigée. Peut-être avoir pu discuter de cela avec John Resig, Monsieur jQuery qui ne s’imagine plus écrire du code allant être utilisé à grand échelle sans un minimum de tests a aidé à me faire franchir le pas. Personnellement je n’en suis pas à son niveau, mais pour être professionnel, un code partant en production mérite la touche qualité que sont ces tests là. Écrire les tests avant le code, le Test Driven Development est l’idée poussée à l’extrème, écrire des tests de non-régression (au fur et à mesure que des bogues sont corrigés) est déjà un bon point que peu peuvent se vanter de remplir.

Merci de suivre la partie anglophone de cet article pour un rapide introduction au Test-Driven Development avec JavaScript, ci-dessous je vais détailler la structure d’une page de tests avec le système utilisé.

Je me suis servi des outils utilisés par jQuery pour tester ma propre bibliothèques JavaScript. Les pages de test comportent deux parties : une zone JavaScript contenant les tests de la forme :

test("maFonction", function() {
 // nombre de tests
 expect(2);
 // un test
 ok(expression valide);
 // un autre test
 equals(maFonction(), valeur référence, "label");
});

Ensuite dans le corps de la page, une zone HTML qui va servir de bac à sable. Une zone pour mettre de l’HTML d’entrée allant être traîté par votre librairie puis ensuite testé avec les valeurs références. En principe JavaScript agit sur l’HTML, c’est donc le moyen de le manipuler.

Il serait intéressant de tester différents outils de tests unitaires en JavaScript. Pour le moment, je vais m’essayer à celui-ci, n’hésitez pas à tenter le développement piloté par les tests, s’il semble contraignant c’est très plaisant de finir avec un code qui fonctionne, car on commence par dire qu’il est cassé. Que du bonheur.

4 bits of me

Yoan BlancFri 22 June 2007,

A blogger chain sent by Jen around the number 4.

Jobs I did:

  1. watch-maker in the workshop of my grand-father
  2. cooker-helper, I knoy how to do fries now (brilliant)
  3. sound-light-beer helper in a summer festival
  4. social worker with disabled people

Movies I liked :

  1. Usual Suspect
  2. El Laberintho del Fauno
  3. Wild Style
  4. The Shawshank Redemption

Place I lived :

  1. La Chaux-de-Fonds, République street, all my childhood
  2. La Chaux-de-Fonds, Jaquet-Droz 6, the teenager’s life with beer, beer and beer.
  3. Lausanne, Couchirard in a georgious flat sharing experience.
  4. Paris, near the Canal St-Martin, for now and tomorrow afaik

TV Shows (I don’t have any tv atm) :

  1. Animaniacs, Steven Spielbergs rocks
  2. Scrubs
  3. IT crowd
  4. The Office (UK version)

Holidays I did :

  1. Corsica, the nicest Island in the Mediterranean sea
  2. Berlin for the New Year’s Eve
  3. US and Canada, mainly Montreal, Québec and the NYC area.
  4. Estearn Europe this summer I hope

Web stuff :

  1. Planet.* (intertwingly, python, gnome, inertie, mono, lisp)
  2. Reddit (programming)
  3. Google Reader
  4. Osnews

Food I won’t eat ever :

  1. Poo
  2. Eyes
  3. Balls
  4. living beast

Dishes I love :

  1. Swiss fondue
  2. Japanese fondue
  3. Tatin
  4. Indian food in general

Place I wanna be right now :

  1. on your belly
  2. on the top of la tour de Gourdz watching the Leman Lake
  3. swimming in Le Doubs
  4. in my bed sleeping

I should invite some bloggers to do the same but I’m not, just follow the others answers to see what they said.

After this one, I’ll have to do a really techie post to pardon me.

Une chaîne à laquelle j’ajoute mon maillon mais la termine, car c’est avoir la classe 4 d’agir ainsi, non ?

Métiers :

  1. aide-horloger, dans l’atelier de mon grand-père Michel chez Rolex.
  2. aide-cuisine, 1 année et demi dans un supermarché, je suis le pro pour nettoyer une friteuse maintenant
  3. intermitant du spectable bénévole, à la Plage des Six-Pompes
  4. aide-moniteur dans une association s’occupant de personnes handicapées mentales.

Films :

  1. American Beauty
  2. Man on the Moon
  3. Et milieu coule la rivière (Légende d’Automne fait peut-être trop cliché, mais on va les mettre à égalité)
  4. Kids (sur un pied d’égalité avec Elephant)

Endroits où j’ai vécu :

  1. À la Chaux-de-Fonds, rue de la République, lieu de mon enfance par excellence où 120% de mon temps se passait sur le « terrain de basket ».
  2. Même ville, rue Jaquet-Droz, le temps des études et des retours ivre-mort en vie à 3 avec mon frangin.
  3. Lausanne, rue Couchirard, en colocation avec Batiste et : Aïcha et Eve ou Eve ou Louisa pour la fin déjantée.
  4. Paris, à deux pas du Canal St-Martin, actuellement et jusqu’à autre chose.

Émissions de tv (n’ayant pas la tv, des émissions que j’aimais regarder en général) :

  1. les animaniacs
  2. tracks
  3. la semaine des guignols
  4. Scrubs

Lieux de vacances :

  1. la Corse, juste merveilleux, je dois faire le GR20 un jour, on verra quand.
  2. Berlin, à Nouvel An, pour ses pâtisseries, son vin chaud, café au lait et les redoutables curry wurtz
  3. Les États-Unis, Canada, récemment la région Washington, NYC, Boston, Montréal, Québec et un tour complet de tout le pays en 1989 (oui j’étais tout petit)
  4. Europe de l’Est, cet été, à planifier encore

Trucs du web (je suis un nerd fini, horrible) :

  1. planet.* (intertwingly, python, gnome, inertie, mono, lisp)
  2. google reader
  3. osnews
  4. linuxfr

ne mangerais pour rien au monde :

  1. sandwich au caca (ça fait partie d’une blague, néanmoins)
  2. cervelle ou abats
  3. des asperges du pérou au mois de mars
  4. des fraises d’Espagne au mois de février

plats que j’aime :

  1. cuisine indienne, genre curry de chou-fleur avec naan
  2. vâcherin Mont-D’Or sur des patates
  3. tarte tatin (pur caramal, pur beurre, pur sucre de canne)
  4. sukiyaki

endroits où j’aimerais être :

  1. la tête sur ton ventre
  2. à la tour de Gourdz les cheveux au vent
  3. dans le Doubs, complétement immergé n’entendant que le bruit de ma réspiration dans l’eau
  4. en plein fou rire avec Bibi, Maverick et Moser au Coyote Bar

Et je n’invite pas de bloggueur à suivre mon exemple, mais remontez la chaîne pour voir ceux qui ont été sage.

Putting some dynamic microformats into Dopplr

Yoan BlancSun 10 June 2007, , ,

My first play with Greasemonkey the famous Firefox extension that enables to script it with JavaScript.

A gentle person invited me on Dopplr, the sooo nerdy web site for frequent travelers, I think the majority of the users are people who love attending to conferences all around the world. It’s a very simple and clean interface. But, microformats are missing and this annoys me a little bit.

First of all, you need an extension to extract microformats like Operator (unfortunately Tails doesn’t work) and of course Greasemonkey.

Dopplr displays a list of travels with dates.

<ul class="locations">
 <li class="month" id="trip_6919">
  <span class="bullet" style="background:#59ead8">&nbsp;</span>
  <a href="http://www.dopplr.com/city/london">London</a>
  from
  <span>June 11th</span>
  to
  <span>19th</span>.
  […]
 </li>
 […]
</ul>

And what could described the same way but as a hCalendar event is:

<ul class="locations">
 <li class="month vevent" id="trip_6919">
  <span class="bullet" style="background:#59ead8">&nbsp;</span>
  <a href="http://www.dopplr.com/city/london" class="location summary">London</a>
  from
  <span>
   <abbr class="dtstart" title="20070611T000000+0100">June 11th</abbr>
  </span>
  to
  <span>
   <abbr class="dtend" title="20070619T235959+0100">19th</abbr>
  </span>.
  […]
 </li>
 […]
</ul>

Let’s do it with JavaScript, because Greasemonkey is on top of Firefox we can use more advanced features like XPath queries:

var trips = document.evaluate(
 "//ul[@class='locations']/li",
 document,
 null,
 XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
 null);

for(var i=0; i<trips.snapshotLength; i++) {
 var event = trips.snapshotItem(i);
 // the code goes here.
}

Starting from this, we can iterate over each element and by editing the className attribute of the nodes putting the microformat sugar. For example:

event.className += " vevent";
event.getElementsByTagName("A")[0].className += " location summary";

And so on. For the abbr tricky part, I steal a very nice piece of code from Simon Willison: A better way of entering dates It’s tricky because Dopplr doesn’t give you the Year information, you have to guess it. I’ll let you dive into the source code to inspect how I did this.

export of hCard from Operator

I also added some hCard for your fellows travelers but I care less about this information actually.

You can find it on userscripts and learns more about Greasemonkey reading the book written by Mark Pilgrim: Dive into Greasemonkey. Test it, report my some bugs, improve it. It remains me some invitations to Dopplr, you won’t be able to test it being logged.

Greasemonkey scripts are a very useful functionality. With them you can improve your daily life a very little-cost, because developing them isn’t really complicated. Does your Intranet suck?

Ma première expérience avec Greasemonkey, la fabuleuse extension Firefox permettant d’appliquer du JavaScript aux pages affichées, de scripter le navigateur.

On m’a fait découvrir (merci Steph) Dopplr récemment, un outil super simple pour partager ses destinations futures avec son réseau de connaissances. Il peut nous dire qui sera au même lieu au même moment que nous. L’interface est propre est intuitive, mais elle manque de microformats. Ainsi je peux travailler via Dopplr et exporter ça dans Google Calendar ou Sunbird d’un simple clic.

Tout d’abord munissez-vous d’une bonne extension Firefox pour extraire les microformats, Operator est parfait, et de Greasemonkey bien entendu.

Si la version anglaise de cette article se préoccupe d’ajouter des informations hCalendar, on va traiter ici les hCard, c’est plus simple. La structure HTML fournie est simple :

<li>
 <a
  title="Stephanie Booth is at home in Lausanne"
  class="traveller_icon"
  href="http://www.dopplr.com/traveller/steph">
   <img
    src="[…]"
    width="32" height="32"
    alt="Stephanie Booth"
    style="border: 3px solid #2f4d15" />
 </a>
</li>

et ce que nous voulons est :

<li class="vcard">
 <a
  title="Stephanie Booth is at home in Lausanne"
  class="traveller_icon url"
  href="http://www.dopplr.com/traveller/steph">
   <img
    class="photo fn"
    src="[…]"
    width="32" height="32"
    alt="Stephanie Booth"
    style="border: 3px solid #2f4d15" />
 </a>
</li>

Le petit script ci-dessous, va s’occuper d’appliquer ces modifications à tous les éléments trouvés :

var fellows = document.evaluate(
 "//a[@class='traveller_icon']",
 document,
 null,
 XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
 null);
   
for(var i=0; i<fellows.snapshotLength; i++) {
 var fellow = fellows.snapshotItem(i);
 fellow.parentNode.className += " vcard";
 fellow.className += " url";
 fellow.getElementsByTagName("img")[0].className += " photo fn";
}

Greasemonkey autorise des fonctionnalités plus avancées de JavaScript comme les requêtes XPath car on reste à priori confiné à Firefox.

export of hCalendar from Operator

Le script est disponible sur userscripts, n’hésitez pas à me faire vos commentaires. Sinon pour en découvrir un peu plus sur Greasemonkey, le livre de Mark Pilgrim : Dive into Greasemonkey est la documentation par laquelle il faut commencer, et bien évidemment le blog Greasepot. Un jour Dopplr sera plein de microformats d’origine j’en suis certain.

About

meYoan Blanc is a web developer that lives in Paris (19, rue Bichat75010France) works for Yahoo! and comes from Switzerland ( La Chaux-de-Fonds). This web site is for this weblog, a playground for random stuffs and can help keepingconnected with some friends out there.

Get my vCard or contact me by phone (+33 1 74 30 12 92) or email ().

Misc

RSS, list.blogug.ch

This site reflects only my opinion and is not affiliated with my employer.

copyright 2006-2007 — doSimple.ch