Snapshot
Aprenda sobre Snapshots em vídeo na Vue SchoolTestes de snapshot são uma ferramenta muito útil sempre que você precisa garantir que a saída de suas funções não mude inesperadamente.
Ao usar snapshots, o Vitest captura o valor fornecido e o compara com um arquivo de snapshot de referência armazenado junto com o teste. O teste falhará se os dois snapshots não corresponderem: isso pode indicar uma mudança inesperada no código, 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 toMatchSnapshot()
da API expect()
:
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchSnapshot();
});
Na primeira vez que este teste é executado, o Vitest cria um arquivo de snapshot com o seguinte conteúdo:
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports['toUpperCase 1'] = '"FOOBAR"';
O arquivo de snapshot deve ser versionado (commitado) junto com as alterações de código e revisado como parte do seu processo de revisão. Nas próximas execuções dos testes, o Vitest comparará a saída gerada com o snapshot anterior. Se houver correspondência, o teste passará. Caso contrário, o executor de testes indicará um bug no seu código que precisa ser corrigido, ou que a implementação mudou e o snapshot deve ser atualizado.
WARNING
Ao usar Snapshots com testes assíncronos concorrentes, o expect
do Contexto de Teste local deve ser utilizado para garantir que o teste correto seja detectado.
Snapshots Inline
De forma similar, você pode usar o toMatchInlineSnapshot()
para armazenar o snapshot diretamente no arquivo de teste.
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 modificará o arquivo de teste diretamente para atualizar o snapshot como uma string:
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchInlineSnapshot('"FOOBAR"');
});
Isso permite que você visualize a saída esperada diretamente, sem a necessidade de navegar por diferentes arquivos.
WARNING
Ao usar Snapshots com testes assíncronos concorrentes, o expect
do Contexto de Teste local deve ser utilizado para garantir que o teste correto seja detectado.
Atualizando Snapshots
Quando o valor recebido não corresponde ao snapshot, o teste falha e exibe a diferença entre eles. Se a alteração no snapshot for esperada, você pode querer atualizá-lo para o estado atual.
No modo de observação (watch
), você pode pressionar a tecla u
no terminal para atualizar o snapshot com falha diretamente.
Alternativamente, você pode usar a flag --update
ou -u
na CLI para que o Vitest atualize os snapshots.
vitest -u
Snapshots de Arquivo
Ao chamar toMatchSnapshot()
, todos os snapshots são armazenados em um arquivo de snapshot formatado. Isso implica que precisamos escapar alguns caracteres (especificamente as aspas duplas "
e o acento grave `
) na string do snapshot. Além disso, você pode perder o destaque de sintaxe para o conteúdo do snapshot (se ele for de alguma linguagem específica).
Por isso, introduzimos o toMatchFileSnapshot()
para comparar explicitamente com um arquivo. Isso permite atribuir qualquer tipo de extensão de arquivo ao snapshot, tornando-os mais legíveis.
import { expect, it } from 'vitest';
it('render basic', async () => {
const result = renderHTML(h('div', { class: 'foo' }));
await expect(result).toMatchFileSnapshot('./test/basic.output.html');
});
Ele será comparado com o conteúdo de ./test/basic.output.html
e pode ser atualizado com a flag --update
.
Snapshots de Imagem
Também é possível criar snapshots de imagens usando jest-image-snapshot
.
npm i -D jest-image-snapshot
test('image snapshot', () => {
expect(readFileSync('./test/stubs/input-image.png')).toMatchImageSnapshot();
});
Serializador Personalizado
Você pode inserir sua própria lógica para alterar como seus snapshots são serializados. Assim como o Jest, o Vitest possui serializadores padrão para tipos JavaScript nativos, elementos HTML, ImmutableJS e elementos React.
Você pode incluir 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 suportamos a 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 'vitest/config';
export default defineConfig({
test: {
snapshotSerializers: ['path/to/custom-serializer.ts'],
},
});
Depois de adicionar um teste como este:
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 o pretty-format
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 idêntico ao do 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://vitest.dev/guide/snapshot.html
Isso não afeta a funcionalidade, mas pode impactar o diff do seu commit ao migrar do Jest.
2. printBasicPrototype
é false
por padrão {#_2-printbasicprototype-is-default-to-false}
Os snapshots do Jest e do Vitest são baseados em pretty-format
. No Vitest, definimos printBasicPrototype
como false
por padrão para fornecer uma saída de snapshot mais limpa, enquanto no Jest <29.0.0 é true
por padrão.
import { expect, test } from 'vitest';
test('snapshot', () => {
const bar = [
{
foo: 'bar',
},
];
// no Jest
expect(bar).toMatchInlineSnapshot(`
Array [
Object {
"foo": "bar",
},
]
`);
// no Vitest
expect(bar).toMatchInlineSnapshot(`
[
{
"foo": "bar",
},
]
`);
});
Consideramos esta opção mais adequada para legibilidade e uma melhor experiência de desenvolvimento. Se você ainda preferir o comportamento do Jest, pode alterar sua configuração:
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
snapshotFormat: {
printBasicPrototype: true,
},
},
});
3. O caractere >
é 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 >
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 de Error
padrão é diferente para toThrowErrorMatchingSnapshot
e toThrowErrorMatchingInlineSnapshot
{#_4-default-error-snapshot-is-different-for-tothrowerrormatchingsnapshot-and-tothrowerrormatchinginlinesnapshot}
import { expect, test } from 'vitest'
test('snapshot', () => {
// no Jest e Vitest
expect(new Error('error')).toMatchInlineSnapshot(`[Error: error]`)
// O Jest cria snapshots de `Error.message` para instâncias de `Error`
// O Vitest imprime o mesmo valor que toMatchInlineSnapshot
expect(() => {
throw new Error('error')
}).toThrowErrorMatchingInlineSnapshot(`"error"`)
}).toThrowErrorMatchingInlineSnapshot(`[Error: error]`)
})