Enable web foundation tests (#34032)
diff --git a/.cirrus.yml b/.cirrus.yml index 3e42c4c..d9e9332 100644 --- a/.cirrus.yml +++ b/.cirrus.yml
@@ -79,6 +79,11 @@ - 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 cca6791..e892be6 100644 --- a/dev/bots/test.dart +++ b/dev/bots/test.dart
@@ -341,15 +341,8 @@ } Future<void> _runWebTests() async { - final List<String> testfiles = <String>[]; - 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: <String>[ - path.join('test', 'foundation'), + await _runFlutterWebTest(path.join(flutterRoot, 'packages', 'flutter'), expectFailure: false, tests: <String>[ + 'test/foundation/', ]); } @@ -612,23 +605,30 @@ Duration timeout = _kLongTimeout, List<String> tests, }) async { - final List<String> args = <String>['test', '--platform=chrome']; + final List<String> args = <String>['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: <String, String>{ - '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: <String, String>{ + 'FLUTTER_WEB': 'true', + 'FLUTTER_LOW_RESOURCE_MODE': 'true', + }, + ); + } finally { + Directory.current = oldCurrent; + } } Future<void> _runFlutterTest(String workingDirectory, {
diff --git a/packages/flutter/test/flutter_test_alternative.dart b/packages/flutter/test/flutter_test_alternative.dart index 9d0c457..12711c1 100644 --- a/packages/flutter/test/flutter_test_alternative.dart +++ b/packages/flutter/test/flutter_test_alternative.dart
@@ -12,3 +12,6 @@ /// A matcher that compares the type of the actual value to the type argument T. Matcher isInstanceOf<T>() => test_package.TypeMatcher<T>(); + +/// 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 4db1b82..c2d5ddc 100644 --- a/packages/flutter/test/foundation/assertions_test.dart +++ b/packages/flutter/test/foundation/assertions_test.dart
@@ -14,7 +14,7 @@ }); expect(log[0], contains('Example label')); expect(log[1], contains('debugPrintStack')); - }); + }, skip: isBrowser); test('debugPrintStack', () { final List<String> log = captureOutput(() { @@ -39,7 +39,7 @@ 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 3c09faa..020ecdc 100644 --- a/packages/flutter/test/foundation/change_notifier_test.dart +++ b/packages/flutter/test/foundation/change_notifier_test.dart
@@ -102,7 +102,7 @@ expect(log, <String>['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 27278f2..ec25445 100644 --- a/packages/flutter/test/foundation/diagnostics_test.dart +++ b/packages/flutter/test/foundation/diagnostics_test.dart
@@ -1187,7 +1187,7 @@ 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 1808b6c..06183bf 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 d829dea..9adc08e 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 @@ defaultGenerateFor: const InputSet( include: <String>[ 'lib/**', - 'web/**', + ], + ), + ), + core.apply( + 'flutter_tools|test_entrypoint', + <BuilderFactory>[ + (BuilderOptions options) => FlutterWebTestEntrypointBuilder( + options.config['targets'] ?? const <String>[] + ), + ], + core.toRoot(), + hideOutput: true, + defaultGenerateFor: const InputSet( + include: <String>[ 'test/**_test.dart.browser_test.dart', ], ), @@ -213,6 +226,7 @@ skipBuildScriptCheck: true, trackPerformance: false, deleteFilesByDefault: true, + enableLowResourcesMode: platform.environment['FLUTTER_LOW_RESOURCE_MODE']?.toLowerCase() == 'true', ); final Set<core.BuildDirectory> buildDirs = <core.BuildDirectory>{ if (testOutputDir != null) @@ -290,6 +304,10 @@ 'targets': targets, 'release': release, }, + 'flutter_tools|test_entrypoint': <String, dynamic>{ + 'targets': targets, + 'release': release, + }, 'flutter_tools|shell': <String, dynamic>{ 'targets': targets, } @@ -348,6 +366,40 @@ } /// A ddc-only entrypoint builder that respects the Flutter target flag. +class FlutterWebTestEntrypointBuilder implements Builder { + const FlutterWebTestEntrypointBuilder(this.targets); + + final List<String> targets; + + @override + Map<String, List<String>> get buildExtensions => const <String, List<String>>{ + '.dart': <String>[ + ddcBootstrapExtension, + jsEntrypointExtension, + jsEntrypointSourceMapExtension, + jsEntrypointArchiveExtension, + digestsEntrypointExtension, + ], + }; + + @override + Future<void> 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 d30266d..cce7e75 100644 --- a/packages/flutter_tools/lib/src/commands/test.dart +++ b/packages/flutter_tools/lib/src/commands/test.dart
@@ -110,6 +110,7 @@ @override Future<Set<DevelopmentArtifact>> get requiredArtifacts async => <DevelopmentArtifact>{ 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 796a03d..f9df159 100644 --- a/packages/flutter_tools/lib/src/test/runner.dart +++ b/packages/flutter_tools/lib/src/test/runner.dart
@@ -73,13 +73,16 @@ .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 3d91107..77961a2 100644 --- a/packages/flutter_tools/lib/src/web/chrome.dart +++ b/packages/flutter_tools/lib/src/web/chrome.dart
@@ -98,16 +98,19 @@ '--disable-default-apps', '--disable-translate', if (headless) - ...<String>['--headless', '--disable-gpu'], + ...<String>['--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;