FAIL tests/calculadora.test.js
✓ Somar 2 + 2 deveria retornar 4 (9 ms)
✓ Somar 5 + 7 deveria retornar 12 (1 ms)
✓ Somar 5.5 + 7 deveria retornar 12.5
✕ Somar 5.13792468 + 7 deveria retornar 12.13792468 (4 ms)
● Somar 5.13792468 + 7 deveria retornar 12.13792468
expect(received).toBe(expected) // Object.is equality
Expected: 12.13792468
Received: 12.137924680000001
18 | test("Somar 5.13792468 + 7 deveria retornar 12.13792468", () => {
19 | const resultado = calculadora.somar(5.13792468, 7);
> 20 | expect(resultado).toBe(12.13792468);
| ^
21 | });
22 |
at Object.toBe (tests/calculadora.test.js:20:21)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 3 passed, 4 total
Snapshots: 0 total
Time: 1.231 s
Ran all test suites.
Watch Usage: Press w to show more.
Essa falha ocorreu devido à forma como números de ponto flutuante são representados na maioria das linguagens de programação (uma questão entre converter base binária a que os computadores usam para base decimal os números que nós digitamos), incluindo o JavaScript.
Assim sendo, quando você realiza operações com números decimais, pode ocorrer uma perda de precisão durante a conversão de bases, resultando em um número diferente do esperado. No nosso caso 12.137924680000001 ao invés de 12.13792468.
Para contornar esse problema, no ponto de verificação dos testes com jest, você pode escrever um teste substituindo o método toBe( ) do jest pelo toBeCloseTo do jest, que verifica uma igualdade até certo número de casas decimais. Fica assim:
expect(received).toBeCloseTo(expected, precision);
Na prática
const received = 5.13792468 + 7;
const expected = 12.13792468;
expect(received).toBeCloseTo(expected, 8); // 8 é a precisão, ou seja, a quantidade de casas decimais a considerar
Assim, por fim, mudamos nosso teste para considerar a comparação entre o número esperado e o computado. De forma que vamos comprar decimais somente até sua 8ª casa decimal.
Claro que eu não preciso nem dizer que você deveria pensar se sempre comparar decimais até a 8ª casa atende os requisitos do seu sistema… Bem, se atender a solução nos testes é essa.
Em teoria terminaríamos aqui, mas calma que mais uma coisa interssante sobre o .toBeCloseTo.
Olha o teste abaixo:
FAIL tests/calculadora.test.js
✕ Somar 5.13 + 7 deveria retornar 12.13 (12 ms)
● Somar 5.13 + 7 deveria retornar 12.13
expect(received).toBe(expected) // Object.is equality
Expected: 12.13
Received: 12.129999999999999
18 | test("Somar 5.13 + 7 deveria retornar 12.13", () => {
19 | const resultado = calculadora.somar(5.13, 7);
> 20 | expect(resultado).toBe(12.13);
| ^
21 | });
22 |
at Object.toBe (tests/calculadora.test.js:20:21)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 1.031 s
Ran all test suites.
Watch Usage: Press w to show more.
Agora nos deparamos com esperar 12.13 e obter 12.129999999999999.
Tudo indica que com precisão de 8, teríamos 12.13 x 12.12999999 o que resultaria em falha.
Porém o teste passa. Por que?