|  | // Copyright 2014 The Flutter Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | import 'dart:async'; | 
|  | import 'dart:io' as io; | 
|  |  | 
|  | import 'package:flutter_devicelab/framework/browser.dart'; | 
|  | import 'package:shelf/shelf.dart'; | 
|  | import 'package:shelf/shelf_io.dart' as shelf_io; | 
|  | import 'package:shelf_static/shelf_static.dart'; | 
|  |  | 
|  | /// Runs Chrome, opens the given `appUrl`, and returns the result reported by the | 
|  | /// app. | 
|  | /// | 
|  | /// The app is served from the `appDirectory`. Typically, the app is built | 
|  | /// using `flutter build web` and served from `build/web`. | 
|  | /// | 
|  | /// The launched app is expected to report the result by sending an HTTP POST | 
|  | /// request to "/test-result" containing result data as plain text body of the | 
|  | /// request. This function has no opinion about what that string contains. | 
|  | Future<String> evalTestAppInChrome({ | 
|  | required String appUrl, | 
|  | required String appDirectory, | 
|  | int serverPort = 8080, | 
|  | int browserDebugPort = 8081, | 
|  | }) async { | 
|  | io.HttpServer? server; | 
|  | Chrome? chrome; | 
|  | try { | 
|  | final Completer<String> resultCompleter = Completer<String>(); | 
|  | server = await io.HttpServer.bind('localhost', serverPort); | 
|  | final Cascade cascade = Cascade() | 
|  | .add((Request request) async { | 
|  | if (request.requestedUri.path.endsWith('/test-result')) { | 
|  | resultCompleter.complete(await request.readAsString()); | 
|  | return Response.ok('Test results received'); | 
|  | } | 
|  | return Response.notFound(''); | 
|  | }) | 
|  | .add(createStaticHandler(appDirectory)); | 
|  | shelf_io.serveRequests(server, cascade.handler); | 
|  | final io.Directory userDataDirectory = io.Directory.systemTemp.createTempSync('flutter_chrome_user_data.'); | 
|  | chrome = await Chrome.launch(ChromeOptions( | 
|  | headless: true, | 
|  | debugPort: browserDebugPort, | 
|  | url: appUrl, | 
|  | userDataDirectory: userDataDirectory.path, | 
|  | windowHeight: 500, | 
|  | windowWidth: 500, | 
|  | ), onError: resultCompleter.completeError); | 
|  | return await resultCompleter.future; | 
|  | } finally { | 
|  | chrome?.stop(); | 
|  | await server?.close(); | 
|  | } | 
|  | } | 
|  |  | 
|  | typedef ServerRequestListener = void Function(Request); | 
|  |  | 
|  | class AppServer { | 
|  | AppServer._(this._server, this.chrome, this.onChromeError); | 
|  |  | 
|  | static Future<AppServer> start({ | 
|  | required String appUrl, | 
|  | required String appDirectory, | 
|  | required String cacheControl, | 
|  | int serverPort = 8080, | 
|  | int browserDebugPort = 8081, | 
|  | bool headless = true, | 
|  | List<Handler>? additionalRequestHandlers, | 
|  | }) async { | 
|  | io.HttpServer server; | 
|  | Chrome chrome; | 
|  | server = await io.HttpServer.bind('localhost', serverPort); | 
|  | final Handler staticHandler = createStaticHandler(appDirectory, defaultDocument: 'index.html'); | 
|  | Cascade cascade = Cascade(); | 
|  | if (additionalRequestHandlers != null) { | 
|  | for (final Handler handler in additionalRequestHandlers) { | 
|  | cascade = cascade.add(handler); | 
|  | } | 
|  | } | 
|  | cascade = cascade.add((Request request) async { | 
|  | final Response response = await staticHandler(request); | 
|  | return response.change(headers: <String, Object>{ | 
|  | 'cache-control': cacheControl, | 
|  | }); | 
|  | }); | 
|  | shelf_io.serveRequests(server, cascade.handler); | 
|  | final io.Directory userDataDirectory = io.Directory.systemTemp.createTempSync('flutter_chrome_user_data.'); | 
|  | final Completer<String> chromeErrorCompleter = Completer<String>(); | 
|  | chrome = await Chrome.launch(ChromeOptions( | 
|  | headless: headless, | 
|  | debugPort: browserDebugPort, | 
|  | url: appUrl, | 
|  | userDataDirectory: userDataDirectory.path, | 
|  | ), onError: chromeErrorCompleter.complete); | 
|  | return AppServer._(server, chrome, chromeErrorCompleter.future); | 
|  | } | 
|  |  | 
|  | final Future<String> onChromeError; | 
|  | final io.HttpServer _server; | 
|  | final Chrome chrome; | 
|  |  | 
|  | Future<void> stop() async { | 
|  | chrome.stop(); | 
|  | await _server.close(); | 
|  | } | 
|  | } |