Resolvendo variáveis de ambiente em testes automatizados com dotenv
Tags: seguranca, testes, qa
Published: 2021-07-02 16:56:49

## O Problema

Sempre é uma questão recorrente de, como utilizar variáveis de ambiente em testes automatizados? Como remover do código credenciais de acesso, urls de acesso ao sistema e diminiur a vulnerabilidade?

Isso é extremamente importante quando o assunto é segurança dos seus repos (mesmo privados), então o que me motivou a criar este post é mostrar como fazer isso usando recursos simples, disponíveis na maior parte das linguagens e frameworks de mercado.

### Variáveis de ambiente, o que são?

> Uma variável de ambiente possui um valor recebido de forma dinâmica, que pode afetar a forma em que os processos em execução se comporta no sistema operacional.

Trocando `seis` por `meia dúzia`, são variáveis que em tempo de execução recebem valores definidos de forma dinâmica, podendo customizar o valor de acordo com o ambiente executado. 
Um bom exemplo são ambientes de execução como `Dev`, `Homolog` e `Produção`, ou credenciais de acesso nesses diferentes ambientes como `email` e `senha`.

E quais são os riscos de deixar isso no repositório?

Pode ser até uma pergunta fácil de responder, mas os riscos variam de acordo com o sistema em que você atua.

Imagine um ambiente que comumente é atacado e explorado sua vulnerabilidade? Qualquer brecha é um risco para que exponha dados sensíveis para o mundo externo. Mesmo em repositórios privados, tem o fator humano que pode expor propositalmente e complicar a vida de um time inteiro. 

Então sem mais delongas, vamos ver como resolver isso dentro dos códigos e quais soluções de mercado temos para isso.

#### .ENV

Dentro do ecossistema JavaScript, temos o `dotenv` que é uma lib muito comum e fácil de usar.

vamos analisar o seguinte trecho de código:

```typescript
describe("Teste recurso /login", async ()=>{
    it("login com sucesso", async ()=>{
        credentials = {
            "email":"fulano@qa.com",
            "password":"teste"}
        response = await postLogin(credentials);
        expect(response.statusCode).to.eq(200);
        expect(response.body.message).to.eq(
            "Login realizado com sucesso");
    })
})
```
Pois bem, as credenciais de acesso estão expostas no código, e podem ser facilmente identificadas pelos termos de pesquisa de código como `password`, `email`.

Em um sistema operacional como o Linux, quando precisamos atribuir um valor a uma variável de ambiente em tempo de execução, usando o comando:
>  `export VARIAVEL='valor-da-variavel'`

E para imprimir o valor e conferir o seu armazenamento podemos usar o comando 

> `echo $VARIAVEL`
> `// valor-da-variavel`
 
vide exemplo abaixo

![Vaviáveis de ambiente exportadas no terminal](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6kfuk2x3j7kxcjf450gu.png)

Considerando essa informação, vamos fazer um teste com nosso trecho de código onde vou substituir os valores que estão expostos por variáveis de ambiente em tempo de execução. Para isso vamos usar o `process.env`.

O `process.env` é um recurso do próprio do node de pegar as variáveis de ambiente do sistema.
Se usarmos o mesmo teste do terminal imprimindo apenas as variáveis de ambiente do SO usnado o `process.env` do node.js.

![variáveis de ambiente process.env](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wybq4inzlw6ihgog324c.png)

Ao começar a digitar o `process.env` no node, o terminal já exibe previamente uma lista de variáveis que o sistema disponibiliza. Essas variáveis são definidas previamente quando ligamos o computador e damos o arranque no sistema operacional, para isso ele pega as variáveis de ambiente definidas em arquivos específicos.

Exemplo: `~./bashrc` do Linux

Quando exportamos uma variável como mostra no comando da imagem acima, elas ficam disponíveis enquanto o terminal está em execução, então essas variáveis são listadas quando imprimimos:

vide saída do comando `process.env`

![variável email](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ktyb6l4zribo5wz92i2v.png)

![vairável password](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0a8smhzhu7thafa5hu1r.png)

Então, vamos fazer um teste: Antes de executar o mesmo trecho de código vou substituir os valores por `process.env.EMAIL` e `process.env.PASSWORD` e executar o código.

```typescript
describe("Teste recurso /login", async ()=>{
    it("login com sucesso", async ()=>{
        credentials = {
            "email":`${process.env.EMAIL}`,
            "password":`${process.env.PASSWORD}`}
        response = await postLogin(credentials);
        expect(response.statusCode).to.eq(200);
        expect(response.body.message).to.eq(
            "Login realizado com sucesso");
    })
})
```

Executando o comando para realizar o teste exportando as variáveis:

```shell
"test-dev": "export EMAIL='fulano@qa.com' && export PASSWORD='teste' &&  mocha --file login-test.js",
```

Obtive sucesso no teste

![Testes executados com sucesso](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o6rcwz0cczfd4ovmth8a.png)

Então precisamos exportar sempre? Claro que não!

Vamos utilizar uma lib popular que ja mencionei que se chama dotenv. Para isso, use o comando de instalar a dependência dotenv no seu projeto usando o gerenciador de dependências

Exemplo: `yarn add dotenv` ou `npm install dotenv`

Após a instalação, crie um arquivo na raiz do projeto `.env` contendo os valores das variáveis de ambiente.

![Variáveis de ambiente no arquivo .env](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tk635gfxn1rs0swnoqzq.png)

Crie as variáveis de ambiente, contendo todas as informações que precisa abstrair do sistema para as variáveis de ambiente.

Agora na classe de testes, vamos substituir os valores das credenciais por variáveis de ambiente. E também vamos importar o arquivo .env para dentro da classe de testes.

```typescript
import * as dotenv from 'dotenv'
dotenv.config({ path: '../../.env' });



describe("Teste recurso /login", async ()=>{
    it("login com sucesso", async ()=>{
            credentials = {
                email: `${process.env.EMAIL}`,
                password: `${process.env.PASSWORD}`
            }
            console.log(credentials);
            
        response = await postLogin(credentials);
        expect(response.statusCode).to.eq(200);

    })
})
```
Repare que no código estou imprimindo as credenciais para ter certeza que o valor esta sendo atribuído para as variáveis de ambiente.

Executando o teste então temos:

![Testes executados imprimindo os valores das variáveis](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/89q5mootu5rljhum7drs.png)


Veja como é simples!
Agora tem uma dica importante. Precisamos adicionar no .gitignore o arquivo .env e criar um arquivo de exemplo para quem foi baixar o seu repositório, saiba que precisa cria-lo para expor as variáveis de ambiente.

![Exemplo do arquivo .env.example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/imm69mzsjnw6zrvrcxsy.png)


#### Concluindo

Este foi um exemplo simples de configuração, lembrando que existem maneiras mais abstratas e combinadas com uso de outras libs como cross-env

Aqui estão os repositórios oficiais do [dotenv](https://www.npmjs.com/package/dotenv) e [cross-env](https://www.npmjs.com/package/cross-env)

Neste repositório, eu utilizo os mesmos recursos deste post!

{% github rafaelbercam/api-tests-typescript %}