> For the complete documentation index, see [llms.txt](https://docs.decentraland.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.decentraland.org/contributor/contributor-pt/guias-para-colaboradores/testing-standards/writing-tests.md).

# Escrever testes

Os testes podem ser escritos de várias maneiras. Esta seção tenta dar um padrão e uma justificativa para a forma como escrevemos testes.

Os testes DEVEM ser escritos usando o **describe** e o **it** métodos fornecidos pelo jest

## seção Descrevendo e construindo contexto

O **describe** O método DEVE ser usado para descrever, sempre que possível, o contexto em que a parte do código a ser testada será executada e DEVE construir esse contexto dentro do seu escopo.

```tsx
describe('quando a flag está vermelha', () => {
	...
})

describe('quando a flag está azul', () => {
	...
})
```

Para descrever o contexto, DEVEMOS usar uma das seguintes palavras: **quando** para describes de nível superior e **tendo** ou **e** para indicar que existe um contexto que depende de outro contexto definido anteriormente. A justificativa para isso é ter contextos auto-descritos que possam ser facilmente entendidos e verificados combinando as frases de describe. Como a ideia é concatenar as descrições dos contextos, **describes** DEVEM ser escritos em minúsculas.

```tsx
describe('quando a flag está vermelha', () => {
	...
	describe('e o vento está forte', () => {
     // O contexto aqui é descrito pela conjunção dos describes:
     // "quando a flag vermelha está vermelha e o vento está forte"
     ...
  })
})
```

Múltiplos describes podem ser aninhados no mesmo nível e em um nível mais baixo. Os describes no mesmo nível denotam contextos diferentes e os describes em níveis mais baixos (describes aninhados) denotam um contexto mais específico.

```tsx
describe('quando a flag está vermelha', () => {
	...
	describe('e o vento está forte', () => {
     ...
  })

	describe('e o vento está fraco', () => {
     ...
  })
})
```

Como mencionado antes, cada describe DEVE ser acompanhado por um método que constrói o contexto ou por um método que destrói ou altera o contexto. Os métodos que DEVEM ser usados são os **beforeEach** e o **afterEach**.

{% hint style="warning" %}
O framework Jest tem dois métodos, **beforeEach** e **beforeAll**, mas combinar ambos gera confusão e problemas de execução quando contextos aninhados estão presentes, pois [a ordem em que eles são executados](https://jestjs.io/docs/setup-teardown#scoping) não é o que esperaríamos.
{% endhint %}

Os contextos criados com o **beforeEach** método serão cada vez mais definidos à medida que avançamos mais fundo na árvore de describe. Cada **beforeEach** um especificará o contexto de forma mais precisa de acordo com o que seu texto diz.

### Escopo de Variáveis

O **variáveis** definidas nos contextos DEVEM ser definidas de acordo com o escopo em que vão ser usadas. Ou seja, se uma variável for usada apenas para um contexto específico em um nível aninhado de describes, a variável DEVE ser definida apenas nesse contexto específico. A justificativa para isso é manter as variáveis próximas do código em que estão sendo usadas, tornando o código mais fácil de entender.

```tsx
let flag = 'azul'
describe('quando a flag está vermelha', () => {
	let wind = 'morno'
	beforeEach(() => {
    flag = 'vermelha'
  })
  ...

	describe('e o vento está forte', () => {
		beforeEach(() => {
	    wind = 'forte'
	  })
    ...
  })

	describe('e o vento está fraco', () => {
		beforeEach(() => {
	    wind = 'fraco'
	  })
    ...
  })
})
```

Variáveis de **tipos primitivos**, que **não serão alterados** no contexto em que são definidos ou em contextos subsequentes DEVEM ser definidos como **const** uma única vez, acima da **beforeEach** definição no escopo.

Variáveis de **tipos primitivos** que serão alterados no contexto em que são definidos ou em contextos subsequentes DEVEM ser definidos como **let**, pois a natureza do TypeScript assim o exige.

Variáveis de **tipos não primitivos** (objetos, arrays, etc.) DEVEM ser definidos como **let** e seu valor DEVE ser definido em um **beforeEach.** A justificativa para isso é que objetos em JS são mutáveis, o que significa que qualquer execução de código que use esse objeto está sujeita a mudanças e a afetar outros testes de maneira involuntária.

```tsx
let flag
describe('quando a flag está vermelha', () => {
  // Um valor primitivo que será modificado em vários escopos.
	let wind
  // Um valor de objeto que será usado no código do teste.
  let someObject
	beforeEach(() => {
    flag = 'vermelha'
		someObject = { id: 1 }
  })
  ...

	describe('e o vento está forte', () => {
		// Um valor primitivo constante que será usado apenas neste escopo.
		const aConstantPrimitiveValue = 'alguma coisa'
		beforeEach(() => {
	    wind = 'forte'
	  })
    ...
  })

	describe('e o vento está fraco', () => {
		beforeEach(() => {
	    wind = 'fraco'
	  })
    ...
  })
})
...
```

Variáveis DEVEM ser tipadas corretamente sempre que possível. Tipos repetidos DEVEM ser abstraídos em um type.

```tsx
let flag: string
describe('quando a flag está vermelha', () => {
  // Um valor primitivo que será modificado em vários escopos.
	let wind: string
  // Um valor de objeto que será usado no código do teste.
  let someObject: { id: string }
	beforeEach(() => {
    flag = 'vermelha'
		someObject = { id: 1 }
  })
  ...

	describe('e o vento está forte', () => {
		// Um valor primitivo constante que será usado apenas neste escopo.
		const aConstantPrimitiveValue = 'alguma coisa'
		beforeEach(() => {
	    wind = 'forte'
	  })
    ...
  })

	describe('e o vento está fraco', () => {
		beforeEach(() => {
	    wind = 'fraco'
	  })
    ...
  })
})
...
```

## Descrevendo expectativas e executando código

O **it** método DEVE estar sempre colocado dentro do escopo de um **describe** e DEVE ser usado para descrever o que esperamos do código que vamos testar e DEVE conter, se possível, apenas **uma** asserção. Várias asserções por **it** podem existir se houver um problema de desempenho, já que os testes serão executados uma vez por **it** (por causa do **beforeEach**), ou se o que é esperado puder ser descrito com clareza na descrição da expectativa.

```tsx
let flag: string
describe('quando a flag está vermelha', () => {
	let wind: string
  let someObject: { id: string }
	beforeEach(() => {
    flag = 'vermelha'
		someObject = { id: 1, swim: jest.fn() }
  })
  ...

  // Expectativa única da execução de um teste em um contexto (um it)
	describe('e o vento está forte', () => {
		const aConstantPrimitiveValue = 'alguma coisa'
		beforeEach(() => {
	    wind = 'forte'
	  })
    
		it('não deve ir nadar', () => {
      expect(goSwimming(flag, wind, someObject)).toBe(false)
    })
  })

  // Múltiplas expectativas da execução de um teste em um contexto (dois its)
	describe('e o vento está fraco', () => {
    let result: boolean
		beforeEach(() => {
	    wind = 'fraco'
      result = goSwimming(flag, wind, someObject)
	  })

		it('deve ir nadar', () => {
      expect(goSwimming(flag, wind, someObject)).toBe(true)
    })

    it('deve ter chamado o método swim', () => {
      expect(someObject.swim).toHaveBeenCalled()
    })
  })
})
...
```

A justificativa para essa estrutura é fornecer clareza ao revisor dos testes e aos desenvolvedores que vão manter e fazer alterações no código, já que cada contexto e expectativa são claramente enumerados, tornando mais fácil entender o que está sendo testado, como está sendo testado e o que ainda falta testar.

Seguindo as **describe** descrições até os **it**s, os desenvolvedores podem entender facilmente o que está sendo testado ao concatenar as frases.

```tsx
// Isto é lido como: "quando a flag está vermelha e o vento está forte, 
// ele deve ir nadar"
describe('quando a flag está vermelha', () => {
  ...
  describe('e o vento está forte', () => {
		...
		it('deve ir nadar', () => {
			...
		})
  })
})
```

### Escrevendo Expectativas Claras

A descrição das expectativas escritas no **it**s DEVEM ser o mais descritivas possível sobre o que é esperado da execução dos testes. Os desenvolvedores NÃO DEVEM usar frases abstratas ou genéricas para definir expectativas, pois isso remove a clareza sobre o que se espera do código.

{% hint style="danger" %}
**O desenvolvedor NÃO DEVE usar frases como:**

* "should work as expected" ⇒ O que deve funcionar como esperado?
* "should return the correct value" ⇒ Qual é o valor correto?
* "should resolve/return/work correctly" ⇒ Como algo funciona corretamente?
* "should fail" ⇒ Como deve falhar? Qual é a mensagem que deve fornecer?
  {% endhint %}

É preciso levar em consideração que, ao especificar o que é esperado nos **it**s ou qual será o contexto nos **describe**s, os desenvolvedores PODEM usar nomes de funções ou mensagens de erro exatas se isso for necessário para entender melhor a intenção, mas DEVEM usar uma representação textual quando possível para tornar os testes mais fáceis de manter.

```tsx
// math.ts
export function div(a: number, b: number): number {
	if(b === 0)	{
		throw new Error('O divisor b é igual a 0, a divisão não pode ser realizada')
	}
}

// test.spec.ts
import { div } from './math.ts'

describe('quando dividir por zero', () => {
  // A descrição do it descreve a intenção da mensagem da exceção
	it('deve lançar uma exceção sinalizando que uma divisão por 0 não é possível', () => {
		expect(() => div(12, 0)).toThrowError('O divisor b é igual a 0, a divisão não pode ser realizada')
	})
})
```

## O que testar

Escolher o que testar pode variar dependendo do código que está sendo executado. Diferentes fatores, desde desempenho ou um grande domínio de entradas, podem certamente mudar o que deve ou não ser testado nos testes. Aqui vamos expor um conjunto único de casos que o desenvolvedor DEVE testar, se possível.

```tsx
function run(kilometers: number): number {
	if(kilometers > 1000) {
    throw new Error('O corredor não pode correr mais de 1000 quilômetros')
  }

  if(kilometers <= 10) {
		return kilometers
  } else if(kilometers > 10) {
		doSomething(kilometers)
    return beLazy(kilometers)
  }
}
```

A função run aqui tem alguns fluxos de execução diferentes. Funções, ou seções de código, NÃO DEVEM ser testadas apenas com base nos diferentes fluxos de execução possíveis, mas sim no que é esperado da função, já que ela pode não estar fazendo o que foi escrita para fazer e os testes podem ficar fortemente acoplados ao código e não detectar diferentes problemas nele. Isso implica que o desenvolvedor DEVE sempre testar todos os possíveis caminhos de execução e DEVE testar também outros caminhos possíveis, de acordo com a semântica da função.

Para este caso específico, o desenvolvedor DEVE testar **pelo menos** os seguintes casos:

1. Executar a função run com uma quantidade de quilômetros maior que 1000
2. Executar a função run com uma quantidade de quilômetros igual a 10
3. Executar a função run com uma quantidade de quilômetros maior que 10, mas menor que 1000

Para o primeiro caso, o desenvolvedor precisa testar que a função run lança uma exceção. **As exceções DEVEM ser verificadas pela sua mensagem de erro**, pois qualquer outra exceção também pode ser lançada, invalidando o propósito do teste. Se a exceção for uma exceção personalizada, o desenvolvedor PODE verificar a instância da exceção.

Para o segundo caso, o desenvolvedor precisa testar que a função retornou o mesmo número de quilômetros que lhe foi dado.

Para o terceiro caso, o desenvolvedor precisa testar que a função retornou o que uma função externa, **beLazy** retornou e, como **doSomething** (também executada no método) não pode ser verificada por meio do valor de retorno da função, o desenvolvedor DEVE **testar que ela foi chamada com os argumentos corretos**.

```tsx
import { doSomething, beLazy } from '../runningUtils'
jest.mock('../runningUtils')

// Observe que não há describe principal
// O único contexto global são funções que queremos simular com jest

const mockDoSomething = doSomething as jest.MockedFunction<typeof doSomething>
const mockBeLazy = beLazy as jest.MockedFunction<typeof beLazy>

describe('quando executar mais de 1000 quilômetros', () => {
	it('deve lançar um erro sinalizando que o corredor não pode correr mais de 1000 quilômetros', () => {
		expect(() => run(1001)).toThrowError('O corredor não pode correr mais de 1000 quilômetros')
	})
})

describe('quando executar 10 quilômetros ou menos', () => {
	it('deve retornar a mesma quantidade de quilômetros que foi dada', () => {
		expect(run(2)).toEqual(2)
	})
})

describe('quando executar mais de 10 quilômetros, mas menos de 1000', () => {
	const kilometers = 50
	let result: number
	beforeEach(() => {
		mockDoSomething.mockReturnValueOnce(undefined)
		mockBeLazy.mockImplementationOnce(value => value)
		result = run(kilometers)
	})
	
	it('deve retornar os quilômetros depois de ficar preguiçoso', () => {
		expect(result).toEqual(kilometers)
	})

	it('deve chamar a função doSomething com os quilômetros dados', () => {
		expect(mockDoSomething).toHaveBeenCalledWith(kilometers)
	})
})
```

## Quando simular

A simulação dependerá principalmente do tipo de testes que o desenvolvedor está escrevendo.

* Testes unitários DEVEM ter todas as funções externas simuladas, com a exceção de funções que fazem coisas simples, como formatar strings, etc.
* Testes de API DEVEM ter mocks apenas para comunicar com serviços externos, isto é, DBs ou APIs diferentes. Se uma das operações realizadas no teste afetar o desempenho da suíte de testes, um mock pode ser implementado para mitigar esse problema.

Todos os mocks DEVEM ser feitos usando as ferramentas fornecidas pelo Jest, com exceção dos `redux-saga-test-plan` mocks.

### Mocks e funções utilitárias

* Quaisquer mocks do Jest DEVEM ser simulados usando seu **once** método, quando possível, ou seja, `mockReturnValueOnce` ou `mockResolvedValueOnce` não é recomendado usar `mockReturnValue` ou `mockResolvedValue`A justificativa para isso é impedir que mocks indesejados sejam executados, alterando a execução dos nossos testes.
* O Jest oferece uma série de tipos que você pode usar para diferentes tipos de mocks. Por exemplo, ao simular um objeto, você DEVE usar `jest.Mocked<typeof someObject>`, para classes você DEVE usar `jest.MockedClass<typeof SomeClass>`, e para funções, `jest.MockedFunction<typeof someFunction>`.
* Um `afterEach` DEVE ser escrito para ser executado após cada teste com um `jest.resetAllMocks` para limpar qualquer implementação simulada de módulos simulados globalmente que possa vazar para outros testes. Você pode ignorar esse reset se estiver usando `mockReturnValueOnce` ou `mockResolvedValueOnce` porque isso é feito automaticamente para você.
* Um diretório chamado `mocks` PODE ser criado para armazenar mocks, que devem ser colocados no diretório `test` ou `spec` diretório. Mocks grandes DEVEM ser armazenados em arquivos diferentes dos testes para evitar arquivos de teste extensos. Mocks pequenos, se não houver muitos, DEVEM ser mantidos nos testes.
  * Os arquivos de mock DEVEM ser nomeados de acordo com a entidade que estão simulando, então, por exemplo, se estivermos simulando um profile, o mock deve ser colocado no `/test/mocks/profile.ts` arquivo.
  * No caso de serem necessários vários mocks grandes, eles DEVEM ser colocados em arquivos diferentes dentro de um diretório chamado como a entidade a ser simulada, então, por exemplo, se tivermos dois mocks de profile, vamos armazená-los como: `/test/mocks/profile/profile-with-wearables.ts` e `/test/mocks/profile/profile-without-wearables.ts`. Para acessá-los facilmente, você DEVE criar um `index.ts` arquivo dentro do `/test/mocks/profile/` diretório e exportá-los.
  * Para evitar a mutação de objetos simulados, os mocks **DEVEM ser exportados como funções** que os retornam.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.decentraland.org/contributor/contributor-pt/guias-para-colaboradores/testing-standards/writing-tests.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
