Resolvendo variáveis de ambiente em testes automatizados com dotenv

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:

describe("Teste recurso /login", async ()=>{
    it("login com sucesso", async ()=>{
        credentials = {
            "email":"[email protected]",
            "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

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.

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

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.

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:

"test-dev": "export EMAIL='[email protected]' && export PASSWORD='teste' &&  mocha --file login-test.js",

Obtive sucesso no teste

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.

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.

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:

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.

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 e cross-env

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

GitHub logo rafaelbercam / api-tests-typescript

Automação de Testes de API com TypeScript

Boilerplate Testes de API em TypeScript

Pré-requisitos

  1. Instalar o Node

Ambiente

Para executar os testes localmente, estou utilizando o ServeRest

Logo do ServeRest

Link do Repo: https://github.com/ServeRest/ServeRest

ServeRest está disponível de forma online, no npm e no docker.

Instalando Dependências

  1. Rodar o comando
npm i
  1. Criar arquivo .env na raiz do projeto

Criar o arquivo com as seguintes variáveis

PROD=https://serverest.dev
DEV=http://localhost:3000
  1. Rodar os testes localhost
npm run test-dev
  1. Para rodar os testes em Produção
npm run test-prod

Configuração do Projeto

Estrutura de Pastas

O projeto esta dividido da seguinte maneira:

[api-tests-typescript]
   [src] -> código fonte
        [config] -> arquivos de configuração ambiente
        [factory] -> métodos para criar objetos
        [services] -> funções que retornam requisições das rotas
        [test] -> Arquivos de testes com Mocha e Chai
   .env -> arquivo com variáveis de ambiente(normalmente não commitada)
   .mocharc.js -> arquivo de configuração do Mochawesome

Services

Services são funções que retornam requests pré-estabelecidas de cara um…

20