execute method

Future<TestReport> execute(
  1. {String? name,
  2. TestReport? report,
  3. bool reset = true,
  4. Duration? stepTimeout,
  5. required List<TestStep> steps,
  6. bool submitReport = true,
  7. String? suiteName,
  8. TestSuiteReport? testSuiteReport,
  9. Duration? testTimeout,
  10. required int version}
)

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();
  }

  final settings = TestAppSettings.settings;

  stepTimeout ??= settings.stepTimeout;
  testTimeout ??= settings.testTimeout;

  final cancelToken = CancelToken(timeout: testTimeout);
  final 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(const Duration(milliseconds: 100));

    report ??= TestReport(
      name: name,
      suiteName: suiteName,
      version: version,
    );
    final 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++;
        final 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);
        final futures = <Future>[];
        futures.add(
          _navigatorKey?.currentState?.push(
                MaterialPageRoute(
                  builder: _testReportBuilder ??
                      ((BuildContext context) => TestReportPage()),
                  settings: RouteSettings(
                    name: '/atf/test-report',
                    arguments: report,
                  ),
                ),
              ) ??
              Future.delayed(
                const Duration(seconds: 1),
              ),
        );
        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();
  }
}