Skip to content

Commit 52bcfa5

Browse files
committed
Updated unit tests for all AsyncNotifier subclasses
# Conflicts: # ecommerce_app/test/src/features/authentication/presentation/account/account_screen_controller_test.dart # Conflicts: # ecommerce_app/test/src/features/cart/presentation/add_to_cart/add_to_cart_controller_test.dart
1 parent f63a7f3 commit 52bcfa5

File tree

7 files changed

+410
-188
lines changed

7 files changed

+410
-188
lines changed

ecommerce_app/test/src/features/authentication/presentation/account/account_screen_controller_test.dart

Lines changed: 85 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
@Timeout(Duration(milliseconds: 500))
2+
import 'package:ecommerce_app/src/features/authentication/data/fake_auth_repository.dart';
23
import 'package:ecommerce_app/src/features/authentication/presentation/account/account_screen_controller.dart';
34
import 'package:flutter_riverpod/flutter_riverpod.dart';
45
import 'package:flutter_test/flutter_test.dart';
@@ -7,56 +8,112 @@ import 'package:mocktail/mocktail.dart';
78
import '../../../../mocks.dart';
89

910
void main() {
10-
late MockAuthRepository authRepository;
11-
late AccountScreenController controller;
12-
setUp(() {
13-
authRepository = MockAuthRepository();
14-
controller = AccountScreenController(
15-
authRepository: authRepository,
11+
ProviderContainer makeProviderContainer(MockAuthRepository authRepository) {
12+
final container = ProviderContainer(
13+
overrides: [
14+
authRepositoryProvider.overrideWithValue(authRepository),
15+
],
1616
);
17+
addTearDown(container.dispose);
18+
return container;
19+
}
20+
21+
setUpAll(() {
22+
registerFallbackValue(const AsyncLoading<int>());
1723
});
24+
1825
group('AccountScreenController', () {
19-
test('initial state is AsyncValue.data', () {
26+
test('initial state is AsyncData', () {
27+
final authRepository = MockAuthRepository();
28+
// create the ProviderContainer with the mock auth repository
29+
final container = makeProviderContainer(authRepository);
30+
// create a listener
31+
final listener = Listener<AsyncValue<void>>();
32+
// listen to the provider and call [listener] whenever its value changes
33+
container.listen(
34+
accountScreenControllerProvider,
35+
listener.call,
36+
fireImmediately: true,
37+
);
38+
// verify
39+
verify(
40+
// the build method returns a value immediately, so we expect AsyncData
41+
() => listener(null, const AsyncData<void>(null)),
42+
);
43+
// verify that the listener is no longer called
44+
verifyNoMoreInteractions(listener);
45+
// verify that [signInAnonymously] was not called during initialization
2046
verifyNever(authRepository.signOut);
21-
expect(controller.state, const AsyncData<void>(null));
2247
});
2348

2449
test('signOut success', () async {
2550
// setup
26-
when(authRepository.signOut).thenAnswer(
27-
(_) => Future.value(),
28-
);
29-
// expect later
30-
expectLater(
31-
controller.stream,
32-
emitsInOrder(const [
33-
AsyncLoading<void>(),
34-
AsyncData<void>(null),
35-
]),
51+
final authRepository = MockAuthRepository();
52+
// stub method to return success
53+
when(authRepository.signOut).thenAnswer((_) => Future.value());
54+
// create the ProviderContainer with the mock auth repository
55+
final container = makeProviderContainer(authRepository);
56+
// create a listener
57+
final listener = Listener<AsyncValue<void>>();
58+
// listen to the provider and call [listener] whenever its value changes
59+
container.listen(
60+
accountScreenControllerProvider,
61+
listener.call,
62+
fireImmediately: true,
3663
);
64+
// sto
65+
const data = AsyncData<void>(null);
66+
// verify initial value from build method
67+
verify(() => listener(null, data));
3768
// run
69+
final controller =
70+
container.read(accountScreenControllerProvider.notifier);
3871
await controller.signOut();
3972
// verify
73+
verifyInOrder([
74+
// set loading state
75+
// * use a matcher since AsyncLoading != AsyncLoading with data
76+
// * https://codewithandrea.com/articles/unit-test-async-notifier-riverpod/
77+
() => listener(data, any(that: isA<AsyncLoading>())),
78+
// data when complete
79+
() => listener(any(that: isA<AsyncLoading>()), data),
80+
]);
81+
verifyNoMoreInteractions(listener);
4082
verify(authRepository.signOut).called(1);
4183
});
4284
test('signOut failure', () async {
4385
// setup
86+
final authRepository = MockAuthRepository();
87+
// stub method to return success
4488
final exception = Exception('Connection failed');
4589
when(authRepository.signOut).thenThrow(exception);
46-
// expect later
47-
expectLater(
48-
controller.stream,
49-
emitsInOrder([
50-
const AsyncLoading<void>(),
51-
predicate<AsyncValue<void>>((value) {
52-
expect(value.hasError, true);
53-
return true;
54-
}),
55-
]),
90+
// create the ProviderContainer with the mock auth repository
91+
final container = makeProviderContainer(authRepository);
92+
// create a listener
93+
final listener = Listener<AsyncValue<void>>();
94+
// listen to the provider and call [listener] whenever its value changes
95+
container.listen(
96+
accountScreenControllerProvider,
97+
listener.call,
98+
fireImmediately: true,
5699
);
100+
const data = AsyncData<void>(null);
101+
// verify initial value from build method
102+
verify(() => listener(null, data));
57103
// run
104+
final controller =
105+
container.read(accountScreenControllerProvider.notifier);
58106
await controller.signOut();
59107
// verify
108+
verifyInOrder([
109+
// set loading state
110+
// * use a matcher since AsyncLoading != AsyncLoading with data
111+
() => listener(data, any(that: isA<AsyncLoading>())),
112+
// error when complete
113+
() => listener(
114+
any(that: isA<AsyncLoading>()), any(that: isA<AsyncError>())),
115+
]);
116+
verifyNoMoreInteractions(listener);
60117
verify(authRepository.signOut).called(1);
61118
});
62119
});

ecommerce_app/test/src/features/authentication/presentation/sign_in/email_password_sign_in_controller_test.dart

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ import 'package:mocktail/mocktail.dart';
99
import '../../../../mocks.dart';
1010

1111
void main() {
12+
const testEmail = 'test@test.com';
13+
const testPassword = '1234';
14+
const testFormType = EmailPasswordSignInFormType.signIn;
15+
1216
ProviderContainer makeProviderContainer(MockAuthRepository authRepository) {
1317
final container = ProviderContainer(
1418
overrides: [
@@ -19,9 +23,9 @@ void main() {
1923
return container;
2024
}
2125

22-
const testEmail = 'test@test.com';
23-
const testPassword = '1234';
24-
const testFormType = EmailPasswordSignInFormType.signIn;
26+
setUpAll(() {
27+
registerFallbackValue(const AsyncLoading<int>());
28+
});
2529

2630
group('EmailPasswordSignInController', () {
2731
test('sign in success', () async {
@@ -32,24 +36,32 @@ void main() {
3236
testPassword,
3337
)).thenAnswer((_) => Future.value());
3438
final container = makeProviderContainer(authRepository);
35-
final controller =
36-
container.read(emailPasswordSignInControllerProvider.notifier);
37-
// expect later
38-
expectLater(
39-
controller.stream,
40-
emitsInOrder([
41-
const AsyncLoading<void>(),
42-
const AsyncData<void>(null),
43-
]),
39+
final listener = Listener<AsyncValue<void>>();
40+
container.listen(
41+
emailPasswordSignInControllerProvider,
42+
listener.call,
43+
fireImmediately: true,
4444
);
45+
const data = AsyncData<void>(null);
46+
// verify initial value from build method
47+
verify(() => listener(null, data));
4548
// run
49+
final controller =
50+
container.read(emailPasswordSignInControllerProvider.notifier);
4651
final result = await controller.submit(
4752
email: testEmail,
4853
password: testPassword,
4954
formType: testFormType,
5055
);
5156
// verify
5257
expect(result, true);
58+
verifyInOrder([
59+
// set loading state
60+
() => listener(data, any(that: isA<AsyncLoading>())),
61+
// data when complete
62+
() => listener(any(that: isA<AsyncLoading>()), data),
63+
]);
64+
verifyNoMoreInteractions(listener);
5365
});
5466
test('sign in failure', () async {
5567
// setup
@@ -60,27 +72,32 @@ void main() {
6072
testPassword,
6173
)).thenThrow(exception);
6274
final container = makeProviderContainer(authRepository);
63-
final controller =
64-
container.read(emailPasswordSignInControllerProvider.notifier);
65-
// expect later
66-
expectLater(
67-
controller.stream,
68-
emitsInOrder([
69-
const AsyncLoading<void>(),
70-
predicate<AsyncValue<void>>((state) {
71-
expect(state.hasError, true);
72-
return true;
73-
}),
74-
]),
75+
final listener = Listener<AsyncValue<void>>();
76+
container.listen(
77+
emailPasswordSignInControllerProvider,
78+
listener.call,
79+
fireImmediately: true,
7580
);
81+
// verify initial value from build method
82+
verify(() => listener(null, const AsyncData<void>(null)));
7683
// run
84+
final controller =
85+
container.read(emailPasswordSignInControllerProvider.notifier);
7786
final result = await controller.submit(
7887
email: testEmail,
7988
password: testPassword,
8089
formType: testFormType,
8190
);
8291
// verify
8392
expect(result, false);
93+
verifyInOrder([
94+
// set loading state
95+
() => listener(
96+
const AsyncData<void>(null), any(that: isA<AsyncLoading>())),
97+
// error when complete
98+
() => listener(
99+
any(that: isA<AsyncLoading>()), any(that: isA<AsyncError>())),
100+
]);
84101
});
85102
});
86103
}

0 commit comments

Comments
 (0)