From 5bfc3d43ae80da270d1192e06e1fdf570c902c9f Mon Sep 17 00:00:00 2001 From: Nate Wilson Date: Thu, 3 Oct 2024 15:10:03 -0600 Subject: [PATCH] Refactor devfs_web_ddc_modules_test.dart (#155609) This pull request adds a local function `runInTestbed()` to **devfs_web_ddc_modules_test.dart**, which wraps the `testbed.run()` method. Several whitespace adjustments have been made as well.
It's much easier to read after clicking "hide whitespace".
Relevant style guidelines: - Prefer avoiding line breaks after assignment operators. - If you have a newline after some opening punctuation, match it on the closing punctuation. - Only use `=>` when everything, including the function declaration, fits on a single line. --- .../web/devfs_web_ddc_modules_test.dart | 2894 ++++++++--------- 1 file changed, 1327 insertions(+), 1567 deletions(-) diff --git a/packages/flutter_tools/test/general.shard/web/devfs_web_ddc_modules_test.dart b/packages/flutter_tools/test/general.shard/web/devfs_web_ddc_modules_test.dart index bd8d5748783..b99c001b8b6 100644 --- a/packages/flutter_tools/test/general.shard/web/devfs_web_ddc_modules_test.dart +++ b/packages/flutter_tools/test/general.shard/web/devfs_web_ddc_modules_test.dart @@ -21,6 +21,7 @@ import 'package:flutter_tools/src/isolated/devfs_web.dart'; import 'package:flutter_tools/src/web/compile.dart'; import 'package:flutter_tools/src/web_template.dart'; import 'package:logging/logging.dart' as logging; +import 'package:meta/meta.dart'; import 'package:package_config/package_config.dart'; import 'package:shelf/shelf.dart'; import 'package:test/fake.dart'; @@ -30,70 +31,14 @@ import '../../src/common.dart'; import '../../src/testbed.dart'; const List kTransparentImage = [ - 0x89, - 0x50, - 0x4E, - 0x47, - 0x0D, - 0x0A, - 0x1A, - 0x0A, - 0x00, - 0x00, - 0x00, - 0x0D, - 0x49, - 0x48, - 0x44, - 0x52, - 0x00, - 0x00, - 0x00, - 0x01, - 0x00, - 0x00, - 0x00, - 0x01, - 0x08, - 0x06, - 0x00, - 0x00, - 0x00, - 0x1F, - 0x15, - 0xC4, - 0x89, - 0x00, - 0x00, - 0x00, - 0x0A, - 0x49, - 0x44, - 0x41, - 0x54, - 0x78, - 0x9C, - 0x63, - 0x00, - 0x01, - 0x00, - 0x00, - 0x05, - 0x00, - 0x01, - 0x0D, - 0x0A, - 0x2D, - 0xB4, - 0x00, - 0x00, - 0x00, - 0x00, - 0x49, - 0x45, - 0x4E, - 0x44, - 0xAE, + 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, // + 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4, + 0x89, 0x00, 0x00, 0x00, 0x0A, 0x49, 0x44, 0x41, + 0x54, 0x78, 0x9C, 0x63, 0x00, 0x01, 0x00, 0x00, + 0x05, 0x00, 0x01, 0x0D, 0x0A, 0x2D, 0xB4, 0x00, + 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, ]; void main() { @@ -117,1385 +62,1214 @@ void main() { httpServer = FakeHttpServer(); linux = FakePlatform(environment: {}); windows = FakePlatform( - operatingSystem: 'windows', environment: {}); + operatingSystem: 'windows', + environment: {}, + ); logger = BufferLogger.test(); testbed = Testbed( - setup: () { - webAssetServer = WebAssetServer( - httpServer, - packages, - InternetAddress.loopbackIPv4, - {}, - {}, - NullSafetyMode.unsound, - usesDdcModuleSystem, - webRenderer: WebRendererMode.canvaskit, - useLocalCanvasKit: false, - ); - releaseAssetServer = ReleaseAssetServer( - globals.fs.file('main.dart').uri, - fileSystem: globals.fs, - flutterRoot: null, // ignore: avoid_redundant_argument_values - platform: FakePlatform(), - webBuildDirectory: null, // ignore: avoid_redundant_argument_values - needsCoopCoep: false, - ); - }, - overrides: { - Logger: () => logger, - }); + setup: () { + webAssetServer = WebAssetServer( + httpServer, + packages, + InternetAddress.loopbackIPv4, + {}, + {}, + NullSafetyMode.unsound, + usesDdcModuleSystem, + webRenderer: WebRendererMode.canvaskit, + useLocalCanvasKit: false, + ); + releaseAssetServer = ReleaseAssetServer( + globals.fs.file('main.dart').uri, + fileSystem: globals.fs, + flutterRoot: null, + platform: FakePlatform(), + webBuildDirectory: null, + needsCoopCoep: false, + ); + }, + overrides: {Logger: () => logger}, + ); }); - test( - '.log() reports warnings', - () => testbed.run(() { - const String unresolvedUriMessage = 'Unresolved uri:'; - const String otherMessage = 'Something bad happened'; - - final List events = [ - logging.LogRecord( - logging.Level.WARNING, - unresolvedUriMessage, - 'DartUri', - ), - logging.LogRecord( - logging.Level.WARNING, - otherMessage, - 'DartUri', - ), - ]; - - events.forEach(log); - expect(logger.warningText, contains(unresolvedUriMessage)); - expect(logger.warningText, contains(otherMessage)); - })); - - test( - 'Handles against malformed manifest', - () => testbed.run(() async { - final File source = globals.fs.file('source') - ..writeAsStringSync('main() {}'); - final File sourcemap = globals.fs.file('sourcemap') - ..writeAsStringSync('{}'); - final File metadata = globals.fs.file('metadata') - ..writeAsStringSync('{}'); - - // Missing ending offset. - final File manifestMissingOffset = globals.fs.file('manifestA') - ..writeAsStringSync(json.encode({ - '/foo.js': { - 'code': [0], - 'sourcemap': [0], - 'metadata': [0], - }, - })); - final File manifestOutOfBounds = globals.fs.file('manifest') - ..writeAsStringSync(json.encode({ - '/foo.js': { - 'code': [0, 100], - 'sourcemap': [0], - 'metadata': [0], - }, - })); - - expect( - webAssetServer.write( - source, manifestMissingOffset, sourcemap, metadata), - isEmpty); - expect( - webAssetServer.write( - source, manifestOutOfBounds, sourcemap, metadata), - isEmpty); - })); - - test( - 'serves JavaScript files from in memory cache', - () => testbed.run(() async { - final File source = globals.fs.file('source') - ..writeAsStringSync('main() {}'); - final File sourcemap = globals.fs.file('sourcemap') - ..writeAsStringSync('{}'); - final File metadata = globals.fs.file('metadata') - ..writeAsStringSync('{}'); - final File manifest = globals.fs.file('manifest') - ..writeAsStringSync(json.encode({ - '/foo.js': { - 'code': [0, source.lengthSync()], - 'sourcemap': [0, 2], - 'metadata': [0, 2], - }, - })); - webAssetServer.write(source, manifest, sourcemap, metadata); - - final Response response = await webAssetServer.handleRequest( - Request('GET', Uri.parse('http://foobar/foo.js'))); - - expect( - response.headers, - allOf([ - containsPair(HttpHeaders.contentLengthHeader, - source.lengthSync().toString()), - containsPair( - HttpHeaders.contentTypeHeader, 'application/javascript'), - containsPair(HttpHeaders.etagHeader, isNotNull), - ])); - expect((await response.read().toList()).first, - source.readAsBytesSync()); - }, overrides: { - Platform: () => linux, - })); - - test( - 'serves metadata files from in memory cache', - () => testbed.run(() async { - const String metadataContents = '{"name":"foo"}'; - final File source = globals.fs.file('source') - ..writeAsStringSync('main() {}'); - final File sourcemap = globals.fs.file('sourcemap') - ..writeAsStringSync('{}'); - final File metadata = globals.fs.file('metadata') - ..writeAsStringSync(metadataContents); - final File manifest = globals.fs.file('manifest') - ..writeAsStringSync(json.encode({ - '/foo.js': { - 'code': [0, source.lengthSync()], - 'sourcemap': [0, sourcemap.lengthSync()], - 'metadata': [0, metadata.lengthSync()], - }, - })); - webAssetServer.write(source, manifest, sourcemap, metadata); - - final String? merged = await webAssetServer - .metadataContents('main_module.ddc_merged_metadata'); - expect(merged, equals(metadataContents)); - - final String? single = - await webAssetServer.metadataContents('foo.js.metadata'); - expect(single, equals(metadataContents)); - }, overrides: { - Platform: () => linux, - })); - - test( - 'Removes leading slashes for valid requests to avoid requesting outside' - ' of served directory', - () => testbed.run(() async { - globals.fs.file('foo.png').createSync(); - globals.fs.currentDirectory = - globals.fs.directory('project_directory')..createSync(); - - final File source = - globals.fs.file(globals.fs.path.join('web', 'foo.png')) - ..createSync(recursive: true) - ..writeAsBytesSync(kTransparentImage); - final Response response = await webAssetServer.handleRequest( - Request('GET', Uri.parse('http://foobar////foo.png'))); - - expect( - response.headers, - allOf([ - containsPair(HttpHeaders.contentLengthHeader, - source.lengthSync().toString()), - containsPair(HttpHeaders.contentTypeHeader, 'image/png'), - containsPair(HttpHeaders.etagHeader, isNotNull), - containsPair(HttpHeaders.cacheControlHeader, - 'max-age=0, must-revalidate'), - ])); - expect((await response.read().toList()).first, - source.readAsBytesSync()); - })); - - test( - 'takes base path into account when serving', - () => testbed.run(() async { - webAssetServer.basePath = 'base/path'; - - globals.fs.file('foo.png').createSync(); - globals.fs.currentDirectory = - globals.fs.directory('project_directory')..createSync(); - - final File source = - globals.fs.file(globals.fs.path.join('web', 'foo.png')) - ..createSync(recursive: true) - ..writeAsBytesSync(kTransparentImage); - final Response response = await webAssetServer.handleRequest( - Request('GET', Uri.parse('http://foobar/base/path/foo.png')), - ); - - expect( - response.headers, - allOf([ - containsPair(HttpHeaders.contentLengthHeader, - source.lengthSync().toString()), - containsPair(HttpHeaders.contentTypeHeader, 'image/png'), - containsPair(HttpHeaders.etagHeader, isNotNull), - containsPair(HttpHeaders.cacheControlHeader, - 'max-age=0, must-revalidate'), - ])); - expect((await response.read().toList()).first, - source.readAsBytesSync()); - })); - - test( - 'serves index.html at the base path', - () => testbed.run(() async { - webAssetServer.basePath = 'base/path'; - - const String htmlContent = - ''; - final Directory webDir = - globals.fs.currentDirectory.childDirectory('web')..createSync(); - webDir.childFile('index.html').writeAsStringSync(htmlContent); - globals.fs.file(globals.fs.path.join( - globals.artifacts!.getHostArtifact(HostArtifact.flutterJsDirectory).path, - 'flutter.js', - ))..createSync(recursive: true)..writeAsStringSync('flutter.js content'); - - - final Response response = await webAssetServer.handleRequest( - Request('GET', Uri.parse('http://foobar/base/path/'))); - - expect(response.statusCode, HttpStatus.ok); - expect(await response.readAsString(), htmlContent); - })); - - test( - 'serves index.html at / if href attribute is $kBaseHrefPlaceholder', - () => testbed.run(() async { - const String htmlContent = - ''; - final Directory webDir = - globals.fs.currentDirectory.childDirectory('web')..createSync(); - webDir.childFile('index.html').writeAsStringSync(htmlContent); - globals.fs.file(globals.fs.path.join( - globals.artifacts!.getHostArtifact(HostArtifact.flutterJsDirectory).path, - 'flutter.js', - ))..createSync(recursive: true)..writeAsStringSync('flutter.js content'); - - final Response response = await webAssetServer - .handleRequest(Request('GET', Uri.parse('http://foobar/'))); - - expect(response.statusCode, HttpStatus.ok); - expect(await response.readAsString(), - htmlContent.replaceAll(kBaseHrefPlaceholder, '/')); - })); - - test( - 'does not serve outside the base path', - () => testbed.run(() async { - webAssetServer.basePath = 'base/path'; - - const String htmlContent = - ''; - final Directory webDir = - globals.fs.currentDirectory.childDirectory('web')..createSync(); - webDir.childFile('index.html').writeAsStringSync(htmlContent); - - final Response response = await webAssetServer - .handleRequest(Request('GET', Uri.parse('http://foobar/'))); - - expect(response.statusCode, HttpStatus.notFound); - })); - - test( - 'parses base path from index.html', - () => testbed.run(() async { - const String htmlContent = - ''; - final Directory webDir = - globals.fs.currentDirectory.childDirectory('web')..createSync(); - webDir.childFile('index.html').writeAsStringSync(htmlContent); - - final WebAssetServer webAssetServer = WebAssetServer( - httpServer, - packages, - InternetAddress.loopbackIPv4, - {}, - {}, - NullSafetyMode.unsound, - usesDdcModuleSystem, - webRenderer: WebRendererMode.canvaskit, - useLocalCanvasKit: false, - ); - - expect(webAssetServer.basePath, 'foo/bar'); - })); - - test( - 'handles lack of base path in index.html', - () => testbed.run(() async { - const String htmlContent = - ''; - final Directory webDir = - globals.fs.currentDirectory.childDirectory('web')..createSync(); - webDir.childFile('index.html').writeAsStringSync(htmlContent); - - final WebAssetServer webAssetServer = WebAssetServer( - httpServer, - packages, - InternetAddress.loopbackIPv4, - {}, - {}, - NullSafetyMode.unsound, - usesDdcModuleSystem, - webRenderer: WebRendererMode.canvaskit, - useLocalCanvasKit: false, - ); - - // Defaults to "/" when there's no base element. - expect(webAssetServer.basePath, ''); - })); - - test( - 'throws if base path is relative', - () => testbed.run(() async { - const String htmlContent = - ''; - final Directory webDir = - globals.fs.currentDirectory.childDirectory('web')..createSync(); - webDir.childFile('index.html').writeAsStringSync(htmlContent); - - expect( - () => WebAssetServer( - httpServer, - packages, - InternetAddress.loopbackIPv4, - {}, - {}, - NullSafetyMode.unsound, - usesDdcModuleSystem, - webRenderer: WebRendererMode.canvaskit, - useLocalCanvasKit: false, - ), - throwsToolExit(), - ); - })); - - test( - 'throws if base path does not end with slash', - () => testbed.run(() async { - const String htmlContent = - ''; - final Directory webDir = - globals.fs.currentDirectory.childDirectory('web')..createSync(); - webDir.childFile('index.html').writeAsStringSync(htmlContent); - - expect( - () => WebAssetServer( - httpServer, - packages, - InternetAddress.loopbackIPv4, - {}, - {}, - NullSafetyMode.unsound, - usesDdcModuleSystem, - webRenderer: WebRendererMode.canvaskit, - useLocalCanvasKit: false, - ), - throwsToolExit(), - ); - })); - - test( - 'serves JavaScript files from in memory cache not from manifest', - () => testbed.run(() async { - webAssetServer.writeFile('foo.js', 'main() {}'); - - final Response response = await webAssetServer.handleRequest( - Request('GET', Uri.parse('http://foobar/foo.js'))); - - expect( - response.headers, - allOf([ - containsPair(HttpHeaders.contentLengthHeader, '9'), - containsPair( - HttpHeaders.contentTypeHeader, 'application/javascript'), - containsPair(HttpHeaders.etagHeader, isNotNull), - containsPair(HttpHeaders.cacheControlHeader, - 'max-age=0, must-revalidate'), - ])); - expect((await response.read().toList()).first, - utf8.encode('main() {}')); - })); - - test( - 'Returns notModified when the ifNoneMatch header matches the etag', - () => testbed.run(() async { - webAssetServer.writeFile('foo.js', 'main() {}'); - - final Response response = await webAssetServer.handleRequest( - Request('GET', Uri.parse('http://foobar/foo.js'))); - final String etag = response.headers[HttpHeaders.etagHeader]!; - - final Response cachedResponse = await webAssetServer.handleRequest( - Request('GET', Uri.parse('http://foobar/foo.js'), - headers: { - HttpHeaders.ifNoneMatchHeader: etag, - })); - - expect(cachedResponse.statusCode, HttpStatus.notModified); - expect(await cachedResponse.read().toList(), isEmpty); - })); - - test( - 'serves index.html when path is unknown', - () => testbed.run(() async { - const String htmlContent = - ''; - final Directory webDir = - globals.fs.currentDirectory.childDirectory('web')..createSync(); - webDir.childFile('index.html').writeAsStringSync(htmlContent); - globals.fs.file(globals.fs.path.join( - globals.artifacts!.getHostArtifact(HostArtifact.flutterJsDirectory).path, - 'flutter.js', - ))..createSync(recursive: true)..writeAsStringSync('flutter.js content'); - - final Response response = await webAssetServer.handleRequest( - Request('GET', Uri.parse('http://foobar/bar/baz'))); - - expect(response.statusCode, HttpStatus.ok); - expect(await response.readAsString(), htmlContent); - })); - - test( - 'does not serve outside the base path', - () => testbed.run(() async { - webAssetServer.basePath = 'base/path'; - - const String htmlContent = - ''; - final Directory webDir = - globals.fs.currentDirectory.childDirectory('web')..createSync(); - webDir.childFile('index.html').writeAsStringSync(htmlContent); - - final Response response = await webAssetServer - .handleRequest(Request('GET', Uri.parse('http://foobar/'))); - - expect(response.statusCode, HttpStatus.notFound); - })); - - test( - 'does not serve index.html when path is inside assets or packages', - () => testbed.run(() async { - const String htmlContent = - ''; - final Directory webDir = - globals.fs.currentDirectory.childDirectory('web')..createSync(); - webDir.childFile('index.html').writeAsStringSync(htmlContent); - - Response response = await webAssetServer.handleRequest( - Request('GET', Uri.parse('http://foobar/assets/foo/bar.png'))); - expect(response.statusCode, HttpStatus.notFound); - - response = await webAssetServer.handleRequest(Request( - 'GET', Uri.parse('http://foobar/packages/foo/bar.dart.js'))); - expect(response.statusCode, HttpStatus.notFound); - - webAssetServer.basePath = 'base/path'; - - response = await webAssetServer.handleRequest(Request('GET', - Uri.parse('http://foobar/base/path/assets/foo/bar.png'))); - expect(response.statusCode, HttpStatus.notFound); - - response = await webAssetServer.handleRequest(Request('GET', - Uri.parse('http://foobar/base/path/packages/foo/bar.dart.js'))); - expect(response.statusCode, HttpStatus.notFound); - })); - - test( - 'serves default index.html', - () => testbed.run(() async { - globals.fs.file(globals.fs.path.join( - globals.artifacts!.getHostArtifact(HostArtifact.flutterJsDirectory).path, - 'flutter.js', - ))..createSync(recursive: true)..writeAsStringSync('flutter.js content'); - - final Response response = await webAssetServer - .handleRequest(Request('GET', Uri.parse('http://foobar/'))); - - expect(response.statusCode, HttpStatus.ok); - expect((await response.read().toList()).first, - containsAllInOrder(utf8.encode(''))); - })); - - test( - 'handles web server paths without .lib extension', - () => testbed.run(() async { - final File source = globals.fs.file('source') - ..writeAsStringSync('main() {}'); - final File sourcemap = globals.fs.file('sourcemap') - ..writeAsStringSync('{}'); - final File metadata = globals.fs.file('metadata') - ..writeAsStringSync('{}'); - final File manifest = globals.fs.file('manifest') - ..writeAsStringSync(json.encode({ - '/foo.dart.lib.js': { - 'code': [0, source.lengthSync()], - 'sourcemap': [0, 2], - 'metadata': [0, 2], - }, - })); - webAssetServer.write(source, manifest, sourcemap, metadata); - - final Response response = await webAssetServer.handleRequest( - Request('GET', Uri.parse('http://foobar/foo.dart.js'))); - - expect(response.statusCode, HttpStatus.ok); - })); - - test( - 'serves JavaScript files from in memory cache on Windows', - () => testbed.run(() async { - final File source = globals.fs.file('source') - ..writeAsStringSync('main() {}'); - final File sourcemap = globals.fs.file('sourcemap') - ..writeAsStringSync('{}'); - final File metadata = globals.fs.file('metadata') - ..writeAsStringSync('{}'); - final File manifest = globals.fs.file('manifest') - ..writeAsStringSync(json.encode({ - '/foo.js': { - 'code': [0, source.lengthSync()], - 'sourcemap': [0, 2], - 'metadata': [0, 2], - }, - })); - webAssetServer.write(source, manifest, sourcemap, metadata); - final Response response = await webAssetServer.handleRequest( - Request('GET', Uri.parse('http://localhost/foo.js'))); - - expect( - response.headers, - allOf([ - containsPair(HttpHeaders.contentLengthHeader, - source.lengthSync().toString()), - containsPair( - HttpHeaders.contentTypeHeader, 'application/javascript'), - containsPair(HttpHeaders.etagHeader, isNotNull), - containsPair(HttpHeaders.cacheControlHeader, - 'max-age=0, must-revalidate'), - ])); - expect((await response.read().toList()).first, - source.readAsBytesSync()); - }, overrides: { - Platform: () => windows, - })); - - test( - 'serves asset files from in filesystem with url-encoded paths', - () => testbed.run(() async { - final File source = globals.fs.file(globals.fs.path - .join('build', 'flutter_assets', Uri.encodeFull('abcd象形字.png'))) - ..createSync(recursive: true) - ..writeAsBytesSync(kTransparentImage); - final Response response = await webAssetServer.handleRequest(Request( - 'GET', - Uri.parse( - 'http://foobar/assets/abcd%25E8%25B1%25A1%25E5%25BD%25A2%25E5%25AD%2597.png'))); - - expect( - response.headers, - allOf([ - containsPair(HttpHeaders.contentLengthHeader, - source.lengthSync().toString()), - containsPair(HttpHeaders.contentTypeHeader, 'image/png'), - containsPair(HttpHeaders.etagHeader, isNotNull), - containsPair(HttpHeaders.cacheControlHeader, - 'max-age=0, must-revalidate'), - ])); - expect((await response.read().toList()).first, - source.readAsBytesSync()); - })); - test( - 'serves files from web directory', - () => testbed.run(() async { - final File source = - globals.fs.file(globals.fs.path.join('web', 'foo.png')) - ..createSync(recursive: true) - ..writeAsBytesSync(kTransparentImage); - final Response response = await webAssetServer.handleRequest( - Request('GET', Uri.parse('http://foobar/foo.png'))); - - expect( - response.headers, - allOf([ - containsPair(HttpHeaders.contentLengthHeader, - source.lengthSync().toString()), - containsPair(HttpHeaders.contentTypeHeader, 'image/png'), - containsPair(HttpHeaders.etagHeader, isNotNull), - containsPair(HttpHeaders.cacheControlHeader, - 'max-age=0, must-revalidate'), - ])); - expect((await response.read().toList()).first, - source.readAsBytesSync()); - })); - - test( - 'serves asset files from in filesystem with known mime type on Windows', - () => testbed.run(() async { - final File source = globals.fs.file( - globals.fs.path.join('build', 'flutter_assets', 'foo.png')) - ..createSync(recursive: true) - ..writeAsBytesSync(kTransparentImage); - final Response response = await webAssetServer.handleRequest( - Request('GET', Uri.parse('http://foobar/assets/foo.png'))); - - expect( - response.headers, - allOf([ - containsPair(HttpHeaders.contentLengthHeader, - source.lengthSync().toString()), - containsPair(HttpHeaders.contentTypeHeader, 'image/png'), - containsPair(HttpHeaders.etagHeader, isNotNull), - containsPair(HttpHeaders.cacheControlHeader, - 'max-age=0, must-revalidate'), - ])); - expect((await response.read().toList()).first, - source.readAsBytesSync()); - }, overrides: { - Platform: () => windows, - })); - - test( - 'serves Dart files from in filesystem on Linux/macOS', - () => testbed.run(() async { - final File source = globals.fs.file('foo.dart').absolute - ..createSync(recursive: true) - ..writeAsStringSync('void main() {}'); - - final Response response = await webAssetServer.handleRequest( - Request('GET', Uri.parse('http://foobar/foo.dart'))); - - expect( - response.headers, - containsPair(HttpHeaders.contentLengthHeader, - source.lengthSync().toString())); - expect((await response.read().toList()).first, - source.readAsBytesSync()); - }, overrides: { - Platform: () => linux, - })); - - test( - 'serves asset files from in filesystem with known mime type', - () => testbed.run(() async { - final File source = globals.fs.file( - globals.fs.path.join('build', 'flutter_assets', 'foo.png')) - ..createSync(recursive: true) - ..writeAsBytesSync(kTransparentImage); - - final Response response = await webAssetServer.handleRequest( - Request('GET', Uri.parse('http://foobar/assets/foo.png'))); - - expect( - response.headers, - allOf([ - containsPair(HttpHeaders.contentLengthHeader, - source.lengthSync().toString()), - containsPair(HttpHeaders.contentTypeHeader, 'image/png'), - ])); - expect((await response.read().toList()).first, - source.readAsBytesSync()); - })); - - test( - 'serves asset files from in filesystem with known mime type and empty content', - () => testbed.run(() async { - final File source = globals.fs - .file(globals.fs.path.join('web', 'foo.js')) - ..createSync(recursive: true); - - final Response response = await webAssetServer.handleRequest( - Request('GET', Uri.parse('http://foobar/foo.js'))); - - expect( - response.headers, - allOf([ - containsPair(HttpHeaders.contentLengthHeader, '0'), - containsPair( - HttpHeaders.contentTypeHeader, 'text/javascript'), - ])); - expect((await response.read().toList()).first, - source.readAsBytesSync()); - })); - - test( - 'serves asset files from in filesystem with unknown mime type', - () => testbed.run(() async { - final File source = globals.fs - .file(globals.fs.path.join('build', 'flutter_assets', 'foo')) - ..createSync(recursive: true) - ..writeAsBytesSync(List.filled(100, 0)); - - final Response response = await webAssetServer.handleRequest( - Request('GET', Uri.parse('http://foobar/assets/foo'))); - - expect( - response.headers, - allOf([ - containsPair(HttpHeaders.contentLengthHeader, '100'), - containsPair(HttpHeaders.contentTypeHeader, - 'application/octet-stream'), - ])); - expect((await response.read().toList()).first, - source.readAsBytesSync()); - })); - - test( - 'serves valid etag header for asset files with non-ascii characters', - () => testbed.run(() async { - globals.fs - .file(globals.fs.path.join('build', 'flutter_assets', 'fooπ')) - ..createSync(recursive: true) - ..writeAsBytesSync([1, 2, 3]); - - final Response response = await webAssetServer.handleRequest( - Request('GET', Uri.parse('http://foobar/assets/fooπ'))); - final String etag = response.headers[HttpHeaders.etagHeader]!; - - expect( - etag.runes, everyElement(predicate((int char) => char < 255))); - })); - - test( - 'serves /packages// files as if they were ' - 'package:/ uris', - () => testbed.run(() async { - final Uri? expectedUri = - packages.resolve(Uri.parse('package:flutter_tools/foo.dart')); - final File source = - globals.fs.file(globals.fs.path.fromUri(expectedUri)) - ..createSync(recursive: true) - ..writeAsBytesSync([1, 2, 3]); - - final Response response = await webAssetServer.handleRequest( - Request('GET', - Uri.parse('http:///packages/flutter_tools/foo.dart'))); - - expect( - response.headers, - allOf([ - containsPair(HttpHeaders.contentLengthHeader, '3'), - containsPair(HttpHeaders.contentTypeHeader, 'text/x-dart'), - ])); - expect((await response.read().toList()).first, - source.readAsBytesSync()); - })); - - test( - 'calling dispose closes the http server', - () => testbed.run(() async { - await webAssetServer.dispose(); - - expect(httpServer.closed, true); - })); - - test( - 'Can start web server with specified DDC module system assets', - () => testbed.run(() async { - final File outputFile = globals.fs - .file(globals.fs.path.join('lib', 'main.dart')) - ..createSync(recursive: true); - outputFile.parent.childFile('a.sources').writeAsStringSync(''); - outputFile.parent.childFile('a.json').writeAsStringSync('{}'); - outputFile.parent.childFile('a.map').writeAsStringSync('{}'); - outputFile.parent.childFile('a.metadata').writeAsStringSync('{}'); - - final ResidentCompiler residentCompiler = FakeResidentCompiler() - ..output = const CompilerOutput('a', 0, []); - - final WebDevFS webDevFS = WebDevFS( - hostname: 'localhost', - port: 0, - tlsCertPath: null, - tlsCertKeyPath: null, - packagesFilePath: '.dart_tool/package_config.json', - urlTunneller: null, // ignore: avoid_redundant_argument_values - useSseForDebugProxy: true, - useSseForDebugBackend: true, - useSseForInjectedClient: true, - nullAssertions: true, - nativeNullAssertions: true, - buildInfo: const BuildInfo( - BuildMode.debug, - '', - treeShakeIcons: false, - nullSafetyMode: NullSafetyMode.unsound, - packageConfigPath: '.dart_tool/package_config.json', - ), - enableDwds: false, - enableDds: false, - entrypoint: Uri.base, - testMode: true, - expressionCompiler: - null, // ignore: avoid_redundant_argument_values - extraHeaders: const {}, - chromiumLauncher: null, // ignore: avoid_redundant_argument_values - nullSafetyMode: NullSafetyMode.unsound, - ddcModuleSystem: usesDdcModuleSystem, - webRenderer: WebRendererMode.html, - isWasm: false, - useLocalCanvasKit: false, - rootDirectory: globals.fs.currentDirectory, - ); - webDevFS.ddcModuleLoaderJS.createSync(recursive: true); - webDevFS.flutterJs.createSync(recursive: true); - webDevFS.stackTraceMapper.createSync(recursive: true); - - final Uri uri = await webDevFS.create(); - webDevFS.webAssetServer.entrypointCacheDirectory = - globals.fs.currentDirectory; - final String webPrecompiledSdk = globals.artifacts! - .getHostArtifact(HostArtifact.webPrecompiledDdcSdk) - .path; - final String webPrecompiledSdkSourcemaps = globals.artifacts! - .getHostArtifact(HostArtifact.webPrecompiledDdcSdkSourcemaps) - .path; - final String webPrecompiledCanvaskitSdk = globals.artifacts! - .getHostArtifact(HostArtifact.webPrecompiledDdcCanvaskitSdk) - .path; - final String webPrecompiledCanvaskitSdkSourcemaps = globals - .artifacts! - .getHostArtifact( - HostArtifact.webPrecompiledDdcCanvaskitSdkSourcemaps) - .path; - globals.fs.currentDirectory - .childDirectory('lib') - .childFile('web_entrypoint.dart') - ..createSync(recursive: true) - ..writeAsStringSync('GENERATED'); - globals.fs.file(webPrecompiledSdk) - ..createSync(recursive: true) - ..writeAsStringSync('HELLO'); - globals.fs.file(webPrecompiledSdkSourcemaps) - ..createSync(recursive: true) - ..writeAsStringSync('THERE'); - globals.fs.file(webPrecompiledCanvaskitSdk) - ..createSync(recursive: true) - ..writeAsStringSync('OL'); - globals.fs.file(webPrecompiledCanvaskitSdkSourcemaps) - ..createSync(recursive: true) - ..writeAsStringSync('CHUM'); - - await webDevFS.update( - mainUri: - globals.fs.file(globals.fs.path.join('lib', 'main.dart')).uri, - generator: residentCompiler, - trackWidgetCreation: true, - bundleFirstUpload: true, - invalidatedFiles: [], - packageConfig: PackageConfig.empty, - pathToReload: '', - dillOutputPath: 'out.dill', - shaderCompiler: const FakeShaderCompiler(), - ); - - expect(webDevFS.webAssetServer.getFile('ddc_module_loader.js'), - isNotNull); - expect(webDevFS.webAssetServer.getFile('stack_trace_mapper.js'), - isNotNull); - expect(webDevFS.webAssetServer.getFile('main.dart'), isNotNull); - expect(webDevFS.webAssetServer.getFile('manifest.json'), isNotNull); - expect(webDevFS.webAssetServer.getFile('flutter.js'), isNotNull); - expect(webDevFS.webAssetServer.getFile('flutter_service_worker.js'), - isNotNull); - expect(webDevFS.webAssetServer.getFile('version.json'), isNotNull); - expect( - await webDevFS.webAssetServer.dartSourceContents('dart_sdk.js'), - 'HELLO'); - expect( - await webDevFS.webAssetServer - .dartSourceContents('dart_sdk.js.map'), - 'THERE'); - - // Update to the SDK. - globals.fs.file(webPrecompiledSdk).writeAsStringSync('BELLOW'); - - // New SDK should be visible.. - expect( - await webDevFS.webAssetServer.dartSourceContents('dart_sdk.js'), - 'BELLOW'); - - // Generated entrypoint. - expect( - await webDevFS.webAssetServer - .dartSourceContents('web_entrypoint.dart'), - contains('GENERATED')); - - // served on localhost - expect(uri.host, 'localhost'); - - await webDevFS.destroy(); - }, overrides: { - Artifacts: () => Artifacts.test(), - })); - - test( - 'Can start web server with specified assets in sound null safety mode', - () => testbed.run(() async { - final File outputFile = globals.fs - .file(globals.fs.path.join('lib', 'main.dart')) - ..createSync(recursive: true); - outputFile.parent.childFile('a.sources').writeAsStringSync(''); - outputFile.parent.childFile('a.json').writeAsStringSync('{}'); - outputFile.parent.childFile('a.map').writeAsStringSync('{}'); - outputFile.parent.childFile('a.metadata').writeAsStringSync('{}'); - - final ResidentCompiler residentCompiler = FakeResidentCompiler() - ..output = const CompilerOutput('a', 0, []); - - final WebDevFS webDevFS = WebDevFS( - hostname: 'localhost', - port: 0, - tlsCertPath: null, - tlsCertKeyPath: null, - packagesFilePath: '.dart_tool/package_config.json', - urlTunneller: null, // ignore: avoid_redundant_argument_values - useSseForDebugProxy: true, - useSseForDebugBackend: true, - useSseForInjectedClient: true, - nullAssertions: true, - nativeNullAssertions: true, - buildInfo: const BuildInfo( - BuildMode.debug, - '', - treeShakeIcons: false, - packageConfigPath: '.dart_tool/package_config.json', - ), - enableDwds: false, - enableDds: false, - entrypoint: Uri.base, - testMode: true, - expressionCompiler: - null, // ignore: avoid_redundant_argument_values - extraHeaders: const {}, - chromiumLauncher: null, // ignore: avoid_redundant_argument_values - nullSafetyMode: NullSafetyMode.sound, - ddcModuleSystem: usesDdcModuleSystem, - webRenderer: WebRendererMode.html, - isWasm: false, - useLocalCanvasKit: false, - rootDirectory: globals.fs.currentDirectory, - ); - webDevFS.ddcModuleLoaderJS.createSync(recursive: true); - webDevFS.flutterJs.createSync(recursive: true); - webDevFS.stackTraceMapper.createSync(recursive: true); - - final Uri uri = await webDevFS.create(); - webDevFS.webAssetServer.entrypointCacheDirectory = - globals.fs.currentDirectory; - globals.fs.currentDirectory - .childDirectory('lib') - .childFile('web_entrypoint.dart') - ..createSync(recursive: true) - ..writeAsStringSync('GENERATED'); - final String webPrecompiledSdk = globals.artifacts! - .getHostArtifact(HostArtifact.webPrecompiledDdcSoundSdk) - .path; - final String webPrecompiledSdkSourcemaps = globals.artifacts! - .getHostArtifact( - HostArtifact.webPrecompiledDdcSoundSdkSourcemaps) - .path; - final String webPrecompiledCanvaskitSdk = globals.artifacts! - .getHostArtifact( - HostArtifact.webPrecompiledDdcCanvaskitSoundSdk) - .path; - final String webPrecompiledCanvaskitSdkSourcemaps = globals - .artifacts! - .getHostArtifact( - HostArtifact.webPrecompiledDdcCanvaskitSoundSdkSourcemaps) - .path; - globals.fs.file(webPrecompiledSdk) - ..createSync(recursive: true) - ..writeAsStringSync('HELLO'); - globals.fs.file(webPrecompiledSdkSourcemaps) - ..createSync(recursive: true) - ..writeAsStringSync('THERE'); - globals.fs.file(webPrecompiledCanvaskitSdk) - ..createSync(recursive: true) - ..writeAsStringSync('OL'); - globals.fs.file(webPrecompiledCanvaskitSdkSourcemaps) - ..createSync(recursive: true) - ..writeAsStringSync('CHUM'); - - await webDevFS.update( - mainUri: - globals.fs.file(globals.fs.path.join('lib', 'main.dart')).uri, - generator: residentCompiler, - trackWidgetCreation: true, - bundleFirstUpload: true, - invalidatedFiles: [], - packageConfig: PackageConfig.empty, - pathToReload: '', - dillOutputPath: '', - shaderCompiler: const FakeShaderCompiler(), - ); - - expect(webDevFS.webAssetServer.getFile('ddc_module_loader.js'), - isNotNull); - expect(webDevFS.webAssetServer.getFile('stack_trace_mapper.js'), - isNotNull); - expect(webDevFS.webAssetServer.getFile('main.dart'), isNotNull); - expect(webDevFS.webAssetServer.getFile('manifest.json'), isNotNull); - expect(webDevFS.webAssetServer.getFile('flutter.js'), isNotNull); - expect(webDevFS.webAssetServer.getFile('flutter_service_worker.js'), - isNotNull); - expect(webDevFS.webAssetServer.getFile('version.json'), isNotNull); - expect( - await webDevFS.webAssetServer.dartSourceContents('dart_sdk.js'), - 'HELLO'); - expect( - await webDevFS.webAssetServer - .dartSourceContents('dart_sdk.js.map'), - 'THERE'); - - // Update to the SDK. - globals.fs.file(webPrecompiledSdk).writeAsStringSync('BELLOW'); - - // New SDK should be visible.. - expect( - await webDevFS.webAssetServer.dartSourceContents('dart_sdk.js'), - 'BELLOW'); - - // Generated entrypoint. - expect( - await webDevFS.webAssetServer - .dartSourceContents('web_entrypoint.dart'), - contains('GENERATED')); - - // served on localhost - expect(uri.host, 'localhost'); - - await webDevFS.destroy(); - }, overrides: { - Artifacts: () => Artifacts.test(), - })); - - test( - '.connect() will never call vmServiceFactory twice', - () => testbed.run(() async { - await FakeAsync().run>((FakeAsync time) { - final File outputFile = globals.fs - .file(globals.fs.path.join('lib', 'main.dart')) - ..createSync(recursive: true); - outputFile.parent.childFile('a.sources').writeAsStringSync(''); - outputFile.parent.childFile('a.json').writeAsStringSync('{}'); - outputFile.parent.childFile('a.map').writeAsStringSync('{}'); - outputFile.parent.childFile('a.metadata').writeAsStringSync('{}'); - - final WebDevFS webDevFS = WebDevFS( - // if this is any other value, we will do a real ip lookup - hostname: 'any', - port: 0, - tlsCertPath: null, - tlsCertKeyPath: null, - packagesFilePath: '.dart_tool/package_config.json', - urlTunneller: null, - useSseForDebugProxy: true, - useSseForDebugBackend: true, - useSseForInjectedClient: true, - nullAssertions: true, - nativeNullAssertions: true, - buildInfo: const BuildInfo( - BuildMode.debug, - '', - treeShakeIcons: false, - packageConfigPath: '.dart_tool/package_config.json', - ), - enableDwds: true, - enableDds: false, - entrypoint: Uri.base, - testMode: true, - expressionCompiler: null, - extraHeaders: const {}, - chromiumLauncher: null, - nullSafetyMode: NullSafetyMode.sound, - ddcModuleSystem: usesDdcModuleSystem, - webRenderer: WebRendererMode.canvaskit, - isWasm: false, - useLocalCanvasKit: false, - rootDirectory: globals.fs.currentDirectory, - ); - webDevFS.ddcModuleLoaderJS.createSync(recursive: true); - webDevFS.stackTraceMapper.createSync(recursive: true); - final FakeAppConnection firstConnection = FakeAppConnection(); - final FakeAppConnection secondConnection = FakeAppConnection(); - - final Future done = webDevFS.create().then((Uri _) { - // In non-test mode, webDevFS.create() would have initialized DWDS - webDevFS.webAssetServer.dwds = FakeDwds( - [firstConnection, secondConnection]); - - int vmServiceFactoryInvocationCount = 0; - Future vmServiceFactory(Uri uri, - {CompressionOptions? compression, required Logger logger}) { - if (vmServiceFactoryInvocationCount > 0) { - fail('Called vmServiceFactory twice!'); - } - vmServiceFactoryInvocationCount += 1; - return Future.delayed( - const Duration(seconds: 2), - () => FakeVmService(), - ); - } - - return webDevFS - .connect(false, vmServiceFactory: vmServiceFactory) - .then((ConnectionResult? firstConnectionResult) { - return webDevFS.destroy(); - }); - }); - time.elapse(const Duration(seconds: 1)); - time.elapse(const Duration(seconds: 2)); - return done; - }); - }, overrides: { - Artifacts: () => Artifacts.test(), - })); - - test( - 'Can start web server with hostname any', - () => testbed.run(() async { - final File outputFile = globals.fs - .file(globals.fs.path.join('lib', 'main.dart')) - ..createSync(recursive: true); - outputFile.parent.childFile('a.sources').writeAsStringSync(''); - outputFile.parent.childFile('a.json').writeAsStringSync('{}'); - outputFile.parent.childFile('a.map').writeAsStringSync('{}'); - - final WebDevFS webDevFS = WebDevFS( - hostname: 'any', - port: 0, - tlsCertPath: null, - tlsCertKeyPath: null, - packagesFilePath: '.dart_tool/package_config.json', - urlTunneller: null, // ignore: avoid_redundant_argument_values - useSseForDebugProxy: true, - useSseForDebugBackend: true, - useSseForInjectedClient: true, - buildInfo: BuildInfo.debug, - enableDwds: false, - enableDds: false, - entrypoint: Uri.base, - testMode: true, - expressionCompiler: - null, // ignore: avoid_redundant_argument_values - extraHeaders: const {}, - chromiumLauncher: null, // ignore: avoid_redundant_argument_values - nullAssertions: true, - nativeNullAssertions: true, - nullSafetyMode: NullSafetyMode.sound, - ddcModuleSystem: usesDdcModuleSystem, - webRenderer: WebRendererMode.canvaskit, - isWasm: false, - useLocalCanvasKit: false, - rootDirectory: globals.fs.currentDirectory, - ); - webDevFS.ddcModuleLoaderJS.createSync(recursive: true); - webDevFS.stackTraceMapper.createSync(recursive: true); - - final Uri uri = await webDevFS.create(); - - expect(uri.host, 'localhost'); - await webDevFS.destroy(); - })); - - test( - 'Can start web server with canvaskit enabled', - () => testbed.run(() async { - final File outputFile = globals.fs - .file(globals.fs.path.join('lib', 'main.dart')) - ..createSync(recursive: true); - outputFile.parent.childFile('a.sources').writeAsStringSync(''); - outputFile.parent.childFile('a.json').writeAsStringSync('{}'); - outputFile.parent.childFile('a.map').writeAsStringSync('{}'); - - final WebDevFS webDevFS = WebDevFS( - hostname: 'localhost', - port: 0, - tlsCertPath: null, - tlsCertKeyPath: null, - packagesFilePath: '.dart_tool/package_config.json', - urlTunneller: null, // ignore: avoid_redundant_argument_values - useSseForDebugProxy: true, - useSseForDebugBackend: true, - useSseForInjectedClient: true, - nullAssertions: true, - nativeNullAssertions: true, - buildInfo: const BuildInfo( - BuildMode.debug, '', - treeShakeIcons: false, - dartDefines: [ - 'FLUTTER_WEB_USE_SKIA=true', - ], - packageConfigPath: '.dart_tool/package_config.json', - ), - enableDwds: false, - enableDds: false, - entrypoint: Uri.base, - testMode: true, - expressionCompiler: - null, // ignore: avoid_redundant_argument_values - extraHeaders: const {}, - chromiumLauncher: null, // ignore: avoid_redundant_argument_values - nullSafetyMode: NullSafetyMode.sound, - ddcModuleSystem: usesDdcModuleSystem, - webRenderer: WebRendererMode.canvaskit, - isWasm: false, - useLocalCanvasKit: false, - rootDirectory: globals.fs.currentDirectory, - ); - webDevFS.ddcModuleLoaderJS.createSync(recursive: true); - webDevFS.stackTraceMapper.createSync(recursive: true); - - await webDevFS.create(); - - expect( - webDevFS.webAssetServer.webRenderer, WebRendererMode.canvaskit); - - await webDevFS.destroy(); - })); - - test( - 'Can start web server with auto detect enabled', - () => testbed.run(() async { - final File outputFile = globals.fs - .file(globals.fs.path.join('lib', 'main.dart')) - ..createSync(recursive: true); - outputFile.parent.childFile('a.sources').writeAsStringSync(''); - outputFile.parent.childFile('a.json').writeAsStringSync('{}'); - outputFile.parent.childFile('a.map').writeAsStringSync('{}'); - - final WebDevFS webDevFS = WebDevFS( - hostname: 'localhost', - port: 0, - tlsCertPath: null, - tlsCertKeyPath: null, - packagesFilePath: '.dart_tool/package_config.json', - urlTunneller: null, // ignore: avoid_redundant_argument_values - useSseForDebugProxy: true, - useSseForDebugBackend: true, - useSseForInjectedClient: true, - nullAssertions: true, - nativeNullAssertions: true, - buildInfo: const BuildInfo( - BuildMode.debug, '', - treeShakeIcons: false, - dartDefines: [ - 'FLUTTER_WEB_AUTO_DETECT=true', - ], - packageConfigPath: '.dart_tool/package_config.json', - ), - enableDwds: false, - enableDds: false, - entrypoint: Uri.base, - testMode: true, - expressionCompiler: - null, // ignore: avoid_redundant_argument_values - extraHeaders: const {}, - chromiumLauncher: null, // ignore: avoid_redundant_argument_values - nullSafetyMode: NullSafetyMode.sound, - ddcModuleSystem: usesDdcModuleSystem, - webRenderer: WebRendererMode.auto, - isWasm: false, - useLocalCanvasKit: false, - rootDirectory: globals.fs.currentDirectory, - ); - webDevFS.ddcModuleLoaderJS.createSync(recursive: true); - webDevFS.stackTraceMapper.createSync(recursive: true); - - await webDevFS.create(); - - expect(webDevFS.webAssetServer.webRenderer, WebRendererMode.auto); - - await webDevFS.destroy(); - })); - - test( - 'Can start web server with tls connection', - () => testbed.run(() async { - final String dataPath = globals.fs.path.join( - getFlutterRoot(), - 'packages', - 'flutter_tools', - 'test', - 'data', - 'asset_test', - ); - - final String dummyCertPath = - globals.fs.path.join(dataPath, 'tls_cert', 'dummy-cert.pem'); - final String dummyCertKeyPath = - globals.fs.path.join(dataPath, 'tls_cert', 'dummy-key.pem'); - - final WebDevFS webDevFS = WebDevFS( - hostname: 'localhost', - port: 0, - tlsCertPath: dummyCertPath, - tlsCertKeyPath: dummyCertKeyPath, - packagesFilePath: '.dart_tool/package_config.json', - urlTunneller: null, // ignore: avoid_redundant_argument_values - useSseForDebugProxy: true, - useSseForDebugBackend: true, - useSseForInjectedClient: true, - nullAssertions: true, - nativeNullAssertions: true, - buildInfo: BuildInfo.debug, - enableDwds: false, - enableDds: false, - entrypoint: Uri.base, - testMode: true, - expressionCompiler: - null, // ignore: avoid_redundant_argument_values - extraHeaders: const {}, - chromiumLauncher: null, // ignore: avoid_redundant_argument_values - nullSafetyMode: NullSafetyMode.unsound, - ddcModuleSystem: usesDdcModuleSystem, - webRenderer: WebRendererMode.canvaskit, - isWasm: false, - useLocalCanvasKit: false, - rootDirectory: globals.fs.currentDirectory, - ); - webDevFS.ddcModuleLoaderJS.createSync(recursive: true); - webDevFS.stackTraceMapper.createSync(recursive: true); - - final Uri uri = await webDevFS.create(); - - // Ensure the connection established is secure - expect(uri.scheme, 'https'); - - await webDevFS.destroy(); - }, overrides: { - Artifacts: () => Artifacts.test(), - })); - - test('allows frame embedding', () async { - final WebAssetServer webAssetServer = await WebAssetServer.start( - null, - 'localhost', - 0, - null, - null, - null, - true, - true, - true, - const BuildInfo( + @isTest + void runInTestbed( + String description, + FutureOr Function() body, { + Map? overrides, + }) { + test(description, () => testbed.run(body, overrides: overrides)); + } + + runInTestbed('.log() reports warnings', () { + const String unresolvedUriMessage = 'Unresolved uri:'; + const String otherMessage = 'Something bad happened'; + + final List events = [ + logging.LogRecord(logging.Level.WARNING, unresolvedUriMessage, 'DartUri'), + logging.LogRecord(logging.Level.WARNING, otherMessage, 'DartUri'), + ]; + + events.forEach(log); + expect(logger.warningText, contains(unresolvedUriMessage)); + expect(logger.warningText, contains(otherMessage)); + }); + + runInTestbed('Handles against malformed manifest', () async { + final File source = globals.fs.file('source') + ..writeAsStringSync('main() {}'); + final File sourcemap = globals.fs.file('sourcemap') + ..writeAsStringSync('{}'); + final File metadata = globals.fs.file('metadata') + ..writeAsStringSync('{}'); + + // Missing ending offset. + final File manifestMissingOffset = globals.fs.file('manifestA') + ..writeAsStringSync(json.encode({ + '/foo.js': { + 'code': [0], + 'sourcemap': [0], + 'metadata': [0], + }, + })); + final File manifestOutOfBounds = globals.fs.file('manifest') + ..writeAsStringSync(json.encode({ + '/foo.js': { + 'code': [0, 100], + 'sourcemap': [0], + 'metadata': [0], + }, + })); + + expect( + webAssetServer.write(source, manifestMissingOffset, sourcemap, metadata), + isEmpty, + ); + expect( + webAssetServer.write(source, manifestOutOfBounds, sourcemap, metadata), + isEmpty, + ); + }); + + runInTestbed('serves JavaScript files from memory cache', () async { + final File source = globals.fs.file('source') + ..writeAsStringSync('main() {}'); + final File sourcemap = globals.fs.file('sourcemap') + ..writeAsStringSync('{}'); + final File metadata = globals.fs.file('metadata') + ..writeAsStringSync('{}'); + final File manifest = globals.fs.file('manifest') + ..writeAsStringSync(json.encode({ + '/foo.js': { + 'code': [0, source.lengthSync()], + 'sourcemap': [0, 2], + 'metadata': [0, 2], + }, + })); + webAssetServer.write(source, manifest, sourcemap, metadata); + + final Response response = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http://foobar/foo.js')), + ); + + expect(response.headers, allOf( + containsPair(HttpHeaders.contentLengthHeader, source.lengthSync().toString()), + containsPair(HttpHeaders.contentTypeHeader, 'application/javascript'), + containsPair(HttpHeaders.etagHeader, isNotNull), + )); + expect((await response.read().toList()).first, source.readAsBytesSync()); + }, overrides: {Platform: () => linux}); + + runInTestbed('serves metadata files from memory cache', () async { + const String metadataContents = '{"name":"foo"}'; + final File source = globals.fs.file('source') + ..writeAsStringSync('main() {}'); + final File sourcemap = globals.fs.file('sourcemap') + ..writeAsStringSync('{}'); + final File metadata = globals.fs.file('metadata') + ..writeAsStringSync(metadataContents); + final File manifest = globals.fs.file('manifest') + ..writeAsStringSync(json.encode({ + '/foo.js': { + 'code': [0, source.lengthSync()], + 'sourcemap': [0, sourcemap.lengthSync()], + 'metadata': [0, metadata.lengthSync()], + }, + })); + webAssetServer.write(source, manifest, sourcemap, metadata); + + final String? merged = await webAssetServer.metadataContents('main_module.ddc_merged_metadata'); + expect(merged, equals(metadataContents)); + + final String? single = await webAssetServer.metadataContents('foo.js.metadata'); + expect(single, equals(metadataContents)); + }, overrides: {Platform: () => linux}); + + // Ensures that no requests are made outside of served directory. + runInTestbed('Removes leading slashes for valid requests', () async { + globals.fs.file('foo.png').createSync(); + globals.fs.currentDirectory = globals.fs.directory('project_directory') + ..createSync(); + + final File source = globals.fs.file(globals.fs.path.join('web', 'foo.png')) + ..createSync(recursive: true) + ..writeAsBytesSync(kTransparentImage); + final Response response = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http://foobar////foo.png')), + ); + + expect(response.headers, allOf( + containsPair(HttpHeaders.contentLengthHeader, source.lengthSync().toString()), + containsPair(HttpHeaders.contentTypeHeader, 'image/png'), + containsPair(HttpHeaders.etagHeader, isNotNull), + containsPair(HttpHeaders.cacheControlHeader, 'max-age=0, must-revalidate'), + )); + expect((await response.read().toList()).first, source.readAsBytesSync()); + }); + + runInTestbed('takes base path into account when serving', () async { + webAssetServer.basePath = 'base/path'; + + globals.fs.file('foo.png').createSync(); + globals.fs.currentDirectory = globals.fs.directory('project_directory') + ..createSync(); + + final File source = globals.fs.file(globals.fs.path.join('web', 'foo.png')) + ..createSync(recursive: true) + ..writeAsBytesSync(kTransparentImage); + final Response response = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http://foobar/base/path/foo.png')), + ); + + expect(response.headers, allOf( + containsPair(HttpHeaders.contentLengthHeader, source.lengthSync().toString()), + containsPair(HttpHeaders.contentTypeHeader, 'image/png'), + containsPair(HttpHeaders.etagHeader, isNotNull), + containsPair(HttpHeaders.cacheControlHeader, 'max-age=0, must-revalidate'), + )); + expect((await response.read().toList()).first, source.readAsBytesSync()); + }); + + runInTestbed('serves index.html at the base path', () async { + webAssetServer.basePath = 'base/path'; + + const String htmlContent = ''; + final Directory webDir = globals.fs.currentDirectory.childDirectory('web') + ..createSync(); + webDir.childFile('index.html').writeAsStringSync(htmlContent); + + final String flutterJsPath = globals.fs.path.join( + globals.artifacts!.getHostArtifact(HostArtifact.flutterJsDirectory).path, + 'flutter.js', + ); + globals.fs.file(flutterJsPath) + ..createSync(recursive: true) + ..writeAsStringSync('flutter.js content'); + + final Response response = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http://foobar/base/path/')), + ); + + expect(response.statusCode, HttpStatus.ok); + expect(await response.readAsString(), htmlContent); + }); + + runInTestbed('serves index.html at / if href attribute is $kBaseHrefPlaceholder', () async { + const String htmlContent = ''; + final Directory webDir = globals.fs.currentDirectory.childDirectory('web')..createSync(); + webDir.childFile('index.html').writeAsStringSync(htmlContent); + + final String flutterJsPath = globals.fs.path.join( + globals.artifacts!.getHostArtifact(HostArtifact.flutterJsDirectory).path, + 'flutter.js', + ); + globals.fs.file(flutterJsPath) + ..createSync(recursive: true) + ..writeAsStringSync('flutter.js content'); + + final Response response = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http://foobar/')), + ); + + expect(response.statusCode, HttpStatus.ok); + expect(await response.readAsString(), htmlContent.replaceAll(kBaseHrefPlaceholder, '/')); + }); + + runInTestbed('does not serve outside the base path', () async { + webAssetServer.basePath = 'base/path'; + + const String htmlContent = ''; + final Directory webDir = globals.fs.currentDirectory.childDirectory('web')..createSync(); + webDir.childFile('index.html').writeAsStringSync(htmlContent); + + final Response response = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http://foobar/')), + ); + + expect(response.statusCode, HttpStatus.notFound); + }); + + runInTestbed('parses base path from index.html', () async { + const String htmlContent = ''; + final Directory webDir = globals.fs.currentDirectory.childDirectory('web')..createSync(); + webDir.childFile('index.html').writeAsStringSync(htmlContent); + + final WebAssetServer webAssetServer = WebAssetServer( + httpServer, + packages, + InternetAddress.loopbackIPv4, + {}, + {}, + NullSafetyMode.unsound, + usesDdcModuleSystem, + webRenderer: WebRendererMode.canvaskit, + useLocalCanvasKit: false, + ); + + expect(webAssetServer.basePath, 'foo/bar'); + }); + + runInTestbed('handles lack of base path in index.html', () async { + const String htmlContent = ''; + final Directory webDir = globals.fs.currentDirectory.childDirectory('web')..createSync(); + webDir.childFile('index.html').writeAsStringSync(htmlContent); + + final WebAssetServer webAssetServer = WebAssetServer( + httpServer, + packages, + InternetAddress.loopbackIPv4, + {}, + {}, + NullSafetyMode.unsound, + usesDdcModuleSystem, + webRenderer: WebRendererMode.canvaskit, + useLocalCanvasKit: false, + ); + + // Defaults to "/" when there's no base element. + expect(webAssetServer.basePath, ''); + }); + + runInTestbed('throws if base path is relative', () async { + const String htmlContent = ''; + final Directory webDir = globals.fs.currentDirectory.childDirectory('web')..createSync(); + webDir.childFile('index.html').writeAsStringSync(htmlContent); + + expect( + () => WebAssetServer( + httpServer, + packages, + InternetAddress.loopbackIPv4, + {}, + {}, + NullSafetyMode.unsound, + usesDdcModuleSystem, + webRenderer: WebRendererMode.canvaskit, + useLocalCanvasKit: false, + ), + throwsToolExit(), + ); + }); + + runInTestbed('throws if base path does not end with slash', () async { + const String htmlContent = ''; + final Directory webDir = globals.fs.currentDirectory.childDirectory('web')..createSync(); + webDir.childFile('index.html').writeAsStringSync(htmlContent); + + expect( + () => WebAssetServer( + httpServer, + packages, + InternetAddress.loopbackIPv4, + {}, + {}, + NullSafetyMode.unsound, + usesDdcModuleSystem, + webRenderer: WebRendererMode.canvaskit, + useLocalCanvasKit: false, + ), + throwsToolExit(), + ); + }); + + runInTestbed('serves JavaScript files from memory cache not from manifest', () async { + webAssetServer.writeFile('foo.js', 'main() {}'); + + final Response response = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http://foobar/foo.js')), + ); + + expect(response.headers, allOf( + containsPair(HttpHeaders.contentLengthHeader, '9'), + containsPair(HttpHeaders.contentTypeHeader, 'application/javascript'), + containsPair(HttpHeaders.etagHeader, isNotNull), + containsPair(HttpHeaders.cacheControlHeader, 'max-age=0, must-revalidate'), + )); + expect((await response.read().toList()).first, utf8.encode('main() {}')); + }); + + runInTestbed('Returns notModified when the ifNoneMatch header matches the etag', () async { + webAssetServer.writeFile('foo.js', 'main() {}'); + + final Response response = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http://foobar/foo.js')), + ); + final Map requestHeaders = { + HttpHeaders.ifNoneMatchHeader: response.headers[HttpHeaders.etagHeader]!, + }; + final Response cachedResponse = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http://foobar/foo.js'), headers: requestHeaders), + ); + + expect(cachedResponse.statusCode, HttpStatus.notModified); + expect(await cachedResponse.read().toList(), isEmpty); + }); + + runInTestbed('serves index.html when path is unknown', () async { + const String htmlContent = ''; + final Directory webDir = globals.fs.currentDirectory.childDirectory('web')..createSync(); + webDir.childFile('index.html').writeAsStringSync(htmlContent); + final String flutterJsPath = globals.fs.path.join( + globals.artifacts!.getHostArtifact(HostArtifact.flutterJsDirectory).path, + 'flutter.js', + ); + globals.fs.file(flutterJsPath) + ..createSync(recursive: true) + ..writeAsStringSync('flutter.js content'); + + final Response response = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http://foobar/bar/baz')), + ); + + expect(response.statusCode, HttpStatus.ok); + expect(await response.readAsString(), htmlContent); + }); + + runInTestbed('does not serve outside the base path', () async { + webAssetServer.basePath = 'base/path'; + + const String htmlContent =''; + final Directory webDir = globals.fs.currentDirectory.childDirectory('web')..createSync(); + webDir.childFile('index.html').writeAsStringSync(htmlContent); + + final Response response = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http://foobar/')), + ); + + expect(response.statusCode, HttpStatus.notFound); + }); + + runInTestbed('does not serve index.html when path is inside assets or packages', () async { + const String htmlContent = ''; + final Directory webDir = globals.fs.currentDirectory.childDirectory('web')..createSync(); + webDir.childFile('index.html').writeAsStringSync(htmlContent); + + Response response = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http://foobar/assets/foo/bar.png')), + ); + expect(response.statusCode, HttpStatus.notFound); + + response = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http://foobar/packages/foo/bar.dart.js')), + ); + expect(response.statusCode, HttpStatus.notFound); + + webAssetServer.basePath = 'base/path'; + + response = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http://foobar/base/path/assets/foo/bar.png')), + ); + expect(response.statusCode, HttpStatus.notFound); + + response = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http://foobar/base/path/packages/foo/bar.dart.js')), + ); + expect(response.statusCode, HttpStatus.notFound); + }); + + runInTestbed('serves default index.html', () async { + final String flutterJsPath = globals.fs.path.join( + globals.artifacts!.getHostArtifact(HostArtifact.flutterJsDirectory).path, + 'flutter.js', + ); + globals.fs.file(flutterJsPath) + ..createSync(recursive: true) + ..writeAsStringSync('flutter.js content'); + + final Response response = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http://foobar/')), + ); + + expect(response.statusCode, HttpStatus.ok); + expect( + (await response.read().toList()).first, + containsAllInOrder(utf8.encode('')), + ); + }); + + runInTestbed('handles web server paths without .lib extension', () async { + final File source = globals.fs.file('source') + ..writeAsStringSync('main() {}'); + final File sourcemap = globals.fs.file('sourcemap') + ..writeAsStringSync('{}'); + final File metadata = globals.fs.file('metadata') + ..writeAsStringSync('{}'); + final File manifest = globals.fs.file('manifest') + ..writeAsStringSync(json.encode({ + '/foo.dart.lib.js': { + 'code': [0, source.lengthSync()], + 'sourcemap': [0, 2], + 'metadata': [0, 2], + }, + })); + webAssetServer.write(source, manifest, sourcemap, metadata); + + final Response response = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http://foobar/foo.dart.js')), + ); + + expect(response.statusCode, HttpStatus.ok); + }); + + runInTestbed('serves JavaScript files from memory cache on Windows', () async { + final File source = globals.fs.file('source') + ..writeAsStringSync('main() {}'); + final File sourcemap = globals.fs.file('sourcemap') + ..writeAsStringSync('{}'); + final File metadata = globals.fs.file('metadata') + ..writeAsStringSync('{}'); + final File manifest = globals.fs.file('manifest') + ..writeAsStringSync(json.encode({ + '/foo.js': { + 'code': [0, source.lengthSync()], + 'sourcemap': [0, 2], + 'metadata': [0, 2], + }, + })); + webAssetServer.write(source, manifest, sourcemap, metadata); + final Response response = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http://localhost/foo.js')), + ); + + expect(response.headers, allOf( + containsPair(HttpHeaders.contentLengthHeader, source.lengthSync().toString()), + containsPair(HttpHeaders.contentTypeHeader, 'application/javascript'), + containsPair(HttpHeaders.etagHeader, isNotNull), + containsPair(HttpHeaders.cacheControlHeader, 'max-age=0, must-revalidate'), + )); + expect((await response.read().toList()).first, source.readAsBytesSync()); + }, overrides: {Platform: () => windows}); + + runInTestbed('serves asset files from filesystem with url-encoded paths', () async { + final String path = globals.fs.path.join( + 'build', + 'flutter_assets', + Uri.encodeFull('abcd象形字.png'), + ); + final File source = globals.fs.file(path) + ..createSync(recursive: true) + ..writeAsBytesSync(kTransparentImage); + final Response response = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http://foobar/assets/abcd%25E8%25B1%25A1%25E5%25BD%25A2%25E5%25AD%2597.png')), + ); + + expect(response.headers, allOf( + containsPair(HttpHeaders.contentLengthHeader, source.lengthSync().toString()), + containsPair(HttpHeaders.contentTypeHeader, 'image/png'), + containsPair(HttpHeaders.etagHeader, isNotNull), + containsPair(HttpHeaders.cacheControlHeader, 'max-age=0, must-revalidate'), + )); + expect((await response.read().toList()).first, source.readAsBytesSync()); + }); + + runInTestbed('serves files from web directory', () async { + final File source = globals.fs.file(globals.fs.path.join('web', 'foo.png')) + ..createSync(recursive: true) + ..writeAsBytesSync(kTransparentImage); + final Response response = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http://foobar/foo.png')), + ); + + expect(response.headers, allOf( + containsPair(HttpHeaders.contentLengthHeader, source.lengthSync().toString()), + containsPair(HttpHeaders.contentTypeHeader, 'image/png'), + containsPair(HttpHeaders.etagHeader, isNotNull), + containsPair(HttpHeaders.cacheControlHeader, 'max-age=0, must-revalidate'), + )); + expect((await response.read().toList()).first, source.readAsBytesSync()); + }); + + runInTestbed('serves asset files from filesystem with known mime type on Windows', () async { + final String path = globals.fs.path.join('build', 'flutter_assets', 'foo.png'); + final File source = globals.fs.file(path) + ..createSync(recursive: true) + ..writeAsBytesSync(kTransparentImage); + final Response response = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http://foobar/assets/foo.png')), + ); + + expect(response.headers, allOf( + containsPair(HttpHeaders.contentLengthHeader, source.lengthSync().toString()), + containsPair(HttpHeaders.contentTypeHeader, 'image/png'), + containsPair(HttpHeaders.etagHeader, isNotNull), + containsPair(HttpHeaders.cacheControlHeader, 'max-age=0, must-revalidate'), + )); + expect((await response.read().toList()).first, source.readAsBytesSync()); + }, overrides: {Platform: () => windows}); + + runInTestbed('serves Dart files from filesystem on Linux/macOS', () async { + final File source = globals.fs.file('foo.dart').absolute + ..createSync(recursive: true) + ..writeAsStringSync('void main() {}'); + + final Response response = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http://foobar/foo.dart')), + ); + + expect( + response.headers, + containsPair(HttpHeaders.contentLengthHeader, source.lengthSync().toString()), + ); + expect((await response.read().toList()).first, source.readAsBytesSync()); + }, overrides: {Platform: () => linux}); + + runInTestbed('serves asset files from filesystem with known mime type', () async { + final String path = globals.fs.path.join('build', 'flutter_assets', 'foo.png'); + final File source = globals.fs.file(path) + ..createSync(recursive: true) + ..writeAsBytesSync(kTransparentImage); + + final Response response = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http://foobar/assets/foo.png')), + ); + + expect(response.headers, allOf( + containsPair(HttpHeaders.contentLengthHeader, source.lengthSync().toString()), + containsPair(HttpHeaders.contentTypeHeader, 'image/png'), + )); + expect((await response.read().toList()).first, source.readAsBytesSync()); + }); + + runInTestbed('serves asset files from filesystem with known mime type and empty content', () async { + final String path = globals.fs.path.join('web', 'foo.js'); + final File source = globals.fs.file(path) + ..createSync(recursive: true); + + final Response response = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http://foobar/foo.js')), + ); + + expect(response.headers, allOf( + containsPair(HttpHeaders.contentLengthHeader, '0'), + containsPair(HttpHeaders.contentTypeHeader, 'text/javascript'), + )); + expect((await response.read().toList()).first, source.readAsBytesSync()); + }); + + runInTestbed('serves asset files from filesystem with unknown mime type', () async { + final String path = globals.fs.path.join('build', 'flutter_assets', 'foo'); + final File source = globals.fs.file(path) + ..createSync(recursive: true) + ..writeAsBytesSync(List.filled(100, 0)); + + final Response response = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http://foobar/assets/foo')), + ); + + expect(response.headers, allOf( + containsPair(HttpHeaders.contentLengthHeader, '100'), + containsPair(HttpHeaders.contentTypeHeader, 'application/octet-stream'), + )); + expect((await response.read().toList()).first, source.readAsBytesSync()); + }); + + runInTestbed('serves valid etag header for asset files with non-ascii characters', () async { + final String path = globals.fs.path.join('build', 'flutter_assets', 'fooπ'); + globals.fs.file(path) + ..createSync(recursive: true) + ..writeAsBytesSync([1, 2, 3]); + + final Response response = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http://foobar/assets/fooπ')), + ); + final String etag = response.headers[HttpHeaders.etagHeader]!; + + expect(etag.runes, everyElement(predicate((int char) => char < 255))); + }); + + runInTestbed('serves /packages// files as if they were package:/ uris', () async { + final String path = globals.fs.path.fromUri( + packages.resolve(Uri.parse('package:flutter_tools/foo.dart')), + ); + final File source = globals.fs.file(path) + ..createSync(recursive: true) + ..writeAsBytesSync([1, 2, 3]); + + final Response response = await webAssetServer.handleRequest( + Request('GET', Uri.parse('http:///packages/flutter_tools/foo.dart')), + ); + + expect(response.headers, allOf( + containsPair(HttpHeaders.contentLengthHeader, '3'), + containsPair(HttpHeaders.contentTypeHeader, 'text/x-dart'), + )); + expect((await response.read().toList()).first, source.readAsBytesSync()); + }); + + runInTestbed('calling dispose closes the HTTP server', () async { + await webAssetServer.dispose(); + expect(httpServer.closed, true); + }); + + runInTestbed('Can start web server with specified DDC module system assets', () async { + final String path = globals.fs.path.join('lib', 'main.dart'); + final File outputFile = globals.fs.file(path) + ..createSync(recursive: true); + outputFile.parent.childFile('a.sources').writeAsStringSync(''); + outputFile.parent.childFile('a.json').writeAsStringSync('{}'); + outputFile.parent.childFile('a.map').writeAsStringSync('{}'); + outputFile.parent.childFile('a.metadata').writeAsStringSync('{}'); + + final ResidentCompiler residentCompiler = FakeResidentCompiler() + ..output = const CompilerOutput('a', 0, []); + + final WebDevFS webDevFS = WebDevFS( + hostname: 'localhost', + port: 0, + tlsCertPath: null, + tlsCertKeyPath: null, + packagesFilePath: '.dart_tool/package_config.json', + urlTunneller: null, + useSseForDebugProxy: true, + useSseForDebugBackend: true, + useSseForInjectedClient: true, + nullAssertions: true, + nativeNullAssertions: true, + buildInfo: const BuildInfo( + BuildMode.debug, + '', + treeShakeIcons: false, + nullSafetyMode: NullSafetyMode.unsound, + packageConfigPath: '.dart_tool/package_config.json', + ), + enableDwds: false, + enableDds: false, + entrypoint: Uri.base, + testMode: true, + expressionCompiler: null, + extraHeaders: const {}, + chromiumLauncher: null, + nullSafetyMode: NullSafetyMode.unsound, + ddcModuleSystem: usesDdcModuleSystem, + webRenderer: WebRendererMode.html, + isWasm: false, + useLocalCanvasKit: false, + rootDirectory: globals.fs.currentDirectory, + ); + webDevFS.ddcModuleLoaderJS.createSync(recursive: true); + webDevFS.flutterJs.createSync(recursive: true); + webDevFS.stackTraceMapper.createSync(recursive: true); + + final Uri uri = await webDevFS.create(); + webDevFS.webAssetServer.entrypointCacheDirectory = globals.fs.currentDirectory; + final String webPrecompiledSdk = globals.artifacts! + .getHostArtifact(HostArtifact.webPrecompiledDdcSdk) + .path; + final String webPrecompiledSdkSourcemaps = globals.artifacts! + .getHostArtifact(HostArtifact.webPrecompiledDdcSdkSourcemaps) + .path; + final String webPrecompiledCanvaskitSdk = globals.artifacts! + .getHostArtifact(HostArtifact.webPrecompiledDdcCanvaskitSdk) + .path; + final String webPrecompiledCanvaskitSdkSourcemaps = globals + .artifacts! + .getHostArtifact( + HostArtifact.webPrecompiledDdcCanvaskitSdkSourcemaps) + .path; + globals.fs.currentDirectory.childDirectory('lib').childFile('web_entrypoint.dart') + ..createSync(recursive: true) + ..writeAsStringSync('GENERATED'); + globals.fs.file(webPrecompiledSdk) + ..createSync(recursive: true) + ..writeAsStringSync('HELLO'); + globals.fs.file(webPrecompiledSdkSourcemaps) + ..createSync(recursive: true) + ..writeAsStringSync('THERE'); + globals.fs.file(webPrecompiledCanvaskitSdk) + ..createSync(recursive: true) + ..writeAsStringSync('OL'); + globals.fs.file(webPrecompiledCanvaskitSdkSourcemaps) + ..createSync(recursive: true) + ..writeAsStringSync('CHUM'); + + await webDevFS.update( + mainUri: globals.fs.file(globals.fs.path.join('lib', 'main.dart')).uri, + generator: residentCompiler, + trackWidgetCreation: true, + bundleFirstUpload: true, + invalidatedFiles: [], + packageConfig: PackageConfig.empty, + pathToReload: '', + dillOutputPath: 'out.dill', + shaderCompiler: const FakeShaderCompiler(), + ); + + expect(webDevFS.webAssetServer.getFile('ddc_module_loader.js'), isNotNull); + expect(webDevFS.webAssetServer.getFile('stack_trace_mapper.js'), isNotNull); + expect(webDevFS.webAssetServer.getFile('main.dart'), isNotNull); + expect(webDevFS.webAssetServer.getFile('manifest.json'), isNotNull); + expect(webDevFS.webAssetServer.getFile('flutter.js'), isNotNull); + expect(webDevFS.webAssetServer.getFile('flutter_service_worker.js'), isNotNull); + expect(webDevFS.webAssetServer.getFile('version.json'), isNotNull); + expect(await webDevFS.webAssetServer.dartSourceContents('dart_sdk.js'), 'HELLO'); + expect(await webDevFS.webAssetServer.dartSourceContents('dart_sdk.js.map'), 'THERE'); + + // Update to the SDK. + globals.fs.file(webPrecompiledSdk).writeAsStringSync('BELLOW'); + + // New SDK should be visible.. + expect( + await webDevFS.webAssetServer.dartSourceContents('dart_sdk.js'), + 'BELLOW', + ); + + // Generated entrypoint. + expect( + await webDevFS.webAssetServer.dartSourceContents('web_entrypoint.dart'), + contains('GENERATED'), + ); + + // served on localhost + expect(uri.host, 'localhost'); + + await webDevFS.destroy(); + }, overrides: {Artifacts: Artifacts.test}); + + runInTestbed('Can start web server with specified assets in sound null safety mode', () async { + final String path = globals.fs.path.join('lib', 'main.dart'); + final File outputFile = globals.fs.file(path) + ..createSync(recursive: true); + outputFile.parent.childFile('a.sources').writeAsStringSync(''); + outputFile.parent.childFile('a.json').writeAsStringSync('{}'); + outputFile.parent.childFile('a.map').writeAsStringSync('{}'); + outputFile.parent.childFile('a.metadata').writeAsStringSync('{}'); + + final ResidentCompiler residentCompiler = FakeResidentCompiler() + ..output = const CompilerOutput('a', 0, []); + + final WebDevFS webDevFS = WebDevFS( + hostname: 'localhost', + port: 0, + tlsCertPath: null, + tlsCertKeyPath: null, + packagesFilePath: '.dart_tool/package_config.json', + urlTunneller: null, + useSseForDebugProxy: true, + useSseForDebugBackend: true, + useSseForInjectedClient: true, + nullAssertions: true, + nativeNullAssertions: true, + buildInfo: const BuildInfo( + BuildMode.debug, + '', + treeShakeIcons: false, + packageConfigPath: '.dart_tool/package_config.json', + ), + enableDwds: false, + enableDds: false, + entrypoint: Uri.base, + testMode: true, + expressionCompiler: null, + extraHeaders: const {}, + chromiumLauncher: null, + nullSafetyMode: NullSafetyMode.sound, + ddcModuleSystem: usesDdcModuleSystem, + webRenderer: WebRendererMode.html, + isWasm: false, + useLocalCanvasKit: false, + rootDirectory: globals.fs.currentDirectory, + ); + webDevFS.ddcModuleLoaderJS.createSync(recursive: true); + webDevFS.flutterJs.createSync(recursive: true); + webDevFS.stackTraceMapper.createSync(recursive: true); + + final Uri uri = await webDevFS.create(); + webDevFS.webAssetServer.entrypointCacheDirectory = globals.fs.currentDirectory; + globals.fs.currentDirectory.childDirectory('lib').childFile('web_entrypoint.dart') + ..createSync(recursive: true) + ..writeAsStringSync('GENERATED'); + final String webPrecompiledSdk = globals.artifacts! + .getHostArtifact(HostArtifact.webPrecompiledDdcSoundSdk) + .path; + final String webPrecompiledSdkSourcemaps = globals.artifacts! + .getHostArtifact(HostArtifact.webPrecompiledDdcSoundSdkSourcemaps) + .path; + final String webPrecompiledCanvaskitSdk = globals.artifacts! + .getHostArtifact(HostArtifact.webPrecompiledDdcCanvaskitSoundSdk) + .path; + final String webPrecompiledCanvaskitSdkSourcemaps = globals + .artifacts! + .getHostArtifact(HostArtifact.webPrecompiledDdcCanvaskitSoundSdkSourcemaps) + .path; + globals.fs.file(webPrecompiledSdk) + ..createSync(recursive: true) + ..writeAsStringSync('HELLO'); + globals.fs.file(webPrecompiledSdkSourcemaps) + ..createSync(recursive: true) + ..writeAsStringSync('THERE'); + globals.fs.file(webPrecompiledCanvaskitSdk) + ..createSync(recursive: true) + ..writeAsStringSync('OL'); + globals.fs.file(webPrecompiledCanvaskitSdkSourcemaps) + ..createSync(recursive: true) + ..writeAsStringSync('CHUM'); + + await webDevFS.update( + mainUri: globals.fs.file(globals.fs.path.join('lib', 'main.dart')).uri, + generator: residentCompiler, + trackWidgetCreation: true, + bundleFirstUpload: true, + invalidatedFiles: [], + packageConfig: PackageConfig.empty, + pathToReload: '', + dillOutputPath: '', + shaderCompiler: const FakeShaderCompiler(), + ); + + expect(webDevFS.webAssetServer.getFile('ddc_module_loader.js'), isNotNull); + expect(webDevFS.webAssetServer.getFile('stack_trace_mapper.js'), isNotNull); + expect(webDevFS.webAssetServer.getFile('main.dart'), isNotNull); + expect(webDevFS.webAssetServer.getFile('manifest.json'), isNotNull); + expect(webDevFS.webAssetServer.getFile('flutter.js'), isNotNull); + expect(webDevFS.webAssetServer.getFile('flutter_service_worker.js'), isNotNull); + expect(webDevFS.webAssetServer.getFile('version.json'), isNotNull); + expect(await webDevFS.webAssetServer.dartSourceContents('dart_sdk.js'), 'HELLO'); + expect(await webDevFS.webAssetServer.dartSourceContents('dart_sdk.js.map'), 'THERE'); + + // Update to the SDK. + globals.fs.file(webPrecompiledSdk).writeAsStringSync('BELLOW'); + + // New SDK should be visible.. + expect( + await webDevFS.webAssetServer.dartSourceContents('dart_sdk.js'), + 'BELLOW', + ); + + // Generated entrypoint. + expect( + await webDevFS.webAssetServer.dartSourceContents('web_entrypoint.dart'), + contains('GENERATED'), + ); + + // served on localhost + expect(uri.host, 'localhost'); + + await webDevFS.destroy(); + }, overrides: {Artifacts: Artifacts.test}); + + runInTestbed('.connect() will never call vmServiceFactory twice', () async { + await FakeAsync().run>((FakeAsync time) { + final String path = globals.fs.path.join('lib', 'main.dart'); + final File outputFile = globals.fs.file(path) + ..createSync(recursive: true); + outputFile.parent.childFile('a.sources').writeAsStringSync(''); + outputFile.parent.childFile('a.json').writeAsStringSync('{}'); + outputFile.parent.childFile('a.map').writeAsStringSync('{}'); + outputFile.parent.childFile('a.metadata').writeAsStringSync('{}'); + + final WebDevFS webDevFS = WebDevFS( + // if this is any other value, we will do a real ip lookup + hostname: 'any', + port: 0, + tlsCertPath: null, + tlsCertKeyPath: null, + packagesFilePath: '.dart_tool/package_config.json', + urlTunneller: null, + useSseForDebugProxy: true, + useSseForDebugBackend: true, + useSseForInjectedClient: true, + nullAssertions: true, + nativeNullAssertions: true, + buildInfo: const BuildInfo( BuildMode.debug, '', treeShakeIcons: false, packageConfigPath: '.dart_tool/package_config.json', ), - false, - false, - Uri.base, - null, - const {}, - NullSafetyMode.unsound, + enableDwds: true, + enableDds: false, + entrypoint: Uri.base, + testMode: true, + expressionCompiler: null, + extraHeaders: const {}, + chromiumLauncher: null, + nullSafetyMode: NullSafetyMode.sound, + ddcModuleSystem: usesDdcModuleSystem, webRenderer: WebRendererMode.canvaskit, isWasm: false, useLocalCanvasKit: false, - testMode: true); + rootDirectory: globals.fs.currentDirectory, + ); + webDevFS.ddcModuleLoaderJS.createSync(recursive: true); + webDevFS.stackTraceMapper.createSync(recursive: true); + final FakeAppConnection firstConnection = FakeAppConnection(); + final FakeAppConnection secondConnection = FakeAppConnection(); + + final Future done = webDevFS.create().then((Uri _) { + // In non-test mode, webDevFS.create() would have initialized DWDS + webDevFS.webAssetServer.dwds = FakeDwds( + [firstConnection, secondConnection], + ); + + int vmServiceFactoryInvocationCount = 0; + Future vmServiceFactory( + Uri uri, { + CompressionOptions? compression, + required Logger logger, + }) { + if (vmServiceFactoryInvocationCount > 0) { + fail('Called vmServiceFactory twice!'); + } + vmServiceFactoryInvocationCount += 1; + return Future.delayed( + const Duration(seconds: 2), + FakeVmService.new, + ); + } + + return webDevFS + .connect(false, vmServiceFactory: vmServiceFactory) + .then((ConnectionResult? firstConnectionResult) => webDevFS.destroy()); + }); + time.elapse(const Duration(seconds: 1)); + time.elapse(const Duration(seconds: 2)); + return done; + }); + }, overrides: {Artifacts: Artifacts.test}); + + runInTestbed('Can start web server with hostname any', () async { + final String path = globals.fs.path.join('lib', 'main.dart'); + final File outputFile = globals.fs.file(path) + ..createSync(recursive: true); + outputFile.parent.childFile('a.sources').writeAsStringSync(''); + outputFile.parent.childFile('a.json').writeAsStringSync('{}'); + outputFile.parent.childFile('a.map').writeAsStringSync('{}'); + + final WebDevFS webDevFS = WebDevFS( + hostname: 'any', + port: 0, + tlsCertPath: null, + tlsCertKeyPath: null, + packagesFilePath: '.dart_tool/package_config.json', + urlTunneller: null, + useSseForDebugProxy: true, + useSseForDebugBackend: true, + useSseForInjectedClient: true, + buildInfo: BuildInfo.debug, + enableDwds: false, + enableDds: false, + entrypoint: Uri.base, + testMode: true, + expressionCompiler: null, + extraHeaders: const {}, + chromiumLauncher: null, + nullAssertions: true, + nativeNullAssertions: true, + nullSafetyMode: NullSafetyMode.sound, + ddcModuleSystem: usesDdcModuleSystem, + webRenderer: WebRendererMode.canvaskit, + isWasm: false, + useLocalCanvasKit: false, + rootDirectory: globals.fs.currentDirectory, + ); + webDevFS.ddcModuleLoaderJS.createSync(recursive: true); + webDevFS.stackTraceMapper.createSync(recursive: true); + + final Uri uri = await webDevFS.create(); + + expect(uri.host, 'localhost'); + await webDevFS.destroy(); + }); + + runInTestbed('Can start web server with canvaskit enabled', () async { + final String path = globals.fs.path.join('lib', 'main.dart'); + final File outputFile = globals.fs.file(path) + ..createSync(recursive: true); + outputFile.parent.childFile('a.sources').writeAsStringSync(''); + outputFile.parent.childFile('a.json').writeAsStringSync('{}'); + outputFile.parent.childFile('a.map').writeAsStringSync('{}'); + + final WebDevFS webDevFS = WebDevFS( + hostname: 'localhost', + port: 0, + tlsCertPath: null, + tlsCertKeyPath: null, + packagesFilePath: '.dart_tool/package_config.json', + urlTunneller: null, + useSseForDebugProxy: true, + useSseForDebugBackend: true, + useSseForInjectedClient: true, + nullAssertions: true, + nativeNullAssertions: true, + buildInfo: const BuildInfo( + BuildMode.debug, '', + treeShakeIcons: false, + dartDefines: ['FLUTTER_WEB_USE_SKIA=true'], + packageConfigPath: '.dart_tool/package_config.json', + ), + enableDwds: false, + enableDds: false, + entrypoint: Uri.base, + testMode: true, + expressionCompiler: null, + extraHeaders: const {}, + chromiumLauncher: null, + nullSafetyMode: NullSafetyMode.sound, + ddcModuleSystem: usesDdcModuleSystem, + webRenderer: WebRendererMode.canvaskit, + isWasm: false, + useLocalCanvasKit: false, + rootDirectory: globals.fs.currentDirectory, + ); + webDevFS.ddcModuleLoaderJS.createSync(recursive: true); + webDevFS.stackTraceMapper.createSync(recursive: true); + + await webDevFS.create(); + + expect(webDevFS.webAssetServer.webRenderer, WebRendererMode.canvaskit); + + await webDevFS.destroy(); + }); + + runInTestbed('Can start web server with auto detect enabled', () async { + final String path = globals.fs.path.join('lib', 'main.dart'); + final File outputFile = globals.fs.file(path) + ..createSync(recursive: true); + outputFile.parent.childFile('a.sources').writeAsStringSync(''); + outputFile.parent.childFile('a.json').writeAsStringSync('{}'); + outputFile.parent.childFile('a.map').writeAsStringSync('{}'); + + final WebDevFS webDevFS = WebDevFS( + hostname: 'localhost', + port: 0, + tlsCertPath: null, + tlsCertKeyPath: null, + packagesFilePath: '.dart_tool/package_config.json', + urlTunneller: null, + useSseForDebugProxy: true, + useSseForDebugBackend: true, + useSseForInjectedClient: true, + nullAssertions: true, + nativeNullAssertions: true, + buildInfo: const BuildInfo( + BuildMode.debug, '', + treeShakeIcons: false, + dartDefines: ['FLUTTER_WEB_AUTO_DETECT=true'], + packageConfigPath: '.dart_tool/package_config.json', + ), + enableDwds: false, + enableDds: false, + entrypoint: Uri.base, + testMode: true, + expressionCompiler: null, + extraHeaders: const {}, + chromiumLauncher: null, + nullSafetyMode: NullSafetyMode.sound, + ddcModuleSystem: usesDdcModuleSystem, + webRenderer: WebRendererMode.auto, + isWasm: false, + useLocalCanvasKit: false, + rootDirectory: globals.fs.currentDirectory, + ); + webDevFS.ddcModuleLoaderJS.createSync(recursive: true); + webDevFS.stackTraceMapper.createSync(recursive: true); + + await webDevFS.create(); + + expect(webDevFS.webAssetServer.webRenderer, WebRendererMode.auto); + + await webDevFS.destroy(); + }); + + runInTestbed('Can start web server with tls connection', () async { + final String dataPath = globals.fs.path.join( + getFlutterRoot(), + 'packages', + 'flutter_tools', + 'test', + 'data', + 'asset_test', + ); + + final String dummyCertPath = globals.fs.path.join(dataPath, 'tls_cert', 'dummy-cert.pem'); + final String dummyCertKeyPath = globals.fs.path.join(dataPath, 'tls_cert', 'dummy-key.pem'); + + final WebDevFS webDevFS = WebDevFS( + hostname: 'localhost', + port: 0, + tlsCertPath: dummyCertPath, + tlsCertKeyPath: dummyCertKeyPath, + packagesFilePath: '.dart_tool/package_config.json', + urlTunneller: null, + useSseForDebugProxy: true, + useSseForDebugBackend: true, + useSseForInjectedClient: true, + nullAssertions: true, + nativeNullAssertions: true, + buildInfo: BuildInfo.debug, + enableDwds: false, + enableDds: false, + entrypoint: Uri.base, + testMode: true, + expressionCompiler: null, + extraHeaders: const {}, + chromiumLauncher: null, + nullSafetyMode: NullSafetyMode.unsound, + ddcModuleSystem: usesDdcModuleSystem, + webRenderer: WebRendererMode.canvaskit, + isWasm: false, + useLocalCanvasKit: false, + rootDirectory: globals.fs.currentDirectory, + ); + webDevFS.ddcModuleLoaderJS.createSync(recursive: true); + webDevFS.stackTraceMapper.createSync(recursive: true); + + final Uri uri = await webDevFS.create(); + + // Ensure the connection established is secure + expect(uri.scheme, 'https'); + + await webDevFS.destroy(); + }, overrides: {Artifacts: Artifacts.test}); + + test('allows frame embedding', () async { + final WebAssetServer webAssetServer = await WebAssetServer.start( + null, + 'localhost', + 0, + null, + null, + null, + true, + true, + true, + const BuildInfo( + BuildMode.debug, + '', + treeShakeIcons: false, + packageConfigPath: '.dart_tool/package_config.json', + ), + false, + false, + Uri.base, + null, + const {}, + NullSafetyMode.unsound, + webRenderer: WebRendererMode.canvaskit, + isWasm: false, + useLocalCanvasKit: false, + testMode: true, + ); expect(webAssetServer.defaultResponseHeaders['x-frame-options'], null); await webAssetServer.dispose(); @@ -1505,151 +1279,137 @@ void main() { const String extraHeaderKey = 'hurray'; const String extraHeaderValue = 'flutter'; final WebAssetServer webAssetServer = await WebAssetServer.start( - null, - 'localhost', - 0, - null, - null, - null, - true, - true, - true, - const BuildInfo( - BuildMode.debug, - '', - treeShakeIcons: false, - packageConfigPath: '.dart_tool/package_config.json', - ), - false, - false, - Uri.base, - null, - const { - extraHeaderKey: extraHeaderValue, - }, - NullSafetyMode.unsound, - webRenderer: WebRendererMode.canvaskit, - isWasm: false, - useLocalCanvasKit: false, - testMode: true); + null, + 'localhost', + 0, + null, + null, + null, + true, + true, + true, + const BuildInfo( + BuildMode.debug, + '', + treeShakeIcons: false, + packageConfigPath: '.dart_tool/package_config.json', + ), + false, + false, + Uri.base, + null, + const { + extraHeaderKey: extraHeaderValue, + }, + NullSafetyMode.unsound, + webRenderer: WebRendererMode.canvaskit, + isWasm: false, + useLocalCanvasKit: false, + testMode: true, + ); - expect(webAssetServer.defaultResponseHeaders[extraHeaderKey], - [extraHeaderValue]); + expect( + webAssetServer.defaultResponseHeaders[extraHeaderKey], + [extraHeaderValue], + ); await webAssetServer.dispose(); }); - test( - 'WebAssetServer responds to POST requests with 404 not found', - () => testbed.run(() async { - final Response response = await webAssetServer.handleRequest( - Request('POST', Uri.parse('http://foobar/something')), - ); - expect(response.statusCode, 404); - })); + runInTestbed('WebAssetServer responds to POST requests with 404 not found', () async { + final Response response = await webAssetServer.handleRequest( + Request('POST', Uri.parse('http://foobar/something')), + ); + expect(response.statusCode, 404); + }); - test( - 'ReleaseAssetServer responds to POST requests with 404 not found', - () => testbed.run(() async { - final Response response = await releaseAssetServer.handle( - Request('POST', Uri.parse('http://foobar/something')), - ); - expect(response.statusCode, 404); - })); + runInTestbed('ReleaseAssetServer responds to POST requests with 404 not found', () async { + final Response response = await releaseAssetServer.handle( + Request('POST', Uri.parse('http://foobar/something')), + ); + expect(response.statusCode, 404); + }); - test( - 'WebAssetServer strips leading base href off of asset requests', - () => testbed.run(() async { - const String htmlContent = - ''; - globals.fs.currentDirectory - .childDirectory('web') - .childFile('index.html') - ..createSync(recursive: true) - ..writeAsStringSync(htmlContent); - final WebAssetServer webAssetServer = WebAssetServer( - FakeHttpServer(), - PackageConfig.empty, - InternetAddress.anyIPv4, - {}, - {}, - NullSafetyMode.sound, - usesDdcModuleSystem, - webRenderer: WebRendererMode.canvaskit, - useLocalCanvasKit: false, - ); + runInTestbed('WebAssetServer strips leading base href off of asset requests', () async { + const String htmlContent = ''; + globals.fs.currentDirectory.childDirectory('web').childFile('index.html') + ..createSync(recursive: true) + ..writeAsStringSync(htmlContent); + final WebAssetServer webAssetServer = WebAssetServer( + FakeHttpServer(), + PackageConfig.empty, + InternetAddress.anyIPv4, + {}, + {}, + NullSafetyMode.sound, + usesDdcModuleSystem, + webRenderer: WebRendererMode.canvaskit, + useLocalCanvasKit: false, + ); - expect( - await webAssetServer - .metadataContents('foo/main_module.ddc_merged_metadata'), - null); - // Not base href. - expect( - () async => webAssetServer - .metadataContents('bar/main_module.ddc_merged_metadata'), - throwsException); - })); + expect( + await webAssetServer.metadataContents('foo/main_module.ddc_merged_metadata'), + null, + ); + // Not base href. + expect( + () => webAssetServer.metadataContents('bar/main_module.ddc_merged_metadata'), + throwsException, + ); + }); - test( - 'DevFS URI includes any specified base path.', - () => testbed.run(() async { - final File outputFile = globals.fs - .file(globals.fs.path.join('lib', 'main.dart')) - ..createSync(recursive: true); - const String htmlContent = - ''; - globals.fs.currentDirectory - .childDirectory('web') - .childFile('index.html') - ..createSync(recursive: true) - ..writeAsStringSync(htmlContent); - outputFile.parent.childFile('a.sources').writeAsStringSync(''); - outputFile.parent.childFile('a.json').writeAsStringSync('{}'); - outputFile.parent.childFile('a.map').writeAsStringSync('{}'); - outputFile.parent.childFile('a.metadata').writeAsStringSync('{}'); + runInTestbed('DevFS URI includes any specified base path.', () async { + final String path = globals.fs.path.join('lib', 'main.dart'); + final File outputFile = globals.fs.file(path) + ..createSync(recursive: true); + const String htmlContent = ''; + globals.fs.currentDirectory.childDirectory('web').childFile('index.html') + ..createSync(recursive: true) + ..writeAsStringSync(htmlContent); + outputFile.parent.childFile('a.sources').writeAsStringSync(''); + outputFile.parent.childFile('a.json').writeAsStringSync('{}'); + outputFile.parent.childFile('a.map').writeAsStringSync('{}'); + outputFile.parent.childFile('a.metadata').writeAsStringSync('{}'); - final WebDevFS webDevFS = WebDevFS( - hostname: 'localhost', - port: 0, - tlsCertPath: null, - tlsCertKeyPath: null, - packagesFilePath: '.dart_tool/package_config.json', - urlTunneller: null, // ignore: avoid_redundant_argument_values - useSseForDebugProxy: true, - useSseForDebugBackend: true, - useSseForInjectedClient: true, - nullAssertions: true, - nativeNullAssertions: true, - buildInfo: BuildInfo.debug, - enableDwds: false, - enableDds: false, - entrypoint: Uri.base, - testMode: true, - expressionCompiler: - null, // ignore: avoid_redundant_argument_values - extraHeaders: const {}, - chromiumLauncher: null, // ignore: avoid_redundant_argument_values - nullSafetyMode: NullSafetyMode.unsound, - ddcModuleSystem: usesDdcModuleSystem, - webRenderer: WebRendererMode.canvaskit, - isWasm: false, - useLocalCanvasKit: false, - rootDirectory: globals.fs.currentDirectory, - ); - webDevFS.ddcModuleLoaderJS.createSync(recursive: true); - webDevFS.stackTraceMapper.createSync(recursive: true); + final WebDevFS webDevFS = WebDevFS( + hostname: 'localhost', + port: 0, + tlsCertPath: null, + tlsCertKeyPath: null, + packagesFilePath: '.dart_tool/package_config.json', + urlTunneller: null, + useSseForDebugProxy: true, + useSseForDebugBackend: true, + useSseForInjectedClient: true, + nullAssertions: true, + nativeNullAssertions: true, + buildInfo: BuildInfo.debug, + enableDwds: false, + enableDds: false, + entrypoint: Uri.base, + testMode: true, + expressionCompiler: null, + extraHeaders: const {}, + chromiumLauncher: null, + nullSafetyMode: NullSafetyMode.unsound, + ddcModuleSystem: usesDdcModuleSystem, + webRenderer: WebRendererMode.canvaskit, + isWasm: false, + useLocalCanvasKit: false, + rootDirectory: globals.fs.currentDirectory, + ); + webDevFS.ddcModuleLoaderJS.createSync(recursive: true); + webDevFS.stackTraceMapper.createSync(recursive: true); - final Uri uri = await webDevFS.create(); + final Uri uri = await webDevFS.create(); - // served on localhost - expect(uri.host, 'localhost'); - // Matches base URI specified in html. - expect(uri.path, '/foo'); + // served on localhost + expect(uri.host, 'localhost'); + // Matches base URI specified in html. + expect(uri.path, '/foo'); - await webDevFS.destroy(); - }, overrides: { - Artifacts: () => Artifacts.test(), - })); + await webDevFS.destroy(); + }, overrides: {Artifacts: Artifacts.test}); } class FakeHttpServer extends Fake implements HttpServer { @@ -1698,15 +1458,15 @@ class FakeShaderCompiler implements DevelopmentShaderCompiler { class FakeDwds extends Fake implements Dwds { FakeDwds(Iterable connectedAppsIterable) - : connectedApps = - Stream.fromIterable(connectedAppsIterable); + : connectedApps = Stream.fromIterable(connectedAppsIterable); @override final Stream connectedApps; @override - Future debugConnection(AppConnection appConnection) => - Future.value(FakeDebugConnection()); + Future debugConnection(AppConnection appConnection) { + return Future.value(FakeDebugConnection()); + } } class FakeAppConnection extends Fake implements AppConnection {