1
+ // Copyright 2024, the Chromium project authors. Please see the AUTHORS file
2
+ // for details. All rights reserved. Use of this source code is governed by a
3
+ // BSD-style license that can be found in the LICENSE file.
4
+
5
+ import 'package:firebase_database/firebase_database.dart' ;
6
+ import 'package:flutter/material.dart' ;
7
+ import 'package:flutter_test/flutter_test.dart' ;
8
+ import 'package:firebase_ui_database/firebase_ui_database.dart' ;
9
+ import 'package:mockito/mockito.dart' ;
10
+ import '../utils.dart' ;
11
+
12
+ const _kTestPath = 'flutter-tests' ;
13
+
14
+ void main () {
15
+ group ('DatabaseListViewBuilder' , () {
16
+ setUp (() async {
17
+ await clearReference (
18
+ rtdb.ref (_kTestPath),
19
+ );
20
+ });
21
+
22
+ testWidgets ('Allows specifying custom error handler' , (tester) async {
23
+ final builderSpy = ListViewBuilderSpy ();
24
+ final ref = rtdb.ref ('unknown' );
25
+
26
+ await tester.pumpWidget (
27
+ MaterialApp (
28
+ home: Scaffold (
29
+ body: FirebaseDatabaseListView (
30
+ query: ref,
31
+ errorBuilder: (context, error, stack) {
32
+ return Text ('error: $error ' );
33
+ },
34
+ itemBuilder: builderSpy.call,
35
+ ),
36
+ ),
37
+ ),
38
+ );
39
+
40
+ expect (find.byType (CircularProgressIndicator ), findsOneWidget);
41
+ expect (find.byType (ListView ), findsNothing);
42
+
43
+ await tester.pumpAndSettle ();
44
+
45
+ verifyZeroInteractions (builderSpy);
46
+
47
+ expect (
48
+ find.text (
49
+ 'error: [firebase_database/permission-denied] '
50
+ 'Client doesn\' t have permission to access the desired data.' ,
51
+ ),
52
+ findsOneWidget,
53
+ );
54
+ expect (find.byType (ListView ), findsNothing);
55
+ });
56
+
57
+ testWidgets ('Allows specifying custom loading handler' , (tester) async {
58
+ final ref = rtdb.ref (_kTestPath);
59
+
60
+ await tester.pumpWidget (
61
+ MaterialApp (
62
+ home: Scaffold (
63
+ body: FirebaseDatabaseListView (
64
+ query: ref,
65
+ loadingBuilder: (context) => const Text ('loading...' ),
66
+ itemBuilder: (context, snapshot) => throw UnimplementedError (),
67
+ ),
68
+ ),
69
+ ),
70
+ );
71
+
72
+ expect (find.text ('loading...' ), findsOneWidget);
73
+ expect (find.byType (CircularProgressIndicator ), findsNothing);
74
+ expect (find.byType (ListView ), findsNothing);
75
+ });
76
+
77
+ testWidgets (
78
+ 'By default, shows a progress indicator when loading' ,
79
+ (tester) async {
80
+ final ref = rtdb.ref (_kTestPath);
81
+
82
+ await tester.pumpWidget (
83
+ MaterialApp (
84
+ home: Scaffold (
85
+ body: FirebaseDatabaseListView (
86
+ query: ref,
87
+ itemBuilder: (context, snapshot) => throw UnimplementedError (),
88
+ ),
89
+ ),
90
+ ),
91
+ );
92
+
93
+ expect (find.byType (CircularProgressIndicator ), findsOneWidget);
94
+ expect (find.byType (ListView ), findsNothing);
95
+ },
96
+ );
97
+
98
+ testWidgets ('By default, ignore errors' , (tester) async {
99
+ final builderSpy = ListViewBuilderSpy ();
100
+ final ref = rtdb.ref (_kTestPath);
101
+
102
+ await tester.pumpWidget (
103
+ MaterialApp (
104
+ home: Scaffold (
105
+ body: FirebaseDatabaseListView (
106
+ query: ref,
107
+ cacheExtent: 0 ,
108
+ itemBuilder: (context, snapshot) => throw UnimplementedError (),
109
+ ),
110
+ ),
111
+ ),
112
+ );
113
+
114
+ verifyZeroInteractions (builderSpy);
115
+
116
+ expect (find.byType (CircularProgressIndicator ), findsOneWidget);
117
+ expect (find.byType (ListView ), findsNothing);
118
+
119
+ await ref.onValue.first.then ((value) {}, onError: (_) {});
120
+
121
+ await tester.pump ();
122
+
123
+ expect (find.byType (ListView ), findsOneWidget);
124
+ });
125
+
126
+ testWidgets (
127
+ 'When reaching the end of the list, loads more items' ,
128
+ (tester) async {
129
+ final ref = rtdb.ref ().child (_kTestPath);
130
+
131
+ await fillReference (ref, 25 );
132
+ late double size;
133
+
134
+ await tester.pumpWidget (
135
+ MaterialApp (
136
+ home: Material (
137
+ child: Builder (builder: (context) {
138
+ final mq = MediaQuery .of (context);
139
+ final h = mq.size.height;
140
+ size = h / 5 ;
141
+
142
+ return FirebaseDatabaseListView (
143
+ physics: const ClampingScrollPhysics (),
144
+ query: ref.orderByValue (),
145
+ cacheExtent: 0 ,
146
+ pageSize: 5 ,
147
+ itemExtent: size,
148
+ itemBuilder: (context, snapshot) {
149
+ final v = snapshot.value as int ;
150
+
151
+ return Container (
152
+ alignment: Alignment .center,
153
+ color: Colors .black.withAlpha (v % 2 == 0 ? 50 : 100 ),
154
+ key: ValueKey (v.toString ()),
155
+ child: Text (
156
+ v.toString (),
157
+ textAlign: TextAlign .center,
158
+ ),
159
+ );
160
+ },
161
+ );
162
+ }),
163
+ ),
164
+ ),
165
+ );
166
+
167
+ await tester.pumpAndSettle ();
168
+
169
+ for (int i = 0 ; i < 5 ; i++ ) {
170
+ expect (find.byKey (ValueKey (i.toString ())), findsOneWidget);
171
+ }
172
+
173
+ // allow for more items to be fetcehed
174
+ await Future .delayed (const Duration (milliseconds: 500 ));
175
+
176
+ await tester.drag (
177
+ find.byKey (const ValueKey ('4' )),
178
+ Offset (0 , - size * 5 ),
179
+ touchSlopY: 0 ,
180
+ );
181
+
182
+ await tester.pumpAndSettle ();
183
+
184
+ for (int i = 5 ; i < 9 ; i++ ) {
185
+ expect (find.byKey (ValueKey (i.toString ())), findsOneWidget);
186
+ }
187
+
188
+ // allow for more items to be fetched
189
+ await Future .delayed (const Duration (milliseconds: 500 ));
190
+
191
+ await tester.drag (
192
+ find.byKey (const ValueKey ('9' )),
193
+ Offset (0 , - size * 5 ),
194
+ touchSlopY: 0 ,
195
+ );
196
+
197
+ await tester.pumpAndSettle ();
198
+
199
+ for (int i = 10 ; i < 15 ; i++ ) {
200
+ expect (find.byKey (ValueKey (i.toString ())), findsOneWidget);
201
+ }
202
+ },
203
+ );
204
+ });
205
+ }
206
+
207
+ class ListViewBuilderSpy <T > extends Mock {
208
+ Widget call (
209
+ BuildContext ? context,
210
+ T ? snapshot,
211
+ ) {
212
+ return super .noSuchMethod (
213
+ Invocation .method (#call, [context, snapshot]),
214
+ returnValueForMissingStub: Container (),
215
+ returnValue: Container (),
216
+ );
217
+ }
218
+ }
219
+
220
+ Future <void > fillReference (DatabaseReference ref, int length) {
221
+ return Future .wait ([
222
+ for (var i = 0 ; i < length; i++ ) ref.push ().set (i),
223
+ ]);
224
+ }
0 commit comments