execute method
Executes a series of tests steps. This accepts the name
of the test
which may be null
or empty. The reset
defines if the controller
should ask the application to perform a full reset before running or if it
should attempt to run for the current state.
The list of steps
may not be null
or empty and define the steps that
the controller should execute.
The submitReport
value determines if the testReporter
should be
executed after all steps have been completed or not. Generally this value
will be true
when running full tests and false
when running debugging
level tests.
The version
defines the overall test version. This may be null
or
empty and should always be a value of 0 or higher when set.
Implementation
Future<TestReport> execute({
String? name,
TestReport? report,
bool reset = true,
Duration? stepTimeout,
required List<TestStep> steps,
bool submitReport = true,
String? suiteName,
TestSuiteReport? testSuiteReport,
Duration? testTimeout,
required int version,
}) async {
if (_testControllerState.runningTest == true) {
await cancelRunningTests();
}
var settings = TestAppSettings.settings;
stepTimeout ??= settings.stepTimeout;
testTimeout ??= settings.testTimeout;
var cancelToken = CancelToken(timeout: testTimeout);
var cancelSubscription = _cancelController.stream.listen(
(_) => cancelToken.cancel(),
);
_testControllerState.currentTest = name;
_testControllerState.progress = 0.0;
_testControllerState.runningTest = true;
try {
_testControllerState.passing = true;
step = ProgressValue(max: steps.length, value: 0);
if (reset == true) {
await this.reset();
}
status = '<set up>';
await Future.delayed(Duration(milliseconds: 100));
report ??= TestReport(
name: name,
suiteName: suiteName,
version: version,
);
var logSubscription = Logger.root.onRecord.listen((record) {
if (_testReportLogLevel <= record.level) {
report!.appendLog(
'${record.level.name}: ${record.time}: ${record.message}',
);
if (record.error != null) {
report.appendLog('${record.error}');
}
if (record.stackTrace != null) {
report.appendLog('${record.stackTrace}');
}
}
});
try {
setGlobalVariable(
value: _testControllerState.passing,
variableName: '_passing',
);
var idx = 0;
for (var step in steps) {
if (cancelToken.cancelled == true) {
break;
}
Timer? timeoutTimer;
if (stepTimeout != null) {
timeoutTimer = Timer(stepTimeout, () => cancelToken.cancel());
}
try {
_testControllerState.passing = await executeStep(
cancelToken: cancelToken,
report: report,
step: step,
subStep: false,
) &&
_testControllerState.passing;
} finally {
timeoutTimer?.cancel();
}
idx++;
var progress = ProgressValue(max: steps.length, value: idx);
this.step = progress;
_testControllerState.progress = progress.progress;
if (stopOnFirstFail == true && _testControllerState.passing != true) {
break;
}
}
} catch (e, stack) {
report.exception('Exception in test', e, stack);
_logger.severe('EXCEPTION IN TEST: ', e, stack);
} finally {
await logSubscription.cancel();
await _sleep(delays.testTearDown);
step = null;
report.complete();
_testControllerState.runningTest = false;
if (cancelToken.cancelled == false &&
(reset == true || submitReport == true)) {
_testControllerState.runningTest = false;
testSuiteReport?.addTestReport(report);
var futures = <Future>[];
futures.add(
_navigatorKey.currentState!.push(
MaterialPageRoute(
builder: _testReportBuilder ??
((BuildContext context) => TestReportPage()),
settings: RouteSettings(
name: '/atf/test-report',
arguments: report,
),
),
),
);
if (submitReport == true) {
futures.add(this.submitReport(report));
await _sleep(delays.postSubmitReport);
await this.reset();
}
await Future.wait(futures);
}
}
return report;
} finally {
await cancelSubscription.cancel();
await cancelToken.complete();
}
}