Skip to content

Commit

Permalink
Merge pull request #2387 from leancodepl/change-patrol-output
Browse files Browse the repository at this point in the history
Change patrol output
  • Loading branch information
pdenert authored Nov 8, 2024
2 parents 6213633 + 9444598 commit 3a6854a
Show file tree
Hide file tree
Showing 20 changed files with 306 additions and 31 deletions.
2 changes: 2 additions & 0 deletions dev/e2e_app/integration_test/example_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ void main() {
await $(#textField).enterText('Hello, Flutter!');
expect($('Hello, Flutter!'), findsOneWidget);

$.log('Tapped the button');
await $.native.pressHome();
await $.native.openApp();

Expand All @@ -32,6 +33,7 @@ void main() {

patrol(
'short test with two tags',
skip: true,
tags: ['smoke', 'fume'],
($) async {
await createApp($);
Expand Down
2 changes: 2 additions & 0 deletions dev/e2e_app/macos/Flutter/GeneratedPluginRegistrant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import flutter_local_notifications
import flutter_timezone
import geolocator_apple
import patrol
import webview_flutter_wkwebview

func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin"))
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
FlutterTimezonePlugin.register(with: registry.registrar(forPlugin: "FlutterTimezonePlugin"))
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
PatrolPlugin.register(with: registry.registrar(forPlugin: "PatrolPlugin"))
FLTWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "FLTWebViewFlutterPlugin"))
}
24 changes: 19 additions & 5 deletions dev/e2e_app/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.7.10"
dispose_scope:
dependency: transitive
description:
name: dispose_scope
sha256: "48ec38ca2631c53c4f8fa96b294c801e55c335db5e3fb9f82cede150cfe5a2af"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
equatable:
dependency: transitive
description:
Expand Down Expand Up @@ -491,15 +499,21 @@ packages:
path: "../../packages/patrol"
relative: true
source: path
version: "3.11.1"
version: "3.11.2"
patrol_finders:
dependency: transitive
description:
name: patrol_finders
sha256: "6bf2c3093fbccd02f80f73fafc1bd021d76410cbab6e329be220b5e3bc58f072"
url: "https://pub.dev"
source: hosted
path: "../../packages/patrol_finders"
relative: true
source: path
version: "2.1.2"
patrol_log:
dependency: transitive
description:
path: "../../packages/patrol_log"
relative: true
source: path
version: "0.0.1"
permission_handler:
dependency: "direct main"
description:
Expand Down
3 changes: 2 additions & 1 deletion packages/patrol/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## Unreleased
## 3.13.0-dev.1

- Add support for the patrol_log package. (#2387)
- Fix tapping on notification on iOS 18. (#2394)

## 3.12.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ public RunDartTestResponse runDartTest(String name) {
if (response.getResult() == Contracts.RunDartTestResponseResult.failure) {
throw new AssertionError("Dart test failed: " + name + "\n" + response.getDetails());
}
Logger.INSTANCE.i(TAG + "Test execution succeeded");
return response;
} catch (PatrolAppServiceClientException e) {
Logger.INSTANCE.e(TAG + e.getMessage(), e.getCause());
Expand Down
8 changes: 8 additions & 0 deletions packages/patrol/lib/src/common.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import 'package:patrol/src/global_state.dart' as global_state;
import 'package:patrol/src/native/contracts/contracts.dart';
import 'package:patrol/src/native/native.dart';
import 'package:patrol_finders/patrol_finders.dart' as finders;
import 'package:patrol_log/patrol_log.dart';

/// We need [Group] to recreate test hierarchy.
// ignore: implementation_imports
Expand Down Expand Up @@ -94,11 +95,15 @@ void patrolTest(
LiveTestWidgetsFlutterBindingFramePolicy framePolicy =
LiveTestWidgetsFlutterBindingFramePolicy.fadePointers,
}) {
final patrolLog = PatrolLogWriter();
final automator = NativeAutomator(config: nativeAutomatorConfig);
final automator2 = NativeAutomator2(config: nativeAutomatorConfig);
final patrolBinding = PatrolBinding.ensureInitialized(nativeAutomatorConfig)
..framePolicy = framePolicy;

if (skip ?? false) {
patrolLog.log(TestEntry(name: description, status: TestEntryStatus.skip));
}
testWidgets(
description,
skip: skip,
Expand Down Expand Up @@ -131,6 +136,9 @@ void patrolTest(
// We don't have to call this line because automator.configure() does the same.
// await automator2.configure();

patrolLog.log(
TestEntry(name: description, status: TestEntryStatus.start),
);
final patrolTester = PatrolIntegrationTester(
tester: widgetTester,
nativeAutomator: automator,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import 'package:patrol/src/native/native_automator.dart';
import 'package:patrol/src/native/native_automator2.dart';
import 'package:patrol_finders/patrol_finders.dart' as finders;
import 'package:patrol_log/patrol_log.dart';

/// PatrolIntegrationTester extends the capabilities of [finders.PatrolTester]
/// with the ability to interact with native platform features via [native].
class PatrolIntegrationTester extends finders.PatrolTester {
/// Creates a new [PatrolIntegrationTester] which wraps [tester].
const PatrolIntegrationTester({
PatrolIntegrationTester({
required super.tester,
required super.config,
required this.nativeAutomator,
required this.nativeAutomator2,
});
}) : _patrolLog = PatrolLogWriter();

/// The log for the patrol.
final PatrolLogWriter _patrolLog;

/// Native automator that allows for interaction with OS the app is running
/// on.
Expand All @@ -28,4 +32,9 @@ class PatrolIntegrationTester extends finders.PatrolTester {

/// Shorthand for [nativeAutomator2].
NativeAutomator2 get native2 => nativeAutomator2;

/// Logs a message to the patrol log.
void log(String message) {
_patrolLog.log(LogEntry(message: message));
}
}
46 changes: 44 additions & 2 deletions packages/patrol/lib/src/native/native_automator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:meta/meta.dart';
import 'package:patrol/src/native/contracts/contracts.dart' as contracts;
import 'package:patrol/src/native/contracts/contracts.dart';
import 'package:patrol/src/native/contracts/native_automator_client.dart';
import 'package:patrol_log/patrol_log.dart';

/// Thrown when a native action fails.
class PatrolActionException implements Exception {
Expand Down Expand Up @@ -199,6 +200,7 @@ class NativeAutomator {
_config.logger('NativeAutomatorClient created, port: ${_config.port}');
}

final PatrolLogWriter _patrolLog = PatrolLogWriter();
final NativeAutomatorConfig _config;

late final NativeAutomatorClient _client;
Expand All @@ -214,19 +216,53 @@ class NativeAutomator {
throw StateError('unsupported platform');
}

Future<T> _wrapRequest<T>(String name, Future<T> Function() request) async {
Future<T> _wrapRequest<T>(
String name,
Future<T> Function() request, {
bool enablePatrolLog = true,
}) async {
_config.logger('$name() started');
final text =
'${AnsiCodes.lightBlue}$name${AnsiCodes.reset} ${AnsiCodes.gray}(native)${AnsiCodes.reset}';

if (enablePatrolLog) {
_patrolLog.log(StepEntry(action: text, status: StepEntryStatus.start));
}
try {
final result = await request();
_config.logger('$name() succeeded');
if (enablePatrolLog) {
_patrolLog
.log(StepEntry(action: text, status: StepEntryStatus.success));
}
return result;
} on NativeAutomatorClientException catch (err) {
_config.logger('$name() failed');
final log = 'NativeAutomatorClientException: '
'$name() failed with $err';

if (enablePatrolLog) {
_patrolLog.log(
StepEntry(
action: text,
status: StepEntryStatus.failure,
exception: log,
),
);
}
throw PatrolActionException(log);
} catch (err) {
_config.logger('$name() failed');

if (enablePatrolLog) {
_patrolLog.log(
StepEntry(
action: text,
status: StepEntryStatus.failure,
exception: err.toString(),
),
);
}
rethrow;
}
}
Expand All @@ -241,7 +277,11 @@ class NativeAutomator {
/// See also:
/// * https://github.com/flutter/flutter/issues/129231
Future<void> initialize() async {
await _wrapRequest('initialize', _client.initialize);
await _wrapRequest(
'initialize',
_client.initialize,
enablePatrolLog: false,
);
}

/// Configures the native automator.
Expand All @@ -260,6 +300,7 @@ class NativeAutomator {
findTimeoutMillis: _config.findTimeout.inMilliseconds,
),
),
enablePatrolLog: false,
);
exception = null;
break;
Expand Down Expand Up @@ -940,6 +981,7 @@ class NativeAutomator {
await _wrapRequest(
'markPatrolAppServiceReady',
_client.markPatrolAppServiceReady,
enablePatrolLog: false,
);
}
}
46 changes: 44 additions & 2 deletions packages/patrol/lib/src/native/native_automator2.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:patrol/src/native/contracts/contracts.dart' as contracts;
import 'package:patrol/src/native/contracts/native_automator_client.dart';
import 'package:patrol/src/native/native_automator.dart';
import 'package:patrol/src/native/native_automator.dart' as native_automator;
import 'package:patrol_log/patrol_log.dart';

/// This class represents the result of [NativeAutomator.getNativeViews].
class GetNativeViewsResult {
Expand Down Expand Up @@ -81,6 +82,7 @@ class NativeAutomator2 {
_config.logger('NativeAutomatorClient created, port: ${_config.port}');
}

final PatrolLogWriter _patrolLog = PatrolLogWriter();
final NativeAutomatorConfig _config;

late final NativeAutomatorClient _client;
Expand All @@ -96,19 +98,53 @@ class NativeAutomator2 {
throw StateError('unsupported platform');
}

Future<T> _wrapRequest<T>(String name, Future<T> Function() request) async {
Future<T> _wrapRequest<T>(
String name,
Future<T> Function() request, {
bool enablePatrolLog = true,
}) async {
_config.logger('$name() started');
final text =
'${AnsiCodes.lightBlue}$name${AnsiCodes.reset} ${AnsiCodes.gray}(native)${AnsiCodes.reset}';

if (enablePatrolLog) {
_patrolLog.log(StepEntry(action: text, status: StepEntryStatus.start));
}
try {
final result = await request();
_config.logger('$name() succeeded');
if (enablePatrolLog) {
_patrolLog
.log(StepEntry(action: text, status: StepEntryStatus.success));
}
return result;
} on NativeAutomatorClientException catch (err) {
_config.logger('$name() failed');
final log = 'NativeAutomatorClientException: '
'$name() failed with $err';

if (enablePatrolLog) {
_patrolLog.log(
StepEntry(
action: text,
status: StepEntryStatus.failure,
exception: log,
),
);
}
throw PatrolActionException(log);
} catch (err) {
_config.logger('$name() failed');

if (enablePatrolLog) {
_patrolLog.log(
StepEntry(
action: text,
status: StepEntryStatus.failure,
exception: err.toString(),
),
);
}
rethrow;
}
}
Expand All @@ -123,7 +159,11 @@ class NativeAutomator2 {
/// See also:
/// * https://github.com/flutter/flutter/issues/129231
Future<void> initialize() async {
await _wrapRequest('initialize', _client.initialize);
await _wrapRequest(
'initialize',
_client.initialize,
enablePatrolLog: false,
);
}

/// Configures the native automator.
Expand All @@ -142,6 +182,7 @@ class NativeAutomator2 {
findTimeoutMillis: _config.findTimeout.inMilliseconds,
),
),
enablePatrolLog: false,
);
exception = null;
break;
Expand Down Expand Up @@ -819,6 +860,7 @@ class NativeAutomator2 {
await _wrapRequest(
'markPatrolAppServiceReady',
_client.markPatrolAppServiceReady,
enablePatrolLog: false,
);
}
}
22 changes: 22 additions & 0 deletions packages/patrol/lib/src/native/patrol_app_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'dart:io';
import 'package:patrol/src/common.dart';
import 'package:patrol/src/native/contracts/contracts.dart';
import 'package:patrol/src/native/contracts/patrol_app_service_server.dart';
import 'package:patrol_log/patrol_log.dart';
import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf/shelf_io.dart' as shelf_io;

Expand Down Expand Up @@ -78,6 +79,8 @@ class PatrolAppService extends PatrolAppServiceServer {
return _testExecutionCompleted.future;
}

final PatrolLogWriter _patrolLog = PatrolLogWriter();

/// Marks [dartFileName] as completed with the given [passed] status.
///
/// If an exception was thrown during the test, [details] should contain the
Expand Down Expand Up @@ -150,6 +153,25 @@ class PatrolAppService extends PatrolAppServiceServer {
_testExecutionRequested.complete(request.name);

final testExecutionResult = await testExecutionCompleted;
if (!testExecutionResult.passed) {
_patrolLog.log(
TestEntry(
name: request.name,
status: TestEntryStatus.failure,
),
);
testExecutionResult.details?.split('\n').forEach(
(e) => _patrolLog.log(ErrorEntry(message: e)),
);
} else {
_patrolLog.log(
TestEntry(
name: request.name,
status: TestEntryStatus.success,
),
);
}

return RunDartTestResponse(
result: testExecutionResult.passed
? RunDartTestResponseResult.success
Expand Down
Loading

0 comments on commit 3a6854a

Please sign in to comment.