diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable.dart index d17ea0bb612b..41f51be90557 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable.dart @@ -11,6 +11,18 @@ import '../../cloud_functions_platform_interface.dart'; import 'method_channel_firebase_functions.dart'; import 'utils/exception.dart'; +dynamic _convertNested(Object? value) { + if (value is List) { + return value.map(_convertNested).toList(); + } + if (value is Map) { + return value.map( + (key, value) => MapEntry(key as String, _convertNested(value)), + ); + } + return value; +} + /// Method Channel delegate for [HttpsCallablePlatform]. class MethodChannelHttpsCallable extends HttpsCallablePlatform { /// Creates a new [MethodChannelHttpsCallable] instance. @@ -38,11 +50,7 @@ class MethodChannelHttpsCallable extends HttpsCallablePlatform { 'limitedUseAppCheckToken': options.limitedUseAppCheckToken, }); - if (result is Map) { - return Map.from(result); - } else { - return result; - } + return _convertNested(result); } catch (e, s) { convertPlatformException(e, s); } @@ -70,12 +78,7 @@ class MethodChannelHttpsCallable extends HttpsCallablePlatform { 'limitedUseAppCheckToken': options.limitedUseAppCheckToken, 'timeout': options.timeout.inMilliseconds, }; - yield* channel.receiveBroadcastStream(eventData).map((message) { - if (message is Map) { - return Map.from(message); - } - return message; - }); + yield* channel.receiveBroadcastStream(eventData).map(_convertNested); } catch (e, s) { convertPlatformException(e, s); } diff --git a/packages/cloud_functions/cloud_functions_platform_interface/test/method_channel/method_channel_https_callable_test.dart b/packages/cloud_functions/cloud_functions_platform_interface/test/method_channel/method_channel_https_callable_test.dart index 88c3fd3b1c1d..50c92849d903 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/test/method_channel/method_channel_https_callable_test.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/test/method_channel/method_channel_https_callable_test.dart @@ -11,13 +11,13 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import '../mock.dart'; +import '../pigeon/test_api.dart'; void main() { setupFirebaseFunctionsMocks(); MethodChannelFirebaseFunctions? functions; MethodChannelHttpsCallable? httpsCallable; - final List logger = []; // mock props bool mockPlatformExceptionThrown = false; @@ -32,22 +32,15 @@ void main() { setUpAll(() async { FirebaseApp app = await Firebase.initializeApp(); - handleMethodCall((call) async { - logger.add(call); + TestCloudFunctionsHostApi.setUp(_TestCloudFunctionsHostApi(() async { if (mockExceptionThrown) { throw Exception(); } else if (mockPlatformExceptionThrown) { throw PlatformException( code: 'UNKNOWN', message: kPlatformExceptionMessage); } - - switch (call.method) { - case 'FirebaseFunctions#call': - return kParameters; - default: - return null; - } - }); + return kParameters; + })); functions = MethodChannelFirebaseFunctions(app: app, region: 'us-central1'); @@ -64,8 +57,6 @@ void main() { mockPlatformExceptionThrown = false; mockExceptionThrown = false; httpsCallable!.options = kOptions; - - logger.clear(); }); group('constructor', () { @@ -101,6 +92,22 @@ void main() { }); group('call', () { + test('converts maps nested in lists', () async { + final originalParameters = kParameters; + addTearDown(() => kParameters = originalParameters); + kParameters = [ + {'name': 'value'}, + ]; + + final result = await httpsCallable!.call(); + + expect(result, isA>()); + expect((result as List).single, isA>()); + expect(result, [ + {'name': 'value'}, + ]); + }); + test('catch an [Exception] error', () async { mockExceptionThrown = true; await testExceptionHandling('EXCEPTION', httpsCallable!.call); @@ -115,3 +122,15 @@ void main() { }); }); } + +class _TestCloudFunctionsHostApi implements TestCloudFunctionsHostApi { + _TestCloudFunctionsHostApi(this.callHandler); + + final Future Function() callHandler; + + @override + Future call(Map arguments) => callHandler(); + + @override + Future registerEventChannel(Map arguments) async {} +}