diff --git a/packages/database/src/core/view/EventRegistration.ts b/packages/database/src/core/view/EventRegistration.ts index cd9ff28985a..1a814163e24 100644 --- a/packages/database/src/core/view/EventRegistration.ts +++ b/packages/database/src/core/view/EventRegistration.ts @@ -71,8 +71,9 @@ export class CallbackContext { matches(other: CallbackContext): boolean { return ( this.snapshotCallback === other.snapshotCallback || - (this.snapshotCallback.userCallback === - other.snapshotCallback.userCallback && + (this.snapshotCallback.userCallback !== undefined && + this.snapshotCallback.userCallback === + other.snapshotCallback.userCallback && this.snapshotCallback.context === other.snapshotCallback.context) ); } diff --git a/packages/database/test/exp/integration.test.ts b/packages/database/test/exp/integration.test.ts index 9790c88d24c..c2e276d8794 100644 --- a/packages/database/test/exp/integration.test.ts +++ b/packages/database/test/exp/integration.test.ts @@ -17,6 +17,7 @@ // eslint-disable-next-line import/no-extraneous-dependencies import { initializeApp, deleteApp } from '@firebase/app-exp'; +import { Deferred } from '@firebase/util'; import { expect } from 'chai'; import { @@ -24,8 +25,10 @@ import { getDatabase, goOffline, goOnline, + push, ref, - refFromURL + refFromURL, + runTransaction } from '../../exp/index'; import { onValue, set } from '../../src/exp/Reference_impl'; import { EventAccumulatorFactory } from '../helpers/EventAccumulator'; @@ -150,4 +153,36 @@ describe('Database@exp Tests', () => { expect(() => ref(db)).to.throw('Cannot call ref on a deleted database.'); defaultApp = undefined; }); + + it('Can listen to transaction changes', async () => { + // Repro for https://github.com/firebase/firebase-js-sdk/issues/5195 + let latestValue = 0; + + let deferred = new Deferred(); + + const database = getDatabase(defaultApp); + const counterRef = push(ref(database, 'counter')); + + onValue(counterRef, snap => { + latestValue = snap.val(); + deferred.resolve(); + }); + + async function incrementViaTransaction() { + deferred = new Deferred(); + await runTransaction(counterRef, currentData => { + return currentData + 1; + }); + // Wait for the snapshot listener to fire. They are not invoked inline + // for transactions. + await deferred.promise; + } + + expect(latestValue).to.equal(0); + + await incrementViaTransaction(); + expect(latestValue).to.equal(1); + await incrementViaTransaction(); + expect(latestValue).to.equal(2); + }); }); diff --git a/packages/database/test/transaction.test.ts b/packages/database/test/transaction.test.ts index 530c41361b3..5bf5caabd2b 100644 --- a/packages/database/test/transaction.test.ts +++ b/packages/database/test/transaction.test.ts @@ -1500,4 +1500,34 @@ describe('Transaction Tests', () => { done(); }); }); + + it('Can listen to transaction changes', async () => { + // Repro for https://github.com/firebase/firebase-js-sdk/issues/5195 + let latestValue = 0; + + const ref = getRandomNode() as Reference; + + let deferred = new Deferred(); + ref.on('value', snap => { + latestValue = snap.val() as number; + deferred.resolve(); + }); + + async function incrementViaTransaction() { + deferred = new Deferred(); + await ref.transaction(currentData => { + return (currentData as number) + 1; + }); + // Wait for the snapshot listener to fire. They are not invoked inline + // for transactions. + await deferred.promise; + } + + expect(latestValue).to.equal(0); + + await incrementViaTransaction(); + expect(latestValue).to.equal(1); + await incrementViaTransaction(); + expect(latestValue).to.equal(2); + }); });