Olá pessoal! O curso
Desenvolvedor JavaScript inicia nesta quinta-feira. Nesse sentido, decidimos compartilhar a tradução de outro material interessante. Boa leitura.
Jest sempre foi minha ferramenta indispensável de teste de unidade. É tão confiável que começo a pensar que sempre o subutilizei. Embora os testes funcionassem, com o tempo eu os refatorei aqui e ali, porque não sabia que Jest poderia fazer isso. Cada vez que esse código é novo, verifico a documentação do Jest.
Então, vou compartilhar alguns dos meus truques favoritos do Jest que alguns de vocês já devem saber, porque leem a documentação e não gostam de mim (vergonha), mas espero que isso ajude aqueles que passaram por ela rapidamente !
A propósito, eu uso o Jest v24.8.0 como material de referência, portanto, tenha cuidado, algumas coisas podem não funcionar na versão do Jest que você está usando no momento. Além disso, os exemplos não representam o código de teste real, isso é apenas uma demonstração.
# 1 .toBe vs .toEqual
A princípio, todas essas declarações pareciam normais para mim:
expect('foo').toEqual('foo') expect(1).toEqual(1) expect(['foo']).toEqual(['foo'])
Com base no uso de
chai para declarações de igualdade (to.equal), isso é natural. De fato, Jest não vai reclamar, e essas declarações passam como de costume.
No entanto, o Jest possui .toBe e .toEqual. O primeiro é usado para afirmar a igualdade usando
Object.is , e o segundo é fornecer uma comparação profunda de objetos e matrizes. .toEqual tem um fallback para usar
Object.is, se você não precisar de uma comparação profunda, como afirmar igualdade de valores primitivos, o que explica por que o exemplo anterior foi muito bem.
expect('foo').toBe('foo') expect(1).toBe(1) expect(['foo']).toEqual(['foo'])
Dessa forma, você pode pular todo o
if-else
em
.toEqual
usando
.toBe
se você já sabe quais valores está testando.
Um erro comum é que você usará
.toBe
para afirmar a igualdade de valores primitivos.
expect(['foo']).toBe(['foo'])
Se você observar o
código-fonte quando o .toBe travar, ele tentará determinar se você realmente cometeu esse erro
chamando a função que o .toEqual usa. Isso pode ser um gargalo ao otimizar seu teste.
Se você tiver certeza de que está usando valores primitivos, seu código pode ser reorganizado para propósitos de otimização:
expect(Object.is('foo', 'foo')).toBe(true)
Mais detalhes na
documentação .
# 2 Comparações mais adequadas
Tecnicamente, você pode usar
.toBe
para validar quaisquer valores. Com o Jest, você pode usar especificamente determinadas ferramentas de comparação para tornar seu teste mais legível (e em alguns casos mais curto).
Estes são apenas alguns dos que selecionei na longa lista de compiladores Jest na documentação. Você pode dar uma olhada no resto.
# 3 Teste de captura instantânea em elementos sem uma interface com o usuário
Você pode ter ouvido falar sobre o
teste de captura instantânea no Jest , onde ajuda a rastrear alterações nos elementos da interface do usuário. Mas o teste com snapshots não se limita a isso.
Considere este exemplo:
const allEmployees = getEmployees() const happyEmployees = giveIncrementByPosition(allEmployees) expect(happyEmployees[0].nextMonthPaycheck).toBe(1000) expect(happyEmployees[1].nextMonthPaycheck).toBe(5000) expect(happyEmployees[2].nextMonthPaycheck).toBe(4000)
Seria cansativo se você reivindicasse cada vez mais funcionários. Além disso, se houver necessidade de mais solicitações para cada funcionário, multiplique o número de novas solicitações pelo número de funcionários e você terá uma idéia.
Com o teste de instantâneo, tudo isso pode ser feito da seguinte maneira:
const allEmployees = getEmployees() const happyEmployees = giveIncrementByPosition(allEmployees) expect(happyEmployees).toMatchSnapshot()
Sempre que ocorrerem regressões, você saberá exatamente qual árvore no nó não corresponde à imagem.
Mas a comodidade tem um preço: esse método é mais suscetível a erros. Existe a possibilidade de você não saber que a foto está realmente incorreta e, no final, você a fotografará de qualquer maneira. Portanto, verifique seu snapshot como se fosse seu próprio código de aprovação (porque é).
Obviamente, o teste não se limita a instantâneos. Leia a
documentação completa.
# 4 descrever.cada e testar.cada
Você já escreveu um teste que é um pouco semelhante a isso?
describe('When I am a supervisor', () => { test('I should have a supervisor badge', () => { const employee = new Employee({ level: 'supervisor' }) expect(employee.badges).toContain('badge-supervisor') }) test('I should have a supervisor level', () => { const employee = new Employee({ level: 'supervisor' }) expect(employee.level).toBe('supervisor') }) }) describe('When I am a manager', () => { test('I should have a manager badge', () => { const employee = new Employee({ level: 'manager' }) expect(employee.badges).toContain('badge-manager') }) test('I should have a manager level', () => { const employee = new Employee({ level: 'manager' }) expect(employee.level).toBe('manager') }) })
Isso é monótono e rotineiro, certo? Imagine fazer isso com muitos casos.
Com
description.each
e
test.each
você pode compactar o código da seguinte maneira:
const levels = [['manager'], ['supervisor']] const privileges = [['badges', 'toContain', 'badge-'], ['level', 'toBe', '']] describe.each(levels)('When I am a %s', (level) => { test.each(privileges)(`I should have a ${level} %s`, (kind, assert, prefix) => { const employee = new Employee({ level }) expect(employee[kind])[assert](`${prefix}${level}`) }) })
No entanto, ainda tenho que usar isso em meu próprio teste, pois prefiro que meu teste seja detalhado, mas achei que seria um truque interessante.
Consulte a
documentação para obter mais detalhes sobre os argumentos (spoiler: a sintaxe da tabela é muito legal).
# 5 Imitação única de funções globais
Em algum momento, você terá que testar algo que depende das funções globais em um caso de teste específico. Por exemplo, uma função que recebe informações sobre a data atual usando o objeto javascript Date ou uma biblioteca que depende dele. A dificuldade é que, quando se trata da data atual, você nunca pode obter a declaração correta.
function foo () { return Date.now() } expect(foo()).toBe(Date.now())
No final, você teria que redefinir o objeto Date global para que ele seja consistente e gerenciável:
function foo () { return Date.now() } Date.now = () => 1234567890123 expect(foo()).toBe(1234567890123)
No entanto, isso é considerado uma prática ruim, pois a redefinição é mantida entre os testes. Você não notará isso se não houver outro teste baseado no Date.now, mas ele também vazará.
test('First test', () => { function foo () { return Date.now() Date.now = () => 1234567890123 expect(foo()).toBe(1234567890123)
Eu costumava "quebrar" para não vazar:
test('First test', () => { function foo () { return Date.now() const oriDateNow = Date.now Date.now = () => 1234567890123 expect(foo()).toBe(1234567890123)
No entanto, há uma maneira muito melhor e menos hacker de fazer isso:
test('First test', () => { function foo () { return Date.now() jest.spyOn(Date, 'now').mockImplementationOnce(() => 1234567890123) expect(foo()).toBe(1234567890123)
Assim, o
jest.spyOn
segue o objeto global Data, imitando a implementação da função now para apenas uma chamada. Isso, por sua vez, deixará o Date.now intacto para o restante dos testes.
Definitivamente, há mais informações sobre stubs no Jest. Consulte a
documentação completa para mais detalhes.
Este artigo está ficando longo o suficiente, então acho que é tudo por enquanto. Isso afeta apenas uma pequena parte dos recursos do Jest, e apenas destaquei meus favoritos. Se você tiver outros fatos interessantes, me avise.
Além disso, se você já usou o Jest com frequência, consulte o
Majestic , que é uma interface gráfica do usuário sem interface gráfica para o Jest, uma alternativa muito boa à saída chata do terminal. Não sei se o autor está em dev.to, mas mesmo assim respeita essa pessoa.
Como sempre, obrigado pela atenção!
Só isso. Vejo você no curso.