firebase-functions-test icon indicating copy to clipboard operation
firebase-functions-test copied to clipboard

Testing onWrite cloud function does not correctly return `ref.parent`

Open ospfranco opened this issue 3 years ago • 1 comments

Version info

firebase-functions-test: 0.2.3

firebase-functions: 3.12.0

firebase-admin: 9.4.1

Test case

Assume the following firebase function that triggers on a sub-field change:

functions.database.ref(`/users/{uid}/${fieldname}`).onWrite((change, context) => {
    const uid = context.params.uid
    const value = change.after.val()

    if (!change.before.exists() && !value) {
      return null
    }

    return change.after.ref.parent?.once('value').then(snapshot => {
      const user = snapshot.val()
      const email = user?.providerData?.email

      if (typeof email !== 'string') {
        return null
      }

      return createOrUpdateContact(uid, user)
    })
  })

Now to write a unit test for such function:

it('correctly updates flag at mailer', async (done) => {
    const userId = chance.guid();
    const userEmail = chance.email()
    const userAfter = {
      uid: userId,
      subscription: true,
      providerData: {
        email: userEmail
      }
    };

    const beforeSnap = functionsMock.database.makeDataSnapshot(
      {
        uid: userId,
        subscription: false,
        providerData: {
          email: userEmail
        }
      },
      `/users/${userId}`
    );

    const afterSnap = functionsMock.database.makeDataSnapshot(
      true,
      `/users/${userId}/subscription`
    );

    const wrapped = functionsMock.wrap(update_subscription_flag);

    const change = functionsMock.makeChange(beforeSnap, afterSnap);

    const res = await wrapped(change, {
      params: {
        uid: userId
      }
    });

    expect(res).toBeTruthy()

    expect(createOrUpdateContact).toHaveBeenCalledWith(userId, userAfter)


    done()
  })

Steps to reproduce

So, the exact problem occurs on this line:

return change.after.ref.parent?.once('value').then(snapshot => {

Even though change.after does correctly reference only the field that changed, when trying to get it's parent null is returned instead of the value in the beforeSnap

Expected behavior

The correct parent ref is detected or at least there is a way to set it so the real firebase behavior can be replicated

Actual behavior

The ref's parent is set to null, which diverges from real firebase behavior

ospfranco avatar Dec 04 '20 11:12 ospfranco

  • 1 I'm having the same issue.

sTranaeus avatar Oct 19 '22 15:10 sTranaeus