From c709cde0c1c7f311cbd7c31370b94165156e3f17 Mon Sep 17 00:00:00 2001 From: Jacob MacDonald Date: Wed, 10 Jan 2024 11:31:38 -0800 Subject: [PATCH] fix a bug where test html files were not created in precompiled mode (#2170) * fix a bug where test html files were not created in precompiled mode * support wasm and js precompiled tests --- pkgs/test/CHANGELOG.md | 5 +- .../browser/compilers/compiler_support.dart | 70 ++++++++++++++++++- .../src/runner/browser/compilers/dart2js.dart | 35 +--------- .../runner/browser/compilers/dart2wasm.dart | 39 +---------- .../runner/browser/compilers/precompiled.dart | 38 +++++++--- .../test/lib/src/runner/browser/platform.dart | 3 + pkgs/test/pubspec.yaml | 2 +- 7 files changed, 112 insertions(+), 80 deletions(-) diff --git a/pkgs/test/CHANGELOG.md b/pkgs/test/CHANGELOG.md index c84450720..346c83ee4 100644 --- a/pkgs/test/CHANGELOG.md +++ b/pkgs/test/CHANGELOG.md @@ -1,4 +1,7 @@ -## 1.25.1-wip +## 1.25.1 + +* Fix a bug where in precompiled mode, html files for tests were no longer + created. * Document the silent reporter in CLI help output. diff --git a/pkgs/test/lib/src/runner/browser/compilers/compiler_support.dart b/pkgs/test/lib/src/runner/browser/compilers/compiler_support.dart index 4501e55e4..4fa1b88a9 100644 --- a/pkgs/test/lib/src/runner/browser/compilers/compiler_support.dart +++ b/pkgs/test/lib/src/runner/browser/compilers/compiler_support.dart @@ -3,13 +3,26 @@ // BSD-style license that can be found in the LICENSE file. import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; +import 'package:path/path.dart' as p; +import 'package:shelf/shelf.dart' as shelf; import 'package:test_api/backend.dart' show StackTraceMapper, SuitePlatform; +import 'package:test_core/src/runner/configuration.dart'; // ignore: implementation_imports import 'package:test_core/src/runner/suite.dart'; // ignore: implementation_imports import 'package:web_socket_channel/web_socket_channel.dart'; // ignore: implementation_imports /// The shared interface for all compiler support libraries. -abstract interface class CompilerSupport { +abstract class CompilerSupport { + /// The global test runner configuration. + final Configuration config; + + /// The default template path. + final String defaultTemplatePath; + + CompilerSupport(this.config, this.defaultTemplatePath); + /// The URL at which this compiler serves its tests. /// /// Each compiler serves its tests under a different directory. @@ -34,4 +47,59 @@ abstract interface class CompilerSupport { /// Closes down anything necessary for this implementation. Future close(); + + /// A handler that serves html wrapper files used to bootstrap tests. + shelf.Response htmlWrapperHandler(shelf.Request request); +} + +mixin JsHtmlWrapper on CompilerSupport { + @override + shelf.Response htmlWrapperHandler(shelf.Request request) { + var path = p.fromUri(request.url); + + if (path.endsWith('.html')) { + var test = p.setExtension(path, '.dart'); + var scriptBase = htmlEscape.convert(p.basename(test)); + var link = ''; + var testName = htmlEscape.convert(test); + var template = config.customHtmlTemplatePath ?? defaultTemplatePath; + var contents = File(template).readAsStringSync(); + var processedContents = contents + // Checked during loading phase that there is only one {{testScript}} placeholder. + .replaceFirst('{{testScript}}', link) + .replaceAll('{{testName}}', testName); + return shelf.Response.ok(processedContents, + headers: {'Content-Type': 'text/html'}); + } + + return shelf.Response.notFound('Not found.'); + } +} + +mixin WasmHtmlWrapper on CompilerSupport { + @override + shelf.Response htmlWrapperHandler(shelf.Request request) { + var path = p.fromUri(request.url); + + if (path.endsWith('.html')) { + var test = '${p.withoutExtension(path)}.dart'; + var scriptBase = htmlEscape.convert(p.basename(test)); + var link = ''; + var testName = htmlEscape.convert(test); + var template = config.customHtmlTemplatePath ?? defaultTemplatePath; + var contents = File(template).readAsStringSync(); + var jsRuntime = p.basename('$test.browser_test.dart.mjs'); + var wasmData = ''; + var processedContents = contents + // Checked during loading phase that there is only one {{testScript}} placeholder. + .replaceFirst('{{testScript}}', '$link\n$wasmData') + .replaceAll('{{testName}}', testName); + return shelf.Response.ok(processedContents, + headers: {'Content-Type': 'text/html'}); + } + + return shelf.Response.notFound('Not found.'); + } } diff --git a/pkgs/test/lib/src/runner/browser/compilers/dart2js.dart b/pkgs/test/lib/src/runner/browser/compilers/dart2js.dart index 5aa086149..6794c645e 100644 --- a/pkgs/test/lib/src/runner/browser/compilers/dart2js.dart +++ b/pkgs/test/lib/src/runner/browser/compilers/dart2js.dart @@ -3,7 +3,6 @@ // BSD-style license that can be found in the LICENSE file. import 'dart:async'; -import 'dart:convert'; import 'dart:io'; import 'package:http_multi_server/http_multi_server.dart'; @@ -30,7 +29,7 @@ import '../../../util/path_handler.dart'; import 'compiler_support.dart'; /// Support for Dart2Js compiled tests. -class Dart2JsSupport implements CompilerSupport { +class Dart2JsSupport extends CompilerSupport with JsHtmlWrapper { /// Whether [close] has been called. bool _closed = false; @@ -47,12 +46,6 @@ class Dart2JsSupport implements CompilerSupport { /// The [Dart2JsCompilerPool] managing active instances of `dart2js`. final _compilerPool = Dart2JsCompilerPool(); - /// The global test runner configuration. - final Configuration _config; - - /// The default template path. - final String _defaultTemplatePath; - /// Mappers for Dartifying stack traces, indexed by test path. final _mappers = {}; @@ -81,14 +74,14 @@ class Dart2JsSupport implements CompilerSupport { @override Uri get serverUrl => _server.url.resolve('$_secret/'); - Dart2JsSupport._(this._config, this._defaultTemplatePath, this._server, + Dart2JsSupport._(super.config, super.defaultTemplatePath, this._server, this._root, String faviconPath) { var cascade = shelf.Cascade() .add(_webSocketHandler.handler) .add(packagesDirHandler()) .add(_pathHandler.handler) .add(createStaticHandler(_root)) - .add(_wrapperHandler); + .add(htmlWrapperHandler); var pipeline = const shelf.Pipeline() .addMiddleware(PathHandler.nestedIn(_secret)) @@ -111,28 +104,6 @@ class Dart2JsSupport implements CompilerSupport { config, defaultTemplatePath, server, root, faviconPath); } - /// A handler that serves wrapper files used to bootstrap tests. - shelf.Response _wrapperHandler(shelf.Request request) { - var path = p.fromUri(request.url); - - if (path.endsWith('.html')) { - var test = p.setExtension(path, '.dart'); - var scriptBase = htmlEscape.convert(p.basename(test)); - var link = ''; - var testName = htmlEscape.convert(test); - var template = _config.customHtmlTemplatePath ?? _defaultTemplatePath; - var contents = File(template).readAsStringSync(); - var processedContents = contents - // Checked during loading phase that there is only one {{testScript}} placeholder. - .replaceFirst('{{testScript}}', link) - .replaceAll('{{testName}}', testName); - return shelf.Response.ok(processedContents, - headers: {'Content-Type': 'text/html'}); - } - - return shelf.Response.notFound('Not found.'); - } - @override Future compileSuite( String dartPath, SuiteConfiguration suiteConfig, SuitePlatform platform) { diff --git a/pkgs/test/lib/src/runner/browser/compilers/dart2wasm.dart b/pkgs/test/lib/src/runner/browser/compilers/dart2wasm.dart index 94a9d2048..697a9c50b 100644 --- a/pkgs/test/lib/src/runner/browser/compilers/dart2wasm.dart +++ b/pkgs/test/lib/src/runner/browser/compilers/dart2wasm.dart @@ -3,7 +3,6 @@ // BSD-style license that can be found in the LICENSE file. import 'dart:async'; -import 'dart:convert'; import 'dart:io'; import 'package:http_multi_server/http_multi_server.dart'; @@ -29,7 +28,7 @@ import '../browser_manager.dart'; import 'compiler_support.dart'; /// Support for Dart2Wasm compiled tests. -class Dart2WasmSupport implements CompilerSupport { +class Dart2WasmSupport extends CompilerSupport with WasmHtmlWrapper { /// Whether [close] has been called. bool _closed = false; @@ -46,12 +45,6 @@ class Dart2WasmSupport implements CompilerSupport { /// The [WasmCompilerPool] managing active instances of `dart2wasm`. final _compilerPool = WasmCompilerPool(); - /// The global test runner configuration. - final Configuration _config; - - /// The default template path. - final String _defaultTemplatePath; - /// The `package:test` side wrapper for the Dart2Wasm runtime. final String _jsRuntimeWrapper; @@ -83,14 +76,14 @@ class Dart2WasmSupport implements CompilerSupport { @override Uri get serverUrl => _server.url.resolve('$_secret/'); - Dart2WasmSupport._(this._config, this._defaultTemplatePath, + Dart2WasmSupport._(super.config, super.defaultTemplatePath, this._jsRuntimeWrapper, this._server, this._root, String faviconPath) { var cascade = shelf.Cascade() .add(_webSocketHandler.handler) .add(packagesDirHandler()) .add(_pathHandler.handler) .add(createStaticHandler(_root)) - .add(_wrapperHandler); + .add(htmlWrapperHandler); var pipeline = const shelf.Pipeline() .addMiddleware(PathHandler.nestedIn(_secret)) @@ -114,32 +107,6 @@ class Dart2WasmSupport implements CompilerSupport { server, root, faviconPath); } - /// A handler that serves wrapper files used to bootstrap tests. - shelf.Response _wrapperHandler(shelf.Request request) { - var path = p.fromUri(request.url); - - if (path.endsWith('.html')) { - var test = '${p.withoutExtension(path)}.dart'; - var scriptBase = htmlEscape.convert(p.basename(test)); - var link = ''; - var testName = htmlEscape.convert(test); - var template = _config.customHtmlTemplatePath ?? _defaultTemplatePath; - var contents = File(template).readAsStringSync(); - var jsRuntime = p.basename('$test.browser_test.dart.mjs'); - var wasmData = ''; - var processedContents = contents - // Checked during loading phase that there is only one {{testScript}} placeholder. - .replaceFirst('{{testScript}}', '$link\n$wasmData') - .replaceAll('{{testName}}', testName); - return shelf.Response.ok(processedContents, - headers: {'Content-Type': 'text/html'}); - } - - return shelf.Response.notFound('Not found.'); - } - @override Future compileSuite( String dartPath, SuiteConfiguration suiteConfig, SuitePlatform platform) { diff --git a/pkgs/test/lib/src/runner/browser/compilers/precompiled.dart b/pkgs/test/lib/src/runner/browser/compilers/precompiled.dart index aa0af5059..f4c6a7a7e 100644 --- a/pkgs/test/lib/src/runner/browser/compilers/precompiled.dart +++ b/pkgs/test/lib/src/runner/browser/compilers/precompiled.dart @@ -12,7 +12,9 @@ import 'package:shelf/shelf_io.dart' as shelf_io; import 'package:shelf_packages_handler/shelf_packages_handler.dart'; import 'package:shelf_static/shelf_static.dart'; import 'package:shelf_web_socket/shelf_web_socket.dart'; -import 'package:test_api/backend.dart' show StackTraceMapper, SuitePlatform; +import 'package:test_api/backend.dart' + show Compiler, StackTraceMapper, SuitePlatform; +import 'package:test_core/src/runner/configuration.dart'; // ignore: implementation_imports import 'package:test_core/src/runner/suite.dart'; // ignore: implementation_imports import 'package:test_core/src/util/package_config.dart'; // ignore: implementation_imports import 'package:test_core/src/util/stack_trace_mapper.dart'; // ignore: implementation_imports @@ -24,17 +26,17 @@ import '../../../util/package_map.dart'; import '../../../util/path_handler.dart'; import 'compiler_support.dart'; +class JsPrecompiledSupport = PrecompiledSupport with JsHtmlWrapper; +class WasmPrecompiledSupport = PrecompiledSupport with WasmHtmlWrapper; + /// Support for precompiled test files. -class PrecompiledSupport implements CompilerSupport { +abstract class PrecompiledSupport extends CompilerSupport { /// Whether [close] has been called. bool _closed = false; /// Mappers for Dartifying stack traces, indexed by test path. final _mappers = {}; - /// A [PathHandler] used to serve test specific artifacts. - final _pathHandler = PathHandler(); - /// The root directory served statically by the server. final String _root; @@ -60,12 +62,16 @@ class PrecompiledSupport implements CompilerSupport { @override Uri get serverUrl => _server.url.resolve('$_secret/'); - PrecompiledSupport._(this._server, this._root, String faviconPath) { + PrecompiledSupport._(super.config, super.defaultTemplatePath, this._server, + this._root, String faviconPath) { var cascade = shelf.Cascade() .add(_webSocketHandler.handler) + .add(createStaticHandler(_root, serveFilesOutsidePath: true)) + // TODO: This packages dir handler should not be necessary? .add(packagesDirHandler()) - .add(_pathHandler.handler) - .add(createStaticHandler(_root)); + // Even for precompiled tests, we will auto-create a bootstrap html file + // if none was present. + .add(htmlWrapperHandler); var pipeline = const shelf.Pipeline() .addMiddleware(PathHandler.nestedIn(_secret)) @@ -78,11 +84,25 @@ class PrecompiledSupport implements CompilerSupport { } static Future start({ + required Compiler compiler, + required Configuration config, + required String defaultTemplatePath, required String root, required String faviconPath, }) async { var server = shelf_io.IOServer(await HttpMultiServer.loopback(0)); - return PrecompiledSupport._(server, root, faviconPath); + + return switch (compiler) { + Compiler.dart2js => JsPrecompiledSupport._( + config, defaultTemplatePath, server, root, faviconPath), + Compiler.dart2wasm => WasmPrecompiledSupport._( + config, defaultTemplatePath, server, root, faviconPath), + Compiler.exe || + Compiler.kernel || + Compiler.source => + throw UnsupportedError( + 'The browser platform does not support $compiler'), + }; } /// Compiles [dartPath] using [suiteConfig] for [platform]. diff --git a/pkgs/test/lib/src/runner/browser/platform.dart b/pkgs/test/lib/src/runner/browser/platform.dart index 205df4474..c4df1b32c 100644 --- a/pkgs/test/lib/src/runner/browser/platform.dart +++ b/pkgs/test/lib/src/runner/browser/platform.dart @@ -63,6 +63,9 @@ class BrowserPlatform extends PlatformPlugin _compilerSupport.putIfAbsent(compiler, () { if (_config.suiteDefaults.precompiledPath != null) { return PrecompiledSupport.start( + compiler: compiler, + config: _config, + defaultTemplatePath: _defaultTemplatePath, root: _config.suiteDefaults.precompiledPath!, faviconPath: _faviconPath); } diff --git a/pkgs/test/pubspec.yaml b/pkgs/test/pubspec.yaml index 0a95dfaaf..dd05394a2 100644 --- a/pkgs/test/pubspec.yaml +++ b/pkgs/test/pubspec.yaml @@ -1,5 +1,5 @@ name: test -version: 1.25.1-wip +version: 1.25.1 description: >- A full featured library for writing and running Dart tests across platforms. repository: https://github.com/dart-lang/test/tree/master/pkgs/test