Как вызвать функции firebase из модульного теста с использованием эмуляторов Firebase?

# #javascript #firebase-authentication #google-cloud-functions #firebase-tools

Вопрос:

У меня работают эмуляторы базы огня.

Мое приложение может вызвать облачную функцию firebase, которая может создать пользовательское утверждение пользователя, если это разрешено пользователю (в зависимости от значения в базе данных).

Я пытаюсь вызвать эту функцию:

 
import * as firebase from '@firebase/testing';
import * as fs from 'fs';

const app = firebase.initializeTestApp({
  databaseName: 'mydb',
  auth: {
    uid: 'useruid'
  },
});

describe('Firebase Functions', () => {
  beforeEach(async () => {
    await firebase.loadDatabaseRules({
      databaseName: 'mydb',
      rules: fs.readFileSync('database.rules.json', 'utf8'),
    });
  });

  afterAll(async () => {
    await Promise.all(firebase.apps().map((app) => app.delete()));
  });

  const cloudfunction = app.functions().httpsCallable('cloudfunction')

  it('throws error if user is not authenticated', async () => {
    await firebase.assertFail(cloudfunction())
  })
});


 

Это приводит к ошибке:

Ошибка: Ошибка: В ответе на предполетный запрос неверный код состояния HTTP 404

Ответ №1:

На мой взгляд, вам не нужно вызывать firebase из вашего модульного теста, потому что это не ваше дело, правильно ли работает firebase или нет, вам нужно проверить свою бизнес-логику, чтобы это означало, что вы будете издеваться над методом, который вызывает firebase, и проверять ожидаемые возвращаемые значения этого метода, например, вы можете написать 2 случая, когда уведомление будет отправлено без ошибок, и во-вторых, если служба firebase вернет сбой, для этих 2 случаев ваш код должен иметь соответствующее поведение. Тестирование службы firebase будет проводиться командой, работающей на базе firebase

Комментарии:

1. Я пишу интеграционные тесты. Мои другие тесты уже взаимодействуют с базой данных, издевающейся над эмуляторами Firebase, почему бы и не использовать функции? Я тестирую весь поток end2end, например, пользователь может нажать кнопку в пользовательском интерфейсе, которая вызывает функции firebase, которые изменяют данные в базе данных, если у пользователей есть правильные разрешения. Я могу модульно протестировать каждый шаг, но я также хотел бы протестировать все поведение, чтобы убедиться, что между каждым шагом нет ошибок.

2. Просто в любом случае вы можете имитировать метод firebase, я имею в виду, что вы можете протестировать firebase вручную, когда будете создавать приложение, но в процессе разработки я считаю более разумным имитировать и тестировать ваши коды,

3. Даже если вы разработчик firebase, вы должны протестировать firebase изнутри firebase, а из внешнего приложения вы должны просто издеваться и смотреть на все случаи, когда эта служба вернет некоторые сбои или успех, вы должны ожидать, что все случаи

4. В противном случае вы хотите проверить, правильно ли вы обратились к этой службе или нет, но для этой службы есть библиотеки и документация, это непроверяемая часть кода, в модульных тестах и в интеграционных тестах вы можете проверить свою локальную бизнес-логику

5. Я понимаю вашу точку зрения, но это не решает проблему. На данный момент я буду издеваться над своими функциями, но для @firebase/testing не имеет смысла не поддерживать вызов эмуляторов облачных функций, когда это работает для базы данных.

Ответ №2:

Для этого существует тест firebase-функций. Это позволяет вам оборачивать облачные функции и вызывать их напрямую, а также создавать заглушки для обновлений документов. При запуске в контексте эмулятора пакет SDK firebase-admin по-прежнему взаимодействует с эмулятором. Базовая настройка может выглядеть следующим образом (при условии наличия машинописного текста)::

 // functions/src/test/functions.test.ts
import {expect} from "chai";
import "mocha";

import firebaseFunctionTest from "firebase-functions-test";
import * as cf from "../index";

const projectId = "demo-project";
const test = firebaseFunctionTest({
  projectId,
});

after(() => test.cleanup());

describe("cloud functions", () => {
  afterEach(async () => {
    await test.firestore.clearFirestoreData(projectId);
  });

  describe("myFunction", () => {
      const myFunction = test.wrap(cf.myFunction);
      // Create mock data with the admin SDK and test function.
  }
}
 

В вашем package.json вы можете поместить сценарий, подобный.

 "scripts": {
  "test:unit": "mocha -r ts-node/register --timeout 5000 --exit src/**/*.test.ts",
  "test": "npm run build amp;amp; npx firebase -P demo-project emulators:exec 'npm run test:unit'",
  ...
}  
 

Возможно, вы также захотите взглянуть на https://github.com/firebase/quickstart-testing/tree/master/unit-test-cloud-functions
и https://firebase.google.com/docs/functions/unit-testing.

Комментарии:

1. Это предназначено для тестирования облачной функции. Я хочу протестировать свое веб-приложение, которое вызывает эту функцию. Я не могу import * as cf from "../index"; , так как облачная функция объявлена в отдельном проекте.

2. Ладно, я неправильно это понял. Не могли бы вы запустить эмулятор в отдельном проекте и подключить проект, который вы хотите протестировать, к этому эмулятору?

3. Проблема в том, что вы не можете вызвать облачную функцию, запущенную в эмуляторе, из модульного теста с использованием @firebase/testing библиотеки. Я прибегнул к простому издевательству над функцией базы данных в модульном тесте моего приложения