Skip to content

Commit

Permalink
Merge pull request #2294 from gogolon/features/code-coverage
Browse files Browse the repository at this point in the history
Code coverage
  • Loading branch information
gogolon authored Sep 13, 2024
2 parents 7695660 + 569dc8c commit 2656cfe
Show file tree
Hide file tree
Showing 23 changed files with 849 additions and 84 deletions.
18 changes: 18 additions & 0 deletions docs/cli-commands/test.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,24 @@ patrol test --exclude-tags android
patrol test --exclude-tags='(android||ios)'
```

#### Coverage

To collect coverage from patrol tests, use `--coverage`.

```
patrol test --coverage
```

The LCOV report will be saved to `/coverage/patrol_lcov.info`.

Additionally, you can exclude certain files from the report using glob patterns and `--coverage-ignore` option. For instance,

```
patrol test --coverage --coverage-ignore="**/*.g.dart"
```

excludes all files ending with `.g.dart`.

### Under the hood

`patrol test` basically calls `patrol build` and then runs the built app
Expand Down
17 changes: 9 additions & 8 deletions docs/compatibility-table.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ is by always using the latest version. However,
if for some reason that isn't possible, you can refer to
the table below to assess which version you should use.

| patrol | patrol_cli |
| patrol_cli | patrol |
| -------------- | -------------- |
| 3.10.0 - | 3.1.0 - |
| 3.6.0 - | 2.6.5 - 3.0.1 |
| 3.4.0 - 3.5.2 | 2.6.0 - 2.6.4 |
| 3.0.0 - 3.3.0 | 2.3.0 - 2.5.0 |
| 2.3.0 - 2.3.2 | 2.2.0 - 2.2.2 |
| 2.0.1 - 2.2.5 | 2.0.1 - 2.1.5 |
| 3.2.0 - | 3.11.0 - |
| 3.1.0 - 3.1.1 | 3.10.0 |
| 2.6.5 - 3.0.1 | 3.6.0 - 3.10.0 |
| 2.6.0 - 2.6.4 | 3.4.0 - 3.5.2 |
| 2.3.0 - 2.5.0 | 3.0.0 - 3.3.0 |
| 2.2.0 - 2.2.2 | 2.3.0 - 2.3.2 |
| 2.0.1 - 2.1.5 | 2.0.1 - 2.2.5 |
| 2.0.0 | 2.0.0 |
| 1.0.9 - 1.1.11 | 1.1.4 - 1.1.11 |
| 1.1.4 - 1.1.11 | 1.0.9 - 1.1.11 |
5 changes: 3 additions & 2 deletions packages/patrol/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
## Unreleased
## 3.11.0

- Add code coverage collection support. (#2294)
- No throw error in `selectFineLocation` when it's already selected. (#2302)
- Add Option to select tap Location in enterText and enterTextByIndex (#2312)
- Add option to select tap location in `enterText` and `enterTextByIndex` (#2312)

## 3.10.0

Expand Down
23 changes: 23 additions & 0 deletions packages/patrol/lib/src/binding.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'dart:io' as io;
import 'dart:isolate';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
Expand Down Expand Up @@ -93,6 +96,25 @@ class PatrolBinding extends LiveTestWidgetsFlutterBinding {
final nameOfRequestedTest = await patrolAppService.testExecutionRequested;

if (nameOfRequestedTest == _currentDartTest) {
if (const bool.fromEnvironment('COVERAGE_ENABLED')) {
postEvent(
'waitForCoverageCollection',
{'mainIsolateId': Service.getIsolateId(Isolate.current)},
);

final testCompleter = Completer<void>();

registerExtension(
'ext.patrol.markTestCompleted',
(method, parameters) async {
testCompleter.complete();
return ServiceExtensionResponse.result(jsonEncode({}));
},
);

await testCompleter.future;
}

logger(
'finished test $_currentDartTest. Will report its status back to the native side',
);
Expand All @@ -101,6 +123,7 @@ class PatrolBinding extends LiveTestWidgetsFlutterBinding {
logger(
'tearDown(): test "$testName" in group "$_currentDartTest", passed: $passed',
);

await patrolAppService.markDartTestAsCompleted(
dartFileName: _currentDartTest!,
passed: passed,
Expand Down
24 changes: 20 additions & 4 deletions packages/patrol/lib/src/common.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'dart:developer';
import 'dart:io' as io;

import 'package:boolean_selector/boolean_selector.dart';
Expand Down Expand Up @@ -266,19 +267,34 @@ String deduplicateGroupEntryName(String parentName, String currentName) {
);
}

/// Recursively prints the structure of the test suite.
/// Recursively prints the structure of the test suite and reports test count
/// of the top-most group
@internal
void printGroupStructure(DartGroupEntry group, {int indentation = 0}) {
int reportGroupStructure(DartGroupEntry group, {int indentation = 0}) {
var testCount = group.type == GroupEntryType.test ? 1 : 0;

final indent = ' ' * indentation;
debugPrint("$indent-- group: '${group.name}'");
final tag = group.type == GroupEntryType.group ? 'group' : 'test';
debugPrint("$indent-- $tag: '${group.name}'");

for (final entry in group.entries) {
if (entry.type == GroupEntryType.test) {
++testCount;
debugPrint("$indent -- test: '${entry.name}'");
} else {
for (final subgroup in entry.entries) {
printGroupStructure(subgroup, indentation: indentation + 5);
testCount +=
reportGroupStructure(subgroup, indentation: indentation + 5);
}
}
}

if (indentation == 0) {
postEvent(
'testCount',
{'testCount': testCount},
);
}

return testCount;
}
2 changes: 1 addition & 1 deletion packages/patrol/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: patrol
description: >
Powerful Flutter-native UI testing framework overcoming limitations of
existing Flutter testing tools. Ready for action!
version: 3.10.0
version: 3.11.0
homepage: https://patrol.leancode.co
repository: https://github.com/leancodepl/patrol/tree/master/packages/patrol
issue_tracker: https://github.com/leancodepl/patrol/issues
Expand Down
4 changes: 4 additions & 0 deletions packages/patrol_cli/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 3.2.0

- Add code coverage collection support (#2294)

## 3.1.1

- Fix checking `java` version. (#2301)
Expand Down
2 changes: 1 addition & 1 deletion packages/patrol_cli/lib/src/base/constants.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
/// Version of Patrol CLI. Must be kept in sync with pubspec.yaml.
/// If you update this, make sure that compatibility-table.mdx is updated (if needed)
const version = '3.1.1';
const version = '3.2.0';
2 changes: 1 addition & 1 deletion packages/patrol_cli/lib/src/commands/develop.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import 'package:patrol_cli/src/base/exceptions.dart';
import 'package:patrol_cli/src/base/extensions/core.dart';
import 'package:patrol_cli/src/base/logger.dart';
import 'package:patrol_cli/src/commands/dart_define_utils.dart';
import 'package:patrol_cli/src/compatibility_checker.dart';
import 'package:patrol_cli/src/compatibility_checker/compatibility_checker.dart';
import 'package:patrol_cli/src/crossplatform/app_options.dart';
import 'package:patrol_cli/src/crossplatform/flutter_tool.dart';
import 'package:patrol_cli/src/dart_defines_reader.dart';
Expand Down
36 changes: 35 additions & 1 deletion packages/patrol_cli/lib/src/commands/test.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import 'dart:async';

import 'package:glob/glob.dart';
import 'package:patrol_cli/src/analytics/analytics.dart';
import 'package:patrol_cli/src/android/android_test_backend.dart';
import 'package:patrol_cli/src/base/extensions/core.dart';
import 'package:patrol_cli/src/base/logger.dart';
import 'package:patrol_cli/src/commands/dart_define_utils.dart';
import 'package:patrol_cli/src/compatibility_checker.dart';
import 'package:patrol_cli/src/compatibility_checker/compatibility_checker.dart';
import 'package:patrol_cli/src/coverage/coverage_tool.dart';
import 'package:patrol_cli/src/crossplatform/app_options.dart';
import 'package:patrol_cli/src/dart_defines_reader.dart';
import 'package:patrol_cli/src/devices.dart';
Expand All @@ -27,6 +29,7 @@ class TestCommand extends PatrolCommand {
required AndroidTestBackend androidTestBackend,
required IOSTestBackend iosTestBackend,
required MacOSTestBackend macOSTestBackend,
required CoverageTool coverageTool,
required Analytics analytics,
required Logger logger,
}) : _deviceFinder = deviceFinder,
Expand All @@ -38,6 +41,7 @@ class TestCommand extends PatrolCommand {
_androidTestBackend = androidTestBackend,
_iosTestBackend = iosTestBackend,
_macosTestBackend = macOSTestBackend,
_coverageTool = coverageTool,
_analytics = analytics,
_logger = logger {
usesTargetOption();
Expand All @@ -51,6 +55,7 @@ class TestCommand extends PatrolCommand {
usesPortOptions();
usesTagsOption();
usesExcludeTagsOption();
useCoverageOptions();

usesUninstallOption();

Expand All @@ -67,6 +72,7 @@ class TestCommand extends PatrolCommand {
final AndroidTestBackend _androidTestBackend;
final IOSTestBackend _iosTestBackend;
final MacOSTestBackend _macosTestBackend;
final CoverageTool _coverageTool;

final Analytics _analytics;
final Logger _logger;
Expand Down Expand Up @@ -159,6 +165,8 @@ See https://github.com/leancodepl/patrol/issues/1316 to learn more.
final wait = intArg('wait') ?? defaultWait;
final displayLabel = boolArg('label');
final uninstall = boolArg('uninstall');
final coverageEnabled = boolArg('coverage');
final ignoreGlobs = stringsArg('coverage-ignore').map(Glob.new).toSet();

final customDartDefines = {
..._dartDefinesReader.fromFile(),
Expand All @@ -175,6 +183,7 @@ See https://github.com/leancodepl/patrol/issues/1316 to learn more.
'PATROL_TEST_LABEL_ENABLED': displayLabel.toString(),
'PATROL_TEST_SERVER_PORT': super.testServerPort.toString(),
'PATROL_APP_SERVER_PORT': super.appServerPort.toString(),
'COVERAGE_ENABLED': coverageEnabled.toString(),
}.withNullsRemoved();

final dartDefines = {...customDartDefines, ...internalDartDefines};
Expand Down Expand Up @@ -236,6 +245,19 @@ See https://github.com/leancodepl/patrol/issues/1316 to learn more.

await _build(androidOpts, iosOpts, macosOpts, device);
await _preExecute(androidOpts, iosOpts, macosOpts, device, uninstall);

if (coverageEnabled) {
unawaited(
_coverageTool.run(
device: device,
flutterPackageName: config.flutterPackageName,
platform: device.targetPlatform,
logger: _logger,
ignoreGlobs: ignoreGlobs,
),
);
}

final allPassed = await _execute(
flutterOpts,
androidOpts,
Expand Down Expand Up @@ -362,4 +384,16 @@ See https://github.com/leancodepl/patrol/issues/1316 to learn more.

return allPassed;
}

void useCoverageOptions() {
argParser
..addFlag(
'coverage',
help: 'Generate coverage.',
)
..addMultiOption(
'coverage-ignore',
help: 'Exclude files from coverage using glob patterns.',
);
}
}
Loading

0 comments on commit 2656cfe

Please sign in to comment.