From d9cf066191dd0188d517ce92220d71a1887a2988 Mon Sep 17 00:00:00 2001 From: Kostia Sokolovskyi Date: Mon, 20 May 2024 19:49:04 +0200 Subject: [PATCH] Add tests for shared_app_data.#.dart API examples. (#147830) This PR contributes to https://github.com/flutter/flutter/issues/130459 ### Description - Updates `examples/api/lib/widgets/shared_app_data/shared_app_data.0.dart` to meet latest API examples structure - Updates `examples/api/lib/widgets/shared_app_data/shared_app_data.1.dart` to meet latest API examples structure - Adds tests for `examples/api/lib/widgets/shared_app_data/shared_app_data.0.dart` - Adds tests for `examples/api/lib/widgets/shared_app_data/shared_app_data.1.dart` --- dev/bots/check_code_samples.dart | 2 - .../shared_app_data/shared_app_data.0.dart | 63 +++++++---- .../shared_app_data/shared_app_data.1.dart | 74 ++++++++----- .../shared_app_data.0_test.dart | 100 ++++++++++++++++++ .../shared_app_data.1_test.dart | 48 +++++++++ 5 files changed, 242 insertions(+), 45 deletions(-) create mode 100644 examples/api/test/widgets/shared_app_data/shared_app_data.0_test.dart create mode 100644 examples/api/test/widgets/shared_app_data/shared_app_data.1_test.dart diff --git a/dev/bots/check_code_samples.dart b/dev/bots/check_code_samples.dart index b473032223..3bd8ce371b 100644 --- a/dev/bots/check_code_samples.dart +++ b/dev/bots/check_code_samples.dart @@ -384,8 +384,6 @@ final Set _knownMissingTests = { 'examples/api/test/widgets/inherited_theme/inherited_theme.0_test.dart', 'examples/api/test/widgets/sliver/decorated_sliver.0_test.dart', 'examples/api/test/widgets/autofill/autofill_group.0_test.dart', - 'examples/api/test/widgets/shared_app_data/shared_app_data.1_test.dart', - 'examples/api/test/widgets/shared_app_data/shared_app_data.0_test.dart', 'examples/api/test/widgets/nested_scroll_view/nested_scroll_view_state.0_test.dart', 'examples/api/test/widgets/nested_scroll_view/nested_scroll_view.2_test.dart', 'examples/api/test/widgets/nested_scroll_view/nested_scroll_view.1_test.dart', diff --git a/examples/api/lib/widgets/shared_app_data/shared_app_data.0.dart b/examples/api/lib/widgets/shared_app_data/shared_app_data.0.dart index 2a2c698e50..e1ef871279 100644 --- a/examples/api/lib/widgets/shared_app_data/shared_app_data.0.dart +++ b/examples/api/lib/widgets/shared_app_data/shared_app_data.0.dart @@ -6,38 +6,41 @@ import 'package:flutter/material.dart'; /// Flutter code sample for [SharedAppData]. -class ShowSharedValue extends StatelessWidget { - const ShowSharedValue({super.key, required this.appDataKey}); +void main() { + runApp(const SharedAppDataExampleApp()); +} - final String appDataKey; +class SharedAppDataExampleApp extends StatelessWidget { + const SharedAppDataExampleApp({super.key}); @override Widget build(BuildContext context) { - // The SharedAppData.getValue() call causes this widget to depend on the - // value of the SharedAppData's 'foo' key. If it's changed, with - // SharedAppData.setValue(), then this widget will be rebuilt. - final String value = SharedAppData.getValue(context, appDataKey, () => 'initial'); - return Text('$appDataKey: $value'); + return const MaterialApp( + home: SharedAppDataExample(), + ); } } // Demonstrates that changes to the SharedAppData _only_ cause the dependent // widgets to be rebuilt. In this case that's the ShowSharedValue widget that's // displaying the value of a key whose value has been updated. -class Home extends StatefulWidget { - const Home({super.key}); +class SharedAppDataExample extends StatefulWidget { + const SharedAppDataExample({super.key}); @override - State createState() => _HomeState(); + State createState() => _SharedAppDataExampleState(); } -class _HomeState extends State { +class _SharedAppDataExampleState extends State { int _fooVersion = 0; int _barVersion = 0; @override Widget build(BuildContext context) { return Scaffold( + appBar: AppBar( + title: const Text('SharedAppData Sample'), + ), body: Center( child: Column( mainAxisSize: MainAxisSize.min, @@ -50,10 +53,13 @@ class _HomeState extends State { child: const Text('change foo'), onPressed: () { _fooVersion += 1; - // Changing the SharedAppData's value for 'foo' causes the - // widgets that depend on 'foo' to be rebuilt. + // Changing the SharedAppData's value for 'foo' key causes the + // widgets that depend on 'foo' key to be rebuilt. SharedAppData.setValue( - context, 'foo', 'FOO $_fooVersion'); // no need to call setState() + context, + 'foo', + 'FOO $_fooVersion', + ); // No need to call setState(). }, ), const SizedBox(height: 16), @@ -61,8 +67,13 @@ class _HomeState extends State { child: const Text('change bar'), onPressed: () { _barVersion += 1; + // Changing the SharedAppData's value for 'bar' key causes the + // widgets that depend on 'bar' key to be rebuilt. SharedAppData.setValue( - context, 'bar', 'BAR $_barVersion'); // no need to call setState() + context, + 'bar', + 'BAR $_barVersion', + ); // No need to call setState(). }, ), ], @@ -72,6 +83,22 @@ class _HomeState extends State { } } -void main() { - runApp(const MaterialApp(home: Home())); +class ShowSharedValue extends StatelessWidget { + const ShowSharedValue({super.key, required this.appDataKey}); + + final String appDataKey; + + @override + Widget build(BuildContext context) { + // The SharedAppData.getValue() call causes this widget to depend on the + // value of the SharedAppData's key. If it's changed, with + // SharedAppData.setValue(), then this widget will be rebuilt. + final String value = SharedAppData.getValue( + context, + appDataKey, + () => 'initial', + ); + + return Text('$appDataKey: $value'); + } } diff --git a/examples/api/lib/widgets/shared_app_data/shared_app_data.1.dart b/examples/api/lib/widgets/shared_app_data/shared_app_data.1.dart index 76b081e895..544c688a3e 100644 --- a/examples/api/lib/widgets/shared_app_data/shared_app_data.1.dart +++ b/examples/api/lib/widgets/shared_app_data/shared_app_data.1.dart @@ -7,27 +7,34 @@ import 'package:flutter/material.dart'; /// Flutter code sample for [SharedAppData]. -// A single lazily-constructed object that's shared with the entire application -// via `SharedObject.of(context)`. The value of the object can be changed with -// `SharedObject.reset(context)`. Resetting the value will cause all of the -// widgets that depend on it to be rebuilt. -class SharedObject { - SharedObject._(); +void main() { + runApp(const SharedAppDataExampleApp()); +} - static final Object _sharedObjectKey = Object(); +class SharedAppDataExampleApp extends StatelessWidget { + const SharedAppDataExampleApp({super.key}); @override - String toString() => describeIdentity(this); - - static void reset(BuildContext context) { - // Calling SharedAppData.setValue() causes dependent widgets to be rebuilt. - SharedAppData.setValue(context, _sharedObjectKey, SharedObject._()); + Widget build(BuildContext context) { + return const MaterialApp( + home: SharedAppDataExample(), + ); } +} - static SharedObject of(BuildContext context) { - // If a value for _sharedObjectKey has never been set then the third - // callback parameter is used to generate an initial value. - return SharedAppData.getValue(context, _sharedObjectKey, () => SharedObject._()); +class SharedAppDataExample extends StatelessWidget { + const SharedAppDataExample({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('SharedAppData Sample'), + ), + body: const Center( + child: CustomWidget(), + ), + ); } } @@ -48,17 +55,34 @@ class CustomWidget extends StatelessWidget { } } -class Home extends StatelessWidget { - const Home({super.key}); +// A single lazily-constructed object that's shared with the entire application +// via `SharedObject.of(context)`. The value of the object can be changed with +// `SharedObject.reset(context)`. Resetting the value will cause all of the +// widgets that depend on it to be rebuilt. +class SharedObject { + SharedObject._(); + + static final Object _sharedObjectKey = Object(); @override - Widget build(BuildContext context) { - return const Scaffold( - body: Center(child: CustomWidget()), + String toString() => describeIdentity(this); + + static void reset(BuildContext context) { + // Calling SharedAppData.setValue() causes dependent widgets to be rebuilt. + SharedAppData.setValue( + context, + _sharedObjectKey, + SharedObject._(), + ); + } + + static SharedObject of(BuildContext context) { + // If a value for _sharedObjectKey has never been set then the third + // callback parameter is used to generate an initial value. + return SharedAppData.getValue( + context, + _sharedObjectKey, + () => SharedObject._(), ); } } - -void main() { - runApp(const MaterialApp(home: Home())); -} diff --git a/examples/api/test/widgets/shared_app_data/shared_app_data.0_test.dart b/examples/api/test/widgets/shared_app_data/shared_app_data.0_test.dart new file mode 100644 index 0000000000..c84cb86208 --- /dev/null +++ b/examples/api/test/widgets/shared_app_data/shared_app_data.0_test.dart @@ -0,0 +1,100 @@ +// 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 'package:flutter/material.dart'; +import 'package:flutter_api_samples/widgets/shared_app_data/shared_app_data.0.dart' + as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('Verify correct labels are displayed', (WidgetTester tester) async { + await tester.pumpWidget( + const example.SharedAppDataExampleApp(), + ); + + expect(find.text('SharedAppData Sample'), findsOneWidget); + expect(find.text('foo: initial'), findsOneWidget); + expect(find.text('bar: initial'), findsOneWidget); + expect(find.text('change foo'), findsOneWidget); + expect(find.text('change bar'), findsOneWidget); + }); + + testWidgets('foo value can be updated', (WidgetTester tester) async { + await tester.pumpWidget( + const example.SharedAppDataExampleApp(), + ); + + int counter = 0; + + while (counter < 10) { + counter++; + + await tester.tap(find.ancestor( + of: find.text('change foo'), + matching: find.byType(ElevatedButton), + )); + await tester.pump(); + + expect(find.text('foo: FOO $counter'), findsOneWidget); + } + }); + + testWidgets('bar value can be updated', (WidgetTester tester) async { + await tester.pumpWidget( + const example.SharedAppDataExampleApp(), + ); + + int counter = 0; + + while (counter < 10) { + counter++; + + await tester.tap(find.ancestor( + of: find.text('change bar'), + matching: find.byType(ElevatedButton), + )); + await tester.pump(); + + expect(find.text('bar: BAR $counter'), findsOneWidget); + } + }); + + testWidgets('foo and bar values update independently of one another', (WidgetTester tester) async { + await tester.pumpWidget( + const example.SharedAppDataExampleApp(), + ); + + int fooCounter = 0; + int barCounter = 0; + + for (int i = 0; i < 20; i++) { + if (i.isEven) { + fooCounter++; + } else { + barCounter++; + } + + await tester.tap( + find.ancestor( + of: i.isEven ? find.text('change foo') : find.text('change bar'), + matching: find.byType(ElevatedButton), + ), + ); + await tester.pump(); + + expect( + find.text( + 'foo: ${fooCounter == 0 ? 'initial' : 'FOO $fooCounter'}', + ), + findsOneWidget, + ); + expect( + find.text( + 'bar: ${barCounter == 0 ? 'initial' : 'BAR $barCounter'}', + ), + findsOneWidget, + ); + } + }); +} diff --git a/examples/api/test/widgets/shared_app_data/shared_app_data.1_test.dart b/examples/api/test/widgets/shared_app_data/shared_app_data.1_test.dart new file mode 100644 index 0000000000..4ada24bddd --- /dev/null +++ b/examples/api/test/widgets/shared_app_data/shared_app_data.1_test.dart @@ -0,0 +1,48 @@ +// 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 'package:flutter/material.dart'; +import 'package:flutter_api_samples/widgets/shared_app_data/shared_app_data.1.dart' + as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + example.SharedObject getSharedObject(WidgetTester tester) { + final BuildContext context = tester.element( + find.byType(example.CustomWidget), + ); + return example.SharedObject.of(context); + } + + testWidgets('Verify correct labels are displayed', (WidgetTester tester) async { + await tester.pumpWidget( + const example.SharedAppDataExampleApp(), + ); + + final example.SharedObject sharedObject = getSharedObject(tester); + + expect(find.text('SharedAppData Sample'), findsOneWidget); + expect(find.text('Replace $sharedObject'), findsOneWidget); + }); + + testWidgets('Button tap resets SharedObject', (WidgetTester tester) async { + await tester.pumpWidget( + const example.SharedAppDataExampleApp(), + ); + + for (int i = 0; i < 10; i++) { + final example.SharedObject sharedObject = getSharedObject(tester); + + final Finder buttonFinder = find.ancestor( + of: find.text('Replace $sharedObject'), + matching: find.byType(ElevatedButton), + ); + + expect(buttonFinder, findsOneWidget); + + await tester.tap(buttonFinder); + await tester.pump(); + } + }); +}