Reland Add test for dynamic_content_color.0.dart (#158547)
Fixes https://github.com/flutter/flutter/issues/130459 Follow up of the reverted https://github.com/flutter/flutter/pull/158309 It adds a test for - `examples/api/lib/material/color_scheme/dynamic_content_color.0.dart`
This commit is contained in:
parent
f38127af06
commit
c1ee381b18
@ -142,29 +142,18 @@ class SampleChecker {
|
|||||||
// Get a list of the filenames that were not found in the source files.
|
// Get a list of the filenames that were not found in the source files.
|
||||||
final List<String> missingFilenames = checkForMissingLinks(exampleFilenames, exampleLinks);
|
final List<String> missingFilenames = checkForMissingLinks(exampleFilenames, exampleLinks);
|
||||||
|
|
||||||
// Get a list of any tests that are missing, as well as any that used to be
|
// Get a list of any tests that are missing.
|
||||||
// missing, but have been implemented.
|
final List<File> missingTests = checkForMissingTests(exampleFilenames);
|
||||||
final (List<File> missingTests, List<File> noLongerMissing) = checkForMissingTests(exampleFilenames);
|
|
||||||
|
|
||||||
// Remove any that we know are exceptions (examples that aren't expected to be
|
// Remove any that we know are exceptions (examples that aren't expected to be
|
||||||
// linked into any source files). These are typically template files used to
|
// linked into any source files). These are typically template files used to
|
||||||
// generate new examples.
|
// generate new examples.
|
||||||
missingFilenames.removeWhere((String file) => _knownUnlinkedExamples.contains(file));
|
missingFilenames.removeWhere((String file) => _knownUnlinkedExamples.contains(file));
|
||||||
|
|
||||||
if (missingFilenames.isEmpty && missingTests.isEmpty && noLongerMissing.isEmpty && malformedLinks.isEmpty) {
|
if (missingFilenames.isEmpty && missingTests.isEmpty && malformedLinks.isEmpty) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (noLongerMissing.isNotEmpty) {
|
|
||||||
final StringBuffer buffer = StringBuffer('The following tests have been implemented! Huzzah!:\n');
|
|
||||||
for (final File name in noLongerMissing) {
|
|
||||||
buffer.writeln(' ${getRelativePath(name)}');
|
|
||||||
}
|
|
||||||
buffer.writeln('However, they now need to be removed from the _knownMissingTests');
|
|
||||||
buffer.write('list in the script $_scriptLocation.');
|
|
||||||
foundError(buffer.toString().split('\n'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (missingTests.isNotEmpty) {
|
if (missingTests.isNotEmpty) {
|
||||||
final StringBuffer buffer = StringBuffer('The following example test files are missing:\n');
|
final StringBuffer buffer = StringBuffer('The following example test files are missing:\n');
|
||||||
for (final File name in missingTests) {
|
for (final File name in missingTests) {
|
||||||
@ -279,35 +268,14 @@ class SampleChecker {
|
|||||||
return '${path.join(testPath, path.basenameWithoutExtension(example.path))}_test.dart';
|
return '${path.join(testPath, path.basenameWithoutExtension(example.path))}_test.dart';
|
||||||
}
|
}
|
||||||
|
|
||||||
(List<File>, List<File>) checkForMissingTests(List<File> exampleFilenames) {
|
List<File> checkForMissingTests(List<File> exampleFilenames) {
|
||||||
final List<File> missingTests = <File>[];
|
final List<File> missingTests = <File>[];
|
||||||
final List<File> noLongerMissingTests = <File>[];
|
|
||||||
for (final File example in exampleFilenames) {
|
for (final File example in exampleFilenames) {
|
||||||
final File testFile = filesystem.file(getTestNameForExample(example, examples));
|
final File testFile = filesystem.file(getTestNameForExample(example, examples));
|
||||||
final String name = path.relative(testFile.absolute.path, from: flutterRoot.absolute.path);
|
|
||||||
if (!testFile.existsSync()) {
|
if (!testFile.existsSync()) {
|
||||||
missingTests.add(testFile);
|
missingTests.add(testFile);
|
||||||
} else if (_knownMissingTests.contains(name.replaceAll(r'\', '/'))) {
|
|
||||||
noLongerMissingTests.add(testFile);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Skip any that we know are missing.
|
return missingTests;
|
||||||
missingTests.removeWhere(
|
|
||||||
(File test) {
|
|
||||||
final String name = path.relative(test.absolute.path, from: flutterRoot.absolute.path).replaceAll(r'\', '/');
|
|
||||||
return _knownMissingTests.contains(name);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
return (missingTests, noLongerMissingTests);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// These tests are known to be missing. They should all eventually be
|
|
||||||
// implemented, but until they are we allow them, so that we can catch any new
|
|
||||||
// examples that are added without tests.
|
|
||||||
//
|
|
||||||
// TODO(gspencergoog): implement the missing tests.
|
|
||||||
// See https://github.com/flutter/flutter/issues/130459
|
|
||||||
final Set<String> _knownMissingTests = <String>{
|
|
||||||
'examples/api/test/material/color_scheme/dynamic_content_color.0_test.dart',
|
|
||||||
};
|
|
||||||
|
@ -9,26 +9,34 @@ import 'package:flutter/material.dart';
|
|||||||
const Widget divider = SizedBox(height: 10);
|
const Widget divider = SizedBox(height: 10);
|
||||||
const double narrowScreenWidthThreshold = 400;
|
const double narrowScreenWidthThreshold = 400;
|
||||||
|
|
||||||
void main() => runApp(DynamicColorExample());
|
void main() => runApp(const DynamicColorExample());
|
||||||
|
|
||||||
class DynamicColorExample extends StatefulWidget {
|
class DynamicColorExample extends StatefulWidget {
|
||||||
DynamicColorExample({super.key});
|
const DynamicColorExample({
|
||||||
|
this.loadColorScheme,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
final List<ImageProvider> images = <NetworkImage>[
|
static const List<ImageProvider> images = <NetworkImage>[
|
||||||
const NetworkImage(
|
NetworkImage(
|
||||||
'https://flutter.github.io/assets-for-api-docs/assets/material/content_based_color_scheme_1.png'),
|
'https://flutter.github.io/assets-for-api-docs/assets/material/content_based_color_scheme_1.png'),
|
||||||
const NetworkImage(
|
NetworkImage(
|
||||||
'https://flutter.github.io/assets-for-api-docs/assets/material/content_based_color_scheme_2.png'),
|
'https://flutter.github.io/assets-for-api-docs/assets/material/content_based_color_scheme_2.png'),
|
||||||
const NetworkImage(
|
NetworkImage(
|
||||||
'https://flutter.github.io/assets-for-api-docs/assets/material/content_based_color_scheme_3.png'),
|
'https://flutter.github.io/assets-for-api-docs/assets/material/content_based_color_scheme_3.png'),
|
||||||
const NetworkImage(
|
NetworkImage(
|
||||||
'https://flutter.github.io/assets-for-api-docs/assets/material/content_based_color_scheme_4.png'),
|
'https://flutter.github.io/assets-for-api-docs/assets/material/content_based_color_scheme_4.png'),
|
||||||
const NetworkImage(
|
NetworkImage(
|
||||||
'https://flutter.github.io/assets-for-api-docs/assets/material/content_based_color_scheme_5.png'),
|
'https://flutter.github.io/assets-for-api-docs/assets/material/content_based_color_scheme_5.png'),
|
||||||
const NetworkImage(
|
NetworkImage(
|
||||||
'https://flutter.github.io/assets-for-api-docs/assets/material/content_based_color_scheme_6.png'),
|
'https://flutter.github.io/assets-for-api-docs/assets/material/content_based_color_scheme_6.png'),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
final Future<ColorScheme> Function(
|
||||||
|
ImageProvider<Object> provider,
|
||||||
|
Brightness brightness,
|
||||||
|
)? loadColorScheme;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<DynamicColorExample> createState() => _DynamicColorExampleState();
|
State<DynamicColorExample> createState() => _DynamicColorExampleState();
|
||||||
}
|
}
|
||||||
@ -48,7 +56,7 @@ class _DynamicColorExampleState extends State<DynamicColorExample> {
|
|||||||
isLoading = true;
|
isLoading = true;
|
||||||
currentColorScheme = const ColorScheme.light();
|
currentColorScheme = const ColorScheme.light();
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
_updateImage(widget.images[selectedImage]);
|
_updateImage(DynamicColorExample.images[selectedImage]);
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -105,7 +113,7 @@ class _DynamicColorExampleState extends State<DynamicColorExample> {
|
|||||||
onChanged: (bool value) {
|
onChanged: (bool value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
isLight = value;
|
isLight = value;
|
||||||
_updateImage(widget.images[selectedImage]);
|
_updateImage(DynamicColorExample.images[selectedImage]);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
@ -120,7 +128,7 @@ class _DynamicColorExampleState extends State<DynamicColorExample> {
|
|||||||
divider,
|
divider,
|
||||||
_imagesRow(
|
_imagesRow(
|
||||||
context,
|
context,
|
||||||
widget.images,
|
DynamicColorExample.images,
|
||||||
colorScheme,
|
colorScheme,
|
||||||
),
|
),
|
||||||
divider,
|
divider,
|
||||||
@ -186,13 +194,23 @@ class _DynamicColorExampleState extends State<DynamicColorExample> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _updateImage(ImageProvider provider) async {
|
Future<void> _updateImage(ImageProvider provider) async {
|
||||||
final ColorScheme newColorScheme = await ColorScheme.fromImageProvider(
|
final ColorScheme newColorScheme;
|
||||||
provider: provider, brightness: isLight ? Brightness.light : Brightness.dark);
|
if (widget.loadColorScheme != null) {
|
||||||
|
newColorScheme = await widget.loadColorScheme!(
|
||||||
|
provider,
|
||||||
|
isLight ? Brightness.light : Brightness.dark,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
newColorScheme = await ColorScheme.fromImageProvider(
|
||||||
|
provider: provider,
|
||||||
|
brightness: isLight ? Brightness.light : Brightness.dark,
|
||||||
|
);
|
||||||
|
}
|
||||||
if (!mounted) {
|
if (!mounted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setState(() {
|
setState(() {
|
||||||
selectedImage = widget.images.indexOf(provider);
|
selectedImage = DynamicColorExample.images.indexOf(provider);
|
||||||
currentColorScheme = newColorScheme;
|
currentColorScheme = newColorScheme;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -227,7 +245,7 @@ class _DynamicColorExampleState extends State<DynamicColorExample> {
|
|||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () => _updateImage(image),
|
onTap: () => _updateImage(image),
|
||||||
child: Card(
|
child: Card(
|
||||||
color: widget.images.indexOf(image) == selectedImage
|
color: DynamicColorExample.images.indexOf(image) == selectedImage
|
||||||
? colorScheme.primaryContainer
|
? colorScheme.primaryContainer
|
||||||
: colorScheme.surface,
|
: colorScheme.surface,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
|
@ -0,0 +1,181 @@
|
|||||||
|
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_api_samples/material/color_scheme/dynamic_content_color.0.dart' as example;
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
final List<(ImageProvider<Object>, Brightness)> loadColorSchemeCalls = <(ImageProvider<Object>, Brightness)>[];
|
||||||
|
|
||||||
|
Future<ColorScheme> fakeColorSchemeLoader(ImageProvider<Object> provider, Brightness brightness) async {
|
||||||
|
loadColorSchemeCalls.add((provider, brightness));
|
||||||
|
final int index = example.DynamicColorExample.images.indexOf(provider);
|
||||||
|
final int seedColor = 0xf * pow(0x10, index).toInt();
|
||||||
|
return ColorScheme.fromSeed(seedColor: Color(seedColor), brightness: brightness);
|
||||||
|
}
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
loadColorSchemeCalls.clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
// The app being tested loads images via HTTP which the test
|
||||||
|
// framework defeats by default.
|
||||||
|
setUpAll(() {
|
||||||
|
HttpOverrides.global = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('The content is visible', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
example.DynamicColorExample(
|
||||||
|
loadColorScheme: fakeColorSchemeLoader,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
find.widgetWithText(AppBar, 'Content Based Dynamic Color'),
|
||||||
|
findsOne,
|
||||||
|
);
|
||||||
|
expect(find.byType(Switch), findsOne);
|
||||||
|
expect(find.byIcon(Icons.light_mode), findsOne);
|
||||||
|
|
||||||
|
expect(find.text('Light ColorScheme'), findsOne);
|
||||||
|
expect(find.text('Dark ColorScheme'), findsOne);
|
||||||
|
expect(find.text('primary'), findsExactly(2));
|
||||||
|
expect(find.text('onPrimary'), findsExactly(2));
|
||||||
|
expect(find.text('primaryContainer'), findsExactly(2));
|
||||||
|
expect(find.text('onPrimaryContainer'), findsExactly(2));
|
||||||
|
expect(find.text('secondary'), findsExactly(2));
|
||||||
|
expect(find.text('onSecondary'), findsExactly(2));
|
||||||
|
expect(find.text('secondaryContainer'), findsExactly(2));
|
||||||
|
expect(find.text('onSecondaryContainer'), findsExactly(2));
|
||||||
|
expect(find.text('tertiary'), findsExactly(2));
|
||||||
|
expect(find.text('onTertiary'), findsExactly(2));
|
||||||
|
expect(find.text('tertiaryContainer'), findsExactly(2));
|
||||||
|
expect(find.text('onTertiaryContainer'), findsExactly(2));
|
||||||
|
expect(find.text('error'), findsExactly(2));
|
||||||
|
expect(find.text('onError'), findsExactly(2));
|
||||||
|
expect(find.text('errorContainer'), findsExactly(2));
|
||||||
|
expect(find.text('onErrorContainer'), findsExactly(2));
|
||||||
|
expect(find.text('surface'), findsExactly(2));
|
||||||
|
expect(find.text('onSurface'), findsExactly(2));
|
||||||
|
expect(find.text('onSurfaceVariant'), findsExactly(2));
|
||||||
|
expect(find.text('outline'), findsExactly(2));
|
||||||
|
expect(find.text('shadow'), findsExactly(2));
|
||||||
|
expect(find.text('inverseSurface'), findsExactly(2));
|
||||||
|
expect(find.text('onInverseSurface'), findsExactly(2));
|
||||||
|
expect(find.text('inversePrimary'), findsExactly(2));
|
||||||
|
|
||||||
|
expect(loadColorSchemeCalls, hasLength(1));
|
||||||
|
expect(
|
||||||
|
loadColorSchemeCalls.single.$1,
|
||||||
|
isA<NetworkImage>()
|
||||||
|
.having(
|
||||||
|
(NetworkImage provider) => provider.url,
|
||||||
|
'url',
|
||||||
|
'https://flutter.github.io/assets-for-api-docs/assets/material/content_based_color_scheme_1.png',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
loadColorSchemeCalls.single.$2,
|
||||||
|
Brightness.light,
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpAndSettle(); // Clears the timers from image loading.
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('The brightness can be changed', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
example.DynamicColorExample(
|
||||||
|
loadColorScheme: fakeColorSchemeLoader,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(loadColorSchemeCalls, hasLength(1));
|
||||||
|
expect(
|
||||||
|
loadColorSchemeCalls.single.$1,
|
||||||
|
isA<NetworkImage>()
|
||||||
|
.having(
|
||||||
|
(NetworkImage provider) => provider.url,
|
||||||
|
'url',
|
||||||
|
'https://flutter.github.io/assets-for-api-docs/assets/material/content_based_color_scheme_1.png',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
loadColorSchemeCalls.single.$2,
|
||||||
|
Brightness.light,
|
||||||
|
);
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(kThemeChangeDuration);
|
||||||
|
|
||||||
|
ThemeData themeData = Theme.of(tester.element(find.byType(Scaffold)));
|
||||||
|
|
||||||
|
expect(themeData.colorScheme.primary, const Color(0xff565992));
|
||||||
|
expect(themeData.colorScheme.secondary, const Color(0xff5c5d72));
|
||||||
|
|
||||||
|
await tester.tap(find.byType(Switch));
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(loadColorSchemeCalls, hasLength(2));
|
||||||
|
expect(
|
||||||
|
loadColorSchemeCalls.last.$1,
|
||||||
|
isA<NetworkImage>()
|
||||||
|
.having(
|
||||||
|
(NetworkImage provider) => provider.url,
|
||||||
|
'url',
|
||||||
|
'https://flutter.github.io/assets-for-api-docs/assets/material/content_based_color_scheme_1.png',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
loadColorSchemeCalls.last.$2,
|
||||||
|
Brightness.dark,
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pump(kThemeChangeDuration);
|
||||||
|
|
||||||
|
themeData = Theme.of(tester.element(find.byType(Scaffold)));
|
||||||
|
|
||||||
|
expect(themeData.colorScheme.primary, const Color(0xffbfc2ff));
|
||||||
|
expect(themeData.colorScheme.secondary, const Color(0xffc5c4dd));
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Tapping an image loads a new color scheme', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
example.DynamicColorExample(
|
||||||
|
loadColorScheme: fakeColorSchemeLoader,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
await tester.tapAt(tester.getCenter(find.byType(Image).at(3)));
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(loadColorSchemeCalls, hasLength(2));
|
||||||
|
expect(
|
||||||
|
loadColorSchemeCalls.last.$1,
|
||||||
|
isA<NetworkImage>()
|
||||||
|
.having(
|
||||||
|
(NetworkImage provider) => provider.url,
|
||||||
|
'url',
|
||||||
|
'https://flutter.github.io/assets-for-api-docs/assets/material/content_based_color_scheme_4.png',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
loadColorSchemeCalls.last.$2,
|
||||||
|
Brightness.light,
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pump(kThemeChangeDuration);
|
||||||
|
|
||||||
|
final ThemeData themeData = Theme.of(tester.element(find.byType(Scaffold)));
|
||||||
|
|
||||||
|
expect(themeData.colorScheme.primary, const Color(0xff406836));
|
||||||
|
expect(themeData.colorScheme.secondary, const Color(0xff54634d));
|
||||||
|
});
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user