| // 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:io' show Platform; |
| import 'dart:ui'; |
| |
| import 'package:flutter/services.dart'; |
| import 'package:flutter_test/flutter_test.dart'; |
| |
| import 'common.dart'; |
| import 'src/channel.dart'; |
| |
| /// The dart:io implementation of [CallbackManager]. |
| /// |
| /// See also: |
| /// |
| /// * `_callback_web.dart`, which has the dart:html implementation |
| CallbackManager get callbackManager => _singletonCallbackManager; |
| |
| /// IOCallbackManager singleton. |
| final IOCallbackManager _singletonCallbackManager = IOCallbackManager(); |
| |
| /// Manages communication between `integration_tests` and the `driver_tests`. |
| /// |
| /// This is the dart:io implementation. |
| class IOCallbackManager implements CallbackManager { |
| @override |
| Future<Map<String, dynamic>> callback( |
| Map<String, String> params, IntegrationTestResults testRunner) async { |
| final String command = params['command']!; |
| Map<String, String> response; |
| switch (command) { |
| case 'request_data': |
| final bool allTestsPassed = await testRunner.allTestsPassed.future; |
| response = <String, String>{ |
| 'message': allTestsPassed |
| ? Response.allTestsPassed(data: testRunner.reportData).toJson() |
| : Response.someTestsFailed( |
| testRunner.failureMethodsDetails, |
| data: testRunner.reportData, |
| ).toJson(), |
| }; |
| break; |
| case 'get_health': |
| response = <String, String>{'status': 'ok'}; |
| break; |
| default: |
| throw UnimplementedError('$command is not implemented'); |
| } |
| return <String, dynamic>{ |
| 'isError': false, |
| 'response': response, |
| }; |
| } |
| |
| @override |
| void cleanup() { |
| // no-op. |
| // Add any IO platform specific Completer/Future cleanups to here if any |
| // comes up in the future. For example: `WebCallbackManager.cleanup`. |
| } |
| |
| // [convertFlutterSurfaceToImage] has been called and [takeScreenshot] is ready to capture the surface (Android only). |
| bool _isSurfaceRendered = false; |
| |
| @override |
| Future<void> convertFlutterSurfaceToImage() async { |
| if (!Platform.isAndroid) { |
| // No-op on other platforms. |
| return; |
| } |
| assert(!_isSurfaceRendered, 'Surface already converted to an image'); |
| await integrationTestChannel.invokeMethod<void>( |
| 'convertFlutterSurfaceToImage', |
| null, |
| ); |
| _isSurfaceRendered = true; |
| |
| addTearDown(() async { |
| assert(_isSurfaceRendered, 'Surface is not an image'); |
| await integrationTestChannel.invokeMethod<void>( |
| 'revertFlutterImage', |
| null, |
| ); |
| _isSurfaceRendered = false; |
| }); |
| } |
| |
| @override |
| Future<Map<String, dynamic>> takeScreenshot(String screenshot) async { |
| if (Platform.isAndroid && !_isSurfaceRendered) { |
| throw StateError('Call convertFlutterSurfaceToImage() before taking a screenshot'); |
| } |
| integrationTestChannel.setMethodCallHandler(_onMethodChannelCall); |
| final List<int>? rawBytes = await integrationTestChannel.invokeMethod<List<int>>( |
| 'captureScreenshot', |
| <String, dynamic>{'name': screenshot}, |
| ); |
| if (rawBytes == null) { |
| throw StateError('Expected a list of bytes, but instead captureScreenshot returned null'); |
| } |
| return <String, dynamic>{ |
| 'screenshotName': screenshot, |
| 'bytes': rawBytes, |
| }; |
| } |
| |
| Future<dynamic> _onMethodChannelCall(MethodCall call) async { |
| switch (call.method) { |
| case 'scheduleFrame': |
| PlatformDispatcher.instance.scheduleFrame(); |
| break; |
| } |
| return null; |
| } |
| } |