Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions .github/workflows/dart.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,7 @@ jobs:
run: dart pub global activate coverage

- name: 🧪 Run tests
run: dart pub global run coverage:test_with_coverage

- name: 🎯 Check Code Coverage
uses: VeryGoodOpenSource/very_good_coverage@v1
run: dart pub global run coverage:test_with_coverage --fail-under 100

- name: 🥇 Update coverage badge
if: github.event_name != 'pull_request'
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## [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

## [2.0.0] - Upgrade dependencies

* **BREAKING CHANGE**: The package doesn't provide pre-built steps anymore. Steps will appear in the `step` folder.
Expand Down
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,33 @@ targets:
include: package:<your_package>/bdd_options.yaml
```

### How to add custom headers to generated files?

You can add custom header lines (imports, comments, etc.) to all generated step files **and feature files** using the `customHeaders` option in the `build.yaml` file:
```yaml
targets:
$default:
builders:
bdd_widget_test|featureBuilder:
options:
customHeaders:
- "import 'package:flutter_test/flutter_test.dart';"
- "import 'package:patrol/patrol.dart';"
- "// Custom test utilities"
- "import 'package:my_custom_package/my_helper.dart';"
```

This is useful when you need to:
- Use custom test frameworks (like Patrol) instead of the default flutter_test
- Import custom helper classes or utilities in all your generated files
- Add specific packages that your tests will commonly use
- Include custom test utilities, mocks, or constants
- Add custom comments or documentation to generated files

The custom headers will be added to:
- **Feature files**: After any data table imports, replacing the default flutter/material and flutter_test imports
- **Step files**: After any data table imports, replacing the default flutter_test import

### How to group steps in a single project?

You may create sub-folders (like `common`, `login`, `home`, etc.) in the `step` folder and move generated steps there. The plugin is smart enough to find them (see the `example` folder).
Expand Down Expand Up @@ -397,6 +424,9 @@ targets:
testerName: $
testerType: PatrolIntegrationTester
includeIntegrationTestBinding: false
customHeaders:
- "import 'package:flutter_test/flutter_test.dart';"
- "import 'package:patrol/patrol.dart';"
```

Since Patrol version 3.0.0, `IntegrationTestWidgetsFlutterBinding.ensureInitialized` must not be called. Set `includeIntegrationTestBinding` to `false`.
Expand Down
14 changes: 14 additions & 0 deletions example/bdd_options_example.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Example bdd_options.yaml file showing how to use customHeaders
# This file can be referenced from build.yaml using the include option

# Add custom header lines that will be added to all generated step files
customHeaders:
- "import 'package:flutter_test/flutter_test.dart';"
- "import 'package:mockito/mockito.dart';"
- "import 'package:my_project/test_helpers.dart';"
- "import 'package:my_project/mocks/database_mock.dart';"

# You can also include external steps from other packages
externalSteps:
- package:common_bdd_steps/step/i_wait.dart
- package:common_bdd_steps/step/i_see_loading.dart
3 changes: 3 additions & 0 deletions example/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ targets:
# addHooks: true # if true, hooks will be added to the test; default is false
# hookFolderName: bdd_hooks
# include: package:<package1>/bdd_options.yaml # you may add defaul external steps with this line
# customHeaders: # add custom header lines to all generated step files
# - "import 'package:flutter_test/flutter_test.dart';"
# - "import 'package:my_project/test_helpers.dart';"
externalSteps: # or list only steps that you need
# - package:<package2>/step/i_see_text.dart
# - package:<package2>/step/i_dont_see_text.dart
Expand Down
1 change: 1 addition & 0 deletions lib/src/feature_file.dart
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ class FeatureFile {
includeIntegrationTestBinding,
includeIntegrationTestImport,
hookFile,
generatorOptions,
);

List<StepFile> getStepFiles() => _stepFiles;
Expand Down
15 changes: 13 additions & 2 deletions lib/src/feature_generator.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:bdd_widget_test/src/bdd_line.dart';
import 'package:bdd_widget_test/src/data_table_parser.dart';
import 'package:bdd_widget_test/src/generator_options.dart';
import 'package:bdd_widget_test/src/hook_file.dart';
import 'package:bdd_widget_test/src/scenario_generator.dart';
import 'package:bdd_widget_test/src/step_file.dart';
Expand All @@ -16,6 +17,7 @@ String generateFeatureDart(
bool includeIntegrationTestBinding,
bool includeIntegrationTestImport,
HookFile? hookFile,
GeneratorOptions generatorOptions,
) {
final sb = StringBuffer();
sb.writeln('// GENERATED CODE - DO NOT MODIFY BY HAND');
Expand Down Expand Up @@ -59,8 +61,17 @@ String generateFeatureDart(
if (hasBddDataTable(lines)) {
sb.writeln("import 'package:bdd_widget_test/data_table.dart' as bdd;");
}
sb.writeln("import 'package:flutter/material.dart';");
sb.writeln("import 'package:flutter_test/flutter_test.dart';");

// Use custom headers if provided, otherwise use default imports
if (generatorOptions.customHeaders.isNotEmpty) {
for (final header in generatorOptions.customHeaders) {
sb.writeln(header);
}
} else {
sb.writeln("import 'package:flutter/material.dart';");
sb.writeln("import 'package:flutter_test/flutter_test.dart';");
}

if (includeIntegrationTestImport) {
sb.writeln("import 'package:integration_test/integration_test.dart';");
}
Expand Down
35 changes: 20 additions & 15 deletions lib/src/generator_options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class GeneratorOptions {
String? hookFolderName,
this.include,
bool? includeIntegrationTestBinding,
List<String>? customHeaders,
}) : stepFolder = stepFolderName ?? _stepFolderName,
relativeToTestFolder = relativeToTestFolder ?? true,
testMethodName = testMethodName ?? _defaultTestMethodName,
Expand All @@ -28,24 +29,26 @@ class GeneratorOptions {
addHooks = addHooks ?? false,
hookFolderName = hookFolderName ?? _hookFolderName,
externalSteps = externalSteps ?? const [],
includeIntegrationTestBinding = includeIntegrationTestBinding ?? true;
includeIntegrationTestBinding = includeIntegrationTestBinding ?? true,
customHeaders = customHeaders ?? const [];

factory GeneratorOptions.fromMap(Map<String, dynamic> json) =>
GeneratorOptions(
testMethodName: json['testMethodName'] as String?,
testerType: json['testerType'] as String?,
testerName: json['testerName'] as String?,
externalSteps: (json['externalSteps'] as List?)?.cast<String>(),
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<String>(),
includeIntegrationTestBinding:
json['includeIntegrationTestBinding'] as bool?,
);
testMethodName: json['testMethodName'] as String?,
testerType: json['testerType'] as String?,
testerName: json['testerName'] as String?,
externalSteps: (json['externalSteps'] as List?)?.cast<String>(),
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<String>(),
includeIntegrationTestBinding:
json['includeIntegrationTestBinding'] as bool?,
customHeaders:
(json['customHeaders'] as List?)?.cast<String>() ?? []);

final String stepFolder;
final bool relativeToTestFolder;
Expand All @@ -57,6 +60,7 @@ class GeneratorOptions {
final List<String>? include;
final List<String> externalSteps;
final bool includeIntegrationTestBinding;
final List<String> customHeaders;
}

Future<GeneratorOptions> flattenOptions(GeneratorOptions options) async {
Expand Down Expand Up @@ -109,4 +113,5 @@ GeneratorOptions merge(GeneratorOptions a, GeneratorOptions b) =>
include: b.include,
includeIntegrationTestBinding:
a.includeIntegrationTestBinding || b.includeIntegrationTestBinding,
customHeaders: [...a.customHeaders, ...b.customHeaders],
);
17 changes: 13 additions & 4 deletions lib/src/step/generic_step.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:bdd_widget_test/src/generator_options.dart';
import 'package:bdd_widget_test/src/regex.dart';
import 'package:bdd_widget_test/src/step/bdd_step.dart';
import 'package:bdd_widget_test/src/step_generator.dart';
Expand All @@ -10,25 +11,33 @@ class GenericStep implements BddStep {
this.testerType,
this.customTesterName,
this.hasDataTable,
this.generatorOptions,
);

final String rawLine;
final String methodName;
final String testerType;
final String customTesterName;
final bool hasDataTable;
final GeneratorOptions generatorOptions;

@override
String get content =>
'${hasDataTable ? "import 'package:bdd_widget_test/data_table.dart' as bdd;\n" : ''}'
'''
import 'package:flutter_test/flutter_test.dart';
String get content {
final hasCustomHeaders = generatorOptions.customHeaders.isNotEmpty;
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" : ''}'
'''
$headerSection

/// Usage: $rawLine
Future<void> $methodName($testerType $customTesterName${_getMethodParameters(rawLine, hasDataTable)}) async {
throw UnimplementedError();
}
''';
}

String _getMethodParameters(String stepLine, bool hadDataTable) {
final params = parseRawStepLine(stepLine).skip(1);
Expand Down
5 changes: 5 additions & 0 deletions lib/src/step_file.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ abstract class StepFile {
testerTypeTagValue,
testerNameTagValue,
bddLine.type == LineType.dataTableStep,
generatorOptions,
);
}

Expand All @@ -67,6 +68,7 @@ abstract class StepFile {
testerTypeTagValue,
testerNameTagValue,
bddLine.type == LineType.dataTableStep,
generatorOptions,
);
}
}
Expand All @@ -80,6 +82,7 @@ class NewStepFile extends StepFile {
this.testerType,
this.testerName,
this.hasDataTable,
this.generatorOptions,
) : super._();

final String package;
Expand All @@ -88,12 +91,14 @@ class NewStepFile extends StepFile {
final String testerType;
final String testerName;
final bool hasDataTable;
final GeneratorOptions generatorOptions;
String get dartContent => generateStepDart(
package,
line,
testerType,
testerName,
hasDataTable,
generatorOptions,
);
}

Expand Down
5 changes: 5 additions & 0 deletions lib/src/step_generator.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:bdd_widget_test/src/generator_options.dart';
import 'package:bdd_widget_test/src/regex.dart';
import 'package:bdd_widget_test/src/step/bdd_step.dart';
import 'package:bdd_widget_test/src/step/generic_step.dart';
Expand Down Expand Up @@ -52,6 +53,7 @@ String generateStepDart(
String testerType,
String customTesterName,
bool hasDataTable,
GeneratorOptions generatorOptions,
) {
final methodName = getStepMethodName(line);

Expand All @@ -62,6 +64,7 @@ String generateStepDart(
testerType,
customTesterName,
hasDataTable,
generatorOptions,
);
return bddStep.content;
}
Expand All @@ -73,6 +76,7 @@ BddStep _getStep(
String testerType,
String testerName,
bool hasDataTable,
GeneratorOptions generatorOptions,
) {
//for now, predefined steps don't support testerType
final factory = predefinedSteps[methodName] ??
Expand All @@ -82,6 +86,7 @@ BddStep _getStep(
testerType,
testerName,
hasDataTable,
generatorOptions,
);
return factory(package, line);
}
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: bdd_widget_test
description: A BDD-style widget testing library. Generates Flutter widget tests from *.feature files.
version: 2.0.0
version: 2.0.1
repository: https://github.com/olexale/bdd_widget_test
issue_tracker: https://github.com/olexale/bdd_widget_test/issues

Expand Down
Loading