Solucionado (ver solução)
Solucionado
(ver solução)
9
respostas

Erro na execução do Mocha

Ao executar o mocha, estou recebendo o seguinte erro na console do Windows:

C:\Desenvolvimento\workspace\nodejs\casadocodigo>mocha

  #ProdutosController
    1) "before each" hook for "#listagem de produtos json"

  0 passing (16ms)
  1 failing

  1) #ProdutosController "before each" hook for "#listagem de produtos json":
     TypeError: Cannot read property 'connectionFactory' of undefined
      at Context.<anonymous> (test\produtos.js:8:33)

Código do produto.js da pasta test:

var express = require('../config/express');
var request = require('supertest')(express);

describe('#ProdutosController', function() {

       beforeEach(function(done){
        var conn = express.infra.connectionFactory();        
        conn.query("delete from produtos",function(ex, result){
            if(!ex){
                done();
            }
        });
    });

    it('#listagem de produtos json', function (done) {
      request.get('/produtos')
            .set('Accpet', 'application/json')
            .expect('Content-Type', /json/)
            .expect(200,done);

        });

    it('#Cadastro de novo produto com dados inválidos',function(done){
        request.post('/produtos')
        .send({titulo:"",descricao:"novo livro"})
        .expect(400, done);

    });

    it('#Cadastro de novo produto com dados válidos',function(done){
        request.post('/produtos')
        .send({titulo:"titulo do livro",descricao:"novo livro",preco:20.50})
        .expect(302, done);

    });
});

Código do connectionFactory.js

var mysql = require('mysql');

function createDBConnection(){

    if(!process.env.NODE_ENV || process.env.NODE_ENV === 'dev'){
        console.log('Conexao 1 - A variavel de ambiente nao existe ou chama dev!');
        return mysql.createConnection({
            host : 'localhost',
            user : 'nodedbuser',
            password : 'nodedbuser123*',
            database : 'casadocodigo_nodejs'
        });        
    }

    if(process.env.NODE_ENV == 'test'){
        console.log('Conexao 2 - A variavel de ambiente existe e chama test!');
        return mysql.createConnection({
            host : 'localhost',
            user : 'nodedbuser',
            password : 'nodedbuser123*',
            database : 'casadocodigo_nodejs_test'
        });
    }        

}

module.exports = function(){
    console.log("express load me chamando");
    return createDBConnection;
}

Variável de ambiente do Windows:

NODE_ENV=test
9 respostas

Oi Andre, tudo bem? Me explica uma coisa, você fez algo diferente da aula? Por que na aula o arquivo de configuração carregado é o app.js, onde é utilizado o express-load pra carregar toda a infra do projeto. Essa linha então, estaria errada pelo que lembro do curso.

var express = require('../config/express');

Você não tem o app.js? O que há nesse arquivo express.js?

Olá Wanderson. A aplicação (app.js) está funcionando normalmente. O problema é no teste (Aula 7) da aplicação que fica em test\produtos.js. O código que gerei está igual ao da aula e não funciona. O express.js que fica em \config tem o seguinte código:

express.js

var express = require('express');
var load = require('express-load');
var bodyParser = require('body-parser');
var expressValidator = require('express-validator');


module.exports = function (){
    var app = express();
    app.use(express.static('./app/public'));
    app.set('view engine','ejs');
    app.set('views','./app/views');
    app.use(bodyParser.urlencoded({extended: true}));
    app.use(bodyParser.json());
    app.use(expressValidator());
    load('routes',{cwd:'app'})
        .then('infra')
        .into(app);
    return app;
}

Entendi, neste caso, você não está recebendo o objeto app diretamente, mas sim a função exportada, você precisa executar a função pra receber o retorno dela, no caso, o objeto app.

var express = require('../config/express')();

Testa pra gente?

Wanderson, obrigado pelo retorno. Ao colocar () após o require o erro mudou. Parece que passou do ponto que estava. Seria bom a Alura corrigir estes erros de sintaxe/digitação deste curso pois me deparei com vários deste tipo.

O erro agora é o seguinte:

C:\Desenvolvimento\workspace\nodejs\casadocodigo>mocha

  #ProdutosController
Conexao 2 - A variavel de ambiente existe e chama test!
    1) "before each" hook for "#listagem de produtos json"


  0 passing (2s)
  1 failing

  1) #ProdutosController "before each" hook for "#listagem de produtos json":
     Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.

O código com a alteração: produtos.js

var express = require('../config/express')();
var request = require('supertest')(express);


describe('#ProdutosController', function() {

       beforeEach(function(done){
        var conn = express.infra.connectionFactory();        
        conn.query("delete from produtos",function(ex, result){
            if(!ex){
                done();
            }
        });
    });

    it('#listagem de produtos json', function (done) {
      request.get('/produtos')
            .set('Accpet', 'application/json')
            .expect('Content-Type', /json/)
            .expect(200,done);

        });

    it('#Cadastro de novo produto com dados inválidos',function(done){
        request.post('/produtos')
        .send({titulo:"",descricao:"novo livro"})
        .expect(400, done);

    });

    it('#Cadastro de novo produto com dados válidos',function(done){
        request.post('/produtos')
        .send({titulo:"titulo do livro",descricao:"novo livro",preco:20.50})
        .expect(302, done);
    });
});

Obs.: Voltei no material novamente e os parênteses após o require do express já foram colocados. Obrigado.

Pela mensagem de erro, pode ser que a conexão com o banco não está sendo possível. Verifique se o MySQL está rodando e se as credenciais de acesso/nome do banco estão corretos.

Uma forma de identificar o problema pode ser utilizando um tratamento de erro. Exemplo:

  beforeEach(function(done){
    try {
        var conn = express.infra.connectionFactory();        
        conn.query("delete from produtos",function(ex, result){
            if(!ex){
                done();
            }
        });
    } catch(err) {
            done(err);
    }    

    });

Oi Andre, vou pedir pra equipe verificar os erros. Obrigado pelo feedback. Mas, vamos lá, o problema é que você está usando o done, mas o done precisa ser chamado de um jeito ou de outro. No seu código atual, se o erro não acontecer ele chama o done, mas e se acontecer? A aplicação fica travada. Quando trava, o timeout acaba e gera esse erro.

Testes assincronos geralmente dão esses erros. Você pode usar a solução do Daniel acima, ou usar simplesmente o seguinte truque.

beforeEach(function(done){
    var conn = express.infra.connectionFactory();        
    conn.query("delete from produtos",function(ex, result){
        if(!ex){
            return done();
        }
        done(ex);
        });
    });

Dessa forma, se o erro não for encontrado, você finaliza o teste com o done. Caso seja encontrado, você finaliza a bateria de testes executando o done com o erro sendo exibido no terminal.

Daniel, Wanderson obrigado pelo retorno. Com o exemplo de vocês para capturar o erro deu para identificar que era o nome da tabela que estava "produtos" e deveria ser "livros". O curso pede para criar uma tabela "livros" lá no início, depois, vez ou outra o material do curso muda para "produtos" e não atentei para esta vez.

Agora está apresentando o seguinte erro:

    1) #listagem de produtos json
Conexao 2 - A variavel de ambiente existe e chama test!
{ titulo: '', descricao: 'novo livro' }
[ { param: 'titulo', msg: 'Título deve ser preenchido', value: '' },
  { param: 'preco', msg: 'Formato inválido', value: undefined } ]
    √ #Cadastro de novo produto com dados inválidos (47ms)
Conexao 2 - A variavel de ambiente existe e chama test!
{ titulo: 'titulo do livro',
  descricao: 'novo livro',
  preco: 20.5 }
Conexao 2 - A variavel de ambiente existe e chama test!
null
    √ #Cadastro de novo produto com dados válidos (189ms)


  2 passing (606ms)
  1 failing

  1) #ProdutosController #listagem de produtos json:
     Error: expected "Content-Type" matching /json/, got "text/html; charset=utf-8"
      at Test._assertHeader (node_modules\supertest\lib\test.js:243:14)
      at Test._assertFunction (node_modules\supertest\lib\test.js:281:11)
      at Test.assert (node_modules\supertest\lib\test.js:171:18)
      at Server.assert (node_modules\supertest\lib\test.js:131:12)
      at emitCloseNT (net.js:1544:8)
      at _combinedTickCallback (internal/process/next_tick.js:71:11)
      at process._tickCallback (internal/process/next_tick.js:98:9)

Pela mensagem de erro, o que deve ter acontecido é que houve a comunicação, mas o formato do retorno não era o esperado. Você queria um retorno em JSON, mas recebeu um retorno em HTML.

Neste caso, teria que ajustar a rota que está sendo testada, no caso a "/produtos".

Mas antes, tem que dar uma olhada no teste. Eu vi que tem um erro de ortografia neste trecho:

 it('#listagem de produtos json', function (done) {
      request.get('/produtos')
            .set('Accpet', 'application/json')
            .expect('Content-Type', /json/)
            .expect(200,done);

        });

O "set" está errado, o correto seria:

   .set('Accept', 'application/json')

Se o erro persistir, confira a rota. Para definir um retorno para HTML e outro para JSON, você poderia seguir este exemplo:

  app.get('/produtos', function(req,res, next){


        var connection = app.infra.connectionFactory();



        var produtosDAO  = new app.infra.ProdutosDAO(connection);

          produtosDAO.lista(function(erros, resultados){
                if(erros){
                    return next(erros);
                }


                 res.format({
                    html: function(){
                        res.render('produtos/lista',{lista:resultados});
                    },
                    json: function(){
                        res.json(resultados)
                    }
                });


           });

        connection.end();
    });
solução!

Daniel, realmente escrevi errado. Ao corrigir, este último problema foi resolvido. A saída agora ficou conforme esperado no exercício:

  #ProdutosController
Conexao 2 - A variavel de ambiente existe e chama test!
Conexao 2 - A variavel de ambiente existe e chama test!
null
    √ #listagem de produtos json (47ms)
Conexao 2 - A variavel de ambiente existe e chama test!
{ titulo: '', descricao: 'novo livro' }
[ { param: 'titulo', msg: 'Título deve ser preenchido', value: '' },
  { param: 'preco', msg: 'Formato inválido', value: undefined } ]
    √ #Cadastro de novo produto com dados inválidos (70ms)
Conexao 2 - A variavel de ambiente existe e chama test!
{ titulo: 'titulo do livro',
  descricao: 'novo livro',
  preco: 20.5 }
Conexao 2 - A variavel de ambiente existe e chama test!
null
    √ #Cadastro de novo produto com dados válidos (68ms)


  3 passing (417ms)

Obrigado ao Wanderson e ao Daniel para solução!