Skip to content

Commit 27e74d1

Browse files
author
GitLab CI
committed
style: dart format all files
1 parent 78a3f98 commit 27e74d1

41 files changed

Lines changed: 1522 additions & 815 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

bin/flutter_skill.dart

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ void main(List<String> args) async {
3434
print(' explore <url> AI Test Agent — auto-explore and test any web app');
3535
print(' monkey <url> Monkey testing — random fuzz testing for web apps');
3636
print(' plan <url> AI Test Plan Generator — auto-generate test cases');
37-
print(' security <url> Security Scanner — XSS, CSRF, headers, sensitive data');
37+
print(
38+
' security <url> Security Scanner — XSS, CSRF, headers, sensitive data');
3839
print(' diff <url> Diff testing — compare app state against baseline');
3940
print(' test <url> Zero-config web testing — launch Chrome + CDP');
4041
print(' doctor Check installation and environment health');
@@ -117,33 +118,36 @@ void main(List<String> args) async {
117118
print('');
118119
print('Examples:');
119120
print(' flutter-skill test https://example.com');
120-
print(' flutter-skill test --url=https://example.com --platforms=web,electron,android');
121+
print(
122+
' flutter-skill test --url=https://example.com --platforms=web,electron,android');
121123
print('');
122124
print('Options:');
123125
print(' --url=<url> URL to test');
124-
print(' --platforms=<list> Platforms: web,electron,android,ios (default: web)');
126+
print(
127+
' --platforms=<list> Platforms: web,electron,android,ios (default: web)');
125128
print(' --cdp-port=<port> CDP port (default: 9222)');
126129
print(' --no-headless Show browser window');
127130
print(' --report=<path> Save JSON report to file');
128131
exit(1);
129132
}
130133
// Check if --platforms flag is used → parallel test runner
131-
final hasMultiPlatform = commandArgs.any((a) => a.startsWith('--platforms='));
134+
final hasMultiPlatform =
135+
commandArgs.any((a) => a.startsWith('--platforms='));
132136
if (hasMultiPlatform) {
133137
await runTestRunner(commandArgs);
134138
} else {
135139
// Single-platform: convenience wrapper → server --url=<url>
136140
final testUrl = commandArgs.firstWhere((a) => !a.startsWith('--'),
137141
orElse: () => commandArgs
138-
.firstWhere((a) => a.startsWith('--url='),
139-
orElse: () => '')
142+
.firstWhere((a) => a.startsWith('--url='), orElse: () => '')
140143
.replaceFirst('--url=', ''));
141144
if (testUrl.isEmpty) {
142145
print('Error: URL is required');
143146
exit(1);
144147
}
145148
final serverArgs = ['--url=$testUrl'];
146-
serverArgs.addAll(commandArgs.where((a) => a != testUrl && !a.startsWith('--url=')));
149+
serverArgs.addAll(
150+
commandArgs.where((a) => a != testUrl && !a.startsWith('--url=')));
147151
await runServer(serverArgs);
148152
}
149153
break;

lib/src/bridge/cdp_driver.dart

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ 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 = {};
37+
final Map<String, List<void Function(Map<String, dynamic>)>> _eventListeners =
38+
{};
3839
bool _dialogHandlerInstalled = false;
3940
final Map<String, Map<String, dynamic>> _interceptRules = {};
4041

@@ -114,7 +115,10 @@ class CdpDriver implements AppDriver {
114115
// When connecting to an existing instance (launchChrome=false),
115116
// skip navigation if URL is about:blank or matches the CDP port
116117
// (the target already has content loaded).
117-
final skipNav = !_launchChrome && (_url.isEmpty || _url == 'about:blank' || _url.contains('localhost:$_port'));
118+
final skipNav = !_launchChrome &&
119+
(_url.isEmpty ||
120+
_url == 'about:blank' ||
121+
_url.contains('localhost:$_port'));
118122
if (!skipNav) {
119123
await _call('Page.navigate', {'url': _url});
120124
// Wait for DOMContentLoaded or timeout (much faster than fixed 2s delay)
@@ -675,26 +679,33 @@ class CdpDriver implements AppDriver {
675679
double startX, double startY, double endX, double endY) async {
676680
try {
677681
return await Future(() async {
678-
await _dispatchMouseEvent('mousePressed', startX, startY, button: 'left', clickCount: 1);
682+
await _dispatchMouseEvent('mousePressed', startX, startY,
683+
button: 'left', clickCount: 1);
679684
const steps = 10;
680685
for (var i = 1; i <= steps; i++) {
681686
final x = startX + (endX - startX) * i / steps;
682687
final y = startY + (endY - startY) * i / steps;
683688
await _dispatchMouseEvent('mouseMoved', x, y, button: 'left');
684689
}
685-
await _dispatchMouseEvent('mouseReleased', endX, endY, button: 'left', clickCount: 1);
690+
await _dispatchMouseEvent('mouseReleased', endX, endY,
691+
button: 'left', clickCount: 1);
686692
return {"success": true} as Map<String, dynamic>;
687693
}).timeout(const Duration(seconds: 10));
688694
} on TimeoutException {
689-
return {"success": false, "error": "Drag timed out — mouse event not acknowledged by browser"};
695+
return {
696+
"success": false,
697+
"error": "Drag timed out — mouse event not acknowledged by browser"
698+
};
690699
}
691700
}
692701

693702
/// Long press at coordinates.
694703
Future<void> longPressAt(double x, double y) async {
695-
await _dispatchMouseEvent('mousePressed', x, y, button: 'left', clickCount: 1);
704+
await _dispatchMouseEvent('mousePressed', x, y,
705+
button: 'left', clickCount: 1);
696706
await Future.delayed(const Duration(milliseconds: 800));
697-
await _dispatchMouseEvent('mouseReleased', x, y, button: 'left', clickCount: 1);
707+
await _dispatchMouseEvent('mouseReleased', x, y,
708+
button: 'left', clickCount: 1);
698709
}
699710

700711
/// Swipe between coordinates.
@@ -703,19 +714,24 @@ class CdpDriver implements AppDriver {
703714
{int durationMs = 300}) async {
704715
try {
705716
return await Future(() async {
706-
await _dispatchMouseEvent('mousePressed', startX, startY, button: 'left', clickCount: 1);
717+
await _dispatchMouseEvent('mousePressed', startX, startY,
718+
button: 'left', clickCount: 1);
707719
const steps = 8;
708720
for (var i = 1; i <= steps; i++) {
709721
final x = startX + (endX - startX) * i / steps;
710722
final y = startY + (endY - startY) * i / steps;
711723
await _dispatchMouseEvent('mouseMoved', x, y, button: 'left');
712724
await Future.delayed(Duration(milliseconds: durationMs ~/ steps));
713725
}
714-
await _dispatchMouseEvent('mouseReleased', endX, endY, button: 'left', clickCount: 1);
726+
await _dispatchMouseEvent('mouseReleased', endX, endY,
727+
button: 'left', clickCount: 1);
715728
return {"success": true} as Map<String, dynamic>;
716729
}).timeout(const Duration(seconds: 10));
717730
} on TimeoutException {
718-
return {"success": false, "error": "Swipe timed out — mouse event not acknowledged by browser"};
731+
return {
732+
"success": false,
733+
"error": "Swipe timed out — mouse event not acknowledged by browser"
734+
};
719735
}
720736
}
721737

@@ -765,21 +781,28 @@ class CdpDriver implements AppDriver {
765781
try {
766782
return await Future(() async {
767783
final first = points.first;
768-
await _dispatchMouseEvent('mousePressed', (first['x'] as num).toDouble(),
769-
(first['y'] as num).toDouble(), button: 'left');
784+
await _dispatchMouseEvent('mousePressed',
785+
(first['x'] as num).toDouble(), (first['y'] as num).toDouble(),
786+
button: 'left');
770787
for (var i = 1; i < points.length; i++) {
771-
await _dispatchMouseEvent('mouseMoved',
788+
await _dispatchMouseEvent(
789+
'mouseMoved',
772790
(points[i]['x'] as num).toDouble(),
773-
(points[i]['y'] as num).toDouble(), button: 'left');
791+
(points[i]['y'] as num).toDouble(),
792+
button: 'left');
774793
await Future.delayed(const Duration(milliseconds: 20));
775794
}
776795
final last = points.last;
777-
await _dispatchMouseEvent('mouseReleased', (last['x'] as num).toDouble(),
778-
(last['y'] as num).toDouble(), button: 'left');
796+
await _dispatchMouseEvent('mouseReleased',
797+
(last['x'] as num).toDouble(), (last['y'] as num).toDouble(),
798+
button: 'left');
779799
return {"success": true} as Map<String, dynamic>;
780800
}).timeout(const Duration(seconds: 10));
781801
} on TimeoutException {
782-
return {"success": false, "error": "Gesture timed out — mouse event not acknowledged by browser"};
802+
return {
803+
"success": false,
804+
"error": "Gesture timed out — mouse event not acknowledged by browser"
805+
};
783806
}
784807
}
785808

@@ -827,7 +850,8 @@ class CdpDriver implements AppDriver {
827850
return JSON.stringify({ success: true, checked: el.getAttribute('aria-checked') === 'true' });
828851
})()
829852
''');
830-
return _parseJsonEval(result) ?? {"success": false, "error": "Element not found"};
853+
return _parseJsonEval(result) ??
854+
{"success": false, "error": "Element not found"};
831855
}
832856

833857
/// Get slider value.
@@ -852,7 +876,8 @@ class CdpDriver implements AppDriver {
852876
});
853877
})()
854878
''');
855-
return _parseJsonEval(result) ?? {"success": false, "error": "Element not found"};
879+
return _parseJsonEval(result) ??
880+
{"success": false, "error": "Element not found"};
856881
}
857882

858883
/// Get page state (title, url, scroll, viewport).
@@ -1101,7 +1126,7 @@ class CdpDriver implements AppDriver {
11011126
}
11021127

11031128
/// Highlight an element on the page.
1104-
Future<Map<String, dynamic>> highlightElement(String selector,
1129+
Future<Map<String, dynamic>> highlightElement(String selector,
11051130
{String color = 'red', int duration = 3000}) async {
11061131
// Parse color to rgba for background (20% opacity)
11071132
final bgAlpha = '0.1';
@@ -1276,7 +1301,8 @@ class CdpDriver implements AppDriver {
12761301
_call(method, params);
12771302

12781303
/// Register a listener for a CDP event (supports multiple listeners per event).
1279-
void onEvent(String method, void Function(Map<String, dynamic> params) callback) {
1304+
void onEvent(
1305+
String method, void Function(Map<String, dynamic> params) callback) {
12801306
_eventListeners.putIfAbsent(method, () => []);
12811307
_eventListeners[method]!.add(callback);
12821308
}

lib/src/cli/ai_client.dart

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@ class AiClient {
3131
String model;
3232
if (key.startsWith('sk-ant-')) {
3333
// Anthropic — use their native API
34-
baseUrl = Platform.environment['AI_BASE_URL'] ??
35-
'https://api.anthropic.com';
34+
baseUrl =
35+
Platform.environment['AI_BASE_URL'] ?? 'https://api.anthropic.com';
3636
model = Platform.environment['AI_MODEL'] ?? 'claude-3-5-haiku-20241022';
3737
return _AnthropicClient(apiKey: key, baseUrl: baseUrl, model: model);
3838
} else {
3939
// OpenAI-compatible (OpenAI, Ollama, OpenRouter, etc.)
40-
baseUrl = Platform.environment['AI_BASE_URL'] ??
41-
'https://api.openai.com/v1';
40+
baseUrl =
41+
Platform.environment['AI_BASE_URL'] ?? 'https://api.openai.com/v1';
4242
model = Platform.environment['AI_MODEL'] ?? 'gpt-4o-mini';
4343
}
4444

@@ -114,7 +114,8 @@ class _AnthropicClient extends AiClient {
114114
final responseBody = await response.transform(utf8.decoder).join();
115115

116116
if (response.statusCode != 200) {
117-
throw Exception('Anthropic API error ${response.statusCode}: $responseBody');
117+
throw Exception(
118+
'Anthropic API error ${response.statusCode}: $responseBody');
118119
}
119120

120121
final data = jsonDecode(responseBody) as Map<String, dynamic>;

lib/src/cli/diff.dart

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,7 @@ Future<void> runDiff(List<String> args) async {
111111

112112
print('');
113113
print('✅ Baseline created at $baselinePath');
114-
print(
115-
' Run the same command again to compare against this baseline.');
114+
print(' Run the same command again to compare against this baseline.');
116115
} else {
117116
// Compare against baseline
118117
print('');
@@ -162,8 +161,7 @@ Future<void> runDiff(List<String> args) async {
162161
print(' Report saved to: $reportPath');
163162

164163
// Summary
165-
final changed =
166-
results.where((r) => r['status'] != 'unchanged').length;
164+
final changed = results.where((r) => r['status'] != 'unchanged').length;
167165
final total = results.length;
168166
print('');
169167
if (changed == 0) {
@@ -183,7 +181,8 @@ Future<void> runDiff(List<String> args) async {
183181

184182
/// Discover pages by crawling links
185183
Future<List<String>> _discoverPages(
186-
CdpDriver cdp, String startUrl, int maxDepth, {int maxPages = 10}) async {
184+
CdpDriver cdp, String startUrl, int maxDepth,
185+
{int maxPages = 10}) async {
187186
final visited = <String>{};
188187
final toVisit = <String>[startUrl];
189188
final baseUri = Uri.parse(startUrl);
@@ -497,8 +496,7 @@ Future<void> _generateDiffReport(
497496

498497
// Summary
499498
final total = results.length;
500-
final unchanged =
501-
results.where((r) => r['status'] == 'unchanged').length;
499+
final unchanged = results.where((r) => r['status'] == 'unchanged').length;
502500
final changed = results.where((r) => r['status'] == 'changed').length;
503501
final removed = results.where((r) => r['status'] == 'removed').length;
504502

@@ -520,8 +518,7 @@ Future<void> _generateDiffReport(
520518
final status = result['status'] as String;
521519
final pageUrl = result['url'] as String;
522520
final changes = result['changes'] as List? ?? [];
523-
final details =
524-
result['details'] as Map<String, dynamic>? ?? {};
521+
final details = result['details'] as Map<String, dynamic>? ?? {};
525522

526523
buf.writeln('<div class="page $status">');
527524
buf.writeln(
@@ -540,10 +537,8 @@ Future<void> _generateDiffReport(
540537
if (details['baseline_screenshot'] != null &&
541538
details['current_screenshot'] != null) {
542539
try {
543-
final baselineFile =
544-
File(details['baseline_screenshot'] as String);
545-
final currentFile =
546-
File(details['current_screenshot'] as String);
540+
final baselineFile = File(details['baseline_screenshot'] as String);
541+
final currentFile = File(details['current_screenshot'] as String);
547542
if (baselineFile.existsSync() && currentFile.existsSync()) {
548543
final baseB64 = base64.encode(await baselineFile.readAsBytes());
549544
final currB64 = base64.encode(await currentFile.readAsBytes());

lib/src/cli/doctor.dart

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,10 @@ Future<void> runDoctor(List<String> args) async {
117117
// ADB
118118
final adbDevices = await _run('adb', ['devices', '-l']);
119119
if (adbDevices != null) {
120-
final lines = adbDevices.split('\n').skip(1).where(
121-
(l) => l.trim().isNotEmpty && l.contains('device'));
120+
final lines = adbDevices
121+
.split('\n')
122+
.skip(1)
123+
.where((l) => l.trim().isNotEmpty && l.contains('device'));
122124
if (lines.isNotEmpty) {
123125
for (final line in lines) {
124126
final parts = line.trim().split(RegExp(r'\s+'));
@@ -146,7 +148,8 @@ Future<void> runDoctor(List<String> args) async {
146148
// iOS Simulator
147149
try {
148150
final result = await Process.run(
149-
'xcrun', ['simctl', 'list', 'devices', 'booted', '-j'],
151+
'xcrun',
152+
['simctl', 'list', 'devices', 'booted', '-j'],
150153
);
151154
if (result.exitCode == 0) {
152155
final json = jsonDecode(result.stdout as String);
@@ -206,7 +209,8 @@ Future<void> runDoctor(List<String> args) async {
206209

207210
// Internet check
208211
try {
209-
final result = await Process.run('ping', ['-c', '1', '-W', '2', 'google.com']);
212+
final result =
213+
await Process.run('ping', ['-c', '1', '-W', '2', 'google.com']);
210214
if (result.exitCode == 0) {
211215
ok('Internet connection');
212216
} else {
@@ -256,13 +260,15 @@ Future<void> runDoctor(List<String> args) async {
256260
print('');
257261
print(' AI Agent Config:');
258262

259-
final homeDir = Platform.environment['HOME'] ?? Platform.environment['USERPROFILE'];
263+
final homeDir =
264+
Platform.environment['HOME'] ?? Platform.environment['USERPROFILE'];
260265
if (homeDir != null) {
261266
final claudeSettings = File('$homeDir/.claude/settings.json');
262267
if (claudeSettings.existsSync()) {
263268
try {
264269
final content = claudeSettings.readAsStringSync();
265-
if (content.contains('flutter-skill') || content.contains('flutter_skill')) {
270+
if (content.contains('flutter-skill') ||
271+
content.contains('flutter_skill')) {
266272
ok('Claude Code MCP: configured');
267273
} else {
268274
warn('Claude Code MCP: not configured', 'Run: flutter-skill init');
@@ -278,7 +284,8 @@ Future<void> runDoctor(List<String> args) async {
278284
if (cursorConfig.existsSync()) {
279285
try {
280286
final content = cursorConfig.readAsStringSync();
281-
if (content.contains('flutter-skill') || content.contains('flutter_skill')) {
287+
if (content.contains('flutter-skill') ||
288+
content.contains('flutter_skill')) {
282289
ok('Cursor MCP: configured');
283290
} else {
284291
warn('Cursor MCP: not configured');

0 commit comments

Comments
 (0)