From 9e8e2f2b126341922a1f16027aaef94897a9521a Mon Sep 17 00:00:00 2001 From: Oleksandr Leushchenko Date: Mon, 22 Sep 2025 19:49:30 +0300 Subject: [PATCH 1/3] update version to 2.1.0 --- CHANGELOG.md | 6 ++++++ pubspec.yaml | 8 ++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88638b6..7b8b13d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [2.1.0] - Update dependencies + +* Update min SDK to 3.7.0 +* Update build_runner and dependencies (by @lsaudon) +* Remove Extra Curly Braces from Data Table Variables in Scenario Outlines (by @tide-khushal) + ## [2.0.1] - Custom headers support * Add `customHeaders` configuration option to include custom header lines (imports, comments, etc.) in all generated step files and feature files diff --git a/pubspec.yaml b/pubspec.yaml index 4aee37f..d426079 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,11 +1,11 @@ name: bdd_widget_test description: A BDD-style widget testing library. Generates Flutter widget tests from *.feature files. -version: 2.0.1 +version: 2.1.0 repository: https://github.com/olexale/bdd_widget_test issue_tracker: https://github.com/olexale/bdd_widget_test/issues environment: - sdk: ">=2.18.0 <4.0.0" + sdk: ^3.7.0 dependencies: build: ^4.0.0 @@ -21,6 +21,6 @@ dependencies: dev_dependencies: build_runner: ^2.8.0 - build_test: ^3.3.2 + build_test: ^3.4.0 test: ^1.26.3 - very_good_analysis: ^9.0.0 + very_good_analysis: ^10.0.0 From c59645d668057fc569b17d65f3b5049f0721bce3 Mon Sep 17 00:00:00 2001 From: Oleksandr Leushchenko Date: Mon, 22 Sep 2025 19:49:58 +0300 Subject: [PATCH 2/3] Reformat code --- lib/bdd_widget_test.dart | 25 +++--- lib/src/bdd_line.dart | 6 +- lib/src/data_table_parser.dart | 20 +++-- lib/src/existing_steps.dart | 5 +- lib/src/feature_file.dart | 136 ++++++++++++++++-------------- lib/src/feature_generator.dart | 81 +++++++++--------- lib/src/generator_options.dart | 90 ++++++++++---------- lib/src/scenario_generator.dart | 10 ++- lib/src/step/generic_step.dart | 7 +- lib/src/step_file.dart | 36 ++++---- lib/src/step_generator.dart | 55 ++++++------ lib/src/util/common.dart | 5 +- test/custom_tester_type_test.dart | 5 +- test/feature_generator_test.dart | 57 ++++++++----- test/feature_test.dart | 21 ++--- test/integration_test.dart | 23 ++--- test/step_folder_name_test.dart | 5 +- test/steps_test.dart | 7 +- test/test_method_name_test.dart | 5 +- 19 files changed, 326 insertions(+), 273 deletions(-) diff --git a/lib/bdd_widget_test.dart b/lib/bdd_widget_test.dart index 21df54b..4d4c4fb 100644 --- a/lib/bdd_widget_test.dart +++ b/lib/bdd_widget_test.dart @@ -32,8 +32,8 @@ import 'package:yaml/yaml.dart'; /// /// Returns a [FeatureBuilder] instance configured with the specified options. Builder featureBuilder(BuilderOptions options) => FeatureBuilder( - GeneratorOptions.fromMap(options.config), - ); + GeneratorOptions.fromMap(options.config), +); /// A code generator builder that transforms BDD feature files into Dart test files. /// @@ -139,7 +139,7 @@ class FeatureBuilder implements Builder { final featureDir = p.dirname(inputId.path); final isIntegrationTest = inputId.pathSegments.contains('integration_test') && - _hasIntegrationTestDevDependency(); + _hasIntegrationTestDevDependency(); final feature = FeatureFile( featureDir: featureDir, @@ -159,9 +159,8 @@ class FeatureBuilder implements Builder { ); final steps = feature.getStepFiles().whereType().map( - (e) => - _createFileRecursively(e.filename, formatDartCode(e.dartContent)), - ); + (e) => _createFileRecursively(e.filename, formatDartCode(e.dartContent)), + ); await Future.wait(steps); final hookFile = feature.hookFile; @@ -171,12 +170,14 @@ class FeatureBuilder implements Builder { } Future _prepareOptions() async { - final fileOptions = fs.file('bdd_options.yaml').existsSync() - ? readFromUri(Uri.file('bdd_options.yaml')) - : null; - final mergedOptions = fileOptions != null - ? merge(generatorOptions, fileOptions) - : generatorOptions; + final fileOptions = + fs.file('bdd_options.yaml').existsSync() + ? readFromUri(Uri.file('bdd_options.yaml')) + : null; + final mergedOptions = + fileOptions != null + ? merge(generatorOptions, fileOptions) + : generatorOptions; final options = await flattenOptions(mergedOptions); return options; } diff --git a/lib/src/bdd_line.dart b/lib/src/bdd_line.dart index d04c3cd..07237ab 100644 --- a/lib/src/bdd_line.dart +++ b/lib/src/bdd_line.dart @@ -1,11 +1,11 @@ class BddLine { BddLine(this.rawLine) - : type = _lineTypeFromString(rawLine), - value = _removeLinePrefix(rawLine); + : type = _lineTypeFromString(rawLine), + value = _removeLinePrefix(rawLine); BddLine.fromValue(this.type, this.value) : rawLine = ''; BddLine.fromRawValue(this.type, this.rawLine) - : value = _removeLinePrefix(rawLine); + : value = _removeLinePrefix(rawLine); final String rawLine; final String value; diff --git a/lib/src/data_table_parser.dart b/lib/src/data_table_parser.dart index c9b319e..658d806 100644 --- a/lib/src/data_table_parser.dart +++ b/lib/src/data_table_parser.dart @@ -4,7 +4,8 @@ import 'package:bdd_widget_test/src/scenario_generator.dart'; bool hasBddDataTable(List lines) { for (var index = 0; index < lines.length; index++) { - final isStep = lines[index].type == LineType.step || + final isStep = + lines[index].type == LineType.step || lines[index].type == LineType.dataTableStep; final isNextLineTable = isTable(lines: lines, index: index + 1); final isExamplesFormatted = hasExamplesFormat(bddLine: lines[index]); @@ -17,13 +18,15 @@ bool hasBddDataTable(List lines) { Iterable replaceDataTables(List lines) sync* { for (var index = 0; index < lines.length; index++) { - final isStep = lines[index].type == LineType.step || + final isStep = + lines[index].type == LineType.step || lines[index].type == LineType.dataTableStep; final isNextLineTable = isTable(lines: lines, index: index + 1); if (isStep && isNextLineTable) { - final table = !hasExamplesFormat(bddLine: lines[index]) - ? _createCucumberDataTable(lines: lines, index: index) - : _createDataTableFromExamples(lines: lines, index: index); + final table = + !hasExamplesFormat(bddLine: lines[index]) + ? _createCucumberDataTable(lines: lines, index: index) + : _createDataTableFromExamples(lines: lines, index: index); yield* table; // skip the parsed table while (isTable(lines: lines, index: index + 1)) { @@ -38,8 +41,7 @@ Iterable replaceDataTables(List lines) sync* { bool isTable({ required List lines, required int index, -}) => - index < lines.length && lines[index].type == LineType.examples; +}) => index < lines.length && lines[index].type == LineType.examples; bool hasExamplesFormat({required BddLine bddLine}) => examplesRegExp.firstMatch(bddLine.rawLine) != null; @@ -75,8 +77,8 @@ Iterable _createDataTableFromExamples({ final dataTable = [lines[index]]; do { dataTable.add(lines[++index]); - } while ( - index + 1 < lines.length && lines[index + 1].type == LineType.examples); + } while (index + 1 < lines.length && + lines[index + 1].type == LineType.examples); final data = generateScenariosFromScenarioOutline([ // pretend to be an Example section to re-use some logic BddLine.fromValue(LineType.exampleTitle, ''), diff --git a/lib/src/existing_steps.dart b/lib/src/existing_steps.dart index c7d1d42..f96d33a 100644 --- a/lib/src/existing_steps.dart +++ b/lib/src/existing_steps.dart @@ -20,7 +20,10 @@ Map getExistingStepSubfolders( if (!steps.existsSync()) { return {}; } - return steps.listSync(recursive: true).asMap().map( + return steps + .listSync(recursive: true) + .asMap() + .map( (_, step) => MapEntry( p.basename(step.path), p.dirname( diff --git a/lib/src/feature_file.dart b/lib/src/feature_file.dart index e6097e1..a358e40 100644 --- a/lib/src/feature_file.dart +++ b/lib/src/feature_file.dart @@ -18,16 +18,17 @@ class FeatureFile { this.includeIntegrationTestBinding = false, this.existingSteps = const {}, this.generatorOptions = const GeneratorOptions(), - }) : _lines = _prepareLines( - input.split('\n').map((line) => line.trim()).map(BddLine.new), - ), - hookFile = generatorOptions.addHooks - ? HookFile.create( - featureDir: featureDir, - package: package, - generatorOptions: generatorOptions, - ) - : null { + }) : _lines = _prepareLines( + input.split('\n').map((line) => line.trim()).map(BddLine.new), + ), + hookFile = + generatorOptions.addHooks + ? HookFile.create( + featureDir: featureDir, + package: package, + generatorOptions: generatorOptions, + ) + : null { _testerType = parseCustomTagFromFeatureTagLine( _lines, generatorOptions.testerType, @@ -40,23 +41,25 @@ class FeatureFile { testerNameTag, ); - _stepFiles = _lines - .where( - (line) => - line.type == LineType.step || line.type == LineType.dataTableStep, - ) - .map( - (bddLine) => StepFile.create( - featureDir, - package, - bddLine, - existingSteps, - generatorOptions, - _testerType, - _testerName, - ), - ) - .toList(); + _stepFiles = + _lines + .where( + (line) => + line.type == LineType.step || + line.type == LineType.dataTableStep, + ) + .map( + (bddLine) => StepFile.create( + featureDir, + package, + bddLine, + existingSteps, + generatorOptions, + _testerType, + _testerName, + ), + ) + .toList(); } late List _stepFiles; @@ -75,52 +78,57 @@ class FeatureFile { final HookFile? hookFile; String get dartContent => generateFeatureDart( - _lines, - getStepFiles(), - generatorOptions.testMethodName, - _testerType, - _testerName, - includeIntegrationTestBinding, - includeIntegrationTestImport, - hookFile, - generatorOptions, - ); + _lines, + getStepFiles(), + generatorOptions.testMethodName, + _testerType, + _testerName, + includeIntegrationTestBinding, + includeIntegrationTestImport, + hookFile, + generatorOptions, + ); List getStepFiles() => _stepFiles; static List _prepareLines(Iterable input) { - final lines = input.mapIndexed( - (index, bddLine) { - final isStep = bddLine.type == LineType.step; - final hasExamplesFormat = data_table_parser.hasExamplesFormat( - bddLine: bddLine, - ); - final isNextTable = data_table_parser.isTable( - lines: input.toList(), - index: index + 1, - ); - if (isStep && !hasExamplesFormat && isNextTable) { - return BddLine.fromRawValue(LineType.dataTableStep, bddLine.rawLine); - } else { - return bddLine; - } - }, - ).toList(growable: false); + final lines = input + .mapIndexed( + (index, bddLine) { + final isStep = bddLine.type == LineType.step; + final hasExamplesFormat = data_table_parser.hasExamplesFormat( + bddLine: bddLine, + ); + final isNextTable = data_table_parser.isTable( + lines: input.toList(), + index: index + 1, + ); + if (isStep && !hasExamplesFormat && isNextTable) { + return BddLine.fromRawValue( + LineType.dataTableStep, + bddLine.rawLine, + ); + } else { + return bddLine; + } + }, + ) + .toList(growable: false); final headers = lines .takeWhile((value) => value.type != LineType.feature) .where((value) => value.type == LineType.unknown) .foldIndexed( - // this removes empty line dupicates - [], - (index, headers, line) => [ - ...headers, - if (index == 0 && line.rawLine != '\n' && line.rawLine.isNotEmpty) - line - else if (headers.isNotEmpty && headers.last.rawLine != line.rawLine) - line, - ], - ); + // this removes empty line dupicates + [], + (index, headers, line) => [ + ...headers, + if (index == 0 && line.rawLine != '\n' && line.rawLine.isNotEmpty) + line + else if (headers.isNotEmpty && headers.last.rawLine != line.rawLine) + line, + ], + ); final steps = lines.where((value) => value.type != LineType.unknown); return [...headers, ...steps]; } diff --git a/lib/src/feature_generator.dart b/lib/src/feature_generator.dart index d9ebfe6..4e03fcb 100644 --- a/lib/src/feature_generator.dart +++ b/lib/src/feature_generator.dart @@ -31,8 +31,9 @@ String generateFeatureDart( final linesBeforeFeature = lines.takeWhile((value) => value.type != LineType.feature).toList(); - final tagLines = - linesBeforeFeature.where((line) => line.type == LineType.tag); + final tagLines = linesBeforeFeature.where( + (line) => line.type == LineType.tag, + ); final tags = []; for (final line in tagLines) { final methodName = parseCustomTag(line.rawLine, testMethodNameTag); @@ -53,8 +54,9 @@ String generateFeatureDart( sb.writeln("@Tags(['${tags.join("', '")}'])"); } - for (final line - in linesBeforeFeature.where((line) => line.type != LineType.tag)) { + for (final line in linesBeforeFeature.where( + (line) => line.type != LineType.tag, + )) { sb.writeln(line.rawLine); } @@ -64,9 +66,7 @@ String generateFeatureDart( // Use custom headers if provided, otherwise use default imports if (generatorOptions.customHeaders.isNotEmpty) { - for (final header in generatorOptions.customHeaders) { - sb.writeln(header); - } + generatorOptions.customHeaders.forEach(sb.writeln); } else { sb.writeln("import 'package:flutter/material.dart';"); sb.writeln("import 'package:flutter_test/flutter_test.dart';"); @@ -208,30 +208,28 @@ bool _parseBackground( List lines, String testerType, String testerName, -) => - _parseSetup( - sb, - lines, - LineType.background, - setUpMethodName, - testerType, - testerName, - ); +) => _parseSetup( + sb, + lines, + LineType.background, + setUpMethodName, + testerType, + testerName, +); bool _parseAfter( StringBuffer sb, List lines, String testerType, String testerName, -) => - _parseSetup( - sb, - lines, - LineType.after, - tearDownMethodName, - testerType, - testerName, - ); +) => _parseSetup( + sb, + lines, + LineType.after, + tearDownMethodName, + testerType, + testerName, +); bool _parseSetup( StringBuffer sb, @@ -241,11 +239,13 @@ bool _parseSetup( String testerType, String testerName, ) { - final flattenDataTables = replaceDataTables( - lines.skipWhile((line) => line.type == LineType.tag).toList(), - ).toList(); - var offset = - flattenDataTables.indexWhere((element) => element.type == elementType); + final flattenDataTables = + replaceDataTables( + lines.skipWhile((line) => line.type == LineType.tag).toList(), + ).toList(); + var offset = flattenDataTables.indexWhere( + (element) => element.type == elementType, + ); if (offset != -1) { sb.writeln(' Future $title($testerType $testerName) async {'); offset++; @@ -270,9 +270,10 @@ void _parseFeature( String testMethodName, String testerName, ) { - final scenarios = _splitScenarios( - feature.skipWhile((value) => !_isNewScenario(value.type)).toList(), - ).toList(); + final scenarios = + _splitScenarios( + feature.skipWhile((value) => !_isNewScenario(value.type)).toList(), + ).toList(); for (final scenario in scenarios) { final scenarioTagLines = scenario.where((line) => line.type == LineType.tag).toList(); @@ -288,12 +289,14 @@ void _parseFeature( scenarioParamsTag, ); - final flattenDataTables = replaceDataTables( - scenario.skipWhile((line) => line.type == LineType.tag).toList(), - ).toList(); - final scenariosToParse = flattenDataTables.first.type == LineType.scenario - ? [flattenDataTables] - : generateScenariosFromScenarioOutline(flattenDataTables); + final flattenDataTables = + replaceDataTables( + scenario.skipWhile((line) => line.type == LineType.tag).toList(), + ).toList(); + final scenariosToParse = + flattenDataTables.first.type == LineType.scenario + ? [flattenDataTables] + : generateScenariosFromScenarioOutline(flattenDataTables); for (final s in scenariosToParse) { parseScenario( diff --git a/lib/src/generator_options.dart b/lib/src/generator_options.dart index a6a08f0..cf9e29a 100644 --- a/lib/src/generator_options.dart +++ b/lib/src/generator_options.dart @@ -21,34 +21,35 @@ class GeneratorOptions { this.include, bool? includeIntegrationTestBinding, List? customHeaders, - }) : stepFolder = stepFolderName ?? _stepFolderName, - relativeToTestFolder = relativeToTestFolder ?? true, - testMethodName = testMethodName ?? _defaultTestMethodName, - testerType = testerType ?? _defaultTesterType, - testerName = testerName ?? _defaultTesterName, - addHooks = addHooks ?? false, - hookFolderName = hookFolderName ?? _hookFolderName, - externalSteps = externalSteps ?? const [], - includeIntegrationTestBinding = includeIntegrationTestBinding ?? true, - customHeaders = customHeaders ?? const []; + }) : stepFolder = stepFolderName ?? _stepFolderName, + relativeToTestFolder = relativeToTestFolder ?? true, + testMethodName = testMethodName ?? _defaultTestMethodName, + testerType = testerType ?? _defaultTesterType, + testerName = testerName ?? _defaultTesterName, + addHooks = addHooks ?? false, + hookFolderName = hookFolderName ?? _hookFolderName, + externalSteps = externalSteps ?? const [], + includeIntegrationTestBinding = includeIntegrationTestBinding ?? true, + customHeaders = customHeaders ?? const []; factory GeneratorOptions.fromMap(Map json) => GeneratorOptions( - testMethodName: json['testMethodName'] as String?, - testerType: json['testerType'] as String?, - testerName: json['testerName'] as String?, - externalSteps: (json['externalSteps'] as List?)?.cast(), - stepFolderName: json['stepFolderName'] as String?, - relativeToTestFolder: json['relativeToTestFolder'] as bool?, - addHooks: json['addHooks'] as bool?, - hookFolderName: json['hookFolderName'] as String?, - include: json['include'] is String - ? [(json['include'] as String)] - : (json['include'] as List?)?.cast(), - includeIntegrationTestBinding: - json['includeIntegrationTestBinding'] as bool?, - customHeaders: - (json['customHeaders'] as List?)?.cast() ?? []); + testMethodName: json['testMethodName'] as String?, + testerType: json['testerType'] as String?, + testerName: json['testerName'] as String?, + externalSteps: (json['externalSteps'] as List?)?.cast(), + stepFolderName: json['stepFolderName'] as String?, + relativeToTestFolder: json['relativeToTestFolder'] as bool?, + addHooks: json['addHooks'] as bool?, + hookFolderName: json['hookFolderName'] as String?, + include: + json['include'] is String + ? [(json['include'] as String)] + : (json['include'] as List?)?.cast(), + includeIntegrationTestBinding: + json['includeIntegrationTestBinding'] as bool?, + customHeaders: (json['customHeaders'] as List?)?.cast() ?? [], + ); final String stepFolder; final bool relativeToTestFolder; @@ -93,25 +94,24 @@ GeneratorOptions readFromUri(Uri uri) { return GeneratorOptions.fromMap(doc.value.cast()); } -GeneratorOptions merge(GeneratorOptions a, GeneratorOptions b) => - GeneratorOptions( - testMethodName: a.testMethodName != _defaultTestMethodName +GeneratorOptions merge( + GeneratorOptions a, + GeneratorOptions b, +) => GeneratorOptions( + testMethodName: + a.testMethodName != _defaultTestMethodName ? a.testMethodName : b.testMethodName, - testerType: - a.testerType != _defaultTesterType ? a.testerType : b.testerType, - testerName: - a.testerName != _defaultTesterName ? a.testerName : b.testerName, - stepFolderName: - a.stepFolder != _stepFolderName ? a.stepFolder : b.stepFolder, - relativeToTestFolder: a.relativeToTestFolder && b.relativeToTestFolder, - externalSteps: [...a.externalSteps, ...b.externalSteps], - addHooks: a.addHooks || b.addHooks, - hookFolderName: a.hookFolderName != _hookFolderName - ? a.hookFolderName - : b.hookFolderName, - include: b.include, - includeIntegrationTestBinding: - a.includeIntegrationTestBinding || b.includeIntegrationTestBinding, - customHeaders: [...a.customHeaders, ...b.customHeaders], - ); + testerType: a.testerType != _defaultTesterType ? a.testerType : b.testerType, + testerName: a.testerName != _defaultTesterName ? a.testerName : b.testerName, + stepFolderName: a.stepFolder != _stepFolderName ? a.stepFolder : b.stepFolder, + relativeToTestFolder: a.relativeToTestFolder && b.relativeToTestFolder, + externalSteps: [...a.externalSteps, ...b.externalSteps], + addHooks: a.addHooks || b.addHooks, + hookFolderName: + a.hookFolderName != _hookFolderName ? a.hookFolderName : b.hookFolderName, + include: b.include, + includeIntegrationTestBinding: + a.includeIntegrationTestBinding || b.includeIntegrationTestBinding, + customHeaders: [...a.customHeaders, ...b.customHeaders], +); diff --git a/lib/src/scenario_generator.dart b/lib/src/scenario_generator.dart index 1af4a53..e1da2b7 100644 --- a/lib/src/scenario_generator.dart +++ b/lib/src/scenario_generator.dart @@ -121,13 +121,19 @@ Iterable _processScenarioLines( yield BddLine.fromValue( line.type, _replacePlaceholders( - line.value, line.type == LineType.dataTableStep, examples), + line.value, + line.type == LineType.dataTableStep, + examples, + ), ); } } String _replacePlaceholders( - String line, bool isDataTableStep, Map example) { + String line, + bool isDataTableStep, + Map example, +) { var replaced = line; for (final e in example.keys) { final value = isDataTableStep ? '${example[e]}' : '{${example[e]}}'; diff --git a/lib/src/step/generic_step.dart b/lib/src/step/generic_step.dart index 9f19e33..c01e3f4 100644 --- a/lib/src/step/generic_step.dart +++ b/lib/src/step/generic_step.dart @@ -24,9 +24,10 @@ class GenericStep implements BddStep { @override String get content { final hasCustomHeaders = generatorOptions.customHeaders.isNotEmpty; - final headerSection = hasCustomHeaders - ? generatorOptions.customHeaders.join('\n') - : "import 'package:flutter_test/flutter_test.dart';"; + final headerSection = + hasCustomHeaders + ? generatorOptions.customHeaders.join('\n') + : "import 'package:flutter_test/flutter_test.dart';"; return '${hasDataTable ? "import 'package:bdd_widget_test/data_table.dart' as bdd;\n" : ''}' ''' diff --git a/lib/src/step_file.dart b/lib/src/step_file.dart index ab2dd0f..fe2da2a 100644 --- a/lib/src/step_file.dart +++ b/lib/src/step_file.dart @@ -20,13 +20,16 @@ abstract class StepFile { final file = '${getStepFilename(bddLine.value)}.dart'; if (existingSteps.containsKey(file)) { - final import = - p.join('.', existingSteps[file], file).replaceAll(r'\', '/'); + final import = p + .join('.', existingSteps[file], file) + .replaceAll(r'\', '/'); return ExistingStepFile._(import); } - final externalStep = generatorOptions.externalSteps - .firstWhere((l) => l.contains(file), orElse: () => ''); + final externalStep = generatorOptions.externalSteps.firstWhere( + (l) => l.contains(file), + orElse: () => '', + ); if (externalStep.isNotEmpty) { return ExternalStepFile._(externalStep); } @@ -34,8 +37,9 @@ abstract class StepFile { if (generatorOptions.stepFolder.startsWith('./') || generatorOptions.stepFolder.startsWith('../')) { // step folder is relative to feature file - final import = - p.join(generatorOptions.stepFolder, file).replaceAll(r'\', '/'); + final import = p + .join(generatorOptions.stepFolder, file) + .replaceAll(r'\', '/'); final filename = p.join(featureDir, generatorOptions.stepFolder, file); return NewStepFile._( import, @@ -50,8 +54,10 @@ abstract class StepFile { } // step folder is relative to test folder - final pathToTestFolder = - p.relative(getPathToStepFolder(generatorOptions), from: featureDir); + final pathToTestFolder = p.relative( + getPathToStepFolder(generatorOptions), + from: featureDir, + ); final import = p .join(pathToTestFolder, generatorOptions.stepFolder, file) .replaceAll(r'\', '/'); @@ -93,13 +99,13 @@ class NewStepFile extends StepFile { final bool hasDataTable; final GeneratorOptions generatorOptions; String get dartContent => generateStepDart( - package, - line, - testerType, - testerName, - hasDataTable, - generatorOptions, - ); + package, + line, + testerType, + testerName, + hasDataTable, + generatorOptions, + ); } class ExistingStepFile extends StepFile { diff --git a/lib/src/step_generator.dart b/lib/src/step_generator.dart index 752cceb..ef1f25b 100644 --- a/lib/src/step_generator.dart +++ b/lib/src/step_generator.dart @@ -79,38 +79,39 @@ BddStep _getStep( GeneratorOptions generatorOptions, ) { //for now, predefined steps don't support testerType - final factory = predefinedSteps[methodName] ?? - (_, __) => GenericStep( - methodName, - line, - testerType, - testerName, - hasDataTable, - generatorOptions, - ); + final factory = + predefinedSteps[methodName] ?? + (_, _) => GenericStep( + methodName, + line, + testerType, + testerName, + hasDataTable, + generatorOptions, + ); return factory(package, line); } final predefinedSteps = { 'theAppIsRunning': (package, _) => TheAppInRunningStep(package), - 'iDismissThePage': (_, __) => IDismissThePage(), - 'iDontSeeIcon': (_, __) => IDontSeeIcon(), - 'iDontSeeRichText': (_, __) => IDontSeeRichText(), - 'iDontSeeText': (_, __) => IDontSeeText(), - 'iDontSeeWidget': (_, __) => IDontSeeWidget(), - 'iEnterIntoInputField': (_, __) => IEnterIntoInputField(), - 'iSeeDisabledElevatedButton': (_, __) => ISeeDisabledElevatedButton(), - 'iSeeEnabledElevatedButton': (_, __) => ISeeEnabledElevatedButton(), - 'iSeeExactlyWidgets': (_, __) => ISeeExactlyWidgets(), - 'iSeeIcon': (_, __) => ISeeIcon(), - 'iSeeMultipleTexts': (_, __) => ISeeMultipleTexts(), - 'iSeeMultipleWidgets': (_, __) => ISeeMultipleWidgets(), - 'iSeeRichText': (_, __) => ISeeRichText(), - 'iSeeText': (_, __) => ISeeText(), - 'iSeeWidget': (_, __) => ISeeWidget(), - 'iTapIcon': (_, __) => ITapIcon(), - 'iTapText': (_, __) => ITapText(), - 'iWait': (_, __) => IWait(), + 'iDismissThePage': (_, _) => IDismissThePage(), + 'iDontSeeIcon': (_, _) => IDontSeeIcon(), + 'iDontSeeRichText': (_, _) => IDontSeeRichText(), + 'iDontSeeText': (_, _) => IDontSeeText(), + 'iDontSeeWidget': (_, _) => IDontSeeWidget(), + 'iEnterIntoInputField': (_, _) => IEnterIntoInputField(), + 'iSeeDisabledElevatedButton': (_, _) => ISeeDisabledElevatedButton(), + 'iSeeEnabledElevatedButton': (_, _) => ISeeEnabledElevatedButton(), + 'iSeeExactlyWidgets': (_, _) => ISeeExactlyWidgets(), + 'iSeeIcon': (_, _) => ISeeIcon(), + 'iSeeMultipleTexts': (_, _) => ISeeMultipleTexts(), + 'iSeeMultipleWidgets': (_, _) => ISeeMultipleWidgets(), + 'iSeeRichText': (_, _) => ISeeRichText(), + 'iSeeText': (_, _) => ISeeText(), + 'iSeeWidget': (_, _) => ISeeWidget(), + 'iTapIcon': (_, _) => ITapIcon(), + 'iTapText': (_, _) => ITapText(), + 'iWait': (_, _) => IWait(), }; /// Return an array of Strings where first element is the step name and the rest diff --git a/lib/src/util/common.dart b/lib/src/util/common.dart index 899d174..d800db7 100644 --- a/lib/src/util/common.dart +++ b/lib/src/util/common.dart @@ -18,8 +18,9 @@ String parseCustomTagFromFeatureTagLine( ) { var tagType = defaultTagValue; - final customTagLine = featureTagLines - .firstWhereOrNull((line) => line.rawLine.startsWith(customTag)); + final customTagLine = featureTagLines.firstWhereOrNull( + (line) => line.rawLine.startsWith(customTag), + ); if (customTagLine != null) { final tagOverride = parseCustomTag( diff --git a/test/custom_tester_type_test.dart b/test/custom_tester_type_test.dart index 86f4b16..2a81308 100644 --- a/test/custom_tester_type_test.dart +++ b/test/custom_tester_type_test.dart @@ -68,8 +68,9 @@ void main() { featureDir: 'test.feature', package: 'test', input: featureFile, - generatorOptions: - const GeneratorOptions(testerType: 'PatrolIntegrationTester'), + generatorOptions: const GeneratorOptions( + testerType: 'PatrolIntegrationTester', + ), ); expect(feature.dartContent, expectedFeatureDart); }); diff --git a/test/feature_generator_test.dart b/test/feature_generator_test.dart index 93a93e5..23cc3c7 100644 --- a/test/feature_generator_test.dart +++ b/test/feature_generator_test.dart @@ -21,7 +21,8 @@ void main() { }); test('no customization', () async { - const expected = '// GENERATED CODE - DO NOT MODIFY BY HAND\n' + const expected = + '// GENERATED CODE - DO NOT MODIFY BY HAND\n' '// ignore_for_file: type=lint, type=warning\n' '\n' "import 'package:flutter/material.dart';\n" @@ -42,8 +43,10 @@ void main() { test('existing step should not regenerate', () async { const scenario = 'existing_step'; - final dummyStepPath = - p.join(getStepFolderName(scenario), 'the_app_is_running.dart'); + final dummyStepPath = p.join( + getStepFolderName(scenario), + 'the_app_is_running.dart', + ); const expectedFileContent = '// existing step'; fs.file(dummyStepPath) ..createSync(recursive: true) @@ -65,8 +68,11 @@ relativeToTestFolder: false ..writeAsStringSync(bddOptions); const scenario = 'existing_step_outside_test_folder'; - final dummyStepPath = - p.join(fs.currentDirectory.path, 'my_steps', 'the_app_is_running.dart'); + final dummyStepPath = p.join( + fs.currentDirectory.path, + 'my_steps', + 'the_app_is_running.dart', + ); fs.file(dummyStepPath) ..createSync(recursive: true) ..writeAsStringSync('dummy'); @@ -74,7 +80,8 @@ relativeToTestFolder: false // note: the import is so weird because p.relative() can not // find intersection between two paths (however, somehow it works) // not a problem in the real world - const expected = '// GENERATED CODE - DO NOT MODIFY BY HAND\n' + const expected = + '// GENERATED CODE - DO NOT MODIFY BY HAND\n' '// ignore_for_file: type=lint, type=warning\n' '\n' "import 'package:flutter/material.dart';\n" @@ -107,7 +114,8 @@ customHeaders: ..createSync() ..writeAsStringSync(bddOptions); - const expected = '// GENERATED CODE - DO NOT MODIFY BY HAND\n' + const expected = + '// GENERATED CODE - DO NOT MODIFY BY HAND\n' '// ignore_for_file: type=lint, type=warning\n' '\n' "import 'package:flutter_test/flutter_test.dart';\n" @@ -186,7 +194,8 @@ testMethodName: customName stepFolderName: ./scenarios '''); - const expected = '// GENERATED CODE - DO NOT MODIFY BY HAND\n' + const expected = + '// GENERATED CODE - DO NOT MODIFY BY HAND\n' '// ignore_for_file: type=lint, type=warning\n' '\n' "import 'package:flutter/material.dart';\n" @@ -239,7 +248,8 @@ include: $externalYaml3 stepFolderName: ./scenarios '''); - const expected = '// GENERATED CODE - DO NOT MODIFY BY HAND\n' + const expected = + '// GENERATED CODE - DO NOT MODIFY BY HAND\n' '// ignore_for_file: type=lint, type=warning\n' '\n' "import 'package:flutter/material.dart';\n" @@ -274,7 +284,8 @@ dev_dependencies: sdk: flutter '''); - const expected = '// GENERATED CODE - DO NOT MODIFY BY HAND\n' + const expected = + '// GENERATED CODE - DO NOT MODIFY BY HAND\n' '// ignore_for_file: type=lint, type=warning\n' '\n' "import 'package:flutter/material.dart';\n" @@ -304,7 +315,8 @@ dev_dependencies: dev_dependencies: '''); - const expected = '// GENERATED CODE - DO NOT MODIFY BY HAND\n' + const expected = + '// GENERATED CODE - DO NOT MODIFY BY HAND\n' '// ignore_for_file: type=lint, type=warning\n' '\n' "import 'package:flutter/material.dart';\n" @@ -344,18 +356,19 @@ Future generate( featureBuilder(options ?? BuilderOptions.empty), srcs, rootPackage: pkgName, - outputs: expectedOutput != null - ? { - '$pkgName|$path/sample_test.dart': decodedMatches(expectedOutput), - } - : null, + outputs: + expectedOutput != null + ? { + '$pkgName|$path/sample_test.dart': decodedMatches(expectedOutput), + } + : null, ); } String getStepFolderName(String scenario) => p.joinAll([ - fs.currentDirectory.path, - 'test', - 'builder_scenarios', - scenario, - 'step', - ]); + fs.currentDirectory.path, + 'test', + 'builder_scenarios', + scenario, + 'step', +]); diff --git a/test/feature_test.dart b/test/feature_test.dart index be66180..1263057 100644 --- a/test/feature_test.dart +++ b/test/feature_test.dart @@ -126,16 +126,17 @@ void main() { '''; final feature = FeatureFile( - featureDir: 'test.feature', - package: 'test', - input: minimalFeatureFile, - generatorOptions: const GeneratorOptions( - customHeaders: [ - "import 'package:patrol/patrol.dart';", - '// Import flutter_test for compatibility', - "import 'package:flutter_test/flutter_test.dart';", - ], - )); + featureDir: 'test.feature', + package: 'test', + input: minimalFeatureFile, + generatorOptions: const GeneratorOptions( + customHeaders: [ + "import 'package:patrol/patrol.dart';", + '// Import flutter_test for compatibility', + "import 'package:flutter_test/flutter_test.dart';", + ], + ), + ); expect(feature.dartContent, expectedFeatureDart); }); } diff --git a/test/integration_test.dart b/test/integration_test.dart index 401c708..ee6302a 100644 --- a/test/integration_test.dart +++ b/test/integration_test.dart @@ -37,9 +37,9 @@ void main() { }); test( - 'integration-related lines are not added if includeIntegrationTestBinding is false', - () { - const expectedFeatureDart = ''' + 'integration-related lines are not added if includeIntegrationTestBinding is false', + () { + const expectedFeatureDart = ''' // GENERATED CODE - DO NOT MODIFY BY HAND // ignore_for_file: type=lint, type=warning @@ -58,14 +58,15 @@ void main() { } '''; - final feature = FeatureFile( - featureDir: 'test.feature', - package: 'test', - input: minimalFeatureFile, - includeIntegrationTestImport: true, - ); - expect(feature.dartContent, expectedFeatureDart); - }); + final feature = FeatureFile( + featureDir: 'test.feature', + package: 'test', + input: minimalFeatureFile, + includeIntegrationTestImport: true, + ); + expect(feature.dartContent, expectedFeatureDart); + }, + ); test('integration-related code is not added by default', () { const expectedFeatureDart = ''' diff --git a/test/step_folder_name_test.dart b/test/step_folder_name_test.dart index f17d576..ec7fc73 100644 --- a/test/step_folder_name_test.dart +++ b/test/step_folder_name_test.dart @@ -32,8 +32,9 @@ void main() { featureDir: 'test.feature', package: 'test', input: featureFile, - generatorOptions: - const GeneratorOptions(stepFolderName: '../../../custom_steps'), + generatorOptions: const GeneratorOptions( + stepFolderName: '../../../custom_steps', + ), ); expect(feature.dartContent, expectedFeatureDart); }); diff --git a/test/steps_test.dart b/test/steps_test.dart index af9958a..ed39f97 100644 --- a/test/steps_test.dart +++ b/test/steps_test.dart @@ -5,8 +5,11 @@ void main() { test('Empty feature file parses', () { const path = 'test'; - final feature = - FeatureFile(featureDir: '$path.feature', package: path, input: ''); + final feature = FeatureFile( + featureDir: '$path.feature', + package: path, + input: '', + ); expect(feature.getStepFiles().length, 0); }); } diff --git a/test/test_method_name_test.dart b/test/test_method_name_test.dart index 185102a..a360ccf 100644 --- a/test/test_method_name_test.dart +++ b/test/test_method_name_test.dart @@ -32,8 +32,9 @@ void main() { featureDir: 'test.feature', package: 'test', input: featureFile, - generatorOptions: - const GeneratorOptions(testMethodName: 'customTestWidgets'), + generatorOptions: const GeneratorOptions( + testMethodName: 'customTestWidgets', + ), ); expect(feature.dartContent, expectedFeatureDart); }); From 0dd697ed7e5e407dc89e459008c39596ba2e1a5d Mon Sep 17 00:00:00 2001 From: Oleksandr Leushchenko Date: Tue, 23 Sep 2025 09:31:58 +0300 Subject: [PATCH 3/3] Fix pana score --- analysis_options.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/analysis_options.yaml b/analysis_options.yaml index 7ed1273..f8c075f 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -7,3 +7,6 @@ linter: constant_identifier_names: false lines_longer_than_80_chars: false public_member_api_docs: false + +formatter: + trailing_commas: preserve \ No newline at end of file