במהלך פיתוח האפליקציה, יכול להיות שתרצו להגביל את הגישה למסד הנתונים של Cloud Firestore. עם זאת, לפני ההשקה, תצטרכו להגדיר אסטרטגיה מורכבת יותר Cloud Firestore Security Rules. באמצעות האמולטור Cloud Firestore, בנוסף ליצירת אב טיפוס ולבדיקה של התכונות וההתנהגות הכלליות של האפליקציה, אפשר לכתוב בדיקות יחידה שבודקות את ההתנהגות של Cloud Firestore Security Rules.
מדריך למתחילים
כדי לנסות כמה תרחישי בדיקה בסיסיים עם כללים פשוטים, אפשר להשתמש בדוגמה להפעלה מהירה.
הסבר על Cloud Firestore Security Rules
כדאי להטמיע Firebase Authentication ו-Cloud Firestore Security Rules לאימות, להרשאה ולאימות נתונים ללא שרת כשמשתמשים בספריות הלקוח לנייד ולאינטרנט.
Cloud Firestore Security Rules כולל שני חלקים:
match
הצהרה שמזהה מסמכים במסד הנתונים.- ביטוי
allow
ששולט בגישה למסמכים האלה.
Firebase Authentication מאמת את פרטי הכניסה של המשתמשים ומספק את הבסיס למערכות גישה מבוססות-משתמשים ומבוססות-תפקידים.
כל בקשה למסד נתונים מCloud Firestoreספריית לקוח לנייד או לאינטרנט נבדקת מול כללי האבטחה לפני קריאה או כתיבה של נתונים. אם הכללים דוחים גישה לאחד מנתיבי המסמכים שצוינו, הבקשה כולה נכשלת.
מידע נוסף על 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
שמתוארת בהמשך, האמולטור יתייחס לכל הפרויקטים כאילו יש להם כללים פתוחים. - רוב ערכות ה-SDK של Firebase פועלות ישירות עם האמולטורים, אבל רק ספריית
@firebase/rules-unit-testing
תומכת ב-mockingauth
בכללי האבטחה, ולכן קל יותר לבצע בדיקות יחידה. בנוסף, הספרייה תומכת בכמה תכונות ספציפיות לאמולטור, כמו מחיקת כל הנתונים, כמו שמופיע בהמשך. - האמולטורים יקבלו גם טוקנים של Firebase Auth מהסביבה הפרודקטיבית שסופקו דרך ערכות SDK של לקוח, ויעריכו את הכללים בהתאם. כך תוכלו לקשר את האפליקציה ישירות לאמולטורים בבדיקות שילוב ובבדיקות ידניות.
הרצת בדיקות יחידה מקומיות
הרצת בדיקות יחידה מקומיות באמצעות JavaScript SDK בגרסה 9
Firebase מפיצה ספרייה לבדיקת יחידות של כללי אבטחה עם גרסה 9 של JavaScript SDK ועם גרסה 8 של SDK. ממשקי ה-API של הספרייה שונים באופן משמעותי. מומלץ להשתמש בספריית הבדיקות v9, שהיא יעילה יותר ודורשת פחות הגדרות כדי להתחבר לאמולטורים, וכך אפשר להימנע בבטחה משימוש לא מכוון במשאבי ייצור. כדי לשמור על תאימות לאחור, אנחנו ממשיכים להציע את ספריית הבדיקות v8.
משתמשים במודול @firebase/rules-unit-testing
כדי ליצור אינטראקציה עם האמולטור שפועל באופן מקומי. אם מופיעות שגיאות של פסק זמן או שגיאות ECONNREFUSED
, צריך לוודא שהאמולטור פועל.
מומלץ מאוד להשתמש בגרסה עדכנית של Node.js כדי שתוכלו להשתמש בסימון async/await
. כמעט כל ההתנהגויות שתרצו לבדוק כוללות פונקציות אסינכרוניות, ומודול הבדיקה מיועד לעבוד עם קוד מבוסס-Promise.
ספריית בדיקות היחידה של כללים בגרסה 9 תמיד מודעת לאמולטורים ולעולם לא נוגעת במשאבי הייצור שלכם.
מייבאים את הספרייה באמצעות הצהרות ייבוא מודולריות של גרסה 9. לדוגמה:
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.
אחרי הייבוא, כדי להטמיע בדיקות יחידה צריך:
- יצירה והגדרה של
RulesTestEnvironment
עם קריאה אלinitializeTestEnvironment
. - הגדרה של נתוני בדיקה בלי להפעיל כללים, באמצעות שיטה נוחה שמאפשרת לעקוף אותם באופן זמני,
RulesTestEnvironment.withSecurityRulesDisabled
. - הגדרה של חבילת בדיקות ושל פעולות לפני ואחרי כל בדיקה עם קריאות לניקוי נתוני הבדיקה והסביבה, כמו
RulesTestEnvironment.cleanup()
אוRulesTestEnvironment.clearFirestore()
. - הטמעה של תרחישי בדיקה שמדמים מצבי אימות באמצעות
RulesTestEnvironment.authenticatedContext
ו-RulesTestEnvironment.unauthenticatedContext
.
שיטות נפוצות ופונקציות בסיסיות
אפשר גם לעיין בשיטות בדיקה ספציפיות לאמולטור ב-SDK בגרסה 9.
initializeTestEnvironment() => RulesTestEnvironment
הפונקציה הזו מאתחלת סביבת בדיקה לבדיקות יחידה של כללים. צריך להפעיל את הפונקציה הזו קודם כדי להגדיר את הבדיקה. כדי שההפעלה תתבצע בהצלחה, האמולטורים צריכים לפעול.
הפונקציה מקבלת אובייקט אופציונלי שמגדיר 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
, שמתנהג כמו משתמש מאומת של Authentication. לבקשות שנוצרו באמצעות ההקשר שהוחזר יצורף טוקן אימות מדומה. אופציונלי: אפשר להעביר אובייקט שמגדיר טענות מותאמות אישית או שינויים במטען הייעודי (payload) של טוקנים לאימות.
משתמשים באובייקט הקשר של הבדיקה שמוחזר בבדיקות כדי לגשת לכל המופעים של האמולטור שהוגדרו, כולל אלה שהוגדרו באמצעות 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(), '/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()
הפעלת פונקציית הגדרת בדיקה עם הקשר שמתנהג כאילו כללי האבטחה מושבתים.
השיטה הזו מקבלת פונקציית קריאה חוזרת, שמקבלת את ההקשר של עקיפת כללי האבטחה ומחזירה אובייקט 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'), { ... });
שיטות ספציפיות לאמולטור
אפשר גם לעיין בשיטות נפוצות לבדיקה ופונקציות עזר ב-SDK בגרסה 9.
RulesTestEnvironment.clearFirestore() => Promise<void>
השיטה הזו מוחקת נתונים במסד הנתונים של Firestore ששייכים ל-projectId
שהוגדר לאמולטור של Firestore.
RulesTestContext.firestore(settings?: Firestore.FirestoreSettings) => Firestore;
השיטה הזו מאחזרת מופע של Firestore עבור הקשר של הבדיקה הזו. אפשר להשתמש במופע של Firebase JS Client SDK שמוחזר עם ממשקי API של Client SDK (מודולריים בגרסה 9 או תואמים בגרסה 9).
הדמיה של הערכות הכללים
האמולטור Cloud Firestore מאפשר לכם לראות את בקשות הלקוח בממשק המשתמש של Emulator Suite, כולל מעקב אחר הערכות של כללי אבטחה ב-Firebase.
פותחים את הכרטיסייה Firestore > בקשות כדי לראות את רצף ההערכה המפורט של כל בקשה.
יצירת דוחות בדיקה
אחרי שמריצים סדרה של בדיקות, אפשר לגשת לדוחות כיסוי של הבדיקות שמראים איך כל אחד מכללי האבטחה הוערך.
כדי לקבל את הדוחות, צריך להריץ שאילתה על נקודת קצה (endpoint) שחשופה באמולטור. כדי להשתמש בגרסה שמתאימה לדפדפן, משתמשים בכתובת ה-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 סיפקנו את ה-method
initializeTestApp()
בספרייהrules-unit-testing
, שמקבלת שדהauth
. ה-handle של Firebase שנוצר באמצעות השיטה הזו יתנהג כאילו האימות שלו בוצע בהצלחה כישות שסיפקתם. אם מעבירים את הערךnull
, המערכת תתייחס למשתמש כאל משתמש לא מאומת (לדוגמה, כלליauth != null
ייכשלו).
פתרון בעיות מוכרות
יכול להיות שתיתקלו בבעיות הידועות הבאות במהלך השימוש באמולטור של Cloud Firestore. כדי לפתור בעיות בהתנהגות לא סדירה, פועלים לפי ההנחיות הבאות. ההערות האלה נכתבו בהתייחס לספריית בדיקות היחידה של כללי האבטחה, אבל הגישות הכלליות רלוונטיות לכל Firebase SDK.
התנהגות הבדיקה לא עקבית
אם הבדיקות עוברות ונכשלות מדי פעם, גם בלי שנעשו שינויים בבדיקות עצמן, יכול להיות שצריך לוודא שהן מסודרות ברצף הנכון.
רוב האינטראקציות עם האמולטור הן אסינכרוניות, לכן חשוב לוודא שכל הקוד האסינכרוני מסודר ברצף הנכון. כדי לתקן את הרצף, אפשר לשרשר הבטחות או להשתמש בסימון 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 מאפשר או חוסם
תרחישים שונים בצורה נכונה.