// 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. // This is a CLI library; we use prints as part of the interface. // ignore_for_file: avoid_print import 'dart:async'; import 'dart:io'; import 'package:flutter_driver/flutter_driver.dart'; import 'common.dart'; /// Adaptor to run an integration test using `flutter drive`. /// /// To an integration test `.dart` using `flutter drive`, put a file named /// `_test.dart` in the app's `test_driver` directory: /// /// ```dart /// import 'dart:async'; /// /// import 'package:integration_test/integration_test_driver_extended.dart'; /// /// Future main() async { /// final FlutterDriver driver = await FlutterDriver.connect(); /// await integrationDriver( /// driver: driver, /// onScreenshot: (String screenshotName, List screenshotBytes) async { /// return true; /// }, /// ); /// } /// ``` /// /// ## Parameters: /// /// `driver` A custom driver. Defaults to `FlutterDriver.connect()`. /// /// `onScreenshot` can be used to process the screenshots taken during the test. /// An example could be that this callback compares the byte array against a baseline image, /// and it returns `true` if both images are equal. /// /// As a result, returning `false` from `onScreenshot` will make the test fail. Future integrationDriver( {FlutterDriver? driver, ScreenshotCallback? onScreenshot}) async { driver ??= await FlutterDriver.connect(); // Test states that it's waiting on web driver commands. // [DriverTestMessage] is converted to string since json format causes an // error if it's used as a message for requestData. String jsonResponse = await driver.requestData(DriverTestMessage.pending().toString()); final Map onScreenshotResults = {}; Response response = Response.fromJson(jsonResponse); // Until `integration_test` returns a [WebDriverCommandType.noop], keep // executing WebDriver commands. while (response.data != null && response.data!['web_driver_command'] != null && response.data!['web_driver_command'] != '${WebDriverCommandType.noop}') { final String? webDriverCommand = response.data!['web_driver_command'] as String?; if (webDriverCommand == '${WebDriverCommandType.screenshot}') { assert(onScreenshot != null, 'screenshot command requires an onScreenshot callback'); // Use `driver.screenshot()` method to get a screenshot of the web page. final List screenshotImage = await driver.screenshot(); final String screenshotName = response.data!['screenshot_name']! as String; final Map? args = (response.data!['args'] as Map?)?.cast(); final bool screenshotSuccess = await onScreenshot!(screenshotName, screenshotImage, args); onScreenshotResults[screenshotName] = screenshotSuccess; if (screenshotSuccess) { jsonResponse = await driver.requestData(DriverTestMessage.complete().toString()); } else { jsonResponse = await driver.requestData(DriverTestMessage.error().toString()); } response = Response.fromJson(jsonResponse); } else if (webDriverCommand == '${WebDriverCommandType.ack}') { // Previous command completed ask for a new one. jsonResponse = await driver.requestData(DriverTestMessage.pending().toString()); response = Response.fromJson(jsonResponse); } else { break; } } // If No-op command is sent, ask for the result of all tests. if (response.data != null && response.data!['web_driver_command'] != null && response.data!['web_driver_command'] == '${WebDriverCommandType.noop}') { jsonResponse = await driver.requestData(null); response = Response.fromJson(jsonResponse); print('result $jsonResponse'); } if (response.data != null && response.data!['screenshots'] != null && onScreenshot != null) { final List screenshots = response.data!['screenshots'] as List; final List failures = []; for (final dynamic screenshot in screenshots) { final Map data = screenshot as Map; final List screenshotBytes = data['bytes'] as List; final String screenshotName = data['screenshotName'] as String; bool ok = false; try { ok = onScreenshotResults[screenshotName] ?? await onScreenshot(screenshotName, screenshotBytes.cast()); } catch (exception) { throw StateError( 'Screenshot failure:\n' 'onScreenshot("$screenshotName", ) threw an exception: $exception', ); } if (!ok) { failures.add(screenshotName); } } if (failures.isNotEmpty) { throw StateError('The following screenshot tests failed: ${failures.join(', ')}'); } } await driver.close(); if (response.allTestsPassed) { print('All tests passed.'); exit(0); } else { print('Failure Details:\n${response.formattedFailureDetails}'); exit(1); } }