> 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-do-contribuidor/testing-standards/writing-tests.md).

# Escrever Testes

Os testes podem ser escritos de várias maneiras. Esta seção tenta fornecer um padrão e a justificativa por trás da forma como escrevemos testes.

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

## Describing and building context

O **describe** o método DEVE ser usado para descrever, sempre que possível, o contexto no qual o trecho de código a ser testado será executado e DEVE construir esse contexto dentro do seu escopo.

```tsx
describe('when the flag is red', () => {
	...
})

describe('when the flag is blue', () => {
	...
})
```

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

```tsx
describe('when the flag is red', () => {
	...
	describe('and the wind is strong', () => {
     // O contexto aqui é descrito pela conjunção dos describes:
     // "when the red flag is red and the wind is strong"
     ...
  })
})
```

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

```tsx
describe('when the flag is red', () => {
	...
	describe('and the wind is strong', () => {
     ...
  })

	describe('and the wind is weak', () => {
     ...
  })
})
```

Como mencionado antes, cada describe DEVE ser acompanhado por um método que construa o contexto ou um método que destrua ou altere o contexto. Os métodos que DEVEM ser usados são o **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 %}

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

### Escopo de Variáveis

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

```tsx
let flag = 'blue'
describe('when the flag is red', () => {
	let wind = 'mild'
	beforeEach(() => {
    flag = 'red'
  })
  ...

	describe('and the wind is strong', () => {
		beforeEach(() => {
	    wind = 'strong'
	  })
    ...
  })

	describe('and the wind is weak', () => {
		beforeEach(() => {
	    wind = 'weak'
	  })
    ...
  })
})
```

Variáveis de **tipos primitivos**, que **não serão mudadas** no contexto em que estão definidas ou em contextos subsequentes DEVEM ser definidas como **const** uma vez, sobre a **beforeEach** definição no escopo.

Variáveis de **tipos primitivos** que serão alterados no contexto em que estão definidos ou em contextos subsequentes DEVEM ser definidos como **let**, conforme a natureza do Typescript 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 por trás disso é 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 alterações e pode afetar outros testes de maneira involuntária.

```tsx
let flag
describe('when the flag is red', () => {
  // Um valor primitivo que será modificado em múltiplos escopos.
	let wind
  // Um valor objeto que será usado no código do teste.
  let someObject
	beforeEach(() => {
    flag = 'red'
		someObject = { id: 1 }
  })
  ...

	describe('and the wind is strong', () => {
		// Um valor primitivo constante que será usado apenas neste escopo.
		const aConstantPrimitiveValue = 'something'
		beforeEach(() => {
	    wind = 'strong'
	  })
    ...
  })

	describe('and the wind is weak', () => {
		beforeEach(() => {
	    wind = 'weak'
	  })
    ...
  })
})
...
```

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

```tsx
let flag: string
describe('when the flag is red', () => {
  // Um valor primitivo que será modificado em múltiplos escopos.
	let wind: string
  // Um valor objeto que será usado no código do teste.
  let someObject: { id: string }
	beforeEach(() => {
    flag = 'red'
		someObject = { id: 1 }
  })
  ...

	describe('and the wind is strong', () => {
		// Um valor primitivo constante que será usado apenas neste escopo.
		const aConstantPrimitiveValue = 'something'
		beforeEach(() => {
	    wind = 'strong'
	  })
    ...
  })

	describe('and the wind is weak', () => {
		beforeEach(() => {
	    wind = 'weak'
	  })
    ...
  })
})
...
```

## Descrevendo expectativas e executando código

O **it** o método DEVE ser 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. Múltiplas asserções por **it** podem existir se houver um problema de performance, 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('when the flag is red', () => {
	let wind: string
  let someObject: { id: string }
	beforeEach(() => {
    flag = 'red'
		someObject = { id: 1, swim: jest.fn() }
  })
  ...

  // Expectativa única da execução de um teste em um contexto (um it)
	describe('and the wind is strong', () => {
		const aConstantPrimitiveValue = 'something'
		beforeEach(() => {
	    wind = 'strong'
	  })
    
		it('should not go swimming', () => {
      expect(goSwimming(flag, wind, someObject)).toBe(false)
    })
  })

  // Múltiplas expectativas da execução de um teste em um contexto (dois its)
	describe('and the wind is weak', () => {
    let result: boolean
		beforeEach(() => {
	    wind = 'weak'
      result = goSwimming(flag, wind, someObject)
	  })

		it('should go swimming', () => {
      expect(goSwimming(flag, wind, someObject)).toBe(true)
    })

    it('should have called the swim method', () => {
      expect(someObject.swim).toHaveBeenCalled()
    })
  })
})
...
```

A justificativa por trás dessa estrutura é fornecer clareza ao revisor dos testes e aos desenvolvedores que irão manter e alterar o código, já que cada contexto e expectativa está claramente enumerado, tornando mais fácil entender o que está sendo testado, como está sendo testado e o que falta testar.

Seguindo os **describe** descritores até os **it**os desenvolvedores podem facilmente entender o que está sendo testado concatenando as sentenças.

```tsx
// Isso é lido como: "when the flag is red and the wind is strong, 
// it should go swimming"
describe('when the flag is red', () => {
  ...
  describe('and the wind is strong', () => {
		...
		it('should go swimming', () => {
			...
		})
  })
})
```

### Escrevendo Expectativas Claras

A descrição das expectativas escritas nos **it**DEVE ser o mais descritiva possível sobre o que se espera da execução dos testes. Os desenvolvedores NÃO DEVEM usar frases abstratas ou gerais para definir expectativas, pois isso reduz a clareza do que está sendo esperado 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 %}

Deve-se levar em consideração que ao especificar o que é esperado nos **it**ou qual será o contexto nos **describe**os desenvolvedores PODEM usar nomes de funções ou mensagens de erro exatas se 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('The divisor b equals 0, the division can\'t be performed')
	}
}

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

describe('when dividing by zero', () => {
  // A descrição do it descreve a intenção da mensagem da exceção
	it('should throw an exception signaling that a division by 0 is not possible', () => {
		expect(() => div(12, 0)).toThrowError('The divisor b equals 0, the division can\'t be performed')
	})
})
```

## O que testar

Escolher o que testar pode variar dependendo do código que está sendo executado. Diferentes fatores, desde performance até um grande domínio de entradas, podem definitivamente alterar o que deve ou não ser testado. Aqui exporemos um único conjunto de casos que o desenvolvedor DEVE testar, se possível.

```tsx
function run(kilometers: number): number {
	if(kilometers > 1000) {
    throw new Error('The runner can\'t run more than 1000 kilometers')
  }

  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 trechos de código, NÃO DEVEM ser testados apenas com base nos diferentes fluxos de execução possíveis, mas no que se espera da função, pois a função pode não estar fazendo aquilo para o qual foi escrita e os testes podem ficar fortemente acoplados ao código e não detectar problemas diferentes. Isso implica que o desenvolvedor DEVE sempre testar todos os caminhos de execução possíveis e DEVE testar outros caminhos possíveis também, 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. **Exceções DEVEM ser verificadas quanto à sua mensagem de erro**, pois qualquer outra exceção também poderia ser lançada, invalidando o propósito do teste. Se a exceção for 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 foi fornecido.

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 através 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')

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

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

describe('when running more than 1000 kilometers', () => {
	it('should throw an error signaling that the runner can\'t run more than 1000 kilometers', () => {
		expect(() => run(1001)).toThrowError("The runner can't run more than 1000 kilometers")
	})
})

describe('when running less or equal than 10', () => {
	it('should return the same amount of kilometers as the ones given', () => {
		expect(run(2)).toEqual(2)
	})
})

describe('when running more than 10 kilometers but less than 1000', () => {
	const kilometers = 50
	let result: number
	beforeEach(() => {
		mockDoSomething.mockReturnValueOnce(undefined)
		mockBeLazy.mockImplementationOnce(value => value)
		result = run(kilometers)
	})
	
	it('should return the kilometers after being lazy', () => {
		expect(result).toEqual(kilometers)
	})

	it('should call the doSomething function with the given kilometers', () => {
		expect(mockDoSomething).toHaveBeenCalledWith(kilometers)
	})
})
```

## Quando mockar

Mocking dependerá principalmente do tipo de testes que o desenvolvedor está escrevendo.

* Testes unitários DEVEM ter toda função externa mockada, com exceção de funções que fazem coisas simples, como formatar strings, etc.
* Testes de API DEVEM ter mocks apenas para a comunicação com serviços externos, ou seja, DBs ou APIs diferentes. Se uma das operações feitas no teste afetar a performance 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 a exceção dos `redux-saga-test-plan` mocks.

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

* Quaisquer mocks do Jest DEVEM ser mockados usando seus **once** método quando possível, isto é, `mockReturnValueOnce` ou `mockResolvedValueOnce` é recomendado evitar `mockReturnValue` ou `mockResolvedValue`. A justificativa por trás disso é prevenir que mocks indesejados executem, alterando a execução dos nossos testes.
* O Jest oferece diversos Types que você pode usar para diferentes tipos de mocks. Por exemplo, ao mockar 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 rodar após cada teste com um `jest.resetAllMocks` para limpar qualquer implementação mockada de módulos mockados 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 `diretório de teste` ou `spec` . Mocks grandes DEVEM ser armazenados em arquivos diferentes dos testes para evitar arquivos de teste extensos. Mocks pequenos, se não forem muitos, DEVEM ser mantidos nos próprios testes.
  * Arquivos de mock DEVEM ser nomeados como a entidade que estão mockando, então por exemplo, se estivermos mockando um profile, o mock deve ser colocado em `/test/mocks/profile.ts` arquivo.
  * Caso vários mocks grandes sejam necessários, ELES DEVEM ser colocados em arquivos diferentes dentro de um diretório nomeado como a entidade a ser mockada, então por exemplo, se tivermos dois mocks de profile, iremos armazená-los como: `/test/mocks/profile/profile-with-wearables.ts` e `/test/mocks/profile/profile-without-wearables.ts`. Para facilitar o acesso a eles, VOCÊ DEVE criar um `index.ts` arquivo dentro do `/test/mocks/profile/` diretório e exportá-los.
  * A fim de evitar mutação de objetos mockados, mocks **DEVEM ser exportados como funções** que os retornem.


---

# 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 dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

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

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
