huawei_health_registration_dialog_test.dart 6.58 KB
import 'package:doublefeel_flutter/app/actions/dialog_action.dart';
import 'dart:async';

import 'package:doublefeel_flutter/core/error/app_error.dart';
import 'package:doublefeel_flutter/core/network/api/harmony_api.dart';
import 'package:doublefeel_flutter/core/result/app_result.dart';
import 'package:doublefeel_flutter/app/modules/home/widgets/today/huawei_health_registration_dialog.dart';
import 'package:doublefeel_flutter/app/modules/webview/controllers/hw_health_auth_webview_controller.dart';
import 'package:doublefeel_flutter/app/routes/app_pages.dart';
import 'package:doublefeel_flutter/core/platform/pigeon_api_facade.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:get/get.dart';

class _HarmonyApi extends Fake implements HarmonyApi {
  final response = Completer<AppResult<void>>();
  final submittedCodes = <String>[];

  @override
  Future<AppResult<void>> postHmAuth(String code) {
    submittedCodes.add(code);
    return response.future;
  }
}

void main() {
  const channel = BasicMessageChannel<Object?>(
    'dev.flutter.pigeon.doublefeel_flutter.PlatformHostApi.nativeHandleUrl',
    StandardMessageCodec(),
  );

  testWidgets('registration dialog waits for confirmation', (tester) async {
    addTearDown(Get.reset);
    DialogAction? confirmed;
    await tester.pumpWidget(GetMaterialApp(
      home: Scaffold(
          body: TextButton(
        onPressed: () async {
          confirmed = await HuaweiHealthRegistrationDialog.show();
        },
        child: const Text('show'),
      )),
    ));
    await tester.tap(find.text('show'));
    await tester.pumpAndSettle();
    expect(find.text('该账号暂未注册华为运动健康'), findsOneWidget);
    expect(find.text('请注册后再进行授权'), findsOneWidget);
    expect(find.byType(Image), findsNothing);
    await tester.tapAt(const Offset(10, 10));
    await tester.pumpAndSettle();
    expect(confirmed, isNull);
    expect(find.text('去注册'), findsOneWidget);
    await tester.tap(find.text('去注册'));
    await tester.pumpAndSettle();
    expect(confirmed, DialogAction.confirm);
    expect(find.text('去注册'), findsNothing);
    expect(tester.takeException(), isNull);
  });

  testWidgets('unbind returns a distinct action without registering',
      (tester) async {
    addTearDown(Get.reset);
    DialogAction? action;
    await tester.pumpWidget(GetMaterialApp(
      home: Scaffold(
          body: TextButton(
        onPressed: () async {
          action = await HuaweiHealthRegistrationDialog.show();
        },
        child: const Text('show'),
      )),
    ));
    await tester.tap(find.text('show'));
    await tester.pumpAndSettle();
    await tester.tap(find.text('解除绑定该账号'));
    await tester.pumpAndSettle();
    expect(action, DialogAction.cancel);
    expect(find.text('去注册'), findsNothing);
    expect(tester.takeException(), isNull);
  });

  for (final error in [
    '3',
    'access_denied',
    'invalid_state',
    'backend_success',
    'backend_network_failure',
    'backend_server_failure'
  ]) {
    testWidgets('Huawei authorization result $error', (tester) async {
      tester.view.physicalSize = const Size(375, 812);
      tester.view.devicePixelRatio = 1;
      addTearDown(tester.view.resetPhysicalSize);
      addTearDown(tester.view.resetDevicePixelRatio);
      final openedUrls = <Object?>[];
      final harmonyApi = _HarmonyApi();
      Get.put<HarmonyApi>(harmonyApi);
      final isBackendResult = error.startsWith('backend_');
      tester.binding.defaultBinaryMessenger
          .setMockDecodedMessageHandler<Object?>(
        channel,
        (message) async {
          openedUrls.add((message! as List<Object?>).single);
          return [true];
        },
      );
      addTearDown(() {
        tester.binding.defaultBinaryMessenger
            .setMockDecodedMessageHandler<Object?>(channel, null);
        Get.reset();
      });
      HealthAuthorizationStatus? authorization;
      await tester.pumpWidget(GetMaterialApp(
        home: Scaffold(
          body: TextButton(
            onPressed: () async {
              authorization = await AppHealthKitHostApi(
                appPlatform: AppPigeonPlatform.ohos,
              ).requestHealthClientAuthorization();
            },
            child: const Text('authorize'),
          ),
        ),
        getPages: [
          GetPage(
            name: Routes.HW_HEALTH_AUTH_WEB_VIEW,
            page: () => Scaffold(
              body: TextButton(
                onPressed: () {
                  final arguments =
                      Get.arguments as HwHealthAuthWebviewArguments;
                  final state = Uri.parse(arguments.authorizationUrl)
                      .queryParameters['state'];
                  Get.back(
                      result: HealthAuthEvent(
                    state: error == 'invalid_state' ? 'wrong' : state,
                    code: isBackendResult ? 'test-authorization-code' : null,
                    error: isBackendResult
                        ? null
                        : (error == 'invalid_state' ? '3' : error),
                  ));
                },
                child: const Text('return authorization'),
              ),
            ),
          ),
        ],
      ));
      await tester.tap(find.text('authorize'));
      await tester.pumpAndSettle();
      await tester.tap(find.text('return authorization'));
      await tester.pumpAndSettle();
      if (isBackendResult) {
        expect(harmonyApi.submittedCodes, ['test-authorization-code']);
        // A valid OAuth code alone must not report authorization success.
        expect(authorization, isNull);
        expect(openedUrls, isEmpty);
        harmonyApi.response.complete(switch (error) {
          'backend_success' => const AppSuccess<void>(null),
          'backend_network_failure' =>
            const AppFailure<void>(AppNetworkError('offline')),
          _ => const AppFailure<void>(AppHttpError(statusCode: 500)),
        });
        await tester.pumpAndSettle();
      } else {
        expect(harmonyApi.submittedCodes, isEmpty);
      }
      expect(openedUrls, isEmpty);
      // The facade reports the result without displaying UI or opening apps.
      expect(find.text('去注册'), findsNothing);
      expect(
        authorization,
        switch (error) {
          '3' => HealthAuthorizationStatus.activationRequired,
          'backend_success' => HealthAuthorizationStatus.authorized,
          _ => HealthAuthorizationStatus.unauthorized,
        },
      );
      expect(tester.takeException(), isNull);
    });
  }
}