Laços de repetição com funções recursivas e comandos do Cypress
Published: 2022-08-04 19:21:00

Recentemente me deparei com um problema, onde utilizava `cy.wait()` para esperar até que dados de um sistema passassem por alguns micro-serviços e fossem refletidos em outro sistema que era uma API, o problema é que utilizando `cy.wait()` os dados poderiam já terem sido refletidos, mas o Cypress ainda iria continuar esperando o tempo pré-definido. 

Buscando então uma solução, pensei em criar uma forma onde o código iria ficar consultando a requisição da Api, durante um certo tempo ou até que o dado fosse refletido. 

Inicialmente pensei em utilizar laços de repetição tradicionais (do, while, do while), assim colocaria uma condição onde o loop iria parar caso o número de interações chegasse ao limite ou os dados fossem refletidos na Api. Mas com Cypress isso não é possível, pelo fato desses laços de repetição serem síncronos, mas o comando (`cy.request`) do Cypress ser assíncrono.

Desta maneira, a outra forma que encontrei foi  utilizar funções recursivas, que são funções que chamam a si mesmo até uma certa condição ser satisfeita, uma vez satisfeita a chamada das funções é encerrada.

**Exemplo de função recursiva com código do Cypress** 

Inicialmente criei uma função que recebe como parâmetro um contador, que será o número de tentativas de consulta na API.

```
function recursiva(contador = 60) {
```

Em seguida, inseri as informações para realizar a requisição no comando `cy.request`:

```
cy
		.request({
			method: 'GET',
			url: 'https://UrlDeExemplo.com.br',
			log: false,
			failOnStatusCode: false
		})
```
Deixei a flag `log` desativada para não mostrar todas as requisições no console do Cypress, e também desativei a flag `failOnStatusCode` para o Cypress não dar erro de execução caso a requisição falhe.

Assim, uma vez o `cy.request` executado, eu obtenho a resposta da requisição utilizando o comando `.then()` e salvando o valor na variável `resposta`. 

Dentro `.then()` é onde coloco as condições para encerrar a chamada de função:

1. No primeiro `if` verifico se o status da resposta foi 200, isso significa que o dado foi refletido na API, assim posso encerrar a chamada das funções; 

2. Na segunda, caso o contador chegue a 0,  significa que o número total de requisições que defini foi executado e as respostas das requisições continuaram não dando 200, assim considero que os dados não foram refletidos e posso acabar também a execução das funções;

3. E por último, é caso a requisição não deu 200 e o número de requisições não foram finalizadas, assim decremento um na variável `contador` e chamo a função novamente passando o novo valor do contador.

```
.then((resposta) => {
			if (resposta.status === 200) return;
			else if (contador === 0) {
				cy.log('Os dados não foram refletidos');
				return;
			} else {
				const DECREMENTA_CONTADOR = contador - 1; 
				recursiva(DECREMENTA_CONTADOR);
			}
		});
```

Juntando as partes do código,  ele fica da seguinte maneira: 

```
function recursiva(contador = 60) {
	cy
		.request({
			method: 'GET',
			url: 'https://UrlDeExemplo.com.br',
			log: false,
			failOnStatusCode: false
		})
		.then((resposta) => {
			if (resposta.status === 200) return;
			else if (contador === 0) {
				cy.log('Os dados não foram refletidos');
				return;
			} else {
				const DECREMENTA_CONTADOR = contador - 1; 
				recursiva(DECREMENTA_CONTADOR);
			}
		});
}
```

O código acima pode ser adaptado de acordo com sua necessidade, o que mais é importante é a condição para parar a execução da função.

**Conclusão**

Utilizando funções recursivas é possível realizar laços de repetição com comandos do Cypress. O principal fato de ter optado por essa escolha foi evitar o uso de `cy.wait()` e assim diminuir o tempo de execução, mas ainda continuar garantido que se o dado não foi refletido para a API não foi por questão de espera de tempo.

**Créditos**

Créditos para o Rodrigo Matola que deu idéia de utilizar funções recursivas para resolver o problema.

Linkdin do Rodrigo: https://www.linkedin.com/in/rodrigomatola/

Meu Linkdin:
https://www.linkedin.com/in/jo%C3%A3o-pedro-costi-78a874a2/