มาทำ Automated Test Firebase Authentication ด้วย Cypress แบบง่ายๆ กัน

Traitanit Huangsri
Cypress.io Thailand
5 min readJun 5, 2021

สวัสดีครับ ผมเชื่อว่าหลายคนที่พัฒนา Web Application ก็มักจะต้องสร้างระบบ Authentication เพื่อให้ User ทำการ Login เข้าใช้งานระบบกันมาบ้างใช่มั้ยครับ

ซึ่งในยุคนี้ต้องบอกเลยว่าหลายๆ คนก็คงจะไม่มาสร้างระบบ Authentication System กันเองแล้ว เพราะในปัจจุบันมีผู้ให้บริการระบบ Authentication System แบบพร้อมใช้มาให้เราเลือกใช้งานโดยเพียงแค่เรานำ App ของเราไปเชื่อมต่อกับระบบนั้นก็จะสามารถได้ ระบบการทำ Authentication ดีๆ มาใช้แล้ว ซึ่ง Firebase Authentication ก็ถือเป็นหนึ่งในตัวเลือกระดับต้นๆ ที่นักพัฒนามักจะเลือกมาใช้งานกัน เพราะมันใช้งานง่าย มี SDK และ Library ต่างๆ คอยสนับสนุนให้ใช้งานได้อย่างง่ายดาย

สำหรับใครที่ผ่านเข้ามาอ่านบทความนี้แล้วยังไม่รู้จักว่า Firebase Authentication คืออะไร ขอแนะนำให้อ่านบทความด้านล่างนี้ก่อนเลยครับ

ปัญหาอย่างหนึ่งที่เป็นปัญหาคลาสสิกของนักพัฒนาและ Testers หลายๆ ท่านก็คือ เวลาที่เราต้องการจะเทส Web Application ของเราที่มีระบบ Authentication อยู่แล้วนั้นเราจะต้องทำการ Login เข้าสู่ระบบของเราให้เรียบร้อยเสียก่อนถึงจะเริ่มเข้าไปเทส Feature ต่างๆ ภายในแอพได้ ซึ่งหลายคนก็มักจะติดปัญหาตรงนี้และเลิกล้มความตั้งใจในการเขียน Automated Test ให้กับระบบของตัวเองไปในที่สุด

ในบทความนี้ผมจะขอนำเสนอวิธีการทำ Automated Test Firebase Authentication ด้วย Cypress แบบง่ายๆ เพื่อให้คุณสามารถเขียนเทสให้กับ Web Application ของคุณได้แบบง่ายๆ เลย มาดูกัน!

Testing Diagram

Firebase Authentication with Cypress

เรามานั่งดู Testing Diagram ที่ผม Design ไว้กันก่อนว่าเราจะสร้าง Automated Test Firebase Authentication ได้อย่างไร? เทคนิคที่ผมจะนำเสนอในบทความนี้คือ การนำ Firebase Emulator Suite มาประยุกต์ใช้โดยให้ Cypress เป็นคนทำ Automated Login เข้าสู่ระบบของเราโดยที่เราไม่ต้องเปลืองแรงคนมานั่งเทสระบบของเราอีกต่อไป

Firebase Emulator Suite คือชุดเครื่องมือชั้นเยี่ยมที่ทาง Firebase เตรียมไว้ให้นักพัฒนาเอาไว้ Debug และ Test App ของตัวเองที่ใช้งาน Firebase Service โดยเราสามารถนำ ​Firebase Emulator Suite มารันใน local ภายในเครื่องเราเสมือนกับว่าเรายก Firebase จาก Google Cloud มาอยู่ในเครื่องของเราอย่างงั้นเลย เราไม่จำเป็นต้อง Deploy โค้ดของเราขึ้น Production ถ้าเรายังเทสมันไม่ดีพอ และ Firebase Emulator Suite เกิดมาเพื่อตอบโจทย์สิ่งนี้โดยเฉพาะครับ

https://firebase.google.com/docs/emulator-suite

ซึ่งปัจจุบัน Firebase Emulator Suite ก็ได้ Provide Firebase Service มาให้เราใช้งานหลายตัวเช่น Cloud Firestore, Realtime Database และล่าสุด Authentication Service ก็ได้ถูกนำมารวมไว้อยู่ใน Emulator Suite นี้ด้วย

หลักการก็คือเมื่อ App ของเราถูกรันขึ้นมาเพื่อทำเทสด้วย Cypress ก็ให้มันทำการต่อกับ Firebase Auth Emulator แทนที่จะต่อกับ Firebase Authentication จริงๆ บน Google Cloud และให้ Test ของเราสามารถ Login เข้าสู่ระบบได้ผ่านการใช้ Email Auth Provider ได้แบบง่ายๆ เลย

Project Setup

ตัวอย่างโค้ดในบทความนี้ผมจะใช้ React ทำงานร่วมกับ Firebase UI ซึ่งเป็น Library ที่ Firebase เตรียมไว้ให้เราสามารถสร้าง UI Login Flow ได้แบบง่ายๆ เลย

  1. สร้าง Firebase Project

สำหรับใครที่ยังไม่เคยใช้งาน Firebase มาก่อน ให้เข้าไปที่ https://console.firebase.google.com/ เพื่อสร้าง Project ก่อนนะครับ สามารถทำตาม Instruction ที่อยู่ในเว็บได้เลย เมื่อสร้างเสร็จแล้วให้ไปที่เมนู Authentication -> Sign-in method เพื่อทำการ Enable Email/Password Sign-in Provider ขึ้นมาแบบนี้ครับ

2. สร้าง React Project

ผมเลือกใช้ create-react-app ทำการสร้าง React Project ขึ้นมาครับ

$ npx create-react-app firebase-auth-cypress

หลังจากนั้นให้ทำการ Install Dependencies เข้าไปตามนี้

$ yarn add firebase react-firebaseui react-router-dom

และสำหรับ Test Dependencies

$ yarn add -D cypress

3. Setup Firebase

ให้เราทำการเชื่อมต่อ App ของเราเข้ากับ Firebase โดยใช้ firebase-tools นะครับ

$ firebase --init

ให้ทำการ Config Project ของเราโดยเลือก Project ที่เราสร้างไว้ใน Firebase Console และ Option อื่นๆ ก็ตามที่เห็นข้างล่างนี้

จะเห็นได้ว่าเราได้ทำการเพิ่ม Firebase Authentication Emulator เข้าไปใน Project ด้วยเพื่อให้เราทำการเทสแอพของเราผ่านตัว Emulator ได้อย่างง่ายๆ ครับ โดยมันจะรันอยู่ที่ http://localhost:9099 นั่นเอง

เมื่อ Setup เสร็จแล้ว เราจะได้ไฟล์ firebase.json และ .firebaserc เข้ามาอยู่ใน Project ของเราอัตโนมัติ

4. Initialize Firebase Config

เราจะต้องทำการสร้างไฟล์ firebase.js ไว้ใน Project เพื่อทำการ Initialize ตัว Firebase ด้วยตัว Config ของ Project เราด้วย

ให้เราไปที่ Firebase Console -> Project Settings -> General -> Add App เพื่อเพิ่ม Web App ของเราเข้าไป เมื่อเพิ่มเสร็จแล้วเราจะเห็น config ของ Firebase Project ออกมาแบบนี้ ให้เราทำการ Copy และมาแปะไว้ใน firebase/firebase.js ครับ

เมื่อได้มาแล้วให้ทำการ import firebase SDK เข้ามาเพื่อทำการ initializeApp แบบนี้ครับ

สร้าง Login Page โดยใช้ Firebase UI

ผมเลือกใช้ React Router เพื่อจัดการ Path ต่างๆ ในแอพของเราโดยเพิ่ม /login/email เข้าไปเพื่อให้ผู้ใช้งานสามารถ Login เข้าใช้งานผ่าน Email ได้

หลังจากนั้นผมทำการสร้าง Login Page ขึ้นมาแบบนี้ครับ

จากโค้ดจะเห็นว่า ถ้าแอพถูกรันด้วย Cypress ขึ้นมาก็จะให้ต่อกับตัว Firebase Auth Emulator แทนที่จะต่อกับ Firebase Authentication จริงๆ เพื่อให้เราสามารถ Control Login Flow ด้วย Test ได้นั่นเอง

นอกจากนั้นในตัวโค้ดผมเลือกใช้ Library react-firebaseui เพื่อทำการวาด Login UI รวมถึงการ Control Login Flow ต่างๆ ด้วยการ Map State ที่อยู่ใน Component ได้แบบง่ายๆ ผ่านการใช้ useEffect และ useState hooks นั่นเอง

จากโค้ดจะเห็นได้ว่ามีการเช็ค Login State ไว้ โดยที่ถ้า User ได้ทำการ Login เป็นที่เรียบร้อยแล้วจะให้แสดงผลหน้าที่บอกว่า “Sign-in with Email success” และทำการดึง E-mail ที่ User ใช้ Login มาแสดงผลด้วย แต่ถ้ายังไม่เคย Login มาก่อนก็ให้ทำการแสดงผล Login Form เพื่อให้ User ทำการกรอก E-mail และ Password เพื่อทำการเข้าสู่ระบบอีกที

ผมไม่ลืมที่จะเพิ่ม data attribute data-testid ไว้ใน UI component เพื่อให้ Cypress สามารถเข้าถึง UI ต่างๆ ได้อย่างง่ายด้วยครับ

ลองรัน App ขึ้นมา!

เมื่อลองรันแอพขึ้นมาแล้วไปที่ http://localhost:3000/login/email ก็จะได้หน้าตาออกมาแบบนี้

หน้า Login มาแล้ว

จะเห็นได้ว่า ถ้าเรายังไม่เคย Login เข้าสู่ระบบมาก่อน ตัว App ก็จะแสดงผล Login Form เพื่อให้เรากรอกข้อมูลเพื่อทำการเข้าสู่ระบบครับ

Start Firebase Auth Emulator เพื่อทำการเพิ่ม Test User เข้าไป

เมื่อทุกอย่างพร้อมแล้ว ให้เราทำการ Start Firebase Auth Emulator ขึ้นมาเพื่อทำการเพิ่ม User ที่จะใช้สำหรับเทสเข้าไปกันครับ

$ firebase emulator:start

ตัว Firebase Auth Emulator จะมีหน้า UI ที่ให้เราสามารถเข้าไป Config User ต่างๆ ได้โดยง่าย โดยสามารถเข้าใช้งานผ่าน Browser ได้ที่ URL http://localhost:4000/auth ได้เลยครับ

เมื่อเข้ามาแล้วก็ให้เราทำการเพิ่ม User โดยคลิกปุ่ม Add user แล้วก็กรอก User Information ที่เราจะใช้เทสได้เลย

เมื่อกรอกเสร็จแล้วก็ให้กด ​Save เพื่อเก็บข้อมูลไว้ Note ไว้นิดนึงนะครับว่าถ้าเรา Kill Firebase Emulator Suite ไปแล้วข้อมูลตรงนี้ก็จะหายไปด้วยนะครับ ซึ่งเราสามารถ Save ข้อมูลต่างๆ ที่เราสร้างไว้แล้ว export เก็บไว้ในไฟล์ได้ เมื่อ Start Emulator ครั้งถัดไปก็สามารถ Import Data ที่เคย Export ไว้มาใช้งานได้เช่นกัน

$ firebase emulators:export <path>

และเมื่อ start emulator กลับมาใหม่ก็ให้ import data ที่ export ไว้กลับมาได้

$ firebase emulators:start --import <path>

เท่านี้ Data ที่เราสร้างไว้ก็จะไม่หายไปและสามารถนำมา Reuse ใช้งานได้ตลอดกาลครับ

เริ่มเขียน Automated Test ด้วย Cypress

สำหรับใครที่ยังไม่รู้จักหรือยังไม่เคยใช้งาน Cypress มาก่อนขอให้แนะนำให้อ่านบทความนี้ก่อนนะครับ

ก่อนอื่นให้เราทำการวางโครงสร้าง Folder Structure ของ Cypress ก่อนด้วยการเรียกใช้ Command

$ npx cypress open

เมื่อได้ Folder Structure ของ ​Test แล้วให้ทำการเพิ่มเทสเข้าไปที่ Folder integration ได้เลยครับ

จากเทสจะเห็นว่า Step Simple มากก็คือเปิด Web App ขึ้นมาเข้าหน้า Login -> กรอก Email และ Password แล้วกดปุ่ม Submit แล้วเช็คดูว่า Login มาสำเร็จหรือไม่

โดยผมได้ทำการ Config baseUrl ไว้ใน cypress.json แบบนี้ครับ

มาลองรัน Automated Test กัน!

เนื่องจากเราจะต้องมีการเรียก Firebase Emulator -> Start React App -> Start Cypress Test ผมจึงเลือกใช้ Library start-server-and-test เพื่อให้การรันเทสเกิดขึ้นได้ง่ายเพียงการเรียก Command เดียวแบบนี้ครับ

นี่คือส่วนของ scripts ใน package.json ใน Project จะเห็นว่าถ้าเราเรียก script test:e2e:run ขึ้นมา มันจะทำการไป Start Firebase Emulator ขึ้นมาก่อน หลังจากนั้นก็ค่อยไป Start React App ขึ้นมา และสุดท้ายก็ทำการ Start Cypress Test ขึ้นมารันบน Chrome Browser อีกทีครับ เรียกได้ว่าเรียก Script ตัวเดียวมันก็ทำให้เราทุกอย่างเลย สะดวกสุดๆ ถ้าใครที่ยังไม่เคยใช้ขอแนะนำ Library ตัวนี้เลยครับ

$ yarn test:e2e:run

จะเห็นได้ว่าเมื่อเทสถูกรันขึ้นมานั้น ตัว Web App ของเราจะทำการ Login ผ่าน Firebase Auth Emulator แทนที่จะไปใช้ Firebase Authentication จริงๆ (สังเกตจากตัวหนังสือสีแดงที่เขียนว่า “Running in emulator mode..”) ซึ่งทำให้เราสามารถจัดการ Test User ได้ง่ายกว่า และการันตีว่าจะไม่มีใครมาแก้ไขหรือเปลี่ยนแปลง Account ของเราระหว่างรันเทสได้นั่นเองครับ

Tips ส่งท้าย

หลายคนอาจจะพอทราบว่า Firebase Authentication นั้นรองรับการทำ Authentication ได้หลากหลาย Providers มากๆ ไม่ว่าจะเป็น Email หรือจะเป็น 3rd Party​ Identity Providers เช่น Facebook, Twitter, Google, etc. ซึ่งในเชิงการสร้าง Maintainable Automated Tests แล้วนั้น ถ้าเราไม่ได้จะเทสระบบ Login จริงๆ (เพราะนั้นคือคุณกำลังเทส Firebase Authentication ไม่ใช่เทส App ของคุณ) ขอแนะนำให้ใช้วิธีการทำ Login แบบเรียบง่าย โดยอาจจะเลือกใช้ Email Provider เป็นหนึ่งในทางเลือกที่จะให้ Test ของคุณสามารถเข้าสู่ระบบในแอพของคุณได้โดยอาจจะเปิดให้ใช้เฉพาะบน Dev หรือ Test Environment เท่านั้น น่าจะเป็นตัวเลือกที่ดีกว่าการให้ Test ของเราไป Login กับ 3rd Party Identity Providers ต่างๆทุกครั้งที่รันเทส ซึ่งอาจจะสร้างปัญหาในการเขียนเทสในระยะยาวที่มากกว่าครับ

หวังว่าบทความนี้จะเป็นประโยชน์ให้กับนักพัฒนาและ Tester หลายๆ คนเริ่มมาเขียน Automated Tests ให้กับระบบที่มีการทำ Login ด้วย Firebase Authentication กันนะครับ Happy Coding & Testing!

สามารถดูรายละเอียด Source Code เต็มๆ ของโปรเจ็คตัวอย่างในบทความนี้ได้ที่ลิ้งค์ด้านล่างนี้เลยครับ

--

--