Skip to content

Commit ea25b2e

Browse files
Fix transaction interference in v9 (#5205)
1 parent bd50d83 commit ea25b2e

File tree

3 files changed

+69
-3
lines changed

3 files changed

+69
-3
lines changed

packages/database/src/core/view/EventRegistration.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,9 @@ export class CallbackContext {
7171
matches(other: CallbackContext): boolean {
7272
return (
7373
this.snapshotCallback === other.snapshotCallback ||
74-
(this.snapshotCallback.userCallback ===
75-
other.snapshotCallback.userCallback &&
74+
(this.snapshotCallback.userCallback !== undefined &&
75+
this.snapshotCallback.userCallback ===
76+
other.snapshotCallback.userCallback &&
7677
this.snapshotCallback.context === other.snapshotCallback.context)
7778
);
7879
}

packages/database/test/exp/integration.test.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,18 @@
1717

1818
// eslint-disable-next-line import/no-extraneous-dependencies
1919
import { initializeApp, deleteApp } from '@firebase/app-exp';
20+
import { Deferred } from '@firebase/util';
2021
import { expect } from 'chai';
2122

2223
import {
2324
get,
2425
getDatabase,
2526
goOffline,
2627
goOnline,
28+
push,
2729
ref,
28-
refFromURL
30+
refFromURL,
31+
runTransaction
2932
} from '../../exp/index';
3033
import { onValue, set } from '../../src/exp/Reference_impl';
3134
import { EventAccumulatorFactory } from '../helpers/EventAccumulator';
@@ -150,4 +153,36 @@ describe('Database@exp Tests', () => {
150153
expect(() => ref(db)).to.throw('Cannot call ref on a deleted database.');
151154
defaultApp = undefined;
152155
});
156+
157+
it('Can listen to transaction changes', async () => {
158+
// Repro for https://github.com/firebase/firebase-js-sdk/issues/5195
159+
let latestValue = 0;
160+
161+
let deferred = new Deferred<void>();
162+
163+
const database = getDatabase(defaultApp);
164+
const counterRef = push(ref(database, 'counter'));
165+
166+
onValue(counterRef, snap => {
167+
latestValue = snap.val();
168+
deferred.resolve();
169+
});
170+
171+
async function incrementViaTransaction() {
172+
deferred = new Deferred<void>();
173+
await runTransaction(counterRef, currentData => {
174+
return currentData + 1;
175+
});
176+
// Wait for the snapshot listener to fire. They are not invoked inline
177+
// for transactions.
178+
await deferred.promise;
179+
}
180+
181+
expect(latestValue).to.equal(0);
182+
183+
await incrementViaTransaction();
184+
expect(latestValue).to.equal(1);
185+
await incrementViaTransaction();
186+
expect(latestValue).to.equal(2);
187+
});
153188
});

packages/database/test/transaction.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1500,4 +1500,34 @@ describe('Transaction Tests', () => {
15001500
done();
15011501
});
15021502
});
1503+
1504+
it('Can listen to transaction changes', async () => {
1505+
// Repro for https://github.com/firebase/firebase-js-sdk/issues/5195
1506+
let latestValue = 0;
1507+
1508+
const ref = getRandomNode() as Reference;
1509+
1510+
let deferred = new Deferred<void>();
1511+
ref.on('value', snap => {
1512+
latestValue = snap.val() as number;
1513+
deferred.resolve();
1514+
});
1515+
1516+
async function incrementViaTransaction() {
1517+
deferred = new Deferred<void>();
1518+
await ref.transaction(currentData => {
1519+
return (currentData as number) + 1;
1520+
});
1521+
// Wait for the snapshot listener to fire. They are not invoked inline
1522+
// for transactions.
1523+
await deferred.promise;
1524+
}
1525+
1526+
expect(latestValue).to.equal(0);
1527+
1528+
await incrementViaTransaction();
1529+
expect(latestValue).to.equal(1);
1530+
await incrementViaTransaction();
1531+
expect(latestValue).to.equal(2);
1532+
});
15031533
});

0 commit comments

Comments
 (0)