เส้นทางการทดสอบ E2E ตอนที่ 1: STUI ไปยัง WebdriverIO
เผยแพร่แล้ว: 2019-11-21หมายเหตุ: นี่เป็นโพสต์จาก #frontend@twiiosendgrid สำหรับบทความด้านวิศวกรรมอื่นๆ ตรงไปที่บล็อกทางเทคนิค
เนื่องจากสถาปัตยกรรมฟรอนต์เอนด์ของ SendGrid เริ่มเติบโตในแอปพลิเคชันเว็บของเรา เราจึงต้องการเพิ่มการทดสอบอีกระดับนอกเหนือจากหน่วยปกติและเลเยอร์การทดสอบการรวม เราพยายามสร้างเพจและคุณสมบัติใหม่ด้วยความครอบคลุมการทดสอบ E2E (end-to-end) ด้วยเครื่องมืออัตโนมัติของเบราว์เซอร์
เราต้องการทำให้การทดสอบเป็นไปโดยอัตโนมัติจากมุมมองของลูกค้า และเพื่อหลีกเลี่ยงการทดสอบการถดถอยแบบแมนนวลหากเป็นไปได้สำหรับการเปลี่ยนแปลงครั้งใหญ่ที่อาจเกิดขึ้นกับส่วนใดส่วนหนึ่งของสแตก เรามีและยังคงมี เป้าหมายต่อไปนี้: ให้วิธีการเขียนการทดสอบระบบอัตโนมัติ E2E ที่สอดคล้องกัน ดีบัก บำรุงรักษาได้ และมีคุณค่าสำหรับแอปพลิเคชันส่วนหน้าของเรา และผสานรวมกับ CICD (การผสานรวมอย่างต่อเนื่องและการปรับใช้อย่างต่อเนื่อง)
เราทดลองด้วยวิธีการทางเทคนิคหลายอย่าง จนกระทั่งได้ข้อสรุปเกี่ยวกับโซลูชันในอุดมคติของเราสำหรับการทดสอบ E2E ในระดับสูง นี่เป็นการสรุปการเดินทางของเรา:
- การสร้างโซลูชัน Ruby Selenium ภายในของเราเอง SiteTestUI aka STUI
- การเปลี่ยนจาก STUI เป็น WebdriverIO . ที่ใช้โหนด
- ไม่พอใจกับการตั้งค่าและในที่สุดก็ย้ายไปยัง Cypress
โพสต์ในบล็อกนี้เป็นหนึ่งในสองส่วนในการจัดทำเอกสารและเน้นย้ำถึงประสบการณ์ บทเรียนที่ได้เรียนรู้ และข้อขัดแย้งกับแต่ละแนวทางที่ใช้ไปพร้อมกันเพื่อหวังว่าจะแนะนำคุณและนักพัฒนาคนอื่นๆ เกี่ยวกับวิธีเชื่อมต่อการทดสอบ E2E ด้วยรูปแบบที่เป็นประโยชน์และกลยุทธ์การทดสอบ
ส่วนที่หนึ่งครอบคลุมการดิ้นรนในช่วงแรกของเรากับ STUI วิธีที่เราย้ายไปยัง WebdriverIO แต่ยังคงพบกับความหายนะที่คล้ายคลึงกันกับ STUI เราจะพูดถึงวิธีที่เราเขียนการทดสอบด้วย WebdriverIO เชื่อมต่อการทดสอบเพื่อรันในคอนเทนเนอร์ และในที่สุดก็รวมการทดสอบกับ Buildkite ผู้ให้บริการ CICD ของเรา
หากคุณต้องการข้ามไปยังจุดที่เราอยู่ด้วยการทดสอบ E2E ในวันนี้ โปรดไปยังส่วนที่สองในการย้ายครั้งสุดท้ายจาก STUI และ WebdriverIO ไปยัง Cypress และวิธีที่เราตั้งค่าในทีมต่างๆ
TLDR: เราประสบปัญหาคล้ายกันและต้องดิ้นรนกับทั้งโซลูชันห่อหุ้ม Selenium, STUI และ WebdriverIO ซึ่งในที่สุดเราก็เริ่มมองหาทางเลือกอื่นใน Cypress เราได้เรียนรู้บทเรียนเชิงลึกมากมายเพื่อจัดการกับการเขียนการทดสอบ E2E และการผสานรวมกับ Docker และ Buildkite
สารบัญ:
การโจมตีครั้งแรกในการทดสอบ E2E: siteTESUI aka STUI
การเปลี่ยนจาก STUI เป็น WebdriverIO
ขั้นตอนที่ 1: ตัดสินใจเลือกการอ้างอิงสำหรับ WebdriverIO
ขั้นตอนที่ 2: การกำหนดค่าสภาพแวดล้อมและสคริปต์
ขั้นตอนที่ 3: การนำการทดสอบ ENE ไปใช้ในเครื่อง
ขั้นตอนที่ 4: เทียบท่าการทดสอบทั้งหมด
ขั้นตอนที่ 5: การผสานรวมกับ CICD
ประนีประนอมกับ WebdriverIo
ย้ายไปที่ Cypress
การโจมตีครั้งแรกในการทดสอบ E2E: SiteTestUI aka STUI
เมื่อเริ่มค้นหาเครื่องมืออัตโนมัติของเบราว์เซอร์ SDET ของเรา (วิศวกรพัฒนาซอฟต์แวร์ในการทดสอบ) ได้พยายามสร้างโซลูชันภายในของเราเองที่สร้างขึ้นด้วย Ruby และ Selenium โดยเฉพาะ Rspec และเฟรมเวิร์ก Selenium แบบกำหนดเองที่เรียกว่า Gridium เราให้ความสำคัญกับการสนับสนุนข้ามเบราว์เซอร์ ความสามารถในการกำหนดค่าการผสานรวมแบบกำหนดเองของเรากับ TestRail สำหรับกรณีทดสอบของวิศวกร QA (Quality Assurance) และความคิดในการสร้าง repo ในอุดมคติสำหรับทีมส่วนหน้าทั้งหมดเพื่อเขียนการทดสอบ E2E ในที่เดียวและเพื่อเป็น ทำงานตามกำหนดเวลา
ในฐานะนักพัฒนาฟรอนท์เอนด์ที่กระตือรือร้นที่จะเขียนการทดสอบ E2E เป็นครั้งแรกด้วยเครื่องมือที่ SDET สร้างขึ้นสำหรับเรา เราจึงเริ่มใช้การทดสอบสำหรับหน้าเว็บที่เราได้เผยแพร่ไปแล้ว และได้ไตร่ตรองถึงวิธีการตั้งค่าผู้ใช้และเริ่มต้นข้อมูลอย่างเหมาะสมเพื่อมุ่งเน้นไปที่ส่วนต่างๆ ของ คุณลักษณะที่เราต้องการทดสอบ เราได้เรียนรู้สิ่งดีๆ ระหว่างทาง เช่น การสร้างออบเจ็กต์ของเพจเพื่อจัดระเบียบการทำงานของตัวช่วยและตัวเลือกขององค์ประกอบที่เราต้องการโต้ตอบด้วยหน้า และเริ่มสร้างข้อกำหนดที่เป็นไปตามโครงสร้างนี้:
เราค่อยๆ สร้างชุดทดสอบจำนวนมากในทีมต่างๆ ใน repo เดียวกันตามรูปแบบที่คล้ายคลึงกัน แต่ในไม่ช้าเราก็พบกับความผิดหวังมากมายที่จะทำให้ความคืบหน้าของเราช้าลงอย่างมากสำหรับนักพัฒนาใหม่และผู้สนับสนุน STUI อย่างสม่ำเสมอ เช่น:
- การเริ่มต้นและใช้งานต้องใช้เวลาและความพยายามอย่างมาก ในการติดตั้งไดรเวอร์เบราว์เซอร์ทั้งหมด การพึ่งพา Ruby Gem และเวอร์ชันที่ถูกต้องก่อนที่จะเรียกใช้ชุดทดสอบ บางครั้งเราต้องค้นหาว่าเหตุใดการทดสอบจึงทำงานบนเครื่องของตนกับเครื่องของบุคคลอื่น และการตั้งค่าต่างกันอย่างไร
- ห้องทดสอบขยายตัวและทำงานเป็นเวลาหลายชั่วโมงจนเสร็จ เนื่องจากทุกทีมมีส่วนร่วมใน repo เดียวกัน การทดสอบทั้งหมดแบบต่อเนื่องหมายถึงการรอหลายชั่วโมงเพื่อให้ชุดการทดสอบโดยรวมทำงาน และหลายทีมที่กดรหัสใหม่อาจนำไปสู่การทดสอบที่เสียหายอีกครั้งที่อื่น
- เราเริ่ม หงุดหงิดกับตัวเลือก CSS ที่ไม่สม่ำเสมอและตัวเลือก XPath ที่ซับซ้อน รูปภาพด้านล่างนี้อธิบายได้อย่างเพียงพอว่าการใช้ XPath สามารถทำให้สิ่งต่าง ๆ ซับซ้อนขึ้นได้อย่างไร และสิ่งเหล่านี้เป็นสิ่งที่ง่ายกว่า
- การทดสอบการดีบักนั้นเจ็บปวด เรามีปัญหาในการดีบักผลลัพธ์ของข้อผิดพลาดที่คลุมเครือ และโดยปกติเราไม่รู้ว่าสิ่งต่างๆ ล้มเหลวที่ไหนและอย่างไร เราทำการทดสอบซ้ำแล้วซ้ำอีกและสังเกตเบราว์เซอร์เพื่ออนุมานได้ว่าจุดใดที่อาจล้มเหลวและโค้ดใดที่รับผิดชอบ เมื่อการทดสอบล้มเหลวในสภาพแวดล้อม Docker ใน CICD โดยไม่ต้องดูอย่างอื่นนอกจากคอนโซลเอาต์พุต เราพยายามสร้างซ้ำในเครื่องและแก้ปัญหา
- เราพบ ข้อบกพร่องและความช้าของซีลีเนียม การทดสอบทำงานช้าเนื่องจากคำขอทั้งหมดที่ส่งจากเซิร์ฟเวอร์ไปยังเบราว์เซอร์ และบางครั้งการทดสอบของเราจะล้มเหลวพร้อมกันเมื่อพยายามเลือกองค์ประกอบจำนวนมากบนหน้าเว็บหรือด้วยเหตุผลที่ไม่ทราบสาเหตุระหว่างการทดสอบ
- ใช้เวลามากขึ้นในการแก้ไขและข้ามการทดสอบ และการรันการทดสอบตามกำหนดเวลาที่ใช้งานไม่ได้เริ่มถูกละเลย การทดสอบไม่ได้ให้คุณค่าในการแสดงข้อผิดพลาดที่แท้จริงในระบบ
- ทีมงานส่วนหน้าของเรารู้สึกว่าถูกตัดการเชื่อมต่อจากการทดสอบ E2E เนื่องจากมีอยู่ใน repo ที่แยกต่างหาก จากการทดสอบบนเว็บแอปพลิเคชันที่เกี่ยวข้อง เรามักจะต้องเปิด repos ทั้งสองไว้พร้อมกัน และยังคงมองย้อนกลับไปมาระหว่าง codebases นอกเหนือจากแท็บเบราว์เซอร์เมื่อการทดสอบทำงาน
- ทีมฟรอนท์เอนด์ไม่ชอบการสลับบริบทจากการเขียนโค้ดใน JavaScript หรือ TypeScript ในแต่ละวันเป็น Ruby และต้องเรียนรู้วิธีเขียนการทดสอบใหม่ทุกครั้งที่มีส่วนร่วมกับ STUI
- เนื่องจากเป็นขั้นตอนแรกสำหรับพวกเราหลายคนในการทดสอบ เราจึงตกอยู่ในรูปแบบ ต่างๆ เช่น การสร้างสถานะผ่าน UI สำหรับการเข้าสู่ระบบ การฉีกขาดหรือการตั้งค่าไม่เพียงพอผ่าน API และไม่มีเอกสารเพียงพอ เพื่อติดตามสิ่งที่ทำให้การทดสอบที่ยอดเยี่ยม
แม้ว่าเราจะคืบหน้าในการเขียนการทดสอบ E2E จำนวนมากสำหรับทีมต่างๆ มากมายใน repo เดียว และการเรียนรู้รูปแบบที่เป็นประโยชน์บางอย่างที่จะนำมาใช้กับเรา เราก็ประสบปัญหากับประสบการณ์โดยรวมของนักพัฒนา ความล้มเหลวหลายจุด และการขาดการทดสอบที่ทรงคุณค่าและมีเสถียรภาพ เพื่อตรวจสอบสแต็กทั้งหมดของเรา
เราให้ความสำคัญกับวิธีส่งเสริมนักพัฒนาส่วนหน้าคนอื่นๆ และ QA ในการสร้างชุดการทดสอบ E2E ที่เสถียรด้วย JavaScript ที่มีโค้ดแอปพลิเคชันของตนเองเพื่อส่งเสริมการใช้ซ้ำ ความใกล้ชิด และความเป็นเจ้าของการทดสอบ สิ่งนี้ทำให้เราตรวจสอบ WebdriverIO ซึ่งเป็นเฟรมเวิร์ก Selenium ที่ใช้ JavaScript สำหรับการทดสอบเบราว์เซอร์อัตโนมัติ เป็นการแทนที่ครั้งแรกของเราสำหรับ STUI ซึ่งเป็นโซลูชันภายในของ Ruby Selenium แบบกำหนดเอง
ต่อมาเราจะพบกับความล่มสลายและในที่สุดก็ย้ายไปที่ Cypress (กรอไปที่ส่วนที่ 2 ที่นี่หากสิ่งที่ WebdriverIO ไม่ดึงดูดใจคุณ) แต่เราได้รับประสบการณ์อันล้ำค่าในการสร้างโครงสร้างพื้นฐานที่ได้มาตรฐานใน repo ของแต่ละทีม ซึ่งรวมการทดสอบ E2E เข้ากับ CICD สำหรับส่วนหน้าของเรา และใช้รูปแบบทางเทคนิคที่ควรค่าแก่การจัดทำเป็นเอกสารในการเดินทางของเราและเพื่อให้ผู้อื่นได้เรียนรู้ว่าใครที่กำลังจะเข้าสู่ WebdriverIO หรือโซลูชันการทดสอบ E2E อื่นๆ
การเปลี่ยนจาก STUI เป็น WebdriverIO
เมื่อเริ่มต้นใช้งาน WebdriverIO เพื่อหวังว่าจะบรรเทาความผิดหวังที่เราพบ เราได้ทดลองโดยให้แต่ละทีมส่วนหน้าแปลงการทดสอบระบบอัตโนมัติที่มีอยู่ซึ่งเขียนด้วยแนวทาง Ruby Selenium เพื่อทดสอบ WebdriverIO ใน JavaScript หรือ TypeScript และเปรียบเทียบความเสถียร ความเร็ว ประสบการณ์ของนักพัฒนา และการบำรุงรักษาโดยรวมของ การทดสอบ
เพื่อให้บรรลุการตั้งค่าที่เหมาะสมที่สุดในการมีการทดสอบ E2E อยู่ใน repos แอปพลิเคชันของทีมฟรอนต์เอนด์และทำงานทั้งใน CICD และไปป์ไลน์ตามกำหนดการ เราได้สรุปขั้นตอนต่อไปนี้ซึ่งโดยทั่วไปแล้วจะนำไปใช้กับทีมใดๆ ที่ต้องการเข้าร่วมเฟรมเวิร์กการทดสอบ E2E โดยมีเป้าหมายที่คล้ายคลึงกัน :
- การติดตั้งและเลือกการพึ่งพาเพื่อเชื่อมต่อกับเฟรมเวิร์กการทดสอบ
- การสร้างการกำหนดค่าสภาพแวดล้อมและคำสั่งสคริปต์
- การนำการทดสอบ E2E ไปใช้ที่ผ่านในพื้นที่เทียบกับสภาพแวดล้อมที่แตกต่างกัน
- เทียบท่าการทดสอบ
- การรวมการทดสอบ Dockerized กับผู้ให้บริการ CICD
ขั้นตอนที่ 1: ตัดสินใจเลือกการอ้างอิงสำหรับ WebdriverIO
WebdriverIO ช่วยให้นักพัฒนามีความยืดหยุ่นในการเลือกเฟรมเวิร์ก ผู้รายงาน และบริการต่างๆ เพื่อเริ่มดำเนินการทดสอบ สิ่งนี้ต้องใช้การซ่อมแซมและการวิจัยจำนวนมากสำหรับทีมเพื่อจัดการกับห้องสมุดบางแห่งเพื่อเริ่มต้น
เนื่องจาก WebdriverIO ไม่ได้กำหนดไว้ว่าจะใช้งานอะไร มันจึงเปิดประตูให้ทีมส่วนหน้ามีไลบรารีและการกำหนดค่าที่แตกต่างกัน แม้ว่าการทดสอบหลักโดยรวมจะมีความสอดคล้องกันในการใช้ WebdriverIO API
เราเลือกที่จะให้แต่ละทีมส่วนหน้าปรับแต่งตามความต้องการของพวกเขา และโดยทั่วไปแล้วเราจะใช้ Mocha เป็นเฟรมเวิร์กการทดสอบ Mochawesome เป็นนักข่าว บริการ Selenium Standalone และการสนับสนุน Typescript เราเลือก Mocha และ Mochawesome เนื่องจากทีมของเราคุ้นเคยและมีประสบการณ์กับ Mocha มาก่อน แต่ทีมอื่นก็ตัดสินใจใช้ทางเลือกอื่นเช่นกัน
ขั้นตอนที่ 2: การกำหนดค่าสภาพแวดล้อมและสคริปต์
หลังจากตัดสินใจเลือกโครงสร้างพื้นฐาน WebdriverIO เราต้องการวิธีทดสอบ WebdriverIO ของเราเพื่อรันด้วยการตั้งค่าที่แตกต่างกันสำหรับแต่ละสภาพแวดล้อม ต่อไปนี้คือรายการที่แสดงกรณีการใช้งานส่วนใหญ่ว่าเราต้องการดำเนินการทดสอบเหล่านี้อย่างไร และเหตุใดเราจึงต้องการสนับสนุนการทดสอบเหล่านี้:
- เทียบกับ เซิร์ฟเวอร์ Webpack dev ที่ทำงานบน localhost (เช่น http://localhost:8000) และเซิร์ฟเวอร์ dev นั้นจะชี้ไปที่ API สภาพแวดล้อมบางอย่าง เช่น การทดสอบหรือ staging (เช่น https://testing.api.com หรือ https:// staging.api.com)
ทำไม? บางครั้ง เราจำเป็นต้องทำการเปลี่ยนแปลงในเว็บแอปในพื้นที่ของเรา เช่น การเพิ่มตัวเลือกเฉพาะสำหรับการทดสอบของเราเพื่อโต้ตอบกับองค์ประกอบต่างๆ ในลักษณะที่มีประสิทธิภาพมากขึ้น หรือเรากำลังดำเนินการพัฒนาคุณลักษณะใหม่และจำเป็นต้องปรับและตรวจสอบการทดสอบระบบอัตโนมัติที่มีอยู่ จะส่งผ่านภายในเครื่องเทียบกับการเปลี่ยนแปลงรหัสใหม่ของเรา เมื่อใดก็ตามที่รหัสของแอปพลิเคชันเปลี่ยนไปและเรายังไม่ได้ผลักดันสภาพแวดล้อมที่ปรับใช้ เราใช้คำสั่งนี้เพื่อเรียกใช้การทดสอบกับเว็บแอปในพื้นที่ของเรา - เทียบกับ แอปที่ปรับใช้สำหรับสภาพแวดล้อมบางอย่าง (เช่น https://testing.app.com หรือ https://staging.app.com) เช่น การทดสอบหรือการแสดงละคร
ทำไม? ในบางครั้ง โค้ดของแอปพลิเคชันไม่เปลี่ยนแปลง แต่เราอาจต้องแก้ไขโค้ดทดสอบเพื่อแก้ไขความไม่แน่นอน หรือเรารู้สึกมั่นใจมากพอที่จะเพิ่มหรือลบการทดสอบทั้งหมดโดยไม่ทำการเปลี่ยนแปลงส่วนหน้า เราใช้คำสั่งนี้อย่างหนักเพื่ออัปเดตหรือดีบักการทดสอบในเครื่องกับแอปที่ปรับใช้เพื่อจำลองวิธีที่การทดสอบของเราทำงานในไปป์ไลน์ CICD อย่างใกล้ชิดยิ่งขึ้น - ทำงานใน คอนเทนเนอร์ Docker กับแอปที่ปรับใช้สำหรับสภาพแวดล้อมบางอย่าง เช่น การทดสอบหรือการแสดงละคร
ทำไม? สิ่งนี้มีไว้สำหรับไปป์ไลน์ CICD เพื่อให้เราสามารถทริกเกอร์การทดสอบ E2E เพื่อรันในคอนเทนเนอร์ Docker เทียบกับแอปที่ปรับใช้การจัดเตรียม และตรวจสอบให้แน่ใจว่าผ่านก่อนที่จะปรับใช้โค้ดสำหรับการผลิต หรือในการทดสอบตามกำหนดการในไปป์ไลน์เฉพาะ เมื่อตั้งค่าคำสั่งเหล่านี้ในขั้นต้น เราได้ดำเนินการทดลองและข้อผิดพลาดจำนวนมากเพื่อหมุนคอนเทนเนอร์ Docker ด้วยค่าตัวแปรสภาพแวดล้อมที่แตกต่างกัน และทดสอบเพื่อดูการทดสอบที่เหมาะสมที่ดำเนินการได้สำเร็จก่อนที่จะเชื่อมต่อกับ Buildkite ผู้ให้บริการ CICD ของเรา
เพื่อให้บรรลุสิ่งนี้ เราตั้งค่าไฟล์กำหนดค่าพื้นฐานทั่วไปพร้อมคุณสมบัติที่ใช้ร่วมกันและไฟล์เฉพาะสภาพแวดล้อมจำนวนมาก โดยที่ไฟล์กำหนดค่าสภาพแวดล้อมแต่ละไฟล์จะรวมเข้ากับไฟล์ฐานและเขียนทับหรือเพิ่มคุณสมบัติตามต้องการ เราอาจมีไฟล์เดียวสำหรับแต่ละสภาพแวดล้อมโดยไม่จำเป็นต้องใช้ไฟล์พื้นฐาน แต่นั่นจะนำไปสู่การทำซ้ำจำนวนมากในการตั้งค่าทั่วไป เราเลือกที่จะใช้ไลบรารีอย่าง deepmerge
เพื่อจัดการกับมัน แต่สิ่งสำคัญคือต้องสังเกตว่าการรวมไม่ได้สมบูรณ์แบบเสมอไปกับอ็อบเจ็กต์หรืออาร์เรย์ที่ซ้อนกัน ตรวจสอบการกำหนดค่าเอาต์พุตที่เป็นผลลัพธ์อีกครั้งเสมอ เนื่องจากอาจนำไปสู่การทำงานที่ไม่ได้กำหนดเมื่อมีคุณสมบัติที่ซ้ำกันซึ่งไม่ได้ผสานอย่างถูกต้อง
เราสร้าง ไฟล์กำหนดค่าพื้นฐานทั่วไป , wdio.conf.js
เช่นนี้:
เพื่อให้พอดีกับกรณีการใช้งานหลักครั้งแรกของเราในการรันการทดสอบ E2E กับเซิร์ฟเวอร์ webpack dev ในเครื่องที่ชี้ไปที่ API สภาพแวดล้อม เราจึงสร้างไฟล์กำหนดค่า localhost คือ wdio.localhost.conf.js
โดยทำดังนี้:
สังเกตว่าเราได้รวมไฟล์ฐานและเพิ่มคุณสมบัติเฉพาะของ localhost ลงในไฟล์เพื่อให้กระชับและง่ายต่อการบำรุงรักษา เรายังใช้บริการ Selenium Standalone เพื่อเพิ่มความสามารถของเบราว์เซอร์ประเภทต่างๆ
สำหรับกรณีการใช้งานครั้งที่สองของการทดสอบ E2E กับเว็บแอปที่ปรับใช้ เราได้ตั้งค่าไฟล์ การทดสอบและจัดเตรียมแอป , `wdio.testing.conf.js` และ wdio.staging.conf.js
คล้ายกับสิ่งนี้:
ในที่นี้ เราได้เพิ่มตัวแปรสภาพแวดล้อมพิเศษบางตัวลงในไฟล์ปรับแต่ง เช่น ข้อมูลรับรองการเข้าสู่ระบบสำหรับผู้ใช้เฉพาะในการแสดงละคร และอัปเดต `baseUrl' ให้ชี้ไปที่ URL ของแอปการแสดงละครที่ปรับใช้
สำหรับกรณีการใช้งานครั้งที่สามของการรันการทดสอบ E2E ในคอนเทนเนอร์ Docker กับเว็บแอปที่ปรับใช้ภายในขอบเขตของผู้ให้บริการ CICD ของเรา เราได้ตั้งค่า ไฟล์กำหนดค่า CICD , wdio.cicd.testing.conf.js
และ wdio.cicd.staging.conf.js
เช่น:
สังเกตว่าเราไม่ใช้บริการ Selenium Standalone อีกต่อไป เนื่องจากเราจะติดตั้ง Selenium Chrome, Selenium Hub และรหัสแอปพลิเคชันในบริการแยกต่างหากในไฟล์ Docker Compose ในภายหลัง การกำหนดค่านี้ยังแสดงตัวแปรสภาพแวดล้อมเดียวกันกับการกำหนดค่าการจัดเตรียม เช่น ข้อมูลรับรองการเข้าสู่ระบบและ "baseUrl" เนื่องจากเราคาดว่าจะเรียกใช้การทดสอบของเรากับแอปจัดเตรียมที่ปรับใช้ และความแตกต่างเพียงอย่างเดียวคือการทดสอบเหล่านี้มีจุดมุ่งหมายเพื่อดำเนินการภายในคอนเทนเนอร์ Docker .
เมื่อสร้างไฟล์กำหนดค่าสภาพแวดล้อมเหล่านี้แล้ว เราได้สรุปคำสั่งสคริปต์ package.json
ที่จะใช้เป็นพื้นฐานสำหรับการทดสอบของเรา สำหรับตัวอย่างนี้ เรานำหน้าคำสั่งด้วย "uiest" เพื่อแสดงถึงการทดสอบ UI ด้วย WebdriverIO และเนื่องจากเราสิ้นสุดไฟล์ทดสอบด้วย *.uitest.js
ต่อไปนี้คือคำสั่งตัวอย่างบางส่วนสำหรับสภาวะแวดล้อมการจัดเตรียม:
ขั้นตอนที่ 3: การนำการทดสอบ E2E ไปใช้ในเครื่อง
ด้วยคำสั่งทดสอบทั้งหมดที่มีอยู่ เราได้กำหนดขอบเขตการทดสอบใน STUI repo เพื่อให้เราแปลงเป็นการทดสอบ WebdriverIO เรามุ่งเน้นไปที่การทดสอบหน้าขนาดเล็กถึงขนาดกลาง และเริ่มใช้รูปแบบวัตถุของหน้าเพื่อสรุป UI ทั้งหมดสำหรับแต่ละหน้าในลักษณะที่เป็นระเบียบ
เราอาจมีไฟล์ที่มีโครงสร้างซึ่งมีฟังก์ชันตัวช่วยจำนวนมาก หรือตัวระบุวัตถุหรือกลยุทธ์อื่นๆ แต่สิ่งสำคัญคือต้องมีวิธีที่สอดคล้องกันในการทดสอบที่บำรุงรักษาได้อย่างรวดเร็วและปฏิบัติตาม หากโฟลว์ UI หรือองค์ประกอบ DOM เปลี่ยนไปสำหรับหน้าใดหน้าหนึ่ง เราจำเป็นต้องปรับโครงสร้างออบเจกต์ของหน้าที่เกี่ยวข้องใหม่เท่านั้น และอาจเป็นไปได้ว่าโค้ดทดสอบผ่านการทดสอบอีกครั้ง
เรานำรูปแบบออบเจ็กต์ของเพจมาใช้โดยมีออบเจ็กต์เพจพื้นฐานที่มีฟังก์ชันการทำงานร่วมกันซึ่งออบเจกต์เพจอื่นๆ ทั้งหมดจะขยายออกไป เรามีฟังก์ชันต่างๆ เช่น เปิดเพื่อให้ API ที่สอดคล้องกันในออบเจ็กต์หน้าเว็บทั้งหมดของเราเพื่อ "เปิด" หรือไปที่ URL ของหน้าในเบราว์เซอร์ มันคล้ายกับสิ่งนี้:
การนำออบเจ็กต์ของเพจไปใช้นั้นเป็นไปตามรูปแบบเดียวกันของการขยายจากคลาส Page
พื้นฐาน และเพิ่มตัวเลือกให้กับองค์ประกอบบางอย่างที่เราต้องการโต้ตอบหรือยืนยัน และฟังก์ชันตัวช่วยเพื่อดำเนินการกับเพจ
สังเกตว่าเราใช้คลาสพื้นฐาน open ผ่าน super.open(...)
กับเส้นทางเฉพาะของเพจอย่างไร เพื่อให้เราสามารถเยี่ยมชมเพจด้วยการโทรนี้ SomePage.open()
นอกจากนี้เรายังส่งออกคลาสที่เริ่มต้นแล้วเพื่อให้เราสามารถอ้างอิงองค์ประกอบเช่น SomePage.submitButton
หรือ SomePage.tableRows
และโต้ตอบกับหรือยืนยันองค์ประกอบเหล่านั้นด้วยคำสั่ง WebdriverIO หากอ็อบเจกต์เพจมีขึ้นเพื่อแบ่งปันและเริ่มต้นด้วยคุณสมบัติของสมาชิกในคอนสตรัคเตอร์ เราก็สามารถเอ็กซ์พอร์ตคลาสได้โดยตรงและสร้างอินสแตนซ์ออบเจกต์เพจในไฟล์ทดสอบด้วย new SomePage(...constructorArgs)
หลังจากที่เราวางออบเจ็กต์ของหน้าด้วยตัวเลือกและฟังก์ชันของตัวช่วย เราก็เขียนการทดสอบ E2E และจำลองสูตรการทดสอบนี้โดยทั่วไป:
- ตั้งค่าหรือทำลายผ่าน API สิ่งที่จำเป็นในการรีเซ็ตเงื่อนไขการทดสอบเป็นจุดเริ่มต้นที่คาดไว้ก่อนที่จะเรียกใช้การทดสอบจริง
- เข้าสู่ระบบเป็นผู้ใช้เฉพาะ สำหรับการทดสอบ ดังนั้นเมื่อใดก็ตามที่เราเยี่ยมชมหน้าเว็บโดยตรง เราจะอยู่ในระบบต่อไปและไม่ต้องผ่าน UI เราได้สร้างฟังก์ชันตัวช่วยการ
login
อย่างง่ายที่ใช้ชื่อผู้ใช้และรหัสผ่านที่ทำให้การเรียก API แบบเดียวกับที่เราใช้สำหรับหน้าเข้าสู่ระบบของเรา และในที่สุดก็ส่งคืนโทเค็นการตรวจสอบสิทธิ์ของเราที่จำเป็นต่อการอยู่ในระบบต่อไปและส่งต่อส่วนหัวของคำขอ API ที่ได้รับการป้องกัน บริษัทอื่นๆ อาจมีปลายทางหรือเครื่องมือภายในที่กำหนดเองมากกว่านี้เพื่อสร้างผู้ใช้ใหม่ด้วยข้อมูลเริ่มต้นและการกำหนดค่าอย่างรวดเร็ว แต่โชคไม่ดีที่เราไม่มีข้อมูลเพียงพอ เราจะใช้วิธีที่ล้าสมัยและสร้างผู้ใช้ทดสอบโดยเฉพาะในสภาพแวดล้อมของเราด้วยการกำหนดค่าที่แตกต่างกันผ่าน UI และมักจะทำลายการทดสอบสำหรับหน้าที่มีผู้ใช้ที่แตกต่างกันเพื่อหลีกเลี่ยงการปะทะกันของทรัพยากรและยังคงแยกตัวออกเมื่อการทดสอบทำงานพร้อมกัน เราต้องตรวจสอบให้แน่ใจว่าผู้ใช้การทดสอบโดยเฉพาะไม่ถูกแตะต้องโดยผู้อื่น มิฉะนั้นการทดสอบจะพังเมื่อมีคนซ่อมแซมโดยไม่รู้ตัว - ทำให้ขั้นตอนเป็นอัตโนมัติราวกับว่าผู้ใช้ปลายทางจะโต้ตอบกับคุณลักษณะ/หน้า โดยปกติ เราจะไปที่หน้าซึ่งมีโฟลว์ฟีเจอร์ของเราและเริ่มทำตามขั้นตอนระดับสูงที่ผู้ใช้ปลายทางต้องการ เช่น การกรอกอินพุต การคลิกปุ่ม รอให้โมดอลหรือแบนเนอร์ปรากฏขึ้น และการสังเกตตารางสำหรับผลลัพธ์ที่เปลี่ยนแปลง ผลของการกระทำ ด้วยการใช้ออบเจ็กต์และตัวเลือกของเพจที่มีประโยชน์ เราดำเนินการแต่ละขั้นตอนอย่างรวดเร็ว และในขณะที่ตรวจสอบสุขภาพจิตตลอดทาง เราจะยืนยันเกี่ยวกับสิ่งที่ผู้ใช้ควรหรือไม่ควรเห็นบนเพจระหว่างการไหลของฟีเจอร์เพื่อให้บางสิ่งทำงานตามที่คาดไว้ ก่อนและหลังแต่ละขั้นตอน เรายังได้พิจารณาอย่างรอบคอบเกี่ยวกับการเลือกการทดสอบ Happy Path ที่มีมูลค่าสูงและบางครั้งก็มีสถานะข้อผิดพลาดทั่วไปที่ทำซ้ำได้ง่าย โดยเลื่อนการทดสอบระดับล่างที่เหลือไปเป็นการทดสอบหน่วยและการทดสอบการรวม
ต่อไปนี้คือตัวอย่างคร่าวๆ ของเลย์เอาต์ทั่วไปของการทดสอบ E2E ของเรา (กลยุทธ์นี้ใช้กับเฟรมเวิร์กการทดสอบอื่นๆ ที่เราลองใช้ด้วย):
ในหมายเหตุด้านข้าง เราเลือกที่จะไม่ครอบคลุมเคล็ดลับและ gotchas ทั้งหมดสำหรับแนวทางปฏิบัติที่ดีที่สุดสำหรับ WebdriverIO และ E2E ในชุดโพสต์บล็อกนี้ แต่เราจะพูดถึงหัวข้อเหล่านั้นในโพสต์บล็อกในอนาคต โปรดคอยติดตาม!
ขั้นตอนที่ 4: เทียบท่าการทดสอบทั้งหมด
เมื่อดำเนินการขั้นตอนไปป์ไลน์ Buildkite แต่ละรายการบนเครื่อง AWS ใหม่ในคลาวด์ เราไม่สามารถเรียกง่ายๆ ว่า “npm run uitests:staging” เพราะเครื่องเหล่านั้นไม่มีโหนด เบราว์เซอร์ รหัสแอปพลิเคชันของเรา หรือการขึ้นต่อกันอื่นๆ เพื่อเรียกใช้การทดสอบจริง .
เพื่อแก้ปัญหานี้ เราได้รวมการพึ่งพาทั้งหมด เช่น Node, Selenium, Chrome และรหัสแอปพลิเคชันในคอนเทนเนอร์ Docker เพื่อให้การทดสอบ WebdriverIO ทำงานสำเร็จ เราใช้ประโยชน์จาก Docker และ Docker Compose เพื่อรวบรวมบริการทั้งหมดที่จำเป็นในการเริ่มต้นและใช้งาน ซึ่งแปลเป็น Dockerfiles
และไฟล์ docker docker-compose.yml
compose.yml และการทดลองมากมายด้วยการหมุนคอนเทนเนอร์ Docker ในเครื่องเพื่อให้ทำงานได้
เพื่อให้บริบทมากขึ้น เราไม่ใช่ผู้เชี่ยวชาญใน Docker ดังนั้นจึงต้องใช้เวลาพอสมควรในการทำความเข้าใจวิธีรวบรวมสิ่งต่างๆ มีหลายวิธีในการทดสอบ Dockerize WebdriverIO และเราพบว่าเป็นการยากที่จะประสานบริการต่างๆ เข้าด้วยกันและกรองผ่านอิมเมจ Docker เวอร์ชัน Compose และบทช่วยสอนต่างๆ จนกว่าสิ่งต่างๆ จะทำงาน
เราจะสาธิตไฟล์ที่ปรับแต่งเป็นส่วนใหญ่ซึ่งตรงกับหนึ่งในการกำหนดค่าของทีมของเรา และเราหวังว่าสิ่งนี้จะให้ข้อมูลเชิงลึกสำหรับคุณหรือใครก็ตามที่แก้ปัญหาทั่วไปของการทดสอบโดยใช้ Dockerizing Selenium
ในระดับสูง การทดสอบของเราต้องการสิ่งต่อไปนี้:
- ซีลีเนียม เพื่อรันคำสั่งและสื่อสารกับเบราว์เซอร์ เราใช้ Selenium Hub เพื่อหมุนหลายอินสแตนซ์ตามต้องการ และดาวน์โหลดรูปภาพ “ซีลีเนียม/ฮับ” สำหรับบริการ
selenium-hub
ในไฟล์เขียนเทียบท่า - เบราว์เซอร์ ที่จะต่อต้าน เรานำอินสแตนซ์ Selenium Chrome ขึ้นมาและติดตั้งอิมเมจ “selenium/node-chrome-debug” สำหรับบริการ
selenium-chrome
ในdocker-compose.yml file
- รหัสแอปพลิเคชัน เพื่อเรียกใช้ไฟล์ทดสอบของเราโดยติดตั้งโมดูลโหนดอื่น ๆ เราสร้าง
Dockerfile
ใหม่เพื่อให้มีสภาพแวดล้อมที่มี Node เพื่อติดตั้งแพ็คเกจ npm และรันสคริปต์package.json
คัดลอกโค้ดทดสอบ และกำหนดบริการเฉพาะสำหรับการรันไฟล์ทดสอบที่ชื่อuitests
ในไฟล์ dockerdocker-compose.yml
compose.yml
เพื่อให้บริการกับแอปพลิเคชันทั้งหมดของเราและโค้ดทดสอบที่จำเป็นในการรันการทดสอบ WebdriverIO เราได้สร้าง Dockerfile
ชื่อ Dockerfile.uitests
และติดตั้ง node_modules
ทั้งหมดและคัดลอกโค้ดไปยังไดเร็กทอรีการทำงานของอิมเมจในสภาพแวดล้อมของโหนด สิ่งนี้จะถูกใช้โดยบริการ Docker Compose ของเราและเราตั้งค่า uitests
Dockerfile
ด้วยวิธีต่อไปนี้:
เพื่อนำ Selenium Hub, เบราว์เซอร์ Chrome และรหัสทดสอบแอปพลิเคชันมารวมกันเพื่อให้การทดสอบ WebdriverIO ทำงาน เราได้สรุปบริการ selenium-hub
, selenium-chrom
e และ uitest
ในไฟล์ docker-compose.uitests.yml
-compose.uitests.yml :
เราเชื่อมต่อ Selenium Hub และอิมเมจ Chrome ผ่านตัวแปรสภาพแวดล้อม, depends_on
และเปิดเผยพอร์ตไปยังบริการต่างๆ ในที่สุดอิมเมจรหัสแอปพลิเคชันทดสอบของเราจะถูกผลักขึ้นและดึงออกจากรีจิสทรี Docker ส่วนตัวที่เราจัดการ
เราจะสร้างอิมเมจ Docker สำหรับโค้ดทดสอบระหว่าง CICD ด้วยตัวแปรสภาพแวดล้อมบางอย่าง เช่น VERSION
และ PIPELINE_SUFFIX
เพื่ออ้างอิงรูปภาพโดยใช้แท็กและชื่อที่เจาะจงมากขึ้น จากนั้นเราจะเริ่มบริการ Selenium และดำเนินการคำสั่งผ่านบริการ uitests
เพื่อดำเนินการทดสอบ WebdriverIO
เมื่อเราสร้างไฟล์ Docker Compose เราใช้ประโยชน์จากคำสั่งที่เป็นประโยชน์ เช่น docker-compose up
และ docker-compose down
ด้วย Mac Docker ที่ติดตั้งบนเครื่องของเรา เพื่อทดสอบอิมเมจของเราในเครื่องว่ามีการกำหนดค่าที่เหมาะสมและทำงานได้อย่างราบรื่นก่อนที่จะผสานรวมกับ Buildkite เราจัดทำเอกสารคำสั่งทั้งหมดที่จำเป็นในการสร้างภาพที่ติดแท็ก ดันขึ้นไปยังรีจิสทรี ดึงลง และเรียกใช้การทดสอบตามค่าตัวแปรของสภาพแวดล้อม
ขั้นตอนที่ 5: การผสานรวมกับ CICD
หลังจากที่เราสร้างคำสั่ง Docker ที่ใช้งานได้และการทดสอบของเราทำงานสำเร็จภายในคอนเทนเนอร์ Docker กับสภาพแวดล้อมที่แตกต่างกัน เราก็เริ่มผสานรวมกับ Buildkite ซึ่งเป็นผู้ให้บริการ CICD ของเรา
Buildkite มีวิธีดำเนินการตามขั้นตอนในไฟล์ .yml
บนเครื่อง AWS ของเราด้วยสคริปต์ Bash และตัวแปรสภาพแวดล้อมที่ตั้งค่าผ่านโค้ดหรือ UI การตั้งค่า Buildkite สำหรับไปป์ไลน์ของ repo ของเรา
Buildkite ยังอนุญาตให้เราทริกเกอร์ไปป์ไลน์การทดสอบนี้จากไพพ์ไลน์การปรับใช้หลักของเราด้วยตัวแปรสภาพแวดล้อมที่ส่งออก และเราจะนำขั้นตอนการทดสอบเหล่านี้มาใช้ซ้ำสำหรับไพพ์ไลน์การทดสอบแบบแยกอื่น ๆ ซึ่งจะทำงานตามกำหนดเวลาสำหรับ QA ของเราในการตรวจสอบและดู
ในระดับสูง การทดสอบ Buildkite ไปป์ไลน์สำหรับ WebdriverIO และ Cypress ที่ใหม่กว่าได้แชร์ขั้นตอนที่คล้ายกันต่อไปนี้:
- ตั้งค่าอิมเมจ Docker สร้าง แท็ก และพุชอิมเมจ Docker ที่จำเป็นสำหรับการทดสอบจนถึงรีจิสทรี เพื่อให้เราสามารถดึงมันออกมาในขั้นตอนต่อไป
- เรียกใช้การทดสอบตามการกำหนดค่าตัวแปรสภาพแวดล้อม ดึงอิมเมจ Docker ที่ติดแท็กสำหรับบิลด์เฉพาะและรันคำสั่งที่เหมาะสมกับสภาพแวดล้อมที่ปรับใช้เพื่อรันชุดทดสอบที่เลือกจากตัวแปรสภาพแวดล้อมที่ตั้งไว้
นี่คือตัวอย่างคร่าวๆ ของไฟล์ pipeline.uitests.yml
.utests.yml ที่สาธิตการตั้งค่าอิมเมจ Docker ในขั้นตอน "สร้าง UITests Docker Image" และเรียกใช้การทดสอบในขั้นตอน "เรียกใช้การทดสอบ Webdriver กับ Chrome"
สิ่งหนึ่งที่ควรสังเกตคือขั้นตอนแรก "สร้าง UITests Docker Image" และวิธีตั้งค่าอิมเมจ Docker สำหรับการทดสอบ มันใช้คำสั่งบิลด์ Docker Compose เพื่อ build
บริการ uitests
ด้วยโค้ดทดสอบแอปพลิเคชันทั้งหมดและแท็กด้วยตัวแปรสภาพแวดล้อม latest
และ ${VERSION}
เพื่อให้เราสามารถดึงรูปภาพเดียวกันนั้นลงมาด้วยแท็กที่เหมาะสมสำหรับบิลด์นี้ในอนาคต ขั้นตอน
แต่ละขั้นตอนอาจดำเนินการบนเครื่องอื่นใน AWS Cloud ที่ใดที่หนึ่ง ดังนั้นแท็กจึงระบุรูปภาพสำหรับการเรียกใช้ Buildkite ที่เฉพาะเจาะจงได้โดยไม่ซ้ำกัน หลังจากติดแท็กรูปภาพแล้ว เราได้เพิ่มรูปภาพที่ติดแท็กเวอร์ชันล่าสุดไปยังรีจิสทรี Docker ส่วนตัวของเราเพื่อนำกลับมาใช้ใหม่
ในขั้นตอน “เรียกใช้การทดสอบ Webdriver กับ Chrome” เราจะดึงรูปภาพที่เราสร้าง แท็ก และพุชลงในขั้นตอนแรกและเริ่มต้น Selenium Hub, Chrome และบริการทดสอบ ตามตัวแปรสภาพแวดล้อมเช่น $UITESTENV
และ $UITESTSUITE
เราจะเลือกและเลือกประเภทของคำสั่งที่จะเรียกใช้เช่น npm run uitest:
และชุดทดสอบที่จะรันสำหรับ Buildkite build เฉพาะ เช่น --suite $UITESTSUITE
ตัวแปรสภาพแวดล้อมเหล่านี้จะถูกตั้งค่าผ่านการตั้งค่าไปป์ไลน์ Buildkite หรือจะถูกทริกเกอร์แบบไดนามิกจากสคริปต์ทุบตีที่จะแยกวิเคราะห์ฟิลด์เลือก Buildkite เพื่อกำหนดว่าชุดการทดสอบใดที่จะทำงานและเทียบกับสภาพแวดล้อมใด
ต่อไปนี้คือตัวอย่างการทดสอบ WebdriverIO ที่ทริกเกอร์ในไพพ์ไลน์การทดสอบเฉพาะ ซึ่งนำไฟล์ pipeline.uitests.yml
.utests.yml เดิมกลับมาใช้ใหม่ แต่มีการตั้งค่าตัวแปรสภาพแวดล้อมที่ไปป์ไลน์ถูกทริกเกอร์ บิลด์นี้ล้มเหลวและมีภาพหน้าจอแสดงข้อผิดพลาดให้เราดูในแท็บ Artifacts
และเอาต์พุตคอนโซลใต้แท็บ Logs
จำ artifact_paths
ในไพพ์ไลน์. pipeline.uitests.yml
(https://gist.github.com/alfredlucero/71032a82f3a72cb2128361c08edbcff2#file-pipeline-uitests-yml-L38) การตั้งค่าภาพหน้าจอสำหรับ `mochawesome' ใน `wdio.conf.js ` (https://gist.github.com/alfredlucero/4ee280be0e0674048974520b79dc993a#file-wdio-conf-js-L39) และติดตั้งโวลุ่มในบริการ `uitests' ใน `docker-compose.uitests.yml` (https://gist.github.com/alfredlucero/d2df4533a4a49d5b2f2c4a0eb5590ff8#file-docker-compose-yml-L32)?
เราสามารถเชื่อมต่อภาพหน้าจอเพื่อให้สามารถเข้าถึงได้ผ่าน Buildkite UI เพื่อให้เราดาวน์โหลดโดยตรงและดูได้ทันทีเพื่อช่วยในการทดสอบการดีบักดังที่แสดงด้านล่าง
อีกตัวอย่างหนึ่งของการทดสอบ WebdriverIO ที่ทำงานในไปป์ไลน์ที่แยกจากกันตามกำหนดเวลาสำหรับหน้าเฉพาะโดยใช้ไฟล์ pipeline.uitests.yml
.utests.yml ยกเว้นตัวแปรสภาพแวดล้อมที่กำหนดค่าไว้แล้วในการตั้งค่าไปป์ไลน์ Buildkite จะแสดงอยู่ด้านล่าง
สิ่งสำคัญคือต้องสังเกตว่าผู้ให้บริการ CICD ทุกรายมีฟังก์ชันการทำงานที่แตกต่างกันและวิธีการรวมขั้นตอนต่างๆ ในกระบวนการปรับใช้บางประเภทเมื่อรวมโค้ดใหม่ ไม่ว่าจะผ่านไฟล์ .yml
ที่มีรูปแบบเฉพาะ การตั้งค่า GUI สคริปต์ทุบตี หรือวิธีการอื่นๆ
เมื่อเราเปลี่ยนจาก Jenkins เป็น Buildkite เราได้ปรับปรุงความสามารถอย่างมากสำหรับทีมในการกำหนดไปป์ไลน์ของตนเองภายใน codebase ที่เกี่ยวข้อง การทำขั้นตอนคู่ขนานระหว่างเครื่องปรับขนาดตามต้องการ และใช้คำสั่งอ่านที่ง่ายกว่า
ไม่ว่าคุณจะใช้ผู้ให้บริการ CICD รายใด กลยุทธ์ในการรวมการทดสอบจะคล้ายกันในการตั้งค่าอิมเมจ Docker และรันการทดสอบตามตัวแปรสภาพแวดล้อมสำหรับการพกพาและความยืดหยุ่น
ประนีประนอมกับ WebdriverIO
หลังจากแปลงการทดสอบโซลูชัน Ruby Selenium แบบกำหนดเองจำนวนมากไปเป็นการทดสอบ WebdriverIO และผสานรวมกับ Docker และ Buildkite เราได้ปรับปรุงในบางพื้นที่ แต่ก็ยังรู้สึกว่ามีปัญหาคล้ายกันกับระบบเก่าที่ท้ายที่สุดแล้วทำให้เราหยุดต่อไปและสุดท้ายด้วย Cypress สำหรับ โซลูชันการทดสอบ E2E ของเรา
นี่คือรายการข้อดีบางประการที่เราพบจากประสบการณ์ของเรากับ WebdriverIO เมื่อเปรียบเทียบกับโซลูชัน Ruby Selenium แบบกำหนดเอง:
- การทดสอบเขียนด้วย JavaScript หรือ TypeScript ล้วนๆ แทนที่จะเป็น Ruby นี่หมายถึงการสลับบริบทระหว่างภาษาน้อยลง และใช้เวลาน้อยลงในการเรียนรู้ Ruby ใหม่ทุกครั้งที่เราเขียนการทดสอบ E2E
- เรา จัดการทดสอบด้วยรหัสแอปพลิเคชัน แทนที่จะอยู่ใน repo ที่แชร์ของ Ruby เราไม่รู้สึกต้องพึ่งพาการทดสอบของทีมอื่นที่ล้มเหลวอีกต่อไป และรับความเป็นเจ้าของโดยตรงมากขึ้นในการทดสอบ E2E สำหรับคุณสมบัติของเราใน repos ของเรา
- เราชื่นชมตัวเลือกของการทดสอบข้ามเบราว์เซอร์ ด้วย WebdriverIO ทำให้เราสามารถทำการทดสอบกับความสามารถหรือเบราว์เซอร์ต่างๆ เช่น Chrome, Firefox และ IE ได้ แม้ว่าเราจะเน้นไปที่การทดสอบกับ Chrome เป็นหลัก เนื่องจากผู้ใช้ของเรามากกว่า 80% เข้าชมแอปของเราผ่าน Chrome
- เราให้ความบันเทิงกับความเป็นไปได้ในการผสานรวมกับบริการของบุคคลที่สาม เอกสารประกอบ WebdriverIO อธิบายวิธีผสานรวมกับบริการของบุคคลที่สาม เช่น BrowserStack และ SauceLabs เพื่อช่วยในการครอบคลุมแอปของเราในอุปกรณ์และเบราว์เซอร์ทั้งหมด
- เรามีความยืดหยุ่นในการเลือกนักวิ่งทดสอบ นักข่าว และบริการของเราเอง WebdriverIO ไม่ได้กำหนดว่าจะใช้อะไร ดังนั้นแต่ละทีมจึงใช้เสรีภาพในการตัดสินใจว่าจะใช้สิ่งต่างๆ เช่น Mocha และ Chai หรือ Jest และบริการอื่นๆ หรือไม่ สิ่งนี้สามารถตีความได้ว่าเป็นข้อเสียเมื่อทีมเริ่มแยกจากการตั้งค่าของกันและกันและต้องใช้เวลาพอสมควรในการทดสอบแต่ละตัวเลือกเพื่อให้เราเลือกได้
- WebdriverIO API, CLI และเอกสารประกอบนั้นสามารถให้บริการได้มากพอที่จะเขียนการทดสอบและรวมเข้ากับ Docker และ CIC D เราอาจมีไฟล์กำหนดค่าต่างๆ มากมาย จัดกลุ่มข้อกำหนด ดำเนินการทดสอบผ่านบรรทัดคำสั่ง และเขียนการทดสอบตามรูปแบบวัตถุของหน้า อย่างไรก็ตาม เอกสารประกอบอาจมีความชัดเจนมากขึ้น และเราต้องขุดหาจุดบกพร่องแปลก ๆ มากมาย อย่างไรก็ตาม เราสามารถแปลงการทดสอบของเราจากโซลูชัน Ruby Selenium ได้
เรามีความคืบหน้าในหลาย ๆ ด้านที่เราขาดในโซลูชัน Ruby Selenium ก่อนหน้านี้ แต่เราพบผู้แสดงจำนวนมากที่ขัดขวางไม่ให้เราใช้งาน WebdriverIO ทั้งหมดดังต่อไปนี้:
- เนื่องจาก WebdriverIO ยังคงเป็น แบบ Selenium เราจึงประสบปัญหาการหมดเวลา การขัดข้อง และข้อบกพร่องแปลกๆ มากมาย ทำให้เรานึกถึงเหตุการณ์ที่เกิดขึ้นในเชิงลบด้วยโซลูชัน Ruby Selenium แบบเก่าของเรา บางครั้งการทดสอบของเราจะล้มเหลวโดยสิ้นเชิงเมื่อเราเลือกองค์ประกอบหลายอย่างบนหน้าและการทดสอบจะทำงานช้ากว่าที่เราต้องการ เราต้องหาวิธีแก้ไขปัญหาผ่านปัญหา Github จำนวนมากหรือหลีกเลี่ยงวิธีการบางอย่างเมื่อเขียนการทดสอบ
- ประสบการณ์โดยรวมของนักพัฒนาซอฟต์แวร์นั้น ไม่มีประสิทธิภาพ เอกสารประกอบให้ภาพรวมระดับสูงของคำสั่งต่างๆ แต่มีตัวอย่างไม่เพียงพอที่จะอธิบายวิธีการใช้งานทั้งหมด เราหลีกเลี่ยงการเขียนการทดสอบ E2E ด้วย Ruby และในที่สุดก็ต้องเขียนการทดสอบใน JavaScript หรือ TypeScript แต่ WebdriverIO API ค่อนข้างสับสนในการจัดการ ตัวอย่างทั่วไปบางส่วน ได้แก่ การใช้
$
เทียบกับ$$
สำหรับองค์ประกอบเอกพจน์เทียบกับพหูพจน์$('...').waitForVisible(9000, true)
สำหรับการรอให้องค์ประกอบไม่ปรากฏให้เห็น และคำสั่งที่ไม่ได้ตั้งใจอื่นๆ เราพบกับตัวเลือกที่ไม่แน่นอนจำนวนมาก และต้อง$(...).waitForVisible()
อย่างชัดเจนสำหรับทุกสิ่ง - การทดสอบการดีบักนั้นเจ็บปวดและน่าเบื่อมาก สำหรับนักพัฒนาและ QA Whenever tests failed, we only had screenshots, which would often be blank or not capturing the right moment for us to deduce what went wrong, and vague console error messages that did not point us in the right direction of how to solve the problem and even where the issue occurred. We often had to re-run the tests many times and stare closely at the Chrome browser running the tests to hopefully put things together as to where in the code our tests failed. We used things like
browser.debug()
but it often did not work or did not provide enough information. We gradually gathered a bunch of console error messages and mapped them to possible solutions over time but it took lots of pain and headache to get there. - WebdriverIO tests were tough to set up with Docker . We struggled with trying to incorporate it into Docker as there were many tutorials and ways to do things in articles online, but it was hard to figure out a way that worked in general. Hooking up 2 to 3 services together with all these configurations led to long trial and error experiments and the documentation did not guide us enough in how to do that.
- Choosing the test runner, reporter, assertions, and services demanded lots of research time upfront . Since WebdriverIO was flexible enough to allow other options, many teams had to spend plenty of time to even have a solid WebdriverIO infrastructure after experimenting with a lot of different choices and each team can have a completely different setup that doesn't transfer over well for shared knowledge and reuse.
To summarize our WebdriverIO and STUI comparison, we analyzed the overall developer experience (related to tools, writing tests, debugging, API, documentation, etc.), test run times, test passing rates, and maintenance as displayed in this table:
Moving On to Cypress
At the end of the day, our WebdriverIO tests were still flaky and tough to maintain. More time was still spent debugging tests in dealing with weird Selenium issues, vague console errors, and somewhat useful screenshots than actually reaping the benefits of seeing tests fail for when the backend or frontend encountered issues.
We appreciated cross-browser testing and implementing tests in JavaScript, but if our tests could not pass consistently without much headache for even Chrome, then it became no longer worth it and we would then simply have a STUI 2.0.
With WebdriverIO we still strayed from the crucial aspect of providing a way to write consistent, debuggable, maintainable, and valuable E2E automation tests for our frontend applications in our original goal. Overall, we learned a lot about integrating with Buildkite and Docker, using page objects, and outlining tests in a structured way that will transfer over to our final solution with Cypress.
If we felt it was necessary to run our tests in multiple browsers and against various third-party services, we could always circle back to having some tests written with WebdriverIO, or if we needed something fully custom, we would revisit the STUI solution.
Ultimately, neither solution met our main goal for E2E tests, so follow us on our journey in how we migrated from STUI and WebdriverIO to Cypress in part 2 of the blog post series.