Testando API com Unirest em Node.js
Published: 2024-02-22 19:33:55

Olhando o code snippet no Postman, me deparei com exemplos usando Unirest em Node.js. Fiquei curioso e resolvi dar uma olhada mais de perto.

Unirest é uma biblioteca HTTP client, desenvolvida e mantida pelo Kong, disponível em várias linguagens.

A documentação do [Unirest Node.js](https://github.com/Kong/unirest-nodejs) contém vários exemplos de Requests e Responses com a descrição de uso.

Com base nos exemplos, criei um projeto simples de testes automatizados de API. O framework de teste utilizado foi o [Vitest](https://vitest.dev/) entre outras dependências como: _dotenv_ e o _prettier_ , para gerenciamento de variáveis de ambiente e formatação de código, respectivamente.

---

### Iniciando o projeto
Assumindo que Node.js está ou foi instalado na máquina, podemos dar inicio ao projeto.
Crie o diretório com o nome e local que desejar, acesse-o, inicie um projeto node e instale as dependências.


No diretório do projeto execute o comando:

```
npm init -y
```


Com o arquivo package.json presente, instale as dependências:


- Unirest
```
npm install unirest
```
- Vitest
```
npm install -D vitest
```
- Dotenv
``` 
npm i dotenv
```
- Prettier - Opcional para este exemplo

```
npm install --save-dev --save-exact prettier
```

---

### Definindo a estrutura
Como disse é um projeto simples, motivado por curiosidade e estudo pessoal e aplicação de conhecimento.

Apesar de simples, serve como _boilerplate_ e claro adaptar e escalar de acordo com a necessidade. 

Incialmente o projeto está organizado em dois diretórios:
- **data**

Destinado a criação de dados em **JSON** utilizado nos testes. Use essa massa dados exemplificada.

```
{
  "books": {
    "create": {
      "firstname": "Richard",
      "lastname": "Bandler",
      "totalprice": 111,
      "depositpaid": true,
      "bookingdates": {
        "checkin": "2018-01-01",
        "checkout": "2019-01-01"
      },
      "additionalneeds": "Breakfast"
    },
    "update": {
      "firstname": "John",
      "lastname": "Grinder",
      "totalprice": 111,
      "depositpaid": true,
      "bookingdates": {
        "checkin": "2018-01-01",
        "checkout": "2019-01-01"
      },
      "additionalneeds": "Breakfast"
    }
  }
}
```
- **tests**

Aqui encontra-se o os arquivos de testes. Onde podemos organizar, como preferirmos. Nesse exemplo, criei apenas uma arquivo, no padrão `.test.js`. 

Tendo apenas um arquivo, agrupei os testes dentro de uma suíte, então ficou dessa forma:

```
describe("Testing restful-booker API with Unirest", () => {
  test("Should generate token", async () => {

  });

  test("Should register a book", async () => {
    
  });
...
});
```
---

### Implementando os testes
A **API** usada no projeto foi a  [restful-booker](https://restful-booker.herokuapp.com/apidoc/index.html) bem conhecida pela comunidade, para fins de estudo. 

**Criando o arquivo .env**
Antes de adentrar aos testes crie na raiz do projeto o arquivo `.env` com as variáveis e seus valores, conforme a documentação.

```
BASE_URL=https://restful-booker.herokuapp.com
USERNAME=admin
PASSWORD=password123
```
**Imports e variáveis**
Próximo passo é o _import_ das _libs_ e declaração das variáveis, ficando dessa forma:

```
import { describe, expect, test } from 'vitest';
const unirest = require('unirest');
const { books } = require('../data/books.json');
const dotenv = require('dotenv');
dotenv.config({ override: true });

let token;
let bookingId;

const BASE_URL = process.env.BASE_URL;
const USERNAME = process.env.USERNAME;
const PASSWORD = process.env.PASSWORD;
```

O primeiro teste é um método **POST** para criação do _token_, que será atribuído ao _cookie_ em outros métodos. 

Por ser uma estrutura base, mantive a autenticação como um teste. Uma melhor opção, pensando na evolução do projeto, seria criar uma função com a finalidade de obter o _token_ e usa-lá sempre que precisarmos

```
test('Should generate token', async () => {
    await unirest
      .post(`${BASE_URL}/auth`)
      .headers({
        Accept: 'application/json',
        'Content-Type': 'application/json',
      })
      .send({ username: USERNAME, password: PASSWORD })
      .then(function (res) {
        token = res.body.token;
        expect(res.status).toBe(200);
      });
  });
```

O próximo teste é o registro de um livro(_book_), também com o método **POST**. Neste usamos a massa de dados passando o _path_ `books.create`

```
 test('Should register a book', async () => {
    await unirest
      .post(`${BASE_URL}/booking`)
      .headers({
        'Content-Type': 'application/json',
        Accept: 'application/json',
      })
      .send(JSON.stringify(books.create))
      .then(function (res) {
        bookingId = res.body.bookingid;
        expect(res.status).toBe(200);
      });
  });
```

Agora é o teste de atualização de livros(_book_) com o método **PUT**. Usaremos massa de dados de `books.update` e conforme requerido o _token_.

```
 test('Should update a book', async () => {
    await unirest
      .put(`${BASE_URL}/booking/${bookingId}`)
      .headers({
        Accept: 'application/json',
        'Content-Type': 'application/json',
        Cookie: `token=${token}`,
      })
      .send(JSON.stringify(books.update))
      .then(function (res) {
        expect(res.status).toBe(200);
      });
  });
```
Finalizando com método **DELETE** onde é passado o `bookingid` no _path_ da URL. Esse valor é obtido no _response_ ao criarmos um livro.

```
test('Should remove a book', async () => {
    await unirest
      .delete(`${BASE_URL}/booking/${bookingId}`)
      .headers({
        Accept: 'application/json',
        'Content-Type': 'application/json',
        Cookie: `token=${token}`,
      })
      .then(function (res) {
        expect(res.status).toBe(201);
      });
  });
```
---

### Executando os testes
Além de asserções de _status code_, podemos fazer outras, então explore a vontade de acordo com os objetivos de cada teste.

No `package.json` adicione aos scripts:

```
"scripts": {
    "test": "vitest"
  },
```
No terminal execute o comando:

```
npm test
```
O _output_ com o resultado dos testes será esse:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fqtdelh7xcgd5q1jt2k0.png)

---
### Concluindo
Minha principal intenção com esse material, além de contribuir de alguma forma com a comunidade, foi a organização das informações, aplicação e transferência de conhecimento.