1
+import 'dart:async';
2
+
3
+import 'package:cake_wallet/core/execution_state.dart';
4
+import 'package:cake_wallet/generated/i18n.dart';
5
+import 'package:cake_wallet/src/screens/send/send_page.dart';
6
+import 'package:cake_wallet/view_model/send/send_view_model_state.dart';
7
+import 'package:cw_core/crypto_currency.dart';
8
+import 'package:cw_core/transaction_priority.dart';
9
+import 'package:flutter/foundation.dart';
10
+import 'package:flutter_test/flutter_test.dart';
11
+
12
+import '../components/common_test_cases.dart';
13
+import '../components/common_test_constants.dart';
14
+import 'auth_page_robot.dart';
15
+
16
+class SendPageRobot {
17
+ SendPageRobot({required this.tester})
18
+ : commonTestCases = CommonTestCases(tester),
19
+ authPageRobot = AuthPageRobot(tester);
20
+
21
+ WidgetTester tester;
22
+ CommonTestCases commonTestCases;
23
+ AuthPageRobot authPageRobot;
24
+
25
+ Future<void> isSendPage() async {
26
+ await commonTestCases.isSpecificPage<SendPage>();
27
+ }
28
+
29
+ void hasTitle() {
30
+ commonTestCases.hasText(S.current.send);
31
+ }
32
+
33
+ void confirmViewComponentsDisplayProperly() {
34
+ SendPage sendPage = tester.widget(find.byType(SendPage));
35
+ final sendViewModel = sendPage.sendViewModel;
36
+
37
+ commonTestCases.hasValueKey('send_page_address_textfield_key');
38
+ commonTestCases.hasValueKey('send_page_note_textfield_key');
39
+ commonTestCases.hasValueKey('send_page_amount_textfield_key');
40
+ commonTestCases.hasValueKey('send_page_add_template_button_key');
41
+
42
+ if (sendViewModel.hasMultipleTokens) {
43
+ commonTestCases.hasValueKey('send_page_currency_picker_button_key');
44
+ }
45
+
46
+ if (!sendViewModel.isBatchSending) {
47
+ commonTestCases.hasValueKey('send_page_send_all_button_key');
48
+ }
49
+
50
+ if (!sendViewModel.isFiatDisabled) {
51
+ commonTestCases.hasValueKey('send_page_fiat_amount_textfield_key');
52
+ }
53
+
54
+ if (sendViewModel.hasFees) {
55
+ commonTestCases.hasValueKey('send_page_select_fee_priority_button_key');
56
+ }
57
+
58
+ if (sendViewModel.hasCoinControl) {
59
+ commonTestCases.hasValueKey('send_page_unspent_coin_button_key');
60
+ }
61
+
62
+ if (sendViewModel.hasCurrecyChanger) {
63
+ commonTestCases.hasValueKey('send_page_change_asset_button_key');
64
+ }
65
+
66
+ if (sendViewModel.sendTemplateViewModel.hasMultiRecipient) {
67
+ commonTestCases.hasValueKey('send_page_add_receiver_button_key');
68
+ }
69
+ }
70
+
71
+ Future<void> selectReceiveCurrency(CryptoCurrency receiveCurrency) async {
72
+ final currencyPickerKey = 'send_page_currency_picker_button_key';
73
+ final currencyPickerDialogKey = 'send_page_currency_picker_dialog_button_key';
74
+
75
+ await commonTestCases.tapItemByKey(currencyPickerKey);
76
+ commonTestCases.hasValueKey(currencyPickerDialogKey);
77
+
78
+ SendPage sendPage = tester.widget(find.byType(SendPage));
79
+ final sendViewModel = sendPage.sendViewModel;
80
+
81
+ if (receiveCurrency == sendViewModel.selectedCryptoCurrency) {
82
+ await commonTestCases
83
+ .tapItemByKey('picker_items_index_${receiveCurrency.name}_selected_item_button_key');
84
+ return;
85
+ }
86
+
87
+ await commonTestCases.scrollUntilVisible(
88
+ 'picker_items_index_${receiveCurrency.name}_button_key',
89
+ 'picker_scrollbar_key',
90
+ );
91
+ await commonTestCases.defaultSleepTime();
92
+
93
+ await commonTestCases.tapItemByKey('picker_items_index_${receiveCurrency.name}_button_key');
94
+ }
95
+
96
+ Future<void> enterReceiveAddress(String receiveAddress) async {
97
+ await commonTestCases.enterText(receiveAddress, 'send_page_address_textfield_key');
98
+ await commonTestCases.defaultSleepTime();
99
+ }
100
+
101
+ Future<void> enterAmount(String amount) async {
102
+ await commonTestCases.enterText(amount, 'send_page_amount_textfield_key');
103
+ }
104
+
105
+ Future<void> selectTransactionPriority({TransactionPriority? priority}) async {
106
+ SendPage sendPage = tester.widget(find.byType(SendPage));
107
+ final sendViewModel = sendPage.sendViewModel;
108
+
109
+ if (!sendViewModel.hasFees || priority == null) return;
110
+
111
+ final transactionPriorityPickerKey = 'send_page_select_fee_priority_button_key';
112
+ await commonTestCases.tapItemByKey(transactionPriorityPickerKey);
113
+
114
+ if (priority == sendViewModel.transactionPriority) {
115
+ await commonTestCases
116
+ .tapItemByKey('picker_items_index_${priority.title}_selected_item_button_key');
117
+ return;
118
+ }
119
+
120
+ await commonTestCases.scrollUntilVisible(
121
+ 'picker_items_index_${priority.title}_button_key',
122
+ 'picker_scrollbar_key',
123
+ );
124
+ await commonTestCases.defaultSleepTime();
125
+
126
+ await commonTestCases.tapItemByKey('picker_items_index_${priority.title}_button_key');
127
+ }
128
+
129
+ Future<void> onSendButtonPressed() async {
130
+ tester.printToConsole('Pressing send');
131
+
132
+ await commonTestCases.tapItemByKey(
133
+ 'send_page_send_button_key',
134
+ shouldPumpAndSettle: false,
135
+ );
136
+
137
+ await _waitForSendTransactionCompletion();
138
+
139
+ await commonTestCases.defaultSleepTime();
140
+ }
141
+
142
+ Future<void> _waitForSendTransactionCompletion() async {
143
+ await tester.pump();
144
+ final Completer<void> completer = Completer<void>();
145
+
146
+ // Loop to wait for the async operation to complete
147
+ while (true) {
148
+ await Future.delayed(Duration(seconds: 1));
149
+
150
+ tester.printToConsole('Before _handleAuth');
151
+
152
+ await _handleAuthPage();
153
+
154
+ tester.printToConsole('After _handleAuth');
155
+
156
+ await tester.pump();
157
+
158
+ final sendPage = tester.widget<SendPage>(find.byType(SendPage));
159
+ final state = sendPage.sendViewModel.state;
160
+
161
+ await tester.pump();
162
+
163
+ bool isDone = state is ExecutedSuccessfullyState;
164
+ bool isFailed = state is FailureState;
165
+
166
+ tester.printToConsole('isDone: $isDone');
167
+ tester.printToConsole('isFailed: $isFailed');
168
+
169
+ if (isDone || isFailed) {
170
+ tester.printToConsole(
171
+ isDone ? 'Completer is done' : 'Completer is done though operation failed',
172
+ );
173
+ completer.complete();
174
+ await tester.pump();
175
+ break;
176
+ } else {
177
+ tester.printToConsole('Completer is not done');
178
+ await tester.pump();
179
+ }
180
+ }
181
+
182
+ await expectLater(completer.future, completes);
183
+
184
+ tester.printToConsole('Done confirming sending operation');
185
+ }
186
+
187
+ Future<void> _handleAuthPage() async {
188
+ tester.printToConsole('Inside _handleAuth');
189
+ await tester.pump();
190
+ tester.printToConsole('starting auth checks');
191
+
192
+ final authPage = authPageRobot.onAuthPage();
193
+
194
+ tester.printToConsole('hasAuth:$authPage');
195
+
196
+ if (authPage) {
197
+ await tester.pump();
198
+ tester.printToConsole('Starting inner _handleAuth loop checks');
199
+
200
+ try {
201
+ await authPageRobot.enterPinCode(CommonTestConstants.pin, false);
202
+ tester.printToConsole('Auth done');
203
+
204
+ await tester.pump();
205
+
206
+ tester.printToConsole('Auth pump done');
207
+ } catch (e) {
208
+ tester.printToConsole('Auth failed, retrying');
209
+ await tester.pump();
210
+ _handleAuthPage();
211
+ }
212
+ }
213
+ }
214
+
215
+ Future<void> handleSendResult() async {
216
+ tester.printToConsole('Inside handle function');
217
+
218
+ bool hasError = false;
219
+
220
+ hasError = await hasErrorWhileSending();
221
+
222
+ tester.printToConsole('Has an Error in the handle: $hasError');
223
+
224
+ int maxRetries = 20;
225
+ int retries = 0;
226
+
227
+ while (hasError && retries < maxRetries) {
228
+ tester.printToConsole('hasErrorInLoop: $hasError');
229
+ await tester.pump();
230
+
231
+ await onSendFailureDialogButtonPressed();
232
+ tester.printToConsole('Failure button tapped');
233
+
234
+ await commonTestCases.defaultSleepTime();
235
+
236
+ await onSendButtonPressed();
237
+ tester.printToConsole('Send button tapped');
238
+
239
+ hasError = await hasErrorWhileSending();
240
+
241
+ retries++;
242
+ }
243
+
244
+ if (!hasError) {
245
+ tester.printToConsole('No error, proceeding with flow');
246
+ await tester.pump();
247
+ }
248
+
249
+ await commonTestCases.defaultSleepTime();
250
+ }
251
+
252
+ //* ------ On Sending Failure ------------
253
+ Future<bool> hasErrorWhileSending() async {
254
+ await tester.pump();
255
+
256
+ tester.printToConsole('Checking if there is an error');
257
+
258
+ final errorDialog = find.byKey(ValueKey('send_page_send_failure_dialog_button_key'));
259
+
260
+ bool hasError = errorDialog.tryEvaluate();
261
+
262
+ tester.printToConsole('Has error: $hasError');
263
+
264
+ return hasError;
265
+ }
266
+
267
+ Future<void> onSendFailureDialogButtonPressed() async {
268
+ await commonTestCases.defaultSleepTime();
269
+
270
+ tester.printToConsole('Send Button Failure Dialog Triggered');
271
+
272
+ await commonTestCases.tapItemByKey('send_page_send_failure_dialog_button_key');
273
+ }
274
+
275
+ //* ------ On Sending Success ------------
276
+ Future<void> onSendButtonOnConfirmSendingDialogPressed() async {
277
+ tester.printToConsole('Inside confirm sending dialog: For sending');
278
+ await commonTestCases.defaultSleepTime();
279
+ await tester.pump();
280
+
281
+ final sendText = find.text(S.current.send).last;
282
+ bool hasText = sendText.tryEvaluate();
283
+ tester.printToConsole('Has Text: $hasText');
284
+
285
+ if (hasText) {
286
+ await commonTestCases.tapItemByFinder(sendText, shouldPumpAndSettle: false);
287
+ // Loop to wait for the operation to commit transaction
288
+ await _waitForCommitTransactionCompletion();
289
+
290
+ await commonTestCases.defaultSleepTime(seconds: 4);
291
+ } else {
292
+ await commonTestCases.defaultSleepTime();
293
+ await tester.pump();
294
+ onSendButtonOnConfirmSendingDialogPressed();
295
+ }
296
+ }
297
+
298
+ Future<void> _waitForCommitTransactionCompletion() async {
299
+ final Completer<void> completer = Completer<void>();
300
+
301
+ while (true) {
302
+ await Future.delayed(Duration(seconds: 1));
303
+
304
+ final sendPage = tester.widget<SendPage>(find.byType(SendPage));
305
+ final state = sendPage.sendViewModel.state;
306
+
307
+ bool isDone = state is TransactionCommitted;
308
+ bool isFailed = state is FailureState;
309
+
310
+ tester.printToConsole('isDone: $isDone');
311
+ tester.printToConsole('isFailed: $isFailed');
312
+
313
+ if (isDone || isFailed) {
314
+ tester.printToConsole(
315
+ isDone ? 'Completer is done' : 'Completer is done though operation failed',
316
+ );
317
+ completer.complete();
318
+ await tester.pump();
319
+ break;
320
+ } else {
321
+ tester.printToConsole('Completer is not done');
322
+ await tester.pump();
323
+ }
324
+ }
325
+
326
+ await expectLater(completer.future, completes);
327
+
328
+ tester.printToConsole('Done Committing Transaction');
329
+ }
330
+
331
+ Future<void> onCancelButtonOnConfirmSendingDialogPressed() async {
332
+ tester.printToConsole('Inside confirm sending dialog: For canceling');
333
+ await commonTestCases.defaultSleepTime(seconds: 4);
334
+
335
+ final cancelText = find.text(S.current.cancel);
336
+ bool hasText = cancelText.tryEvaluate();
337
+
338
+ if (hasText) {
339
+ await commonTestCases.tapItemByFinder(cancelText);
340
+
341
+ await commonTestCases.defaultSleepTime(seconds: 4);
342
+ }
343
+ }
344
+
345
+ //* ---- Add Contact Dialog On Send Successful Dialog -----
346
+ Future<void> onSentDialogPopUp() async {
347
+ SendPage sendPage = tester.widget(find.byType(SendPage));
348
+ final sendViewModel = sendPage.sendViewModel;
349
+
350
+ final newContactAddress = sendPage.newContactAddress ?? sendViewModel.newContactAddress();
351
+ if (newContactAddress != null) {
352
+ await _onAddContactButtonOnSentDialogPressed();
353
+ }
354
+
355
+ await commonTestCases.defaultSleepTime();
356
+ }
357
+
358
+ Future<void> _onAddContactButtonOnSentDialogPressed() async {
359
+ await commonTestCases.tapItemByKey('send_page_sent_dialog_add_contact_button_key');
360
+ }
361
+
362
+ // ignore: unused_element
363
+ Future<void> _onIgnoreButtonOnSentDialogPressed() async {
364
+ await commonTestCases.tapItemByKey('send_page_sent_dialog_ignore_button_key');
365
+ }
366
+}
\ No newline at end of file