Skip to content

Commit 6ecf073

Browse files
committed
fix: parsing old_value onDocumentDeleted
1 parent 2c7d129 commit 6ecf073

File tree

3 files changed

+70
-3
lines changed

3 files changed

+70
-3
lines changed

lib/src/firestore/firestore_namespace.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -388,8 +388,7 @@ class FirestoreNamespace extends FunctionsNamespace {
388388
);
389389

390390
if (parsed != null) {
391-
// For delete events, the document state before deletion is in 'value'
392-
snapshot = parsed['value'];
391+
snapshot = parsed['old_value'];
393392
}
394393
}
395394
} catch (_) {

test/e2e/tests/firestore_tests.dart

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,38 @@ void runFirestoreTests(
9898
await client.deleteDocument('users/$testUserId');
9999
print('✓ Document deleted successfully');
100100

101-
// Wait for trigger
101+
// Wait for trigger to fire and write result
102102
await Future<void>.delayed(const Duration(seconds: 2));
103103

104104
// Verify document no longer exists
105105
final doc = await client.getDocument('users/$testUserId');
106106
expect(doc, isNull, reason: 'Document should not exist after deletion');
107107
print('✓ Document deletion verified');
108+
109+
// Poll for the side-channel result doc written by the handler
110+
// (up to 5 attempts × 500ms = 2.5s extra headroom)
111+
Map<String, dynamic>? result;
112+
for (var i = 0; i < 5; i++) {
113+
result =
114+
await client.getDocument('trigger_results/deleted_$testUserId');
115+
if (result != null) break;
116+
await Future<void>.delayed(const Duration(milliseconds: 500));
117+
}
118+
119+
expect(
120+
result,
121+
isNotNull,
122+
reason: 'trigger_results doc should have been written by handler',
123+
);
124+
expect(
125+
result!['fields']['hasData']['booleanValue'],
126+
isTrue,
127+
reason: 'event.data should be non-null for delete events',
128+
);
129+
expect(result['fields']['name']['stringValue'], 'To Be Deleted');
130+
expect(result['fields']['email']['stringValue'], 'delete@example.com');
131+
expect(result['fields']['finalMessage']['stringValue'], 'goodbye');
132+
print('✓ Handler received correct pre-deletion document data');
108133
});
109134

110135
test('onDocumentWritten fires for all operations', () async {
@@ -222,6 +247,12 @@ void runFirestoreTests(
222247
} catch (e) {
223248
// Ignore errors during cleanup
224249
}
250+
// Clean up side-channel result doc written by the onDocumentDeleted handler
251+
try {
252+
await client.deleteDocument('trigger_results/deleted_$testUserId');
253+
} catch (e) {
254+
// Ignore errors during cleanup
255+
}
225256
});
226257
});
227258
}

test/fixtures/dart_reference/lib/main.dart

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import 'dart:convert';
2+
import 'dart:io';
3+
14
import 'package:firebase_functions/firebase_functions.dart';
25

36
// =============================================================================
@@ -184,6 +187,40 @@ void main(List<String> args) async {
184187
final data = event.data?.data();
185188
print('Document deleted: users/${event.params['userId']}');
186189
print(' Final data: $data');
190+
191+
// write result to Firestore so the e2e test can assert on
192+
// what the handler actually received (exposes the old_value/value).
193+
final userId = event.params['userId'] as String;
194+
final firestoreHost =
195+
Platform.environment['FIRESTORE_EMULATOR_HOST'] ?? '127.0.0.1:8080';
196+
final parts = firestoreHost.split(':');
197+
final host = parts[0];
198+
final port = int.tryParse(parts.length > 1 ? parts[1] : '8080') ?? 8080;
199+
200+
final resultFields = <String, dynamic>{
201+
'hasData': {'booleanValue': data != null},
202+
'name': {'stringValue': data?['name']?.toString() ?? ''},
203+
'email': {'stringValue': data?['email']?.toString() ?? ''},
204+
'finalMessage': {
205+
'stringValue': data?['finalMessage']?.toString() ?? '',
206+
},
207+
};
208+
209+
try {
210+
final httpClient = HttpClient();
211+
final req = await httpClient.post(
212+
host,
213+
port,
214+
'/v1/projects/demo-test/databases/(default)/documents/'
215+
'trigger_results?documentId=deleted_$userId',
216+
);
217+
req.headers.contentType = ContentType.json;
218+
req.write(jsonEncode({'fields': resultFields}));
219+
await req.close();
220+
httpClient.close();
221+
} catch (e) {
222+
print(' Side-channel write failed: $e');
223+
}
187224
});
188225

189226
firebase.firestore.onDocumentWritten(document: 'users/{userId}', (

0 commit comments

Comments
 (0)