| // Copyright 2013 The Flutter Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| import 'dart:convert'; | |
| import 'dart:io' as io; | |
| import 'package:args/command_runner.dart'; | |
| import 'package:fake_async/fake_async.dart'; | |
| import 'package:file/file.dart'; | |
| import 'package:flutter_plugin_tools/src/common/core.dart'; | |
| import 'package:flutter_plugin_tools/src/common/plugin_utils.dart'; | |
| import 'package:flutter_plugin_tools/src/drive_examples_command.dart'; | |
| import 'package:git/git.dart'; | |
| import 'package:mockito/mockito.dart'; | |
| import 'package:platform/platform.dart'; | |
| import 'package:test/test.dart'; | |
| import 'mocks.dart'; | |
| import 'util.dart'; | |
| const String _fakeIOSDevice = '67d5c3d1-8bdf-46ad-8f6b-b00e2a972dda'; | |
| const String _fakeAndroidDevice = 'emulator-1234'; | |
| const List<String> _defaultWebBrowserFlags = <String>[ | |
| '--web-browser-flag=--no-sandbox', | |
| '--web-browser-flag=--disable-background-timer-throttling', | |
| '--web-browser-flag=--disable-renderer-backgrounding', | |
| '--web-browser-flag=--disable-background-networking', | |
| '--web-browser-flag=--disable-search-engine-choice-screen', | |
| '--web-browser-flag=--disable-extensions', | |
| '--web-browser-flag=--disable-popup-blocking', | |
| '--web-browser-flag=--disable-translate', | |
| '--web-browser-flag=--disable-default-apps', | |
| '--web-browser-flag=--no-default-browser-check', | |
| '--web-browser-flag=--no-first-run', | |
| '--web-browser-flag=--password-store=basic', | |
| '--web-browser-flag=--bwsi', | |
| ]; | |
| void main() { | |
| group('test drive_example_command', () { | |
| late NativePlatform mockPlatform; | |
| late Directory packagesDir; | |
| late CommandRunner<void> runner; | |
| late RecordingProcessRunner processRunner; | |
| late RecordingProcessRunner gitProcessRunner; | |
| setUp(() { | |
| mockPlatform = createMockPlatform(); | |
| final GitDir gitDir; | |
| (:packagesDir, :processRunner, :gitProcessRunner, :gitDir) = configureBaseCommandMocks( | |
| platform: mockPlatform, | |
| ); | |
| final command = DriveExamplesCommand( | |
| packagesDir, | |
| processRunner: processRunner, | |
| platform: mockPlatform, | |
| gitDir: gitDir, | |
| ); | |
| runner = CommandRunner<void>('drive_examples_command', 'Test for drive_example_command'); | |
| runner.addCommand(command); | |
| mockPlatform.environment['FLUTTER_LOGS_DIR'] = '/path/to/logs'; | |
| }); | |
| void setMockFlutterDevicesOutput({ | |
| bool hasIOSDevice = true, | |
| bool hasAndroidDevice = true, | |
| bool includeBanner = false, | |
| }) { | |
| const updateBanner = ''' | |
| ╔════════════════════════════════════════════════════════════════════════════╗ | |
| ║ A new version of Flutter is available! ║ | |
| ║ ║ | |
| ║ To update to the latest version, run "flutter upgrade". ║ | |
| ╚════════════════════════════════════════════════════════════════════════════╝ | |
| '''; | |
| final devices = <String>[ | |
| if (hasIOSDevice) '{"id": "$_fakeIOSDevice", "targetPlatform": "ios"}', | |
| if (hasAndroidDevice) '{"id": "$_fakeAndroidDevice", "targetPlatform": "android-x64"}', | |
| ]; | |
| final output = '''${includeBanner ? updateBanner : ''}[${devices.join(',')}]'''; | |
| final mockDevicesProcess = MockProcess(stdout: output, stdoutEncoding: utf8); | |
| processRunner.mockProcessesForExecutable[getFlutterCommand(mockPlatform)] = <FakeProcessInfo>[ | |
| FakeProcessInfo(mockDevicesProcess, <String>['devices']), | |
| ]; | |
| } | |
| test('fails if no platforms are provided', () async { | |
| setMockFlutterDevicesOutput(); | |
| Error? commandError; | |
| final List<String> output = await runCapturingPrint( | |
| runner, | |
| <String>['drive-examples'], | |
| errorHandler: (Error e) { | |
| commandError = e; | |
| }, | |
| ); | |
| expect(commandError, isA<ToolExit>()); | |
| expect(output, containsAllInOrder(<Matcher>[contains('Exactly one of')])); | |
| }); | |
| test('fails if wasm flag is present but not web platform', () async { | |
| setMockFlutterDevicesOutput(); | |
| Error? commandError; | |
| final List<String> output = await runCapturingPrint( | |
| runner, | |
| <String>['drive-examples', '--android', '--wasm'], | |
| errorHandler: (Error e) { | |
| commandError = e; | |
| }, | |
| ); | |
| expect(commandError, isA<ToolExit>()); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[contains('--wasm is only supported on the web platform')]), | |
| ); | |
| }); | |
| test('fails if multiple platforms are provided', () async { | |
| setMockFlutterDevicesOutput(); | |
| Error? commandError; | |
| final List<String> output = await runCapturingPrint( | |
| runner, | |
| <String>['drive-examples', '--ios', '--macos'], | |
| errorHandler: (Error e) { | |
| commandError = e; | |
| }, | |
| ); | |
| expect(commandError, isA<ToolExit>()); | |
| expect(output, containsAllInOrder(<Matcher>[contains('Exactly one of')])); | |
| }); | |
| test('fails for iOS if no iOS devices are present', () async { | |
| setMockFlutterDevicesOutput(hasIOSDevice: false); | |
| Error? commandError; | |
| final List<String> output = await runCapturingPrint( | |
| runner, | |
| <String>['drive-examples', '--ios'], | |
| errorHandler: (Error e) { | |
| commandError = e; | |
| }, | |
| ); | |
| expect(commandError, isA<ToolExit>()); | |
| expect(output, containsAllInOrder(<Matcher>[contains('No iOS devices')])); | |
| }); | |
| test('handles flutter tool banners when checking devices', () async { | |
| createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>[ | |
| 'example/test_driver/integration_test.dart', | |
| 'example/integration_test/foo_test.dart', | |
| 'example/ios/ios.m', | |
| ], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformIOS: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| setMockFlutterDevicesOutput(includeBanner: true); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--ios', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[contains('Running for plugin'), contains('No issues found!')]), | |
| ); | |
| }); | |
| test('fails for iOS if getting devices fails', () async { | |
| // Simulate failure from `flutter devices`. | |
| processRunner.mockProcessesForExecutable[getFlutterCommand(mockPlatform)] = <FakeProcessInfo>[ | |
| FakeProcessInfo(MockProcess(exitCode: 1), <String>['devices']), | |
| ]; | |
| Error? commandError; | |
| final List<String> output = await runCapturingPrint( | |
| runner, | |
| <String>['drive-examples', '--ios'], | |
| errorHandler: (Error e) { | |
| commandError = e; | |
| }, | |
| ); | |
| expect(commandError, isA<ToolExit>()); | |
| expect(output, containsAllInOrder(<Matcher>[contains('No iOS devices')])); | |
| }); | |
| test('fails for Android if no Android devices are present', () async { | |
| setMockFlutterDevicesOutput(hasAndroidDevice: false); | |
| Error? commandError; | |
| final List<String> output = await runCapturingPrint( | |
| runner, | |
| <String>['drive-examples', '--android'], | |
| errorHandler: (Error e) { | |
| commandError = e; | |
| }, | |
| ); | |
| expect(commandError, isA<ToolExit>()); | |
| expect(output, containsAllInOrder(<Matcher>[contains('No Android devices')])); | |
| }); | |
| test('a plugin without any integration test files is reported as an error', () async { | |
| setMockFlutterDevicesOutput(); | |
| createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>[ | |
| 'example/lib/main.dart', | |
| 'example/android/android.java', | |
| 'example/ios/ios.m', | |
| ], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformAndroid: const PlatformDetails(PlatformSupport.inline), | |
| platformIOS: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| Error? commandError; | |
| final List<String> output = await runCapturingPrint( | |
| runner, | |
| <String>['drive-examples', '--android'], | |
| errorHandler: (Error e) { | |
| commandError = e; | |
| }, | |
| ); | |
| expect(commandError, isA<ToolExit>()); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[ | |
| contains('Running for plugin'), | |
| contains('No driver tests were run (1 example(s) found).'), | |
| contains('No tests ran'), | |
| ]), | |
| ); | |
| }); | |
| test('integration tests using test(...) fail validation', () async { | |
| setMockFlutterDevicesOutput(); | |
| final RepositoryPackage package = createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>[ | |
| 'example/test_driver/integration_test.dart', | |
| 'example/integration_test/foo_test.dart', | |
| 'example/android/android.java', | |
| ], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformAndroid: const PlatformDetails(PlatformSupport.inline), | |
| platformIOS: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| package.directory | |
| .childDirectory('example') | |
| .childDirectory('integration_test') | |
| .childFile('foo_test.dart') | |
| .writeAsStringSync(''' | |
| test('this is the wrong kind of test!'), () { | |
| ... | |
| } | |
| '''); | |
| Error? commandError; | |
| final List<String> output = await runCapturingPrint( | |
| runner, | |
| <String>['drive-examples', '--android'], | |
| errorHandler: (Error e) { | |
| commandError = e; | |
| }, | |
| ); | |
| expect(commandError, isA<ToolExit>()); | |
| expect(output, containsAllInOrder(<Matcher>[contains('foo_test.dart failed validation')])); | |
| }); | |
| test('tests an iOS plugin', () async { | |
| final RepositoryPackage plugin = createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>[ | |
| 'example/integration_test/bar_test.dart', | |
| 'example/integration_test/foo_test.dart', | |
| 'example/integration_test/ignore_me.dart', | |
| 'example/android/android.java', | |
| 'example/ios/ios.m', | |
| ], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformAndroid: const PlatformDetails(PlatformSupport.inline), | |
| platformIOS: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| final Directory pluginExampleDirectory = getExampleDir(plugin); | |
| setMockFlutterDevicesOutput(); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--ios', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[contains('Running for plugin'), contains('No issues found!')]), | |
| ); | |
| expect( | |
| processRunner.recordedCalls, | |
| orderedEquals(<ProcessCall>[ | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'devices', | |
| '--machine', | |
| ], null), | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'test', | |
| '-d', | |
| _fakeIOSDevice, | |
| '--debug-logs-dir=/path/to/logs', | |
| 'integration_test', | |
| ], pluginExampleDirectory.path), | |
| ]), | |
| ); | |
| }); | |
| test('handles missing CI debug logs directory', () async { | |
| mockPlatform.environment.remove('FLUTTER_LOGS_DIR'); | |
| final RepositoryPackage plugin = createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>[ | |
| 'example/integration_test/bar_test.dart', | |
| 'example/integration_test/foo_test.dart', | |
| 'example/integration_test/ignore_me.dart', | |
| 'example/android/android.java', | |
| 'example/ios/ios.m', | |
| ], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformAndroid: const PlatformDetails(PlatformSupport.inline), | |
| platformIOS: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| final Directory pluginExampleDirectory = getExampleDir(plugin); | |
| setMockFlutterDevicesOutput(); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--ios', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[contains('Running for plugin'), contains('No issues found!')]), | |
| ); | |
| expect( | |
| processRunner.recordedCalls, | |
| orderedEquals(<ProcessCall>[ | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'devices', | |
| '--machine', | |
| ], null), | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'test', | |
| '-d', | |
| _fakeIOSDevice, | |
| 'integration_test', | |
| ], pluginExampleDirectory.path), | |
| ]), | |
| ); | |
| }); | |
| test('saves a screenshot if test is taking too long', () async { | |
| setMockFlutterDevicesOutput(); | |
| final RepositoryPackage plugin = createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>['example/integration_test/bar_test.dart', 'example/ios/ios.m'], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformAndroid: const PlatformDetails(PlatformSupport.inline), | |
| platformIOS: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| final fakeAsync = FakeAsync(); | |
| processRunner.mockProcessesForExecutable['flutter']!.addAll(<FakeProcessInfo>[ | |
| FakeProcessInfo( | |
| _FakeDelayingProcess(delayDuration: const Duration(minutes: 11), fakeAsync: fakeAsync), | |
| <String>['test'], | |
| ), | |
| FakeProcessInfo(MockProcess(), <String>['screenshot']), | |
| ]); | |
| final Directory pluginExampleDirectory = getExampleDir(plugin); | |
| var output = <String>[]; | |
| fakeAsync.run((_) { | |
| () async { | |
| output = await runCapturingPrint(runner, <String>['drive-examples', '--ios']); | |
| }(); | |
| }); | |
| fakeAsync.flushTimers(); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[ | |
| contains('Running for plugin'), | |
| contains( | |
| 'Test is taking a long time, taking screenshot test-timeout-screenshot_integration_test.png...', | |
| ), | |
| contains('No issues found!'), | |
| ]), | |
| ); | |
| expect( | |
| processRunner.recordedCalls, | |
| orderedEquals(<ProcessCall>[ | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'devices', | |
| '--machine', | |
| ], null), | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'test', | |
| '-d', | |
| _fakeIOSDevice, | |
| '--debug-logs-dir=/path/to/logs', | |
| 'integration_test', | |
| ], pluginExampleDirectory.path), | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'screenshot', | |
| '-d', | |
| _fakeIOSDevice, | |
| '--out=/path/to/logs/test-timeout-screenshot_integration_test.png', | |
| ], pluginExampleDirectory.path), | |
| ]), | |
| ); | |
| }); | |
| test('driving when plugin does not support Linux is a no-op', () async { | |
| createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>['example/integration_test/plugin_test.dart'], | |
| ); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--linux', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[ | |
| contains('Running for plugin'), | |
| contains('Skipping unsupported platform linux...'), | |
| contains('No issues found!'), | |
| ]), | |
| ); | |
| // Output should be empty since running drive-examples --linux on a non-Linux | |
| // plugin is a no-op. | |
| expect(processRunner.recordedCalls, <ProcessCall>[]); | |
| }); | |
| test('tests a Linux plugin', () async { | |
| final RepositoryPackage plugin = createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>['example/integration_test/plugin_test.dart', 'example/linux/linux.cc'], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformLinux: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| final Directory pluginExampleDirectory = getExampleDir(plugin); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--linux', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[contains('Running for plugin'), contains('No issues found!')]), | |
| ); | |
| expect( | |
| processRunner.recordedCalls, | |
| orderedEquals(<ProcessCall>[ | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'test', | |
| '-d', | |
| 'linux', | |
| '--debug-logs-dir=/path/to/logs', | |
| 'integration_test', | |
| ], pluginExampleDirectory.path), | |
| ]), | |
| ); | |
| }); | |
| test('driving when plugin does not suppport macOS is a no-op', () async { | |
| createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>['example/integration_test/plugin_test.dart'], | |
| ); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--macos', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[ | |
| contains('Running for plugin'), | |
| contains('Skipping unsupported platform macos...'), | |
| contains('No issues found!'), | |
| ]), | |
| ); | |
| // Output should be empty since running drive-examples --macos with no macos | |
| // implementation is a no-op. | |
| expect(processRunner.recordedCalls, <ProcessCall>[]); | |
| }); | |
| test('tests a macOS plugin', () async { | |
| final RepositoryPackage plugin = createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>[ | |
| 'example/integration_test/plugin_test.dart', | |
| 'example/macos/macos.swift', | |
| ], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformMacOS: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| final Directory pluginExampleDirectory = getExampleDir(plugin); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--macos', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[contains('Running for plugin'), contains('No issues found!')]), | |
| ); | |
| expect( | |
| processRunner.recordedCalls, | |
| orderedEquals(<ProcessCall>[ | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'test', | |
| '-d', | |
| 'macos', | |
| '--debug-logs-dir=/path/to/logs', | |
| 'integration_test', | |
| ], pluginExampleDirectory.path), | |
| ]), | |
| ); | |
| }); | |
| // This tests the workaround for https://github.com/flutter/flutter/issues/135673 | |
| // and the behavior it tests should be removed once that is fixed. | |
| group('runs tests separately on desktop', () { | |
| test('macOS', () async { | |
| final RepositoryPackage plugin = createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>[ | |
| 'example/integration_test/first_test.dart', | |
| 'example/integration_test/second_test.dart', | |
| 'example/macos/macos.swift', | |
| ], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformMacOS: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| final Directory pluginExampleDirectory = getExampleDir(plugin); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--macos', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[ | |
| contains('Running for plugin'), | |
| contains('No issues found!'), | |
| ]), | |
| ); | |
| expect( | |
| processRunner.recordedCalls, | |
| orderedEquals(<ProcessCall>[ | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'test', | |
| '-d', | |
| 'macos', | |
| '--debug-logs-dir=/path/to/logs', | |
| 'integration_test/first_test.dart', | |
| ], pluginExampleDirectory.path), | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'test', | |
| '-d', | |
| 'macos', | |
| '--debug-logs-dir=/path/to/logs', | |
| 'integration_test/second_test.dart', | |
| ], pluginExampleDirectory.path), | |
| ]), | |
| ); | |
| }); | |
| // This tests the workaround for https://github.com/flutter/flutter/issues/135673 | |
| // and the behavior it tests should be removed once that is fixed. | |
| test('Linux', () async { | |
| final RepositoryPackage plugin = createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>[ | |
| 'example/integration_test/first_test.dart', | |
| 'example/integration_test/second_test.dart', | |
| 'example/linux/foo.cc', | |
| ], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformLinux: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| final Directory pluginExampleDirectory = getExampleDir(plugin); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--linux', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[ | |
| contains('Running for plugin'), | |
| contains('No issues found!'), | |
| ]), | |
| ); | |
| expect( | |
| processRunner.recordedCalls, | |
| orderedEquals(<ProcessCall>[ | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'test', | |
| '-d', | |
| 'linux', | |
| '--debug-logs-dir=/path/to/logs', | |
| 'integration_test/first_test.dart', | |
| ], pluginExampleDirectory.path), | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'test', | |
| '-d', | |
| 'linux', | |
| '--debug-logs-dir=/path/to/logs', | |
| 'integration_test/second_test.dart', | |
| ], pluginExampleDirectory.path), | |
| ]), | |
| ); | |
| }); | |
| // This tests the workaround for https://github.com/flutter/flutter/issues/135673 | |
| // and the behavior it tests should be removed once that is fixed. | |
| test('Windows', () async { | |
| final RepositoryPackage plugin = createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>[ | |
| 'example/integration_test/first_test.dart', | |
| 'example/integration_test/second_test.dart', | |
| 'example/windows/foo.cpp', | |
| ], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformWindows: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| final Directory pluginExampleDirectory = getExampleDir(plugin); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--windows', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[ | |
| contains('Running for plugin'), | |
| contains('No issues found!'), | |
| ]), | |
| ); | |
| expect( | |
| processRunner.recordedCalls, | |
| orderedEquals(<ProcessCall>[ | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'test', | |
| '-d', | |
| 'windows', | |
| '--debug-logs-dir=/path/to/logs', | |
| 'integration_test/first_test.dart', | |
| ], pluginExampleDirectory.path), | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'test', | |
| '-d', | |
| 'windows', | |
| '--debug-logs-dir=/path/to/logs', | |
| 'integration_test/second_test.dart', | |
| ], pluginExampleDirectory.path), | |
| ]), | |
| ); | |
| }); | |
| }); | |
| test('driving when plugin does not suppport web is a no-op', () async { | |
| createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>['example/integration_test/plugin_test.dart'], | |
| ); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--web', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[contains('Running for plugin'), contains('No issues found!')]), | |
| ); | |
| // Output should be empty since running drive-examples --web on a non-web | |
| // plugin is a no-op. | |
| expect(processRunner.recordedCalls, <ProcessCall>[]); | |
| }); | |
| test('drives a web plugin', () async { | |
| final RepositoryPackage plugin = createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>[ | |
| 'example/integration_test/plugin_test.dart', | |
| 'example/test_driver/integration_test.dart', | |
| 'example/web/index.html', | |
| ], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformWeb: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| final Directory pluginExampleDirectory = getExampleDir(plugin); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--web', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[contains('Running for plugin'), contains('No issues found!')]), | |
| ); | |
| expect( | |
| processRunner.recordedCalls, | |
| orderedEquals(<ProcessCall>[ | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'drive', | |
| '-d', | |
| 'web-server', | |
| '--web-port=7357', | |
| '--browser-name=chrome', | |
| ..._defaultWebBrowserFlags, | |
| '--screenshot=/path/to/logs/plugin_example-drive', | |
| '--driver', | |
| 'test_driver/integration_test.dart', | |
| '--target', | |
| 'integration_test/plugin_test.dart', | |
| ], pluginExampleDirectory.path), | |
| ]), | |
| ); | |
| }); | |
| test('drives a web plugin compiled to WASM', () async { | |
| final RepositoryPackage plugin = createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>[ | |
| 'example/integration_test/plugin_test.dart', | |
| 'example/test_driver/integration_test.dart', | |
| 'example/web/index.html', | |
| ], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformWeb: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| final Directory pluginExampleDirectory = getExampleDir(plugin); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--web', | |
| '--wasm', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[contains('Running for plugin'), contains('No issues found!')]), | |
| ); | |
| expect( | |
| processRunner.recordedCalls, | |
| orderedEquals(<ProcessCall>[ | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'drive', | |
| '-d', | |
| 'web-server', | |
| '--web-port=7357', | |
| '--browser-name=chrome', | |
| '--wasm', | |
| ..._defaultWebBrowserFlags, | |
| '--screenshot=/path/to/logs/plugin_example-drive', | |
| '--driver', | |
| 'test_driver/integration_test.dart', | |
| '--target', | |
| 'integration_test/plugin_test.dart', | |
| ], pluginExampleDirectory.path), | |
| ]), | |
| ); | |
| }); | |
| test('runs chromedriver when requested', () async { | |
| final RepositoryPackage plugin = createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>[ | |
| 'example/integration_test/plugin_test.dart', | |
| 'example/test_driver/integration_test.dart', | |
| 'example/web/index.html', | |
| ], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformWeb: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| final Directory pluginExampleDirectory = getExampleDir(plugin); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--web', | |
| '--run-chromedriver', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[contains('Running for plugin'), contains('No issues found!')]), | |
| ); | |
| expect( | |
| processRunner.recordedCalls, | |
| orderedEquals(<ProcessCall>[ | |
| const ProcessCall('chromedriver', <String>['--port=4444'], null), | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'drive', | |
| '-d', | |
| 'web-server', | |
| '--web-port=7357', | |
| '--browser-name=chrome', | |
| ..._defaultWebBrowserFlags, | |
| '--screenshot=/path/to/logs/plugin_example-drive', | |
| '--driver', | |
| 'test_driver/integration_test.dart', | |
| '--target', | |
| 'integration_test/plugin_test.dart', | |
| ], pluginExampleDirectory.path), | |
| ]), | |
| ); | |
| }); | |
| test('drives a web plugin with CHROME_EXECUTABLE', () async { | |
| final RepositoryPackage plugin = createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>[ | |
| 'example/integration_test/plugin_test.dart', | |
| 'example/test_driver/integration_test.dart', | |
| 'example/web/index.html', | |
| ], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformWeb: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| final Directory pluginExampleDirectory = getExampleDir(plugin); | |
| mockPlatform.environment['CHROME_EXECUTABLE'] = '/path/to/chrome'; | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--web', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[contains('Running for plugin'), contains('No issues found!')]), | |
| ); | |
| expect( | |
| processRunner.recordedCalls, | |
| orderedEquals(<ProcessCall>[ | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'drive', | |
| '-d', | |
| 'web-server', | |
| '--web-port=7357', | |
| '--browser-name=chrome', | |
| '--chrome-binary=/path/to/chrome', | |
| ..._defaultWebBrowserFlags, | |
| '--screenshot=/path/to/logs/plugin_example-drive', | |
| '--driver', | |
| 'test_driver/integration_test.dart', | |
| '--target', | |
| 'integration_test/plugin_test.dart', | |
| ], pluginExampleDirectory.path), | |
| ]), | |
| ); | |
| }); | |
| test('driving when plugin does not suppport Windows is a no-op', () async { | |
| createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>['example/integration_test/plugin_test.dart'], | |
| ); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--windows', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[ | |
| contains('Running for plugin'), | |
| contains('Skipping unsupported platform windows...'), | |
| contains('No issues found!'), | |
| ]), | |
| ); | |
| // Output should be empty since running drive-examples --windows on a | |
| // non-Windows plugin is a no-op. | |
| expect(processRunner.recordedCalls, <ProcessCall>[]); | |
| }); | |
| test('tests a Windows plugin', () async { | |
| final RepositoryPackage plugin = createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>[ | |
| 'example/integration_test/plugin_test.dart', | |
| 'example/windows/windows.cpp', | |
| ], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformWindows: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| final Directory pluginExampleDirectory = getExampleDir(plugin); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--windows', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[contains('Running for plugin'), contains('No issues found!')]), | |
| ); | |
| expect( | |
| processRunner.recordedCalls, | |
| orderedEquals(<ProcessCall>[ | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'test', | |
| '-d', | |
| 'windows', | |
| '--debug-logs-dir=/path/to/logs', | |
| 'integration_test', | |
| ], pluginExampleDirectory.path), | |
| ]), | |
| ); | |
| }); | |
| test('tests an Android plugin', () async { | |
| final RepositoryPackage plugin = createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>[ | |
| 'example/integration_test/plugin_test.dart', | |
| 'example/android/android.java', | |
| ], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformAndroid: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| final Directory pluginExampleDirectory = getExampleDir(plugin); | |
| setMockFlutterDevicesOutput(); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--android', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[contains('Running for plugin'), contains('No issues found!')]), | |
| ); | |
| expect( | |
| processRunner.recordedCalls, | |
| orderedEquals(<ProcessCall>[ | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'devices', | |
| '--machine', | |
| ], null), | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'test', | |
| '-d', | |
| _fakeAndroidDevice, | |
| '--debug-logs-dir=/path/to/logs', | |
| 'integration_test', | |
| ], pluginExampleDirectory.path), | |
| ]), | |
| ); | |
| }); | |
| test('tests an Android plugin with "apk" alias', () async { | |
| final RepositoryPackage plugin = createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>[ | |
| 'example/integration_test/plugin_test.dart', | |
| 'example/android/android.java', | |
| ], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformAndroid: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| final Directory pluginExampleDirectory = getExampleDir(plugin); | |
| setMockFlutterDevicesOutput(); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--apk', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[contains('Running for plugin'), contains('No issues found!')]), | |
| ); | |
| expect( | |
| processRunner.recordedCalls, | |
| orderedEquals(<ProcessCall>[ | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'devices', | |
| '--machine', | |
| ], null), | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'test', | |
| '-d', | |
| _fakeAndroidDevice, | |
| '--debug-logs-dir=/path/to/logs', | |
| 'integration_test', | |
| ], pluginExampleDirectory.path), | |
| ]), | |
| ); | |
| }); | |
| test('driving when plugin does not support Android is no-op', () async { | |
| createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>['example/integration_test/plugin_test.dart'], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformMacOS: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| setMockFlutterDevicesOutput(); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--android', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[ | |
| contains('Running for plugin'), | |
| contains('Skipping unsupported platform android...'), | |
| contains('No issues found!'), | |
| ]), | |
| ); | |
| // Output should be empty other than the device query. | |
| expect(processRunner.recordedCalls, <ProcessCall>[ | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>['devices', '--machine'], null), | |
| ]); | |
| }); | |
| test('driving when plugin does not support iOS is no-op', () async { | |
| createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>['example/integration_test/plugin_test.dart'], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformMacOS: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| setMockFlutterDevicesOutput(); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--ios', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[ | |
| contains('Running for plugin'), | |
| contains('Skipping unsupported platform ios...'), | |
| contains('No issues found!'), | |
| ]), | |
| ); | |
| // Output should be empty other than the device query. | |
| expect(processRunner.recordedCalls, <ProcessCall>[ | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>['devices', '--machine'], null), | |
| ]); | |
| }); | |
| test('platform interface plugins are silently skipped', () async { | |
| createFakePlugin('aplugin_platform_interface', packagesDir, examples: <String>[]); | |
| setMockFlutterDevicesOutput(); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--macos', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[ | |
| contains('Running for aplugin_platform_interface'), | |
| contains('SKIPPING: Platform interfaces are not expected to have integration tests.'), | |
| contains('No issues found!'), | |
| ]), | |
| ); | |
| // Output should be empty since it's skipped. | |
| expect(processRunner.recordedCalls, <ProcessCall>[]); | |
| }); | |
| test('enable-experiment flag', () async { | |
| final RepositoryPackage plugin = createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>[ | |
| 'example/integration_test/plugin_test.dart', | |
| 'example/android/android.java', | |
| 'example/ios/ios.m', | |
| ], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformAndroid: const PlatformDetails(PlatformSupport.inline), | |
| platformIOS: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| final Directory pluginExampleDirectory = getExampleDir(plugin); | |
| setMockFlutterDevicesOutput(); | |
| await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--ios', | |
| '--enable-experiment=exp1', | |
| ]); | |
| expect( | |
| processRunner.recordedCalls, | |
| orderedEquals(<ProcessCall>[ | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'devices', | |
| '--machine', | |
| ], null), | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'test', | |
| '-d', | |
| _fakeIOSDevice, | |
| '--enable-experiment=exp1', | |
| '--debug-logs-dir=/path/to/logs', | |
| 'integration_test', | |
| ], pluginExampleDirectory.path), | |
| ]), | |
| ); | |
| }); | |
| test('fails when no example is present', () async { | |
| createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| examples: <String>[], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformWeb: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| Error? commandError; | |
| final List<String> output = await runCapturingPrint( | |
| runner, | |
| <String>['drive-examples', '--web'], | |
| errorHandler: (Error e) { | |
| commandError = e; | |
| }, | |
| ); | |
| expect(commandError, isA<ToolExit>()); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[ | |
| contains('Running for plugin'), | |
| contains('No driver tests were run (0 example(s) found).'), | |
| contains('The following packages had errors:'), | |
| contains( | |
| ' plugin:\n' | |
| ' No tests ran (use --exclude if this is intentional)', | |
| ), | |
| ]), | |
| ); | |
| }); | |
| test('web fails when no driver is present', () async { | |
| createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>[ | |
| 'example/integration_test/bar_test.dart', | |
| 'example/integration_test/foo_test.dart', | |
| 'example/web/index.html', | |
| ], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformWeb: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| Error? commandError; | |
| final List<String> output = await runCapturingPrint( | |
| runner, | |
| <String>['drive-examples', '--web'], | |
| errorHandler: (Error e) { | |
| commandError = e; | |
| }, | |
| ); | |
| expect(commandError, isA<ToolExit>()); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[ | |
| contains('Running for plugin'), | |
| contains('No driver found for plugin/example'), | |
| contains('No driver tests were run (1 example(s) found).'), | |
| contains('The following packages had errors:'), | |
| contains( | |
| ' plugin:\n' | |
| ' No tests ran (use --exclude if this is intentional)', | |
| ), | |
| ]), | |
| ); | |
| }); | |
| test('web fails when no integration tests are present', () async { | |
| createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>['example/test_driver/integration_test.dart', 'example/web/index.html'], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformWeb: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| Error? commandError; | |
| final List<String> output = await runCapturingPrint( | |
| runner, | |
| <String>['drive-examples', '--web'], | |
| errorHandler: (Error e) { | |
| commandError = e; | |
| }, | |
| ); | |
| expect(commandError, isA<ToolExit>()); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[ | |
| contains('Running for plugin'), | |
| contains('No driver tests were run (1 example(s) found).'), | |
| contains('The following packages had errors:'), | |
| contains( | |
| ' plugin:\n' | |
| ' No tests ran (use --exclude if this is intentional)', | |
| ), | |
| ]), | |
| ); | |
| }); | |
| test('"flutter drive" reports test failures', () async { | |
| final RepositoryPackage plugin = createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>[ | |
| 'example/test_driver/integration_test.dart', | |
| 'example/integration_test/bar_test.dart', | |
| 'example/integration_test/foo_test.dart', | |
| 'example/web/index.html', | |
| ], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformWeb: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| // Simulate failure from `flutter drive`. | |
| processRunner.mockProcessesForExecutable[getFlutterCommand(mockPlatform)] = <FakeProcessInfo>[ | |
| // Fail both bar_test.dart and foo_test.dart. | |
| FakeProcessInfo(MockProcess(exitCode: 1), <String>['drive']), | |
| FakeProcessInfo(MockProcess(exitCode: 1), <String>['drive']), | |
| ]; | |
| Error? commandError; | |
| final List<String> output = await runCapturingPrint( | |
| runner, | |
| <String>['drive-examples', '--web'], | |
| errorHandler: (Error e) { | |
| commandError = e; | |
| }, | |
| ); | |
| expect(commandError, isA<ToolExit>()); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[ | |
| contains('Running for plugin'), | |
| contains('The following packages had errors:'), | |
| contains( | |
| ' plugin:\n' | |
| ' example/integration_test/bar_test.dart\n' | |
| ' example/integration_test/foo_test.dart', | |
| ), | |
| ]), | |
| ); | |
| final Directory pluginExampleDirectory = getExampleDir(plugin); | |
| expect( | |
| processRunner.recordedCalls, | |
| orderedEquals(<ProcessCall>[ | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'drive', | |
| '-d', | |
| 'web-server', | |
| '--web-port=7357', | |
| '--browser-name=chrome', | |
| ..._defaultWebBrowserFlags, | |
| '--screenshot=/path/to/logs/plugin_example-drive', | |
| '--driver', | |
| 'test_driver/integration_test.dart', | |
| '--target', | |
| 'integration_test/bar_test.dart', | |
| ], pluginExampleDirectory.path), | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'drive', | |
| '-d', | |
| 'web-server', | |
| '--web-port=7357', | |
| '--browser-name=chrome', | |
| ..._defaultWebBrowserFlags, | |
| '--screenshot=/path/to/logs/plugin_example-drive', | |
| '--driver', | |
| 'test_driver/integration_test.dart', | |
| '--target', | |
| 'integration_test/foo_test.dart', | |
| ], pluginExampleDirectory.path), | |
| ]), | |
| ); | |
| }); | |
| test('"flutter test" reports test failures', () async { | |
| final RepositoryPackage plugin = createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>[ | |
| 'example/integration_test/bar_test.dart', | |
| 'example/integration_test/foo_test.dart', | |
| 'example/ios/ios.swift', | |
| ], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformIOS: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| setMockFlutterDevicesOutput(); | |
| // Simulate failure from `flutter test`. | |
| processRunner.mockProcessesForExecutable[getFlutterCommand(mockPlatform)]!.add( | |
| FakeProcessInfo(MockProcess(exitCode: 1), <String>['test']), | |
| ); | |
| Error? commandError; | |
| final List<String> output = await runCapturingPrint( | |
| runner, | |
| <String>['drive-examples', '--ios'], | |
| errorHandler: (Error e) { | |
| commandError = e; | |
| }, | |
| ); | |
| expect(commandError, isA<ToolExit>()); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[ | |
| contains('Running for plugin'), | |
| contains('The following packages had errors:'), | |
| contains( | |
| ' plugin:\n' | |
| ' Integration tests failed.', | |
| ), | |
| ]), | |
| ); | |
| final Directory pluginExampleDirectory = getExampleDir(plugin); | |
| expect( | |
| processRunner.recordedCalls, | |
| orderedEquals(<ProcessCall>[ | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'devices', | |
| '--machine', | |
| ], null), | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'test', | |
| '-d', | |
| _fakeIOSDevice, | |
| '--debug-logs-dir=/path/to/logs', | |
| 'integration_test', | |
| ], pluginExampleDirectory.path), | |
| ]), | |
| ); | |
| }); | |
| group('packages', () { | |
| test('can be driven', () async { | |
| final RepositoryPackage package = createFakePackage( | |
| 'a_package', | |
| packagesDir, | |
| extraFiles: <String>[ | |
| 'example/integration_test/foo_test.dart', | |
| 'example/test_driver/integration_test.dart', | |
| 'example/web/index.html', | |
| ], | |
| ); | |
| final Directory exampleDirectory = getExampleDir(package); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--web', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[ | |
| contains('Running for a_package'), | |
| contains('No issues found!'), | |
| ]), | |
| ); | |
| expect( | |
| processRunner.recordedCalls, | |
| orderedEquals(<ProcessCall>[ | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'drive', | |
| '-d', | |
| 'web-server', | |
| '--web-port=7357', | |
| '--browser-name=chrome', | |
| ..._defaultWebBrowserFlags, | |
| '--screenshot=/path/to/logs/a_package_example-drive', | |
| '--driver', | |
| 'test_driver/integration_test.dart', | |
| '--target', | |
| 'integration_test/foo_test.dart', | |
| ], exampleDirectory.path), | |
| ]), | |
| ); | |
| }); | |
| test('drive handles missing CI screenshot directory', () async { | |
| mockPlatform.environment.remove('FLUTTER_LOGS_DIR'); | |
| final RepositoryPackage package = createFakePackage( | |
| 'a_package', | |
| packagesDir, | |
| extraFiles: <String>[ | |
| 'example/integration_test/foo_test.dart', | |
| 'example/test_driver/integration_test.dart', | |
| 'example/web/index.html', | |
| ], | |
| ); | |
| final Directory exampleDirectory = getExampleDir(package); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--web', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[ | |
| contains('Running for a_package'), | |
| contains('No issues found!'), | |
| ]), | |
| ); | |
| expect( | |
| processRunner.recordedCalls, | |
| orderedEquals(<ProcessCall>[ | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'drive', | |
| '-d', | |
| 'web-server', | |
| '--web-port=7357', | |
| '--browser-name=chrome', | |
| ..._defaultWebBrowserFlags, | |
| '--driver', | |
| 'test_driver/integration_test.dart', | |
| '--target', | |
| 'integration_test/foo_test.dart', | |
| ], exampleDirectory.path), | |
| ]), | |
| ); | |
| }); | |
| test('are skipped when example does not support platform', () async { | |
| createFakePackage( | |
| 'a_package', | |
| packagesDir, | |
| isFlutter: true, | |
| extraFiles: <String>[ | |
| 'example/integration_test/foo_test.dart', | |
| 'example/test_driver/integration_test.dart', | |
| ], | |
| ); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--web', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[ | |
| contains('Running for a_package'), | |
| contains( | |
| 'Skipping a_package/example; does not support any ' | |
| 'requested platforms', | |
| ), | |
| contains('SKIPPING: No example supports requested platform(s).'), | |
| ]), | |
| ); | |
| expect(processRunner.recordedCalls.isEmpty, true); | |
| }); | |
| test('drive only supported examples if there is more than one', () async { | |
| final RepositoryPackage package = createFakePackage( | |
| 'a_package', | |
| packagesDir, | |
| isFlutter: true, | |
| examples: <String>['with_web', 'without_web'], | |
| extraFiles: <String>[ | |
| 'example/with_web/integration_test/foo_test.dart', | |
| 'example/with_web/test_driver/integration_test.dart', | |
| 'example/with_web/web/index.html', | |
| 'example/without_web/integration_test/foo_test.dart', | |
| 'example/without_web/test_driver/integration_test.dart', | |
| ], | |
| ); | |
| final Directory supportedExampleDirectory = getExampleDir( | |
| package, | |
| ).childDirectory('with_web'); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--web', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[ | |
| contains('Running for a_package'), | |
| contains( | |
| 'Skipping a_package/example/without_web; does not support any requested platforms.', | |
| ), | |
| contains('No issues found!'), | |
| ]), | |
| ); | |
| expect( | |
| processRunner.recordedCalls, | |
| orderedEquals(<ProcessCall>[ | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'drive', | |
| '-d', | |
| 'web-server', | |
| '--web-port=7357', | |
| '--browser-name=chrome', | |
| ..._defaultWebBrowserFlags, | |
| '--screenshot=/path/to/logs/a_package_example_with_web-drive', | |
| '--driver', | |
| 'test_driver/integration_test.dart', | |
| '--target', | |
| 'integration_test/foo_test.dart', | |
| ], supportedExampleDirectory.path), | |
| ]), | |
| ); | |
| }); | |
| test('are skipped when there is no integration testing', () async { | |
| createFakePackage( | |
| 'a_package', | |
| packagesDir, | |
| isFlutter: true, | |
| extraFiles: <String>['example/web/index.html'], | |
| ); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--web', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[ | |
| contains('Running for a_package'), | |
| contains('SKIPPING: No example is configured for integration tests.'), | |
| ]), | |
| ); | |
| expect(processRunner.recordedCalls.isEmpty, true); | |
| }); | |
| }); | |
| group('file filtering', () { | |
| const files = <String>[ | |
| 'pubspec.yaml', | |
| 'foo.dart', | |
| 'foo.java', | |
| 'foo.kt', | |
| 'foo.m', | |
| 'foo.swift', | |
| 'foo.cc', | |
| 'foo.cpp', | |
| 'foo.h', | |
| ]; | |
| for (final file in files) { | |
| test('runs command for changes to $file', () async { | |
| createFakePackage('package_a', packagesDir); | |
| gitProcessRunner.mockProcessesForExecutable['git-diff'] = <FakeProcessInfo>[ | |
| FakeProcessInfo( | |
| MockProcess( | |
| stdout: | |
| ''' | |
| packages/package_a/$file | |
| ''', | |
| ), | |
| ), | |
| ]; | |
| // The target platform is irrelevant here; because this repo's | |
| // packages are fully federated, there's no need to distinguish | |
| // the ignore list by target (e.g., skipping iOS tests if only Java or | |
| // Kotlin files change), because package-level filering will already | |
| // accomplish the same goal. | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--web', | |
| ]); | |
| expect(output, containsAllInOrder(<Matcher>[contains('Running for package_a')])); | |
| }); | |
| } | |
| test('skips commands if all files should be ignored', () async { | |
| createFakePackage('package_a', packagesDir); | |
| gitProcessRunner.mockProcessesForExecutable['git-diff'] = <FakeProcessInfo>[ | |
| FakeProcessInfo( | |
| MockProcess( | |
| stdout: ''' | |
| README.md | |
| SUGGESTED_REVIEWERS.md | |
| .gitignore | |
| packages/package_a/CHANGELOG.md | |
| ''', | |
| ), | |
| ), | |
| ]; | |
| final List<String> output = await runCapturingPrint(runner, <String>['drive-examples']); | |
| expect(output, isNot(containsAllInOrder(<Matcher>[contains('Running for package_a')]))); | |
| expect(output, containsAllInOrder(<Matcher>[contains('SKIPPING ALL PACKAGES')])); | |
| }); | |
| }); | |
| }); | |
| group('on macOS', () { | |
| late NativePlatform mockPlatform; | |
| late Directory packagesDir; | |
| late CommandRunner<void> runner; | |
| late RecordingProcessRunner processRunner; | |
| setUp(() { | |
| mockPlatform = createMockPlatform(isMacOS: true); | |
| final GitDir gitDir; | |
| (:packagesDir, :processRunner, gitProcessRunner: _, :gitDir) = configureBaseCommandMocks( | |
| platform: mockPlatform, | |
| ); | |
| final command = DriveExamplesCommand( | |
| packagesDir, | |
| processRunner: processRunner, | |
| platform: mockPlatform, | |
| gitDir: gitDir, | |
| ); | |
| runner = CommandRunner<void>('drive_examples_command', 'Test for drive_example_command'); | |
| runner.addCommand(command); | |
| mockPlatform.environment['FLUTTER_LOGS_DIR'] = '/path/to/logs'; | |
| }); | |
| test('drives a web plugin on macOS with mock keychain', () async { | |
| final RepositoryPackage plugin = createFakePlugin( | |
| 'plugin', | |
| packagesDir, | |
| extraFiles: <String>[ | |
| 'example/integration_test/plugin_test.dart', | |
| 'example/test_driver/integration_test.dart', | |
| 'example/web/index.html', | |
| ], | |
| platformSupport: <String, PlatformDetails>{ | |
| platformWeb: const PlatformDetails(PlatformSupport.inline), | |
| }, | |
| ); | |
| final Directory pluginExampleDirectory = getExampleDir(plugin); | |
| final List<String> output = await runCapturingPrint(runner, <String>[ | |
| 'drive-examples', | |
| '--web', | |
| ]); | |
| expect( | |
| output, | |
| containsAllInOrder(<Matcher>[contains('Running for plugin'), contains('No issues found!')]), | |
| ); | |
| expect( | |
| processRunner.recordedCalls, | |
| orderedEquals(<ProcessCall>[ | |
| ProcessCall(getFlutterCommand(mockPlatform), const <String>[ | |
| 'drive', | |
| '-d', | |
| 'web-server', | |
| '--web-port=7357', | |
| '--browser-name=chrome', | |
| ..._defaultWebBrowserFlags, | |
| '--web-browser-flag=--use-mock-keychain', | |
| '--screenshot=/path/to/logs/plugin_example-drive', | |
| '--driver', | |
| 'test_driver/integration_test.dart', | |
| '--target', | |
| 'integration_test/plugin_test.dart', | |
| ], pluginExampleDirectory.path), | |
| ]), | |
| ); | |
| }); | |
| }); | |
| } | |
| class _FakeDelayingProcess extends Fake implements io.Process { | |
| /// Creates a mock process that takes [delayDuration] time to exit successfully. | |
| _FakeDelayingProcess({required Duration delayDuration, required FakeAsync fakeAsync}) | |
| : _delayDuration = delayDuration, | |
| _fakeAsync = fakeAsync; | |
| final Duration _delayDuration; | |
| final FakeAsync _fakeAsync; | |
| @override | |
| Future<int> get exitCode async { | |
| _fakeAsync.elapse(_delayDuration); | |
| return 0; | |
| } | |
| } |