มาทำ Snapshot Testing ด้วย Cypress กัน

Traitanit Huangsri
Cypress.io Thailand
3 min readMay 8, 2021

สวัสดีครับ บทความนี้เป็นบทความสั้นๆ ขอแนะนำ Plugin ตัวหนึ่งบน Cypress ที่น่าสนใจและอยากแชร์ให้หลายๆ คนลองนำไปใช้กัน นั่นคือการทำ Snapshot Testing ด้วย Cypress นั่นเอง

Snapshot Testing คืออะไร?

Snapshot Testing เป็น Testing Technique หนึ่งที่เรามักจะใช้ในการเขียนเทสที่เราสามารถ expect output ที่ได้จากการรันเทสอย่างชัดเจนและไม่มีวันเปลี่ยนแปลง ยกตัวอย่างเช่น เรา render Web Component ขึ้นมาและต้องการดูว่า DOM elements ต่างๆ ที่อยู่ใน component นั้นถูก render ออกมาโดยไม่มีการเปลี่ยนแปลงในแบบที่เราคาดไม่ถึง และจะต้องเรียงลำดับ hierarchy ในแบบที่เรา snapshot เก็บไว้ก่อนหน้านี้เท่านั้น

ซึ่งถ้าใครที่เคยเขียนเทสโดยใช้ Test Runner ชื่อดังอย่าง “Jest” แล้วล่ะก็ น่าจะเคยใช้งาน feature กันมาบ้างใช่มั้ยครับ เพราะเป็น feature ที่ค่อนข้างได้รับความนิยมมากๆ เลยทีเดียว

โดยในวันนี้เราสามารถนำเทคนิคการทำ “Snapshot Testing” มาใช้ในการเขียนเทสด้วย Cypress ได้แล้วโดยสามารถนำไปใช้ได้ทั้งการทำ Component Testing, API Testing หรือ End-to-End Testing เรียกว่านำไปใช้ได้กับการเขียนเทสทุก level เลยก็ว่าได้

ทำ Snapshot Testing สำหรับ Web Testing บน Cypress

การทำ Snapshot Testing บน Cypress นั้นก็ง่ายๆ ครับ เพียงแค่เรา install plugin @cypress/snapshot เข้าไปเพียงเท่านี้ก็สามารถใช้งานได้แล้วครับ

  1. Install Cypress Snapshot Plugin
$ yarn add -D @cypress/snapshot

2. Register Cypress Snapshot Command เข้าไปใน Cypress Project

ให้เราทำการแก้ไขไฟล์ cypress/support/commands.js เพื่อทำการ register Cypress Command ตัวนี้เข้าไปครับ

3. เริ่มเขียนเทสและใช้ Snapshot Command

ในตัวอย่างนี้ผมได้สร้าง Web ที่เป็น HTML ธรรมดาง่ายๆ ขึ้นมาเพื่อลองให้ Cypress Snapshot DOM Object ใน HTML ของผมไว้ดูครับ

HTML นี้ render elements 2 อันคือ h2 และ p โดยผมใส่ custom data attribute “data-testid” ไว้ด้วย เพื่อให้ Cypress เข้าถึง elements ได้โดยง่าย เป็น practice ที่อยากแนะนำให้ทุกคนทำนะครับ

ผมเริ่มเขียนเทสง่ายๆ เพื่อ access ไปที่ tag h2 และ p และให้ Cypress ทำการ snapshot DOM elements สองอันนี้เก็บไว้ครับ

Test ของผมก็ simple มาก เพียงแค่ access ไปที่ element tag h2 และ tag p โดยใช้ cy.get() command และหลังจากนั้นก็เรียก .snapshot() เพื่อทำการ snapshot 2 elements นี้เก็บไว้เพื่อเป็น expected result ในการรันเทสครั้งถัดไปครับ

เมื่อรันเทสข้อนี้ก็จะเห็นผลเทสใน Cypress Test Runner ออกมาแบบนี้ครับ

ผมตั้งชื่อ snapshot ของ tag h2 ไว้ชื่อว่า “test-title” และตั้งชื่อ snapshot ของ tag p ไว้ว่า “test-body” ครับ เมื่อเรา snapshot เสร็จเรียบร้อยแล้ว Cypress จะสร้างไฟล์ snapshot.js ไว้ใน root directory ของ project เรา เมื่อเปิดขึ้นมาดูก็จะเห็นเป็นหน้าตาแบบนี้ครับ

จะเห็นว่า element ที่เรา snapshot ไว้ถูก save เก็บไว้ในรูปแบบของ JSON นั่นเอง

4. ลองแก้ไข HTML เพื่อให้ค่าไม่ตรงกับที่ snapshot เก็บไว้

โดยผมได้ทำการแก้ไข “test-title” จากเดิมที่โชว์คำว่า “Hello World” เป็นคำว่า “Snapshot Testing” แล้วลองรีรันเทสดูครับ

เมื่อรีรันเทสใหม่ก็จะเห็นว่า Test Failed เพราะ สิ่งที่เว็บ Render ออกมาไม่ตรงกับสิ่งที่เรา Snapshot เก็บไว้นั่นเอง จะเห็นว่าเราเขียน Snapshot Testing ได้ไม่ยากเลยจริงมั้ยครับ

API Snapshot Testing

เราสามารถ apply เทคนิคการทำ Snapshot Testing มาใช้กับการทำ API Testing ได้เช่นกัน ยกตัวอย่างเช่น ผมทำการ Call API ไปที่ https://jsonplaceholder.typicode.com/todos/1 เพื่อทำการ Get Todo ออกมาและให้ทำการ Snapshot เก็บ Response Body และ HTTP status ไว้ สามารถเขียนออกมาได้แบบนี้ครับ

โดยเราสามารถใช้ Command cy.request() เพื่อทำ API Call และเมื่อได้ response object กลับมาเราก็สามารถเลือกได้ว่าต้องการจะ snapshot data ส่วนใดใน response object เก็บไว้เป็น expected result ในการรันเทสครั้งถัดไปบ้าง (ในตัวอย่างนี้คือผมเลือก snapshot response body และ http status ไว้) และใช้ command cy.wrap() เพื่อ yield เอา object ใน response มา snapshot เก็บไว้ครับ

ดังนั้นเมื่อการรันเทสข้อนี้ในครั้งถัดไป Cypress ก็จะนำ data ที่ snapshot เก็บไว้มาเป็น expected result ให้เราอัตโนมัติครับ

เมื่อเปิดไฟล์ snapshot.js ก็จะเห็น data ที่เราได้จากการทำ api testing ถูก save เก็บไว้เป็นที่เรียบร้อยแล้ว

สรุป

เราสามารถนำเทคนิคการทำ Snapshot Testing ไปใช้กับการเทส Scenario ที่เราสามารถ expect result ออกมาได้อย่างชัดเจน และมันควรจะได้ output แบบเดิมทุกครั้ง โดยเราสามารถเลือกทำ snapshot ได้ทั้ง data ที่เป็น DOM element, object ต่างๆ ได้หมดเลย

การทำ Snapshot Testing อาจจะไม่เหมาะกับการเทสที่เราไม่สามารถ expect output ที่ได้จากการเทสที่ไม่แน่นอน ยกตัวอย่างเช่นสมมติหน้าเว็บเรามีการ render data ที่เปลี่ยนแปลงไปตลอดเวลา เทคนิคการเทสแบบนี้ก็อาจจะไม่ค่อยเหมาะสักเท่าไหร่ครับ

ตัวอย่างโค้ดทั้งหมดในบทความนี้สามารถดูได้เต็มๆ ที่ Link ด้านล่างนี้ รวมถึงถ้าใครอยากรู้เกี่ยวกับการใช้งาน Snapshot Testing Plugin เพิ่มเติมก็สามารถเข้าไปดูได้ที่ https://github.com/cypress-io/snapshot เลยนะครับ ขอให้ทุกท่านมีความสุขกับการเขียนเทส Happy Testing!

--

--