สภาพแวดล้อมการทดสอบ

ตามที่ได้แนะนำไปในหัวข้อการทดสอบคืออะไร การทดสอบใน JavaScript นั้นโดยพื้นฐานแล้ว เป็นโค้ดที่เราตรวจสอบแล้วว่าใช้งานได้จริง กล่าวคือ ไม่มีการใส่ Error อย่างไรก็ตาม วิธีหนึ่งที่ทำให้คำจำกัดความนี้เข้าใจง่ายคือไม่ได้พิจารณาว่าเราจะเรียกใช้โค้ดที่ใดหรือสภาพแวดล้อมการทดสอบ

สภาพแวดล้อมการทดสอบอาจมองกว้างๆ ได้ว่าเป็นองค์ประกอบ 2 อย่าง ได้แก่ สภาพแวดล้อมรันไทม์ที่คุณใช้ทำการทดสอบ (เช่น โหนดหรือเบราว์เซอร์) และ API ที่พร้อมใช้งาน

สภาพแวดล้อมรันไทม์

รันไทม์อย่างเช่น Node หรือเครื่องมือที่คล้ายกัน เช่น Deno หรือ Bun มีวัตถุประสงค์เพื่อสนับสนุนโค้ด JS ฝั่งเซิร์ฟเวอร์หรือสำหรับจุดประสงค์ทั่วไป สภาพแวดล้อมของพวกเขาจะไม่รวม API ที่คุณอาจคาดหวังในเบราว์เซอร์ เช่น การสร้างและการทำงานกับองค์ประกอบ DOM และ HTML ตลอดจนแนวคิดเกี่ยวกับคอมโพเนนต์ภาพหรือเป้าหมายการแสดงผล (กล่าวคือ ไม่ใช่เฉพาะองค์ประกอบ แต่แสดงผลองค์ประกอบเหล่านั้นด้วย CSS ไปยังวิวพอร์ต)

ดังนั้นรันไทม์สำหรับวัตถุประสงค์ทั่วไปเหล่านี้จะล้มเหลวหากคุณพยายามแสดงผลองค์ประกอบ React อื่นๆ เพื่อให้ทดสอบได้ เนื่องจากไม่มีออบเจ็กต์ document หรือ window ที่พร้อมใช้งาน

ในทางกลับกัน หากคุณทำการทดสอบภายในเบราว์เซอร์ API ในตัวที่คุณคาดหวังได้จากรันไทม์เหล่านี้อาจใช้งานไม่ได้หากไม่มีการเติม Polyfill หรือการดำเนินการเพิ่มเติม Gocha ทั่วไปคือการอ่านและการเขียนไฟล์ กล่าวคือเป็นไปไม่ได้ที่จะ import { fs } from 'node:'fs'; ภายในเบราว์เซอร์และอ่านไฟล์ด้วยวิธีนี้ซึ่งเป็นส่วนหนึ่งของการทดสอบ

ปัญหา API จาก "เว็บ" กับ "แบ็กเอนด์" นี้อยู่นอกเหนือขอบเขตของการทดสอบเท่านั้น เพราะการมี Codebase สำหรับทั้งเซิร์ฟเวอร์และส่วนของไคลเอ็นต์อาจจะแปลกๆ แต่กลับเชื่อมโยงกับแนวคิดการเขียนโค้ดที่ทดสอบได้ ซึ่งเราจะกลับไปทบทวนตลอดทั้งหลักสูตรนี้

ทดสอบอัลกอริทึมหรือตรรกะทางธุรกิจ

โค้ดบางรายการไม่จำเป็นต้องมีการนำเข้าโหนดหรือเบราว์เซอร์จึงจะทำงานได้ ดังนั้นจึงต้องทดสอบด้วย นี่คือสิ่งที่เราจะพูดถึงในภายหลังในหลักสูตรนี้ แต่การจัดโครงสร้างฐานของโค้ดให้ "ตรรกะทางธุรกิจ" แยกจากการแสดงผลหรือโค้ดเฉพาะสำหรับโหนดจะช่วยให้ทดสอบได้ง่ายขึ้น

ดูตัวอย่างง่ายๆ นี้ คุณอาจมีฟังก์ชันโหนดที่อ่านและเขียนไฟล์จากดิสก์ โดยทำการแก้ไขในกระบวนการนี้ การเปลี่ยนโครงสร้างภายในฟังก์ชันให้ยอมรับฟังก์ชันที่อ่านและเขียนจากดิสก์ช่วยให้คุณทดสอบได้ทุกที่

ในกรณีนี้ คุณจะใช้สภาพแวดล้อมใดก็ได้เพื่อทดสอบโค้ดนี้ทั้งในรันไทม์ฝั่งเซิร์ฟเวอร์หรือเบราว์เซอร์ ในการทดสอบ คุณสามารถจัดหาผู้ช่วยที่จัดเก็บไฟล์เสมือนไว้ในหน่วยความจำหรือแสดงผลข้อมูลตัวยึดตำแหน่ง คุณสามารถแนะนำตัวช่วยประเภทนี้ในการทดสอบได้ เพราะว่าไม่สำคัญที่จะต้องตรวจสอบ เช่น ว่า fs.writeFileSync ใช้ได้ผล มุ่งเน้นที่โค้ดและสิ่งที่ทำให้ ไม่ซ้ำกันหรือมีความเสี่ยง

จำลอง API ของเบราว์เซอร์

เฟรมเวิร์กการทดสอบหลายรายการ เช่น Vitest จะมีตัวเลือกให้คุณจำลองสภาพแวดล้อม API ของเบราว์เซอร์โดยไม่ต้องเรียกใช้เบราว์เซอร์ Vitest จะใช้ไลบรารีที่ชื่อว่า JSDOM เป็นการภายใน ตัวเลือกนี้เป็นตัวเลือกที่ดีสำหรับการทดสอบคอมโพเนนต์ง่ายๆ ที่ลดค่าใช้จ่ายในการใช้เบราว์เซอร์สูง

ฟีเจอร์ทั่วไปของไลบรารีการจำลองคือ แม้จะเลียนแบบเบราว์เซอร์ได้ เช่น DOM, องค์ประกอบ และคุกกี้ แต่จะไม่มีคอมโพเนนต์ภาพ ซึ่งหมายความว่าคอมโพเนนต์ทั้ง 2 ประเภทนี้จะมีวิธีการสำคัญในการทำงานร่วมกับองค์ประกอบ HTML และพื้นฐานอื่นๆ แต่คุณจะไม่สามารถแสดงผลเอาต์พุตเป็นรูปภาพหรือหน้าจอ หรือตรวจสอบตำแหน่งขององค์ประกอบเป็นพิกเซลในหน้าเว็บได้

และเช่นเดียวกัน ตัวเลือกนี้อาจเหมาะสมสำหรับการทดสอบคอมโพเนนต์ที่คอมโพเนนต์แสดงถึงองค์ประกอบ "รีแอ็กชัน" หรือ "คอมโพเนนต์เว็บ" เป็นต้น โดยปกติคอมโพเนนต์ประเภทนี้จะสร้างและโต้ตอบกับ DOM ด้วยวิธีที่ค่อนข้างเล็ก และเบราว์เซอร์จำลองที่มีฟังก์ชันการทำงานเพียงพอที่จะยืนยันว่าคอมโพเนนต์ทำงานได้ตามที่ต้องการ ส่วนที่จะเผยแพร่ในเร็วๆ นี้มีตัวอย่าง การทดสอบคอมโพเนนต์ React ด้วย Vitest และ JSDOM

การจำลองเบราว์เซอร์เป็นแนวทางปฏิบัติที่ได้รับมาอย่างยาวนาน โดย JSDOM เปิดตัวในปี 2014 แต่จะแตกต่างจากการใช้เบราว์เซอร์จริงเสมอ ความแตกต่างนี้เห็นได้ชัดเจน เช่น JSDOM ไม่มีเครื่องมือเลย์เอาต์ จึงไม่มีวิธีตรวจสอบขนาดขององค์ประกอบหรือทดสอบท่าทางสัมผัสที่ซับซ้อน เช่น การปัด ความแตกต่างอาจชัดเจนและไม่ทราบ ด้วยเหตุนี้ คุณจึงควรทำให้การทดสอบแบบ JSDOM มีความกระชับ เพื่อให้คุณสามารถ "Timebox" มีความเสี่ยงที่พฤติกรรมจะเบี่ยงเบนไปจากความเป็นจริง

ควบคุมเบราว์เซอร์จริง

ในการทดสอบโค้ดเนื่องจากผู้ใช้จะได้รับประสบการณ์ การใช้เบราว์เซอร์จริงคือตัวเลือกที่ดีที่สุด ในทางปฏิบัติ การทดสอบรันไทม์ที่สนับสนุนเบราว์เซอร์จะเริ่มต้นและควบคุมอินสแตนซ์ของเบราว์เซอร์จริง แม้ว่าการเรียกใช้ "start" ภายใน Node.js ก็ตาม

การควบคุมเบราว์เซอร์ให้เป็นส่วนหนึ่งของการทดสอบหมายความว่าเบราว์เซอร์จะเปิดขึ้น เช่นเดียวกับผู้ใช้ ทำให้การทดสอบควบคุมได้ด้วยการโหลด URL, HTML ที่กำหนดเองและ JS หรืออะไรก็ตามที่จำเป็นต่อการทำการทดสอบ จากนั้นคุณจะเขียนโค้ดเพื่อให้ทำหน้าที่เป็นผู้ใช้ เช่น โดยการควบคุมเมาส์หรือการพิมพ์อินพุตในช่องอินพุตได้

เครื่องมือที่ทันสมัย เช่น WebdriverIO หรือ Web Test Runner จะควบคุมเบราว์เซอร์หลักทั้งหมดหรือเรียกใช้หลายอินสแตนซ์พร้อมกันได้ เบราว์เซอร์เหล่านี้สามารถเรียกใช้ติดกับตัวดำเนินการทดสอบ (เช่น ในคอมพิวเตอร์ของคุณเองหรือเป็นส่วนหนึ่งของการดำเนินการ CI) หรือถูกเอาต์ซอร์สไปยังบริการเชิงพาณิชย์ภายนอกที่จะเรียกใช้ให้คุณ

ไลบรารีการทดสอบที่เป็นที่รู้จักมากขึ้น (รวมถึง Vitest และ Jest) มักมีโหมดเบราว์เซอร์ แต่เนื่องจากต้นทางของไลบรารีเหล่านี้มาจาก Node.js โหมดของเบราว์เซอร์จึงมัก "ถูกยึด" ไว้และขาดคุณลักษณะที่เป็นประโยชน์ ตัวอย่างเช่น Vitest ไม่อาจจำลองการนำเข้าโมดูลในเบราว์เซอร์ ซึ่งเป็นค่าดั้งเดิมที่มีประสิทธิภาพที่เราใช้ในตัวอย่างในหน้าถัดไป

ในทางปฏิบัติ

เมื่อการทดสอบของคุณมีความซับซ้อนมากขึ้น การใช้เบราว์เซอร์จริงก็มีความสำคัญมากขึ้นเรื่อยๆ

  • สำหรับการทดสอบที่ใช้ฟีเจอร์จาก DOM ไปหรือน้อยที่สุด แม้แต่ฟีเจอร์ที่มีใน Node.js และรันไทม์ที่คล้ายกัน เช่น fetch หรือ EventTarget สภาพแวดล้อมจะไม่มีผลใดๆ
  • สำหรับการทดสอบส่วนประกอบขนาดเล็ก อาจเหมาะสำหรับ JSDOM
  • การทดสอบขนาดใหญ่ เช่น การทดสอบแบบปลายทางถึงปลายทาง ซึ่งจำลองได้ที่ผู้ใช้เข้าสู่ระบบและดําเนินการหลัก ควรดำเนินการทั้งหมดในเบราว์เซอร์จริง

ส่วนนี้จะเน้นเกี่ยวกับทฤษฎีและนำเสนอมุมมองที่แตกต่างกันสำหรับทำการทดสอบ ในทางปฏิบัติ ฐานของโค้ดมักจะใช้วิธีการที่แตกต่างกันมากสำหรับการทดสอบประเภทต่างๆ ตามความต้องการของคุณและสิ่งที่เครื่องมือทดสอบมีให้

ทดสอบความเข้าใจ

jsdom *ไม่* สนับสนุนคุณลักษณะใดของเบราว์เซอร์ที่เลเยอร์การจำลอง

เครื่องมือเลย์เอาต์
เนื่องจาก JSDOM ไม่ใช่เครื่องมือแบบภาพ จึงไม่สามารถใช้ในการตรวจสอบตำแหน่งขององค์ประกอบในหน้าเว็บ แอตทริบิวต์ CSS ที่แก้ไขแล้ว หรือส่วนอื่นๆ ของเลย์เอาต์ของเว็บไซต์
WebSocket
JSDOM มี WebSocket polyfill ดังนั้นโค้ดที่ใช้จะใช้งานได้
requestAnimationFrame
ด้วยแฟล็ก "pretendToBeVisual" jsdom จะเรียกโค้ดเรียกกลับ "ภาพเคลื่อนไหว" ที่ 60fps แม้ว่าที่จริงแล้วจะไม่มีการวาดอะไรเลย