Unverified Commit 64a0683b authored by Michael Goderbauer's avatar Michael Goderbauer Committed by GitHub

Analyze code snippets in flutter_test docs (#132246)

Fixes https://github.com/flutter/flutter/issues/132274.
parent e11cc350
...@@ -70,7 +70,8 @@ import 'package:path/path.dart' as path; ...@@ -70,7 +70,8 @@ import 'package:path/path.dart' as path;
import 'package:watcher/watcher.dart'; import 'package:watcher/watcher.dart';
final String _flutterRoot = path.dirname(path.dirname(path.dirname(path.fromUri(Platform.script)))); final String _flutterRoot = path.dirname(path.dirname(path.dirname(path.fromUri(Platform.script))));
final String _defaultFlutterPackage = path.join(_flutterRoot, 'packages', 'flutter', 'lib'); final String _packageFlutter = path.join(_flutterRoot, 'packages', 'flutter', 'lib');
final String _packageFlutterTest = path.join(_flutterRoot, 'packages', 'flutter_test', 'lib');
final String _defaultDartUiLocation = path.join(_flutterRoot, 'bin', 'cache', 'pkg', 'sky_engine', 'lib', 'ui'); final String _defaultDartUiLocation = path.join(_flutterRoot, 'bin', 'cache', 'pkg', 'sky_engine', 'lib', 'ui');
final String _flutter = path.join(_flutterRoot, 'bin', Platform.isWindows ? 'flutter.bat' : 'flutter'); final String _flutter = path.join(_flutterRoot, 'bin', Platform.isWindows ? 'flutter.bat' : 'flutter');
...@@ -142,12 +143,16 @@ Future<void> main(List<String> arguments) async { ...@@ -142,12 +143,16 @@ Future<void> main(List<String> arguments) async {
exit(0); exit(0);
} }
Directory flutterPackage; List<Directory> flutterPackages;
if (parsedArguments.rest.length == 1) { if (parsedArguments.rest.length == 1) {
// Used for testing. // Used for testing.
flutterPackage = Directory(parsedArguments.rest.single); flutterPackages = <Directory>[Directory(parsedArguments.rest.single)];
} else { } else {
flutterPackage = Directory(_defaultFlutterPackage); flutterPackages = <Directory>[
Directory(_packageFlutter),
Directory(_packageFlutterTest),
// TODO(goderbauer): Add all other packages.
];
} }
final bool includeDartUi = parsedArguments.wasParsed('dart-ui-location') || parsedArguments['include-dart-ui'] as bool; final bool includeDartUi = parsedArguments.wasParsed('dart-ui-location') || parsedArguments['include-dart-ui'] as bool;
...@@ -165,14 +170,14 @@ Future<void> main(List<String> arguments) async { ...@@ -165,14 +170,14 @@ Future<void> main(List<String> arguments) async {
if (parsedArguments['interactive'] != null) { if (parsedArguments['interactive'] != null) {
await _runInteractive( await _runInteractive(
flutterPackage: flutterPackage, flutterPackages: flutterPackages,
tempDirectory: parsedArguments['temp'] as String?, tempDirectory: parsedArguments['temp'] as String?,
filePath: parsedArguments['interactive'] as String, filePath: parsedArguments['interactive'] as String,
dartUiLocation: includeDartUi ? dartUiLocation : null, dartUiLocation: includeDartUi ? dartUiLocation : null,
); );
} else { } else {
if (await _SnippetChecker( if (await _SnippetChecker(
flutterPackage, flutterPackages,
tempDirectory: parsedArguments['temp'] as String?, tempDirectory: parsedArguments['temp'] as String?,
verbose: parsedArguments['verbose'] as bool, verbose: parsedArguments['verbose'] as bool,
dartUiLocation: includeDartUi ? dartUiLocation : null, dartUiLocation: includeDartUi ? dartUiLocation : null,
...@@ -360,7 +365,7 @@ class _SnippetChecker { ...@@ -360,7 +365,7 @@ class _SnippetChecker {
/// supplied, the default location of the `dart:ui` code in the Flutter /// supplied, the default location of the `dart:ui` code in the Flutter
/// repository is used (i.e. "<flutter repo>/bin/cache/pkg/sky_engine/lib/ui"). /// repository is used (i.e. "<flutter repo>/bin/cache/pkg/sky_engine/lib/ui").
_SnippetChecker( _SnippetChecker(
this._flutterPackage, { this._flutterPackages, {
String? tempDirectory, String? tempDirectory,
this.verbose = false, this.verbose = false,
Directory? dartUiLocation, Directory? dartUiLocation,
...@@ -438,8 +443,8 @@ class _SnippetChecker { ...@@ -438,8 +443,8 @@ class _SnippetChecker {
/// automatically if there are no errors unless _keepTmp is true. /// automatically if there are no errors unless _keepTmp is true.
final Directory _tempDirectory; final Directory _tempDirectory;
/// The package directory for the flutter package within the flutter root dir. /// The package directories within the flutter root dir that will be checked.
final Directory _flutterPackage; final List<Directory> _flutterPackages;
/// The directory for the dart:ui code to be analyzed with the flutter code. /// The directory for the dart:ui code to be analyzed with the flutter code.
/// ///
...@@ -481,7 +486,7 @@ class _SnippetChecker { ...@@ -481,7 +486,7 @@ class _SnippetChecker {
"import 'dart:typed_data';", "import 'dart:typed_data';",
"import 'dart:ui' as ui;", "import 'dart:ui' as ui;",
"import 'package:flutter_test/flutter_test.dart';", "import 'package:flutter_test/flutter_test.dart';",
for (final File file in _listDartFiles(Directory(_defaultFlutterPackage))) for (final File file in _listDartFiles(Directory(_packageFlutter)))
"import 'package:flutter/${path.basename(file.path)}';", "import 'package:flutter/${path.basename(file.path)}';",
].map<_Line>((String code) => _Line.generated(code: code)).toList(); ].map<_Line>((String code) => _Line.generated(code: code)).toList();
} }
...@@ -495,7 +500,8 @@ class _SnippetChecker { ...@@ -495,7 +500,8 @@ class _SnippetChecker {
stderr.writeln('Unable to analyze engine dart snippets at ${_dartUiLocation!.path}.'); stderr.writeln('Unable to analyze engine dart snippets at ${_dartUiLocation!.path}.');
} }
final List<File> filesToAnalyze = <File>[ final List<File> filesToAnalyze = <File>[
..._listDartFiles(_flutterPackage, recursive: true), for (final Directory flutterPackage in _flutterPackages)
..._listDartFiles(flutterPackage, recursive: true),
if (_dartUiLocation != null && _dartUiLocation!.existsSync()) if (_dartUiLocation != null && _dartUiLocation!.existsSync())
..._listDartFiles(_dartUiLocation!, recursive: true), ..._listDartFiles(_dartUiLocation!, recursive: true),
]; ];
...@@ -1084,7 +1090,7 @@ class _SnippetFile { ...@@ -1084,7 +1090,7 @@ class _SnippetFile {
Future<void> _runInteractive({ Future<void> _runInteractive({
required String? tempDirectory, required String? tempDirectory,
required Directory flutterPackage, required List<Directory> flutterPackages,
required String filePath, required String filePath,
required Directory? dartUiLocation, required Directory? dartUiLocation,
}) async { }) async {
...@@ -1106,7 +1112,7 @@ Future<void> _runInteractive({ ...@@ -1106,7 +1112,7 @@ Future<void> _runInteractive({
print('Starting up in interactive mode on ${path.relative(filePath, from: _flutterRoot)} ...'); print('Starting up in interactive mode on ${path.relative(filePath, from: _flutterRoot)} ...');
print('Type "q" to quit, or "r" to force a reload.'); print('Type "q" to quit, or "r" to force a reload.');
final _SnippetChecker checker = _SnippetChecker(flutterPackage, tempDirectory: tempDirectory) final _SnippetChecker checker = _SnippetChecker(flutterPackages, tempDirectory: tempDirectory)
.._createConfigurationFiles(); .._createConfigurationFiles();
ProcessSignal.sigint.watch().listen((_) { ProcessSignal.sigint.watch().listen((_) {
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
/// with the following signature: /// with the following signature:
/// ///
/// ```dart /// ```dart
/// Future<void> testExecutable(FutureOr<void> Function() testMain); /// Future<void> testExecutable(FutureOr<void> Function() testMain) async { }
/// ``` /// ```
/// ///
/// The test framework will execute that method and pass it the `main()` method /// The test framework will execute that method and pass it the `main()` method
......
...@@ -57,6 +57,9 @@ class Evaluation { ...@@ -57,6 +57,9 @@ class Evaluation {
} }
} }
// Examples can assume:
// typedef HomePage = Placeholder;
/// An accessibility guideline describes a recommendation an application should /// An accessibility guideline describes a recommendation an application should
/// meet to be considered accessible. /// meet to be considered accessible.
/// ///
......
...@@ -55,14 +55,14 @@ import 'package:flutter/widgets.dart'; ...@@ -55,14 +55,14 @@ import 'package:flutter/widgets.dart';
/// // Start recording (`recording` is true) /// // Start recording (`recording` is true)
/// await tester.pumpFrames(animationSheet.record( /// await tester.pumpFrames(animationSheet.record(
/// target, /// target,
/// recording: true, /// recording: true, // ignore: avoid_redundant_argument_values
/// ), const Duration(seconds: 1)); /// ), const Duration(seconds: 1));
/// ///
/// await gesture.up(); /// await gesture.up();
/// ///
/// await tester.pumpFrames(animationSheet.record( /// await tester.pumpFrames(animationSheet.record(
/// target, /// target,
/// recording: true, /// recording: true, // ignore: avoid_redundant_argument_values
/// ), const Duration(seconds: 1)); /// ), const Duration(seconds: 1));
/// ///
/// // Compare against golden file /// // Compare against golden file
......
...@@ -143,6 +143,10 @@ class CapturedAccessibilityAnnouncement { ...@@ -143,6 +143,10 @@ class CapturedAccessibilityAnnouncement {
final Assertiveness assertiveness; final Assertiveness assertiveness;
} }
// Examples can assume:
// late TestWidgetsFlutterBinding binding;
// late Size someSize;
/// Base class for bindings used by widgets library tests. /// Base class for bindings used by widgets library tests.
/// ///
/// The [ensureInitialized] method creates (if necessary) and returns an /// The [ensureInitialized] method creates (if necessary) and returns an
...@@ -1548,7 +1552,7 @@ class AutomatedTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding { ...@@ -1548,7 +1552,7 @@ class AutomatedTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
/// ```dart /// ```dart
/// TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized(); /// TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
/// if (binding is LiveTestWidgetsFlutterBinding) { /// if (binding is LiveTestWidgetsFlutterBinding) {
/// binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.[thePolicy]; /// binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.onlyPumps;
/// } /// }
/// ``` /// ```
/// {@endtemplate} /// {@endtemplate}
......
// 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:typed_data';
import 'package:matcher/expect.dart' show Description;
import 'package:matcher/src/expect/async_matcher.dart'; // ignore: implementation_imports
import 'package:test_api/hooks.dart' show TestFailure;
import 'goldens.dart';
/// Matcher created by [bufferMatchesGoldenFile].
class _BufferGoldenMatcher extends AsyncMatcher {
/// Creates an instance of [BufferGoldenMatcher]. Called by [bufferMatchesGoldenFile].
const _BufferGoldenMatcher(this.key, this.version);
/// The [key] to the golden image.
final Uri key;
/// The [version] of the golden image.
final int? version;
@override
Future<String?> matchAsync(dynamic item) async {
Uint8List buffer;
if (item is List<int>) {
buffer = Uint8List.fromList(item);
} else if (item is Future<List<int>>) {
buffer = Uint8List.fromList(await item);
} else {
throw AssertionError('Expected `List<int>` or `Future<List<int>>`, instead found: ${item.runtimeType}');
}
final Uri testNameUri = goldenFileComparator.getTestUri(key, version);
if (autoUpdateGoldenFiles) {
await goldenFileComparator.update(testNameUri, buffer);
return null;
}
try {
final bool success = await goldenFileComparator.compare(buffer, testNameUri);
return success ? null : 'does not match';
} on TestFailure catch (ex) {
return ex.message;
}
}
@override
Description describe(Description description) {
final Uri testNameUri = goldenFileComparator.getTestUri(key, version);
return description.add('Byte buffer matches golden image "$testNameUri"');
}
}
/// Asserts that a [Future<List<int>>], or [List<int] matches the
/// golden image file identified by [key], with an optional [version] number.
///
/// The [key] is the [String] representation of a URL.
///
/// The [version] is a number that can be used to differentiate historical
/// golden files. This parameter is optional.
///
/// {@tool snippet}
/// Sample invocations of [bufferMatchesGoldenFile].
///
/// ```dart
/// await expectLater(
/// const <int>[ /* bytes... */ ],
/// bufferMatchesGoldenFile('sample.png'),
/// );
/// ```
/// {@end-tool}
AsyncMatcher bufferMatchesGoldenFile(String key, {int? version}) {
return _BufferGoldenMatcher(Uri.parse(key), version);
}
...@@ -24,6 +24,9 @@ const double kDragSlopDefault = 20.0; ...@@ -24,6 +24,9 @@ const double kDragSlopDefault = 20.0;
const String _defaultPlatform = kIsWeb ? 'web' : 'android'; const String _defaultPlatform = kIsWeb ? 'web' : 'android';
// Examples can assume:
// typedef MyWidget = Placeholder;
/// Class that programmatically interacts with the [Semantics] tree. /// Class that programmatically interacts with the [Semantics] tree.
/// ///
/// Allows for testing of the [Semantics] tree, which is used by assistive /// Allows for testing of the [Semantics] tree, which is used by assistive
...@@ -123,13 +126,13 @@ class SemanticsController { ...@@ -123,13 +126,13 @@ class SemanticsController {
/// ///
/// ## Sample Code /// ## Sample Code
/// ///
/// ``` /// ```dart
/// testWidgets('MyWidget', (WidgetTester tester) async { /// testWidgets('MyWidget', (WidgetTester tester) async {
/// await tester.pumpWidget(MyWidget()); /// await tester.pumpWidget(const MyWidget());
/// ///
/// expect( /// expect(
/// tester.semantics.simulatedAccessibilityTraversal(), /// tester.semantics.simulatedAccessibilityTraversal(),
/// containsAllInOrder([ /// containsAllInOrder(<Matcher>[
/// containsSemantics(label: 'My Widget'), /// containsSemantics(label: 'My Widget'),
/// containsSemantics(label: 'is awesome!', isChecked: true), /// containsSemantics(label: 'is awesome!', isChecked: true),
/// ]), /// ]),
......
...@@ -17,6 +17,12 @@ typedef ElementPredicate = bool Function(Element element); ...@@ -17,6 +17,12 @@ typedef ElementPredicate = bool Function(Element element);
/// Some frequently used widget [Finder]s. /// Some frequently used widget [Finder]s.
const CommonFinders find = CommonFinders._(); const CommonFinders find = CommonFinders._();
// Examples can assume:
// typedef Button = Placeholder;
// late WidgetTester tester;
// late String filePath;
// late Key backKey;
/// Provides lightweight syntax for getting frequently used widget [Finder]s. /// Provides lightweight syntax for getting frequently used widget [Finder]s.
/// ///
/// This class is instantiated once, as [find]. /// This class is instantiated once, as [find].
...@@ -116,9 +122,9 @@ class CommonFinders { ...@@ -116,9 +122,9 @@ class CommonFinders {
/// ///
/// ```dart /// ```dart
/// // Suppose you have a button with text 'Update' in it: /// // Suppose you have a button with text 'Update' in it:
/// Button( /// const Button(
/// child: Text('Update') /// child: Text('Update')
/// ) /// );
/// ///
/// // You can find and tap on it like this: /// // You can find and tap on it like this:
/// tester.tap(find.widgetWithText(Button, 'Update')); /// tester.tap(find.widgetWithText(Button, 'Update'));
...@@ -217,9 +223,9 @@ class CommonFinders { ...@@ -217,9 +223,9 @@ class CommonFinders {
/// ///
/// ```dart /// ```dart
/// // Suppose you have a button with icon 'arrow_forward' in it: /// // Suppose you have a button with icon 'arrow_forward' in it:
/// Button( /// const Button(
/// child: Icon(Icons.arrow_forward) /// child: Icon(Icons.arrow_forward)
/// ) /// );
/// ///
/// // You can find and tap on it like this: /// // You can find and tap on it like this:
/// tester.tap(find.widgetWithIcon(Button, Icons.arrow_forward)); /// tester.tap(find.widgetWithIcon(Button, Icons.arrow_forward));
...@@ -242,11 +248,11 @@ class CommonFinders { ...@@ -242,11 +248,11 @@ class CommonFinders {
/// ```dart /// ```dart
/// // Suppose you have a button with image in it: /// // Suppose you have a button with image in it:
/// Button( /// Button(
/// child: Image.file(filePath) /// child: Image.file(File(filePath))
/// ) /// );
/// ///
/// // You can find and tap on it like this: /// // You can find and tap on it like this:
/// tester.tap(find.widgetWithImage(Button, FileImage(filePath))); /// tester.tap(find.widgetWithImage(Button, FileImage(File(filePath))));
/// ``` /// ```
/// ///
/// If the `skipOffstage` argument is true (the default), then this skips /// If the `skipOffstage` argument is true (the default), then this skips
...@@ -283,7 +289,7 @@ class CommonFinders { ...@@ -283,7 +289,7 @@ class CommonFinders {
/// ///
/// ```dart /// ```dart
/// // Suppose you have a button created like this: /// // Suppose you have a button created like this:
/// Widget myButton = Button( /// Widget myButton = const Button(
/// child: Text('Update') /// child: Text('Update')
/// ); /// );
/// ///
...@@ -396,7 +402,7 @@ class CommonFinders { ...@@ -396,7 +402,7 @@ class CommonFinders {
/// tester.widget<Opacity>( /// tester.widget<Opacity>(
/// find.ancestor( /// find.ancestor(
/// of: find.text('faded'), /// of: find.text('faded'),
/// matching: find.byType('Opacity'), /// matching: find.byType(Opacity),
/// ) /// )
/// ).opacity, /// ).opacity,
/// 0.5 /// 0.5
......
...@@ -331,6 +331,13 @@ Matcher isMethodCall(String name, { required dynamic arguments }) { ...@@ -331,6 +331,13 @@ Matcher isMethodCall(String name, { required dynamic arguments }) {
Matcher coversSameAreaAs(Path expectedPath, { required Rect areaToCompare, int sampleSize = 20 }) Matcher coversSameAreaAs(Path expectedPath, { required Rect areaToCompare, int sampleSize = 20 })
=> _CoversSameAreaAs(expectedPath, areaToCompare: areaToCompare, sampleSize: sampleSize); => _CoversSameAreaAs(expectedPath, areaToCompare: areaToCompare, sampleSize: sampleSize);
// Examples can assume:
// late Image image;
// late Future<Image> imageFuture;
// typedef MyWidget = Placeholder;
// late Future<ByteData> someFont;
// late WidgetTester tester;
/// Asserts that a [Finder], [Future<ui.Image>], or [ui.Image] matches the /// Asserts that a [Finder], [Future<ui.Image>], or [ui.Image] matches the
/// golden image file identified by [key], with an optional [version] number. /// golden image file identified by [key], with an optional [version] number.
/// ///
...@@ -404,18 +411,18 @@ Matcher coversSameAreaAs(Path expectedPath, { required Rect areaToCompare, int s ...@@ -404,18 +411,18 @@ Matcher coversSameAreaAs(Path expectedPath, { required Rect areaToCompare, int s
/// {@tool snippet} /// {@tool snippet}
/// How to load a custom font for golden images. /// How to load a custom font for golden images.
/// ```dart /// ```dart
/// testWidgets('Creating a golden image with a custom font', (tester) async { /// testWidgets('Creating a golden image with a custom font', (WidgetTester tester) async {
/// // Assuming the 'Roboto.ttf' file is declared in the pubspec.yaml file /// // Assuming the 'Roboto.ttf' file is declared in the pubspec.yaml file
/// final font = rootBundle.load('path/to/font-file/Roboto.ttf'); /// final Future<ByteData> font = rootBundle.load('path/to/font-file/Roboto.ttf');
/// ///
/// final fontLoader = FontLoader('Roboto')..addFont(font); /// final FontLoader fontLoader = FontLoader('Roboto')..addFont(font);
/// await fontLoader.load(); /// await fontLoader.load();
/// ///
/// await tester.pumpWidget(const SomeWidget()); /// await tester.pumpWidget(const MyWidget());
/// ///
/// await expectLater( /// await expectLater(
/// find.byType(SomeWidget), /// find.byType(MyWidget),
/// matchesGoldenFile('someWidget.png'), /// matchesGoldenFile('myWidget.png'),
/// ); /// );
/// }); /// });
/// ``` /// ```
...@@ -431,7 +438,7 @@ Matcher coversSameAreaAs(Path expectedPath, { required Rect areaToCompare, int s ...@@ -431,7 +438,7 @@ Matcher coversSameAreaAs(Path expectedPath, { required Rect areaToCompare, int s
/// ```dart /// ```dart
/// Future<void> testExecutable(FutureOr<void> Function() testMain) async { /// Future<void> testExecutable(FutureOr<void> Function() testMain) async {
/// setUpAll(() async { /// setUpAll(() async {
/// final fontLoader = FontLoader('SomeFont')..addFont(someFont); /// final FontLoader fontLoader = FontLoader('SomeFont')..addFont(someFont);
/// await fontLoader.load(); /// await fontLoader.load();
/// }); /// });
/// ///
...@@ -473,18 +480,20 @@ AsyncMatcher matchesGoldenFile(Object key, {int? version}) { ...@@ -473,18 +480,20 @@ AsyncMatcher matchesGoldenFile(Object key, {int? version}) {
/// ## Sample code /// ## Sample code
/// ///
/// ```dart /// ```dart
/// final ui.Paint paint = ui.Paint() /// testWidgets('matchesReferenceImage', (WidgetTester tester) async {
/// ..style = ui.PaintingStyle.stroke /// final ui.Paint paint = ui.Paint()
/// ..strokeWidth = 1.0; /// ..style = ui.PaintingStyle.stroke
/// final ui.PictureRecorder recorder = ui.PictureRecorder(); /// ..strokeWidth = 1.0;
/// final ui.Canvas pictureCanvas = ui.Canvas(recorder); /// final ui.PictureRecorder recorder = ui.PictureRecorder();
/// pictureCanvas.drawCircle(Offset.zero, 20.0, paint); /// final ui.Canvas pictureCanvas = ui.Canvas(recorder);
/// final ui.Picture picture = recorder.endRecording(); /// pictureCanvas.drawCircle(Offset.zero, 20.0, paint);
/// ui.Image referenceImage = picture.toImage(50, 50); /// final ui.Picture picture = recorder.endRecording();
/// /// ui.Image referenceImage = await picture.toImage(50, 50);
/// await expectLater(find.text('Save'), matchesReferenceImage(referenceImage)); ///
/// await expectLater(image, matchesReferenceImage(referenceImage); /// await expectLater(find.text('Save'), matchesReferenceImage(referenceImage));
/// await expectLater(imageFuture, matchesReferenceImage(referenceImage)); /// await expectLater(image, matchesReferenceImage(referenceImage));
/// await expectLater(imageFuture, matchesReferenceImage(referenceImage));
/// });
/// ``` /// ```
/// ///
/// See also: /// See also:
...@@ -508,9 +517,12 @@ AsyncMatcher matchesReferenceImage(ui.Image image) { ...@@ -508,9 +517,12 @@ AsyncMatcher matchesReferenceImage(ui.Image image) {
/// ## Sample code /// ## Sample code
/// ///
/// ```dart /// ```dart
/// final SemanticsHandle handle = tester.ensureSemantics(); /// testWidgets('matchesSemantics', (WidgetTester tester) async {
/// expect(tester.getSemantics(find.text('hello')), matchesSemantics(label: 'hello')); /// final SemanticsHandle handle = tester.ensureSemantics();
/// handle.dispose(); /// // ...
/// expect(tester.getSemantics(find.text('hello')), matchesSemantics(label: 'hello'));
/// handle.dispose();
/// });
/// ``` /// ```
/// ///
/// See also: /// See also:
...@@ -685,9 +697,12 @@ Matcher matchesSemantics({ ...@@ -685,9 +697,12 @@ Matcher matchesSemantics({
/// ## Sample code /// ## Sample code
/// ///
/// ```dart /// ```dart
/// final SemanticsHandle handle = tester.ensureSemantics(); /// testWidgets('containsSemantics', (WidgetTester tester) async {
/// expect(tester.getSemantics(find.text('hello')), hasSemantics(label: 'hello')); /// final SemanticsHandle handle = tester.ensureSemantics();
/// handle.dispose(); /// // ...
/// expect(tester.getSemantics(find.text('hello')), containsSemantics(label: 'hello'));
/// handle.dispose();
/// });
/// ``` /// ```
/// ///
/// See also: /// See also:
...@@ -859,9 +874,12 @@ Matcher containsSemantics({ ...@@ -859,9 +874,12 @@ Matcher containsSemantics({
/// ## Sample code /// ## Sample code
/// ///
/// ```dart /// ```dart
/// final SemanticsHandle handle = tester.ensureSemantics(); /// testWidgets('containsSemantics', (WidgetTester tester) async {
/// await expectLater(tester, meetsGuideline(textContrastGuideline)); /// final SemanticsHandle handle = tester.ensureSemantics();
/// handle.dispose(); /// // ...
/// await expectLater(tester, meetsGuideline(textContrastGuideline));
/// handle.dispose();
/// });
/// ``` /// ```
/// ///
/// Supported accessibility guidelines: /// Supported accessibility guidelines:
......
...@@ -12,6 +12,10 @@ import 'finders.dart'; ...@@ -12,6 +12,10 @@ import 'finders.dart';
import 'recording_canvas.dart'; import 'recording_canvas.dart';
import 'test_async_utils.dart'; import 'test_async_utils.dart';
// Examples can assume:
// late RenderObject myRenderObject;
// late Symbol methodName;
/// Matches objects or functions that paint a display list that matches the /// Matches objects or functions that paint a display list that matches the
/// canvas calls described by the pattern. /// canvas calls described by the pattern.
/// ///
...@@ -20,8 +24,8 @@ import 'test_async_utils.dart'; ...@@ -20,8 +24,8 @@ import 'test_async_utils.dart';
/// following signatures: /// following signatures:
/// ///
/// ```dart /// ```dart
/// void function(PaintingContext context, Offset offset); /// void exampleOne(PaintingContext context, Offset offset) { }
/// void function(Canvas canvas); /// void exampleTwo(Canvas canvas) { }
/// ``` /// ```
/// ///
/// In the case of functions that take a [PaintingContext] and an [Offset], the /// In the case of functions that take a [PaintingContext] and an [Offset], the
...@@ -65,7 +69,9 @@ Matcher paintsExactlyCountTimes(Symbol methodName, int count) { ...@@ -65,7 +69,9 @@ Matcher paintsExactlyCountTimes(Symbol methodName, int count) {
/// literal syntax, for example: /// literal syntax, for example:
/// ///
/// ```dart /// ```dart
/// if (methodName == #drawCircle) { ... } /// if (methodName == #drawCircle) {
/// // ...
/// }
/// ``` /// ```
typedef PaintPatternPredicate = bool Function(Symbol methodName, List<dynamic> arguments); typedef PaintPatternPredicate = bool Function(Symbol methodName, List<dynamic> arguments);
......
...@@ -8,15 +8,15 @@ ...@@ -8,15 +8,15 @@
/// ```dart /// ```dart
/// class A { /// class A {
/// const A(this.i); /// const A(this.i);
/// int i; /// final int? i;
/// } /// }
/// ///
/// main () { /// void main () {
/// // prevent prefer_const_constructors lint /// // prevent prefer_const_constructors lint
/// A(nonconst(null)); /// A(nonconst(null));
/// ///
/// // prevent prefer_const_declarations lint /// // prevent prefer_const_declarations lint
/// final int $null = nonconst(null); /// final int? $null = nonconst(null);
/// final A a = nonconst(const A(null)); /// final A a = nonconst(const A(null));
/// } /// }
/// ``` /// ```
......
...@@ -35,6 +35,9 @@ class RecordedInvocation { ...@@ -35,6 +35,9 @@ class RecordedInvocation {
} }
} }
// Examples can assume:
// late WidgetTester tester;
/// A [Canvas] for tests that records its method calls. /// A [Canvas] for tests that records its method calls.
/// ///
/// This class can be used in conjunction with [TestRecordingPaintingContext] /// This class can be used in conjunction with [TestRecordingPaintingContext]
......
...@@ -12,6 +12,9 @@ class _AsyncScope { ...@@ -12,6 +12,9 @@ class _AsyncScope {
final Zone zone; final Zone zone;
} }
// Examples can assume:
// late WidgetTester tester;
/// Utility class for all the async APIs in the `flutter_test` library. /// Utility class for all the async APIs in the `flutter_test` library.
/// ///
/// This class provides checking for asynchronous APIs, allowing the library to /// This class provides checking for asynchronous APIs, allowing the library to
......
...@@ -81,6 +81,9 @@ E? _lastWhereOrNull<E>(Iterable<E> list, bool Function(E) test) { ...@@ -81,6 +81,9 @@ E? _lastWhereOrNull<E>(Iterable<E> list, bool Function(E) test) {
return null; return null;
} }
// Examples can assume:
// typedef MyWidget = Placeholder;
/// Runs the [callback] inside the Flutter test environment. /// Runs the [callback] inside the Flutter test environment.
/// ///
/// Use this function for testing custom [StatelessWidget]s and /// Use this function for testing custom [StatelessWidget]s and
...@@ -117,7 +120,7 @@ E? _lastWhereOrNull<E>(Iterable<E> list, bool Function(E) test) { ...@@ -117,7 +120,7 @@ E? _lastWhereOrNull<E>(Iterable<E> list, bool Function(E) test) {
/// ///
/// ```dart /// ```dart
/// testWidgets('MyWidget', (WidgetTester tester) async { /// testWidgets('MyWidget', (WidgetTester tester) async {
/// await tester.pumpWidget(MyWidget()); /// await tester.pumpWidget(const MyWidget());
/// await tester.tap(find.text('Save')); /// await tester.tap(find.text('Save'));
/// expect(find.text('Success'), findsOneWidget); /// expect(find.text('Success'), findsOneWidget);
/// }); /// });
...@@ -319,12 +322,13 @@ class TargetPlatformVariant extends TestVariant<TargetPlatform> { ...@@ -319,12 +322,13 @@ class TargetPlatformVariant extends TestVariant<TargetPlatform> {
/// } /// }
/// ///
/// final ValueVariant<TestScenario> variants = ValueVariant<TestScenario>( /// final ValueVariant<TestScenario> variants = ValueVariant<TestScenario>(
/// <TestScenario>{value1, value2}, /// <TestScenario>{TestScenario.value1, TestScenario.value2},
/// ); /// );
/// /// void main() {
/// testWidgets('Test handling of TestScenario', (WidgetTester tester) { /// testWidgets('Test handling of TestScenario', (WidgetTester tester) async {
/// expect(variants.currentValue, equals(value1)); /// expect(variants.currentValue, equals(TestScenario.value1));
/// }, variant: variants); /// }, variant: variants);
/// }
/// ``` /// ```
/// {@end-tool} /// {@end-tool}
class ValueVariant<T> extends TestVariant<T> { class ValueVariant<T> extends TestVariant<T> {
...@@ -507,7 +511,7 @@ Future<void> expectLater( ...@@ -507,7 +511,7 @@ Future<void> expectLater(
/// ///
/// ```dart /// ```dart
/// testWidgets('MyWidget', (WidgetTester tester) async { /// testWidgets('MyWidget', (WidgetTester tester) async {
/// await tester.pumpWidget(MyWidget()); /// await tester.pumpWidget(const MyWidget());
/// await tester.tap(find.text('Save')); /// await tester.tap(find.text('Save'));
/// await tester.pump(); // allow the application to handle /// await tester.pump(); // allow the application to handle
/// await tester.pump(const Duration(seconds: 1)); // skip past the animation /// await tester.pump(const Duration(seconds: 1)); // skip past the animation
...@@ -555,7 +559,7 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker ...@@ -555,7 +559,7 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
/// {@tool snippet} /// {@tool snippet}
/// ```dart /// ```dart
/// testWidgets('MyWidget asserts invalid bounds', (WidgetTester tester) async { /// testWidgets('MyWidget asserts invalid bounds', (WidgetTester tester) async {
/// await tester.pumpWidget(MyWidget(-1)); /// await tester.pumpWidget(const MyWidget());
/// expect(tester.takeException(), isAssertionError); // or isNull, as appropriate. /// expect(tester.takeException(), isAssertionError); // or isNull, as appropriate.
/// }); /// });
/// ``` /// ```
......
...@@ -1173,7 +1173,7 @@ class _UnsupportedDisplay implements TestDisplay { ...@@ -1173,7 +1173,7 @@ class _UnsupportedDisplay implements TestDisplay {
/// // Fake the desired properties of the TestWindow. All code running /// // Fake the desired properties of the TestWindow. All code running
/// // within this test will perceive the following fake text scale /// // within this test will perceive the following fake text scale
/// // factor as the real text scale factor of the window. /// // factor as the real text scale factor of the window.
/// testBinding.window.textScaleFactorFakeValue = 2.5; /// testBinding.window.textScaleFactorTestValue = 2.5; // ignore: deprecated_member_use
/// ///
/// // Test code that depends on text scale factor here. /// // Test code that depends on text scale factor here.
/// }); /// });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment