Skip to content

Commit

Permalink
Merge pull request #80 from CityOfLosAngeles/unit-testing
Browse files Browse the repository at this point in the history
Unit Testing Pt. I
  • Loading branch information
cbhernan authored Feb 22, 2024
2 parents af14c07 + 1d2385c commit 457b25d
Show file tree
Hide file tree
Showing 15 changed files with 482 additions and 269 deletions.
13 changes: 9 additions & 4 deletions .github/workflows/dart_analyzer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:

steps:
- name: Check out code
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Setup Dart
uses: dart-lang/setup-dart@v1
Expand All @@ -37,8 +37,13 @@ jobs:
- run: flutter pub get

# Unit Tests
#- name: Run Flutter Tests
# run: flutter test
- name: Run Flutter Tests
run: flutter test --coverage

- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}

# See output in console until we have access
# to sarif file
Expand Down Expand Up @@ -74,7 +79,7 @@ jobs:
image: returntocorp/semgrep

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- run: semgrep ci
env:
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Angeleno - Profile
<a href="https://github.com/CityOfLosAngeles/angeleno-my-account-flutter/actions"><img src="https://github.com/CityOfLosAngeles/angeleno-my-account-flutter/workflows/Dart%20Analyzer/badge.svg" alt="Dart Analyzer Status"></a>
<a href="https://github.com/CityOfLosAngeles/angeleno-my-account-flutter/actions"><img src="https://github.com/CityOfLosAngeles/angeleno-my-account-flutter/workflows/Flutter%20Unit%20Tests/badge.svg" alt="Flutter Tests Status"></a>
[![codecov](https://codecov.io/gh/CityOfLosAngeles/angeleno-my-account/graph/badge.svg?token=ILNR5XOM40)](https://codecov.io/gh/CityOfLosAngeles/angeleno-my-account)

## Getting Started
This branch should act as our main branch until we have a working Minimum Viable Product (MVP) to merge into the `main` branch. To start development you'll `git clone` this repo; after cloning you'll by default be on the main branch, but you can `git checkout mvp-skeleton` to switch to the branch with the code being worked on. From the `mvp-skeleton` branch, you can branch off to work on your own work/issue by running `git checkout -b your-branch-name`. When opening the pull request for your work, make sure the branch is being merged into `mvp-skeleton` and not `main`.
Expand Down
3 changes: 1 addition & 2 deletions lib/controllers/api_implementation.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'dart:convert';
import 'dart:io';
// ignore: avoid_web_libraries_in_flutter
import 'dart:html';

import 'package:angeleno_project/models/api_exception.dart';
import 'package:angeleno_project/models/api_response.dart';
import 'package:angeleno_project/models/password_reset.dart';
Expand Down
37 changes: 20 additions & 17 deletions lib/controllers/user_provider.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// ignore: avoid_web_libraries_in_flutter
import 'dart:html' as html;
import 'package:angeleno_project/models/user.dart';
import 'package:auth0_flutter/auth0_flutter.dart';
import 'package:auth0_flutter/auth0_flutter_web.dart';
Expand All @@ -13,19 +11,20 @@ class UserProvider extends ChangeNotifier {
bool _isEditing = false;

UserProvider() {
auth0Web.onLoad().then((final credentials) async {
if (credentials != null
&& credentials.expiresAt.isAfter(DateTime.now())) {

setUser(credentials.user);
_cleanUser = User.copy(_user!);

} else {
await auth0Web.loginWithRedirect(redirectUrl: redirectUri);
}

html.window.history.pushState(null, 'home', '/');
});
// temporary, to skip tests
if (auth0Domain.isNotEmpty) {
auth0Web.onLoad().then((final credentials) async {
if (credentials != null
&& await auth0Web.hasValidCredentials()) {

setUser(credentials.user);
setCleanUser(_user!);

} else {
await auth0Web.loginWithRedirect(redirectUrl: redirectUri);
}
});
}
}

void setUser(final UserProfile user) {
Expand All @@ -44,8 +43,6 @@ class UserProvider extends ChangeNotifier {
final primaryAddress = metadata['addresses']?['primary'];

if (primaryAddress != null) {
zip = primaryAddress['zip'] != null ?
primaryAddress['zip'] as String : '';
address = primaryAddress['address'] != null ?
primaryAddress['address'] as String : '';
address2 = primaryAddress['address2'] != null ?
Expand All @@ -54,6 +51,8 @@ class UserProvider extends ChangeNotifier {
primaryAddress['city'] as String : '';
state = primaryAddress['state'] != null ?
primaryAddress['state'] as String : '';
zip = primaryAddress['zip'] != null ?
primaryAddress['zip'] as String : '';
}

phone = metadata['phone'] as String;
Expand All @@ -76,6 +75,10 @@ class UserProvider extends ChangeNotifier {
notifyListeners();
}

void setCleanUser(final User user) {
_cleanUser = User.copy(user);
}

void toggleEditing() {
_isEditing = !_isEditing;
notifyListeners();
Expand Down
29 changes: 21 additions & 8 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import 'package:angeleno_project/utils/constants.dart';
import 'package:angeleno_project/views/screens/home_screen.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:url_strategy/url_strategy.dart';


void main() {
setPathUrlStrategy();
runApp(
MultiProvider(
providers: [
Expand All @@ -23,12 +25,23 @@ class MyApp extends StatelessWidget {

@override
Widget build(final BuildContext context) => MaterialApp(
title: 'Angeleno - Account',
debugShowCheckedModeBanner: false,
theme: ThemeData(
useMaterial3: true,
colorScheme: colorScheme
),
home: const MyHomePage(),
);
title: 'Angeleno - Account',
debugShowCheckedModeBanner: false,
theme: ThemeData(
useMaterial3: true,
colorScheme: colorScheme
),
onGenerateRoute: (final settings) {
final uri = Uri.parse(settings.name!);

if (uri.path == '/' && uri.queryParameters.isNotEmpty) {
return MaterialPageRoute(builder: (final context) => const MyHomePage(),
settings: const RouteSettings(name: '/'));
}

return MaterialPageRoute(builder: (final context) => const MyHomePage(),
settings: const RouteSettings(name: '/'));
},
home: const MyHomePage()
);
}
3 changes: 1 addition & 2 deletions lib/views/dialogs/authenticator.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// ignore: avoid_web_libraries_in_flutter
import 'dart:html';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:qr_flutter/qr_flutter.dart';
Expand Down
3 changes: 1 addition & 2 deletions lib/views/dialogs/mobile.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// ignore: avoid_web_libraries_in_flutter
import 'dart:html';
import 'dart:io';
import 'package:angeleno_project/controllers/api_implementation.dart';
import 'package:flutter/material.dart';
import 'package:intl_phone_number_input/intl_phone_number_input.dart';
Expand Down
3 changes: 1 addition & 2 deletions lib/views/screens/advanced_security_screen.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// ignore: avoid_web_libraries_in_flutter
import 'dart:html';
import 'dart:io';
import 'dart:convert';

import 'package:angeleno_project/controllers/api_implementation.dart';
Expand Down
1 change: 0 additions & 1 deletion lib/views/screens/home_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ class MyHomePage extends StatefulWidget {
}

class _MyHomePageState extends State<MyHomePage> {

final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
late UserProvider userProvider;
late User user;
Expand Down
106 changes: 55 additions & 51 deletions lib/views/screens/password_screen.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// ignore: avoid_web_libraries_in_flutter
import 'dart:html';
import 'dart:io';

import 'package:angeleno_project/models/password_reset.dart';
import 'package:angeleno_project/utils/constants.dart';
Expand Down Expand Up @@ -84,7 +83,7 @@ class _PasswordScreenState extends State<PasswordScreen> {

bool enablePasswordSubmit() => !(currentPassword.trim() != ''
&& newPassword.trim() != '' && passwordMatch.trim() != ''
&& acceptableLength);
&& acceptableLength && passwordMatch == newPassword);

@override
Widget build(final BuildContext context) {
Expand All @@ -96,6 +95,7 @@ class _PasswordScreenState extends State<PasswordScreen> {
TextFormField(
obscureText: !viewPassword,
autocorrect: false,
key: const Key('old_password'),
enableSuggestions: false,
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (final value) {
Expand All @@ -105,18 +105,19 @@ class _PasswordScreenState extends State<PasswordScreen> {
return null;
},
decoration: InputDecoration(
border: const OutlineInputBorder(),
labelText: 'Current Password',
suffixIcon: IconButton(
onPressed: () {
setState(() {
viewPassword = !viewPassword;
});
},
icon: Icon(
viewPassword ? Icons.visibility : Icons.visibility_off
)
border: const OutlineInputBorder(),
labelText: 'Current Password',
suffixIcon: IconButton(
key: const Key('toggle_old_password'),
onPressed: () {
setState(() {
viewPassword = !viewPassword;
});
},
icon: Icon(
viewPassword ? Icons.visibility_off : Icons.visibility
)
)
),
onChanged: (final value) {
setState(() {
Expand All @@ -129,6 +130,7 @@ class _PasswordScreenState extends State<PasswordScreen> {
TextFormField(
obscureText: !viewNewPassword,
autocorrect: false,
key: const Key('new_password'),
enableSuggestions: false,
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (final value) {
Expand All @@ -144,18 +146,19 @@ class _PasswordScreenState extends State<PasswordScreen> {
return null;
},
decoration: InputDecoration(
border: const OutlineInputBorder(),
labelText: 'New Password',
suffixIcon: IconButton(
onPressed: () {
setState(() {
viewNewPassword = !viewNewPassword;
});
},
icon: Icon(
viewNewPassword ? Icons.visibility : Icons.visibility_off
)
border: const OutlineInputBorder(),
labelText: 'New Password',
suffixIcon: IconButton(
key: const Key('toggle_new_password'),
onPressed: () {
setState(() {
viewNewPassword = !viewNewPassword;
});
},
icon: Icon(
viewNewPassword ? Icons.visibility_off : Icons.visibility
)
)
),
onChanged: (final value) {
setState(() {
Expand All @@ -167,25 +170,26 @@ class _PasswordScreenState extends State<PasswordScreen> {
),
const SizedBox(height: 5),
Row(
children: [
const Text('Password must:',
style: TextStyle(fontWeight: FontWeight.bold)
),
const SizedBox(width: 10),
Text(
'Be at least $minPasswordLength characters',
style: TextStyle(
color: acceptableLength
? colorScheme.primary
: colorScheme.error
)
children: [
const Text('Password must:',
style: TextStyle(fontWeight: FontWeight.bold)
),
const SizedBox(width: 10),
Text(
'Be at least $minPasswordLength characters',
style: TextStyle(
color: acceptableLength
? colorScheme.primary
: colorScheme.error
)
],
),
)
],
),
const SizedBox(height: 10.0),
TextFormField(
obscureText: !viewPasswordMatch,
autocorrect: false,
key: const Key('match_password'),
enableSuggestions: false,
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (final value) {
Expand All @@ -198,19 +202,19 @@ class _PasswordScreenState extends State<PasswordScreen> {
return null;
},
decoration: InputDecoration(
border: const OutlineInputBorder(),
labelText: 'Confirm New Password',
suffixIcon: IconButton(
onPressed: () {
setState(() {
viewPasswordMatch = !viewPasswordMatch;
});
},
icon: Icon(
viewPasswordMatch ? Icons.visibility : Icons
.visibility_off
)
border: const OutlineInputBorder(),
labelText: 'Confirm New Password',
suffixIcon: IconButton(
key: const Key('toggle_match_password'),
onPressed: () {
setState(() {
viewPasswordMatch = !viewPasswordMatch;
});
},
icon: Icon(
viewPasswordMatch ? Icons.visibility_off : Icons.visibility
)
)
),
onChanged: (final value) {
setState(() {
Expand Down
Loading

0 comments on commit 457b25d

Please sign in to comment.