在测试套件中运行时,云功能中的事务中的数据始终为空

问题描述

我有一个Firebase云功能可以做到这一点:

const admin = require('firebase-admin')
admin.initializeApp()

exports.setSessionState = functions.https.onCall(async (data,context) => {
    const stateId = data.stateId
    const details = data.details
    const stateRef = admin.database().ref(`state/${stateId}`)
    stateRef.transaction((state) => {
        if (state) {
            state.details = details
        }
        return state
    })
})

代码在实际的应用程序中运行良好,并且状态已更新,但是在状态始终为null的测试中运行时,我遇到了问题。 (换句话说,永远不会设置细节。)该测试使用Mocha框架,并且在一个真实的Firebase项目上运行,我看不到这里会有什么不同,但是当从客户端应用程序以及从测试套件中调用它时:

const chai = require('chai')
const assert = chai.assert

const test = require('firebase-functions-test')({
  databaseURL: '<redacted>',storageBucket: '<redacted>',projectId: '<redacted>',},'../service-account-credentials.json')

describe('CFsetSessionState',() => {
  let wrapped
  let cloudFunctions
  let admin

  before(() => {
    cloudFunctions = require('../index')
    admin = require('firebase-admin')
    wrapped = test.wrap(cloudFunctions.CFsetSessionState)
  })

  it('Test setting state',async () => {
    const stateId = 'abc'

    const data = {
      stateId: stateId,details: {
        name: 'New name'
      }
    }

    const context = {
      auth: {
        uid: 123
      }
    }

    const stateRef = admin.database().ref(`state/${stateId}`)

    await stateRef.set({
      name: 'PrevIoUs name',active: true
    })

    await wrapped(data,context)

    const snapshot = await stateRef.once('value')
    const state = snapshot.val()

    // Details do not exist here,why?
    assert.equal(state.details.name,'New name')
  })
})

在测试之后,我将数据库状态保持不变,因此我可以看到状态对象中确实存在数据,但是未设置详细信息。在调用云函数之前和之后进行一些设置和获取数据的实验(使用.once()可以改变行为,使我认为这可能是一些缓存问题,但是这种实验并没有给我任何特别的稳定性结束状态。我不知道等效的本地缓存在云功能中如何工作,它目前显示随机行为。

是什么原因造成的?

解决方法

我还没有尝试过通过测试运行您的Cloud Function,但是很可能是由于您错误地管理Cloud Function的生命周期这一事实造成的。由于它是可调用的,因此您需要通过返回Promise(或所有异步工作完成时的值)来终止它。文档中的更多详细信息herehere

因此,您应该按照以下方式调整CF:

exports.setSessionState = functions.https.onCall(async (data,context) => {
    const stateId = data.stateId
    const details = data.details
    const stateRef = admin.database().ref(`state/${stateId}`)
    return stateRef.transaction((state) => {   // Note the return here
        if (state) {
            state.details = details
        }
        return state
    })
})

我们将返回Promise返回的Transaction

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...