มาทำ Automated Test Firebase Authentication ด้วย Cypress แบบง่ายๆ กัน
สวัสดีครับ ผมเชื่อว่าหลายคนที่พัฒนา 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
เรามานั่งดู 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 เกิดมาเพื่อตอบโจทย์สิ่งนี้โดยเฉพาะครับ
ซึ่งปัจจุบัน 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 ได้แบบง่ายๆ เลย
- สร้าง 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 เข้าสู่ระบบมาก่อน ตัว 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 เต็มๆ ของโปรเจ็คตัวอย่างในบทความนี้ได้ที่ลิ้งค์ด้านล่างนี้เลยครับ