ภาพรวม 1,000 ฟุตของการทดสอบการเขียน Cypress #frontend@twiiosendgrid
เผยแพร่แล้ว: 2020-10-03ที่ Twilio SendGrid เราได้เขียนการ ทดสอบ Cypress end-to-end (E2E) หลายร้อยรายการ และยังคงเขียนต่อไปอีกเมื่อมีการเผยแพร่คุณลักษณะใหม่ผ่านเว็บแอปพลิเคชันและทีมต่างๆ การทดสอบเหล่านี้ครอบคลุมทั้งสแตก โดยเป็นการยืนยันว่ากรณีการใช้งานทั่วไปส่วนใหญ่ที่ลูกค้าจะประสบยังคงทำงานหลังจากพุชการเปลี่ยนแปลงโค้ดใหม่ในแอปพลิเคชันของเรา
หากคุณต้องการย้อนกลับไปและอ่านเพิ่มเติมเกี่ยวกับวิธีคิดเกี่ยวกับการทดสอบ E2E โดยทั่วไป โปรดอ่านโพสต์บนบล็อกนี้และกลับมาอ่านอีกครั้งเมื่อคุณพร้อม โพสต์บล็อกนี้ไม่ต้องการให้คุณเป็นผู้เชี่ยวชาญในการทดสอบ E2E แต่จะช่วยให้คุณมีกรอบความคิดที่ถูกต้อง เพราะคุณจะเห็นว่าทำไมเราจึงทำบางอย่างในการทดสอบของเรา หากคุณกำลังมองหาบทแนะนำทีละขั้นตอนเพิ่มเติมเพื่อแนะนำการทดสอบ Cypress เราขอแนะนำให้คุณดูเอกสาร Cypress ในบล็อกโพสต์นี้ เราคิดว่าคุณอาจเคยเห็นหรือเขียนการทดสอบ Cypress มาก่อนและอยากรู้ว่าคนอื่นเขียนการทดสอบ Cypress สำหรับแอปพลิเคชันของตนเองอย่างไร
หลังจากเขียนการทดสอบ Cypress มากมาย คุณจะเริ่มสังเกตเห็นตัวเองใช้ฟังก์ชัน การยืนยัน และรูปแบบที่คล้ายคลึงกันของ Cypress เพื่อบรรลุสิ่งที่คุณต้องการ เราจะแสดงส่วนและกลยุทธ์ที่พบบ่อยที่สุดที่เราเคยใช้หรือเคยทำมาก่อนกับ Cypress เพื่อเขียนการทดสอบกับสภาพแวดล้อมที่แยกจากกัน เช่น dev หรือ staging เราหวังว่าภาพรวม 1,000 ฟุตของวิธีที่เราเขียนการทดสอบ Cypress จะช่วยให้คุณมีแนวคิดในการเปรียบเทียบกับของคุณเอง และช่วยคุณปรับปรุงวิธีที่คุณเข้าใกล้การทดสอบ Cypress
โครงร่าง:
- บทสรุป Cypress API
- การโต้ตอบกับองค์ประกอบ
- ยืนยันในองค์ประกอบ
- การจัดการกับ API และบริการ
- การส่งคำขอ HTTP ด้วย cy.request(…)
- การสร้างปลั๊กอินที่ใช้ซ้ำได้ด้วย cy.task()
- จำลองคำขอเครือข่ายด้วย cy.server() และ cy.route()
- คำสั่งที่กำหนดเอง
- เกี่ยวกับวัตถุหน้า
- การเลือกที่จะไม่เรียกใช้โค้ดฝั่งไคลเอ็นต์ด้วย window.Cypress checks
- การจัดการกับ iframes
- การกำหนดมาตรฐานในสภาพแวดล้อมการทดสอบ
Cypress API Roundup
มาเริ่มกันที่ส่วนต่างๆ ที่เรามักใช้กับ Cypress API
การเลือกองค์ประกอบ
มีหลายวิธีในการเลือกองค์ประกอบ DOM แต่คุณสามารถบรรลุสิ่งที่คุณต้องทำส่วนใหญ่ผ่านคำสั่ง Cypress เหล่านี้ และคุณสามารถเชื่อมโยงการดำเนินการและการยืนยันเพิ่มเติมหลังจากนี้
- รับองค์ประกอบตามตัวเลือก CSS ด้วย
cy.get(“[data-hook='someSelector']”)หรือcy.find(“.selector”) - การเลือกองค์ประกอบตามข้อความบางอย่าง เช่น
cy.contains(“someText”)หรือรับองค์ประกอบที่มีตัวเลือกเฉพาะที่มีข้อความบางอย่าง เช่นcy.contains(“.selector”, “someText”) - ทำให้องค์ประกอบหลักมีลักษณะ "ภายใน" ดังนั้นการสืบค้นในอนาคตทั้งหมดของคุณจะถูกกำหนดขอบเขตเป็นลูกของผู้ปกครองเช่น
cy.get(“.selector”).within(() => { cy.get(“.child”) }). - ค้นหารายการองค์ประกอบและดูผ่าน "แต่ละองค์ประกอบ" เพื่อดำเนินการค้นหาและยืนยันเพิ่มเติมเช่น
cy.get(“tr”).each(($tableRow) => { cy.wrap($tableRow).find('td').eq(1).should(“contain”, “someText” }). - ในบางครั้ง องค์ประกอบอาจมองไม่เห็นบนหน้า ดังนั้น คุณจะต้องเลื่อนองค์ประกอบเพื่อดูก่อน เช่น
cy.get(“.buttonFarBelow”).scrollIntoView() - บางครั้ง คุณจะต้องใช้การหมดเวลานานกว่าค่าเริ่มต้นของคำสั่งหมดเวลา ดังนั้นคุณสามารถเลือกเพิ่ม
{ timeout: timeoutInMs }เช่นcy.get(“.someElement”, { timeout: 10000 })
การโต้ตอบกับองค์ประกอบ
นี่คือการโต้ตอบที่ใช้บ่อยที่สุดที่พบในการทดสอบ Cypress ของเรา ในบางครั้ง คุณจะต้องใส่คุณสมบัติ { force: true } ในการเรียกใช้ฟังก์ชันเหล่านั้นเพื่อเลี่ยงการตรวจสอบบางอย่างกับองค์ประกอบ สิ่งนี้มักเกิดขึ้นเมื่อองค์ประกอบถูกครอบคลุมในลักษณะใดลักษณะหนึ่งหรือมาจากไลบรารีภายนอกที่คุณไม่มีการควบคุมมากนักในแง่ของการแสดงองค์ประกอบ
- เราต้องคลิกหลายๆ อย่าง เช่น ปุ่มใน modals ตาราง และอื่นๆ ที่คล้ายกัน ดังนั้นเราจึงทำสิ่งต่างๆ เช่น
cy.get(“.button”).click() - แบบฟอร์มมีอยู่ทุกหนทุกแห่งในแอปพลิเคชันเว็บของเราเพื่อกรอกรายละเอียดผู้ใช้และฟิลด์ข้อมูลอื่นๆ เราพิมพ์อินพุตเหล่านั้นด้วย
cy.get(“input”).type(“somekeyboardtyping”)และเราอาจจำเป็นต้องล้างค่าเริ่มต้นของอินพุตด้วยการล้างข้อมูลก่อน เช่นcy.get(“input”).clear().type(“somenewinput”)นอกจากนี้ยังมีวิธีเจ๋งๆ ในการพิมพ์คีย์อื่นๆ เช่น{enter}สำหรับคีย์ Enter เมื่อคุณทำcy.get(“input”).type(“text{enter}”) - เราสามารถโต้ตอบกับตัวเลือกที่เลือกเช่น
cy.get(“select”).select(“value”)และช่องทำเครื่องหมายเช่นcy.get(“.checkbox”).check()
ยืนยันในองค์ประกอบ
นี่เป็นคำยืนยันทั่วไปที่คุณสามารถใช้ในการทดสอบ Cypress ของคุณเพื่อพิจารณาว่ามีสิ่งใดบ้างบนหน้าเว็บที่มีเนื้อหาที่ถูกต้อง
- หากต้องการตรวจสอบว่ามีสิ่งใดปรากฏขึ้นบนหน้าหรือไม่ คุณสามารถสลับระหว่าง
cy.get(“.selector”).should(“be.visible”)และcy.get(“.selector”).should(“not.be.visible”)เป็น.cy.get(“.selector”).should(“not.be.visible”). - ในการพิจารณาว่ามีองค์ประกอบ DOM อยู่ที่ใดที่หนึ่งในมาร์กอัป และหากคุณไม่สนใจว่าองค์ประกอบนั้นจะมองเห็นหรือไม่ คุณสามารถใช้
cy.get(“.element”).should(“exist”)หรือcy.get(“.element”).should(“not.exist”). - หากต้องการดูว่าองค์ประกอบมีหรือไม่มีข้อความหรือไม่ คุณสามารถเลือกระหว่าง
cy.get(“button”).should(“contain”, “someText”)และcy.get(“button”).should(“not.contain”, “someText”). - ในการตรวจสอบการป้อนข้อมูลหรือปุ่มถูกปิดใช้งานหรือเปิดใช้งาน คุณสามารถยืนยันดังนี้:
cy.get(“button”).should(“be.disabled”) - เพื่อยืนยันว่ามีการตรวจสอบบางสิ่งหรือไม่ คุณสามารถทดสอบ like,
cy.get(“.checkbox”).should(“be.checked”) - โดยปกติคุณสามารถพึ่งพาการตรวจสอบข้อความที่จับต้องได้และการมองเห็นได้ แต่บางครั้งคุณต้องพึ่งพาการตรวจสอบคลาส เช่น
cy.get(“element”).should(“have.class”, “class-name”)มีวิธีอื่นๆ ที่คล้ายกันในการทดสอบแอตทริบิวต์ด้วย.should(“have.attr”, “attribute”) - มักจะเป็นประโยชน์สำหรับคุณที่จะเชื่อมโยงการยืนยันเข้าด้วยกันเช่น
cy.get(“div”).should(“be.visible”).and(“contain”, “text”)
การจัดการกับ API และบริการ
เมื่อจัดการกับ API และบริการที่เกี่ยวข้องกับอีเมล คุณสามารถใช้ cy.request(...) เพื่อส่งคำขอ HTTP ไปยังปลายทางแบ็กเอนด์ของคุณด้วยส่วนหัวการตรวจสอบสิทธิ์ อีกทางเลือกหนึ่งคือคุณสามารถสร้าง cy.task(...) ที่สามารถเรียกจากไฟล์ spec ใดๆ เพื่อให้ครอบคลุมการทำงานอื่นๆ ที่สามารถจัดการได้ดีที่สุดในเซิร์ฟเวอร์ Node ร่วมกับไลบรารีอื่นๆ เช่น การเชื่อมต่อกับกล่องขาเข้าของอีเมล และการค้นหา จับคู่อีเมลหรือควบคุมการตอบสนองและการสำรวจการเรียก API บางอย่างได้มากขึ้นก่อนที่จะคืนค่าบางค่าสำหรับการทดสอบที่จะใช้
การส่งคำขอ HTTP ด้วย cy.request(…)
คุณสามารถใช้ cy.request() เพื่อส่งคำขอ HTTP ไปยัง API แบ็กเอนด์ของคุณเพื่อตั้งค่าหรือทำลายข้อมูลก่อนที่กรณีทดสอบของคุณจะทำงาน คุณมักจะส่งผ่าน URL ปลายทาง วิธี HTTP เช่น "GET" หรือ "POST" ส่วนหัว และบางครั้งเนื้อหาคำขอเพื่อส่งไปยัง API แบ็กเอนด์ จากนั้น คุณสามารถโยงสิ่งนี้กับ .then((response) => { }) เพื่อเข้าถึงการตอบสนองของเครือข่ายผ่านคุณสมบัติ เช่น "สถานะ" และ "เนื้อหา" ตัวอย่างของการ cy.request() แสดงไว้ที่นี่
ในบางครั้ง คุณอาจไม่สนใจว่า cy.request(...) จะล้มเหลวด้วยรหัสสถานะ 4xx หรือ 5xx หรือไม่ระหว่างการล้างข้อมูลก่อนทำการทดสอบ สถานการณ์หนึ่งที่คุณอาจเลือกที่จะเพิกเฉยต่อรหัสสถานะที่ล้มเหลวคือเมื่อการทดสอบของคุณส่งคำขอ GET เพื่อตรวจสอบว่ารายการนั้นยังคงมีอยู่และถูกลบไปแล้วหรือไม่ รายการอาจถูกล้างข้อมูลแล้ว และคำขอ GET จะล้มเหลวด้วยรหัสสถานะ 404 ไม่พบ ในกรณีนี้ คุณจะต้องตั้งค่าตัวเลือกอื่นของ failOnStatusCode: false เพื่อให้การทดสอบ Cypress ของคุณไม่ล้มเหลวก่อนที่จะรันขั้นตอนการทดสอบ
การสร้างปลั๊กอินที่ใช้ซ้ำได้ด้วย cy.task()
เมื่อเราต้องการมีความยืดหยุ่นมากขึ้นและควบคุมฟังก์ชันที่ใช้ซ้ำได้เพื่อพูดคุยกับบริการอื่น เช่น ผู้ให้บริการกล่องขาเข้าอีเมลผ่านเซิร์ฟเวอร์โหนด (เราจะกล่าวถึงตัวอย่างนี้ในโพสต์บล็อกในภายหลัง) เราต้องการให้ฟังก์ชันพิเศษของเราเองและ การตอบสนองที่กำหนดเองต่อการเรียก API เพื่อให้เราเชื่อมโยงและนำไปใช้ในการทดสอบ Cypress ของเรา หรือเราต้องการเรียกใช้โค้ดอื่นๆ ในเซิร์ฟเวอร์ Node—เรามักจะสร้างปลั๊กอิน cy.task() สำหรับมัน เราสร้างฟังก์ชันปลั๊กอินในไฟล์โมดูลและนำเข้าใน plugins/index.ts ซึ่งเรากำหนดปลั๊กอินงานด้วยอาร์กิวเมนต์ที่เราต้องใช้เพื่อเรียกใช้ฟังก์ชันดังที่แสดงด้านล่าง
ปลั๊กอินเหล่านี้สามารถเรียกใช้ด้วย cy.task(“pluginName”, { ...args }) ที่ใดก็ได้ในไฟล์ข้อมูลจำเพาะของคุณ และคุณสามารถคาดหวังให้ฟังก์ชันการทำงานเดียวกันนี้เกิดขึ้นได้ ในขณะที่ถ้าคุณใช้ cy.request() คุณจะนำกลับมาใช้ใหม่ได้น้อยลง เว้นแต่คุณจะรวมการเรียกเหล่านั้นไว้ในออบเจกต์ของเพจหรือไฟล์ตัวช่วยที่จะนำเข้าทุกที่
คำเตือนอีกประการหนึ่งคือ เนื่องจากโค้ดงานปลั๊กอินมีไว้เพื่อให้ทำงานในเซิร์ฟเวอร์ Node คุณจึงไม่สามารถเรียกใช้คำสั่ง Cypress ตามปกติภายในฟังก์ชันเหล่านั้นได้ เช่น Cypress.env(“apiHost”) หรือ cy.getCookie('auth_token') คุณส่งผ่านสิ่งต่าง ๆ เช่น สตริงโทเค็นการตรวจสอบสิทธิ์หรือโฮสต์ API แบ็กเอนด์ไปยังอ็อบเจ็กต์อาร์กิวเมนต์ของฟังก์ชันปลั๊กอินของคุณ นอกเหนือจากสิ่งที่จำเป็นสำหรับเนื้อหาคำขอ หากจำเป็นต้องพูดคุยกับแบ็กเอนด์ API ของคุณ
จำลองคำขอเครือข่ายด้วย cy.server() และ cy.route()
สำหรับการทดสอบ Cypress ที่ต้องการข้อมูลที่ทำซ้ำได้ยาก (เช่น การเปลี่ยนแปลงของสถานะ UI ที่สำคัญบนหน้าเว็บหรือการจัดการกับการเรียก API ที่ช้ากว่า) ฟีเจอร์หนึ่งของ Cypress ที่ควรพิจารณาคือการตัดทอนคำขอของเครือข่าย วิธีนี้ใช้งานได้ดีกับคำขอตาม XmlHttpRequest (XHR) หากคุณใช้ vanilla XMLHttpRequest, ไลบรารี axios หรือ jQuery AJAX จากนั้นคุณจะใช้ cy.server() และ cy.route() เพื่อฟังเส้นทางเพื่อเยาะเย้ยการตอบสนองสำหรับสถานะใด ๆ ที่คุณต้องการ นี่คือตัวอย่าง:
กรณีการใช้งานอื่นคือใช้ cy.server() , cy.route() และ cy.wait() ร่วมกันเพื่อรับฟังและรอให้เครือข่ายร้องขอให้เสร็จสิ้นก่อนที่จะดำเนินการในขั้นตอนต่อไป โดยปกติ หลังจากโหลดหน้าหรือดำเนินการบางอย่างบนหน้าแล้ว สัญญาณภาพที่เข้าใจง่ายจะส่งสัญญาณว่ามีบางอย่างสมบูรณ์หรือพร้อมให้เรายืนยันและดำเนินการ สำหรับกรณีที่คุณไม่มีสัญญาณที่มองเห็นได้ คุณสามารถรอให้การเรียก API เสร็จสิ้นได้อย่างชัดเจน
Gotcha ใหญ่อย่างหนึ่งคือ หากคุณกำลังใช้การดึงข้อมูลสำหรับคำขอเครือข่าย คุณจะไม่สามารถเยาะเย้ยคำขอของเครือข่ายหรือรอให้เสร็จสิ้นในลักษณะเดียวกัน คุณจะต้องใช้วิธีแก้ปัญหาโดยแทนที่ window.fetch ปกติด้วยโพลีฟิล XHR และทำการตั้งค่าและล้างข้อมูลก่อนที่การทดสอบของคุณจะทำงานตามที่บันทึกไว้ในปัญหาเหล่า นี้ นอกจากนี้ยังมีคุณสมบัติ experimentalFetchPolyfill ของ Cypress 4.9.0 ที่อาจใช้งานได้สำหรับคุณ แต่โดยรวมแล้ว เรายังคงมองหาวิธีการที่ดีกว่าในการจัดการกับเครือข่ายที่ติดขัดในการดึงข้อมูลและการใช้งาน XHR ในแอปพลิเคชันของเราโดยไม่เกิดข้อผิดพลาด ใน Cypress 5.1.0 มีฟังก์ชัน cy.route2() ใหม่ที่มีแนวโน้ม (โปรดดูเอกสาร Cypress ) สำหรับการเชื่อมต่อเครือข่ายทดลองของทั้ง XHR และคำขอดึงข้อมูล ดังนั้นเราจึงวางแผนที่จะอัปเกรดเวอร์ชัน Cypress ของเราและทดลองกับมันเพื่อดูว่า มันแก้ปัญหาของเรา
คำสั่งที่กำหนดเอง
เช่นเดียวกับไลบรารี เช่น WebdriverIO คุณสามารถสร้างคำสั่งแบบกำหนดเองส่วนกลางที่สามารถนำมาใช้ซ้ำและโยงกับไฟล์ข้อมูลจำเพาะของคุณ เช่น คำสั่งที่กำหนดเองเพื่อจัดการการเข้าสู่ระบบผ่าน API ก่อนที่กรณีทดสอบของคุณจะทำงาน เมื่อคุณพัฒนามันในไฟล์เช่น support/commands.ts คุณสามารถเข้าถึงฟังก์ชันต่างๆ เช่น cy.customCommand() หรือ cy.login() การเขียนคำสั่งที่กำหนดเองสำหรับการเข้าสู่ระบบจะมีลักษณะดังนี้

เกี่ยวกับวัตถุหน้า
ออบเจ็กต์เพจเป็นตัวห่อหุ้มรอบตัวเลือกและฟังก์ชันเพื่อช่วยให้คุณโต้ตอบกับเพจ คุณไม่จำเป็นต้องสร้างออบเจ็กต์หน้าเพื่อเขียนการทดสอบ แต่ควรพิจารณาวิธีสรุปการเปลี่ยนแปลงใน UI คุณต้องการทำให้ชีวิตของคุณง่ายขึ้นในแง่ของการจัดกลุ่มสิ่งต่าง ๆ เข้าด้วยกันเพื่อหลีกเลี่ยงการอัปเดตตัวเลือกและการโต้ตอบในไฟล์หลาย ๆ ไฟล์แทนที่จะอยู่ในที่เดียว
คุณสามารถกำหนดคลาส "เพจ" พื้นฐานด้วยฟังก์ชันทั่วไป เช่น open() สำหรับคลาสเพจที่สืบทอดมาเพื่อแชร์และขยายจาก คลาสเพจที่ได้รับมาจะกำหนดฟังก์ชัน getter ของตนเองสำหรับตัวเลือกและฟังก์ชันตัวช่วยอื่นๆ ในขณะที่นำฟังก์ชันของคลาสพื้นฐานกลับมาใช้ใหม่ผ่านการเรียก เช่น super.open() ดังที่แสดงไว้ที่นี่
การเลือกที่จะไม่เรียกใช้โค้ดฝั่งไคลเอ็นต์ด้วย window.Cypress checks
เมื่อเราทดสอบโฟลว์ด้วยไฟล์ที่ดาวน์โหลดอัตโนมัติ เช่น CSV การดาวน์โหลดมักจะทำลายการทดสอบ Cypress ของเราโดยการหยุดการทดสอบ เพื่อเป็นการประนีประนอม เราต้องการทดสอบเป็นหลักว่าผู้ใช้สามารถเข้าถึงสถานะความสำเร็จที่เหมาะสมสำหรับการดาวน์โหลดหรือไม่ และไม่สามารถดาวน์โหลดไฟล์ในการทดสอบของเราได้จริงโดยการเพิ่มหน้าต่าง การตรวจสอบ window.Cypress
ระหว่างการทดสอบ Cypress จะมีการเพิ่มคุณสมบัติ window.Cypress ลงในเบราว์เซอร์ ในโค้ดฝั่งไคลเอ็นต์ของคุณ คุณสามารถเลือกตรวจสอบว่าไม่มีคุณสมบัติ Cypress บนออบเจ็กต์หน้าต่างหรือไม่ จากนั้นทำการดาวน์โหลดตามปกติ แต่ถ้ามันถูกเรียกใช้ในการทดสอบ Cypress อย่าดาวน์โหลดไฟล์จริงๆ เรายังใช้ประโยชน์จากการตรวจสอบคุณสมบัติ window.Cypress สำหรับการทดสอบ A/B ของเราที่ทำงานในเว็บแอปของเรา เราไม่ต้องการเพิ่มความไม่สม่ำเสมอและพฤติกรรมที่ไม่ได้กำหนดขึ้นจากการทดสอบ A/B ที่อาจแสดงประสบการณ์ที่แตกต่างกันแก่ผู้ใช้ทดสอบของเรา ดังนั้นเราจึงตรวจสอบก่อนว่าพร็อพเพอร์ตี้ไม่มีอยู่ก่อนที่จะเรียกใช้ตรรกะการทดสอบตามที่ไฮไลต์ด้านล่าง
การจัดการกับ iframes
การจัดการกับ iframes อาจเป็นเรื่องยากสำหรับ Cypress เนื่องจากไม่มีการรองรับ iframe ในตัว มี [issue]( https://github.com/cypress-io/cypress/issues/136 ) ที่ทำงานอยู่ซึ่งเต็มไปด้วยวิธีแก้ปัญหาเพื่อจัดการ iframes เดียวและ iframes ที่ซ้อนกัน ซึ่งอาจใช้หรือไม่ก็ได้ขึ้นอยู่กับเวอร์ชันปัจจุบันของ Cypress หรือ iframe ที่คุณต้องการโต้ตอบด้วย สำหรับกรณีการใช้งานของเรา เราต้องการวิธีจัดการกับ iframe การเรียกเก็บเงินของ Zuora ในสภาพแวดล้อมการจัดเตรียมของเราเพื่อตรวจสอบขั้นตอนการอัพเกรด Email API และ Marketing Campaigns API การทดสอบของเราเกี่ยวข้องกับการกรอกข้อมูลการเรียกเก็บเงินตัวอย่างก่อนทำการอัปเกรดเป็นข้อเสนอใหม่ในแอปของเรา
เราได้สร้างคำสั่งแบบกำหนดเอง cy.iframe(iframeSelector) เพื่อสรุปการจัดการกับ iframes การส่งผ่านตัวเลือกไปยัง iframe จะเป็นการตรวจสอบเนื้อหาเนื้อหาของ iframe จนกว่าจะว่างเปล่า จากนั้นจึงส่งคืนเนื้อหาเนื้อหากลับเพื่อให้เชื่อมโยงกับคำสั่ง Cypress เพิ่มเติมดังที่แสดงด้านล่าง:
เมื่อทำงานกับ TypeScript คุณสามารถพิมพ์คำสั่ง iframe แบบกำหนดเองเช่นนี้ในไฟล์ index.d.ts ของคุณ:
เพื่อให้การทดสอบในส่วนการเรียกเก็บเงินของเราสำเร็จ เราใช้คำสั่ง iframe แบบกำหนดเองเพื่อรับเนื้อหาเนื้อหาของ Zuora iframe จากนั้นเลือกองค์ประกอบภายใน iframe และเปลี่ยนค่าโดยตรง ก่อนหน้านี้เรามีปัญหากับการใช้ cy.find(...).type(...) และทางเลือกอื่นๆ ที่ไม่ทำงาน แต่โชคดีที่เราพบวิธีแก้ปัญหาโดยการเปลี่ยนค่าของอินพุตและเลือกโดยตรงด้วยคำสั่งเรียกใช้ เช่น cy.get(selector).invoke('val', 'some value') คุณจะต้องใช้ ”chromeWebSecurity”: false ในไฟล์การกำหนดค่า cypress.json ของคุณด้วย เพื่อให้คุณสามารถข้ามข้อผิดพลาดข้ามต้นทางได้ ตัวอย่างข้อมูลการใช้งานพร้อมตัวเลือกฟิลเลอร์มีให้ด้านล่าง:
การกำหนดมาตรฐานในสภาพแวดล้อมการทดสอบ
หลังจากเขียนการทดสอบกับ Cypress โดยใช้การยืนยัน ฟังก์ชัน และวิธีการที่พบบ่อยที่สุดที่เน้นไว้ก่อนหน้านี้ เราสามารถเรียกใช้การทดสอบและให้ผ่านการทดสอบกับสภาพแวดล้อมเดียวกันได้ นี่เป็นขั้นตอนแรกที่ดี แต่เรามีหลายสภาพแวดล้อมในการปรับใช้โค้ดใหม่และเพื่อทดสอบการเปลี่ยนแปลงของเรา แต่ละสภาพแวดล้อมมีชุดฐานข้อมูล เซิร์ฟเวอร์ และผู้ใช้ของตัวเอง แต่การทดสอบ Cypress ของเราควรเขียนเพียงครั้งเดียวเพื่อทำงานกับขั้นตอนทั่วไปเดียวกัน
ในการเรียกใช้การทดสอบ Cypress กับสภาพแวดล้อมการทดสอบหลายแบบ เช่น dev, การทดสอบ และ staging ก่อนที่เราจะปรับใช้การเปลี่ยนแปลงในการผลิต เราจำเป็นต้องใช้ประโยชน์จากความสามารถของ Cypress ในการเพิ่มตัวแปรสภาพแวดล้อมและแก้ไขค่าการกำหนดค่าเพื่อรองรับกรณีการใช้งานเหล่านั้น
ในการรันการทดสอบของคุณกับสภาพแวดล้อมส่วนหน้าที่แตกต่างกัน :
คุณจะต้องเปลี่ยนค่า “baseUrl” ตามที่เข้าถึงผ่าน Cypress.config(“baseUrl”) เพื่อให้ตรงกับ URL เหล่า นั้น Cypress.config(“baseUrl”) https://staging.app.com หรือ https://testing.app.com สิ่งนี้จะเปลี่ยน URL พื้นฐานสำหรับการ cy.visit(...) ทั้งหมดของคุณเพื่อผนวกเส้นทางของพวกเขา มีหลายวิธีในการตั้งค่า เช่น การตั้งค่า CYPRESS_BASE_URL=<frontend_url> ก่อนรันคำสั่ง Cypress หรือการตั้งค่า --config baseUrl=<frontend_url>
ในการรันการทดสอบของคุณกับสภาพแวดล้อมแบ็กเอนด์ที่แตกต่างกัน :
คุณจำเป็นต้องทราบชื่อโฮสต์ API เช่น https://staging.api.com หรือ https://testing.api.com เพื่อตั้งค่าในตัวแปรสภาพแวดล้อม เช่น “apiHost” และเข้าถึงได้ผ่านการเรียกเช่น Cypress.env(“apiHost”) . สิ่งเหล่านี้จะใช้สำหรับการ cy.request(...) ของคุณเพื่อส่งคำขอ HTTP ไปยังพาธบางเส้นทาง เช่น “<apiHost>/some/endpoint” หรือส่งผ่านไปยังการเรียกฟังก์ชัน cy.task(...) เป็นอาร์กิวเมนต์อื่น คุณสมบัติที่จะรู้ว่าแบ็กเอนด์ใดที่จะตี การโทรที่รับรองความถูกต้องเหล่านี้จะต้องทราบโทเค็นการตรวจสอบความถูกต้องที่คุณน่าจะจัดเก็บไว้ใน localStorage หรือคุกกี้ผ่าน cy.getCookie(“auth_token”) ตรวจสอบให้แน่ใจว่าโทเค็นการตรวจสอบสิทธิ์นี้ถูกส่งผ่านไปโดยเป็นส่วนหนึ่งของส่วนหัว "การอนุญาต" หรือผ่านวิธีการอื่นในคำขอของคุณ มีหลายวิธีในการตั้งค่าตัวแปรสภาพแวดล้อมเหล่านี้ เช่น ในไฟล์ cypress.json โดยตรง หรือในตัวเลือกบรรทัดคำสั่ง --env ซึ่งคุณสามารถอ้างอิงได้ในเอกสารประกอบของ Cypress
ในการเข้าสู่การเข้าสู่ระบบของผู้ใช้ที่แตกต่างกันหรือใช้ข้อมูลเมตาที่แตกต่างกัน:
ตอนนี้คุณรู้วิธีจัดการ URL ส่วนหน้าและโฮสต์ API แบ็กเอนด์หลายรายการแล้ว คุณจะจัดการกับการเข้าสู่ระบบผู้ใช้ที่แตกต่างกันอย่างไร คุณใช้ข้อมูลเมตาที่แตกต่างกันไปตามสภาพแวดล้อม เช่น สิ่งที่เกี่ยวข้องกับโดเมน คีย์ API และทรัพยากรอื่นๆ ที่มีแนวโน้มว่าจะไม่ซ้ำใครในสภาพแวดล้อมการทดสอบอย่างไร
เริ่มต้นด้วยการสร้างตัวแปรสภาพแวดล้อมอื่นที่เรียกว่า "testEnv" ด้วยค่าที่เป็นไปได้ของ "testing" และ "staging" เพื่อให้คุณสามารถใช้สิ่งนี้เป็นวิธีการบอกว่าผู้ใช้และข้อมูลเมตาของสภาพแวดล้อมใดที่จะใช้ในการทดสอบ การใช้ตัวแปรสภาพแวดล้อม “testEnv” คุณสามารถเข้าถึงสิ่งนี้ได้สองวิธี
คุณสามารถสร้าง "staging.json", "testing.json" และไฟล์ JSON สภาพแวดล้อมอื่น ๆ แยกกันภายใต้โฟลเดอร์ fixtures และนำเข้ามาเพื่อให้คุณใช้งานได้ตามค่า "testEnv" เช่น cy.fixture(`${testEnv}.json`).then(...) . อย่างไรก็ตาม คุณไม่สามารถพิมพ์ไฟล์ JSON ได้ดี และมีพื้นที่มากขึ้นสำหรับข้อผิดพลาดในไวยากรณ์และในการเขียนคุณสมบัติทั้งหมดที่จำเป็นต่อการทดสอบ ไฟล์ JSON ยังอยู่ห่างจากโค้ดทดสอบ ดังนั้น คุณจะต้องจัดการไฟล์อย่างน้อย 2 ไฟล์เมื่อแก้ไขการทดสอบ ปัญหาการบำรุงรักษาที่คล้ายกันจะเกิดขึ้นหากข้อมูลการทดสอบสภาพแวดล้อมทั้งหมดถูกกำหนดไว้ในตัวแปรสภาพแวดล้อมโดยตรงใน cypress.json ของคุณ และจะมีจำนวนมากเกินไปที่จะจัดการในการทดสอบมากมายเหลือเฟือ
อีกทางเลือกหนึ่งคือสร้างอ็อบเจ็กต์ฟิกซ์เจอร์ทดสอบภายในไฟล์ข้อมูลจำเพาะพร้อมคุณสมบัติตามการทดสอบหรือการจัดเตรียมเพื่อโหลดผู้ใช้และข้อมูลเมตาของการทดสอบนั้นสำหรับสภาพแวดล้อมบางอย่าง เนื่องจากสิ่งเหล่านี้คืออ็อบเจ็กต์ คุณจึงสามารถกำหนดประเภท TypeScript ทั่วไปที่ดีกว่ารอบอ็อบเจ็กต์ฟิกซ์เจอร์ทดสอบสำหรับไฟล์ข้อมูลจำเพาะทั้งหมดของคุณเพื่อนำมาใช้ซ้ำและเพื่อกำหนดประเภทเมทาดาทา คุณจะต้องเรียก Cypress.env(“testEnv”) เพื่อดูว่าคุณกำลังใช้สภาพแวดล้อมการทดสอบใด และใช้ค่านั้นเพื่อแยกฟิกซ์เจอร์ทดสอบของสภาพแวดล้อมที่เกี่ยวข้องออกจากออบเจกต์ฟิกซ์เจอร์ทดสอบโดยรวม และใช้ค่าเหล่านั้นในการทดสอบของคุณ แนวคิดทั่วไปของอ็อบเจกต์การแข่งขันถูกสรุปไว้ในข้อมูลโค้ดด้านล่าง
การใช้ค่าคอนฟิก Cypress “baseUrl” ตัวแปรสภาพแวดล้อมแบ็กเอนด์ “apiHost” และตัวแปรสภาพแวดล้อม “testEnv” ร่วมกันช่วยให้เรามีการทดสอบ Cypress ที่ทำงานกับหลายสภาพแวดล้อมโดยไม่ต้องเพิ่มเงื่อนไขหลายข้อหรือแยกโฟลว์ลอจิกดังที่แสดงด้านล่าง
ลองย้อนกลับไปดูว่าคุณสามารถสร้างคำสั่ง Cypress ของคุณเองให้ทำงานผ่าน npm ได้อย่างไร แนวคิดที่คล้ายกันนี้สามารถนำไปใช้กับเส้นด้าย Makefile และสคริปต์อื่น ๆ ที่คุณอาจใช้สำหรับแอปพลิเคชันของคุณ คุณอาจต้องการกำหนดรูปแบบต่างๆ ของคำสั่ง "open" และ "run" เพื่อให้สอดคล้องกับ Cypress "open" up GUI และ "run" ในโหมด headless กับสภาพแวดล้อมส่วนหน้าและส่วนหลังต่างๆ ใน package.json ของคุณ คุณยังสามารถตั้งค่าไฟล์ JSON หลายไฟล์สำหรับการกำหนดค่าของแต่ละสภาพแวดล้อมได้ แต่เพื่อความง่าย คุณจะเห็นคำสั่งพร้อมตัวเลือกและค่าในบรรทัด
คุณจะสังเกตเห็นในสคริปต์ package.json ว่า “baseUrl” ส่วนหน้าของคุณมีตั้งแต่ “http://localhost:9001” เมื่อคุณเริ่มต้นแอปของคุณในเครื่องไปยัง URL ของแอปพลิเคชันที่ปรับใช้ เช่น “ https://staging.app คอม ”. คุณสามารถตั้งค่าตัวแปร "apiHost" และ "testEnv" ของแบ็กเอนด์เพื่อช่วยในการส่งคำขอไปยังจุดสิ้นสุดแบ็กเอนด์และโหลดออบเจ็กต์ฟิกซ์เจอร์ทดสอบเฉพาะ คุณยังสามารถสร้างคำสั่ง “cicd” พิเศษเมื่อคุณต้องการรันการทดสอบของคุณในคอนเทนเนอร์ Docker ด้วยคีย์การบันทึก
Takeaway เล็กน้อย
เมื่อพูดถึงการเลือกองค์ประกอบ การโต้ตอบกับองค์ประกอบ และการยืนยันเกี่ยวกับองค์ประกอบบนหน้า คุณสามารถเขียนการทดสอบ Cypress จำนวนมากด้วยรายการคำสั่ง Cypress เล็กน้อย เช่น cy.get() , cy.contains() .click() , .type() , .should .should('be.visible')
นอกจากนี้ยังมีวิธีการส่งคำขอ HTTP ไปยัง API แบ็กเอนด์โดยใช้ cy.request() เรียกใช้รหัสที่กำหนดเองในเซิร์ฟเวอร์โหนดด้วย cy.task() และยกเลิกคำขอเครือข่ายโดยใช้ cy.server() และ cy.route() . คุณยังสามารถสร้างคำสั่งที่กำหนดเองได้ เช่น cy.login() เพื่อช่วยให้คุณเข้าสู่ระบบผู้ใช้ผ่าน API สิ่งเหล่านี้ช่วยในการรีเซ็ตผู้ใช้ไปยังจุดเริ่มต้นที่เหมาะสมก่อนทำการทดสอบ รวมตัวเลือกและฟังก์ชันเหล่านี้ไว้ด้วยกันในไฟล์ และคุณได้สร้างออบเจ็กต์หน้าที่ใช้ซ้ำได้เพื่อใช้ในข้อกำหนดของคุณ
เพื่อช่วยคุณเขียนการทดสอบที่ผ่านมากกว่าหนึ่งสภาพแวดล้อม ให้ใช้ประโยชน์จากตัวแปรสภาพแวดล้อมและอ็อบเจ็กต์ที่มีข้อมูลเมตาเฉพาะของสภาพแวดล้อม
ซึ่งจะช่วยให้คุณเรียกใช้ชุดผู้ใช้ต่างๆ ด้วยแหล่งข้อมูลแยกกันในข้อกำหนด Cypress ของคุณ แยกคำสั่ง Cypress npm เช่น npm run cypress:open:staging ใน package.json ของคุณจะโหลดค่าตัวแปรสภาพแวดล้อมที่เหมาะสมและรันการทดสอบสำหรับสภาพแวดล้อมที่คุณเลือกใช้งาน
นี่เป็นการสรุปภาพรวมหนึ่งพันฟุตของเราในการเขียนการทดสอบ Cypress เราหวังว่าสิ่งนี้จะทำให้คุณมีตัวอย่างและรูปแบบที่นำไปใช้ได้จริงเพื่อนำไปใช้และปรับปรุงในการทดสอบ Cypress ของคุณเอง
สนใจเรียนรู้เพิ่มเติมเกี่ยวกับการทดสอบ Cypress หรือไม่? ตรวจสอบแหล่งข้อมูลต่อไปนี้:
- สิ่งที่ต้องพิจารณาเมื่อเขียนการทดสอบ E2E
- TypeScript ทุกสิ่งในการทดสอบ Cypress ของคุณ
- การจัดการกับกระแสอีเมลในการทดสอบ Cypress
- แนวคิดสำหรับการกำหนดค่า การจัดระเบียบ และการรวมการทดสอบ Cypress ของคุณ
- การรวมการทดสอบ Cypress กับ Docker, Buildkite และ CICD
