أثناء إنشاء تطبيقك، قد تحتاج إلى حظر الوصول إلى قاعدة بياناتك Cloud Firestore. ومع ذلك، قبل إطلاق التطبيق، ستحتاج إلى المزيد من الدقة Cloud Firestore Security Rules. باستخدام محاكي Cloud Firestore، يمكنك كتابة اختبارات الوحدة التي تتحقّق من سلوك Cloud Firestore Security Rules، بالإضافة إلى إنشاء نماذج أولية واختبار الميزات والسلوكيات العامة لتطبيقك.
البدء السريع
للاطّلاع على بعض حالات الاختبار الأساسية التي تتضمّن قواعد بسيطة، جرِّب نموذج البدء السريع.
فهم Cloud Firestore Security Rules
Implement Firebase Authentication and Cloud Firestore Security Rules for serverless authentication, authorization, and data validation when you use the mobile and web client libraries.
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كما هو موضّح أدناه، سيتعامل المحاكي مع جميع المشاريع على أنّها تتضمّن قواعد مفتوحة. - على الرغم من أنّ
معظم حِزم Firebase SDK
تعمل مع المحاكيات مباشرةً، لا تدعم مكتبة
@firebase/rules-unit-testingإلا محاكاةauthفي "قواعد الأمان"، ما يسهّل إجراء اختبارات الوحدة بشكل كبير. بالإضافة إلى ذلك، تدعم المكتبة بعض الميزات الخاصة بالمحاكي، مثل محو جميع البيانات، كما هو موضّح أدناه. - ستقبل المحاكيات أيضًا رموز مصادقة Firebase للإنتاج المقدَّمة من خلال حِزم SDK للعميل وتقيِّم القواعد وفقًا لذلك، ما يسمح بربط تطبيقك مباشرةً بالمحاكيات في الاختبارات التكاملية واليدوية.
تشغيل اختبارات الوحدة المحلية
تشغيل اختبارات الوحدة المحلية باستخدام حزمة JavaScript SDK الإصدار 9
توزّع Firebase مكتبة اختبارات الوحدة لقواعد الأمان مع حزمة JavaScript SDK الإصدار 9 وحزمة SDK الإصدار 8. تختلف واجهات برمجة التطبيقات في المكتبة اختلافًا كبيرًا. ننصحك باستخدام مكتبة الاختبارات الإصدار 9، التي تتسم بأنّها أكثر انسيابية وتتطلّب إعدادًا أقل للاتصال بالمحاكيات، وبالتالي تجنُّب استخدام موارد الإنتاج عن طريق الخطأ بأمان. لضمان التوافق مع الإصدارات السابقة، سنواصل إتاحة مكتبة الاختبارات الإصدار 8.
- طُرق الاختبار الشائعة والدوال المساعدة في حزمة SDK الإصدار 9
- طُرق الاختبار الخاصة بالمحاكي في حزمة SDK الإصدار 9
استخدِم الوحدة @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، الذي يتصرف مثل مستخدم مصادقة تم التحقق منه. ستتضمّن الطلبات التي يتم إنشاؤها من خلال السياق الذي تم إرجاعه رمز مصادقة وهميًا. يمكنك اختياريًا تمرير كائن يحدّد المطالبات المخصّصة أو عمليات الإلغاء لبيانات حمولة رمز المصادقة.
استخدِم كائن سياق الاختبار الذي تم إرجاعه في اختباراتك للوصول إلى أيّ من مثيلات المحاكي التي تم إعدادها، بما في ذلك تلك التي تم إعدادها باستخدام 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.
استخدِم كائن سياق الاختبار الذي تم إرجاعه في اختباراتك للوصول إلى أيّ من مثيلات المحاكي التي تم إعدادها، بما في ذلك تلك التي تم إعدادها باستخدام 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()
شغِّل دالة إعداد اختبار بسياق يتصرف كما لو كانت "قواعد الأمان" غير مفعّلة.
تأخذ هذه الطريقة دالة رد اتصال، تأخذ السياق الذي يتجاوز "قواعد الأمان" وتعرض وعدًا. سيتم تدمير السياق بعد حلّ الوعد أو رفضه.
RulesTestEnvironment.cleanup()
تدمّر هذه الطريقة جميع RulesTestContexts التي تم إنشاؤها في بيئة الاختبار وتنظّف الموارد الأساسية، ما يسمح بالخروج بشكل نظيف.
لا تغيّر هذه الطريقة حالة المحاكيات بأي شكل من الأشكال. لإعادة ضبط البيانات بين الاختبارات، استخدِم طريقة محو البيانات الخاصة بمحاكي التطبيق.
assertSucceeds(pr: Promise<any>)) => Promise<any>
هذه دالة مساعدة لحالة الاختبار.
تؤكّد الدالة أنّ الوعد المقدَّم الذي يغلّف عملية المحاكي سيتم حلّه بدون أي انتهاكات لقواعد الأمان.
await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });assertFails(pr: Promise<any>)) => Promise<any>
هذه دالة مساعدة لحالة الاختبار.
تؤكّد الدالة أنّ الوعد المقدَّم الذي يغلّف عملية المحاكي سيتم رفضه بسبب انتهاك لقواعد الأمان.
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 الذي تم إرجاعه مع واجهات برمجة تطبيقات حزمة SDK للعميل (الإصدار 9 النمطي أو الإصدار 9 المتوافق).
عرض عمليات تقييم القواعد
يتيح لك محاكي Cloud Firestore عرض طلبات العميل في واجهة مستخدم مجموعة أدوات المحاكاة، بما في ذلك تتبُّع التقييم لقواعد أمان 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، قد تواجه المشاكل المعروفة التالية. اتّبِع الإرشادات أدناه لتحديد أي سلوك غير منتظم تواجهه وحلّه. تمت كتابة هذه الملاحظات مع وضع مكتبة اختبارات الوحدة لقواعد الأمان في الاعتبار، ولكنّ المناهج العامة تنطبق على أي حزمة 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 تسمح بالحالات المختلفة أو ترفضها
بشكل صحيح.