Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,34 @@ 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';"
- "// 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

**Important**: When `customHeaders` are provided, the default imports (`import 'package:flutter/material.dart';` and `import 'package:flutter_test/flutter_test.dart';`) are **not** automatically included in feature files, and the default `import 'package:flutter_test/flutter_test.dart';` is not included in step files. You have full control over what imports and content are added to your 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 +425,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