From ad965249666b62884dcd6098c9be53a85b85b4c5 Mon Sep 17 00:00:00 2001 From: Gabriel Moro Date: Mon, 29 Sep 2025 08:11:16 -0300 Subject: [PATCH 1/3] Add unit tests for the commander --- .github/workflows/pr.yml | 1 + .../core/commander/panda_commander_test.dart | 96 +++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 panda_svg/test/core/commander/panda_commander_test.dart diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 05dbabd..a7417ec 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -17,6 +17,7 @@ jobs: uses: ./.github/actions/setup-flutter - name: Run tests + working-directory: ./panda_svg run: flutter test - name: Analyze diff --git a/panda_svg/test/core/commander/panda_commander_test.dart b/panda_svg/test/core/commander/panda_commander_test.dart new file mode 100644 index 0000000..efe4b17 --- /dev/null +++ b/panda_svg/test/core/commander/panda_commander_test.dart @@ -0,0 +1,96 @@ +import 'package:panda_svg/core/commander/command.dart'; +import 'package:panda_svg/model/node_coordinate.dart'; +import 'package:test/test.dart'; + +import '../../../core/commander/panda_commander.dart'; + +void main() { + late PandaCommander commander; + + setUp(() { + commander = PandaCommander(); + }); + + test('should emit correct JS for UpdateBackgroundColor', () async { + final command = UpdateBackgroundColor( + id: 'node1', + colorHex: '#FFFFFF', + ); + + expectLater( + commander.stream, + emits("updateBackgroundColor('node1','#FFFFFF');"), + ); + + commander.execute(command); + }); + + test('should emit correct JS for UpdateStrokeColor', () async { + final command = UpdateStrokeColor( + id: 'node2', + colorHex: '#000000', + ); + + expectLater( + commander.stream, + emits("updateStrokeColor('node2','#000000');"), + ); + + commander.execute(command); + }); + + test('should emit correct JS for UpdateStrokeWidth', () async { + final command = UpdateStrokeWidth( + id: 'node3', + widthInPx: 5, + ); + + expectLater( + commander.stream, + emits("updateStrokeWidth('node3',5);"), + ); + + commander.execute(command); + }); + + test('should emit correct JS for RemoveNode', () async { + final command = RemoveNode(id: 'node4'); + + expectLater( + commander.stream, + emits("removeNode('node4');"), + ); + + commander.execute(command); + }); + + test('should emit correct JS for UpdateRootBackgroundColor', () async { + final command = UpdateRootBackgroundColor(colorInHex: '#ABCDEF'); + + expectLater( + commander.stream, + emits("updateRootBackgroundColor('#ABCDEF');"), + ); + + commander.execute(command); + }); + + test('should emit correct JS for AddRoundedImage', () async { + final command = AddRoundedImage( + elementId: 'container', + imageId: 'img1', + imageUrl: 'http://example.com/image.png', + widthInPx: 100, + heightInPx: 200, + coordinate: NodeCoordinate(x: 50, y: 75), + ); + + expectLater( + commander.stream, + emits("addRoundedImage('container','img1','http://example.com/image.png'," + "'100','200','50.0','75.0');"), + ); + + commander.execute(command); + }); +} From e833fe8ad66f6e4027bab6365a4b6150d26582f1 Mon Sep 17 00:00:00 2001 From: Gabriel Moro Date: Mon, 29 Sep 2025 08:16:54 -0300 Subject: [PATCH 2/3] Update workflow --- .github/actions/setup-flutter/action.yml | 10 +--------- .github/workflows/pr.yml | 12 +++++++++++- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/.github/actions/setup-flutter/action.yml b/.github/actions/setup-flutter/action.yml index 1b859fa..eece83d 100644 --- a/.github/actions/setup-flutter/action.yml +++ b/.github/actions/setup-flutter/action.yml @@ -7,12 +7,4 @@ runs: - name: Set up Flutter uses: subosito/flutter-action@v2 with: - flutter-version: '3.32.6' # Set the desired Flutter version - - - name: Install dependencies - run: flutter pub get - shell: bash - - - name: Generate files - run: dart run build_runner build --delete-conflicting-outputs - shell: bash \ No newline at end of file + flutter-version: '3.32.6' # Set the desired Flutter version \ No newline at end of file diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index a7417ec..debc0ad 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -15,10 +15,20 @@ jobs: - name: Set up Flutter uses: ./.github/actions/setup-flutter + + - name: Install dependencies - Panda SVG + working-directory: ./panda_svg + run: flutter pub get + shell: bash - - name: Run tests + - name: Run tests - Panda SVG working-directory: ./panda_svg run: flutter test + - name: Install dependencies - Sample project + working-directory: ./sample + run: flutter pub get + shell: bash + - name: Analyze run: dart analyze From b2e8b410df30a1148e629a6e2b5b625068283e44 Mon Sep 17 00:00:00 2001 From: Gabriel Moro Date: Mon, 29 Sep 2025 08:23:55 -0300 Subject: [PATCH 3/3] Solve lint issues --- panda_svg/core/commander/panda_commander.dart | 39 ------------ panda_svg/core/panda_widget.dart | 60 ------------------- .../core/commander/panda_commander_test.dart | 3 +- sample/lib/sample_app.dart | 5 -- .../widgets/commands_bottom_sheet_widget.dart | 6 +- 5 files changed, 4 insertions(+), 109 deletions(-) delete mode 100644 panda_svg/core/commander/panda_commander.dart delete mode 100644 panda_svg/core/panda_widget.dart diff --git a/panda_svg/core/commander/panda_commander.dart b/panda_svg/core/commander/panda_commander.dart deleted file mode 100644 index 56152b5..0000000 --- a/panda_svg/core/commander/panda_commander.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'dart:async'; - -import 'package:panda_svg/core/commander/command.dart'; - -class PandaCommander { - final _command = StreamController.broadcast(); - - Stream get stream => _command.stream; - - void execute(Command command) { - _command.add(_convertToJSCode(command)); - } - - // ignore_for_file: lines_longer_than_80_chars - String _convertToJSCode(Command command) { - switch (command) { - case UpdateBackgroundColor(): - return 'updateBackgroundColor(\'${command.id}\',\'${command.colorHex}\');'; - case UpdateStrokeColor(): - return 'updateStrokeColor(\'${command.id}\',\'${command.colorHex}\');'; - case UpdateStrokeWidth(): - return 'updateStrokeWidth(\'${command.id}\',${command.widthInPx});'; - case RemoveNode(): - return 'removeNode(\'${command.id}\');'; - case UpdateRootBackgroundColor(): - return 'updateRootBackgroundColor(\'${command.colorInHex}\');'; - case AddRoundedImage(): - return 'addRoundedImage(' - '\'${command.elementId}\',' - '\'${command.imageId}\',' - '\'${command.imageUrl}\',' - '\'${command.widthInPx}\',' - '\'${command.heightInPx}\',' - '\'${command.coordinate.x}\',' - '\'${command.coordinate.y}\'' - ');'; - } - } -} diff --git a/panda_svg/core/panda_widget.dart b/panda_svg/core/panda_widget.dart deleted file mode 100644 index 91d1226..0000000 --- a/panda_svg/core/panda_widget.dart +++ /dev/null @@ -1,60 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:panda_svg/core/constants.dart'; -import 'commander/panda_commander.dart'; -import 'package:webview_flutter/webview_flutter.dart'; - -class PandaWidget extends StatefulWidget { - final String svgText; - final PandaCommander commander; - - const PandaWidget({ - super.key, - required this.svgText, - required this.commander, - }); - - @override - State createState() => _PandaWebViewState(); -} - -class _PandaWebViewState extends State { - late final WebViewController _controller; - - _PandaWebViewState(); - - @override - void initState() { - super.initState(); - - _setup(); - } - - Future _setup() async { - _controller = WebViewController() - ..setJavaScriptMode(JavaScriptMode.unrestricted); - - final svgText = widget.svgText; - - final completeHtml = baseHtml.replaceFirst(htmlSVGMarker, svgText); - - await _controller.loadHtmlString(completeHtml); - - widget.commander.stream.listen( - (jsCommand) => _runJavascript(jsCommand), - ); - } - - Future _runJavascript(String jsCommand) async { - final result = await _controller.runJavaScriptReturningResult( - jsCommand, - ); - debugPrint(result.toString()); - } - - @override - Widget build(BuildContext context) { - return WebViewWidget( - controller: _controller, - ); - } -} diff --git a/panda_svg/test/core/commander/panda_commander_test.dart b/panda_svg/test/core/commander/panda_commander_test.dart index efe4b17..b5f3d6d 100644 --- a/panda_svg/test/core/commander/panda_commander_test.dart +++ b/panda_svg/test/core/commander/panda_commander_test.dart @@ -1,9 +1,8 @@ import 'package:panda_svg/core/commander/command.dart'; +import 'package:panda_svg/core/commander/panda_commander.dart'; import 'package:panda_svg/model/node_coordinate.dart'; import 'package:test/test.dart'; -import '../../../core/commander/panda_commander.dart'; - void main() { late PandaCommander commander; diff --git a/sample/lib/sample_app.dart b/sample/lib/sample_app.dart index 23d53de..1f5700f 100644 --- a/sample/lib/sample_app.dart +++ b/sample/lib/sample_app.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:panda_svg/core/commander/command.dart'; import 'package:panda_svg/core/commander/panda_commander.dart'; import 'package:panda_svg/core/panda_widget.dart'; import 'package:panda_svg/model/node_info.dart'; @@ -61,10 +60,6 @@ class _SampleAppState extends State { ); } - void _onClick() { - widget.commander.execute(UpdateRootBackgroundColor(colorInHex: '#008000')); - } - _updateSelectedNode(NodeInfo nodeInfo) { setState(() { bottomSheetUiModels = SampleCommandsGenerator.generate(nodeInfo); diff --git a/sample/lib/widgets/commands_bottom_sheet_widget.dart b/sample/lib/widgets/commands_bottom_sheet_widget.dart index cb304bf..40c97b9 100644 --- a/sample/lib/widgets/commands_bottom_sheet_widget.dart +++ b/sample/lib/widgets/commands_bottom_sheet_widget.dart @@ -2,10 +2,10 @@ import 'package:flutter/material.dart'; import 'package:sampleapp/widgets/bottom_sheet_ui_model.dart'; class CommandsBottomSheetWidget extends StatefulWidget { - List uiModels; - Function(CommandUiModel) onSelectCommand; + final List uiModels; + final Function(CommandUiModel) onSelectCommand; - CommandsBottomSheetWidget({ + const CommandsBottomSheetWidget({ super.key, required this.uiModels, required this.onSelectCommand,