From 7f7c00a4e91bc9dcc25ee36bc0942affce84fda9 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Sun, 9 Jun 2019 11:03:46 -0700 Subject: [PATCH] Enable web foundation tests (#34032) --- .cirrus.yml | 5 ++ dev/bots/test.dart | 42 +++++++-------- .../test/flutter_test_alternative.dart | 3 ++ .../test/foundation/assertions_test.dart | 4 +- .../test/foundation/change_notifier_test.dart | 2 +- .../test/foundation/diagnostics_test.dart | 2 +- .../test/foundation/reassemble_test.dart | 1 + .../web_compilation_delegate.dart | 54 ++++++++++++++++++- .../flutter_tools/lib/src/commands/test.dart | 1 + .../flutter_tools/lib/src/test/runner.dart | 5 +- .../flutter_tools/lib/src/web/chrome.dart | 9 ++-- 11 files changed, 98 insertions(+), 30 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 3e42c4c17f..d9e93323fc 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -79,6 +79,11 @@ task: - name: web_tests-linux env: SHARD: web_tests + test_script: + - dart --enable-asserts ./dev/bots/test.dart + container: + cpu: 4 + memory: 12G - name: build_tests-linux env: SHARD: build_tests diff --git a/dev/bots/test.dart b/dev/bots/test.dart index cca6791157..e892be6f27 100644 --- a/dev/bots/test.dart +++ b/dev/bots/test.dart @@ -341,15 +341,8 @@ Future _runTests() async { } Future _runWebTests() async { - final List testfiles = []; - final Directory foundation = Directory(path.join(flutterRoot, 'packages', 'flutter', 'test', 'foundation')); - for (FileSystemEntity entity in foundation.listSync(recursive: true)) { - if (entity is File) { - testfiles.add(entity.path); - } - } - await _runFlutterWebTest(path.join(flutterRoot, 'packages', 'flutter'), expectFailure: true, tests: [ - path.join('test', 'foundation'), + await _runFlutterWebTest(path.join(flutterRoot, 'packages', 'flutter'), expectFailure: false, tests: [ + 'test/foundation/', ]); } @@ -612,23 +605,30 @@ Future _runFlutterWebTest(String workingDirectory, { Duration timeout = _kLongTimeout, List tests, }) async { - final List args = ['test', '--platform=chrome']; + final List args = ['test', '-v', '--platform=chrome']; if (flutterTestArgs != null && flutterTestArgs.isNotEmpty) args.addAll(flutterTestArgs); - args.add('--machine'); args.addAll(tests); - await runCommand( - flutter, - args, - workingDirectory: workingDirectory, - expectNonZeroExit: expectFailure, - timeout: timeout, - environment: { - 'FLUTTER_WEB': 'true', - }, - ); + // TODO(jonahwilliams): fix relative path issues to make this unecessary. + final Directory oldCurrent = Directory.current; + Directory.current = Directory(path.join(flutterRoot, 'packages', 'flutter')); + try { + await runCommand( + flutter, + args, + workingDirectory: workingDirectory, + expectNonZeroExit: expectFailure, + timeout: timeout, + environment: { + 'FLUTTER_WEB': 'true', + 'FLUTTER_LOW_RESOURCE_MODE': 'true', + }, + ); + } finally { + Directory.current = oldCurrent; + } } Future _runFlutterTest(String workingDirectory, { diff --git a/packages/flutter/test/flutter_test_alternative.dart b/packages/flutter/test/flutter_test_alternative.dart index 9d0c457b63..12711c11c6 100644 --- a/packages/flutter/test/flutter_test_alternative.dart +++ b/packages/flutter/test/flutter_test_alternative.dart @@ -12,3 +12,6 @@ export 'package:test_api/test_api.dart' hide TypeMatcher, isInstanceOf; /// A matcher that compares the type of the actual value to the type argument T. Matcher isInstanceOf() => test_package.TypeMatcher(); + +/// Whether we are running in a web browser. +const bool isBrowser = identical(0, 0.0); diff --git a/packages/flutter/test/foundation/assertions_test.dart b/packages/flutter/test/foundation/assertions_test.dart index 4db1b82706..c2d5ddc728 100644 --- a/packages/flutter/test/foundation/assertions_test.dart +++ b/packages/flutter/test/foundation/assertions_test.dart @@ -14,7 +14,7 @@ void main() { }); expect(log[0], contains('Example label')); expect(log[1], contains('debugPrintStack')); - }); + }, skip: isBrowser); test('debugPrintStack', () { final List log = captureOutput(() { @@ -39,7 +39,7 @@ void main() { expect(joined, contains('captureOutput')); expect(joined, contains('\nExample information\n')); - }); + }, skip: isBrowser); test('FlutterErrorDetails.toString', () { expect( diff --git a/packages/flutter/test/foundation/change_notifier_test.dart b/packages/flutter/test/foundation/change_notifier_test.dart index 3c09faaa3c..020ecdc89c 100644 --- a/packages/flutter/test/foundation/change_notifier_test.dart +++ b/packages/flutter/test/foundation/change_notifier_test.dart @@ -102,7 +102,7 @@ void main() { expect(log, ['badListener', 'listener1', 'listener2']); expect(tester.takeException(), isNullThrownError); log.clear(); - }); + }, skip: isBrowser); test('ChangeNotifier with mutating listener', () { final TestNotifier test = TestNotifier(); diff --git a/packages/flutter/test/foundation/diagnostics_test.dart b/packages/flutter/test/foundation/diagnostics_test.dart index 27278f2cfe..ec25445d52 100644 --- a/packages/flutter/test/foundation/diagnostics_test.dart +++ b/packages/flutter/test/foundation/diagnostics_test.dart @@ -1187,7 +1187,7 @@ void main() { expect(missing.isFiltered(DiagnosticLevel.info), isFalse); validateObjectFlagPropertyJsonSerialization(present); validateObjectFlagPropertyJsonSerialization(missing); - }); + }, skip: isBrowser); test('describe bool property', () { final FlagProperty yes = FlagProperty( diff --git a/packages/flutter/test/foundation/reassemble_test.dart b/packages/flutter/test/foundation/reassemble_test.dart index 1808b6cb4d..06183bf42d 100644 --- a/packages/flutter/test/foundation/reassemble_test.dart +++ b/packages/flutter/test/foundation/reassemble_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +@TestOn('!chrome') import 'dart:async'; import 'package:flutter/foundation.dart'; diff --git a/packages/flutter_tools/lib/src/build_runner/web_compilation_delegate.dart b/packages/flutter_tools/lib/src/build_runner/web_compilation_delegate.dart index d829deae78..9adc08e611 100644 --- a/packages/flutter_tools/lib/src/build_runner/web_compilation_delegate.dart +++ b/packages/flutter_tools/lib/src/build_runner/web_compilation_delegate.dart @@ -161,7 +161,20 @@ final List builders = [ defaultGenerateFor: const InputSet( include: [ 'lib/**', - 'web/**', + ], + ), + ), + core.apply( + 'flutter_tools|test_entrypoint', + [ + (BuilderOptions options) => FlutterWebTestEntrypointBuilder( + options.config['targets'] ?? const [] + ), + ], + core.toRoot(), + hideOutput: true, + defaultGenerateFor: const InputSet( + include: [ 'test/**_test.dart.browser_test.dart', ], ), @@ -213,6 +226,7 @@ class BuildRunnerWebCompilationProxy extends WebCompilationProxy { skipBuildScriptCheck: true, trackPerformance: false, deleteFilesByDefault: true, + enableLowResourcesMode: platform.environment['FLUTTER_LOW_RESOURCE_MODE']?.toLowerCase() == 'true', ); final Set buildDirs = { if (testOutputDir != null) @@ -290,6 +304,10 @@ class BuildRunnerWebCompilationProxy extends WebCompilationProxy { 'targets': targets, 'release': release, }, + 'flutter_tools|test_entrypoint': { + 'targets': targets, + 'release': release, + }, 'flutter_tools|shell': { 'targets': targets, } @@ -347,6 +365,40 @@ class BuildRunnerWebCompilationProxy extends WebCompilationProxy { } } +/// A ddc-only entrypoint builder that respects the Flutter target flag. +class FlutterWebTestEntrypointBuilder implements Builder { + const FlutterWebTestEntrypointBuilder(this.targets); + + final List targets; + + @override + Map> get buildExtensions => const >{ + '.dart': [ + ddcBootstrapExtension, + jsEntrypointExtension, + jsEntrypointSourceMapExtension, + jsEntrypointArchiveExtension, + digestsEntrypointExtension, + ], + }; + + @override + Future build(BuildStep buildStep) async { + bool matches = false; + for (String target in targets) { + if (buildStep.inputId.path.contains(target)) { + matches = true; + break; + } + } + if (!matches) { + return; + } + log.info('building for target ${buildStep.inputId.path}'); + await bootstrapDdc(buildStep, platform: flutterWebPlatform); + } +} + /// A ddc-only entrypoint builder that respects the Flutter target flag. class FlutterWebEntrypointBuilder implements Builder { const FlutterWebEntrypointBuilder(this.targets, this.release); diff --git a/packages/flutter_tools/lib/src/commands/test.dart b/packages/flutter_tools/lib/src/commands/test.dart index d30266d6a0..cce7e757e0 100644 --- a/packages/flutter_tools/lib/src/commands/test.dart +++ b/packages/flutter_tools/lib/src/commands/test.dart @@ -110,6 +110,7 @@ class TestCommand extends FastFlutterCommand { @override Future> get requiredArtifacts async => { DevelopmentArtifact.universal, + DevelopmentArtifact.web, }; @override diff --git a/packages/flutter_tools/lib/src/test/runner.dart b/packages/flutter_tools/lib/src/test/runner.dart index 796a03d94a..f9df1599e0 100644 --- a/packages/flutter_tools/lib/src/test/runner.dart +++ b/packages/flutter_tools/lib/src/test/runner.dart @@ -73,13 +73,16 @@ Future runTests( .absolute .uri .toFilePath(); - await webCompilationProxy.initialize( + final bool result = await webCompilationProxy.initialize( projectDirectory: flutterProject.directory, testOutputDir: tempBuildDir, targets: testFiles.map((String testFile) { return fs.path.relative(testFile, from: flutterProject.directory.path); }).toList(), ); + if (!result) { + throwToolExit('Failed to compile tests'); + } testArgs.add('--platform=chrome'); testArgs.add('--precompiled=$tempBuildDir'); testArgs.add('--'); diff --git a/packages/flutter_tools/lib/src/web/chrome.dart b/packages/flutter_tools/lib/src/web/chrome.dart index 3d911076c0..77961a27dd 100644 --- a/packages/flutter_tools/lib/src/web/chrome.dart +++ b/packages/flutter_tools/lib/src/web/chrome.dart @@ -98,16 +98,19 @@ class ChromeLauncher { '--disable-default-apps', '--disable-translate', if (headless) - ...['--headless', '--disable-gpu'], + ...['--headless', '--disable-gpu', '--no-sandbox'], url, ]; - final Process process = await processManager.start(args); + + final Process process = await processManager.start(args, runInShell: true); // Wait until the DevTools are listening before trying to connect. await process.stderr .transform(utf8.decoder) .transform(const LineSplitter()) - .firstWhere((String line) => line.startsWith('DevTools listening')) + .firstWhere((String line) => line.startsWith('DevTools listening'), orElse: () { + return 'Failed to spawn stderr'; + }) .timeout(const Duration(seconds: 60), onTimeout: () { throwToolExit('Unable to connect to Chrome DevTools.'); return null;