163 lines
5.2 KiB
Dart
163 lines
5.2 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
import 'package:go_router/go_router.dart';
|
|
|
|
import 'package:sxchnge_auth/sxchnge_auth.dart';
|
|
|
|
import 'package:sxchnge_app/main.dart';
|
|
import 'package:sxchnge_app/providers/locale.dart';
|
|
|
|
class ControlledLogin implements LoginService {
|
|
final calls = <Completer<AuthResult>>[];
|
|
LoginRequest? request;
|
|
@override
|
|
Future<AuthResult> login(LoginRequest input) {
|
|
request = input;
|
|
final completer = Completer<AuthResult>();
|
|
calls.add(completer);
|
|
return completer.future;
|
|
}
|
|
}
|
|
|
|
class UnverifiedBackend extends BackendAuthServices {
|
|
UnverifiedBackend()
|
|
: super(baseUri: Uri.parse('https://api.example/api/v1'), clientId: 'web');
|
|
int sends = 0;
|
|
@override
|
|
Future<AuthResult> login(LoginRequest request) async =>
|
|
throw const AuthException(AuthError.accountNotVerified);
|
|
@override
|
|
Future<VerificationResult> send({
|
|
required String email,
|
|
required String locale,
|
|
}) async {
|
|
sends++;
|
|
return const VerificationResult(isSimulated: false);
|
|
}
|
|
}
|
|
|
|
void main() {
|
|
testWidgets('backend mode gates workspace and recovers unverified login', (
|
|
tester,
|
|
) async {
|
|
tester.view.physicalSize = const Size(1440, 1200);
|
|
tester.view.devicePixelRatio = 1;
|
|
addTearDown(tester.view.resetPhysicalSize);
|
|
addTearDown(tester.view.resetDevicePixelRatio);
|
|
final backend = UnverifiedBackend();
|
|
await tester.pumpWidget(SxchngeApp(backend: backend));
|
|
await tester.pumpAndSettle();
|
|
final router = GoRouter.of(
|
|
tester.element(find.byKey(const ValueKey('email'))),
|
|
);
|
|
router.go('/accounts');
|
|
await tester.pumpAndSettle();
|
|
expect(router.routeInformationProvider.value.uri.path, '/');
|
|
await tester.enterText(
|
|
find.byKey(const ValueKey('email')),
|
|
'user@example.com',
|
|
);
|
|
await tester.enterText(
|
|
find.byKey(const ValueKey('password')),
|
|
'password-value',
|
|
);
|
|
await tester.ensureVisible(find.byKey(const ValueKey('submit')));
|
|
await tester.tap(find.byKey(const ValueKey('submit')));
|
|
await tester.pumpAndSettle();
|
|
expect(
|
|
router.routeInformationProvider.value.uri.path,
|
|
'/verification-sent',
|
|
);
|
|
expect(backend.sends, 1);
|
|
expect(
|
|
find.textContaining('a verification email is on its way'),
|
|
findsOneWidget,
|
|
);
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
|
|
testWidgets(
|
|
'app shows loading, localized failure, and retries through injected service',
|
|
(tester) async {
|
|
tester.view.physicalSize = const Size(1440, 1200);
|
|
tester.view.devicePixelRatio = 1;
|
|
addTearDown(tester.view.resetPhysicalSize);
|
|
addTearDown(tester.view.resetDevicePixelRatio);
|
|
final service = ControlledLogin();
|
|
await tester.pumpWidget(
|
|
SxchngeApp(
|
|
loginService: service,
|
|
localeProvider: LocaleProvider(initialLocale: const Locale('ru')),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
await tester.enterText(
|
|
find.byKey(const ValueKey('email')),
|
|
'a@example.com',
|
|
);
|
|
await tester.enterText(
|
|
find.byKey(const ValueKey('password')),
|
|
'example-password',
|
|
);
|
|
final button = find.byKey(const ValueKey('submit'));
|
|
await tester.ensureVisible(button);
|
|
await tester.tap(button);
|
|
await tester.pump();
|
|
expect(tester.widget<FilledButton>(button).onPressed, isNull);
|
|
expect(find.text('Подождите…'), findsOneWidget);
|
|
expect(service.request!.locale, 'ru');
|
|
service.calls.single.completeError(
|
|
const AuthException(AuthError.unavailable),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(
|
|
find.text('Сервис недоступен. Попробуйте ещё раз.'),
|
|
findsOneWidget,
|
|
);
|
|
await tester.tap(button);
|
|
await tester.pump();
|
|
expect(service.calls, hasLength(2));
|
|
service.calls.last.complete(
|
|
const AuthResult(userId: 'demo', isSimulated: true),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.byKey(const ValueKey('preview-result')), findsOneWidget);
|
|
expect(find.byKey(const ValueKey('auth-error')), findsNothing);
|
|
expect(tester.takeException(), isNull);
|
|
},
|
|
);
|
|
|
|
testWidgets('changing mode while loading ignores the old login result', (
|
|
tester,
|
|
) async {
|
|
final service = ControlledLogin();
|
|
await tester.pumpWidget(SxchngeApp(loginService: service));
|
|
await tester.pumpAndSettle();
|
|
await tester.enterText(
|
|
find.byKey(const ValueKey('email')),
|
|
'a@example.com',
|
|
);
|
|
await tester.enterText(
|
|
find.byKey(const ValueKey('password')),
|
|
'example-password',
|
|
);
|
|
await tester.ensureVisible(find.byKey(const ValueKey('submit')));
|
|
await tester.tap(find.byKey(const ValueKey('submit')));
|
|
await tester.pump();
|
|
await tester.ensureVisible(find.text('Sign up'));
|
|
await tester.tap(find.text('Sign up'));
|
|
await tester.pumpAndSettle();
|
|
service.calls.single.complete(
|
|
const AuthResult(userId: 'demo', isSimulated: true),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.byKey(const ValueKey('confirmation')), findsOneWidget);
|
|
expect(find.byKey(const ValueKey('preview-result')), findsNothing);
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
}
|