Proyecto Liqueed (4)

Published on Author lopez

Anterior Post
Siguiente Post

Ya quedó claro en los posts anteriores que gran parte del proyecto:

https://github.com/liquid-co-ops/liqueed

ha sido armado siguiendo el flujo de trabajo de TDD (Test-Driven Development).

En el anterior post vimos un ejemplo de lógica de servicio, cómo quedó implementada siguiendo tests. Veamos hoy que hay controladores, módulos JavaScript que exponen métodos como acciones a mapear por Express, que exponen una API (Application Program Interface) hacia afuera. Por ejemplo, controllers\personapi.js, que comienza declarando:

'use strict';

var service = require('../services/person');

Vean que usa al servicio de personas.

Hay tests correspondientes, en test\personapi.js, que comienza importando los módulos que va a usar:

'use strict';

var controller = require('../controllers/personapi');

var loaddata = require('../utils/loaddata');
var db = require('../utils/db');
var async = require('simpleasync');

En el anterior posts, discutí que en JavaScript la granularidad que prefiero para correr los tests es el módulo, más que una función. Luego ejecuto los tests en orden, dentro de ese módulo. Acá aparece el primer test, que se ocupa de inicializar el modelo de dominio:

var persons;

exports['clear and load data'] = function (test) {
    var personService = require('../services/person');

    test.async();
    
    async()
    .then(function (data, next) { db.clear(next); })
    .then(function (data, next) { loaddata(next); })
    .then(function (data, next) { personService.getPersons(next); })
    .then(function (data, next) {
        persons = data;
        test.ok(persons);
        test.ok(persons.length);
        test.done();
    })
    .run();
};

Lo nuevo aca a entender, es el uso de simpleasync, en la variable async, un módulo que escribí hace un tiempo para encadenar funciones JavaScript. Cada función recibe: data, el resultado de la anterior función, y next, un callback de JavaScript que admite dos argumentos: err y data. La función que definamos en la cadena, puede tomar data como resultado bueno de la anterior función definida en la cadena, y entregar err en null, y el nuevo data para el siguiente eslabón. O puede entregar err, y data en null, si detecta algún problema. Vemos en el ejemplo de arriba, que personService.getPersons(next) invoca la recuperación de la lista de personas, y se le pasa next, como callback. Entonces, la siguiente función en la cadena recibe data como respuesta, y lo utiliza.

A pesar que parece que está usando una base de datos, lo asumido es usar un modelo en memoria. Tenemos que ver dónde está esa decisión, pero hoy nos basta saber que el modelo inicial está en el directorio principal, en formato JSON en testdata.json. Parte de este archivo:

{
    "projects": [
        {
            "name": "FaceHub",
            "periods": [
                { 
                    "name": "January 2014", 
                    "date": "2014-01-31", 
                    "amount": 100,
                    "assignments": [
                        { "from": "Alice", 
                            "to": "Bob", 
                            "amount": 50, 
                            "note": "Arrive earlier" },
                        { "from": "Alice", 
                            "to": "Charlie", 
                            "amount": 50 , 
                            "note": "Arrive earlier" },
                        { "from": "Bob", 
                            "to": "Alice", 
                            "amount": 60 , 
                            "note": "Arrive earlier" },
                        { "from": "Bob", 
                            "to": "Charlie", 
                            "amount": 40 , 
                            "note": "Arrive earlier" },
                        { "from": "Charlie", 
                            "to": "Alice", 
                            "amount": 35 , 
                            "note": "Arrive earlier" },
                        { "from": "Charlie", 
                            "to": "Bob", 
                            "amount": 65 , 
                            "note": "Arrive earlier" }
                    ]
                },
                { "name": "February 2014", 
                    "date": "2014-02-28", 
                    "amount": 100 }
            ],
            "team": [ "Alice", "Bob", "Charlie" ],
//....

Vemos que personapi.js como módulo, al final termina exportando las acciones que queremos consumir:

module.exports = {
    list: list,
    get: get,
    getProjects: getProjects,
    loginPerson: loginPerson,
    getPendingShareProjects:getPendingShareProjects,
    updatePassword: updatePassword
}

Veremos en próximos posts, el segundo y siguientes tests de la API de persona, y cómo las acciones se rutean con Express.

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez