· Serhii Siryk · Desenvolvimento Backend  · 7 min de leitura

Depuração de backend Node.js com TypeScript e IntelliJ



Depuração de backend Node.js com TypeScript e IntelliJ

Introdução

Há algumas semanas, migrámos um dos nossos projetos de backend Node.js de Babel para TypeScript. A razão foi, sobretudo, que nos dá uma opção com segurança de tipos, muito necessária, para o desenvolvimento backend com Express. Além disso, temos usado ativamente o TypeScript com Angular e React e gostamos mesmo de todos os benefícios que trouxe às nossas vidas. No entanto, levou-nos algum tempo a voltar a pôr tudo a funcionar com TypeScript, especialmente para configurar o projeto e o IDE de modo a podermos depurar tanto a lógica da aplicação como os testes diretamente a partir do IDE. Neste pequeno tutorial, vamos mostrar como pode depurar o seu backend Node.js escrito com TypeScript usando o IntelliJ IDEA.

🖐️ Olá! Quer ser um programador NodeJS de topo?

Escreva um currículo de programador NodeJS apelativo usando SweetCV – um incrível

criador de CVs online

. Pronto para conquistar o mundo? 👇

Crie o seu CV agora

Note que neste material não encontrará quaisquer passos para inicializar a sua aplicação com Express/Typescript. Existem muitos tutoriais na internet a mostrar como o fazer. Vamos apenas dar uma vista de olhos a uma pequena parte deste processo, nomeadamente a depuração, que normalmente não é bem abordada nos tutoriais mencionados acima. Claro que pode até construir coisas fantásticas com Node.js e TypeScript sem qualquer debugger baseado num IDE; no entanto, por vezes é muito útil poder colocar alguns breakpoints e mergulhar no código em execução no seu IDE.

Agora podemos começar!

Depuração de Testes Unitários

A primeira e mais fácil coisa a depurar são os testes unitários. Eis a lógica típica de um controlador que pode querer testar unitariamente:

self.approveUser = async (req, res, next) => {
  req.customer.approve(req.user);
  let updatedCustomer = await req.customer.save();
  res.json(updatedCustomer);
};

E eis um teste unitário simples (Mocha, Sinon):

describe("approveUser", () => {
    it("approve customer passing current user", () => {
        //arrange
        let customer = {approve: sinon.stub(), save: sinon.stub()};
        let req: any = {user: 'me', customer: customer},
            res: any = {json: sinon.stub()},
            next = sinon.stub();

        //act
        sut.approveUser(req, res, next);

        //assert
        req.customer.approve.calledWith(req.user);
    });
});

Digamos que queremos definir um breakpoint no teste e outro no próprio método. Assim:

Exemplo de Depuração de Teste de Integração de backend
Node.js

Exemplo de Controlador backend Node.js

Como provavelmente reparou na segunda imagem, o IntelliJ IDEA reconheceu o teste e colocou ícones especiais ícone de execução de teste que podem ser usados para executar um único teste ou toda a spec de uma vez. Ao clicar em qualquer um dos ícones, será apresentado um menu onde pode selecionar o que pretende fazer: Run ou Debug. Clicar em debug executará o teste e o IDE parará instantaneamente no primeiro breakpoint.

Exemplo de Depuração de Teste de Integração de backend
Node.js

Primeiro de tudo, podemos ver que o código TypeScript não foi transpilado, o que é ótimo, pois queremos ver o código original durante a depuração. Por baixo do capô, o IntelliJ IDEA usa o ts-node, de modo a que o código TypeScript seja transpilado em tempo real. Eis o comando que o IntelliJ IDEA usa para executar a sessão de depuração com o mocha:

--require ts-node/register
"C:\Program Files\nodejs\node.exe" --inspect-brk=58345 C:\Git\debug-
ts\node_modules\mocha\bin_mocha --require ts-node/register --timeout 0 --ui bdd --reporter
C:\Users\me\.IntelliJIdea2017.2\config\plugins\NodeJS\js\mocha-
intellij\lib\mochaIntellijReporter.js C:\Git\debug-
ts\server\test\unit\users\usersCtrl.unit.ts --grep "UNIT\: users\.ctrl approveUser approve
customer passing current user$"

A maioria dos parâmetros passados aqui são basicamente parâmetros do mocha. Mas, na verdade, nem precisa de perceber nada dessa magia, a menos que precise de alguma configuração personalizada.

Depuração de Testes de Integração

Assumindo que temos a nossa API web a correr em localhost:3333, podemos querer testá-la com testes de integração. Vejamos como é um teste de integração típico para o método do controlador self.approveUser mencionado acima.

it.only('should respond with updated user', async () => {
  //arrange
  let account = await dataHelpers.newRegisteredUser().save();
  let testUser = await dataHelpers.newUser().save();

  //act
  let response = await REST.users.approveUser(account, testUser.id);

  //assert
  response.status.should.equal(200);
  let approvedUser = await db.User.findById(testUser.id);
  response.body.should.eql(JSON.parse(JSON.stringify(approvedUser)));
});

Nota: it.only fará com que o Mocha execute apenas este teste específico.

No bloco arrange, preenchemos a base de dados com registos de teste. Depois, no bloco act, chamamos a nossa API enviando um pedido HTTP: POST localhost:3000/users/:userId/approve. E, por fim, no bloco assert, verificamos os resultados. Obviamente, aqui não usamos mocks em nenhum serviço, apenas chamamos a nossa API alojada localmente. Para realizar o pedido HTTP, usamos um serviço cliente especial – REST –, que usa o supertest por baixo do capô. Outra dependência aqui é o serviço dataHelpers. Este é o nosso cliente de base de dados simples, usado para pré-preencher dados de teste em cada teste específico.

De um modo geral, o IntelliJ IDEA reconhece o teste e também pode clicar no ícone ícone de execução de teste, mas o teste irá falhar. A razão é que o nosso teste exige agora mais dependências, nomeadamente – config com o host real da API e as definições de ligação à base de dados, hooks do mocha para criar a ligação à base de dados antes de todos os testes e fechá-la no final, asserções personalizadas, etc. Primeiro de tudo, vejamos como podemos executar testes de integração fora do IDE. Para isso, vamos criar um script no nosso package.json:

"scripts": {
    "it:dev": "mocha ./server/test/integration/**/*.it.ts --opts ./server/test/mocha.it.opts
     --config=./server/test/.config/dev-debug.json || true",
}

Como pode ver, estamos a executar o mocha passando três parâmetros:

  1. ./server/test/integration/**/*.it.ts – caminho para os ficheiros que precisam de ser executados pelo mocha

  2. --opts - caminho para o ficheiro de opções do mocha

  3. --config - caminho para o ficheiro de configuração (host da API, ligação à base de dados)

E eis um exemplo de como mocha.it.opts e dev-debug.json podem ser:

--require ts-node/register
--require ./server/test/assertions
--reporter spec
--recursive
./server/test/integration/hooks.ts
--full-trace
--exit
--inline-diffs
--retries 3
{
  "api": {
    "host": "localhost:3000"
  },
  "mongo": {
    "address": "mongodb://localhost/your-database",
    "options": {
      "server": {
        "socketOptions": {
          "keepAlive": 1
        },
        "auto_reconnect": true,
        "reconnectInterval": 1000
      }
    }
  }
 }
}

Executar npm run it-dev irá agora executar todos os testes com sucesso. Então, como podemos passar todos os parâmetros necessários no IDE? Bem, é bastante simples: pode abrir “Run -> Edit Configurations…” no menu principal e adicionar lá uma nova configuração Node.js, assim:

Configuração Run/Debug de testes de backend Node.js no
Intellij Configuração Run/Debug de testes de backend Node.js no Intellij

Ótimo, agora pode selecionar a sua configuração e executar/depurar todos os testes de uma vez. ícones de execução e depuração da configuração

Depuração da Aplicação em Execução

O exemplo anterior mostrou como depurar testes de integração, mas, infelizmente, o seu breakpoint no controlador da aplicação não interromperá a execução. Isto porque iniciamos a nossa aplicação fora do IDE, pelo que o Intellij não tem qualquer indicação sobre o nosso servidor em execução. Portanto, para lhe permitir controlar a execução da nossa aplicação, podemos simplesmente criar uma nova configuração Run/Debug para iniciar o nosso servidor. Em consequência, o nosso IDE irá ligar-se ao processo do backend Node.js e o debugger funcionará tal como queremos. Eis como a configuração pode ser:

Configuração Run/Debug de Backend Node.js no
Intellij Configuração Run/Debug de Backend Node.js no Intellij

Et voilà, agora podemos definir breakpoints nos nossos controladores e, sempre que o código for executado, o IDE parará no breakpoint e nos passará o controlo.

E Agora

Nós esperamos que este tutorial ajude alguém a perceber o básico de como configurar o IntelliJ IDEA para depurar aplicações backend Node.js. No entanto, é praticamente o mesmo se estiver a usar outro IDE como o VSCode/Atom. Se conhece outras formas de tornar a depuração ainda melhor, basta dizer-nos. E, claro, não hesite em partilhar este artigo nas redes sociais :)

Back to Blog

Related Posts

View All Posts »