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

7.Teste de Integração - Supertest - Uncaught Error: Can't set headers after they are sent.

Olá pessoal.

Ao executar o meu teste, tenho o seguinte retorno:

#ProdutosController
estou conectando no MySQL
    √ #listagem json (155ms)
salvou!!
[ { param: 'titulo', msg: 'Titulo é obrigatório', value: '' },
  { param: 'preco', msg: 'Preco valor inválido', value: undefined } ]
{ titulo: '', descricao: 'livro de teste' }
estou conectando no MySQL
    √ #cadastro de um novo produto com dados invalidos (59ms)
salvou!!
false
{ titulo: 'novo livro',
  preco: 20.5,
  descricao: 'livro de teste' }
estou conectando no MySQL
    1) #cadastro de um novo produto com tudo preenchido


  2 passing (419ms)
  1 failing

  1) #ProdutosController #cadastro de um novo produto com tudo preenchido:
     Uncaught Error: Can't set headers after they are sent.
      at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:346:11)
      at ServerResponse.header (C:\Users\Martin\Desktop\Martin\Alura\JavaScript\Node.js\casadocodigo\node_modules\express\lib\response.js:718:10)
      at ServerResponse.location (C:\Users\Martin\Desktop\Martin\Alura\JavaScript\Node.js\casadocodigo\node_modules\express\lib\response.js:835:8)
      at ServerResponse.redirect (C:\Users\Martin\Desktop\Martin\Alura\JavaScript\Node.js\casadocodigo\node_modules\express\lib\response.js:874:8)
      at Query._callback (C:\Users\Martin\Desktop\Martin\Alura\JavaScript\Node.js\casadocodigo\app\routes\produtos.js:73:22)
      at Query.Sequence.end (C:\Users\Martin\Desktop\Martin\Alura\JavaScript\Node.js\casadocodigo\node_modules\mysql\lib\protocol\sequences\Sequence.js:96:24)
      at Query._handleFinalResultPacket (C:\Users\Martin\Desktop\Martin\Alura\JavaScript\Node.js\casadocodigo\node_modules\mysql\lib\protocol\sequences\Query.js:144:8)
      at Query.OkPacket (C:\Users\Martin\Desktop\Martin\Alura\JavaScript\Node.js\casadocodigo\node_modules\mysql\lib\protocol\sequences\Query.js:78:10)
      at Protocol._parsePacket (C:\Users\Martin\Desktop\Martin\Alura\JavaScript\Node.js\casadocodigo\node_modules\mysql\lib\protocol\Protocol.js:280:23)
      at Parser.write (C:\Users\Martin\Desktop\Martin\Alura\JavaScript\Node.js\casadocodigo\node_modules\mysql\lib\protocol\Parser.js:73:12)
      at Protocol.write (C:\Users\Martin\Desktop\Martin\Alura\JavaScript\Node.js\casadocodigo\node_modules\mysql\lib\protocol\Protocol.js:39:16)
      at Socket.<anonymous> (C:\Users\Martin\Desktop\Martin\Alura\JavaScript\Node.js\casadocodigo\node_modules\mysql\lib\Connection.js:96:28)
      at readableAddChunk (_stream_readable.js:147:16)
      at Socket.Readable.push (_stream_readable.js:111:10)
      at TCP.onread (net.js:525:20)

O teste funciona bem quando eu tiro um dos testes de cadastro. Pesquisando pelas internets da vida, o pessoal fala muito que isso ocorre quando é feito dois "send" em seguida ou quando não existe o retorno de uma requisição.

Código do produtos.js:


module.exports = function(app){

    function validationFields(req, resp,produto){
        var validadorTitulo = req.assert('titulo', 'Titulo é obrigatório').notEmpty();
        var validadorPreco = req.assert('preco', 'Preco valor inválido').isFloat();
        var validadorDescricao = req.assert('descricao','Descrição obrigatório').notEmpty();


        var erros = req.validationErrors();

        console.log(erros);
        if(erros){
            renderFormPage(resp,erros,produto);
            return;
        }
    }

    function renderFormPage(resp,erros, produto){

        resp.format({
            html:function(){
                resp.status(400).render('produtos/form',{errosValidacao:erros, produto:produto});    
            },
            json:function(){
                resp.status(400).json(erros);
            }
        });

    }
    var listaProdutos = function(req,resp){
        var connectionDB = app.infra.connectionFactory();
        var produtosBanco = new app.infra.ProdutosDAO(connectionDB);

        produtosBanco.lista(function(err, result){
            resp.format({
                html:function(){
                    resp.render('produtos/lista',{lista:result});    
                },
                json:function(){
                    resp.json(result);
                }    
            });            
        });

        connectionDB.end();
        //resp.render("produtos/lista");
    };
    app.get('/produtos', listaProdutos);

    app.get('/produtos/form',function(req,resp){
        console.log('cheguei no form');

        renderFormPage(resp,{},{});
    });

    app.post('/produtos', function(req, resp){
        console.log('salvou!!');

        var produto = req.body;

        //Função que faz a validação dos campos
        validationFields(req, resp, produto);

        console.log(produto);

        var connectionDB =  app.infra.connectionFactory();
        var produtosBanco = new app.infra.ProdutosDAO(connectionDB);

        produtosBanco.adiciona(produto, function(err, result){

            if (err == null) {
                resp.redirect('/produtos');
            }else{
                console.log(err);    
            }


        })


    });
}

O código do teste:

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

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

    });

    it('#cadastro de um novo produto com dados invalidos', function (done) {
        request.post('/produtos')
            .send({titulo:"",descricao:"livro de teste"})
            .expect(400,done)

    });

    it('#cadastro de um novo produto com tudo preenchido', function (done) {
        request.post('/produtos')
            .send({titulo:"novo livro",preco:20.50,descricao:"livro de teste"})
            .expect(302, done)
    });
});

O que eu deixei passar?

Obrigado !

2 respostas
solução!

Opa, o problema está aqui:

 //Função que faz a validação dos campos
    ...
        validationFields(req, resp, produto);

        console.log(produto);

        var connectionDB =  app.infra.connectionFactory();
        var produtosBanco = new app.infra.ProdutosDAO(connectionDB);

        produtosBanco.adiciona(produto, function(err, result){

            if (err == null) {
                resp.redirect('/produtos');
            }else{
                console.log(err);    
            }


        })

A função de validação pode já forçar um resposta para o cliente e, mesmo assim, você continua o fluxo.. Tentando gerar outra resposta com o redirect... Faz a função de validação retornar um boolean e só continua o fluxo se ela retornar false.

Deu certo, obrigado Alberto!