This commit is contained in:
J. A. Messias 2025-01-13 16:11:06 -03:00
parent 08016c53b8
commit a8c7897eff
19 changed files with 735 additions and 588 deletions

View File

@ -1,2 +1,2 @@
gradle 8.10.2
kotlin 2.0.20
kotlin 1.8.22

View File

@ -53,9 +53,15 @@ android {
versionName flutterVersionName
multiDexEnabled true
consumerProguardFiles 'proguard-rules.pro'
testInstrumentationRunner "pl.leancode.patrol.PatrolJUnitRunner"
testInstrumentationRunnerArguments clearPackageData: "true"
}
testOptions {
execution "ANDROIDX_TEST_ORCHESTRATOR"
}
compileOptions {
coreLibraryDesugaringEnabled true
@ -94,6 +100,8 @@ android {
debug {
signingConfig signingConfigs.debug
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
minifyEnabled false
shrinkResources false
}
}
}
@ -113,6 +121,11 @@ dependencies {
}
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
androidTestUtil "androidx.test:orchestrator:1.5.1"
// androidTestImplementation 'androidx.test:runner:1.4.0'
// androidTestImplementation 'androidx.test:rules:1.4.0'
}
apply plugin: 'com.google.gms.google-services'

View File

@ -0,0 +1,36 @@
package com.freaccess.hub;
import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import pl.leancode.patrol.PatrolJUnitRunner;
@RunWith(Parameterized.class)
public class MainActivityTest {
private final String dartTestName;
public MainActivityTest(String dartTestName) {
this.dartTestName = dartTestName;
}
@Parameters(name = "{0}")
public static Object[] testCases() {
PatrolJUnitRunner instrumentation = (PatrolJUnitRunner) InstrumentationRegistry.getInstrumentation();
// replace "MainActivity.class" with "io.flutter.embedding.android.FlutterActivity.class"
// if in AndroidManifest.xml in manifest/application/activity you have
// android:name="io.flutter.embedding.android.FlutterActivity"
instrumentation.setUp(MainActivity.class);
instrumentation.waitForPatrolAppService();
return instrumentation.listDartTests();
}
@Test
public void runDartTest() {
PatrolJUnitRunner instrumentation = (PatrolJUnitRunner) InstrumentationRegistry.getInstrumentation();
instrumentation.runDartTest(dartTestName);
}
}

View File

@ -1,6 +1,6 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '2.0.20' // Replace with the latest version
ext.kotlin_version = '1.8.22'
ext.gradle_version = '8.6.0' // Replace with the latest version
ext.google_services_version = '4.4.2' // Replace with the latest version
repositories {
@ -8,9 +8,11 @@ buildscript {
mavenCentral()
}
dependencies {
classpath "com.android.tools.build:gradle:$gradle_version" // Use a versão do Gradle que corresponde à sua configuração
classpath "com.android.tools.build:gradle:$gradle_version"
// Use a versão do Gradle que corresponde à sua configuração
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "com.google.gms:google-services:$google_services_version" // Google Services plugin
classpath "com.google.gms:google-services:$google_services_version"
// Google Services plugin
}
}

View File

@ -20,7 +20,7 @@ plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id 'com.android.application' version '8.6.0' apply false
id 'com.android.library' version '8.6.0' apply false
id 'org.jetbrains.kotlin.android' version '2.0.20' apply false
id 'org.jetbrains.kotlin.android' version '1.8.22' apply false
// START: FlutterFire Configuration
@ -30,7 +30,6 @@ plugins {
// id "org.jetbrains.kotlin.android" version "1.8.10" apply false
}
include ":app"

View File

@ -1,8 +1,10 @@
import 'dart:collection';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:hub/components/molecular_components/throw_exception/throw_exception_widget.dart';
import 'package:hub/components/organism_components/bottom_arrow_linked_locals_component/bottom_arrow_linked_locals_component_widget.dart';
import 'package:hub/components/templates_components/card_item_template_component/card_item_template_component_widget.dart';
import 'package:hub/features/backend/api_requests/index.dart';
@ -16,6 +18,7 @@ import 'package:hub/initialization.dart';
import 'package:hub/main.dart';
import 'package:integration_test/integration_test.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:patrol_finders/patrol_finders.dart';
part 'auth_test.dart';
part 'home_test.dart';
@ -30,12 +33,15 @@ part 'storage_test.dart';
part 'utils_test.dart';
part 'welcome_test.dart';
late PatrolTester $;
void main() {
//init integration test
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
// WelcomeTest.signInToSignUp();
// WelcomeTest.signUpToSignIn();
//
// //
// AuthenticationTest.signIn();
// AuthenticationTest.signUp();
// AuthenticationTest.signOut();
@ -43,7 +49,7 @@ void main() {
// ModularizationTest.switchLicense();
// ModularizationTest.containLicense();
//
// MenuTest.navToEntries();
MenuTest.navToEntries();
// MenuTest.containEntries();
// MenuTest.labels2AppbarConsistency();
//

View File

@ -1,145 +1,143 @@
part of 'app_test.dart';
class AuthenticationTest {
static Future signIn() async {
_setUpUnlogged();
testWidgets('Sign-In with erro@exemplo.com', //
(WidgetTester tester) async {
await tester.pumpWidget(const App());
tester.printToConsole('AuthenticationTest - Navigate Sign-In');
await _navigateToSignIn(tester);
await _auth({
static Future<void> signIn() async {
patrolWidgetTest(
'Sign-In with erro@exemplo.com',
(PatrolTester tester) async {
$ = tester;
final PatrolFinder throwsException = $(Dialog).$(ThrowExceptionWidget);
final Map<String, String> credentials = {
'emailTextFormField': 'erro@exemplo.com',
'passwordTextFormField': '12345678'
}, tester);
await tester.pumpAndSettle();
'passwordTextFormField': '12345678',
};
await _unlogged();
await $.pumpWidgetAndSettle(const App());
await Future.delayed(const Duration(milliseconds: 500));
return;
});
_tearDown();
await _navigateToSignIn($);
await _auth(credentials, $, throwsException);
await Future.delayed(const Duration(milliseconds: 500));
},
);
_setUpUnlogged();
testWidgets('Sign-In with email_app@exemplo.com',
(WidgetTester tester) async {
await tester.pumpWidget(const App());
tester.printToConsole('AuthenticationTest - Navigate Sign-In');
await _navigateToSignIn(tester);
await _auth({
patrolWidgetTest(
'Sign-In with email_app@exemplo.com',
(PatrolTester tester) async {
$ = tester;
final PatrolFinder throwsException = $(Dialog).$(ThrowExceptionWidget);
final Map<String, String> credentials = {
'emailTextFormField': 'email_app@exemplo.com',
'passwordTextFormField': '12345678'
}, tester);
'passwordTextFormField': '12345678',
};
await _unlogged();
await $.pumpWidgetAndSettle(const App());
await _navigateToSignIn($);
await _auth(credentials, $, throwsException);
await Future.delayed(const Duration(milliseconds: 500));
return;
});
_tearDown();
},
);
}
static Future signUp() async {
_setUpUnlogged();
testWidgets('Sign Up - credenciais já registradas',
(WidgetTester tester) async {
var credentials = {
static Future<void> signUp() async {
patrolWidgetTest(
'Sign Up - credenciais já registradas',
(PatrolTester tester) async {
$ = tester;
final PatrolFinder throwsException = $(Dialog).$(ThrowExceptionWidget);
final Map<String, String> credentials = {
'nameTextFormField': 'app',
'emailTextFormField': 'email_app@exemplo.com',
'passwordTextFormField': '12345678'
'passwordTextFormField': '12345678',
};
await tester.pumpWidget(const App());
tester.printToConsole('AuthenticationTest - Navigate Sign-Up');
await _navigateToSignUp(tester);
await _auth(credentials, tester);
await tester.pumpAndSettle();
await _unlogged();
await $.pumpWidgetAndSettle(const App());
await _navigateToSignUp($);
await _auth(credentials, $, throwsException);
await Future.delayed(const Duration(milliseconds: 500));
return;
});
_tearDown();
},
);
_setUpUnlogged();
testWidgets('Sign Up - credenciais novas', //
(WidgetTester tester) async {
late Map<String, String> credentials;
var name = ff.randomString(7, 7, true, true, true);
var email = '$name@example.com';
var password = '12345678';
credentials = {
patrolWidgetTest(
'Sign Up - credenciais novas',
(PatrolTester tester) async {
$ = tester;
final PatrolFinder throwsException = $(Dialog).$(ThrowExceptionWidget);
final name = _generateRandomString(7);
final email = '$name@example.com';
final password = '12345678';
final Map<String, String> credentials = {
'nameTextFormField': name,
'emailTextFormField': email,
'passwordTextFormField': password
'passwordTextFormField': password,
};
await tester.pumpWidget(const App());
tester.printToConsole('AuthenticationTest - Navigate Sign-Up');
await _navigateToSignUp(tester);
await _auth(credentials, tester);
await _unlogged();
await $.pumpWidgetAndSettle(const App());
await _navigateToSignUp($);
await _auth(credentials, $, throwsException);
await Future.delayed(const Duration(milliseconds: 500));
return;
});
_tearDown();
},
);
}
static Future signOut() async {
_setUpLogged();
testWidgets('Deslogar da Conta', (WidgetTester tester) async {
await tester.pumpWidget(const App());
final Finder drawerButton = find.byIcon(Icons.menu_rounded);
await tester.pumpAndSettle();
await tester.tap(drawerButton);
await tester.pumpAndSettle();
final Finder signOutButton = find.byIcon(Icons.exit_to_app);
await tester.pumpAndSettle();
await tester.tap(signOutButton);
await tester.pumpAndSettle();
static Future<void> signOut() async {
patrolWidgetTest(
'Deslogar da Conta',
(PatrolTester tester) async {
$ = tester;
await _logged();
await $.pumpWidgetAndSettle(const App());
await $.waitUntilVisible($(MenuStaggeredView));
await Future.delayed(const Duration(milliseconds: 500));
return;
});
_tearDown();
await $(Icons.menu_rounded).tap();
await $.waitUntilVisible($(MenuListView));
await $(Icons.exit_to_app)
.waitUntilVisible()
.tap(settlePolicy: SettlePolicy.trySettle);
await Future.delayed(const Duration(milliseconds: 500));
},
);
}
static Future recovery() async {}
static Future<void> recovery() async {}
}
Future<void> _auth(
Map<String, dynamic> credentials, WidgetTester tester) async {
await _enterCredentials(credentials, tester);
await _submit('SubmitButtonWidget', tester);
}
Future<void> _send(
Map<String, dynamic> credentials, WidgetTester tester) async {
await _enterCredentials(credentials, tester);
await _submit('SendButtonWidget', tester);
Map<String, String> credentials,
PatrolTester $,
PatrolFinder throwsException,
) async {
await _enterCredentials(credentials, $);
await _submit('SubmitButtonWidget', $, throwsException);
}
Future<void> _enterCredentials(
Map<String, dynamic> credentials, WidgetTester tester) async {
await tester.pumpAndSettle();
Map<String, String> credentials,
PatrolTester $,
) async {
for (var entry in credentials.entries) {
final Finder field = find.byKey(ValueKey<String>(entry.key));
await tester.pumpAndSettle();
expect(field, findsOneWidget);
await tester.enterText(field, entry.value);
await tester.pumpAndSettle();
await $(ValueKey(entry.key)).enterText(entry.value);
await $.pumpAndSettle();
}
await tester.pumpAndSettle();
}
Future<void> _submit(String key, WidgetTester tester) async {
await tester.pumpAndSettle();
final Finder submitButton = find.byKey(ValueKey<String>(key));
await tester.pumpAndSettle();
if (submitButton.evaluate().isNotEmpty) {
await tester.tap(submitButton);
}
final Finder throwExceptionWidget =
find.byKey(const ValueKey<String>('ThrowExceptionWidget'));
if (throwExceptionWidget.evaluate().isNotEmpty) {
await tester.pumpAndSettle();
await tester.ensureVisible(throwExceptionWidget);
await tester.tap(throwExceptionWidget);
await tester.pumpAndSettle();
Future<void> _submit(
String key, PatrolTester $, PatrolFinder throwsException) async {
await $(ValueKey(key)).tap();
if ($(ValueKey('ThrowExceptionWidget')).exists) {
// expect(throwsException, findsOneWidget);
await $(ValueKey('ThrowExceptionWidget')).tap();
} else {
await _navigateBackUsingSystemGesture();
_navigateBackUsingSystemGesture();
}
}
String _generateRandomString(int length) {
const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
final rand = Random();
return List.generate(length, (index) => chars[rand.nextInt(chars.length)])
.join();
}

View File

@ -2,25 +2,26 @@ part of 'app_test.dart';
class LocalsTest {
static Future setLocal() async {
_setUpLogged();
testWidgets('Selecionar um local disponível', //
(WidgetTester tester) async {
await tester.pumpWidget(const App());
await tester.pumpAndSettle();
patrolWidgetTest(
'Selecionar um local disponível', //
(PatrolTester tester) async {
$ = tester;
await _logged();
await $.pumpWidget(const App());
await $.pumpAndSettle();
final Finder profileFinder =
find.byKey(const Key('AsyncLocalProfileComponentWidget_InkWell'));
expect(profileFinder, findsOneWidget);
await tester.tap(profileFinder);
await tester.pump(const Duration(seconds: 1));
await $.tap(profileFinder);
await $.pump(const Duration(seconds: 1));
final Finder bottomSheetFinder =
find.byType(BottomArrowLinkedLocalsComponentWidget);
expect(bottomSheetFinder, findsOneWidget);
await tester.ensureVisible(bottomSheetFinder);
await tester.pump(const Duration(seconds: 1));
await $.pump(const Duration(seconds: 1));
final Finder listViewFinder = find.descendant(
of: bottomSheetFinder,
@ -28,8 +29,7 @@ class LocalsTest {
);
expect(listViewFinder, findsOneWidget);
await tester.ensureVisible(listViewFinder);
await tester.pump(const Duration(seconds: 1));
await $.pump(const Duration(seconds: 1));
final Finder entriesFinder = find.descendant(
of: listViewFinder,
@ -38,33 +38,31 @@ class LocalsTest {
expect(entriesFinder, findsWidgets);
if (entriesFinder.evaluate().isNotEmpty) {
await tester.ensureVisible(entriesFinder.first);
await tester.tap(entriesFinder.first);
await tester.pumpAndSettle();
await $.tap(entriesFinder.first);
await $.pumpAndSettle();
}
await Future.delayed(const Duration(milliseconds: 500));
return;
});
_tearDown();
},
);
}
static Future unlinkLocal() async {
_setUpAllLogged();
testWidgets('Desvincular do local selecionado', //
(WidgetTester tester) async {
await tester.pumpWidget(const App());
await tester.pumpAndSettle();
await tester.pump(const Duration(seconds: 1));
patrolWidgetTest('Desvincular do local selecionado', //
(PatrolTester tester) async {
$ = tester;
await _logged();
await $.pumpWidget(const App());
await $.pumpAndSettle();
await $.pump(const Duration(seconds: 1));
final Finder gridView = find.byType(GridView);
await tester.ensureVisible(gridView);
final Finder entries = find.descendant(
of: gridView,
matching: find.byType(ButtonMenuItem),
);
await tester.pumpAndSettle();
await $.pumpAndSettle();
expect(entries, findsWidgets);
final Finder settings = find.descendant(
of: gridView,
@ -72,28 +70,25 @@ class LocalsTest {
);
expect(settings, findsOneWidget);
await tester.ensureVisible(settings);
await tester.tap(settings);
await tester.pumpAndSettle();
await $.tap(settings);
await $.pumpAndSettle();
final Finder unlinkButton = find.byIcon(Symbols.digital_out_of_home);
expect(unlinkButton, findsOneWidget);
await tester.ensureVisible(unlinkButton);
await tester.tap(unlinkButton);
await tester.pumpAndSettle();
await tester.tap(find.text('Sim'));
await tester.pump();
await tester.pump(const Duration(seconds: 1));
await tester.pump();
await $.tap(unlinkButton);
await $.pumpAndSettle();
await $.tap(find.text('Sim'));
await $.pump();
await $.pump(const Duration(seconds: 1));
await $.pump();
final Finder bottomSheetFinder =
find.byType(BottomArrowLinkedLocalsComponentWidget);
await tester.pump(const Duration(seconds: 1));
await $.pump(const Duration(seconds: 1));
expect(bottomSheetFinder, findsOneWidget);
await tester.pump(const Duration(seconds: 1));
await $.pump(const Duration(seconds: 1));
await tester.ensureVisible(bottomSheetFinder);
await tester.pump(const Duration(seconds: 1));
await $.pump(const Duration(seconds: 1));
final Finder listViewFinder = find.descendant(
of: bottomSheetFinder,
@ -101,8 +96,7 @@ class LocalsTest {
);
expect(listViewFinder, findsOneWidget);
await tester.ensureVisible(listViewFinder);
await tester.pump(const Duration(seconds: 1));
await $.pump(const Duration(seconds: 1));
final Finder entriesFinder = find.descendant(
of: listViewFinder,
@ -113,32 +107,35 @@ class LocalsTest {
return;
});
testWidgets('Desvincular de um local já desvinculado', //
(WidgetTester tester) async {
await tester.pumpWidget(const App());
patrolWidgetTest(
'Desvincular de um local já desvinculado', //
(PatrolTester tester) async {
$ = tester;
await $.pumpWidget(const App());
try {
await tester.pumpAndSettle(
const Duration(seconds: 2),
EnginePhase.sendSemanticsUpdate,
const Duration(seconds: 2),
await $.pumpAndSettle(
// const Duration(seconds: 2),
// EnginePhase.sendSemanticsUpdate,
// const Duration(seconds: 2),
);
throw Exception('Local está vinculado');
} catch (e) {
await Future.delayed(const Duration(milliseconds: 500));
return;
}
});
_tearDownAll();
},
);
}
static Future attachLocal() async {
_setUpAllLogged();
testWidgets('Selecionar um local disponível', //
(WidgetTester tester) async {
await tester.pumpWidget(const App());
patrolWidgetTest(
'Selecionar um local disponível', //
(PatrolTester tester) async {
$ = tester;
await _logged();
await $.pumpWidget(const App());
late Map<String, String> credentials;
final PatrolFinder throwsException = $('');
var name = ff.randomString(7, 7, true, true, true);
var email = '$name@example.com';
@ -149,23 +146,22 @@ class LocalsTest {
'passwordTextFormField': password
};
await tester.pumpWidget(const App());
await _navigateToSignUp(tester);
await _auth(credentials, tester);
await $.pumpWidget(const App());
await _navigateToSignUp($);
await _auth(credentials, $, throwsException);
credentials = {
'emailTextFormField': email,
'passwordTextFormField': password
};
await _auth(credentials, tester);
await _auth(credentials, $, throwsException);
await tester.pumpAndSettle();
await $.pumpAndSettle();
await StorageHelper() //
.set(ProfileStorageKey.clientUUID.key, '7');
await tester.pumpAndSettle();
await $.pumpAndSettle();
await Future.delayed(const Duration(milliseconds: 500));
return;
});
_tearDownAll();
},
);
}
}

View File

@ -2,11 +2,13 @@ part of 'app_test.dart';
class MenuTest {
static Future labels2AppbarConsistency() async {
_setUpAllLogged();
testWidgets('As labels dos menuItems correspondem aos títulos das AppBars?',
(WidgetTester tester) async {
await tester.pumpWidget(const App());
await tester.pumpAndSettle();
patrolWidgetTest(
'As labels dos menuItems correspondem aos títulos das AppBars?', //
(PatrolTester tester) async {
$ = tester;
await _logged();
await $.pumpWidget(const App());
await $.pumpAndSettle();
final List<String> routes = MenuEntry.entries
.where((entry) => entry.key != 'FRE-HUB-LOGOUT')
@ -17,8 +19,6 @@ class MenuTest {
.map((entry) => entry.name)
.toList();
tester.printToConsole(routes.toString());
final LinkedHashMap<String, String> routesTitles =
LinkedHashMap.fromIterables(
routes,
@ -27,44 +27,45 @@ class MenuTest {
for (final entry in routesTitles.entries) {
final String route = entry.key;
final String title = entry.value;
tester.printToConsole('Start: $title');
if (route == '/petsPage') continue;
if (route == '/fastPassPage') continue;
if (route == '/reservation') continue;
await tester.pumpAndSettle();
await $.pumpAndSettle();
ff.navigatorKey.currentContext!.go(route);
await tester.pumpAndSettle();
await $.pumpAndSettle();
Future.delayed(const Duration(milliseconds: 500));
final Finder appBar = find.text(title);
await tester.pumpAndSettle();
await $.pumpAndSettle();
expect(appBar, findsOneWidget);
await tester.pumpAndSettle();
tester.printToConsole('Finish: $title');
await $.pumpAndSettle();
}
await Future.delayed(const Duration(milliseconds: 500));
return;
});
},
);
}
static Future containEntries() async {
_setUpAllLogged();
testWidgets('HomeMenu contém seus itens?', (WidgetTester tester) async {
await tester.pumpWidget(const App());
await tester.pumpAndSettle();
patrolWidgetTest(
'HomeMenu contém seus itens?', //
(PatrolTester tester) async {
$ = tester;
await _logged();
await $.pumpWidget(const App());
await $.pumpAndSettle();
await Future.delayed(const Duration(seconds: 1));
final Finder gridView = find.byType(GridView);
await tester.pumpAndSettle();
await tester.ensureVisible(gridView);
await tester.pumpAndSettle();
await $.pumpAndSettle();
await $.pumpAndSettle();
final Finder gridEntries = find.descendant(
of: gridView,
matching: find.byType(ButtonMenuItem),
);
await tester.pumpAndSettle();
await $.pumpAndSettle();
expect(gridEntries, findsWidgets);
final List<String?> menuKeys = gridEntries
@ -79,38 +80,41 @@ class MenuTest {
.where((key) => key != null)
.toList();
await tester.pumpAndSettle();
await $.pumpAndSettle();
final List<MenuEntry> entries = MenuEntry.entries;
await tester.pumpAndSettle();
await $.pumpAndSettle();
final List<String> entriesKey = entries
.where((entry) => entry.types.contains(MenuEntryType.Home))
.map((entry) => entry.key)
.toList();
await tester.pumpAndSettle();
await $.pumpAndSettle();
expect(entriesKey, containsAll(menuKeys));
await Future.delayed(const Duration(milliseconds: 500));
return;
});
},
);
testWidgets('DrawerMenu contém seus itens?', (WidgetTester tester) async {
await tester.pumpWidget(const App());
await tester.pumpAndSettle();
patrolWidgetTest(
'DrawerMenu contém seus itens?', //
(PatrolTester tester) async {
$ = tester;
await _logged();
await $.pumpWidget(const App());
await $.pumpAndSettle();
await Future.delayed(const Duration(seconds: 1));
final Finder drawerButton = find.byIcon(Icons.menu_rounded);
await tester.pumpAndSettle();
await tester.tap(drawerButton);
await tester.pumpAndSettle();
await $.pumpAndSettle();
await $.tap(drawerButton);
await $.pumpAndSettle();
final Finder gridView = find.byType(ListView);
await tester.pumpAndSettle();
await tester.ensureVisible(gridView);
await tester.pumpAndSettle();
await $.pumpAndSettle();
final Finder gridEntries = find.descendant(
of: gridView,
matching: find.byType(CardMenuItem),
);
await tester.pumpAndSettle();
await $.pumpAndSettle();
expect(gridEntries, findsWidgets);
final List<String?> menuKeys = gridEntries
@ -125,41 +129,54 @@ class MenuTest {
.where((key) => key != null)
.toList();
await tester.pumpAndSettle();
await $.pumpAndSettle();
final List<MenuEntry> entries = MenuEntry.entries;
await tester.pumpAndSettle();
await $.pumpAndSettle();
final List<String> entriesKey = entries
.where((entry) => entry.types.contains(MenuEntryType.Drawer))
.map((entry) => entry.key)
.toList();
await tester.pumpAndSettle();
await $.pumpAndSettle();
expect(entriesKey, containsAll(menuKeys));
await Future.delayed(const Duration(milliseconds: 500));
return;
});
_tearDownAll();
},
);
}
static Future navToEntries() async {
_setUpAllLogged();
testWidgets('Navegação entre items do Menu', (WidgetTester tester) async {
tester = tester;
await tester.pumpWidget(const App());
await tester.pumpAndSettle();
patrolWidgetTest(
'Navegação entre items do Menu',
(PatrolTester tester) async {
$ = tester;
await _logged();
await $.pumpWidgetAndSettle(const App());
await $.waitUntilVisible($(MenuStaggeredView));
final PatrolFinder profile =
$(const Key('AsyncLocalProfileComponentWidget_InkWell'));
await $(profile)
.waitUntilVisible()
.tap(settlePolicy: SettlePolicy.noSettle);
await $.waitUntilVisible($(BottomArrowLinkedLocalsComponentWidget));
final PatrolFinder local = $('FRE ACCESS DEMO');
await $(local)
.waitUntilVisible()
.tap(settlePolicy: SettlePolicy.trySettle);
await $.waitUntilVisible($(MenuStaggeredView));
final Finder gridView = find.byType(GridView);
await tester.ensureVisible(gridView);
final Finder gridEntries = find.descendant(
of: gridView,
matching: find.byType(ButtonMenuItem),
);
await tester.pumpAndSettle();
await Future.delayed(const Duration(seconds: 5));
await $.pumpAndSettle();
expect(gridEntries, findsWidgets);
final int gridEntriesCount = gridEntries.evaluate().length;
for (int i = 0; i < gridEntriesCount; i++) {
await Future.delayed(const Duration(seconds: 1));
await tester.tap(gridEntries.at(i));
await tester.pumpAndSettle();
await Future.delayed(const Duration(seconds: 1));
@ -168,7 +185,7 @@ class MenuTest {
await Future.delayed(const Duration(milliseconds: 500));
return;
}
});
_tearDownAll();
},
);
}
}

View File

@ -2,49 +2,52 @@ part of 'app_test.dart';
class ModularizationTest {
static Future containLicense() async {
_setUpLogged();
testWidgets('Os modulos de licença está sendo processados?',
(WidgetTester tester) async {
await tester.pumpWidget(const App());
await tester.pumpAndSettle();
await Future.delayed(const Duration(seconds: 1));
patrolWidgetTest('Os modulos de licença está sendo processados?',
(PatrolTester tester) async {
$ = tester;
await _logged();
await $.pumpWidgetAndSettle(const App());
await $.waitUntilVisible($(MenuStaggeredView));
await tester.pumpAndSettle();
final LicenseRepository licenseRepository = LicenseRepositoryImpl();
final List<String> result = await licenseRepository.getLicense();
expect(result, isNotEmpty);
await tester.pumpAndSettle();
await $.pumpAndSettle();
final List<MenuEntry> entries = MenuEntry.entries;
await tester.pumpAndSettle();
final List<String> entriesKey = entries
.where((entry) => entry.types.contains(MenuEntryType.Home))
.map((entry) => '{key: ${entry.key}}')
.toList();
await tester.pumpAndSettle();
expect(result, containsAll(entriesKey));
await Future.delayed(const Duration(milliseconds: 500));
return;
});
_tearDown();
}
static Future switchLicense() async {
_setUpLogged();
testWidgets('Licença está sendo atualizada?', (WidgetTester tester) async {
await tester.pumpWidget(const App());
final Finder profile =
find.byKey(const Key('AsyncLocalProfileComponentWidget_InkWell'));
await tester.pumpAndSettle();
await tester.tap(profile);
await tester.pumpAndSettle();
final Finder local = find.text('FRE ACCESS DEMO');
await tester.pumpAndSettle();
await tester.tap(local);
await tester.pumpAndSettle();
await Future.delayed(const Duration(milliseconds: 500));
return;
});
_tearDown();
patrolWidgetTest(
'Licença está sendo atualizada?',
(PatrolTester tester) async {
$ = tester;
await _logged();
await $.pumpWidgetAndSettle(const App());
await $.waitUntilVisible($(MenuStaggeredView));
final PatrolFinder profile =
$(const Key('AsyncLocalProfileComponentWidget_InkWell'));
await $(profile)
.waitUntilVisible()
.tap(settlePolicy: SettlePolicy.noSettle);
await $.waitUntilVisible($(BottomArrowLinkedLocalsComponentWidget));
final PatrolFinder local = $('FRE ACCESS DEMO');
await $(local)
.waitUntilVisible()
.tap(settlePolicy: SettlePolicy.trySettle);
},
);
}
}

View File

@ -1,2 +1,27 @@
class PatrolTest {
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:patrol/patrol.dart';
void main() {
patrolTest(
'counter state is the same after going to home and switching apps',
($) async {
// Replace later with your app's main widget
await $.pumpWidgetAndSettle(
MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('app')),
backgroundColor: Colors.blue,
),
),
);
expect($('app'), findsOneWidget);
if (!Platform.isMacOS) {
await $.native.pressHome();
}
},
);
}

View File

@ -0,0 +1,86 @@
// GENERATED CODE - DO NOT MODIFY BY HAND AND DO NOT COMMIT TO VERSION CONTROL
// ignore_for_file: type=lint, invalid_use_of_internal_member
import 'dart:async';
import 'package:flutter_test/flutter_test.dart';
import 'package:patrol/patrol.dart';
import 'package:patrol/src/native/contracts/contracts.dart';
import 'package:test_api/src/backend/invoker.dart';
// START: GENERATED TEST IMPORTS
import 'app_test.dart' as app_test;
// END: GENERATED TEST IMPORTS
Future<void> main() async {
// This is the entrypoint of the bundled Dart test.
//
// Its responsibilies are:
// * Running a special Dart test that runs before all the other tests and
// explores the hierarchy of groups and tests.
// * Hosting a PatrolAppService, which the native side of Patrol uses to get
// the Dart tests, and to request execution of a specific Dart test.
//
// When running on Android, the Android Test Orchestrator, before running the
// tests, makes an initial run to gather the tests that it will later run. The
// native side of Patrol (specifically: PatrolJUnitRunner class) is hooked
// into the Android Test Orchestrator lifecycle and knows when that initial
// run happens. When it does, PatrolJUnitRunner makes an RPC call to
// PatrolAppService and asks it for Dart tests.
//
// When running on iOS, the native side of Patrol (specifically: the
// PATROL_INTEGRATION_TEST_IOS_RUNNER macro) makes an initial run to gather
// the tests that it will later run (same as the Android). During that initial
// run, it makes an RPC call to PatrolAppSevice and asks it for Dart tests.
//
// Once the native runner has the list of Dart tests, it dynamically creates
// native test cases from them. On Android, this is done using the
// Parametrized JUnit runner. On iOS, new test case methods are swizzled into
// the RunnerUITests class, taking advantage of the very dynamic nature of
// Objective-C runtime.
//
// Execution of these dynamically created native test cases is then fully
// managed by the underlying native test framework (JUnit on Android, XCTest
// on iOS). The native test cases do only one thing - request execution of the
// Dart test (out of which they had been created) and wait for it to complete.
// The result of running the Dart test is the result of the native test case.
final nativeAutomator = NativeAutomator(config: NativeAutomatorConfig());
await nativeAutomator.initialize();
final binding = PatrolBinding.ensureInitialized(NativeAutomatorConfig());
final testExplorationCompleter = Completer<DartGroupEntry>();
// A special test to explore the hierarchy of groups and tests. This is a hack
// around https://github.com/dart-lang/test/issues/1998.
//
// This test must be the first to run. If not, the native side likely won't
// receive any tests, and everything will fall apart.
test('patrol_test_explorer', () {
// Maybe somewhat counterintuitively, this callback runs *after* the calls
// to group() below.
final topLevelGroup = Invoker.current!.liveTest.groups.first;
final dartTestGroup = createDartTestGroup(topLevelGroup,
tags: null,
excludeTags: null,
);
testExplorationCompleter.complete(dartTestGroup);
print('patrol_test_explorer: obtained Dart-side test hierarchy:');
reportGroupStructure(dartTestGroup);
});
// START: GENERATED TEST GROUPS
group('app_test', app_test.main);
// END: GENERATED TEST GROUPS
final dartTestGroup = await testExplorationCompleter.future;
final appService = PatrolAppService(topLevelDartTestGroup: dartTestGroup);
binding.patrolAppService = appService;
await runAppService(appService);
// Until now, the native test runner was waiting for us, the Dart side, to
// come alive. Now that we did, let's tell it that we're ready to be asked
// about Dart tests.
await nativeAutomator.markPatrolAppServiceReady();
await appService.testExecutionCompleted;
}

View File

@ -1,7 +1,6 @@
part of 'app_test.dart';
Future<void> _setUpLogged() async {
setUp(() async {
Future<void> _logged() async {
await initializeApp();
await StorageHelper() //
.set(SecureStorageKey.isLogged.value, 'true');
@ -19,13 +18,14 @@ Future<void> _setUpLogged() async {
.set(SecureStorageKey.password.value, '123456');
await StorageHelper() //
.set(LocalsStorageKey.isNewVersion.key, true);
await PhpGroup.resopndeVinculo.call(tarefa: 'A');
await LicenseRepositoryImpl().resetLicense();
});
await PhpGroup //
.resopndeVinculo
.call(tarefa: 'A');
await LicenseRepositoryImpl() //
.resetLicense();
}
Future<void> _setUpUnlogged() async {
setUp(() async {
Future<void> _unlogged() async {
await initializeApp();
await StorageHelper() //
.set(SecureStorageKey.isLogged.value, 'false');
@ -43,95 +43,16 @@ Future<void> _setUpUnlogged() async {
.set(SecureStorageKey.password.value, '');
await StorageHelper() //
.set(LocalsStorageKey.isNewVersion.key, true);
});
}
Future<void> _tearDownAll() async {
tearDownAll(() async {
await StorageHelper().clean(Storage.databaseStorage);
await StorageHelper().clean(Storage.secureStorage);
await StorageHelper().clean(Storage.sharedPreferences);
});
Future<void> _navigateToSignIn(PatrolTester $) async {
final signInButton = $(#toggleSignInPage);
await signInButton.tap();
}
Future<void> _tearDown() async {
tearDown(() async {
await StorageHelper().clean(Storage.databaseStorage);
await StorageHelper().clean(Storage.secureStorage);
await StorageHelper().clean(Storage.sharedPreferences);
});
}
Future<void> _setUpAllLogged() async {
setUpAll(() async {
await initializeApp().then((_) async {
await StorageHelper() //
.set(SecureStorageKey.isLogged.value, 'true');
await StorageHelper() //
.set(SecureStorageKey.haveLocal.value, 'true');
await StorageHelper() //
.set(ProfileStorageKey.devUUID.key, 'b5c3818753e76d85');
await StorageHelper() //
.set(ProfileStorageKey.userUUID.key, '649c45d7514a28.85876308');
await StorageHelper() //
.set(ProfileStorageKey.clientUUID.key, '7');
await StorageHelper() //
.set(SecureStorageKey.email.value, 'email_app@exemplo.com');
await StorageHelper() //
.set(SecureStorageKey.password.value, '123456');
await StorageHelper() //
.set(LocalsStorageKey.isNewVersion.key, true);
await PhpGroup.resopndeVinculo.call(tarefa: 'A');
});
await LicenseRepositoryImpl().resetLicense();
});
}
Future<void> _setUpAllUnlogged() async {
setUpAll(() async {
await initializeApp().then((_) async {
await StorageHelper() //
.set(SecureStorageKey.isLogged.value, 'false');
await StorageHelper() //
.set(SecureStorageKey.haveLocal.value, 'false');
await StorageHelper() //
.set(ProfileStorageKey.devUUID.key, '');
await StorageHelper() //
.set(ProfileStorageKey.userUUID.key, '');
await StorageHelper() //
.set(ProfileStorageKey.clientUUID.key, '');
await StorageHelper() //
.set(SecureStorageKey.email.value, '');
await StorageHelper() //
.set(SecureStorageKey.password.value, '');
await StorageHelper() //
.set(LocalsStorageKey.isNewVersion.key, true);
});
});
}
Future<void> _navigateToSignIn(WidgetTester tester) async {
await tester.pumpAndSettle();
final Finder navToSignIn =
find.byKey(const ValueKey<String>('toggleSignInPage'));
await tester.pumpAndSettle();
expect(navToSignIn, findsOneWidget);
await tester.pumpAndSettle();
if (navToSignIn.evaluate().isNotEmpty) {
await tester.tap(navToSignIn);
await tester.pumpAndSettle();
}
}
Future<void> _navigateToSignUp(WidgetTester tester) async {
await tester.pumpAndSettle();
final Finder navToSignUp =
find.byKey(const ValueKey<String>('toggleSignUpPage'));
await tester.pumpAndSettle();
if (navToSignUp.evaluate().isNotEmpty) {
await tester.tap(navToSignUp);
await tester.pumpAndSettle();
}
Future<void> _navigateToSignUp(PatrolTester $) async {
final signUpButton = $(#toggleSignUpPage);
await signUpButton.tap();
}
Future<void> _navigateBackUsingSystemGesture() async =>

View File

@ -2,36 +2,28 @@ part of 'app_test.dart';
class WelcomeTest {
static Future signInToSignUp() async {
_setUpAllUnlogged();
testWidgets('Sign-In to Sign-Up', (WidgetTester tester) async {
await tester.pumpWidget(const App());
tester.printToConsole('WelcomeTest - Navigate to Sign-Up to Sign-In');
await tester.pumpAndSettle();
tester.printToConsole('WelcomeTest - Navigate Sign-In');
await _navigateToSignIn(tester);
tester.printToConsole('WelcomeTest - Navigate Sign-Up');
await _navigateToSignUp(tester);
await tester.pumpAndSettle();
await Future.delayed(const Duration(milliseconds: 500));
return;
});
_tearDownAll();
patrolWidgetTest(
'Sign-In to Sign-Up',
(PatrolTester tester) async {
$ = tester;
await _unlogged();
await $.pumpWidgetAndSettle(const App());
await _navigateToSignIn($);
await _navigateToSignUp($);
},
);
}
static Future signUpToSignIn() async {
_setUpAllUnlogged();
testWidgets('Sign-Up to Sign-In', (WidgetTester tester) async {
await tester.pumpWidget(const App());
tester.printToConsole('WelcomeTest - Navigate to Sign-In to Sign-Up');
await tester.pumpAndSettle();
await _navigateToSignUp(tester);
tester.printToConsole('WelcomeTest - Navigate Sign-Up');
await _navigateToSignIn(tester);
tester.printToConsole('WelcomeTest - Navigate Sign-In');
await tester.pumpAndSettle();
await Future.delayed(const Duration(milliseconds: 500));
return;
});
_tearDownAll();
patrolWidgetTest(
'Sign-Up to Sign-In',
(PatrolTester tester) async {
$ = tester;
await _unlogged();
await $.pumpWidgetAndSettle(const App());
await _navigateToSignUp($);
await _navigateToSignIn($);
},
);
}
}

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:hub/features/menu/index.dart';
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
import 'package:hub/flutter_flow/flutter_flow_util.dart';
class CardMenuItem extends MenuItem {
const CardMenuItem({
@ -35,11 +36,11 @@ class _MenuCardItemState extends State<CardMenuItem> {
onTap: _isProcessing
? null
: () async {
setState(() {
safeSetState(() {
_isProcessing = true;
});
await widget.action.call();
setState(() {
safeSetState(() {
_isProcessing = false;
});
},

View File

@ -9,7 +9,9 @@ import 'package:hub/features/module/index.dart';
abstract class LicenseRemoteDataSource {
Future<bool> fetchLicenses(bool isNewVersion);
Future<bool> cleanLicense();
Future<void> processLicense();
}
@ -70,7 +72,7 @@ class LicenseRemoteDataSourceImpl implements LicenseRemoteDataSource {
} catch (e, s) {
log('Erro ao obter licenças: $e', stackTrace: s);
// return await setupLicense(DatabaseStorage.database, isNewVersion);
return false;
return true;
}
}

View File

@ -34,9 +34,11 @@ class LicenseRepositoryImpl implements LicenseRepository {
log('updateLicense');
bool result = false;
final bool isNewVersion = await localDataSource.isNewVersion();
result = await localDataSource.setupLicense(isNewVersion);
if (isNewVersion) {
result = await remoteDataSource.fetchLicenses(isNewVersion);
} else {
result = await localDataSource.setupLicense(isNewVersion);
}
return result;

View File

@ -350,6 +350,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "7.0.2"
dispose_scope:
dependency: transitive
description:
name: dispose_scope
sha256: "48ec38ca2631c53c4f8fa96b294c801e55c335db5e3fb9f82cede150cfe5a2af"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
dropdown_button2:
dependency: "direct main"
description:
@ -665,10 +673,18 @@ packages:
dependency: "direct main"
description:
name: flutter_secure_storage
sha256: c0f1abb088adddc193286ea91eedd71900ec5707ac86503a7ae09d88c9ffc22b
sha256: f7eceb0bc6f4fd0441e29d43cab9ac2a1c5ffd7ea7b64075136b718c46954874
url: "https://pub.dev"
source: hosted
version: "10.0.0-beta.2"
version: "10.0.0-beta.4"
flutter_secure_storage_darwin:
dependency: transitive
description:
name: flutter_secure_storage_darwin
sha256: f226f2a572bed96bc6542198ebaec227150786e34311d455a7e2d3d06d951845
url: "https://pub.dev"
source: hosted
version: "0.1.0"
flutter_secure_storage_linux:
dependency: "direct main"
description:
@ -737,10 +753,10 @@ packages:
dependency: "direct main"
description:
name: flutter_svg
sha256: "54900a1a1243f3c4a5506d853a2b5c2dbc38d5f27e52a52618a8054401431123"
sha256: c200fd79c918a40c5cd50ea0877fa13f81bdaf6f0a5d3dbcc2a13e3285d6aa1b
url: "https://pub.dev"
source: hosted
version: "2.0.16"
version: "2.0.17"
flutter_test:
dependency: "direct dev"
description: flutter
@ -904,10 +920,10 @@ packages:
dependency: "direct main"
description:
name: image_picker_android
sha256: aa6f1280b670861ac45220cc95adc59bb6ae130259d36f980ccb62220dc5e59f
sha256: b62d34a506e12bb965e824b6db4fbf709ee4589cf5d3e99b45ab2287b008ee0c
url: "https://pub.dev"
source: hosted
version: "0.8.12+19"
version: "0.8.12+20"
image_picker_for_web:
dependency: "direct main"
description:
@ -1289,6 +1305,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.3.0"
patrol:
dependency: "direct dev"
description:
name: patrol
sha256: f2b423122e63b1251fc31165ba1f7d85d60e22b4d20076ef39dcb47f83e35467
url: "https://pub.dev"
source: hosted
version: "3.13.2"
patrol_finders:
dependency: "direct dev"
description:
name: patrol_finders
sha256: "5a1e2b4c6636e89645fc596d68224cfe6cca28e11c855b98dd0df9bed0d80405"
url: "https://pub.dev"
source: hosted
version: "2.6.0"
patrol_log:
dependency: transitive
description:
name: patrol_log
sha256: ad5d7b759d16071ca16aa9b27eb4f106ce23079792d4312941874dbc33e795cb
url: "https://pub.dev"
source: hosted
version: "0.2.2"
percent_indicator:
dependency: "direct main"
description:
@ -1501,10 +1541,10 @@ packages:
dependency: "direct main"
description:
name: shared_preferences_android
sha256: "02a7d8a9ef346c9af715811b01fbd8e27845ad2c41148eefd31321471b41863d"
sha256: bf808be89fe9dc467475e982c1db6c2faf3d2acf54d526cd5ec37d86c99dbd84
url: "https://pub.dev"
source: hosted
version: "2.4.0"
version: "2.4.1"
shared_preferences_foundation:
dependency: "direct main"
description:
@ -1834,18 +1874,18 @@ packages:
dependency: transitive
description:
name: url_launcher_web
sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e"
sha256: "3ba963161bd0fe395917ba881d320b9c4f6dd3c4a233da62ab18a5025c85f1e9"
url: "https://pub.dev"
source: hosted
version: "2.3.3"
version: "2.4.0"
url_launcher_windows:
dependency: transitive
description:
name: url_launcher_windows
sha256: "44cf3aabcedde30f2dba119a9dea3b0f2672fbe6fa96e85536251d678216b3c4"
sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77"
url: "https://pub.dev"
source: hosted
version: "3.1.3"
version: "3.1.4"
uuid:
dependency: "direct overridden"
description:
@ -1970,10 +2010,10 @@ packages:
dependency: transitive
description:
name: webview_flutter_wkwebview
sha256: b7e92f129482460951d96ef9a46b49db34bd2e1621685de26e9eaafd9674e7eb
sha256: "4adc14ea9a770cc9e2c8f1ac734536bd40e82615bd0fa6b94be10982de656cc7"
url: "https://pub.dev"
source: hosted
version: "3.16.3"
version: "3.17.0"
win32:
dependency: "direct overridden"
description:
@ -2016,4 +2056,4 @@ packages:
version: "3.1.3"
sdks:
dart: ">=3.6.0 <4.0.0"
flutter: ">=3.24.0"
flutter: ">=3.27.0"

View File

@ -125,6 +125,8 @@ dev_dependencies:
freezed: ^2.5.7
json_serializable: ^6.9.0
test: ^1.25.8
patrol: ^3.13.2
patrol_finders: ^2.6.0
flutter_launcher_icons:
android: "launcher_icon"
@ -159,3 +161,9 @@ fonts:
fonts:
- asset: assets/fonts/menu.ttf
patrol:
app_name: FRE ACCESS HUB
android:
package_name: com.freaccess.hub
ios:
bundle_id: br.com.freaccess.hub