From f30f9a5433bf9245145e24e8f79aa70721c7f850 Mon Sep 17 00:00:00 2001 From: Ernesto Ramirez Date: Mon, 23 Mar 2026 19:31:10 -0600 Subject: [PATCH 1/2] fix: plugin selection on terminal during choices prompt --- .../flutterfire_cli/lib/src/commands/install.dart | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/flutterfire_cli/lib/src/commands/install.dart b/packages/flutterfire_cli/lib/src/commands/install.dart index 1273e94a..06f658e7 100644 --- a/packages/flutterfire_cli/lib/src/commands/install.dart +++ b/packages/flutterfire_cli/lib/src/commands/install.dart @@ -144,15 +144,15 @@ class InstallCommand extends FlutterFireCommand { .where( (element) => listAvailablePluginsInVersion.contains(element.name), ) - .map((plugin) => plugin.displayName) .toList(); + final displayNames = choices.map((plugin) => plugin.displayName).toList(); final defaultSelection = List.filled(choices.length, false); for (final dependency in flutterApp!.package.dependencies) { - final enumValue = FlutterFirePlugins.values.firstWhereOrNull( + final enumValue = choices.firstWhereOrNull( (element) => element.name == dependency, ); if (enumValue != null) { - final index = choices.indexOf(enumValue.displayName); + final index = choices.indexOf(enumValue); defaultSelection[index] = true; } } @@ -161,11 +161,12 @@ class InstallCommand extends FlutterFireCommand { final selectedChoices = promptMultiSelect( 'Select the Firebase plugins you would like to install', - choices, + displayNames, defaultSelection: defaultSelection, ); for (final index in selectedChoices) { - selectedPlugins.add(FlutterFirePlugins.values[index]); + // retrieve plugin based on the choices list + selectedPlugins.add(choices[index]); } return selectedPlugins; } From 2f7e83eceef001f2926224bb438751b43aa6f0dd Mon Sep 17 00:00:00 2001 From: Ernesto Ramirez Date: Tue, 28 Apr 2026 16:35:08 -0600 Subject: [PATCH 2/2] add test --- .../flutterfire_cli/test/install_test.dart | 95 ++++++++++++++++++- 1 file changed, 94 insertions(+), 1 deletion(-) diff --git a/packages/flutterfire_cli/test/install_test.dart b/packages/flutterfire_cli/test/install_test.dart index de79628b..ce41ddac 100644 --- a/packages/flutterfire_cli/test/install_test.dart +++ b/packages/flutterfire_cli/test/install_test.dart @@ -1,11 +1,21 @@ +import 'dart:convert'; import 'dart:io'; +import 'package:async/async.dart'; import 'package:path/path.dart' as p; import 'package:pubspec_parse/pubspec_parse.dart'; import 'package:test/test.dart'; import 'test_utils.dart'; +Future _waitForLine(StreamQueue queue, String content) async { + while (await queue.hasNext) { + final line = await queue.next; + if (line.contains(content)) return true; + } + return false; +} + void main() { String? projectPath; setUp(() async { @@ -131,7 +141,6 @@ void main() { Duration(minutes: 2), ), ); - test( 'Installs then use --only-pubspec-plugins flag to remove dependency', () async { @@ -189,4 +198,88 @@ void main() { Duration(minutes: 2), ), ); + test( + 'Installs from CLI', + () async { + final process = await Process.start( + 'flutterfire', + [ + 'install', + '4.10.0', + ], + workingDirectory: projectPath, + runInShell: true, + ); + final stdoutLines = StreamQueue( + process.stdout + .transform(utf8.decoder) /*.transform(const LineSplitter())*/, + ); + + await _waitForLine( + stdoutLines, + 'Select the Firebase plugins you would like to install', + ); + + // Core + process.stdin.write(' '); + + // Analytics + process.stdin.write('\x1b[B'); + process.stdin.write(' '); + + // Crashlytics + process.stdin.write('\x1b[B' * 4); + process.stdin.write(' '); + + // Messaging + process.stdin.write('\x1b[B' * 5); + process.stdin.write(' '); + + // Performance + process.stdin.write('\x1b[B' * 2); + process.stdin.write(' '); + + // Remote Config + process.stdin.write('\x1b[B'); + process.stdin.write(' '); + + // confirm selection + process.stdin.write('\r'); + + await process.stdin.flush(); + + final installSuccess = + await _waitForLine(stdoutLines, 'Successfully installed'); + expect(installSuccess, isTrue); + + // finish + await process.stdin.flush(); + await process.stdin.close(); + + if (await process.exitCode != 0) { + final errorOutput = await process.stderr.transform(utf8.decoder).join(); + fail(errorOutput); + } + + final parsedPubspec = Pubspec.parse( + await File(p.join(projectPath!, 'pubspec.yaml')).readAsString(), + ); + + expect(parsedPubspec.dependencies['firebase_analytics'], isNotNull); + expect(parsedPubspec.dependencies['firebase_core'], isNotNull); + expect(parsedPubspec.dependencies['firebase_performance'], isNotNull); + expect(parsedPubspec.dependencies['firebase_remote_config'], isNotNull); + expect(parsedPubspec.dependencies['firebase_crashlytics'], isNotNull); + expect(parsedPubspec.dependencies['firebase_messaging'], isNotNull); + + expect(parsedPubspec.dependencies['firebase_in_app_messaging'], isNull); + expect( + parsedPubspec.dependencies['firebase_ml_model_downloader'], + isNull, + ); + }, + timeout: const Timeout( + Duration(minutes: 2), + ), + ); }