diff --git a/README.md b/README.md index f5994ab..0a458fd 100644 --- a/README.md +++ b/README.md @@ -429,6 +429,15 @@ targets: Since Patrol version 3.0.0, `IntegrationTestWidgetsFlutterBinding.ensureInitialized` must not be called. Set `includeIntegrationTestBinding` to `false`. +### I don't like that the plugin creates steps under `test` folder. How to change that? + +You may set a relative path in the `build.yaml` file (see the `example` folder): +```yaml +relativeToTestFolder: false +stepFolderName: integration_test/steps # if you want to have steps in the integration_test folder +hookFolderName: integration_test/bdd_hooks # if you want to have hooks in the integration_test folder +``` + ## Contributing If you find a bug or would like to request a new feature, just [open an issue](https://github.com/olexale/bdd_widget_test/issues/new). Your contributions are always welcome! diff --git a/example/build.yaml b/example/build.yaml index f5d29e0..de4fc9f 100644 --- a/example/build.yaml +++ b/example/build.yaml @@ -10,7 +10,10 @@ targets: options: includeIntegrationTestBinding: false # if false, integration test will not include binding; default is true stepFolderName: step # this trick is required to share steps between widget and integration tests + # relativeToTestFolder: false # if false, steps will be generated in the root of the package; default is true # testMethodName: customTestMethodName + # addHooks: true # if true, hooks will be added to the test; default is false + # hookFolderName: bdd_hooks include: package:bdd_widget_test/bdd_options.yaml # you may add defaul external steps with this line externalSteps: # or list only steps that you need - package:bdd_widget_test/step/i_see_text.dart diff --git a/lib/bdd_widget_test.dart b/lib/bdd_widget_test.dart index 6a39365..61a7216 100644 --- a/lib/bdd_widget_test.dart +++ b/lib/bdd_widget_test.dart @@ -33,7 +33,7 @@ class FeatureBuilder implements Builder { final feature = FeatureFile( featureDir: featureDir, package: inputId.package, - existingSteps: getExistingStepSubfolders(featureDir, options.stepFolder), + existingSteps: getExistingStepSubfolders(featureDir, options), input: contents, generatorOptions: options, includeIntegrationTestImport: isIntegrationTest, diff --git a/lib/src/existing_steps.dart b/lib/src/existing_steps.dart index dc83fb8..c7d1d42 100644 --- a/lib/src/existing_steps.dart +++ b/lib/src/existing_steps.dart @@ -1,16 +1,18 @@ -import 'package:bdd_widget_test/src/util/constants.dart'; +import 'package:bdd_widget_test/src/generator_options.dart'; import 'package:bdd_widget_test/src/util/fs.dart'; +import 'package:bdd_widget_test/src/util/get_test_folder_name.dart'; import 'package:path/path.dart' as p; /// key - step filename, value - path for import (ex: {'i_have_a_step.dart': 'step/common'}) Map getExistingStepSubfolders( String featureDir, - String stepFolderName, + GeneratorOptions options, ) { + final stepFolderName = options.stepFolder; final stepFolder = p.join( stepFolderName.startsWith('./') || stepFolderName.startsWith('../') ? featureDir - : testFolderName, + : getPathToStepFolder(options), stepFolderName, ); diff --git a/lib/src/generator_options.dart b/lib/src/generator_options.dart index a6486de..56ab562 100644 --- a/lib/src/generator_options.dart +++ b/lib/src/generator_options.dart @@ -13,6 +13,7 @@ class GeneratorOptions { String? testMethodName, List? externalSteps, String? stepFolderName, + bool? relativeToTestFolder, String? testerType, String? testerName, bool? addHooks, @@ -20,6 +21,7 @@ class GeneratorOptions { this.include, bool? includeIntegrationTestBinding, }) : stepFolder = stepFolderName ?? _stepFolderName, + relativeToTestFolder = relativeToTestFolder ?? true, testMethodName = testMethodName ?? _defaultTestMethodName, testerType = testerType ?? _defaultTesterType, testerName = testerName ?? _defaultTesterName, @@ -35,6 +37,7 @@ class GeneratorOptions { 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 @@ -45,6 +48,7 @@ class GeneratorOptions { ); final String stepFolder; + final bool relativeToTestFolder; final String testMethodName; final String testerType; final String testerName; @@ -96,6 +100,7 @@ GeneratorOptions merge(GeneratorOptions a, GeneratorOptions b) => 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 diff --git a/lib/src/hook_file.dart b/lib/src/hook_file.dart index 45b15d0..af32889 100644 --- a/lib/src/hook_file.dart +++ b/lib/src/hook_file.dart @@ -1,5 +1,6 @@ import 'package:bdd_widget_test/src/generator_options.dart'; import 'package:bdd_widget_test/src/util/constants.dart'; +import 'package:bdd_widget_test/src/util/get_test_folder_name.dart'; import 'package:path/path.dart' as p; class HookFile { @@ -31,10 +32,13 @@ class HookFile { return HookFile._create( featureDir: featureDir, package: package, - fileName: - p.join(testFolderName, generatorOptions.hookFolderName, fileName), + fileName: p.join( + getPathToStepFolder(generatorOptions), + generatorOptions.hookFolderName, + fileName, + ), import: p.join( - p.relative(testFolderName, from: featureDir), + p.relative(getPathToStepFolder(generatorOptions), from: featureDir), generatorOptions.hookFolderName, fileName, ), diff --git a/lib/src/step_file.dart b/lib/src/step_file.dart index a790eb9..ed9d553 100644 --- a/lib/src/step_file.dart +++ b/lib/src/step_file.dart @@ -1,7 +1,7 @@ import 'package:bdd_widget_test/src/bdd_line.dart'; import 'package:bdd_widget_test/src/generator_options.dart'; import 'package:bdd_widget_test/src/step_generator.dart'; -import 'package:bdd_widget_test/src/util/constants.dart'; +import 'package:bdd_widget_test/src/util/get_test_folder_name.dart'; import 'package:path/path.dart' as p; abstract class StepFile { @@ -33,6 +33,7 @@ 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 filename = p.join(featureDir, generatorOptions.stepFolder, file); @@ -47,11 +48,17 @@ abstract class StepFile { ); } - final pathToTestFolder = p.relative(testFolderName, from: featureDir); + // step folder is relative to test folder + final pathToTestFolder = + p.relative(getPathToStepFolder(generatorOptions), from: featureDir); final import = p .join(pathToTestFolder, generatorOptions.stepFolder, file) .replaceAll(r'\', '/'); - final filename = p.join(testFolderName, generatorOptions.stepFolder, file); + final filename = p.join( + getPathToStepFolder(generatorOptions), + generatorOptions.stepFolder, + file, + ); return NewStepFile._( import, filename, diff --git a/lib/src/util/constants.dart b/lib/src/util/constants.dart index 48a1acc..6205644 100644 --- a/lib/src/util/constants.dart +++ b/lib/src/util/constants.dart @@ -30,5 +30,3 @@ const testerNameTag = '@testerName:'; /// scenario functions for example: @scenarioParams: skip: false, timeout: Timeout(Duration(seconds: 1)) /// because some test packaages like `patrol` support this. const scenarioParamsTag = '@scenarioParams:'; - -const testFolderName = 'test'; diff --git a/lib/src/util/get_test_folder_name.dart b/lib/src/util/get_test_folder_name.dart new file mode 100644 index 0000000..0a78318 --- /dev/null +++ b/lib/src/util/get_test_folder_name.dart @@ -0,0 +1,12 @@ +import 'package:bdd_widget_test/src/generator_options.dart'; +import 'package:bdd_widget_test/src/util/fs.dart'; + +const _testFolderName = 'test'; + +/// Returns the folder where step folder is located. +String getPathToStepFolder(GeneratorOptions options) { + if (options.relativeToTestFolder) { + return _testFolderName; + } + return fs.currentDirectory.path; +} diff --git a/test/feature_generator_test.dart b/test/feature_generator_test.dart index 06a252b..9be194a 100644 --- a/test/feature_generator_test.dart +++ b/test/feature_generator_test.dart @@ -56,6 +56,46 @@ void main() { expect(content, expectedFileContent); }); + test('existing step outside test folder should be found', () async { + const bddOptions = ''' +stepFolderName: my_steps +relativeToTestFolder: false +'''; + fs.file('bdd_options.yaml') + ..createSync() + ..writeAsStringSync(bddOptions); + + const scenario = 'existing_step_outside_test_folder'; + final dummyStepPath = + p.join(fs.currentDirectory.path, 'my_steps', 'the_app_is_running.dart'); + fs.file(dummyStepPath) + ..createSync(recursive: true) + ..writeAsStringSync('dummy'); + + // 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' + '// ignore_for_file: unused_import, directives_ordering\n' + '\n' + "import 'package:flutter/material.dart';\n" + "import 'package:flutter_test/flutter_test.dart';\n" + '\n' + "import './../../../../../../../../my_steps/the_app_is_running.dart';\n" + '\n' + 'void main() {\n' + " group('''Testing feature''', () {\n" + " testWidgets('''Testing scenario''', (tester) async {\n" + ' await theAppIsRunning(tester);\n' + ' });\n' + ' });\n' + '}\n'; + + final content = await generate(scenario); + + expect(content, expected); + }); + test('custom bdd_options', () async { const bddOptions = ''' stepFolderName: ./scenarios diff --git a/test/step_folder_name_test.dart b/test/step_folder_name_test.dart index a2e11ea..23b3ad5 100644 --- a/test/step_folder_name_test.dart +++ b/test/step_folder_name_test.dart @@ -71,4 +71,40 @@ void main() { ); expect(feature.dartContent, expectedFeatureDart); }); + test('step folder is not under test folder', () { + const featureFile = ''' +Feature: Testing feature + Scenario: Testing scenario + Given the app is running +'''; + + const expectedFeatureDart = ''' +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_import, directives_ordering + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../../../custom_steps/the_app_is_running.dart'; + +void main() { + group(\'\'\'Testing feature\'\'\', () { + testWidgets(\'\'\'Testing scenario\'\'\', (tester) async { + await theAppIsRunning(tester); + }); + }); +} +'''; + + final feature = FeatureFile( + featureDir: 'test/subdir/feature', + package: 'test', + input: featureFile, + generatorOptions: const GeneratorOptions( + stepFolderName: 'custom_steps', + relativeToTestFolder: false, + ), + ); + expect(feature.dartContent, expectedFeatureDart); + }); }