Snapshot
Lerne Snapshots mit einem Video von Vue SchoolSnapshot-Tests sind ein äußerst nützliches Werkzeug, um sicherzustellen, dass sich die Ausgabe deiner Funktionen nicht unerwartet ändert.
Bei der Verwendung von Snapshots erstellt Vitest einen Snapshot des gegebenen Wertes und vergleicht ihn dann mit einer Referenz-Snapshot-Datei, die neben dem Test gespeichert ist. Der Test schlägt fehl, wenn die Snapshots nicht übereinstimmen: Entweder ist die Änderung unerwartet, oder der Referenz-Snapshot muss auf die neue Version des Ergebnisses aktualisiert werden.
Snapshots verwenden
Um einen Snapshot eines Wertes zu erstellen, kannst du toMatchSnapshot()
aus der expect()
-API verwenden:
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchSnapshot();
});
Beim ersten Ausführen dieses Tests erstellt Vitest eine Snapshot-Datei mit folgendem Inhalt:
// Vitest Snapshot v1, https://www.getbook.com/de/book/vitest-0/guide/snapshot
exports['toUpperCase 1'] = '"FOOBAR"';
Das Snapshot-Artefakt sollte zusammen mit den Codeänderungen übertragen und im Rahmen der Codeüberprüfung geprüft werden. Bei nachfolgenden Testläufen vergleicht Vitest die gerenderte Ausgabe mit dem vorherigen Snapshot. Wenn sie übereinstimmen, besteht der Test. Wenn sie nicht übereinstimmen, hat der Testrunner möglicherweise einen Fehler in deinem Code gefunden, der behoben werden sollte, oder die Implementierung hat sich geändert und der Snapshot muss aktualisiert werden.
WARNING
Bei der Verwendung von Snapshots mit asynchronen, gleichzeitigen Tests muss expect
aus dem lokalen Testkontext verwendet werden, um sicherzustellen, dass der richtige Test erkannt wird.
Inline-Snapshots
Alternativ kannst du toMatchInlineSnapshot()
verwenden, um den Snapshot direkt in der Testdatei zu speichern.
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchInlineSnapshot();
});
Statt eine Snapshot-Datei zu erstellen, ändert Vitest die Testdatei direkt, um den Snapshot zu aktualisieren:
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchInlineSnapshot('"FOOBAR"');
});
So kannst du die erwartete Ausgabe direkt sehen, ohne zwischen verschiedenen Dateien hin- und herzuspringen.
WARNING
Bei der Verwendung von Snapshots mit asynchronen, gleichzeitigen Tests muss expect
aus dem lokalen Testkontext verwendet werden, um sicherzustellen, dass der richtige Test erkannt wird.
Snapshots aktualisieren
Wenn der empfangene Wert nicht mit dem Snapshot übereinstimmt, schlägt der Test fehl und zeigt dir den Unterschied zwischen den Werten. Wenn die Änderung des Snapshots erwartet wird, solltest du den Snapshot aktualisieren.
Im Watch-Modus kannst du die Taste u
im Terminal drücken, um den fehlgeschlagenen Snapshot direkt zu aktualisieren.
Alternativ kannst du das Flag --update
oder -u
in der CLI verwenden, um Vitest anzuweisen, Snapshots zu aktualisieren.
vitest -u
Datei-Snapshots
Beim Aufruf von toMatchSnapshot()
werden alle Snapshots in einer formatierten SNAP-Datei gespeichert. Dies bedeutet, dass bestimmte Zeichen (insbesondere das doppelte Anführungszeichen "
und Backtick ```) in der Snapshot-Zeichenkette maskiert werden müssen. Zudem kann möglicherweise die Syntaxhervorhebung für den Snapshot-Inhalt verloren gehen (wenn er in einer bestimmten Sprache vorliegt).
Um dies zu verbessern, führen wir toMatchFileSnapshot()
ein. Dies ermöglicht es dir, der Snapshot-Datei eine beliebige Dateiendung zuzuweisen und sie dadurch lesbarer zu machen.
import { expect, it } from 'vitest';
it('render basic', async () => {
const result = renderHTML(h('div', { class: 'foo' }));
await expect(result).toMatchFileSnapshot('./test/basic.output.html');
});
Der Test vergleicht das Ergebnis mit dem Inhalt von ./test/basic.output.html
. Die Datei kann mit dem Flag --update
zurückgeschrieben werden.
Bild-Snapshots
Es ist ebenfalls möglich, Bilder mit jest-image-snapshot
als Snapshot zu speichern.
npm i -D jest-image-snapshot
test('image snapshot', () => {
expect(readFileSync('./test/stubs/input-image.png')).toMatchImageSnapshot();
});
Weitere Informationen findest du im Beispiel examples/image-snapshot
.
Benutzerdefinierte Serialisierer
Du kannst eigene Logik hinzufügen, um zu ändern, wie deine Snapshots serialisiert werden. Wie Jest verfügt Vitest über Standard-Serialisierer für integrierte JavaScript-Typen, HTML-Elemente, ImmutableJS und für React-Elemente.
Beispiel eines Serialisierer-Moduls:
expect.addSnapshotSerializer({
serialize(val, config, indentation, depth, refs, printer) {
// `printer` ist eine Funktion, die einen Wert mit vorhandenen Plugins serialisiert.
return `Pretty foo: ${printer(val.foo)}`;
},
test(val) {
return val && Object.prototype.hasOwnProperty.call(val, 'foo');
},
});
Nach dem Hinzufügen eines Tests wie diesem:
test('foo snapshot test', () => {
const bar = {
foo: {
x: 1,
y: 2,
},
};
expect(bar).toMatchSnapshot();
});
Erhältst du folgenden Snapshot:
Pretty foo: Object {
"x": 1,
"y": 2,
}
Zum Serialisieren von Snapshots verwenden wir Jests pretty-format
. Weitere Informationen dazu findest du hier: pretty-format.
Unterschied zu Jest
Vitest bietet eine nahezu kompatible Snapshot-Funktion mit Jest mit einigen Ausnahmen:
1. Kommentar-Header in der Snapshot-Datei ist unterschiedlich {#_1-comment-header-in-the-snapshot-file-is-different}
- // Jest Snapshot v1, https://goo.gl/fbAQLP
+ // Vitest Snapshot v1, https://www.getbook.com/de/book/vitest-0/guide/snapshot
Dies hat keine Auswirkungen auf die Funktionalität, kann sich aber auf die Commit-Historie auswirken, wenn von Jest migriert wird.
2. printBasicPrototype
ist standardmäßig auf false
gesetzt {#_2-printbasicprototype-is-default-to-false}
Sowohl die Snapshots von Jest als auch die von Vitest werden von pretty-format
unterstützt. In Vitest setzen wir printBasicPrototype
standardmäßig auf false
, um eine sauberere Snapshot-Ausgabe zu erzielen, während es in Jest <29.0.0 standardmäßig true
ist.
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",
},
]
`);
});
Wir halten dies für einen vernünftigeren Standard für die Lesbarkeit und die gesamte Entwicklererfahrung. Wenn du das Verhalten von Jest bevorzugst, kannst du deine Konfiguration ändern:
// vitest.config.js
export default defineConfig({
test: {
snapshotFormat: {
printBasicPrototype: true,
},
},
});
3. Chevron >
wird als Trennzeichen anstelle von Doppelpunkt :
für benutzerdefinierte Nachrichten verwendet {#_3-chevron-is-used-as-a-separator-instead-of-colon-for-custom-messages}
Vitest verwendet zur besseren Lesbarkeit Chevron >
anstelle von Doppelpunkt :
als Trennzeichen, wenn beim Erstellen einer Snapshot-Datei eine benutzerdefinierte Meldung übergeben wird.
Für folgenden Beispiel-Testcode:
test('toThrowErrorMatchingSnapshot', () => {
expect(() => {
throw new Error('error');
}).toThrowErrorMatchingSnapshot('hint');
});
In Jest sieht der Snapshot wie folgt aus:
exports[`toThrowErrorMatchingSnapshot: hint 1`] = `"error"`;
In Vitest sieht der entsprechende Snapshot so aus:
exports[`toThrowErrorMatchingSnapshot > hint 1`] = `"error"`;