// Author: fruit.com.cn import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:fruitshorts/core/data/remote/api_client.dart'; import 'package:fruitshorts/core/data/remote/auth_api.dart'; import 'package:fruitshorts/core/data/services/auth_controller.dart'; import 'package:fruitshorts/core/data/services/auth_session_store.dart'; import 'package:fruitshorts/core/platform/haptics.dart'; import 'package:fruitshorts/l10n/app_localizations.dart'; import 'package:fruitshorts/pages/auth/phone_auth_sheet.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences_platform_interface/in_memory_shared_preferences_async.dart'; import 'package:shared_preferences_platform_interface/shared_preferences_async_platform_interface.dart'; import '../support/fake_haptics.dart'; import '../support/fake_http_adapter.dart'; void main() { setUp(() { SharedPreferencesAsyncPlatform.instance = InMemorySharedPreferencesAsync.empty(); }); testWidgets('should_send_otp_and_sign_in_when_phone_form_is_submitted', ( tester, ) async { final adapter = FakeHttpAdapter((options) async { if (options.uri.path == '/app/auth/otp') { return FakeHttpResponse( jsonEncode({'code': 0, 'message': 'ok', 'data': null}), ); } expect(options.uri.path, '/app/auth/login'); return FakeHttpResponse( jsonEncode({ 'code': 0, 'message': 'ok', 'data': { 'accessToken': 'phone-token', 'refreshToken': 'phone-refresh', 'expiresIn': 7200, 'user': {'uid': 'U9', 'nickname': 'Phone User'}, }, }), ); }); final auth = AuthController( AuthApi(ApiClient(baseUrl: 'http://127.0.0.1:8081', adapter: adapter)), AuthSessionStore(), ); await _pumpHost(tester, auth); await tester.tap(find.byKey(const Key('open-phone-sheet'))); await tester.pumpAndSettle(); await tester.enterText( find.byKey(const Key('auth-phone-number')), '08123456789', ); await tester.tap(find.byKey(const Key('auth-send-code'))); await tester.pumpAndSettle(); expect( adapter.requests.where((item) => item.uri.path == '/app/auth/otp'), hasLength(1), ); await tester.enterText(find.byKey(const Key('auth-phone-code')), '123456'); await tester.tap(find.byKey(const Key('auth-phone-submit'))); await tester.pumpAndSettle(); expect(auth.isSignedIn, isTrue); expect(auth.accessToken, 'phone-token'); }); testWidgets('should_keep_sheet_open_when_phone_number_is_invalid', ( tester, ) async { final adapter = FakeHttpAdapter( (_) async => FakeHttpResponse( jsonEncode({'code': 0, 'message': 'ok', 'data': null}), ), ); final auth = AuthController( AuthApi(ApiClient(baseUrl: 'http://127.0.0.1:8081', adapter: adapter)), AuthSessionStore(), ); await _pumpHost(tester, auth); await tester.tap(find.byKey(const Key('open-phone-sheet'))); await tester.pumpAndSettle(); await tester.enterText(find.byKey(const Key('auth-phone-number')), '12'); await tester.tap(find.byKey(const Key('auth-send-code'))); await tester.pumpAndSettle(); expect(find.text('Enter a valid phone number'), findsOneWidget); expect(adapter.requests, isEmpty); }); testWidgets('should_keep_code_above_ios_keyboard', (tester) async { debugDefaultTargetPlatformOverride = TargetPlatform.iOS; addTearDown(() => debugDefaultTargetPlatformOverride = null); tester.view.physicalSize = const Size(390, 844); tester.view.devicePixelRatio = 1; tester.view.viewInsets = const FakeViewPadding(bottom: 300); addTearDown(tester.view.resetPhysicalSize); addTearDown(tester.view.resetDevicePixelRatio); addTearDown(tester.view.resetViewInsets); final adapter = FakeHttpAdapter( (_) async => FakeHttpResponse( jsonEncode({'code': 0, 'message': 'ok', 'data': null}), ), ); final auth = AuthController( AuthApi(ApiClient(baseUrl: 'http://127.0.0.1:8081', adapter: adapter)), AuthSessionStore(), ); await _pumpHost(tester, auth); await tester.tap(find.byKey(const Key('open-phone-sheet'))); await tester.pumpAndSettle(); await tester.tap(find.byKey(const Key('auth-phone-code'))); await tester.pumpAndSettle(); expect( tester.getBottomLeft(find.byKey(const Key('auth-phone-code'))).dy, lessThanOrEqualTo(844 - 300), ); debugDefaultTargetPlatformOverride = null; }); } Future _pumpHost(WidgetTester tester, AuthController auth) { return tester.pumpWidget( MultiProvider( providers: [ ChangeNotifierProvider.value(value: auth), Provider.value(value: FakeHaptics()), ], child: MaterialApp( locale: const Locale('en'), localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, home: Builder( builder: (context) => Scaffold( body: Center( child: TextButton( key: const Key('open-phone-sheet'), onPressed: () => showPhoneAuthSheet(context), child: const Text('Open'), ), ), ), ), ), ), ); }