Создавайте модульные тесты

Firebase Local Emulator Suite упрощает полную проверку функций и поведения вашего приложения. Это также отличный инструмент для проверки ваших конфигураций правил безопасности Firebase. Используйте эмуляторы Firebase для запуска и автоматизации модульных тестов в локальной среде. Методы, описанные в этом документе, должны помочь вам при создании и автоматизации модульных тестов для вашего приложения, которые проверяют ваши правила.

Если вы еще этого не сделали, настройте эмуляторы Firebase .

Перед запуском эмулятора

Прежде чем начать использовать эмулятор, имейте в виду следующее:

  • Сначала эмулятор загрузит правила, указанные в поле firestore.rules или 'storage.rules' вашего файла firebase.json . Если файл не существует и вы не используете метод loadFirestoreRules или loadStorageRules, как описано ниже, эмулятор рассматривает все проекты как имеющие открытые правила.
  • Хотя большинство Firebase SDK работают с эмуляторами напрямую, только библиотека @firebase/rules-unit-testing поддерживает имитацию auth в правилах безопасности, что значительно упрощает модульные тесты. Кроме того, библиотека поддерживает несколько специфичных для эмулятора функций, таких как очистка всех данных, как указано ниже.
  • Эмуляторы также будут принимать рабочие токены Firebase Auth, предоставленные через клиентские SDK, и соответствующим образом оценивать правила, что позволяет напрямую подключать ваше приложение к эмуляторам при интеграции и ручных тестах.

Различия между эмуляторами баз данных и производством

  • Вам не нужно явно создавать экземпляр базы данных. Эмулятор автоматически создаст любой доступный экземпляр базы данных.
  • Каждая новая база данных запускается с закрытыми правилами, поэтому пользователи без прав администратора не смогут читать или писать.
  • Каждая эмулируемая база данных применяет ограничения и квоты плана Spark (в частности, это ограничивает каждый экземпляр до 100 одновременных подключений).
  • Любая база данных примет строку "owner" в качестве токена авторизации администратора.
  • Эмуляторы в настоящее время не взаимодействуют с другими продуктами Firebase. Примечательно, что обычный поток аутентификации Firebase не работает. Вместо этого вы можете использовать метод initializeTestApp() в библиотеке rules-unit-testing , который принимает поле auth . Объект Firebase, созданный с помощью этого метода, ведет себя так, как если бы он успешно прошел аутентификацию как любой предоставленный вами объект. Если вы передадите null , он будет вести себя как пользователь, не прошедший проверку подлинности (например, правила auth != null не пройдут).

Взаимодействие с эмулятором базы данных реального времени

Экземпляр рабочей базы данных Firebase Realtime доступен на поддомене firebaseio.com , и вы можете получить доступ к API REST следующим образом:

https://<database_name>.firebaseio.com/path/to/my/data.json

Эмулятор работает локально и доступен по адресу localhost:9000 . Чтобы взаимодействовать с конкретным экземпляром базы данных, вам нужно будет использовать параметр запроса ns , чтобы указать имя базы данных.

http://localhost:9000/path/to/my/data.json?ns=<database_name>

Запускайте локальные модульные тесты с помощью JavaScript SDK версии 9.

Firebase распространяет библиотеку модульного тестирования правил безопасности как с SDK JavaScript версии 9, так и с SDK версии 8. API-интерфейсы библиотек существенно отличаются. Мы рекомендуем тестовую библиотеку v9, которая более оптимизирована и требует меньше настроек для подключения к эмуляторам и, таким образом, безопасно предотвращает случайное использование производственных ресурсов. Для обратной совместимости мы продолжаем делать доступной библиотеку тестирования v8 .

Используйте модуль @firebase/rules-unit-testing для взаимодействия с эмулятором, работающим локально. Если вы получаете тайм-ауты или ошибки ECONNREFUSED , дважды проверьте, действительно ли работает эмулятор.

Мы настоятельно рекомендуем использовать последнюю версию Node.js, чтобы вы могли использовать нотацию async/await . Почти все поведение, которое вы, возможно, захотите протестировать, связано с асинхронными функциями, а модуль тестирования предназначен для работы с кодом на основе Promise.

Библиотека модульного тестирования правил версии 9 всегда осведомлена об эмуляторах и никогда не затрагивает ваши производственные ресурсы.

Вы импортируете библиотеку, используя модульные операторы импорта v9. Например:

import {
  assertFails,
  assertSucceeds,
  initializeTestEnvironment,
  RulesTestEnvironment,
} 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 .

Общие методы и служебные функции

Также см. методы тестирования для конкретных эмуляторов с использованием модульного API .

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(), '/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()

Запустите функцию настройки теста с контекстом, который ведет себя так, как если бы правила безопасности были отключены.

Этот метод принимает функцию обратного вызова, которая принимает контекст обхода правил безопасности и возвращает обещание. Контекст будет уничтожен, как только обещание будет разрешено/отклонено.

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'), { ... });

Методы, специфичные для эмулятора

См. также общие методы тестирования и служебные функции, использующие модульный API .

Облако Firestore

Облако Firestore

RulesTestEnvironment.clearFirestore() => Promise<void>

Этот метод очищает данные в базе данных Firestore, принадлежащие projectId , настроенному для эмулятора Firestore.

RulesTestContext.firestore(settings?: Firestore.FirestoreSettings) => Firestore;

Этот метод получает экземпляр Firestore для этого тестового контекста. Возвращенный экземпляр Firebase JS Client SDK можно использовать с клиентскими API SDK (модульным или совместимым с v9).

База данных реального времени

База данных реального времени

RulesTestEnvironment.clearDatabase() => Promise<void>

Этот метод очищает данные в базе данных реального времени, которые принадлежат projectId , настроенному для эмулятора базы данных реального времени.

RulesTestContext.database(databaseURL?: Firestore.FirestoreSettings) => Firestore;

Получите экземпляр базы данных реального времени для этого тестового контекста. Возвращенный экземпляр Firebase JS Client SDK можно использовать с клиентскими API SDK (модульными или с именами, версии 9 или выше). Метод принимает URL-адрес экземпляра базы данных реального времени. Если указано, возвращает экземпляр эмулируемой версии пространства имен с параметрами, извлеченными из URL-адреса.

Облачное хранилище

Облачное хранилище

RulesTestEnvironment.clearStorage() => Promise<void>

Этот метод очищает объекты и метаданные в сегментах хранилища, принадлежащих projectId , настроенному для эмулятора облачного хранилища.

RulesTestContext.storage(bucketUrl?: string) => Firebase Storage;

Этот метод возвращает экземпляр хранилища, настроенный для подключения к эмулятору. Метод принимает URL-адрес gs:// для корзины хранилища Firebase для тестирования. Если указано, возвращает экземпляр хранилища для эмулированной версии имени корзины.

Запускайте локальные модульные тесты с помощью пакета SDK для JavaScript версии 8.

Выберите продукт, чтобы увидеть методы, используемые Firebase Test SDK для взаимодействия с эмулятором.

Облако Firestore

initializeTestApp({ projectId: string, auth: Object }) => FirebaseApp

Этот метод возвращает инициализированное приложение Firebase, соответствующее идентификатору проекта и переменной авторизации, указанным в параметрах. Используйте это, чтобы создать приложение, аутентифицированное как конкретный пользователь, для использования в тестах.

firebase.initializeTestApp({
  projectId: "my-test-project",
  auth: { uid: "alice", email: "alice@example.com" }
});

initializeAdminApp({ projectId: string }) => FirebaseApp

Этот метод возвращает инициализированное приложение администратора Firebase. Это приложение обходит правила безопасности при выполнении операций чтения и записи. Используйте это, чтобы создать приложение, аутентифицированное как администратор, чтобы установить состояние для тестов.

firebase.initializeAdminApp({ projectId: "my-test-project" });
    

apps() => [FirebaseApp] Этот метод возвращает все текущие инициализированные тестовые и административные приложения. Используйте это для очистки приложений между тестами или после них.

Promise.all(firebase.apps().map(app => app.delete()))

loadFirestoreRules({ projectId: string, rules: Object }) => Promise

Этот метод отправляет правила в локально работающую базу данных. Он принимает объект, определяющий правила в виде строки. Используйте этот метод для установки правил вашей базы данных.

firebase.loadFirestoreRules({
  projectId: "my-test-project",
  rules: fs.readFileSync("/path/to/firestore.rules", "utf8")
});
    

assertFails(pr: Promise) => Promise

Этот метод возвращает обещание, которое отклоняется, если ввод выполнен успешно, или успешно, если ввод отклонен. Используйте это, чтобы утверждать, если чтение или запись базы данных завершаются ошибкой.

firebase.assertFails(app.firestore().collection("private").doc("super-secret-document").get());
    

assertSucceeds(pr: Promise) => Promise

Этот метод возвращает обещание, которое успешно выполнено, если ввод выполнен успешно, и отклоняется, если ввод отклонен. Используйте это, чтобы подтвердить успешность чтения или записи базы данных.

firebase.assertSucceeds(app.firestore().collection("public").doc("test-document").get());
    

clearFirestoreData({ projectId: string }) => Promise

Этот метод очищает все данные, связанные с конкретным проектом в локально работающем экземпляре Firestore. Используйте этот метод для очистки после тестов.

firebase.clearFirestoreData({
  projectId: "my-test-project"
});
   

База данных реального времени

База данных реального времени

initializeTestApp({ databaseName: string, auth: Object }) => FirebaseApp

Используйте это, чтобы создать приложение, аутентифицированное как конкретный пользователь, для использования в тестах.

Возвращает инициализированное приложение firebase, соответствующее имени базы данных и переопределению переменной аутентификации, указанным в параметрах.

firebase.initializeTestApp({
  databaseName: "my-database",
  auth: { uid: "alice" }
});

initializeAdminApp({ databaseName: string }) => FirebaseApp

Используйте это, чтобы создать приложение, прошедшее проверку подлинности в качестве администратора, чтобы настроить состояние для тестов.

Возвращает инициализированное приложение firebase администратора, соответствующее имени базы данных, указанному в параметрах. Это приложение обходит правила безопасности при чтении и записи в базу данных.

firebase.initializeAdminApp({ databaseName: "my-database" });

loadDatabaseRules({ databaseName: string, rules: Object }) => Promise

Используйте это, чтобы установить правила вашей базы данных.

Отправляет правила в локально работающую базу данных. Принимает объект параметров, который указывает ваше «databaseName» и ваши «правила» в виде строк.

firebase
      .loadDatabaseRules({
        databaseName: "my-database",
        rules: "{'rules': {'.read': false, '.write': false}}"
      });

apps() => [FirebaseApp]

Возвращает все текущие инициализированные тестовые и административные приложения.

Используйте это для очистки приложений между тестами или после них (обратите внимание, что инициализированные приложения с активными слушателями предотвращают выход JavaScript):

 Promise.all(firebase.apps().map(app => app.delete()))

assertFails(pr: Promise) => Promise

Возвращает обещание, которое отклоняется, если ввод выполнен успешно, и завершается успешно, если ввод отклонен.

Используйте это, чтобы утверждать, что чтение или запись базы данных не удалась:

firebase.assertFails(app.database().ref("secret").once("value"));

assertSucceeds(pr: Promise) => Promise

Возвращает обещание, которое выполняется, если ввод выполнен успешно, и отклоняется, если ввод отклонен.

Используйте это, чтобы подтвердить успешность чтения или записи базы данных:

firebase.assertSucceeds(app.database().ref("public").once("value"));

Облачное хранилище

Облачное хранилище

initializeTestApp({ storageBucket: string, auth: Object }) => FirebaseApp

Используйте это, чтобы создать приложение, аутентифицированное как конкретный пользователь, для использования в тестах.

Возвращает инициализированное приложение firebase, соответствующее имени корзины хранилища и переопределению переменной аутентификации, указанным в параметрах.

firebase.initializeTestApp({
  storageBucket: "my-bucket",
  auth: { uid: "alice" }
});

initializeAdminApp({ storageBucket: string }) => FirebaseApp

Используйте это, чтобы создать приложение, прошедшее проверку подлинности в качестве администратора, чтобы настроить состояние для тестов.

Возвращает инициализированное приложение firebase администратора, соответствующее имени сегмента хранилища, указанному в параметрах. Это приложение обходит правила безопасности при чтении и записи в корзину.

firebase.initializeAdminApp({ storageBucket: "my-bucket" });

loadStorageRules({ storageBucket: string, rules: Object }) => Promise

Используйте это, чтобы установить правила вашего сегмента хранилища.

Отправляет правила в сегменты локально управляемого хранилища. Принимает объект параметров, который указывает ваш «storageBucket» и ваши «правила» в виде строк.

firebase
      .loadStorageRules({
        storageBucket: "my-bucket",
        rules: fs.readFileSync("/path/to/storage.rules", "utf8")
      });

apps() => [FirebaseApp]

Возвращает все текущие инициализированные тестовые и административные приложения.

Используйте это для очистки приложений между тестами или после них (обратите внимание, что инициализированные приложения с активными слушателями предотвращают выход JavaScript):

 Promise.all(firebase.apps().map(app => app.delete()))

assertFails(pr: Promise) => Promise

Возвращает обещание, которое отклоняется, если ввод выполнен успешно, и завершается успешно, если ввод отклонен.

Используйте это, чтобы утверждать, что чтение или запись сегмента хранилища не удалась:

firebase.assertFails(app.storage().ref("letters/private.doc").getMetadata());

assertSucceeds(pr: Promise) => Promise

Возвращает обещание, которое выполняется, если ввод выполнен успешно, и отклоняется, если ввод отклонен.

Используйте это, чтобы утверждать, что чтение или запись сегмента хранилища выполнены успешно:

firebase.assertFails(app.storage().ref("images/cat.png").getMetadata());

API библиотеки RUT для JS SDK v8

Выберите продукт, чтобы увидеть методы, используемые Firebase Test SDK для взаимодействия с эмулятором.

Облако Firestore

Облако Firestore

initializeTestApp({ projectId: string, auth: Object }) => FirebaseApp

Этот метод возвращает инициализированное приложение Firebase, соответствующее идентификатору проекта и переменной авторизации, указанным в параметрах. Используйте это, чтобы создать приложение, аутентифицированное как конкретный пользователь, для использования в тестах.

firebase.initializeTestApp({
  projectId: "my-test-project",
  auth: { uid: "alice", email: "alice@example.com" }
});

initializeAdminApp({ projectId: string }) => FirebaseApp

Этот метод возвращает инициализированное приложение администратора Firebase. Это приложение обходит правила безопасности при выполнении операций чтения и записи. Используйте это, чтобы создать приложение, аутентифицированное как администратор, чтобы установить состояние для тестов.

firebase.initializeAdminApp({ projectId: "my-test-project" });
    

apps() => [FirebaseApp] Этот метод возвращает все текущие инициализированные тестовые и административные приложения. Используйте это для очистки приложений между тестами или после них.

Promise.all(firebase.apps().map(app => app.delete()))

loadFirestoreRules({ projectId: string, rules: Object }) => Promise

Этот метод отправляет правила в локально работающую базу данных. Он принимает объект, определяющий правила в виде строки. Используйте этот метод для установки правил вашей базы данных.

firebase.loadFirestoreRules({
  projectId: "my-test-project",
  rules: fs.readFileSync("/path/to/firestore.rules", "utf8")
});
    

assertFails(pr: Promise) => Promise

Этот метод возвращает обещание, которое отклоняется, если ввод выполнен успешно, или успешно, если ввод отклонен. Используйте это, чтобы утверждать, если чтение или запись базы данных завершаются ошибкой.

firebase.assertFails(app.firestore().collection("private").doc("super-secret-document").get());
    

assertSucceeds(pr: Promise) => Promise

Этот метод возвращает обещание, которое успешно выполнено, если ввод выполнен успешно, и отклоняется, если ввод отклонен. Используйте это, чтобы подтвердить успешность чтения или записи базы данных.

firebase.assertSucceeds(app.firestore().collection("public").doc("test-document").get());
    

clearFirestoreData({ projectId: string }) => Promise

Этот метод очищает все данные, связанные с конкретным проектом в локально работающем экземпляре Firestore. Используйте этот метод для очистки после тестов.

firebase.clearFirestoreData({
  projectId: "my-test-project"
});
   

База данных реального времени

База данных реального времени

initializeTestApp({ databaseName: string, auth: Object }) => FirebaseApp

Используйте это, чтобы создать приложение, аутентифицированное как конкретный пользователь, для использования в тестах.

Возвращает инициализированное приложение firebase, соответствующее имени базы данных и переопределению переменной аутентификации, указанным в параметрах.

firebase.initializeTestApp({
  databaseName: "my-database",
  auth: { uid: "alice" }
});

initializeAdminApp({ databaseName: string }) => FirebaseApp

Используйте это, чтобы создать приложение, прошедшее проверку подлинности в качестве администратора, чтобы настроить состояние для тестов.

Возвращает инициализированное приложение firebase администратора, соответствующее имени базы данных, указанному в параметрах. Это приложение обходит правила безопасности при чтении и записи в базу данных.

firebase.initializeAdminApp({ databaseName: "my-database" });

loadDatabaseRules({ databaseName: string, rules: Object }) => Promise

Используйте это, чтобы установить правила вашей базы данных.

Отправляет правила в локально работающую базу данных. Принимает объект параметров, который указывает ваше «databaseName» и ваши «правила» в виде строк.

firebase
      .loadDatabaseRules({
        databaseName: "my-database",
        rules: "{'rules': {'.read': false, '.write': false}}"
      });

apps() => [FirebaseApp]

Возвращает все текущие инициализированные тестовые и административные приложения.

Используйте это для очистки приложений между тестами или после них (обратите внимание, что инициализированные приложения с активными слушателями предотвращают выход JavaScript):

 Promise.all(firebase.apps().map(app => app.delete()))

assertFails(pr: Promise) => Promise

Возвращает обещание, которое отклоняется, если ввод выполнен успешно, и завершается успешно, если ввод отклонен.

Используйте это, чтобы утверждать, что чтение или запись базы данных не удалась:

firebase.assertFails(app.database().ref("secret").once("value"));

assertSucceeds(pr: Promise) => Promise

Возвращает обещание, которое выполняется, если ввод выполнен успешно, и отклоняется, если ввод отклонен.

Используйте это, чтобы подтвердить успешность чтения или записи базы данных:

firebase.assertSucceeds(app.database().ref("public").once("value"));

Облачное хранилище

Облачное хранилище

initializeTestApp({ storageBucket: string, auth: Object }) => FirebaseApp

Используйте это, чтобы создать приложение, аутентифицированное как конкретный пользователь, для использования в тестах.

Возвращает инициализированное приложение firebase, соответствующее имени корзины хранилища и переопределению переменной аутентификации, указанным в параметрах.

firebase.initializeTestApp({
  storageBucket: "my-bucket",
  auth: { uid: "alice" }
});

initializeAdminApp({ storageBucket: string }) => FirebaseApp

Используйте это, чтобы создать приложение, прошедшее проверку подлинности в качестве администратора, чтобы настроить состояние для тестов.

Возвращает инициализированное приложение firebase администратора, соответствующее имени сегмента хранилища, указанному в параметрах. Это приложение обходит правила безопасности при чтении и записи в корзину.

firebase.initializeAdminApp({ storageBucket: "my-bucket" });

loadStorageRules({ storageBucket: string, rules: Object }) => Promise

Используйте это, чтобы установить правила вашего сегмента хранилища.

Отправляет правила в сегменты локально управляемого хранилища. Принимает объект параметров, который указывает ваш «storageBucket» и ваши «правила» в виде строк.

firebase
      .loadStorageRules({
        storageBucket: "my-bucket",
        rules: fs.readFileSync("/path/to/storage.rules", "utf8")
      });

apps() => [FirebaseApp]

Возвращает все текущие инициализированные тестовые и административные приложения.

Используйте это для очистки приложений между тестами или после них (обратите внимание, что инициализированные приложения с активными слушателями предотвращают выход JavaScript):

 Promise.all(firebase.apps().map(app => app.delete()))

assertFails(pr: Promise) => Promise

Возвращает обещание, которое отклоняется, если ввод выполнен успешно, и завершается успешно, если ввод отклонен.

Используйте это, чтобы утверждать, что чтение или запись сегмента хранилища не удалась:

firebase.assertFails(app.storage().ref("letters/private.doc").getMetadata());

assertSucceeds(pr: Promise) => Promise

Возвращает обещание, которое выполняется, если ввод выполнен успешно, и отклоняется, если ввод отклонен.

Используйте это, чтобы утверждать, что чтение или запись сегмента хранилища выполнены успешно:

firebase.assertFails(app.storage().ref("images/cat.png").getMetadata());