Integrate themed login/signup, EN/RU localization, shared dummy providers, verification recovery screens and named URL routes. Store frontend guidelines, workflow skills, validation and delivery documentation. Related to #2, #3, #5 and #6.
161 lines
5.4 KiB
Dart
161 lines
5.4 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
import 'package:sxchnge_app/auth/validation.dart';
|
|
import 'package:sxchnge_app/main.dart';
|
|
|
|
import 'package:sxchnge_app/generated/i18n/app_localizations_en.dart';
|
|
|
|
Future<void> openApp(
|
|
WidgetTester tester, {
|
|
Size size = const Size(390, 844),
|
|
double scale = 1,
|
|
}) async {
|
|
tester.view.physicalSize = size;
|
|
tester.view.devicePixelRatio = 1;
|
|
tester.platformDispatcher.textScaleFactorTestValue = scale;
|
|
addTearDown(tester.view.resetPhysicalSize);
|
|
addTearDown(tester.view.resetDevicePixelRatio);
|
|
addTearDown(tester.platformDispatcher.clearTextScaleFactorTestValue);
|
|
await tester.pumpWidget(const SxchngeApp());
|
|
await tester.pumpAndSettle();
|
|
}
|
|
|
|
Future<void> submit(WidgetTester tester) async {
|
|
final button = find.byKey(const ValueKey('submit'));
|
|
await tester.ensureVisible(button);
|
|
await tester.tap(button);
|
|
await tester.pumpAndSettle();
|
|
}
|
|
|
|
void main() {
|
|
final l = AppLocalizationsEn();
|
|
test(
|
|
'validation rejects malformed email and mismatched signup passwords',
|
|
() {
|
|
for (final email in ['', 'user', 'user@', 'user @example.com']) {
|
|
expect(AuthValidation.email(email, l), isNotNull);
|
|
}
|
|
expect(AuthValidation.email(' user+tag@example.com ', l), isNull);
|
|
expect(AuthValidation.password('short', l, signUp: true), isNotNull);
|
|
expect(AuthValidation.password('short', l, signUp: false), isNull);
|
|
expect(
|
|
AuthValidation.confirmation('different', 'password', l),
|
|
isNotNull,
|
|
);
|
|
expect(AuthValidation.name(' ', l), isNotNull);
|
|
},
|
|
);
|
|
|
|
testWidgets(
|
|
'login validates, toggles password, and submits with the keyboard',
|
|
(tester) async {
|
|
await openApp(tester);
|
|
await submit(tester);
|
|
expect(find.text('Enter your email address.'), findsOneWidget);
|
|
expect(find.text('Enter your password.'), findsOneWidget);
|
|
await tester.enterText(
|
|
find.byKey(const ValueKey('email')),
|
|
'test@example.com',
|
|
);
|
|
await tester.enterText(
|
|
find.byKey(const ValueKey('password')),
|
|
'example-password',
|
|
);
|
|
await tester.tap(find.byTooltip('Show password'));
|
|
await tester.pump();
|
|
expect(
|
|
tester
|
|
.widget<TextField>(
|
|
find.descendant(
|
|
of: find.byKey(const ValueKey('password')),
|
|
matching: find.byType(TextField),
|
|
),
|
|
)
|
|
.obscureText,
|
|
isFalse,
|
|
);
|
|
await tester.testTextInput.receiveAction(TextInputAction.done);
|
|
await tester.pumpAndSettle();
|
|
expect(find.byKey(const ValueKey('preview-result')), findsOneWidget);
|
|
expect(tester.takeException(), isNull);
|
|
},
|
|
);
|
|
|
|
testWidgets(
|
|
'signup validates confirmation and clears credentials when switching',
|
|
(tester) async {
|
|
await openApp(tester);
|
|
await tester.tap(find.text('Sign up'));
|
|
await tester.pumpAndSettle();
|
|
await tester.enterText(find.byKey(const ValueKey('name')), 'Alex');
|
|
await tester.enterText(
|
|
find.byKey(const ValueKey('email')),
|
|
'alex@example.com',
|
|
);
|
|
await tester.enterText(
|
|
find.byKey(const ValueKey('password')),
|
|
'example-password',
|
|
);
|
|
await tester.enterText(
|
|
find.byKey(const ValueKey('confirmation')),
|
|
'different',
|
|
);
|
|
await submit(tester);
|
|
expect(find.text('Passwords do not match.'), findsOneWidget);
|
|
await tester.enterText(
|
|
find.byKey(const ValueKey('confirmation')),
|
|
'example-password',
|
|
);
|
|
await submit(tester);
|
|
expect(find.byKey(const ValueKey('verification-sent')), findsOneWidget);
|
|
await tester.ensureVisible(
|
|
find.byKey(const ValueKey('demo-confirmation')),
|
|
);
|
|
await tester.tap(find.byKey(const ValueKey('demo-confirmation')));
|
|
await tester.pumpAndSettle();
|
|
expect(
|
|
find.byKey(const ValueKey('verification-verified')),
|
|
findsOneWidget,
|
|
);
|
|
await tester.ensureVisible(find.text('Back to login'));
|
|
await tester.tap(find.text('Back to login'));
|
|
await tester.pumpAndSettle();
|
|
expect(find.byKey(const ValueKey('confirmation')), findsNothing);
|
|
expect(find.text('example-password'), findsNothing);
|
|
expect(find.byKey(const ValueKey('preview-result')), findsNothing);
|
|
expect(tester.takeException(), isNull);
|
|
},
|
|
);
|
|
|
|
testWidgets('resizing preserves the selected mode and entered values', (
|
|
tester,
|
|
) async {
|
|
await openApp(tester, size: const Size(1440, 1000));
|
|
await tester.tap(find.text('Sign up'));
|
|
await tester.pumpAndSettle();
|
|
await tester.enterText(
|
|
find.byKey(const ValueKey('email')),
|
|
'alex@example.com',
|
|
);
|
|
tester.view.physicalSize = const Size(390, 844);
|
|
await tester.pumpAndSettle();
|
|
expect(find.byKey(const ValueKey('name')), findsOneWidget);
|
|
expect(find.text('alex@example.com'), findsOneWidget);
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
|
|
for (final size in [const Size(320, 740), const Size(1440, 1000)]) {
|
|
testWidgets('both modes fit $size at 200% text scale', (tester) async {
|
|
await openApp(tester, size: size, scale: 2);
|
|
expect(tester.takeException(), isNull);
|
|
await tester.ensureVisible(find.text('Sign up'));
|
|
await tester.tap(find.text('Sign up'));
|
|
await tester.pumpAndSettle();
|
|
await submit(tester);
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
}
|
|
}
|