runner.dart 7.32 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4 5 6 7
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import '../artifacts.dart';
import '../base/file_system.dart';
import '../base/io.dart';
8
import '../device.dart';
9
import '../globals.dart' as globals;
10
import '../project.dart';
11
import '../web/chrome.dart';
12
import '../web/memory_fs.dart';
13
import 'flutter_platform.dart' as loader;
14
import 'flutter_web_platform.dart';
15
import 'test_time_recorder.dart';
16
import 'test_wrapper.dart';
17
import 'watcher.dart';
18
import 'web_test_compiler.dart';
19

20 21 22
/// A class that abstracts launching the test process from the test runner.
abstract class FlutterTestRunner {
  const factory FlutterTestRunner() = _FlutterTestRunnerImpl;
23

24 25 26
  /// Runs tests using package:test and the Flutter engine.
  Future<int> runTests(
    TestWrapper testWrapper,
27
    List<Uri> testFiles, {
28
    required DebuggingOptions debuggingOptions,
29 30
    List<String> names = const <String>[],
    List<String> plainNames = const <String>[],
31 32
    String? tags,
    String? excludeTags,
33
    bool enableVmService = false,
34 35
    bool ipv6 = false,
    bool machine = false,
36 37
    String? precompiledDillPath,
    Map<String, String>? precompiledDillFiles,
38
    bool updateGoldens = false,
39 40 41 42 43 44
    TestWatcher? watcher,
    required int? concurrency,
    String? testAssetDirectory,
    FlutterProject? flutterProject,
    String? icudtlPath,
    Directory? coverageDirectory,
45
    bool web = false,
46 47
    String? randomSeed,
    String? reporter,
48
    String? fileReporter,
49
    String? timeout,
50
    bool runSkipped = false,
51 52 53 54
    int? shardIndex,
    int? totalShards,
    Device? integrationTestDevice,
    String? integrationTestUserIdentifier,
55
    TestTimeRecorder? testTimeRecorder,
56 57 58 59 60 61 62 63 64
  });
}

class _FlutterTestRunnerImpl implements FlutterTestRunner {
  const _FlutterTestRunnerImpl();

  @override
  Future<int> runTests(
    TestWrapper testWrapper,
65
    List<Uri> testFiles, {
66
    required DebuggingOptions debuggingOptions,
67 68
    List<String> names = const <String>[],
    List<String> plainNames = const <String>[],
69 70
    String? tags,
    String? excludeTags,
71
    bool enableVmService = false,
72 73
    bool ipv6 = false,
    bool machine = false,
74 75
    String? precompiledDillPath,
    Map<String, String>? precompiledDillFiles,
76
    bool updateGoldens = false,
77 78 79 80 81 82
    TestWatcher? watcher,
    required int? concurrency,
    String? testAssetDirectory,
    FlutterProject? flutterProject,
    String? icudtlPath,
    Directory? coverageDirectory,
83
    bool web = false,
84 85
    String? randomSeed,
    String? reporter,
86
    String? fileReporter,
87
    String? timeout,
88
    bool runSkipped = false,
89 90 91 92
    int? shardIndex,
    int? totalShards,
    Device? integrationTestDevice,
    String? integrationTestUserIdentifier,
93
    TestTimeRecorder? testTimeRecorder,
94 95
  }) async {
    // Configure package:test to use the Flutter engine for child processes.
96
    final String shellPath = globals.artifacts!.getArtifactPath(Artifact.flutterTester);
97 98 99 100 101

    // Compute the command-line arguments for package:test.
    final List<String> testArgs = <String>[
      if (!globals.terminal.supportsColor)
        '--no-color',
102
      if (debuggingOptions.startPaused)
103 104 105
        '--pause-after-load',
      if (machine)
        ...<String>['-r', 'json']
106 107
      else if (reporter != null)
        ...<String>['-r', reporter],
108 109
      if (fileReporter != null)
        '--file-reporter=$fileReporter',
110 111
      if (timeout != null)
        ...<String>['--timeout', timeout],
112 113
      if (concurrency != null)
        '--concurrency=$concurrency',
114 115 116 117
      for (final String name in names)
        ...<String>['--name', name],
      for (final String plainName in plainNames)
        ...<String>['--plain-name', plainName],
118 119
      if (randomSeed != null)
        '--test-randomize-ordering-seed=$randomSeed',
120 121 122 123
      if (tags != null)
        ...<String>['--tags', tags],
      if (excludeTags != null)
        ...<String>['--exclude-tags', excludeTags],
124 125
      if (runSkipped)
        '--run-skipped',
126 127 128 129
      if (totalShards != null)
        '--total-shards=$totalShards',
      if (shardIndex != null)
        '--shard-index=$shardIndex',
130
      '--chain-stack-traces',
131
    ];
132

133 134 135 136 137 138
    if (web) {
      final String tempBuildDir = globals.fs.systemTempDirectory
        .createTempSync('flutter_test.')
        .absolute
        .uri
        .toFilePath();
139 140 141 142
      final WebMemoryFS result = await WebTestCompiler(
        logger: globals.logger,
        fileSystem: globals.fs,
        platform: globals.platform,
143
        artifacts: globals.artifacts!,
144 145 146
        processManager: globals.processManager,
        config: globals.config,
      ).initialize(
147
        projectDirectory: flutterProject!.directory,
148
        testOutputDir: tempBuildDir,
149
        testFiles: testFiles.map((Uri uri) => uri.toFilePath()).toList(),
150
        buildInfo: debuggingOptions.buildInfo,
151 152 153 154
      );
      testArgs
        ..add('--platform=chrome')
        ..add('--')
155
        ..addAll(testFiles.map((Uri uri) => uri.toString()));
156 157 158 159 160 161 162 163
      testWrapper.registerPlatformPlugin(
        <Runtime>[Runtime.chrome],
        () {
          return FlutterWebPlatform.start(
            flutterProject.directory.path,
            updateGoldens: updateGoldens,
            shellPath: shellPath,
            flutterProject: flutterProject,
164
            pauseAfterLoad: debuggingOptions.startPaused,
165
            nullAssertions: debuggingOptions.nullAssertions,
166
            buildInfo: debuggingOptions.buildInfo,
167
            webMemoryFS: result,
168 169 170
            logger: globals.logger,
            fileSystem: globals.fs,
            artifacts: globals.artifacts,
171
            processManager: globals.processManager,
172 173 174 175 176 177 178 179
            chromiumLauncher: ChromiumLauncher(
              fileSystem: globals.fs,
              platform: globals.platform,
              processManager: globals.processManager,
              operatingSystemUtils: globals.os,
              browserFinder: findChromeExecutable,
              logger: globals.logger,
            ),
180
            testTimeRecorder: testTimeRecorder,
181 182 183 184 185
          );
        },
      );
      await testWrapper.main(testArgs);
      return exitCode;
186
    }
187

188 189
    testArgs
      ..add('--')
190
      ..addAll(testFiles.map((Uri uri) => uri.toString()));
191 192 193 194 195 196 197

    final InternetAddressType serverType =
        ipv6 ? InternetAddressType.IPv6 : InternetAddressType.IPv4;

    final loader.FlutterPlatform platform = loader.installHook(
      testWrapper: testWrapper,
      shellPath: shellPath,
198
      debuggingOptions: debuggingOptions,
199
      watcher: watcher,
200
      enableVmService: enableVmService,
201 202 203 204 205
      machine: machine,
      serverType: serverType,
      precompiledDillPath: precompiledDillPath,
      precompiledDillFiles: precompiledDillFiles,
      updateGoldens: updateGoldens,
206
      testAssetDirectory: testAssetDirectory,
207 208 209
      projectRootDirectory: globals.fs.currentDirectory.uri,
      flutterProject: flutterProject,
      icudtlPath: icudtlPath,
210 211
      integrationTestDevice: integrationTestDevice,
      integrationTestUserIdentifier: integrationTestUserIdentifier,
212
      testTimeRecorder: testTimeRecorder,
213
    );
214

215 216 217
    try {
      globals.printTrace('running test package with arguments: $testArgs');
      await testWrapper.main(testArgs);
218

219 220
      // test.main() sets dart:io's exitCode global.
      globals.printTrace('test package returned with exit code $exitCode');
221

222 223 224 225
      return exitCode;
    } finally {
      await platform.close();
    }
226 227
  }
}