Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions lib/screens/dashboard/bloc/pending_transactions_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,14 @@ class PendingTransactionsCubit extends Cubit<List<TransactionDto>> {
Future<void> _loadPendingTransactions() async {
try {
final transactions = await _transactionHistoryService.fetchPendingTransactions();
// The fetch is started in the constructor and not awaited, so the cubit
// can be closed (page popped) before it resolves. Guard the emit to avoid
// a StateError after close (issue #657 P3 #16).
if (isClosed) return;
emit(transactions);
} catch (e) {
developer.log('Failed to load pending transactions: $e', name: '$PendingTransactionsCubit');
if (isClosed) return;
emit([]);
}
}
Expand Down
21 changes: 21 additions & 0 deletions test/screens/dashboard/pending_transactions_cubit_test.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:async';

import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:realunit_wallet/packages/service/dfx/models/transactions/dto/transactions_dto.dart';
Expand Down Expand Up @@ -36,6 +38,25 @@ void main() {
expect(cubit.state, [tx1, tx2]);
});

test('does not emit (no StateError) if closed before the fetch resolves '
'(issue #657 P3 #16 regression)', () async {
final completer = Completer<List<TransactionDto>>();
when(() => service.fetchPendingTransactions())
.thenAnswer((_) => completer.future);

final cubit = PendingTransactionsCubit(service);
// Close while the constructor-started fetch is still in flight.
await cubit.close();

// Resolving now would, without the isClosed guard, emit after close and
// throw 'Cannot emit new states after calling close'.
completer.complete([_StubTx()]);
await Future<void>.delayed(Duration.zero);

// No exception escaped; the closed cubit kept its last state.
expect(cubit.isClosed, isTrue);
});

test('falls back to an empty list when the service throws', () async {
when(() => service.fetchPendingTransactions())
.thenAnswer((_) async => throw Exception('network'));
Expand Down
Loading