ขณะสร้างแอป คุณอาจต้องการล็อกการเข้าถึงฐานข้อมูล Cloud Firestore อย่างไรก็ตาม ก่อนเปิดตัว คุณจะต้องมีCloud Firestore Security Rulesที่ละเอียดยิ่งขึ้น เมื่อใช้โปรแกรมจำลอง Cloud Firestore นอกจากการสร้างต้นแบบและการทดสอบฟีเจอร์และลักษณะการทำงานทั่วไปของแอปแล้ว คุณยังสามารถเขียน Unit Test ที่ตรวจสอบลักษณะการทำงานของ Cloud Firestore Security Rules ได้ด้วย
คู่มือเริ่มใช้งานฉบับย่อ
สำหรับกรอบการทดสอบพื้นฐานบางรายการที่มีกฎง่ายๆ ให้ลองใช้ตัวอย่างการเริ่มต้นใช้งานด่วน
ทำความเข้าใจCloud Firestore Security Rules
ใช้ Firebase Authentication และ Cloud Firestore Security Rules สำหรับการตรวจสอบสิทธิ์ การให้สิทธิ์ และการตรวจสอบข้อมูลแบบ Serverless เมื่อคุณใช้ไลบรารีของไคลเอ็นต์บนอุปกรณ์เคลื่อนที่และเว็บ
Cloud Firestore Security Rules ประกอบด้วย 2 ส่วน ได้แก่
- คำสั่ง
matchที่ระบุเอกสารในฐานข้อมูล - นิพจน์
allowที่ควบคุมการเข้าถึงเอกสารเหล่านั้น
Firebase Authentication จะยืนยันข้อมูลเข้าสู่ระบบของผู้ใช้และเป็นรากฐานสำหรับระบบการเข้าถึงตามฐานผู้ใช้และตามบทบาท
คำขอฐานข้อมูลทุกรายการจากไลบรารีของไคลเอ็นต์บนอุปกรณ์เคลื่อนที่/เว็บบนมือถือของ Rules จะได้รับการประเมินเทียบกับกฎความปลอดภัยก่อนที่จะอ่านหรือเขียนข้อมูลใดๆ หากกฎปฏิเสธการเข้าถึงเส้นทางเอกสารที่ระบุ คำขอทั้งหมดจะล้มเหลว
ดูข้อมูลเพิ่มเติมเกี่ยวกับ Cloud Firestore Security Rules ในเริ่มต้นใช้งาน Cloud Firestore Security Rules
ติดตั้งโปรแกรมจำลอง
หากต้องการติดตั้งโปรแกรมจำลอง Cloud Firestore ให้ใช้ Firebase CLI และเรียกใช้คำสั่งด้านล่าง
firebase setup:emulators:firestore
เรียกใช้โปรแกรมจำลอง
เริ่มต้นด้วยการเริ่มต้นโปรเจ็กต์ Firebase ในไดเรกทอรีการทำงาน ซึ่งเป็นขั้นตอนแรกที่พบบ่อยเมื่อใช้ Firebase CLI
firebase init
เริ่มโปรแกรมจำลองโดยใช้คำสั่งต่อไปนี้ โปรแกรมจำลองจะทำงานจนกว่าคุณจะหยุดกระบวนการ
firebase emulators:start --only firestore
ในหลายกรณี คุณอาจต้องการเริ่มโปรแกรมจำลอง เรียกใช้ชุดโปรแกรมทดสอบ แล้วปิดโปรแกรมจำลองหลังจากการทดสอบทำงาน คุณสามารถทำได้ง่ายๆ โดยใช้คำสั่ง emulators:exec ดังนี้
firebase emulators:exec --only firestore "./my-test-script.sh"
เมื่อเริ่มต้น โปรแกรมจำลองจะพยายามทำงานในพอร์ตเริ่มต้น (8080) คุณเปลี่ยนพอร์ตโปรแกรมจำลองได้โดยแก้ไขส่วน "emulators" ของไฟล์ firebase.json ดังนี้
{
// ...
"emulators": {
"firestore": {
"port": "YOUR_PORT"
}
}
}ก่อนเรียกใช้โปรแกรมจำลอง
โปรดคำนึงถึงสิ่งต่อไปนี้ก่อนเริ่มใช้โปรแกรมจำลอง
- ในตอนแรก โปรแกรมจำลองจะโหลดกฎที่ระบุไว้ในช่อง
firestore.rulesของไฟล์firebase.jsonโดยจะคาดหวังชื่อไฟล์ในเครื่องที่มี Cloud Firestore Security Rules ของคุณ และใช้กฎเหล่านั้นกับโปรเจ็กต์ทั้งหมด หากคุณไม่ได้ระบุเส้นทางไฟล์ในเครื่องหรือใช้เมธอดloadFirestoreRulesตามที่อธิบายไว้ด้านล่าง โปรแกรมจำลองจะถือว่าโปรเจ็กต์ทั้งหมดมีกฎแบบเปิด - แม้ว่า Firebase SDK ส่วนใหญ่จะทำงานร่วมกับโปรแกรมจำลองได้โดยตรง แต่มีเพียงไลบรารี
@firebase/rules-unit-testingเท่านั้นที่รองรับการจำลองauthในกฎความปลอดภัย ซึ่งช่วยให้การทำ Unit Test ง่ายขึ้นมาก นอกจากนี้ ไลบรารียังรองรับฟีเจอร์เฉพาะของโปรแกรมจำลองบางอย่าง เช่น การล้างข้อมูลทั้งหมด ดังที่แสดงด้านล่าง - นอกจากนี้ โปรแกรมจำลองยังยอมรับโทเค็น Firebase Auth เวอร์ชันที่ใช้งานจริงซึ่งได้จาก SDK ของไคลเอ็นต์และประเมินกฎตามนั้น ซึ่งช่วยให้คุณเชื่อมต่อแอปพลิเคชันกับโปรแกรมจำลองได้โดยตรงในการทดสอบการผสานรวมและการทดสอบด้วยตนเอง
เรียกใช้ Unit Test ในเครื่อง
เรียกใช้การทำ Unit Test ในเครื่องด้วย JavaScript SDK เวอร์ชัน 9
Firebase เผยแพร่ไลบรารีการทำ Unit Test ของกฎความปลอดภัยทั้งใน JavaScript SDK เวอร์ชัน 9 และ SDK เวอร์ชัน 8 API ของไลบรารีจะแตกต่างกันอย่างมาก เราขอแนะนำให้ใช้ไลบรารีการทดสอบ v9 ซึ่งมีประสิทธิภาพมากกว่าและต้องมีการตั้งค่าน้อยกว่าเพื่อเชื่อมต่อกับโปรแกรมจำลอง จึงหลีกเลี่ยงการใช้ทรัพยากรเวอร์ชันที่ใช้งานจริงโดยไม่ตั้งใจได้อย่างปลอดภัย เรายังคงให้บริการไลบรารีการทดสอบ v8 เพื่อให้เข้ากันได้แบบย้อนหลัง
ใช้โมดูล @firebase/rules-unit-testing เพื่อโต้ตอบกับโปรแกรมจำลองที่ทำงานในเครื่อง หากคุณได้รับข้อผิดพลาดเกี่ยวกับระยะหมดเวลาหรือข้อผิดพลาด ECONNREFUSED ให้ตรวจสอบอีกครั้งว่าโปรแกรมจำลองทำงานอยู่จริง
เราขอแนะนำอย่างยิ่งให้ใช้ Node.js เวอร์ชันล่าสุดเพื่อให้คุณใช้สัญกรณ์ async/await ได้ ลักษณะการทำงานเกือบทั้งหมดที่คุณอาจต้องการทดสอบเกี่ยวข้องกับฟังก์ชันแบบอะซิงโครนัส และโมดูลการทดสอบได้รับการออกแบบมาให้ทำงานกับโค้ดที่อิงตาม Promise
ไลบรารีการทำ Unit Test ของกฎ v9 จะรับรู้ถึงโปรแกรมจำลองเสมอและจะไม่แตะทรัพยากรเวอร์ชันที่ใช้งานจริง
คุณนำเข้าไลบรารีโดยใช้คำสั่งนำเข้าแบบโมดูลาร์ v9 เช่น
import {
assertFails,
assertSucceeds,
initializeTestEnvironment
} from "@firebase/rules-unit-testing"
// Use `const { … } = require("@firebase/rules-unit-testing")` if imports are not supported
// Or we suggest `const testing = require("@firebase/rules-unit-testing")` if necessary.
เมื่อนำเข้าแล้ว การใช้ Unit Test จะเกี่ยวข้องกับสิ่งต่อไปนี้
- การสร้างและกำหนดค่า
RulesTestEnvironmentด้วยการเรียกใช้initializeTestEnvironment - การตั้งค่าข้อมูลทดสอบโดยไม่เรียกใช้กฎ โดยใช้วิธีที่สะดวกซึ่งช่วยให้คุณข้ามกฎเหล่านั้นได้ชั่วคราว
RulesTestEnvironment.withSecurityRulesDisabled - การตั้งค่าชุดโปรแกรมทดสอบและฮุกก่อน/หลังการทดสอบแต่ละครั้งด้วยการเรียกใช้เพื่อล้างข้อมูลและสภาพแวดล้อมการทดสอบ เช่น
RulesTestEnvironment.cleanup()หรือRulesTestEnvironment.clearFirestore() - การใช้กรอบการทดสอบที่เลียนแบบสถานะการตรวจสอบสิทธิ์โดยใช้
RulesTestEnvironment.authenticatedContextและRulesTestEnvironment.unauthenticatedContext
เมธอดและฟังก์ชันยูทิลิตีทั่วไป
โปรดดูวิธีการทดสอบเฉพาะโปรแกรมจำลองใน v9 SDK ด้วย
initializeTestEnvironment() => RulesTestEnvironment
ฟังก์ชันนี้จะเริ่มต้นสภาพแวดล้อมการทดสอบสำหรับการทำ Unit Test ของกฎ เรียกใช้ฟังก์ชันนี้ก่อนเพื่อตั้งค่าการทดสอบ การดำเนินการที่สำเร็จต้องใช้โปรแกรมจำลองที่ทำงานอยู่
ฟังก์ชันนี้ยอมรับออบเจ็กต์ที่ไม่บังคับซึ่งกำหนด TestEnvironmentConfig ซึ่งอาจประกอบด้วยรหัสโปรเจ็กต์และการตั้งค่าการกำหนดค่าโปรแกรมจำลอง
let testEnv = await initializeTestEnvironment({ projectId: "demo-project-1234", firestore: { rules: fs.readFileSync("firestore.rules", "utf8"), }, });
RulesTestEnvironment.authenticatedContext({ user_id: string, tokenOptions?: TokenOptions }) => RulesTestContext
เมธอดนี้จะสร้าง RulesTestContext ซึ่งทำงานเหมือนกับผู้ใช้ที่ผ่านการตรวจสอบสิทธิ์แล้ว คำขอที่สร้างผ่านบริบทที่แสดงผลจะมีโทเค็นการตรวจสอบสิทธิ์จำลองแนบมาด้วย คุณสามารถส่งออบเจ็กต์ที่กำหนดการอ้างสิทธิ์ที่กำหนดเองหรือการลบล้างสำหรับเพย์โหลดโทเค็นการตรวจสอบสิทธิ์ได้ (ไม่บังคับ)
ใช้ออบเจ็กต์บริบทการทดสอบที่แสดงผลในการทดสอบเพื่อเข้าถึงอินสแตนซ์โปรแกรมจำลองที่กำหนดค่าไว้ รวมถึงอินสแตนซ์ที่กำหนดค่าด้วย initializeTestEnvironment
// Assuming a Firestore app and the Firestore emulator for this example import { setDoc } from "firebase/firestore"; const alice = testEnv.authenticatedContext("alice", { … }); // Use the Firestore instance associated with this context await assertSucceeds(setDoc(alice.firestore().doc('/users/alice'), { ... });
RulesTestEnvironment.unauthenticatedContext() => RulesTestContext
วิธีนี้จะสร้าง RulesTestContext ซึ่งทำงานเหมือนกับไคลเอ็นต์ที่ไม่ได้เข้าสู่ระบบผ่านการตรวจสอบสิทธิ์ คำขอที่สร้างผ่านบริบทที่แสดงผลจะไม่มีโทเค็น Firebase Auth แนบมาด้วย
ใช้ออบเจ็กต์บริบทการทดสอบที่แสดงผลในการทดสอบเพื่อเข้าถึงอินสแตนซ์โปรแกรมจำลองที่กำหนดค่าไว้ รวมถึงอินสแตนซ์ที่กำหนดค่าด้วย initializeTestEnvironment
// Assuming a Cloud Storage app and the Storage emulator for this example import { getStorage, ref, deleteObject } from "firebase/storage"; const alice = testEnv.unauthenticatedContext(); // Use the Cloud Storage instance associated with this context const desertRef = ref(alice.storage(), 'images/desert.jpg'); await assertSucceeds(deleteObject(desertRef));
RulesTestEnvironment.withSecurityRulesDisabled()
เรียกใช้ฟังก์ชันการตั้งค่าการทดสอบด้วยบริบทที่ทำงานเสมือนว่ากฎความปลอดภัยถูกปิดใช้อยู่
เมธอดนี้ใช้ฟังก์ชัน Callback ซึ่งใช้บริบทการข้ามกฎความปลอดภัยและแสดงผล Promise บริบทจะถูกทำลายเมื่อ Promise ได้รับการแก้ไข / ปฏิเสธ
RulesTestEnvironment.cleanup()
วิธีนี้จะทำลาย RulesTestContexts ทั้งหมดที่สร้างขึ้นในสภาพแวดล้อมการทดสอบและล้างทรัพยากรที่เกี่ยวข้อง เพื่อให้สามารถออกได้อย่างสมบูรณ์
วิธีนี้จะไม่เปลี่ยนสถานะของโปรแกรมจำลองแต่อย่างใด หากต้องการรีเซ็ตข้อมูลระหว่างการทดสอบ ให้ใช้วิธีล้างข้อมูลเฉพาะของโปรแกรมจำลองแอปพลิเคชัน
assertSucceeds(pr: Promise<any>)) => Promise<any>
นี่คือฟังก์ชันยูทิลิตีของกรอบการทดสอบ
ฟังก์ชันนี้ยืนยันว่า Promise ที่ระบุซึ่งรวมการดำเนินการของโปรแกรมจำลองจะได้รับการแก้ไขโดยไม่มีการละเมิดกฎความปลอดภัย
await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });assertFails(pr: Promise<any>)) => Promise<any>
นี่คือฟังก์ชันยูทิลิตีของกรอบการทดสอบ
ฟังก์ชันนี้ยืนยันว่า Promise ที่ระบุซึ่งรวมการดำเนินการของโปรแกรมจำลองจะถูกปฏิเสธเนื่องจากละเมิดกฎความปลอดภัย
await assertFails(setDoc(alice.firestore(), '/users/bob'), { ... });วิธีการเฉพาะสำหรับโปรแกรมจำลอง
นอกจากนี้ โปรดดูวิธีการทดสอบและฟังก์ชันยูทิลิตีทั่วไปใน v9 SDK
RulesTestEnvironment.clearFirestore() => Promise<void>
วิธีนี้จะล้างข้อมูลในฐานข้อมูล Firestore ที่เป็นของ projectId ซึ่งกำหนดค่าไว้สำหรับโปรแกรมจำลอง Firestore
RulesTestContext.firestore(settings?: Firestore.FirestoreSettings) => Firestore;
เมธอดนี้จะรับอินสแตนซ์ Firestore สำหรับบริบทการทดสอบนี้ อินสแตนซ์ Firebase JS Client SDK ที่แสดงผลสามารถใช้กับ API ของ SDK ของไคลเอ็นต์ (v9 แบบแยกส่วนหรือ v9 compat)
แสดงภาพการประเมินกฎ
โปรแกรมจำลอง Cloud Firestore ช่วยให้คุณเห็นภาพคำขอของไคลเอ็นต์ใน UI ของชุดโปรแกรมจำลอง รวมถึงการติดตามการประเมินสำหรับกฎความปลอดภัยของ Firebase
เปิดแท็บ Firestore > คำขอเพื่อดูลำดับการประเมินโดยละเอียดสำหรับคำขอแต่ละรายการ
สร้างรายงานการทดสอบ
หลังจากเรียกใช้ชุดการทดสอบแล้ว คุณจะเข้าถึงรายงานความครอบคลุมของการทดสอบที่แสดงวิธีประเมินกฎความปลอดภัยแต่ละข้อได้
หากต้องการรับรายงาน ให้ค้นหาปลายทางที่แสดงในโปรแกรมจำลองขณะที่ทำงานอยู่ หากต้องการเวอร์ชันที่เหมาะกับเบราว์เซอร์ ให้ใช้ URL ต่อไปนี้
http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage.html
ซึ่งจะแบ่งกฎออกเป็นนิพจน์และนิพจน์ย่อยที่คุณสามารถวางเมาส์เหนือเพื่อดูข้อมูลเพิ่มเติม รวมถึงจำนวนการประเมินและค่าที่แสดงผล สำหรับข้อมูลนี้ในเวอร์ชัน JSON ดิบ ให้รวม URL ต่อไปนี้ไว้ในการค้นหา
http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage
ความแตกต่างระหว่างโปรแกรมจำลองและเวอร์ชันที่ใช้งานจริง
- คุณไม่จำเป็นต้องสร้างโปรเจ็กต์ Cloud Firestore อย่างชัดเจน โปรแกรมจำลองจะสร้างอินสแตนซ์ที่เข้าถึงโดยอัตโนมัติ
- โปรแกรมจำลอง Cloud Firestore ไม่ทำงานกับขั้นตอน Firebase Authentication ปกติ
แต่ใน Firebase Test SDK เราได้จัดเตรียมเมธอด
initializeTestApp()ไว้ในไลบรารีrules-unit-testingซึ่งใช้ฟิลด์authแฮนเดิล Firebase ที่สร้างขึ้นโดยใช้วิธีนี้จะทำงานเสมือนว่าได้รับการตรวจสอบสิทธิ์เรียบร้อยแล้วในฐานะเอนทิตีใดก็ตามที่คุณระบุ หากคุณส่งnullระบบจะทำงานเหมือนเป็นผู้ใช้ที่ไม่ได้รับการตรวจสอบสิทธิ์ (เช่น กฎauth != nullจะไม่สำเร็จ)
แก้ปัญหาที่ทราบแล้ว
ขณะใช้โปรแกรมจำลอง Cloud Firestore คุณอาจพบปัญหาที่ทราบแล้วต่อไปนี้ ทำตามคำแนะนำด้านล่างเพื่อแก้ปัญหาลักษณะการทำงานที่ผิดปกติที่คุณพบ บันทึกเหล่านี้เขียนขึ้นโดยคำนึงถึงไลบรารีการทำ Unit Test ของกฎความปลอดภัย แต่วิธีการทั่วไปใช้ได้กับ Firebase SDK ทุกเวอร์ชัน
ลักษณะการทดสอบไม่สอดคล้องกัน
หากการทดสอบผ่านและไม่ผ่านเป็นครั้งคราว แม้ว่าจะไม่มีการเปลี่ยนแปลงใดๆ กับการทดสอบ คุณอาจต้องตรวจสอบว่าการทดสอบมีลำดับที่ถูกต้อง
การโต้ตอบส่วนใหญ่กับโปรแกรมจำลองจะเป็นแบบอะซิงโครนัส ดังนั้นโปรดตรวจสอบอีกครั้งว่าโค้ดแบบอะซิงโครนัสทั้งหมดได้รับการจัดลำดับอย่างถูกต้อง คุณสามารถแก้ไขการจัดลำดับได้โดยการเชื่อมโยง Promise หรือใช้สัญกรณ์ await อย่างอิสระ
โดยเฉพาะอย่างยิ่ง ให้ตรวจสอบการดำเนินการแบบไม่พร้อมกันต่อไปนี้
- การตั้งค่ากฎความปลอดภัย เช่น
initializeTestEnvironment - การอ่านและเขียนข้อมูล เช่น ด้วย
db.collection("users").doc("alice").get() - การยืนยันด้านการปฏิบัติงาน ซึ่งรวมถึง
assertSucceedsและassertFails
การทดสอบจะผ่านเฉพาะครั้งแรกที่คุณโหลดโปรแกรมจำลองเท่านั้น
โปรแกรมจำลองเป็นแบบเก็บสถานะ โดยจะจัดเก็บข้อมูลทั้งหมดที่เขียนลงในหน่วยความจำ ดังนั้นข้อมูลจะสูญหายเมื่อใดก็ตามที่โปรแกรมจำลองปิดตัวลง หากคุณทำการทดสอบหลายรายการกับรหัสโปรเจ็กต์เดียวกัน การทดสอบแต่ละรายการอาจสร้างข้อมูลที่อาจส่งผลต่อการทดสอบครั้งต่อๆ ไป คุณสามารถใช้วิธีการใดก็ได้ต่อไปนี้เพื่อข้ามลักษณะการทำงานนี้
- ใช้รหัสโปรเจ็กต์ที่ไม่ซ้ำกันสำหรับการทดสอบแต่ละครั้ง โปรดทราบว่าหากเลือกดำเนินการนี้ คุณจะต้องเรียกใช้
initializeTestEnvironmentเป็นส่วนหนึ่งของการทดสอบแต่ละรายการ ระบบจะโหลดกฎโดยอัตโนมัติสำหรับรหัสโปรเจ็กต์เริ่มต้นเท่านั้น - ปรับโครงสร้างการทดสอบเพื่อไม่ให้โต้ตอบกับข้อมูลที่เขียนไว้ก่อนหน้านี้ (เช่น ใช้คอลเล็กชันอื่นสำหรับการทดสอบแต่ละครั้ง)
- ลบข้อมูลทั้งหมดที่เขียนระหว่างการทดสอบ
การตั้งค่าการทดสอบซับซ้อนมาก
เมื่อตั้งค่าการทดสอบ คุณอาจต้องการแก้ไขข้อมูลในลักษณะที่ Cloud Firestore Security Rules ไม่อนุญาตจริงๆ หากกฎทำให้การตั้งค่าการทดสอบซับซ้อน ให้ลองใช้ RulesTestEnvironment.withSecurityRulesDisabled ในขั้นตอนการตั้งค่า เพื่อไม่ให้การอ่านและการเขียนทริกเกอร์ข้อผิดพลาด PERMISSION_DENIED
หลังจากนั้น การทดสอบจะดำเนินการในฐานะผู้ใช้ที่ผ่านการตรวจสอบสิทธิ์หรือไม่ผ่านการตรวจสอบสิทธิ์ได้โดยใช้ RulesTestEnvironment.authenticatedContext และ unauthenticatedContext ตามลำดับ ซึ่งจะช่วยให้คุณตรวจสอบได้ว่า Cloud Firestore Security Rules อนุญาต / ปฏิเสธเคสต่างๆ อย่างถูกต้องหรือไม่