Started on the dart_gherkin 3.0 conversion

This commit is contained in:
Bart Vermeulen 2022-06-15 18:22:37 +02:00
parent c6b64cae2e
commit 5c15f0c2c0
7 changed files with 106 additions and 120 deletions

View File

@ -8,7 +8,18 @@ import 'package:glob/glob.dart';
import 'package:glob/list_local_fs.dart';
import 'package:source_gen/source_gen.dart';
class NoOpReporter extends Reporter {}
class NoOpReporter extends MessageReporter {
@override
Future<void> message(String message, MessageLevel level) async {
if(level == MessageLevel.info || level == MessageLevel.debug) {
print(message);
}else if(level == MessageLevel.warning) {
print('\x1B[33m$message\x1B[0m');
}else if(level == MessageLevel.error) {
print('\x1B[31m$message\x1B[0m');
}
}
}
class GherkinSuiteTestGenerator
extends GeneratorForAnnotation<GherkinTestSuite> {
@ -52,16 +63,12 @@ void executeTestSuite(
.getField('index')!
.toIntValue()!;
final executionOrder = ExecutionOrder.values[idx];
final featureFiles = annotation
final featureFiles = annotation
.read('featurePaths')
.listValue
.map((path) => Glob(path.toStringValue()!))
.map(
(glob) => glob
.listSync()
.map((entity) => File(entity.path).readAsStringSync())
.toList(),
)
.map((glob) =>
glob.listSync().map((entity) => File(entity.path)).toList())
.reduce((value, element) => value..addAll(element));
if (executionOrder == ExecutionOrder.random) {
@ -73,11 +80,11 @@ void executeTestSuite(
final featuresToExecute = new StringBuffer();
var id = 0;
for (var featureFileContent in featureFiles) {
for (var featureFile in featureFiles) {
final code = await generator.generate(
id++,
featureFileContent,
'',
featureFile.readAsStringSync(),
featureFile.absolute.path,
_languageService,
_reporter,
);
@ -104,7 +111,7 @@ class FeatureFileTestGenerator {
String featureFileContents,
String path,
LanguageService languageService,
Reporter reporter,
MessageReporter reporter,
) async {
final visitor = FeatureFileTestGeneratorVisitor();
@ -148,14 +155,14 @@ class FeatureFileTestGeneratorVisitor extends FeatureFileVisitor {
{{step_multi_line_strings}},
{{step_table}},
dependencies,
hasToSkip
hasToSkip,
);}
''';
static const String ON_BEFORE_SCENARIO_RUN = '''
onBefore: () async => onBeforeRunFeature('{{feature_name}}', {{feature_tags}},),
''';
static const String ON_AFTER_SCENARIO_RUN = '''
onAfter: () async => onAfterRunFeature('{{feature_name}}',),
onAfter: () async => onAfterRunFeature('{{feature_name}}', '{{path}}'),
''';
final StringBuffer _buffer = StringBuffer();
@ -171,7 +178,7 @@ class FeatureFileTestGeneratorVisitor extends FeatureFileVisitor {
String featureFileContents,
String path,
LanguageService languageService,
Reporter reporter,
MessageReporter reporter,
) async {
_id = id;
await visit(
@ -214,14 +221,9 @@ class FeatureFileTestGeneratorVisitor extends FeatureFileVisitor {
}
@override
Future<void> visitScenario(
String featureName,
Iterable<String> featureTags,
String name,
Iterable<String> tags,
bool isFirst,
bool isLast,
) async {
Future<void> visitScenario(String featureName, Iterable<String> featureTags,
String name, Iterable<String> tags, String path,
{required bool isFirst, required bool isLast}) async {
_flushScenario();
_currentScenarioCode = _replaceVariable(
SCENARIO_TEMPLATE,
@ -238,6 +240,11 @@ class FeatureFileTestGeneratorVisitor extends FeatureFileVisitor {
'feature_name',
_escapeText(featureName),
);
_currentScenarioCode = _replaceVariable(
_currentScenarioCode!,
'path',
_escapeText(path),
);
_currentScenarioCode = _replaceVariable(
_currentScenarioCode!,
'feature_tags',

View File

@ -24,32 +24,6 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:gherkin/gherkin.dart';
class FlutterTestConfiguration extends TestConfiguration {
/// ~~The path(s) to all the features.~~
/// ~~All three [Pattern]s are supported: [RegExp], [String], [Glob].~~
///
/// Instead of using this variable, give the features in the `@GherkinTestSuite(features: <String>[])` option.
@deprecated
Iterable<Pattern> features = const <Pattern>[];
/// ~~The execution order of features - this default to random to avoid any inter-test dependencies~~
///
/// Instead of using this variable, give the executionOrder in the `@GherkinTestSuite(executionOrder: ExecutionOrder.random)` option.
@deprecated
ExecutionOrder order = ExecutionOrder.random;
/// ~~Lists feature files paths, which match [features] patterns.~~
///
/// Instead of using this variable, give the features in the `@GherkinTestSuite(features: <String>[])` option.
@deprecated
FeatureFileMatcher featureFileMatcher = const IoFeatureFileAccessor();
/// ~~The feature file reader.~~
/// ~~Takes files/resources paths from [featureFileIndexer] and returns their content as String.~~
///
/// Instead of using this variable, give the features in the `@GherkinTestSuite(features: <String>[])` option.
@deprecated
FeatureFileReader featureFileReader = const IoFeatureFileAccessor();
/// Enable semantics in a test by creating a [SemanticsHandle].
/// See: [testWidgets] and [WidgetController.ensureSemantics].
@ -63,7 +37,6 @@ class FlutterTestConfiguration extends TestConfiguration {
String targetAppPath = 'test_driver/integration_test_driver.dart',
}) {
return FlutterTestConfiguration()
..features = [RegExp(featurePath)]
..reporters = [
StdoutReporter(MessageLevel.error),
ProgressReporter(),

View File

@ -39,7 +39,7 @@ class FlutterAppRunnerHook extends Hook {
TestConfiguration config,
String scenario,
Iterable<Tag> tags,
bool failed,
{bool? passed,}
) async {
final flutterConfig = _castConfig(config);
haveRunFirstScenario = true;

View File

@ -1,8 +1,4 @@
import 'dart:math';
import 'package:flutter_gherkin/flutter_gherkin.dart';
import 'package:flutter_gherkin/src/flutter/adapters/widget_tester_app_driver_adapter.dart';
import 'package:flutter_gherkin/src/flutter/world/flutter_world.dart';
import 'package:gherkin/gherkin.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
@ -24,14 +20,14 @@ abstract class GherkinIntegrationTestRunner {
TagExpressionEvaluator();
final TestConfiguration configuration;
final Future<void> Function(World world) appMainFunction;
Reporter? _reporter;
AggregatedReporter _reporter = new AggregatedReporter();
Hook? _hook;
Iterable<ExecutableStep>? _executableSteps;
Iterable<CustomParameter>? _customParameters;
IntegrationTestWidgetsFlutterBinding? _binding;
Reporter get reporter => _reporter!;
AggregatedReporter get reporter => _reporter;
Hook get hook => _hook!;
LiveTestWidgetsFlutterBindingFramePolicy? get framePolicy => null;
@ -42,7 +38,7 @@ abstract class GherkinIntegrationTestRunner {
this.appMainFunction,
) {
configuration.prepare();
_reporter = _registerReporters(configuration.reporters);
_registerReporters(configuration.reporters);
_hook = _registerHooks(configuration.hooks);
_customParameters =
_registerCustomParameters(configuration.customStepParameterDefinitions);
@ -66,7 +62,7 @@ abstract class GherkinIntegrationTestRunner {
);
_safeInvokeFuture(() async => await hook.onBeforeRun(configuration));
_safeInvokeFuture(() async => await reporter.onTestRunStarted());
_safeInvokeFuture(() async => await reporter.test.onStarted.maybeCall());
onRun();
}
@ -74,7 +70,7 @@ abstract class GherkinIntegrationTestRunner {
void onRun();
void onRunComplete() {
_safeInvokeFuture(() async => await reporter.onTestRunFinished());
_safeInvokeFuture(() async => await reporter.test.onFinished.maybeCall());
_safeInvokeFuture(() async => await hook.onAfterRun(configuration));
setTestResultData(_binding!);
_safeInvokeFuture(() async => await reporter.dispose());
@ -82,7 +78,7 @@ abstract class GherkinIntegrationTestRunner {
void setTestResultData(IntegrationTestWidgetsFlutterBinding binding) {
if (reporter is SerializableReporter) {
final json = (reporter as SerializableReporter).toJson();
final json = (reporter as SerializableReporter).serialize();
binding.reportData = {'gherkin_reports': json};
}
}
@ -109,12 +105,11 @@ abstract class GherkinIntegrationTestRunner {
final debugInformation = RunnableDebugInformation('', 0, name);
final featureTags =
(tags ?? Iterable<Tag>.empty()).map((t) => Tag(t.toString(), 0));
await reporter.onFeatureStarted(
StartedMessage(
Target.feature,
name,
debugInformation,
featureTags,
await reporter.feature.onStarted.maybeCall(
FeatureMessage(
name: name,
context: debugInformation,
tags: featureTags.toList(),
),
);
}
@ -122,13 +117,14 @@ abstract class GherkinIntegrationTestRunner {
@protected
Future<void> onAfterRunFeature(
String name,
String path
) async {
final debugInformation = RunnableDebugInformation('', 0, name);
await reporter.onFeatureFinished(
FinishedMessage(
Target.feature,
name,
debugInformation,
final debugInformation = RunnableDebugInformation(path, 0, name);
await reporter.test.onFinished.maybeCall(
TestMessage(
target: Target.feature,
name: name,
context: debugInformation,
),
);
}
@ -138,7 +134,7 @@ abstract class GherkinIntegrationTestRunner {
String name,
Iterable<String>? tags,
List<Future<StepResult> Function(TestDependencies dependencies, bool skip,)>
steps, {
steps, String path, {
Future<void> Function()? onBefore,
Future<void> Function()? onAfter,
}) {
@ -151,7 +147,7 @@ abstract class GherkinIntegrationTestRunner {
}
var failed = false;
final debugInformation = RunnableDebugInformation('', 0, name);
final debugInformation = RunnableDebugInformation(path, 0, name);
final scenarioTags =
(tags ?? Iterable<Tag>.empty()).map((t) => Tag(t.toString(), 0));
final dependencies = await createTestDependencies(
@ -177,12 +173,11 @@ abstract class GherkinIntegrationTestRunner {
scenarioTags,
);
await reporter.onScenarioStarted(
StartedMessage(
Target.scenario,
name,
debugInformation,
scenarioTags,
await reporter.scenario.onStarted.maybeCall(
ScenarioMessage(
name: name,
context: debugInformation,
tags: scenarioTags.toList(),
),
);
var hasToSkip = false;
@ -200,11 +195,11 @@ abstract class GherkinIntegrationTestRunner {
}
}
} finally {
await reporter.onScenarioFinished(
ScenarioFinishedMessage(
name,
debugInformation,
!failed,
await reporter.scenario.onFinished.maybeCall(
ScenarioMessage(
name: name,
context: debugInformation,
hasPassed: !failed,
),
);
@ -212,7 +207,7 @@ abstract class GherkinIntegrationTestRunner {
configuration,
name,
scenarioTags,
!failed,
passed: !failed,
);
if (onAfter != null) {
@ -300,7 +295,7 @@ abstract class GherkinIntegrationTestRunner {
if (hasToSkip) {
result = new StepResult(
0, StepExecutionResult.skipped, "Previous step(s) failed.");
0, StepExecutionResult.skipped, resultReason: "Previous step(s) failed.");
} else {
for (int i = 0; i < this.configuration.stepMaxRetries + 1; i++) {
result = await executable.step.run(
@ -345,13 +340,10 @@ abstract class GherkinIntegrationTestRunner {
);
}
Reporter _registerReporters(Iterable<Reporter>? reporters) {
final reporter = AggregatedReporter();
void _registerReporters(Iterable<Reporter>? reporters) {
if (reporters != null) {
reporters.forEach((r) => reporter.addReporter(r));
reporters.forEach((r) => _reporter.addReporter(r));
}
return reporter;
}
Hook _registerHooks(Iterable<Hook>? hooks) {
@ -429,12 +421,12 @@ abstract class GherkinIntegrationTestRunner {
result,
);
await reporter.onStepFinished(
StepFinishedMessage(
step,
RunnableDebugInformation('', 0, step),
result,
dependencies.attachmentManager.getAttachmentsForContext(step),
await reporter.step.onStarted.maybeCall(
StepMessage(
name: step,
context: RunnableDebugInformation('', 0, step),
result: result,
attachments: dependencies.attachmentManager.getAttachmentsForContext(step).toList(),
),
);
}
@ -446,10 +438,10 @@ abstract class GherkinIntegrationTestRunner {
Iterable<String> multiLineStrings,
) async {
await hook.onBeforeStep(world, step);
await reporter.onStepStarted(
StepStartedMessage(
step,
RunnableDebugInformation('', 0, step),
await reporter.step.onStarted.maybeCall(
StepMessage(
name: step,
context: RunnableDebugInformation('', 0, step),
table: table,
multilineString:
multiLineStrings.isNotEmpty ? multiLineStrings.first : null,

View File

@ -22,7 +22,7 @@ StepDefinitionGeneric ThenExpectElementToHaveValue() {
context.expect(text, value);
} catch (e) {
await context.reporter.message('Step error: $e', MessageLevel.error);
// await context.reporter('Step error: $e', MessageLevel.error);
rethrow;
}
},

View File

@ -21,7 +21,7 @@ packages:
name: archive
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.2"
version: "3.1.11"
args:
dependency: transitive
description:
@ -35,7 +35,7 @@ packages:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.8.1"
version: "2.8.2"
boolean_selector:
dependency: transitive
description:
@ -63,7 +63,7 @@ packages:
name: characters
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.2.0"
charcode:
dependency: transitive
description:
@ -98,7 +98,7 @@ packages:
name: collection
url: "https://pub.dartlang.org"
source: hosted
version: "1.15.0"
version: "1.16.0"
convert:
dependency: transitive
description:
@ -126,7 +126,7 @@ packages:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "1.3.0"
file:
dependency: transitive
description:
@ -160,7 +160,7 @@ packages:
name: gherkin
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.8"
version: "3.0.0"
glob:
dependency: "direct main"
description:
@ -193,7 +193,14 @@ packages:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.10"
version: "0.12.11"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.4"
meta:
dependency: "direct dev"
description:
@ -214,7 +221,7 @@ packages:
name: path
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.0"
version: "1.8.1"
pedantic:
dependency: "direct dev"
description:
@ -228,14 +235,14 @@ packages:
name: platform
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
version: "3.1.0"
process:
dependency: transitive
description:
name: process
url: "https://pub.dartlang.org"
source: hosted
version: "4.2.3"
version: "4.2.4"
pub_semver:
dependency: transitive
description:
@ -268,7 +275,7 @@ packages:
name: source_span
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.1"
version: "1.8.2"
stack_trace:
dependency: transitive
description:
@ -310,7 +317,7 @@ packages:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.2"
version: "0.4.9"
typed_data:
dependency: transitive
description:
@ -318,20 +325,27 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
uuid:
dependency: transitive
description:
name: uuid
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.6"
vector_math:
dependency: transitive
description:
name: vector_math
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.1.2"
vm_service:
dependency: transitive
description:
name: vm_service
url: "https://pub.dartlang.org"
source: hosted
version: "7.1.1"
version: "8.2.2"
watcher:
dependency: transitive
description:
@ -354,5 +368,5 @@ packages:
source: hosted
version: "3.1.0"
sdks:
dart: ">=2.14.0 <3.0.0"
dart: ">=2.17.0-0 <3.0.0"
flutter: ">=2.2.0"

View File

@ -18,7 +18,7 @@ dependencies:
sdk: flutter
analyzer: ">=1.7.1 <3.0.0"
collection: ^1.15.0
gherkin: ^2.0.8
gherkin: ^3.0.0
source_gen: ^1.1.1
build: ^2.1.1
glob: ^2.0.2