Snapshot
Aprenda sobre Snapshots com este vídeo da Vue SchoolTestes de Snapshot são uma ferramenta muito útil para garantir que a saída de suas funções não se altere inesperadamente.
Ao usar snapshots, o Vitest cria uma "foto" (snapshot) do valor fornecido e a compara com um arquivo de snapshot de referência, armazenado junto ao teste. O teste falhará se os dois snapshots não corresponderem: isso indica uma alteração inesperada ou que o snapshot de referência precisa ser atualizado para refletir a nova versão do resultado.
Usar Snapshots
Para criar um snapshot de um valor, você pode usar o método toMatchSnapshot()
da API expect()
:
function toUpperCase(str: string) {
return str;
}
// ---cut---
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchSnapshot();
});
Na primeira execução deste teste, o Vitest cria um arquivo de snapshot semelhante a este:
// Vitest Snapshot v1, https://www.getbook.com/pt-br/book/vitest-1/guide/snapshot
exports['toUpperCase 1'] = '"FOOBAR"';
O arquivo de snapshot deve ser versionado (comitado) junto com as alterações de código e revisado como parte do processo de revisão de código. Em execuções subsequentes, o Vitest compara a saída gerada com o snapshot existente. Se houver correspondência, o teste passará. Caso contrário, o executor de teste encontrou um bug no código que precisa ser corrigido, ou a implementação foi alterada e o snapshot precisa ser atualizado.
WARNING
Ao usar Snapshots com testes concorrentes assíncronos, o expect
do Contexto de Testes local deve ser usado para garantir que o teste correto seja detectado.
Snapshots Inline
Você também pode usar o método toMatchInlineSnapshot()
para armazenar o snapshot diretamente dentro do arquivo de teste.
function toUpperCase(str: string) {
return str;
}
// ---cut---
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchInlineSnapshot();
});
Em vez de criar um arquivo de snapshot separado, o Vitest modifica o arquivo de teste diretamente para atualizar o snapshot como uma string:
function toUpperCase(str: string) {
return str;
}
// ---cut---
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchInlineSnapshot('"FOOBAR"');
});
Isso permite que você veja a saída esperada de forma direta, sem precisar alternar entre diferentes arquivos.
WARNING
Ao usar Snapshots com testes concorrentes assíncronos, o expect
do Contexto de Testes local deve ser usado para garantir que o teste correto seja detectado.
Atualizando Snapshots
Quando o valor recebido não corresponde ao snapshot, o teste falha e mostra a diferença entre eles. Se a alteração no snapshot for intencional, você pode atualizá-lo para o estado atual.
No modo de observação (watch mode), pressione a tecla u
no terminal para atualizar o snapshot com falha.
Ou você pode usar a flag --update
ou -u
na CLI para instruir o Vitest a atualizar os snapshots.
vitest -u
Snapshots de Arquivo
Ao chamar toMatchSnapshot()
, todos os snapshots são armazenados em um arquivo de snapshot formatado. Isso significa que alguns caracteres precisam ser escapados (principalmente as aspas duplas "
e o acento grave ```) na string do snapshot. Além disso, o realce de sintaxe do conteúdo do snapshot pode ser perdido (se estiver em alguma linguagem).
Para contornar essa situação, introduzimos o método toMatchFileSnapshot()
para criar snapshots explicitamente em um arquivo separado. Isso permite atribuir qualquer extensão ao arquivo de snapshot, tornando-o mais legível e permitindo o uso de realce de sintaxe apropriado.
import { expect, it } from 'vitest';
it('render basic', async () => {
const result = renderHTML(h('div', { class: 'foo' }));
await expect(result).toMatchFileSnapshot('./test/basic.output.html');
});
Este teste irá comparar a saída com o conteúdo do arquivo ./test/basic.output.html
. O arquivo pode ser reescrito com a flag --update
.
Snapshots de Imagem
Também é possível criar snapshots de imagens usando a biblioteca jest-image-snapshot
.
npm i -D jest-image-snapshot
test('image snapshot', () => {
expect(readFileSync('./test/stubs/input-image.png')).toMatchImageSnapshot();
});
Você pode aprender mais no exemplo disponível em examples/image-snapshot
.
Serializador Customizado
Você pode adicionar sua própria lógica para alterar a forma como seus snapshots são serializados. Assim como o Jest, o Vitest oferece serializadores padrão para tipos JavaScript integrados, elementos HTML, ImmutableJS e elementos React.
Você pode adicionar explicitamente um serializador personalizado usando a API expect.addSnapshotSerializer
.
expect.addSnapshotSerializer({
serialize(val, config, indentation, depth, refs, printer) {
// `printer` é uma função que serializa um valor usando plugins existentes.
return `Pretty foo: ${printer(val.foo, config, indentation, depth, refs)}`;
},
test(val) {
return val && Object.prototype.hasOwnProperty.call(val, 'foo');
},
});
Também oferecemos suporte à opção snapshotSerializers
para adicionar serializadores personalizados implicitamente.
import { SnapshotSerializer } from 'vitest';
export default {
serialize(val, config, indentation, depth, refs, printer) {
// `printer` é uma função que serializa um valor usando plugins existentes.
return `Pretty foo: ${printer(val.foo, config, indentation, depth, refs)}`;
},
test(val) {
return val && Object.prototype.hasOwnProperty.call(val, 'foo');
},
} satisfies SnapshotSerializer;
import { defineConfig } from 'vite';
export default defineConfig({
test: {
snapshotSerializers: ['path/to/custom-serializer.ts'],
},
});
Depois de adicionar um teste semelhante:
test('foo snapshot test', () => {
const bar = {
foo: {
x: 1,
y: 2,
},
};
expect(bar).toMatchSnapshot();
});
Você obterá o seguinte snapshot:
Pretty foo: Object {
"x": 1,
"y": 2,
}
Estamos usando a biblioteca pretty-format
, que faz parte do Jest, para serializar snapshots. Você pode ler mais sobre isso aqui: pretty-format.
Diferença do Jest
O Vitest oferece um recurso de Snapshot quase totalmente compatível com o Jest, com algumas exceções:
1. O cabeçalho de comentário no arquivo de snapshot é diferente {#_1-comment-header-in-the-snapshot-file-is-different}
- // Jest Snapshot v1, https://goo.gl/fbAQLP
+ // Vitest Snapshot v1, https://www.getbook.com/pt-br/book/vitest-1/guide/snapshot
Isso não afeta a funcionalidade, mas pode afetar o seu diff de commit ao migrar do Jest.
2. printBasicPrototype
é definido como false
por padrão {#_2-printbasicprototype-is-default-to-false}
Tanto os snapshots do Jest quanto do Vitest são alimentados pela biblioteca pretty-format
. No Vitest, definimos printBasicPrototype
como false
por padrão para fornecer uma saída de snapshot mais limpa. No Jest, antes da versão 29.0.0, o valor padrão era true
.
import { expect, test } from 'vitest';
test('snapshot', () => {
const bar = [
{
foo: 'bar',
},
];
// in Jest
expect(bar).toMatchInlineSnapshot(`
Array [
Object {
"foo": "bar",
},
]
`);
// in Vitest
expect(bar).toMatchInlineSnapshot(`
[
{
"foo": "bar",
},
]
`);
});
Acreditamos que este é um padrão mais adequado para legibilidade e uma melhor experiência de desenvolvimento (DX) em geral. Se você ainda preferir o comportamento do Jest, pode alterar sua configuração:
// vitest.config.js
export default defineConfig({
test: {
snapshotFormat: {
printBasicPrototype: true,
},
},
});
3. O caractere chevron >
é usado como separador em vez de dois pontos :
para mensagens personalizadas {#_3-chevron-is-used-as-a-separator-instead-of-colon-for-custom-messages}
O Vitest usa o caractere chevron >
como separador em vez de dois pontos :
para melhorar a legibilidade, quando uma mensagem personalizada é passada durante a criação de um arquivo de snapshot.
Para o seguinte exemplo de código de teste:
test('toThrowErrorMatchingSnapshot', () => {
expect(() => {
throw new Error('error');
}).toThrowErrorMatchingSnapshot('hint');
});
No Jest, o snapshot será:
exports[`toThrowErrorMatchingSnapshot: hint 1`] = `"error"`;
No Vitest, o snapshot equivalente será:
exports[`toThrowErrorMatchingSnapshot > hint 1`] = `[Error: error]`;
4. O snapshot padrão de Error
é diferente para toThrowErrorMatchingSnapshot
e toThrowErrorMatchingInlineSnapshot
{#_4-default-error-snapshot-is-different-for-tothrowerrormatchingsnapshot-and-tothrowerrormatchinginlinesnapshot}
import { expect, test } from 'vitest';
// ---cut---
test('snapshot', () => {
//
// in Jest
//
expect(new Error('error')).toMatchInlineSnapshot(`[Error: error]`);
// O Jest tira um snapshot de `Error.message` para a instância `Error`
expect(() => {
throw new Error('error');
}).toThrowErrorMatchingInlineSnapshot(`"error"`);
//
// in Vitest
//
expect(new Error('error')).toMatchInlineSnapshot(`[Error: error]`);
expect(() => {
throw new Error('error');
}).toThrowErrorMatchingInlineSnapshot(`[Error: error]`);
});