- Fix #257 - fixed issue when generating a step with a '$' sign in
- Fix #256 - Ensure all exceptions generated when running a step are logged - Fix #253 - Ensure features with descriptions that span more than one line are parsed correctly - Fix #252 - Ensure all async code is awaited - When taking a screenshot on the web use the render element rather than relying on native code that does not work
This commit is contained in:
parent
4378a2447d
commit
eff82509c7
|
@ -1,3 +1,10 @@
|
||||||
|
## [3.0.0-rc.17] - 25/07/2022
|
||||||
|
- Fix #257 - fixed issue when generating a step with a '$' sign in
|
||||||
|
- Fix #256 - Ensure all exceptions generated when running a step are logged
|
||||||
|
- Fix #253 - Ensure features with descriptions that span more than one line are parsed correctly
|
||||||
|
- Fix #252 - Ensure all async code is awaited
|
||||||
|
- When taking a screenshot on the web use the render element rather than relying on native code that does not work
|
||||||
|
|
||||||
## [3.0.0-rc.16] - 01/07/2022
|
## [3.0.0-rc.16] - 01/07/2022
|
||||||
- Fix #231 - using local coordinate system when taking a screenshot on Android (thanks to @youssef-t for the solution)
|
- Fix #231 - using local coordinate system when taking a screenshot on Android (thanks to @youssef-t for the solution)
|
||||||
- Fix #216 - ensure step exceptions and `expect` failure results are added as errors to the json report
|
- Fix #216 - ensure step exceptions and `expect` failure results are added as errors to the json report
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
@debug
|
Feature: Expect failures
|
||||||
Feature: Expect failure
|
|
||||||
Ensure that when a test fails the exception or test failure is reported
|
Ensure that when a test fails the exception or test failure is reported
|
||||||
|
|
||||||
|
@failure-expected
|
||||||
Scenario: Exception should be added to json report
|
Scenario: Exception should be added to json report
|
||||||
Given I expect the todo list
|
When I tap the "button is not here but exception should be logged in report" button
|
||||||
| Todo |
|
|
||||||
| Buy blueberries |
|
|
||||||
When I tap the "add" button
|
|
||||||
And I fill the "todo" field with "Buy hannah's apples"
|
|
||||||
|
|
||||||
|
@failure-expected
|
||||||
Scenario: Failed expect() should be added to json report
|
Scenario: Failed expect() should be added to json report
|
||||||
Description for this scenario!
|
Description for this scenario!
|
||||||
When I tap the "add" button
|
When I tap the "add" button
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
@debug
|
||||||
|
Feature: Parsing
|
||||||
|
Complex description:
|
||||||
|
- Line "one".
|
||||||
|
- Line two, more text
|
||||||
|
- Line three
|
||||||
|
|
||||||
|
Scenario: Parsing a
|
||||||
|
Given the text "^[A-Z]{3}\\d{5}\$"
|
|
@ -1,7 +1,6 @@
|
||||||
@tag
|
@tag
|
||||||
Feature: Swiping
|
Feature: Swiping
|
||||||
|
|
||||||
@debug
|
|
||||||
Scenario: User can swipe cards left and right
|
Scenario: User can swipe cards left and right
|
||||||
Given I swipe right by 250 pixels on the "scrollable cards"`
|
Given I swipe right by 250 pixels on the "scrollable cards"`
|
||||||
Then I expect the text "Page 2" to be present
|
Then I expect the text "Page 2" to be present
|
||||||
|
|
|
@ -8,18 +8,20 @@ import 'package:gherkin/gherkin.dart';
|
||||||
import 'hooks/reset_app_hook.dart';
|
import 'hooks/reset_app_hook.dart';
|
||||||
import 'steps/expect_failure.dart';
|
import 'steps/expect_failure.dart';
|
||||||
import 'steps/expect_todos_step.dart';
|
import 'steps/expect_todos_step.dart';
|
||||||
|
import 'steps/given_text.dart';
|
||||||
import 'steps/multiline_string_with_formatted_json.dart';
|
import 'steps/multiline_string_with_formatted_json.dart';
|
||||||
import 'steps/when_await_animation.dart';
|
import 'steps/when_await_animation.dart';
|
||||||
import 'steps/when_step_has_timeout.dart';
|
import 'steps/when_step_has_timeout.dart';
|
||||||
import 'world/custom_world.dart';
|
import 'world/custom_world.dart';
|
||||||
|
|
||||||
FlutterTestConfiguration gherkinTestConfiguration = FlutterTestConfiguration(
|
FlutterTestConfiguration gherkinTestConfiguration = FlutterTestConfiguration(
|
||||||
// tagExpression: '@debug', // can be used to limit the tests that are run
|
tagExpression: '@debug2', // can be used to limit the tests that are run
|
||||||
stepDefinitions: [
|
stepDefinitions: [
|
||||||
thenIExpectTheTodos,
|
thenIExpectTheTodos,
|
||||||
whenAnAnimationIsAwaited,
|
whenAnAnimationIsAwaited,
|
||||||
whenStepHasTimeout,
|
whenStepHasTimeout,
|
||||||
givenTheData,
|
givenTheData,
|
||||||
|
givenTheText,
|
||||||
thenIExpectFailure,
|
thenIExpectFailure,
|
||||||
],
|
],
|
||||||
hooks: [
|
hooks: [
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -2,4 +2,4 @@ call npm init -y
|
||||||
|
|
||||||
call npm install --save-dev cucumber-html-reporter
|
call npm install --save-dev cucumber-html-reporter
|
||||||
|
|
||||||
node -e "require('cucumber-html-reporter').generate({theme: 'bootstrap', jsonFile: 'REPORT_NAME.json', output: 'report.html', reportSuiteAsScenarios: true, launchReport: false});"
|
node -e "require('cucumber-html-reporter').generate({theme: 'bootstrap', jsonFile: '{REPORT_NAME}.json', output: 'report.html', reportSuiteAsScenarios: true, launchReport: false});"
|
|
@ -0,0 +1,9 @@
|
||||||
|
import 'package:flutter_gherkin/flutter_gherkin.dart';
|
||||||
|
import 'package:gherkin/gherkin.dart';
|
||||||
|
|
||||||
|
final givenTheText = given1<String, FlutterWidgetTesterWorld>(
|
||||||
|
'the text {String}',
|
||||||
|
(text, world) async {
|
||||||
|
print(text);
|
||||||
|
},
|
||||||
|
);
|
|
@ -13,5 +13,14 @@ void main() {
|
||||||
executeTestSuite(
|
executeTestSuite(
|
||||||
appMainFunction: appInitializationFn,
|
appMainFunction: appInitializationFn,
|
||||||
configuration: gherkinTestConfiguration,
|
configuration: gherkinTestConfiguration,
|
||||||
|
// if you have lots of test you might need to increase the default timeout
|
||||||
|
// scenarioExecutionTimeout: Timeout(const Duration(minutes: 30)),
|
||||||
|
// if your app has lots of endless animations you might need to
|
||||||
|
// provide your own app lifecycle pump handler that doesn't pump
|
||||||
|
// at certain lifecycle stages
|
||||||
|
// appLifecyclePumpHandler: (appPhase, widgetTester) async => {},
|
||||||
|
// you can increase the performance of your tests at the cost of
|
||||||
|
// not drawing some frames but it might lead to unexpected consequences
|
||||||
|
// framePolicy: LiveTestWidgetsFlutterBindingFramePolicy.benchmarkLive,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner {
|
||||||
testFeature1();
|
testFeature1();
|
||||||
testFeature2();
|
testFeature2();
|
||||||
testFeature3();
|
testFeature3();
|
||||||
|
testFeature4();
|
||||||
}
|
}
|
||||||
|
|
||||||
void testFeature0() {
|
void testFeature0() {
|
||||||
|
@ -91,7 +92,7 @@ class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner {
|
||||||
],
|
],
|
||||||
onBefore: () async => onBeforeRunFeature(
|
onBefore: () async => onBeforeRunFeature(
|
||||||
name: 'Creating todos',
|
name: 'Creating todos',
|
||||||
path: r'.\\integration_test\\features\\create.feature',
|
path: '.\\integration_test\\features\\create.feature',
|
||||||
description: null,
|
description: null,
|
||||||
tags: <String>['@tag'],
|
tags: <String>['@tag'],
|
||||||
),
|
),
|
||||||
|
@ -101,7 +102,7 @@ class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner {
|
||||||
name: 'User can create multiple new todo items',
|
name: 'User can create multiple new todo items',
|
||||||
description: null,
|
description: null,
|
||||||
path: '.\\integration_test\\features\\create.feature',
|
path: '.\\integration_test\\features\\create.feature',
|
||||||
tags: <String>['@tag'],
|
tags: <String>['@tag', '@debug2'],
|
||||||
steps: [
|
steps: [
|
||||||
(
|
(
|
||||||
TestDependencies dependencies,
|
TestDependencies dependencies,
|
||||||
|
@ -241,7 +242,7 @@ class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner {
|
||||||
],
|
],
|
||||||
onAfter: () async => onAfterRunFeature(
|
onAfter: () async => onAfterRunFeature(
|
||||||
name: 'Creating todos',
|
name: 'Creating todos',
|
||||||
path: r'.\\integration_test\\features\\create.feature',
|
path: '.\\integration_test\\features\\create.feature',
|
||||||
description: null,
|
description: null,
|
||||||
tags: <String>['@tag'],
|
tags: <String>['@tag'],
|
||||||
),
|
),
|
||||||
|
@ -302,13 +303,13 @@ class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner {
|
||||||
],
|
],
|
||||||
onBefore: () async => onBeforeRunFeature(
|
onBefore: () async => onBeforeRunFeature(
|
||||||
name: 'Checking data',
|
name: 'Checking data',
|
||||||
path: r'.\\integration_test\\features\\check.feature',
|
path: '.\\integration_test\\features\\check.feature',
|
||||||
description: null,
|
description: null,
|
||||||
tags: <String>['@tag'],
|
tags: <String>['@tag'],
|
||||||
),
|
),
|
||||||
onAfter: () async => onAfterRunFeature(
|
onAfter: () async => onAfterRunFeature(
|
||||||
name: 'Checking data',
|
name: 'Checking data',
|
||||||
path: r'.\\integration_test\\features\\check.feature',
|
path: '.\\integration_test\\features\\check.feature',
|
||||||
description: null,
|
description: null,
|
||||||
tags: <String>['@tag'],
|
tags: <String>['@tag'],
|
||||||
),
|
),
|
||||||
|
@ -326,7 +327,7 @@ class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner {
|
||||||
name: 'User can swipe cards left and right',
|
name: 'User can swipe cards left and right',
|
||||||
description: null,
|
description: null,
|
||||||
path: '.\\integration_test\\features\\swiping.feature',
|
path: '.\\integration_test\\features\\swiping.feature',
|
||||||
tags: <String>['@tag', '@debug'],
|
tags: <String>['@tag'],
|
||||||
steps: [
|
steps: [
|
||||||
(
|
(
|
||||||
TestDependencies dependencies,
|
TestDependencies dependencies,
|
||||||
|
@ -381,13 +382,13 @@ class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner {
|
||||||
],
|
],
|
||||||
onBefore: () async => onBeforeRunFeature(
|
onBefore: () async => onBeforeRunFeature(
|
||||||
name: 'Swiping',
|
name: 'Swiping',
|
||||||
path: r'.\\integration_test\\features\\swiping.feature',
|
path: '.\\integration_test\\features\\swiping.feature',
|
||||||
description: null,
|
description: null,
|
||||||
tags: <String>['@tag'],
|
tags: <String>['@tag'],
|
||||||
),
|
),
|
||||||
onAfter: () async => onAfterRunFeature(
|
onAfter: () async => onAfterRunFeature(
|
||||||
name: 'Swiping',
|
name: 'Swiping',
|
||||||
path: r'.\\integration_test\\features\\swiping.feature',
|
path: '.\\integration_test\\features\\swiping.feature',
|
||||||
description: null,
|
description: null,
|
||||||
tags: <String>['@tag'],
|
tags: <String>['@tag'],
|
||||||
),
|
),
|
||||||
|
@ -398,13 +399,13 @@ class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner {
|
||||||
|
|
||||||
void testFeature3() {
|
void testFeature3() {
|
||||||
runFeature(
|
runFeature(
|
||||||
name: 'Expect failure:',
|
name: 'Parsing:',
|
||||||
tags: <String>['@debug'],
|
tags: <String>['@debug'],
|
||||||
run: () {
|
run: () {
|
||||||
runScenario(
|
runScenario(
|
||||||
name: 'Exception should be added to json report',
|
name: 'Parsing a',
|
||||||
description: null,
|
description: null,
|
||||||
path: '.\\integration_test\\features\\failure.feature',
|
path: '.\\integration_test\\features\\parsing.feature',
|
||||||
tags: <String>['@debug'],
|
tags: <String>['@debug'],
|
||||||
steps: [
|
steps: [
|
||||||
(
|
(
|
||||||
|
@ -412,31 +413,7 @@ class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner {
|
||||||
bool skip,
|
bool skip,
|
||||||
) async {
|
) async {
|
||||||
return await runStep(
|
return await runStep(
|
||||||
name: 'Given I expect the todo list',
|
name: 'Given the text "^[A-Z]{3}\\\\d{5}\\\$"',
|
||||||
multiLineStrings: <String>[],
|
|
||||||
table: GherkinTable.fromJson('[{"Todo":"Buy blueberries"}]'),
|
|
||||||
dependencies: dependencies,
|
|
||||||
skip: skip,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
(
|
|
||||||
TestDependencies dependencies,
|
|
||||||
bool skip,
|
|
||||||
) async {
|
|
||||||
return await runStep(
|
|
||||||
name: 'When I tap the "add" button',
|
|
||||||
multiLineStrings: <String>[],
|
|
||||||
table: null,
|
|
||||||
dependencies: dependencies,
|
|
||||||
skip: skip,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
(
|
|
||||||
TestDependencies dependencies,
|
|
||||||
bool skip,
|
|
||||||
) async {
|
|
||||||
return await runStep(
|
|
||||||
name: 'And I fill the "todo" field with "Buy hannah\'s apples"',
|
|
||||||
multiLineStrings: <String>[],
|
multiLineStrings: <String>[],
|
||||||
table: null,
|
table: null,
|
||||||
dependencies: dependencies,
|
dependencies: dependencies,
|
||||||
|
@ -445,19 +422,67 @@ class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
onBefore: () async => onBeforeRunFeature(
|
onBefore: () async => onBeforeRunFeature(
|
||||||
name: 'Expect failure',
|
name: 'Parsing',
|
||||||
path: r'.\\integration_test\\features\\failure.feature',
|
path: '.\\integration_test\\features\\parsing.feature',
|
||||||
description:
|
description: """Complex description:
|
||||||
"Ensure that when a test fails the exception or test failure is reported",
|
- Line "one".
|
||||||
|
- Line two, more text
|
||||||
|
- Line three""",
|
||||||
tags: <String>['@debug'],
|
tags: <String>['@debug'],
|
||||||
),
|
),
|
||||||
|
onAfter: () async => onAfterRunFeature(
|
||||||
|
name: 'Parsing',
|
||||||
|
path: '.\\integration_test\\features\\parsing.feature',
|
||||||
|
description: """Complex description:
|
||||||
|
- Line "one".
|
||||||
|
- Line two, more text
|
||||||
|
- Line three""",
|
||||||
|
tags: <String>['@debug'],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testFeature4() {
|
||||||
|
runFeature(
|
||||||
|
name: 'Expect failures:',
|
||||||
|
tags: <String>[],
|
||||||
|
run: () {
|
||||||
|
runScenario(
|
||||||
|
name: 'Exception should be added to json report',
|
||||||
|
description: null,
|
||||||
|
path: '.\\integration_test\\features\\failure.feature',
|
||||||
|
tags: <String>['@failure-expected'],
|
||||||
|
steps: [
|
||||||
|
(
|
||||||
|
TestDependencies dependencies,
|
||||||
|
bool skip,
|
||||||
|
) async {
|
||||||
|
return await runStep(
|
||||||
|
name:
|
||||||
|
'When I tap the "button is not here but exception should be logged in report" button',
|
||||||
|
multiLineStrings: <String>[],
|
||||||
|
table: null,
|
||||||
|
dependencies: dependencies,
|
||||||
|
skip: skip,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
],
|
||||||
|
onBefore: () async => onBeforeRunFeature(
|
||||||
|
name: 'Expect failures',
|
||||||
|
path: '.\\integration_test\\features\\failure.feature',
|
||||||
|
description:
|
||||||
|
"""Ensure that when a test fails the exception or test failure is reported""",
|
||||||
|
tags: <String>[],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
runScenario(
|
runScenario(
|
||||||
name: 'Failed expect() should be added to json report',
|
name: 'Failed expect() should be added to json report',
|
||||||
description: "Description for this scenario!",
|
description: "Description for this scenario!",
|
||||||
path: '.\\integration_test\\features\\failure.feature',
|
path: '.\\integration_test\\features\\failure.feature',
|
||||||
tags: <String>['@debug'],
|
tags: <String>['@failure-expected'],
|
||||||
steps: [
|
steps: [
|
||||||
(
|
(
|
||||||
TestDependencies dependencies,
|
TestDependencies dependencies,
|
||||||
|
@ -497,11 +522,11 @@ class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
onAfter: () async => onAfterRunFeature(
|
onAfter: () async => onAfterRunFeature(
|
||||||
name: 'Expect failure',
|
name: 'Expect failures',
|
||||||
path: r'.\\integration_test\\features\\failure.feature',
|
path: '.\\integration_test\\features\\failure.feature',
|
||||||
description:
|
description:
|
||||||
"Ensure that when a test fails the exception or test failure is reported",
|
"""Ensure that when a test fails the exception or test failure is reported""",
|
||||||
tags: <String>['@debug'],
|
tags: <String>[],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -213,7 +213,7 @@ packages:
|
||||||
path: ".."
|
path: ".."
|
||||||
relative: true
|
relative: true
|
||||||
source: path
|
source: path
|
||||||
version: "3.0.0-rc.16"
|
version: "3.0.0-rc.17"
|
||||||
flutter_simple_dependency_injection:
|
flutter_simple_dependency_injection:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -72,7 +72,7 @@ class WidgetTesterAppDriverAdapter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<int>> screenshotOnAndroid() async {
|
Future<List<int>> takeScreenshotUsingRenderElement() async {
|
||||||
RenderObject? renderObject = binding.renderViewElement?.renderObject;
|
RenderObject? renderObject = binding.renderViewElement?.renderObject;
|
||||||
if (renderObject != null) {
|
if (renderObject != null) {
|
||||||
while (!renderObject!.isRepaintBoundary) {
|
while (!renderObject!.isRepaintBoundary) {
|
||||||
|
@ -99,22 +99,18 @@ class WidgetTesterAppDriverAdapter
|
||||||
Future<List<int>> screenshot({String? screenshotName}) async {
|
Future<List<int>> screenshot({String? screenshotName}) async {
|
||||||
final name =
|
final name =
|
||||||
screenshotName ?? 'screenshot_${DateTime.now().millisecondsSinceEpoch}';
|
screenshotName ?? 'screenshot_${DateTime.now().millisecondsSinceEpoch}';
|
||||||
if (kIsWeb) {
|
if (kIsWeb || Platform.isAndroid) {
|
||||||
return binding.takeScreenshot(name);
|
// try {
|
||||||
} else {
|
// // TODO: See https://github.com/flutter/flutter/issues/92381
|
||||||
if (Platform.isAndroid) {
|
// // we need to call `revertFlutterImage` once it has been implemented
|
||||||
// try {
|
// await binding.convertFlutterSurfaceToImage();
|
||||||
// // TODO: See https://github.com/flutter/flutter/issues/92381
|
// await binding.pump();
|
||||||
// // we need to call `revertFlutterImage` once it has been implemented
|
// // ignore: no_leading_underscores_for_local_identifiers
|
||||||
// await binding.convertFlutterSurfaceToImage();
|
// } catch (_, __) {}
|
||||||
// await binding.pump();
|
|
||||||
// // ignore: no_leading_underscores_for_local_identifiers
|
|
||||||
// } catch (_, __) {}
|
|
||||||
|
|
||||||
return await screenshotOnAndroid();
|
return await takeScreenshotUsingRenderElement();
|
||||||
} else {
|
} else {
|
||||||
return await binding.takeScreenshot(name);
|
return await binding.takeScreenshot(name);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -183,10 +183,18 @@ class FeatureFileTestGeneratorVisitor extends FeatureFileVisitor {
|
||||||
);}
|
);}
|
||||||
''';
|
''';
|
||||||
static const String onBeforeScenarioRun = '''
|
static const String onBeforeScenarioRun = '''
|
||||||
onBefore: () async => onBeforeRunFeature(name:'{{feature_name}}', path:'{{path}}', description: {{feature_description}}, tags:{{feature_tags}},),
|
onBefore: () async => onBeforeRunFeature(
|
||||||
|
name:'{{feature_name}}',
|
||||||
|
path:'{{path}}',
|
||||||
|
description: {{feature_description}},
|
||||||
|
tags:{{feature_tags}},),
|
||||||
''';
|
''';
|
||||||
static const String onAfterScenarioRun = '''
|
static const String onAfterScenarioRun = '''
|
||||||
onAfter: () async => onAfterRunFeature(name:'{{feature_name}}', path:'{{path}}', description: {{feature_description}}, tags:{{feature_tags}},),
|
onAfter: () async => onAfterRunFeature(
|
||||||
|
name:'{{feature_name}}',
|
||||||
|
path:'{{path}}',
|
||||||
|
description: {{feature_description}},
|
||||||
|
tags:{{feature_tags}},),
|
||||||
''';
|
''';
|
||||||
|
|
||||||
final StringBuffer _buffer = StringBuffer();
|
final StringBuffer _buffer = StringBuffer();
|
||||||
|
@ -275,7 +283,9 @@ class FeatureFileTestGeneratorVisitor extends FeatureFileVisitor {
|
||||||
_currentScenarioCode = _replaceVariable(
|
_currentScenarioCode = _replaceVariable(
|
||||||
_currentScenarioCode!,
|
_currentScenarioCode!,
|
||||||
'feature_description',
|
'feature_description',
|
||||||
_escapeText(featureDescription == null ? null : '"$featureDescription"'),
|
_escapeText(
|
||||||
|
featureDescription == null ? null : '"""$featureDescription"""',
|
||||||
|
),
|
||||||
);
|
);
|
||||||
_currentScenarioCode = _replaceVariable(
|
_currentScenarioCode = _replaceVariable(
|
||||||
_currentScenarioCode!,
|
_currentScenarioCode!,
|
||||||
|
@ -370,6 +380,8 @@ class FeatureFileTestGeneratorVisitor extends FeatureFileVisitor {
|
||||||
return content.replaceAll('{{$property}}', value ?? 'null');
|
return content.replaceAll('{{$property}}', value ?? 'null');
|
||||||
}
|
}
|
||||||
|
|
||||||
String? _escapeText(String? text) =>
|
String? _escapeText(String? text) => text
|
||||||
text?.replaceAll("\\", "\\\\").replaceAll("'", "\\'");
|
?.replaceAll("\\", "\\\\")
|
||||||
|
.replaceAll("'", "\\'")
|
||||||
|
.replaceAll(r"$", r"\$");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// ignore_for_file: avoid_print
|
||||||
|
|
||||||
import 'package:flutter_gherkin/flutter_gherkin_with_driver.dart';
|
import 'package:flutter_gherkin/flutter_gherkin_with_driver.dart';
|
||||||
import 'package:flutter_gherkin/src/flutter/parameters/existence_parameter.dart';
|
import 'package:flutter_gherkin/src/flutter/parameters/existence_parameter.dart';
|
||||||
import 'package:flutter_gherkin/src/flutter/parameters/swipe_direction_parameter.dart';
|
import 'package:flutter_gherkin/src/flutter/parameters/swipe_direction_parameter.dart';
|
||||||
|
|
|
@ -83,24 +83,24 @@ abstract class GherkinIntegrationTestRunner {
|
||||||
_binding.framePolicy = framePolicy ?? _binding.framePolicy;
|
_binding.framePolicy = framePolicy ?? _binding.framePolicy;
|
||||||
|
|
||||||
tearDownAll(
|
tearDownAll(
|
||||||
() {
|
() async {
|
||||||
onRunComplete();
|
await onRunComplete();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
_safeInvokeFuture(() async => await hook.onBeforeRun(configuration));
|
await hook.onBeforeRun(configuration);
|
||||||
_safeInvokeFuture(() async => await reporter.test.onStarted.invoke());
|
await reporter.test.onStarted.invoke();
|
||||||
|
|
||||||
onRun();
|
onRun();
|
||||||
}
|
}
|
||||||
|
|
||||||
void onRun();
|
void onRun();
|
||||||
|
|
||||||
void onRunComplete() {
|
Future<void> onRunComplete() async {
|
||||||
_safeInvokeFuture(() async => await reporter.test.onFinished.invoke());
|
await reporter.test.onFinished.invoke();
|
||||||
_safeInvokeFuture(() async => await hook.onAfterRun(configuration));
|
await hook.onAfterRun(configuration);
|
||||||
setTestResultData(_binding);
|
setTestResultData(_binding);
|
||||||
_safeInvokeFuture(() async => await reporter.dispose());
|
() async => await reporter.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setTestResultData(IntegrationTestWidgetsFlutterBinding binding) {
|
void setTestResultData(IntegrationTestWidgetsFlutterBinding binding) {
|
||||||
|
@ -226,9 +226,11 @@ abstract class GherkinIntegrationTestRunner {
|
||||||
failed = true;
|
failed = true;
|
||||||
hasToSkip = true;
|
hasToSkip = true;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (err, st) {
|
||||||
failed = true;
|
failed = true;
|
||||||
hasToSkip = true;
|
hasToSkip = true;
|
||||||
|
|
||||||
|
await reporter.onException(err, st);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -258,18 +260,16 @@ abstract class GherkinIntegrationTestRunner {
|
||||||
tester,
|
tester,
|
||||||
);
|
);
|
||||||
|
|
||||||
cleanUpScenarioRun(dependencies);
|
await cleanUpScenarioRun(dependencies);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
timeout: scenarioExecutionTimeout,
|
timeout: scenarioExecutionTimeout,
|
||||||
semanticsEnabled: configuration.semanticsEnabled,
|
semanticsEnabled: configuration.semanticsEnabled,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
_safeInvokeFuture(
|
reporter.message(
|
||||||
() async => reporter.message(
|
'Ignoring scenario `$name` as tag expression `${configuration.tagExpression}` not satisfied',
|
||||||
'Ignoring scenario `$name` as tag expression `${configuration.tagExpression}` not satisfied',
|
MessageLevel.info,
|
||||||
MessageLevel.info,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -325,52 +325,62 @@ abstract class GherkinIntegrationTestRunner {
|
||||||
required TestDependencies dependencies,
|
required TestDependencies dependencies,
|
||||||
required bool skip,
|
required bool skip,
|
||||||
}) async {
|
}) async {
|
||||||
final executable = _executableSteps!.firstWhereOrNull(
|
|
||||||
(s) => s.expression.isMatch(name),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (executable == null) {
|
|
||||||
final message = 'Step definition not found for text: `$name`';
|
|
||||||
throw GherkinStepNotDefinedException(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
var parameters = _getStepParameters(
|
|
||||||
step: name,
|
|
||||||
multiLineStrings: multiLineStrings,
|
|
||||||
table: table,
|
|
||||||
code: executable,
|
|
||||||
);
|
|
||||||
|
|
||||||
await _onBeforeStepRun(
|
|
||||||
world: dependencies.world,
|
|
||||||
step: name,
|
|
||||||
table: table,
|
|
||||||
multiLineStrings: multiLineStrings,
|
|
||||||
);
|
|
||||||
|
|
||||||
StepResult? result;
|
StepResult? result;
|
||||||
|
|
||||||
if (skip) {
|
try {
|
||||||
result = StepResult(
|
final executable = _executableSteps!.firstWhereOrNull(
|
||||||
0,
|
(s) => s.expression.isMatch(name),
|
||||||
StepExecutionResult.skipped,
|
|
||||||
resultReason: 'Previous step(s) failed',
|
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
for (int i = 0; i < configuration.stepMaxRetries + 1; i++) {
|
if (executable == null) {
|
||||||
result = await executable.step.run(
|
final message = 'Step definition not found for text: `$name`';
|
||||||
dependencies.world,
|
throw GherkinStepNotDefinedException(message);
|
||||||
reporter,
|
}
|
||||||
configuration.defaultTimeout,
|
|
||||||
parameters,
|
var parameters = _getStepParameters(
|
||||||
|
step: name,
|
||||||
|
multiLineStrings: multiLineStrings,
|
||||||
|
table: table,
|
||||||
|
code: executable,
|
||||||
|
);
|
||||||
|
|
||||||
|
await _onBeforeStepRun(
|
||||||
|
world: dependencies.world,
|
||||||
|
step: name,
|
||||||
|
table: table,
|
||||||
|
multiLineStrings: multiLineStrings,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (skip) {
|
||||||
|
result = StepResult(
|
||||||
|
0,
|
||||||
|
StepExecutionResult.skipped,
|
||||||
|
resultReason: 'Previous step(s) failed',
|
||||||
);
|
);
|
||||||
if (!_isNegativeResult(result.result) ||
|
} else {
|
||||||
configuration.stepMaxRetries == 0) {
|
for (int i = 0; i < configuration.stepMaxRetries + 1; i++) {
|
||||||
break;
|
result = await executable.step.run(
|
||||||
} else {
|
dependencies.world,
|
||||||
await Future.delayed(configuration.retryDelay);
|
reporter,
|
||||||
|
configuration.defaultTimeout,
|
||||||
|
parameters,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!_isNegativeResult(result.result) ||
|
||||||
|
configuration.stepMaxRetries == 0) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
await Future.delayed(configuration.retryDelay);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (err, st) {
|
||||||
|
result = ErroredStepResult(
|
||||||
|
0,
|
||||||
|
StepExecutionResult.error,
|
||||||
|
err,
|
||||||
|
st,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await _onAfterStepRun(
|
await _onAfterStepRun(
|
||||||
|
@ -383,13 +393,9 @@ abstract class GherkinIntegrationTestRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void cleanUpScenarioRun(TestDependencies dependencies) {
|
Future<void> cleanUpScenarioRun(TestDependencies dependencies) async {
|
||||||
_safeInvokeFuture(
|
dependencies.attachmentManager.dispose();
|
||||||
() async => dependencies.attachmentManager.dispose(),
|
dependencies.world.dispose();
|
||||||
);
|
|
||||||
_safeInvokeFuture(
|
|
||||||
() async => dependencies.world.dispose(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _registerReporters(Iterable<Reporter>? reporters) {
|
void _registerReporters(Iterable<Reporter>? reporters) {
|
||||||
|
@ -505,12 +511,6 @@ abstract class GherkinIntegrationTestRunner {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _safeInvokeFuture(Future<void> Function() fn) async {
|
|
||||||
try {
|
|
||||||
await fn().catchError((_, __) {});
|
|
||||||
} catch (_) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _evaluateTagFilterExpression(
|
bool _evaluateTagFilterExpression(
|
||||||
String? tagExpression,
|
String? tagExpression,
|
||||||
Iterable<String>? tags,
|
Iterable<String>? tags,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
name: flutter_gherkin
|
name: flutter_gherkin
|
||||||
description: A Gherkin / Cucumber parser and test runner for Dart and Flutter
|
description: A Gherkin / Cucumber parser and test runner for Dart and Flutter
|
||||||
version: 3.0.0-rc.16
|
version: 3.0.0-rc.17
|
||||||
homepage: https://github.com/jonsamwell/flutter_gherkin
|
homepage: https://github.com/jonsamwell/flutter_gherkin
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
|
|
Loading…
Reference in New Issue