feat(tests): added 2 e2e tests

This commit is contained in:
misha
2025-10-07 18:03:36 +03:00
parent 5275273830
commit b0d2d86a18
11 changed files with 170 additions and 14 deletions

View File

@@ -0,0 +1,38 @@
import 'package:eatvio_app/app_keys.dart';
import 'package:eatvio_app/core/app_initializer.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:eatvio_app/main.dart' as app;
import '../common_cases/skip_welcome_screen.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
setUpAll(() async {
await AppInitializer.initialize(buildType: AppBuildType.tests);
});
testWidgets('Signs in successfully with valid credentials', (WidgetTester tester) async {
await tester.pumpWidget(const app.MyApp());
await tester.pumpAndSettle(const Duration(seconds: 3));
await skipWelcomeScreen(tester);
final emailFieldFinder = find.byKey(AppKeys.emailTextFieldAuthScreen);
final passwordFieldFinder = find.byKey(AppKeys.passwordTextFieldAuthScreen);
final signInButtonFinder = find.byKey(AppKeys.signInButtonAuthScreen);
expect(emailFieldFinder, findsOneWidget, reason: 'Email text field should be found.');
expect(passwordFieldFinder, findsOneWidget, reason: 'Password text field should be found.');
expect(signInButtonFinder, findsOneWidget, reason: 'Sign In button should be found.');
await tester.enterText(emailFieldFinder, 'reshetnik.n+user3@gmail.com');
await tester.enterText(passwordFieldFinder, '1234567890');
await tester.pumpAndSettle();
await tester.tap(signInButtonFinder);
await tester.pumpAndSettle(const Duration(seconds: 3));
expect(signInButtonFinder, findsNothing, reason: 'Sign-in button should not be visible after successful login and navigation.');
});
}

View File

@@ -0,0 +1,32 @@
import 'package:eatvio_app/app_keys.dart';
import 'package:eatvio_app/core/app_initializer.dart';
import 'package:eatvio_app/features/dev_tools/presentation/dev_tools_screen.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:eatvio_app/main.dart' as app;
import '../common_cases/skip_welcome_screen.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
setUpAll(() async {
await AppInitializer.initialize(buildType: AppBuildType.tests);
});
testWidgets('tapping logo 7 times opens dev tools', (WidgetTester tester) async {
await tester.pumpWidget(const app.MyApp());
await tester.pumpAndSettle(const Duration(seconds: 3));
await skipWelcomeScreen(tester);
final logoButtonFinder = find.byKey(AppKeys.hiddenLogoButtonAuthScreen);
expect(logoButtonFinder, findsOneWidget, reason: 'The logo GestureDetector should be found in auth screen');
for (int i = 0; i < 7; i++) {
await tester.tap(logoButtonFinder);
await tester.pump(const Duration(milliseconds: 50));
}
await tester.pumpAndSettle();
expect(find.byType(DevToolsScreen), findsOneWidget, reason: 'DevToolsScreen should be visible after tapping the logo 7 times.');
});
}

View File

@@ -0,0 +1,8 @@
import 'package:eatvio_app/app_keys.dart';
import 'package:flutter_test/flutter_test.dart';
Future<void> skipWelcomeScreen(WidgetTester tester) async {
final welcomeScreenButtonFinder = find.byKey(AppKeys.welcomeScreenButton);
await tester.tap(welcomeScreenButtonFinder);
await tester.pumpAndSettle();
}

View File

@@ -1,5 +1,6 @@
import UIKit
import Flutter
import UIKit
import YandexLoginSDK
@main
@objc class AppDelegate: FlutterAppDelegate {
@@ -10,4 +11,20 @@ import Flutter
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
@available(iOS 8.0, *)
func application(
_ application: UIApplication, continue userActivity: NSUserActivity,
restorationHandler: @escaping ([Any]?) -> Void
) -> Bool {
YXLSdk.shared.processUserActivity(userActivity)
return true
}
override public func application(
_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]
) -> Bool {
return YXLSdk.shared.handleOpen(
url, sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String)
}
}

View File

@@ -67,5 +67,24 @@
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>yandexauth</string>
<string>yandexauth2</string>
<string>yandexauth4</string>
</array>
<key>YAClientId</key>
<string>5399b03636104c6d920b87c1ad329254</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>YandexLoginSDK</string>
<key>CFBundleURLSchemes</key>
<array>
<string>yx5399b03636104c6d920b87c1ad329254</string>
</array>
</dict>
</array>
</dict>
</plist>

13
lib/app_keys.dart Normal file
View File

@@ -0,0 +1,13 @@
import 'package:flutter/material.dart';
class AppKeys {
// Auth Screen
static const hiddenLogoButtonAuthScreen = ValueKey('hiddenLogoButtonAuthScreen');
static const emailTextFieldAuthScreen = ValueKey('emailTextFieldAuthScreen');
static const passwordTextFieldAuthScreen = ValueKey('passwordTextFieldAuthScreen');
static const signInButtonAuthScreen = ValueKey('signInButtonAuthScreen');
// Welcome Screen
static const welcomeScreenButton = ValueKey('welcomeScreenButton');
}

View File

@@ -1,4 +1,5 @@
import 'dart:io' as io;
import 'package:eatvio_app/core/const.dart';
import 'package:eatvio_app/core/env_config.dart';
import 'package:eatvio_app/core/locator_service.dart' as di;
import 'package:eatvio_app/firebase_options.dart';
@@ -12,10 +13,19 @@ import 'package:sentry_flutter/sentry_flutter.dart';
/// Класс для инициализации приложения
class AppInitializer {
/// Инициализация всех сервисов приложения
static Future<void> initialize() async {
await _initializeSentry();
static Future<void> initialize({AppBuildType buildType = AppBuildType.prod}) async {
await _initializeEnvironment();
switch (buildType) {
case AppBuildType.tests:
baseUrl = EnvConfig.devBaseUrl;
buildType = AppBuildType.tests;
break;
case AppBuildType.prod:
break;
}
await _initializeSentry();
await _initializeFirebase();
await _initializeDependencyInjection();
await _initializeDebugMode();
@@ -66,3 +76,5 @@ class AppInitializer {
}, appRunner: appRunner);
}
}
enum AppBuildType { prod, tests }

View File

@@ -2,6 +2,7 @@
import 'dart:async';
import 'dart:developer';
import 'package:eatvio_app/app_keys.dart';
import 'package:eatvio_app/core/app_router.dart';
import 'package:eatvio_app/core/const.dart';
import 'package:eatvio_app/core/firebase_api.dart';
@@ -46,7 +47,7 @@ class _AuthScreenState extends State<AuthScreen> {
late StreamSubscription<bool> keyboardSubscription;
bool isFocused = false;
int tapsCount = 0;
bool _isLoading = false;
@override
void initState() {
super.initState();
@@ -92,6 +93,7 @@ class _AuthScreenState extends State<AuthScreen> {
@override
Widget build(BuildContext context) {
var shortestSide = MediaQuery.sizeOf(context).shortestSide;
final screenSize = MediaQuery.of(context).size;
final bool useMobileLayout = shortestSide < 600;
if (!useMobileLayout) isFocused = true;
final s = S.of(context);
@@ -102,9 +104,10 @@ class _AuthScreenState extends State<AuthScreen> {
builder: (BuildContext context, AuthState state) {
return Scaffold(
appBar: AppBar(
toolbarHeight: screenSize.height * 0.15,
centerTitle: true,
toolbarHeight: isFocused ? 64 : MediaQuery.of(context).size.width - 64,
title: GestureDetector(
key: AppKeys.hiddenLogoButtonAuthScreen,
onTap: () {
tapsCount++;
if (tapsCount == 7) {
@@ -112,7 +115,7 @@ class _AuthScreenState extends State<AuthScreen> {
GoRouter.of(context).pushNamed(DevToolsScreen.name);
}
},
child: SvgPicture.asset(ImageConstant.imgLogoEatvio, height: isFocused ? 64 : MediaQuery.of(context).size.width - 64, fit: BoxFit.contain),
child: SvgPicture.asset(ImageConstant.imgLogoEatvio, height: screenSize.height * 0.20),
),
),
body: SafeArea(
@@ -122,8 +125,8 @@ class _AuthScreenState extends State<AuthScreen> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Social auth buttons at the top (outlined)
const Text('Авторизация через:', style: TextStyle(fontWeight: FontWeight.w600)),
const SizedBox(height: 8),
const Center(child: Text('Авторизация через')),
const SizedBox(height: 12),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@@ -164,6 +167,7 @@ class _AuthScreenState extends State<AuthScreen> {
textInputAction: TextInputAction.next,
keyboardType: TextInputType.emailAddress,
textInputType: TextInputType.emailAddress,
key: AppKeys.emailTextFieldAuthScreen,
hintText: 'Введите email',
),
const SizedBox(height: 16),
@@ -172,6 +176,7 @@ class _AuthScreenState extends State<AuthScreen> {
CustomTextFormField(
obscureText: hidePassword,
controller: passwordController,
key: AppKeys.passwordTextFieldAuthScreen,
hintText: 'Введите пароль',
suffix: IconButton(
onPressed: () {
@@ -249,21 +254,28 @@ class _AuthScreenState extends State<AuthScreen> {
height: 48,
width: MediaQuery.of(context).size.width - 88,
child: FloatingActionButton.extended(
key: AppKeys.signInButtonAuthScreen,
heroTag: 'authButton',
highlightElevation: 0,
elevation: 0,
focusElevation: 0,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
backgroundColor: state is AuthStateLoading ? Colors.black.withAlpha(50) : appTheme.blueA400,
onPressed: state is AuthStateLoading
backgroundColor: (state is AuthStateLoading || _isLoading) ? Colors.black.withAlpha(50) : appTheme.blueA400,
onPressed: (state is AuthStateLoading || _isLoading)
? null
: () async {
setState(() {
_isLoading = true;
});
final isAuthenticated = await authCubit.getTokenByCredentials(emailController.text, passwordController.text);
if (isAuthenticated) {
if (context.mounted) {
_reconnectWebSocket(context);
await _reconnectWebSocket(context);
}
}
setState(() {
_isLoading = false;
});
},
label: state is AuthStateLoading
? const CupertinoActivityIndicator()

View File

@@ -1,3 +1,4 @@
import 'package:eatvio_app/app_keys.dart';
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/core/token_storage.dart';
import 'package:flutter/material.dart';
@@ -79,6 +80,7 @@ class _WelcomeScreenState extends State<WelcomeScreen> {
),
const SizedBox(height: 24),
InkWell(
key: AppKeys.welcomeScreenButton,
onTap: () async {
final sharedPreferences = await SharedPreferences.getInstance();
await sharedPreferences.setBool('welcomeScreenWasShowed', true);

View File

@@ -28,9 +28,10 @@ class S {
static const AppLocalizationDelegate delegate = AppLocalizationDelegate();
static Future<S> load(Locale locale) {
final name = (locale.countryCode?.isEmpty ?? false)
? locale.languageCode
: locale.toString();
final name =
(locale.countryCode?.isEmpty ?? false)
? locale.languageCode
: locale.toString();
final localeName = Intl.canonicalizedLocale(name);
return initializeMessages(localeName).then((_) {
Intl.defaultLocale = localeName;

View File

@@ -88,6 +88,8 @@ dev_dependencies:
sdk: flutter
flutter_lints: ^6.0.0
integration_test:
sdk: flutter
flutter:
uses-material-design: true