Saya menulis pembuat laporan khusus untuk Jest dan mempostingnya di
GitHub . Pembangun saya disebut Jest-snapshots-book, itu membuat buku HTML snapshots dari komponen aplikasi Bereaksi.

Artikel ini akan membahas apa Jest itu, pengujian snapshot, yang umumnya memerlukan pembuat laporan tambahan dan cara menulisnya. Pada dasarnya, semua ini berlaku untuk menguji komponen Bereaksi, tetapi secara teoritis itu dapat diterapkan ketika bekerja dengan data serialable apa pun.
Komponen Bereaksi Paginator
Sebagai contoh, dalam artikel kami akan menguji komponen paginator (
Paginator ). Ini adalah bagian dari proyek kami untuk membuat aplikasi tanpa server di AWS (
GitHub ). Tugas komponen tersebut adalah menampilkan tombol untuk menavigasi halaman-halaman tabel atau yang lainnya.
Ini adalah komponen fungsional sederhana tanpa komponen stateless (komponen stateless). Sebagai input, ia menerima dari jumlah total halaman, halaman saat ini, dan fungsi penangan dari mengklik halaman. Pada output, komponen menghasilkan paginator yang terbentuk. Untuk menampilkan tombol, komponen
Button anak lain digunakan. Jika ada banyak halaman, paginator tidak menampilkan semuanya, menggabungkannya dan menampilkannya dalam bentuk elipsis.

Kode Komponen Paginatorimport React from 'react'; import classes from './Paginator.css'; import Button from '../../UI/Button/Button'; const Paginator = (props) => { const { tp, cp, pageClickHandler } = props; let paginator = null; if (tp !== undefined && tp > 0) { let buttons = []; buttons.push( <Button key={`pback`} disabled={cp === 1} clicked={(cp === 1 ? null : event => pageClickHandler(event, 'back'))}> ← </Button> ); const isDots = (i, tp, cp) => i > 1 && i < tp && (i > cp + 1 || i < cp - 1) && (cp > 4 || i > 5) && (cp < tp - 3 || i < tp - 4); let flag; for (let i = 1; i <= tp; i++) { const dots = isDots(i, tp, cp) && (isDots(i - 1, tp, cp) || isDots(i + 1, tp, cp)); if (flag && dots) { flag = false; buttons.push( <Button key={`p${i}`} className={classes.Dots} disabled={true}> ... </Button> ); } else if (!dots) { flag = true; buttons.push( <Button key={`p${i}`} disabled={i === cp} clicked={(i === cp ? null : event => pageClickHandler(event, i))}> {i} </Button> ); } } buttons.push( <Button key={`pforward`} disabled={cp === tp} clicked={(cp === tp ? null : event => pageClickHandler(event, 'forward'))}> → </Button> ); paginator = <div className={classes.Paginator}> {buttons} </div> } return paginator; } export default Paginator;
Kode Komponen Tombol import React from 'react'; import classes from './Button.css'; const button = (props) => ( <button disabled={props.disabled} className={classes.Button + (props.className ? ' ' + props.className : '')} onClick={props.clicked}> {props.children} </button> ); export default button;
Jest
Jest adalah pustaka sumber terbuka yang terkenal untuk unit yang menguji kode JavaScript. Itu dibuat dan dikembangkan berkat Facebook. Ditulis dalam Node.js.
Secara umum, arti pengujian datang pada fakta bahwa Anda perlu menemukan parameter input untuk kode Anda dan segera menggambarkan output yang harus dihasilkan kode Anda. Saat melakukan tes, Jest mengeksekusi kode Anda dengan parameter input dan memeriksa hasilnya terhadap yang diharapkan. Jika cocok, tes akan lulus, dan jika tidak, itu tidak akan lulus.
Contoh kecil dari
jestjs.io .
Misalkan kita memiliki modul Node.js, yang merupakan fungsi yang menambahkan dua angka (file
sum.js ):
function sum(a, b) { return a + b; } module.exports = sum;
Jika modul kita disimpan dalam file, untuk mengujinya, kita perlu membuat file
sum.test.js untuk menulis kode seperti itu untuk pengujian:
const sum = require('./sum'); test('adds 1 + 2 to equal 3', () => { expect(sum(1, 2)).toBe(3); });
Dalam contoh ini, menggunakan fungsi
tes , kami membuat satu tes yang disebut
'tambah 1 + 2 sama dengan 3' . Parameter kedua untuk fungsi
tes , kami melewati fungsi yang benar-benar melakukan tes.
Tes terdiri dari fakta bahwa kita menjalankan fungsi
penjumlahan kita dengan parameter input
1 dan
2 , meneruskan hasilnya ke fungsi Jest
expect () . Kemudian, menggunakan fungsi Jest
toBe () , hasil yang dikirimkan dibandingkan dengan yang diharapkan (
3 ). Fungsi
toBe () termasuk dalam kategori fungsi pengujian Jest (matchers).
Untuk pengujian, cukup buka folder proyek dan panggil
lelucon di baris perintah. Jest akan menemukan file dengan ekstensi
.test.js dan menjalankan tes. Inilah hasil yang akan ia hasilkan:
PASS ./sum.test.js ✓ adds 1 + 2 to equal 3 (5ms)
Pengujian enzim dan snapshot komponen
Pengujian snapshot adalah fitur yang relatif baru di Jest. Intinya adalah bahwa dengan bantuan fungsi tes khusus, kami meminta Jest untuk menyimpan snapshot dari struktur data kami ke disk, dan selama pengujian berikutnya berjalan, bandingkan snapshot baru dengan yang sebelumnya disimpan.
Cuplikan dalam kasus ini tidak lebih dari representasi tekstual dari data. Misalnya, snapshot dari beberapa objek akan terlihat seperti ini (kunci array di sini adalah nama tes):
exports[`some test name`] = ` Object { "Hello": "world" } `;
Inilah yang tampak seperti fungsi uji Jest, yang melakukan perbandingan gambar (parameter opsional):
expect(value).toMatchSnapshot(propertyMatchers, snapshotName)
Nilainya bisa berupa struktur data serial apa pun. Untuk pertama kalinya, fungsi
toMatchSnapshot () hanya menulis snapshot ke disk, di waktu berikutnya, ia sudah akan melakukan perbandingan.
Paling sering, teknologi pengujian ini digunakan khusus untuk menguji komponen Bereaksi, dan bahkan lebih akurat, untuk menguji rendering komponen Bereaksi yang benar. Untuk melakukan ini, Anda harus melewati komponen sebagai
nilai setelah rendering.
Enzyme adalah perpustakaan yang sangat menyederhanakan pengujian aplikasi Bereaksi dengan menyediakan fungsi rendering komponen yang mudah. Enzim dikembangkan di Airbnb.
Enzim memungkinkan Anda untuk membuat komponen dalam kode. Ada beberapa fungsi nyaman untuk ini yang melakukan opsi render berbeda:
- render lengkap (seperti pada browser, render DOM lengkap);
- rendering yang disederhanakan (rendering dangkal);
- render statis
Kami tidak akan mempelajari opsi render, untuk pengujian snapshot, render statis sudah cukup, yang memungkinkan Anda untuk mendapatkan kode-HTML statis komponen dan komponen turunannya:
const wrapper = render(<Foo title="unique" />);
Jadi, kami merender komponen kami dan meneruskan hasilnya untuk
mengharapkan () , dan kemudian memanggil fungsi
.toMatchSnapshot () . Fungsi itu hanyalah singkatan dari fungsi
tes .
... const wrapper = render(<Paginator tp={tp} cp={cp} />); it(`Total = ${tp}, Current = ${cp}`, () => { expect(wrapper).toMatchSnapshot(); }); ...
Setiap kali tes
dijalankan, toMatchSnapshot () membandingkan dua foto:
diharapkan (yang sebelumnya ditulis ke disk) dan
saat ini (yang diperoleh selama tes saat ini).
Jika gambarnya identik, tes dianggap lulus. Jika ada perbedaan dalam gambar, tes dianggap tidak lulus, dan pengguna ditampilkan perbedaan antara dua gambar dalam bentuk diff (seperti dalam sistem kontrol versi).
Berikut adalah contoh output Jest ketika tes gagal. Di sini kita melihat bahwa kita memiliki tombol tambahan pada gambar saat ini.

Dalam situasi ini, pengguna harus memutuskan apa yang harus dilakukan. Jika perubahan pada snapshot direncanakan karena perubahan pada kode komponen, maka itu harus menimpa snapshot lama dengan yang baru. Dan jika perubahannya tidak terduga, maka Anda perlu mencari masalah dalam kode Anda.
Saya akan memberikan contoh lengkap untuk menguji paginator (file
Paginator.test.js ).
Untuk pengujian paginator yang lebih nyaman, saya membuat fungsi
snapshoot (tp, cp) yang akan mengambil dua parameter: jumlah total halaman dan halaman saat ini. Fungsi ini akan melakukan pengujian dengan parameter yang diberikan. Yang tersisa hanyalah memanggil fungsi
snapshoot () dengan berbagai parameter (bahkan dalam satu lingkaran) dan menguji, menguji ...
import React from 'react'; import { configure, render } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import Paginator from './Paginator'; configure({ adapter: new Adapter() }); describe('Paginator', () => { const snapshoot = (tp, cp) => { const wrapper = render(<Paginator tp={tp} cp={cp} />); it(`Total = ${tp}, Current = ${cp}`, () => { expect(wrapper).toMatchSnapshot(); }); } snapshoot(0, 0); snapshoot(1, -1); snapshoot(1, 1); snapshoot(2, 2); snapshoot(3, 1); for (let cp = 1; cp <= 10; cp++) { snapshoot(10, cp); } });
Mengapa Anda membutuhkan pembuat laporan tambahan
Ketika saya mulai bekerja dengan teknologi pengujian ini, perasaan pendekatan awal yang belum selesai tidak meninggalkan saya. Bagaimanapun, gambar hanya dapat dilihat sebagai teks.
Tetapi bagaimana jika beberapa komponen menghasilkan banyak kode HTML saat rendering? Berikut adalah komponen paginator 3 tombol. Cuplikan dari komponen seperti itu akan terlihat seperti ini:
exports[`Paginator Total = 1, Current = -1 1`] = ` <div class="Paginator" > <button class="Button" > ← </button> <button class="Button" > 1 </button> <button class="Button" > → </button> </div> `;
Pertama, Anda perlu memastikan bahwa versi asli dari komponen dibuat dengan benar. Sangat tidak nyaman untuk melakukan ini hanya dengan melihat kode HTML dalam bentuk teks. Tapi ini hanya tiga tombol. Dan jika Anda perlu menguji, misalnya, meja atau sesuatu yang lebih tebal? Selain itu, untuk pengujian penuh, Anda perlu melihat banyak gambar. Ini akan sangat merepotkan dan sulit.
Kemudian, jika tes gagal, Anda perlu memahami bagaimana penampilan komponen berbeda. Perbedaan kode HTML mereka, tentu saja, akan memungkinkan Anda untuk memahami apa yang telah berubah, tetapi sekali lagi, kesempatan untuk secara pribadi melihat perbedaannya tidak akan berlebihan.
Secara umum, saya berpikir bahwa itu akan diperlukan agar gambar dapat dilihat di browser dalam bentuk yang sama seperti yang terlihat di aplikasi. Termasuk dengan gaya yang diterapkan padanya. Jadi saya mendapat ide untuk meningkatkan proses pengujian snapshot dengan menulis pembuat laporan tambahan untuk Jest.
Ke depan, itulah yang saya dapat. Setiap kali saya menjalankan tes, pembangun saya memperbarui buku foto. Langsung di browser, Anda dapat melihat komponen-komponen seperti yang terlihat di aplikasi, serta langsung melihat kode sumber gambar dan diff (jika pengujian gagal).

Pembuat Laporan Jest
Pembuat Jest telah memberikan kesempatan untuk menulis pembuat laporan tambahan. Ini dilakukan sebagai berikut. Anda perlu menulis modul pada Node.JS yang harus memiliki satu atau lebih metode ini:
onRunStart ,
onTestStart ,
onTestResult ,
onRunComplete , yang terkait dengan berbagai peristiwa kemajuan pengujian.
Maka Anda perlu menghubungkan modul Anda di konfigurasi Jest. Ada arahan
wartawan khusus untuk ini. Jika Anda ingin menyertakan pembuat Anda sebagai tambahan, Anda perlu menambahkannya ke akhir array
reporter .
Setelah itu, Jest akan memanggil metode dari modul Anda pada tahap tertentu dari pelaksanaan tes, meneruskan hasil saat ini ke metode. Kode dalam metode ini, pada kenyataannya, harus membuat laporan tambahan yang Anda butuhkan. Jadi secara umum, pembuatan pembangun laporan tambahan terlihat seperti.
Cara kerja Jest-snapshots-book
Saya tidak secara khusus memasukkan kode modul ke dalam artikel, karena saya akan memperbaikinya lebih lanjut. Ini dapat ditemukan di GitHub saya, ini adalah file
src / index.js di halaman proyek.
Pembuat laporan saya dipanggil setelah menyelesaikan tes. Saya memasukkan kode ke metode
onRunComplete (konteks, hasil) . Ini berfungsi sebagai berikut.
Di properti
results.testResults , Jest meneruskan serangkaian hasil tes ke fungsi ini. Setiap hasil pengujian menyertakan jalur ke file pengujian dan berbagai pesan dengan hasilnya. Pembuat laporan saya mencari setiap file uji dengan file snapshot yang sesuai. Jika file snapshot terdeteksi, pembuat laporan membuat halaman HTML di buku snapshot dan menulisnya ke folder snapshots-buku di folder root proyek.
Untuk menghasilkan halaman HTML, pembuat laporan, menggunakan fungsi rekursif
grabCSS (moduleName, css = [], level = 0), mengumpulkan semua gaya, mulai dari komponen yang diuji dan lebih jauh ke bawah pohon semua komponen yang diimpornya. Dengan demikian, fungsi ini mengumpulkan semua gaya yang diperlukan agar komponen dapat ditampilkan dengan benar. Gaya yang dikoleksi ditambahkan ke halaman HTML buku foto.
Saya menggunakan modul CSS dalam proyek saya, jadi saya tidak yakin apakah ini akan berfungsi jika modul CSS tidak digunakan.
Jika tes ini lulus, pembangun memasukkan iFrame ke halaman HTML dengan gambar dalam dua opsi tampilan: kode sumber (gambar seperti itu) dan komponen setelah rendering. Opsi tampilan di iFrame diubah dengan mengklik mouse.
Jika tes tidak lulus, maka semuanya lebih rumit. Jest hanya menyediakan pesan yang ditampilkan di konsol dalam kasus ini (lihat tangkapan layar di atas).
Ini berisi diffs dan informasi tambahan tentang tes gagal. Bahkan, dalam hal ini, kita pada dasarnya berurusan dengan dua gambar: yang
diharapkan dan yang
sebenarnya . Jika kita memiliki yang diharapkan - itu disimpan pada disk di folder snapshot, maka snapshot Jest saat ini tidak memberikan.
Oleh karena itu, saya harus menulis kode yang menggunakan Jest diff yang diambil dari pesan ke snapshot yang diharapkan dan membuat snapshot aktual berdasarkan yang diharapkan. Setelah itu, pembangun menampilkan di sebelah iFrame snapshot iFrame yang diharapkan dari snapshot saat ini, yang dapat mengubah isinya antara tiga opsi: kode sumber, komponen setelah rendering, diff.
Ini adalah apa yang tampak seperti pembuat laporan jika Anda menetapkan opsi verbose = true untuk itu.

Tautan yang bermanfaat
PS
Pengujian snapshot tidak cukup untuk sepenuhnya menguji aplikasi Bereaksi. Ini hanya mencakup rendering komponen Anda. Penting juga untuk menguji fungsinya (reaksi terhadap tindakan pengguna, misalnya). Namun, pengujian snapshot adalah cara yang sangat mudah untuk memastikan komponen Anda di-render sebagaimana dimaksud. Dan jest-snapshots-book membuat prosesnya sedikit lebih mudah.