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

Wrapped Gen 2 Firestore Trigger receives incorrect data

Open MichaelJBerk opened this issue 1 year ago • 6 comments

Version info

firebase-functions-test: 5.0.1

firebase-functions: 3.3.0

firebase-admin: 12.2.0

Test case

When calling a wrapped function set to a Gen 2 Firestore trigger, the function will receive the value for the exampleDocumentSnapshot, rather than the actual value provided by the test:

/// Test Code
test("Write Item V2", async () => {
	const db = getFirestore()
	const path = `items/${generateTempId()}`
	const data = {name: "MyTest"}
	
	await db.doc(path).set(data)
	testEnv.firestore.exampleDocumentSnapshotChange()
	const wrapped = testEnv.wrap(myOnWriteTrigger)
	const beforeSnap = testEnv.firestore.makeDocumentSnapshot({name:'blah'}, path)
	const afterSnap = testEnv.firestore.makeDocumentSnapshot(data, path)
	const change = testEnv.makeChange(beforeSnap, afterSnap)
	
	await wrapped(change)
})

/// Cloud Function
export const myOnWriteTrigger = onDocumentWritten("items/{itemid}", async (event) => {
	///This will output "{ aString: 'foo', anObject: { a: 'qux', b: 'faz' }, aNumber: 7 }"
	console.log(event.data.after.data())
	///...
}


Steps to reproduce

I've created a sample project with the issue at https://github.com/MichaelJBerk/FirestoreFunctionsTriggerBug. View the readme for details

Expected behavior

event.data.after.data() should contain the data provided in the test

Actual behavior

event.data.after.data() contains the exampleDocumentSnapshot value ({ aString: 'foo', anObject: { a: 'qux', b: 'faz' }, aNumber: 7 })

MichaelJBerk avatar Jul 08 '24 20:07 MichaelJBerk

Lol I thought I was just doing something wrong.

anonimitoraf avatar Jul 09 '24 00:07 anonimitoraf

The Google Cloud CLI is defaulting to v2 as of now. Let's fix testing v2 functions)

RohovDmytro avatar Sep 17 '24 15:09 RohovDmytro

Hi @MichaelJBerk

Thanks for creating this issue! I've managed to reproduce this, and I will soon be looking further into it.

By any chance, did you ever figure this out?

CorieW avatar May 14 '25 23:05 CorieW

In the end I don't think I was able to, though it has been a while since I last played with Firebase

MichaelJBerk avatar May 19 '25 22:05 MichaelJBerk

Damn, I wasn't understand why the hell I was receiving wrong data. Then. This.

alexandercerutti avatar Sep 12 '25 14:09 alexandercerutti

Also ran into this. The trick is that the change must be added to the data prop since the call signature between v1 and v2 are not equal.

That's also part of the example in the readme, but the types don't complain if it is used like the v1 version:

Image

I found it from this line where data is extracted: https://github.com/firebase/firebase-functions-test/blob/fb6cd5ce738231306f9184430f051286f6869dba/src/cloudevent/mocks/firestore/helpers.ts#L35


v1; data and context are passed separately: https://github.com/firebase/firebase-functions-test/blob/fb6cd5ce738231306f9184430f051286f6869dba/src/v1.ts#L108-L111

v2; the whole event is passed that includes data and context: https://github.com/firebase/firebase-functions-test/blob/fb6cd5ce738231306f9184430f051286f6869dba/src/v2.ts#L33-L35

So this works:

/// Test Code
test("Write Item V2", async () => {
	// ...
	const change = testEnv.makeChange(beforeSnap, afterSnap)
	
	// pass in the change in the data prop
	await wrapped({ data: change })
})

/// ...

dhenneke avatar Nov 20 '25 20:11 dhenneke