mynotes: Add tests

This commit is contained in:
Evan Ferrao 2024-07-23 10:29:28 +05:30
parent 6a391c23cd
commit 68854afae6
No known key found for this signature in database
GPG Key ID: F01DEB4D7CFC9B52
6 changed files with 390 additions and 33 deletions

View File

@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
@immutable
class AuthUser {
final bool isEmailVerified;
AuthUser(this.isEmailVerified);
AuthUser({required this.isEmailVerified});
factory AuthUser.fromFirebase(User user) => AuthUser(user.emailVerified);
factory AuthUser.fromFirebase(User user) => AuthUser(isEmailVerified: user.emailVerified);
}

View File

@ -47,7 +47,6 @@ class FirebaseAuthProvider implements AuthProvider {
}
@override
// TODO: implement currentUser
AuthUser? get currentUser {
final user = FirebaseAuth.instance.currentUser;
if (user != null) {

View File

@ -1,6 +1,14 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
_fe_analyzer_shared:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7"
url: "https://pub.dev"
source: hosted
version: "67.0.0"
_flutterfire_internals:
dependency: transitive
description:
@ -9,6 +17,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.38"
analyzer:
dependency: transitive
description:
name: analyzer
sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d"
url: "https://pub.dev"
source: hosted
version: "6.4.1"
args:
dependency: transitive
description:
name: args
sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
url: "https://pub.dev"
source: hosted
version: "2.5.0"
async:
dependency: transitive
description:
@ -73,6 +97,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.18.0"
convert:
dependency: transitive
description:
name: convert
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
url: "https://pub.dev"
source: hosted
version: "3.1.1"
coverage:
dependency: transitive
description:
name: coverage
sha256: "3945034e86ea203af7a056d98e98e42a5518fff200d6e8e6647e1886b07e936e"
url: "https://pub.dev"
source: hosted
version: "1.8.0"
crypto:
dependency: transitive
description:
name: crypto
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
url: "https://pub.dev"
source: hosted
version: "3.0.3"
cupertino_icons:
dependency: "direct main"
description:
@ -89,6 +137,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.1"
file:
dependency: transitive
description:
name: file
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
url: "https://pub.dev"
source: hosted
version: "7.0.0"
firebase_analytics:
dependency: "direct main"
description:
@ -184,6 +240,30 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
frontend_server_client:
dependency: transitive
description:
name: frontend_server_client
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
url: "https://pub.dev"
source: hosted
version: "4.0.0"
glob:
dependency: transitive
description:
name: glob
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
url: "https://pub.dev"
source: hosted
version: "3.2.1"
http_parser:
dependency: transitive
description:
@ -192,6 +272,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.0.2"
io:
dependency: transitive
description:
name: io
sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
url: "https://pub.dev"
source: hosted
version: "1.0.4"
js:
dependency: transitive
description:
name: js
sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf
url: "https://pub.dev"
source: hosted
version: "0.7.1"
leak_tracker:
dependency: transitive
description:
@ -224,6 +320,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.0.0"
logging:
dependency: transitive
description:
name: logging
sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
matcher:
dependency: transitive
description:
@ -248,6 +352,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.12.0"
mime:
dependency: transitive
description:
name: mime
sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2"
url: "https://pub.dev"
source: hosted
version: "1.0.5"
node_preamble:
dependency: transitive
description:
name: node_preamble
sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db"
url: "https://pub.dev"
source: hosted
version: "2.0.2"
package_config:
dependency: transitive
description:
name: package_config
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
path:
dependency: transitive
description:
@ -264,11 +392,75 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.8"
pool:
dependency: transitive
description:
name: pool
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
url: "https://pub.dev"
source: hosted
version: "1.5.1"
pub_semver:
dependency: transitive
description:
name: pub_semver
sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
shelf:
dependency: transitive
description:
name: shelf
sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
url: "https://pub.dev"
source: hosted
version: "1.4.1"
shelf_packages_handler:
dependency: transitive
description:
name: shelf_packages_handler
sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e"
url: "https://pub.dev"
source: hosted
version: "3.0.2"
shelf_static:
dependency: transitive
description:
name: shelf_static
sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e
url: "https://pub.dev"
source: hosted
version: "1.1.2"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1"
url: "https://pub.dev"
source: hosted
version: "1.0.4"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
source_map_stack_trace:
dependency: transitive
description:
name: source_map_stack_trace
sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
source_maps:
dependency: transitive
description:
name: source_maps
sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703"
url: "https://pub.dev"
source: hosted
version: "0.10.12"
source_span:
dependency: transitive
description:
@ -309,6 +501,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.2.1"
test:
dependency: "direct dev"
description:
name: test
sha256: "7ee446762c2c50b3bd4ea96fe13ffac69919352bd3b4b17bac3f3465edc58073"
url: "https://pub.dev"
source: hosted
version: "1.25.2"
test_api:
dependency: transitive
description:
@ -317,6 +517,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.7.0"
test_core:
dependency: transitive
description:
name: test_core
sha256: "2bc4b4ecddd75309300d8096f781c0e3280ca1ef85beda558d33fcbedc2eead4"
url: "https://pub.dev"
source: hosted
version: "0.6.0"
typed_data:
dependency: transitive
description:
@ -341,6 +549,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "14.2.1"
watcher:
dependency: transitive
description:
name: watcher
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
web:
dependency: transitive
description:
@ -349,6 +565,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.5.1"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42"
url: "https://pub.dev"
source: hosted
version: "2.4.5"
webkit_inspection_protocol:
dependency: transitive
description:
name: webkit_inspection_protocol
sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
yaml:
dependency: transitive
description:
name: yaml
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
url: "https://pub.dev"
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.4.1 <4.0.0"
flutter: ">=3.18.0-18.0.pre.54"

View File

@ -50,6 +50,7 @@ dev_dependencies:
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^4.0.0
test: ^1.25.2
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec

147
test/auth_test.dart Normal file
View File

@ -0,0 +1,147 @@
import 'dart:math';
import 'package:mynotes/services/auth/auth_exceptions.dart';
import 'package:mynotes/services/auth/auth_provider.dart';
import 'package:mynotes/services/auth/auth_user.dart';
import 'package:test/test.dart';
void main() {
group('Mock AUthenticatioin', () {
final provider = MockAuthProvider();
test('Should not be initialized to begin with', () {
expect(provider.isInitialized, isFalse);
});
test('Cannot log out if not initialized', () {
expect(
provider.logOut(),
throwsA(const TypeMatcher<NotInitializedAuthException>()),
);
});
test('Should be able to initialize', () async {
await provider.initialize();
expect(provider.isInitialized, isTrue);
});
test('User should be null after initialization', () {
expect(provider.currentUser, isNull);
});
test(
'Should be able to initialize in less than 2 seconds',
() async {
//final stopwatch = Stopwatch()..start();
await provider.initialize();
expect(provider.isInitialized, isTrue);
//expect(stopwatch.elapsed, lessThan(const Duration(seconds: 2)));
},
timeout: const Timeout(
Duration(seconds: 2),
),
);
// is timer better than stopwatch?
// Stopwatch is better for measuring elapsed time in Dart because it is more accurate than Timer.
test('Create user should delegate to login function', () async {
final badEmailUser = provider.createUser(
email: 'foo@bar.com',
password: 'anypassword',
);
expect(badEmailUser,
throwsA(const TypeMatcher<UserNotFoundAuthException>()));
final basPasswordUser = provider.createUser(
email: 'someone@wow.com',
password: 'foobar',
);
expect(basPasswordUser,
throwsA(const TypeMatcher<WrongPasswordAuthException>()));
final user = await provider.createUser(email: 'foo', password: 'bar');
expect(provider.currentUser, user);
expect(user.isEmailVerified, isFalse);
});
test('Login user should be able to get verified', () async {
provider.sendEmailVerification();
final user = provider.currentUser;
expect(user, isNotNull);
expect(user!.isEmailVerified, isTrue);
});
test('Should be able to log out and login in again', () async {
await provider.logOut();
await provider.logIn(
email: 'foo',
password: 'bar',
);
final user = provider.currentUser;
expect(user, isNotNull);
});
});
}
class NotInitializedAuthException implements Exception {}
class MockAuthProvider implements AuthProvider {
AuthUser? _user;
var _isInitialized = false;
bool get isInitialized => _isInitialized;
@override
Future<AuthUser> createUser({
required String email,
required String password,
}) async {
if (!isInitialized) throw NotInitializedAuthException();
await Future.delayed(const Duration(seconds: 1));
return logIn(
email: email,
password: password,
);
}
@override
// TODO: implement currentUser
AuthUser? get currentUser => _user;
@override
Future<void> initialize() async {
await Future.delayed(const Duration(seconds: 1));
_isInitialized = true;
}
@override
Future<AuthUser> logIn({
required String email,
required String password,
}) {
if (!isInitialized) throw NotInitializedAuthException();
if (email == 'foo@bar.com') throw UserNotFoundAuthException();
if (password == 'foobar') throw WrongPasswordAuthException();
var user = AuthUser(isEmailVerified: false);
_user = user;
return Future.value(user);
// what is the difference between Future.value and Future.delayed?
// Future.value returns a Future that completes with the given value.
// Future.delayed returns a Future that completes after the given duration with the given value.
// why do we need to return a Future?
// The return type of the method is Future<AuthUser>, so we need to return a Future that completes with the AuthUser object.
}
@override
Future<void> logOut() async {
if (!isInitialized) throw NotInitializedAuthException();
if (_user == null) throw UserNotLoggedInAuthException();
await Future.delayed(const Duration(seconds: 1));
_user = null;
}
@override
Future<void> sendEmailVerification() async {
if (!isInitialized) throw NotInitializedAuthException();
final user = _user;
if (user == null) throw UserNotFoundAuthException();
var newUser = AuthUser(isEmailVerified: true);
_user = newUser;
}
}

View File

@ -1,30 +0,0 @@
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility in the flutter_test package. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mynotes/main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(const MyApp());
// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}