Skip to content

Commit 49603b6

Browse files
author
GitLab CI
committed
feat: monkey testing, self-healing, network mock, coverage, smart wait, data-driven, multi-device, deep a11y, session persistence
New commands: - flutter-skill monkey <url> — random fuzz testing with crash detection New MCP tools (+29, total 207): - smart_tap/enter_text/assert — self-healing with fuzzy match - mock_api/clear, record_network/replay_network - coverage_start/stop/report/gaps - wait_for_stable/url/text/element_count - test_with_data, generate_test_data - multi_connect/action/compare/disconnect - a11y_full_audit/tab_order/color_contrast/screen_reader - save_session/restore_session/session_diff
1 parent 5804535 commit 49603b6

13 files changed

Lines changed: 3530 additions & 0 deletions

bin/flutter_skill.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import 'package:flutter_skill/src/cli/demo.dart';
1111
import 'package:flutter_skill/src/cli/serve.dart';
1212
import 'package:flutter_skill/src/cli/test_runner.dart';
1313
import 'package:flutter_skill/src/cli/explore.dart';
14+
import 'package:flutter_skill/src/cli/monkey.dart';
1415

1516
void main(List<String> args) async {
1617
if (args.isEmpty) {
@@ -26,6 +27,7 @@ void main(List<String> args) async {
2627
print(' screenshot Take a screenshot of the running app');
2728
print(' serve <url> Zero-config WebMCP server — any site → AI tools');
2829
print(' explore <url> AI Test Agent — auto-explore and test any web app');
30+
print(' monkey <url> Monkey testing — random fuzz testing for web apps');
2931
print(' test <url> Zero-config web testing — launch Chrome + CDP');
3032
print(' doctor Check installation and environment health');
3133
print(' setup Install tool priority rules for Claude Code');
@@ -137,6 +139,9 @@ void main(List<String> args) async {
137139
await runServer(serverArgs);
138140
}
139141
break;
142+
case 'monkey':
143+
await runMonkey(commandArgs);
144+
break;
140145
default:
141146
print('Unknown command: $command');
142147
exit(1);

lib/src/bridge/cdp_driver.dart

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class CdpDriver implements AppDriver {
3434
/// Pending CDP calls keyed by request id.
3535
final Map<int, Completer<Map<String, dynamic>>> _pending = {};
3636
final Map<String, void Function()> _eventSubscriptions = {};
37+
final Map<String, List<void Function(Map<String, dynamic>)>> _eventListeners = {};
3738
bool _dialogHandlerInstalled = false;
3839
final Map<String, Map<String, dynamic>> _interceptRules = {};
3940

@@ -1160,6 +1161,22 @@ class CdpDriver implements AppDriver {
11601161
[Map<String, dynamic>? params]) =>
11611162
_call(method, params);
11621163

1164+
/// Alias for [call] used by monkey testing and other modules.
1165+
Future<Map<String, dynamic>> sendCommand(String method,
1166+
[Map<String, dynamic>? params]) =>
1167+
_call(method, params);
1168+
1169+
/// Register a listener for a CDP event (supports multiple listeners per event).
1170+
void onEvent(String method, void Function(Map<String, dynamic> params) callback) {
1171+
_eventListeners.putIfAbsent(method, () => []);
1172+
_eventListeners[method]!.add(callback);
1173+
}
1174+
1175+
/// Remove all listeners for a CDP event.
1176+
void removeEventListeners(String method) {
1177+
_eventListeners.remove(method);
1178+
}
1179+
11631180
Future<Map<String, dynamic>> _call(String method,
11641181
[Map<String, dynamic>? params]) async {
11651182
if (_ws == null || !_connected) {
@@ -1390,6 +1407,13 @@ function _dqAll(sel, root) {
13901407
final method = json['method'] as String?;
13911408
if (method != null) {
13921409
_eventSubscriptions[method]?.call();
1410+
final listeners = _eventListeners[method];
1411+
if (listeners != null) {
1412+
final params = (json['params'] as Map<String, dynamic>?) ?? {};
1413+
for (final cb in listeners) {
1414+
cb(params);
1415+
}
1416+
}
13931417
}
13941418
} catch (e) {
13951419
// Malformed message

0 commit comments

Comments
 (0)