betterment / alchemist Goto Github PK
View Code? Open in Web Editor NEWA Flutter tool that makes golden testing easy.
License: MIT License
A Flutter tool that makes golden testing easy.
License: MIT License
On my locals, when running the example test on fresh install (flutter create or very_good create), the linux and macos goldens don't display text.
The CI font is not used because the result is different if you look at the icon and the spaces.
I tried different PlatformGoldensConfig with no success.
Adding Roboto fonts from alchemist package into the project is solving the issue.
flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 2.10.4, on Ubuntu 21.10 5.13.0-37-generic, locale en_US.UTF-8)
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2020.3)
[✓] VS Code
[✓] Connected device (2 available)
[✓] HTTP Host Availability
/dev/feat/tolerance
When I run flutter test --machine
it throws an error. It works great on stable version.
../AppData/Local/Pub/Cache/git/alchemist-d57c359ceadeae7ebde51639bcf9fbf37bb5f100/lib/src/golden_test_adapter.dart:53:38: Error: A value of type 'void Function(String, Future<void> Function(WidgetTester), {LeakTesting?
experimentalLeakTesting, int? retry, bool semanticsEnabled, bool? skip, dynamic tags, Timeout? timeout, TestVariant<Object?> variant})' can't be assigned to a variable of type 'FutureOr<void> Function(String, Future<void>
Function(WidgetTester), {Duration? initialTimeout, bool semanticsEnabled, bool? skip, dynamic tags, Timeout? timeout, TestVariant<Object?> variant})'.
- 'Future' is from 'dart:async'.
- 'WidgetTester' is from 'package:flutter_test/src/widget_tester.dart' ('.fvm/flutter_sdk/packages/flutter_test/lib/src/widget_tester.dart').
- 'LeakTesting' is from 'package:leak_tracker_testing/src/leak_testing.dart' ('../AppData/Local/Pub/Cache/hosted/pub.dev/leak_tracker_testing-2.0.1/lib/src/leak_testing.dart').
- 'Timeout' is from 'package:test_api/src/backend/configuration/timeout.dart' ('../AppData/Local/Pub/Cache/hosted/pub.dev/test_api-0.6.1/lib/src/backend/configuration/timeout.dart').
- 'TestVariant' is from 'package:flutter_test/src/widget_tester.dart' ('.fvm/flutter_sdk/packages/flutter_test/lib/src/widget_tester.dart').
- 'Object' is from 'dart:core'.
- 'Duration' is from 'dart:core'.
TestWidgetsFn defaultTestWidgetsFn = testWidgets;
^
0.5.0
After upgrading from version 0.3.3 to 0.5.0 the golden test stopped showing dialogs and opened dropdown menus. I have changed nothing with the pre test pumps, but still
This is a test I wrote, trying to reproduce it:
import 'package:alchemist/alchemist.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
goldenTest(
'drop down',
fileName: 'dropdown',
constraints: const BoxConstraints(
maxWidth: 500,
maxHeight: 500,
),
pumpBeforeTest: (tester) async {
await tester.pumpAndSettle();
await tester.tap(find.byType(DropdownButton<String>));
await tester.pumpAndSettle();
},
builder: () {
return const TestApp();
},
);
goldenTest(
'dialog',
fileName: 'dialog',
constraints: const BoxConstraints(
maxWidth: 500,
maxHeight: 500,
),
pumpBeforeTest: (tester) async {
await tester.pumpAndSettle();
await tester.tap(find.byType(TextButton));
await tester.pumpAndSettle();
},
builder: () {
return const TestApp();
},
);
}
class TestApp extends StatelessWidget {
const TestApp({super.key});
@override
Widget build(BuildContext context) => Material(
child: Center(
child: Column(
children: [
DropdownButton<String>(
value: '0',
items: const [
DropdownMenuItem<String>(
value: '0',
child: Text('0'),
),
DropdownMenuItem<String>(
value: '1',
child: Text('1'),
),
DropdownMenuItem<String>(
value: '2',
child: Text('2'),
),
],
onChanged: null,
),
TextButton(
onPressed: () {
showDialog(
context: context,
builder: (context) => const AlertDialog(
content: Text('popup'),
),
);
},
child: const Text('button'),
)
],
),
),
);
}
This is the config setup:
// flutter_test_config.dart
import 'dart:async';
import 'dart:io';
import 'package:alchemist/alchemist.dart';
import 'package:flutter/material.dart';
Future<void> testExecutable(FutureOr<void> Function() testMain) async {
// This is used to detect if it is running in a github actions workflow
// For other CI Systems this might look different
final isRunningInCi = Platform.environment['CI'] == 'true';
return AlchemistConfig.runWithConfig(
config: AlchemistConfig(
theme: baseTheme.copyWith(textTheme: strippedTextTheme),
platformGoldensConfig: PlatformGoldensConfig(
enabled: !isRunningInCi,
),
),
run: testMain,
);
}
final baseTheme = ThemeData.light();
final baseTextTheme = baseTheme.textTheme;
final strippedTextTheme = baseTextTheme.copyWith(
displayLarge: baseTextTheme.displayLarge?.forGoldens,
displayMedium: baseTextTheme.displayMedium?.forGoldens,
displaySmall: baseTextTheme.displaySmall?.forGoldens,
headlineLarge: baseTextTheme.headlineLarge?.forGoldens,
headlineMedium: baseTextTheme.headlineMedium?.forGoldens,
headlineSmall: baseTextTheme.headlineSmall?.forGoldens,
bodyLarge: baseTextTheme.bodyLarge?.forGoldens,
bodyMedium: baseTextTheme.bodyMedium?.forGoldens,
bodySmall: baseTextTheme.bodySmall?.forGoldens,
titleLarge: baseTextTheme.titleLarge?.forGoldens,
titleMedium: baseTextTheme.titleMedium?.forGoldens,
titleSmall: baseTextTheme.titleSmall?.forGoldens,
labelLarge: baseTextTheme.labelLarge?.forGoldens,
labelMedium: baseTextTheme.labelMedium?.forGoldens,
labelSmall: baseTextTheme.labelSmall?.forGoldens,
);
extension _GoldenTextStyle on TextStyle {
TextStyle get forGoldens {
final familySplit = fontFamily?.split('/');
final rawFamily = familySplit?.last;
return TextStyle(
inherit: inherit,
color: color,
backgroundColor: backgroundColor,
fontSize: fontSize,
fontWeight: fontWeight,
fontStyle: fontStyle,
letterSpacing: letterSpacing,
wordSpacing: wordSpacing,
textBaseline: textBaseline,
height: height,
locale: locale,
foreground: foreground,
background: background,
shadows: shadows,
fontFeatures: fontFeatures,
decoration: decoration,
decorationColor: decorationColor,
decorationStyle: decorationStyle,
decorationThickness: decorationThickness,
debugLabel: debugLabel,
package: null,
fontFamily: rawFamily,
fontFamilyFallback: const ['Roboto'],
);
}
}
And these are the resulting images (for the ci):
The dropdown menu and dialog should be visable like in these screenshots generated with the 0.3.3 version (sadly due to the The non-abstract class 'BlockedTextCanvasAdapter' is missing implementations for these members
error I can't produce these with the provided code, so I took the screenshot from our app):
No response
No response
3.4.0-34.1.pre
After upgrade flutter to beta (3.4.0-34.1.pre) I recive
Error: The non-abstract class 'BlockedTextCanvasAdapter' is missing implementations for these members:
- Canvas.restoreToCount
Try to either
- provide an implementation,
- inherit an implementation from a superclass or mixin,
- mark the class as abstract, or
- provide a 'noSuchMethod' implementation.
on
class BlockedTextCanvasAdapter implements Canvas {
Adding to the BlockedTextCanvasAdapter
method void restoreToCount(int count) => parent.restoreToCount(count);
No response
Golden Testing on iOS and Android
As a developer, I would like to do golden testing on iOS and Android
These are the platforms we target
We currently run golden testing on our pipelines but we cannot do golden testing on integration tests so we cannot test goldens on actual phones.
We currently produce goldens with lots of different sizes with a Linux desktop. That's a problem because the pipeline goldens don't match our local goldens (Mac / windows). We have to do eleborate hacks just to incorporate goldens in our flow.
We've done plenty of research on this and the only other way we can so this is to take literal screenshot and then do image compares ourself.
If this library would allow us to do golden testing on integration tests, especially with Android and iOS, it would be a quantum leap forward for us and basically every flutter developer on the planet that does golden testing.
Thanks
Golden test support for web
While testing for the web I couldn’t test for the web so I wonder if the web will be supported in the future?
Web is an important platform and it has a different features like canvas vs HTML rendering and it allows ci to test on chrome
The command that I tried is
flutter test --update-goldens --platform chrome test/image_picker_golden_test.dart
and I got the following result
Unsupported operation: Platform._operatingSystem
Add a Flutter application example.
Instead of a plain markdown file (https://github.com/Betterment/alchemist/blob/main/example/example.md), it would be great to have a real Flutter example application.
It would be ideal if this example showcased the functionality Alchemist provides. For example, showing a login page with goldens for different languages with a custom font.
No response
I'd like to run a golden test with multiple themes, not just a single theme
I would like to be able to pass AlchemistConfig
a List<ThemeData>?
instead of just a ThemeData?
.
The goldenTest
method should then run the test with all given themes in the current AlchemistConfig
.
This would remove redundancy when testing a widget with multiple themes. Currently you would need a separate goldenTest
for each theme that should be tested, even if the widget under test is the same.
So instead of
void main() {
AlchemistConfig.runWithConfig(
config: AlchemistConfig(
theme: MyLightTheme()
),
run: () => goldenTest('widget should look good with light theme', ..., widget: MyWidget());
);
AlchemistConfig.runWithConfig(
config: AlchemistConfig(
theme: MyDarkTheme()
),
run: () => goldenTest('widget should look good with dark theme', ..., widget: MyWidget());
);
// etc. for all other themes
}
I would like to be able to write the following
void main() {
AlchemistConfig.runWithConfig(
config: AlchemistConfig(
themes: [MyLightTheme(), MyDarkTheme(), ...]
),
run: () => goldenTest('widget should look good with all themes', ..., widget: MyWidget());
);
}
Many apps have multiple themes. E.g. a default light theme and a dark theme. If your app cares about accessibility it may even have a high contrast light theme and a high contrast dark theme.
If you want to write a golden test for a widget and ensure that it looks good on each theme, you would have to write a separate test for each theme because right now you can only pass a single theme to AlchemistConfig
. If you could pass a list of themes as suggested, you would have to write only one golden test and pass it all the themes the widget should be tested with.
No response
I would love if I could run my tests with a lot of screen sizes (iPhone / iPad / desktop)
I would love if I could generate file the same way golden toolkit is doing
Since variant is used for the platform, I cannot find a way to keep the device type properly organized with Alchemist.
Variants are useful to get also a nice overview in IDEs.
No response
alchemist: ^0.3.3
Hi, great package, solves an important problem! However, I am not sure two aspects are clear.
The setup guide suggests checking for environment variables in a different fashion the what is used in the example. For me, only the example way works, perhaps it's worth it update it?
I am not sure I understand how you are handling the platform tests across developers. Since platform goldens are not tracked in CI, what happens when someone adds a new test? Wouldn't I have to first always run flutter test --update-goldens on my local machine?
The setup guide, especially in terms of handling the platform tests, should be clear.
No response
No response
0.2.1
When I'm generating golden files using an asset image it is not rendered while it is rendered correctly for its ci equivalent.
TestAssetBundle
to load your assetsimport 'dart:convert';
import 'package:flutter/services.dart';
class TestAssetBundle extends CachingAssetBundle {
@override
Future<String> loadString(String key, {bool cache = true}) async {
final data = await load(key);
return utf8.decode(data.buffer.asUint8List());
}
@override
Future<ByteData> load(String key) => rootBundle.load(key);
}
goldenTest
with an Image.asset
widget (wrapped inside a DefaultAssetBundle
)import 'package:alchemist/alchemist.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import '../../utils/test_asset_bundle.dart';
void main() {
setUpAll(TestWidgetsFlutterBinding.ensureInitialized);
group('Image.asset: Golden Tests', () {
goldenTest(
'renders correctly',
fileName: 'image_asset',
widget: GoldenTestGroup(
children: [
GoldenTestScenario(
name: 'XYZ Monster.jpg asset',
child: DefaultAssetBundle(
bundle: TestAssetBundle(),
child: Image.asset('assets/type/XYZ Monster.jpg'),
),
),
],
),
);
});
}
flutter test --update-goldens
The golden file generated should display the asset image.
flutter doctor -v
:[√] Flutter (Channel stable, 2.10.2, on Microsoft Windows [version 10.0.22000.527], locale fr-FR)
• Flutter version 2.10.2 at C:\src\flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 097d3313d8 (5 days ago), 2022-02-18 19:33:08 -0600
• Engine revision a83ed0e5e3
• Dart version 2.16.1
• DevTools version 2.9.2
[√] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
• Android SDK at C:\Users\Guillaume\AppData\Local\Android\sdk
• Platform android-30, build-tools 30.0.3
• Java binary at: D:\Android Studio\jre\bin\java
• Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b01)
• All Android licenses accepted.
[√] Chrome - develop for the web
• Chrome at C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
[!] Visual Studio - develop for Windows (Visual Studio Build Tools 2017 15.9.35)
• Visual Studio at C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools
• Visual Studio Build Tools 2017 version 15.9.28307.1500
• Windows 10 SDK version 10.0.17763.0
X Visual Studio 2019 or later is required.
Download at https://visualstudio.microsoft.com/downloads/.
Please install the "Desktop development with C++" workload, including all of its default components
[√] Android Studio (version 4.1)
• Android Studio at D:\Android Studio
• Flutter plugin can be installed from:
https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b01)
[√] Connected device (3 available)
• Windows (desktop) • windows • windows-x64 • Microsoft Windows [version 10.0.22000.527]
• Chrome (web) • chrome • web-javascript • Google Chrome 98.0.4758.102
• Edge (web) • edge • web-javascript • Microsoft Edge 97.0.1072.76
[√] HTTP Host Availability
• All required HTTP hosts are available
! Doctor found issues in 1 category.
0.2.0
In example/example.md
, there is a reference to a file example/RECOMMENDED_SETUP_GUIDE.md
. Because that file does not yet exist, tapping the link results in a 404
Recommended Setup Guide
linkWhen navigating to Recommended Setup Guide
, the file should exist.
No response
Lmk if this is already on a board somewhere since idk where this work is being tracked 👍
I would love if we could specify a configuration (or more) per test
As a developer, I would like to be able to only have to write a single goldenTest and be able to specify multiple configuration where the test would run.
For example:
goldenTest('foo', configuration: config1, ...);
I would expect that if the configuration parameter is not required the global configuration is used (if any) instead. Hence, once the test finishes the global configuration is restored. I would also expect, to be able to give the Configuration some kind of parameter in order if the null properties should be inherited.
The above is just an example. I'm not sure if it is to be considered the best API. Alternatives, could be, for example, to have a configurations
be a List and avoid extracting the test method in order to reuse it. Or another possibility is to have a GoldenTestConfiguration
widget:
class GoldenTestConfiguration extends StatelessWidget {
const GoldenTestConfiguration({
super.key,
required this.config,
required this.child,
this.inheritConfig = true,
});
final AlchemistConfig config;
final bool inheritConfig;
final Widget child;
@override
Widget build(BuildContext context) {
return AlchemistConfig.runWithConfig<Widget>(
config: inheritConfig ? AlchemistConfig.current().merge(config) : config,
run: () => child,
);
}
}
// Or with a widget builder
class GoldenTestConfiguration extends StatelessWidget {
const GoldenTestConfiguration({
super.key,
required this.config,
required this.builder,
this.inheritConfig = true,
});
final AlchemistConfig config;
final bool inheritConfig;
final WidgetBuilder builder;
@override
Widget build(BuildContext context) {
return AlchemistConfig.runWithConfig<Widget>(
config: inheritConfig ? AlchemistConfig.current().merge(config) : config,
run: () => builder(context),
);
}
}
--
I'm unsure if having logic within setUp
and tearDown
that alters the config (similar to the snippet below) would work; but if so, I think it feels very verbose in comparison with just providing the configuration
to goldenTest
.
AlchemistConfig.runWithConfig(
config: AlchemistConfig(
forceUpdateGoldenFiles: true,
),
run: () {
// test here.
},
);
In some scenarios, a developer would like to specify more than a single configuration. This could be motivated, for example, when there are different functionalities to be run when a given flavour or target is given. Hence, as a developer you would be interested on running the same test with different configurations.
Example 1
You have different themes for different platforms and you wish to have a config with each theme. Currently the flutter_test_config.dart
file looks like the above snippet. This is similar to #21 .
// flutter_test_config.dart
Future<void> testExecutable(FutureOr<void> Function() testMain) async {
final enablePlatformTests =
!Platform.environment.containsKey('GITHUB_ACTIONS');
return AlchemistConfig.runWithConfig(
config: AlchemistConfig(
theme: AppTheme(platform: TargetPlatform.android).themeData,
platformGoldensConfig:
AlchemistConfig.current().platformGoldensConfig.copyWith(
enabled: enablePlatformTests,
),
),
run: testMain,
);
}
N/A
Differ between Intel Macs & Apple Silicon Macs
Having two MacOS folders, one for Intel and one for ARM.
File Structure could be like this:
.
└── macos/
├── intel
└── arm
or
.
├── macos-intel
└── macos-arm
If you run Golden Tests with an Intel Mac, it will produce different Golden Images than an Apple Silicon Mac and vice versa.
To be able to test on both platforms reliable, it would be great to have two folders. One for each architecture.
No response
0.4.1
Svg pictures aren't rendered correctly in CI mode. They work fine in macOS, but once you fit them with widgets with size below them they appear weirdly.
I'm using flutter_svg: 1.1.4
Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(
R.ILLUSTRATIONS_GENERIC_ERROR,
fit: BoxFit.fitWidth,
),
const SizedBox(height: 84),
],
),
);
I've also attached the svg picture I'm generating the svg with.
The generated golden should be identical to macOS one.
No response
I'm using flutter 3.0.5
0.4.1
The method FlutterGoldenTestAdapter.pumpGoldenTest
sets a new pixelRatio and textScalorFactor test values that are not reset to the original values on tear down. This makes the test that run after a golden test to have modified properties that can alter the result of the test.
alchemist/lib/src/golden_test_adapter.dart
Lines 226 to 228 in a80c62c
We should clear values on tearDown:
addTearDown(() {
tester.binding.window.clearDevicePixelRatioTestValue();
tester.binding.platformDispatcher.clearTextScaleFactorTestValue();
});
When running the following code, goldenTest sets up a new devicePixelRatio and the test after it fail.
import 'package:alchemist/alchemist.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('before golden devicePixelRatio', (tester) async {
expect(tester.binding.window.devicePixelRatio, 3);
});
goldenTest(
'A',
fileName: 'a',
builder: () => Container(height: 300),
);
testWidgets('after golden devicePixelRatio', (tester) async {
expect(tester.binding.window.devicePixelRatio, 3); // Fails with actual value 1
});
}
When clearing devicePixelRatio on tearDown, the test work as expected
import 'package:alchemist/alchemist.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('before golden devicePixelRatio', (tester) async {
expect(tester.binding.window.devicePixelRatio, 3);
});
goldenTest(
'A',
fileName: 'a',
builder: () => Container(height: 300),
whilePerforming: (tester) async {
addTearDown(() {
tester.binding.window.clearDevicePixelRatioTestValue();
});
return;
},
);
testWidgets('after golden devicePixelRatio', (tester) async {
expect(tester.binding.window.devicePixelRatio, 3);
});
}
No response
I would love to be able to mock network images in my tests
As a developer, I would love to be able to mock network images in my tests but it seems like it is not yet possible with Alchemist or is there any way to do so ?
I tried to make pass a golden test with a NetworkImage widget used in it but I have an infinite loading test.
I found a similar issue but I did not find any response in it.
Does the library supports today network image mocking ?
Thanks a lot for this amazing package :)
0.3.3
Whenever running test I get a warning in the console
../.pub-cache/hosted/pub.dartlang.org/alchemist-0.3.3/lib/src/alchemist_test_variant.dart:39:5: Warning: Operand of null-aware operation '?.' has type 'ImageCache' which excludes null.
- 'ImageCache' is from 'package:flutter/src/painting/image_cache.dart' ('../fvm/versions/3.0.1/packages/flutter/lib/src/painting/image_cache.dart').
imageCache?.clear();
^
Tests still work correctly but warnings fill terminal.
Use Alchemist 0.3.3 with Flutter > 3 and run tests.
flutter_test_config.dart for reference:
Future<void> testExecutable(FutureOr<void> Function() testMain) async {
await loadAppFonts();
return AlchemistConfig.runWithConfig(
config: AlchemistConfig(
platformGoldensConfig: PlatformGoldensConfig(platforms: <HostPlatform>{
HostPlatform.macOS,
HostPlatform.windows,
}),
),
run: testMain,
);
}
When running it shouldn't warn about ImageCache issues.
No response
No response
0.3.3
Reproducible example gist can be found here.
In platform tests (and I suspect CI tests as well), if a Text
is built but no default text style font family is found, it looks like "Ahem" is used as a fallback value, instead of "Roboto".
Theme
with a textButtonTheme
. Assign the style
of this theme to TextButton.styleFrom
. Provide this constructor an empty TextStyle
.AlchemistConfig
or PlatformGoldensConfig
.Default to "Roboto" when no font family is found.
No response
0.7.0
After upgrading from Flutter 3.13.8 to 3.16.0 my golden test is breaking because of the background color.
main.dart
void main() {
runApp(const MainApp());
}
class MainApp extends StatelessWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(useMaterial3: false),
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(
child: Text('Hello World!'),
),
);
}
}
home_golden_test.dart
const iphoneSE = Size(320, 568);
void main() {
goldenTest(
'HomePage',
fileName: 'home_page',
builder: () {
return GoldenTestGroup(children: [
GoldenTestScenario(
constraints: BoxConstraints.tight(iphoneSE),
name: 'default',
child: Theme(
data: ThemeData(useMaterial3: false),
child: const HomePage(),
),
),
]);
},
);
}
flutter test --update-goldens
with Flutter 3.13.8flutter test -t golden
The test should not fail.
3.13.8 | 3.16.0 |
---|---|
I must admit that I never understood why the background color was based off the theme data considering that it could break after any bump of the SDK like here 🤔
0.4.1
When running tests that require MaterialApp.router i am unable to run more than one due to duplicate global keys
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following assertion was thrown while finalizing the widget tree:
Multiple widgets used the same GlobalKey.
The key [LabeledGlobalKey<NavigatorState>#e3a60] was used by multiple widgets. The parents of those
widgets were:
- AutoRouteNavigator(state: _AutoRouteNavigatorState#659c4)
- AutoRouteNavigator(state: _AutoRouteNavigatorState#f4c64)
A GlobalKey can only be specified on one widget at a time in the widget tree
Widget buildWidgetUnderTest() {
router.push(SearchedSongsRoute(
searchTerm: 'query',
));
return ProviderScope(
overrides: [
userNotifierProvider.overrideWithValue(
fakeUserNotifier,
),
authNotifierProvider.overrideWithValue(
mockAuthNotifier,
),
searchedSongsNotifierProvider.overrideWithProvider(mockSearchedSongsNotifierProvider),
searchHistoryNotifierProvider.overrideWithValue(mockSearchHistoryProvider),
],
child: MaterialApp.router(
routerDelegate: AutoRouterDelegate(
router,
navigatorObservers: () => [mockObserver],
initialDeepLink: DashboardRoute.name,
),
routeInformationParser: AppRouter().defaultRouteParser(),
),
);
}
goldenTest(
'renders correctly on mobile',
fileName: 'SearchedSongsPage',
builder: () => GoldenTestGroup(
children: [
GoldenTestDeviceScenario(
key: GlobalKey(debugLabel: 'scaffoldKey'),
device: Device.smallPhone,
name: 'golden test SearchedSongsPage on small phone',
builder: buildWidgetUnderTest,
),
GoldenTestDeviceScenario(
key: GlobalKey(debugLabel: 'scaffoldKeysss'),
device: Device.tabletLandscape,
name: 'golden test SearchedSongsPage on tablet landscape',
builder: buildWidgetUnderTest,
),
// GoldenTestDeviceScenario(
// device: Device.tabletPortrait,
// name: 'golden test SearchedSongsPage on tablet Portrait',
// builder: buildWidgetUnderTest,
// ),
// GoldenTestDeviceScenario(
// name: 'golden test SearchedSongsPage on iphone11',
// builder: buildWidgetUnderTest,
// ),
],
),
);
When running it should update the goldens as it does when running one.
No response
The test is located https://github.com/jeremiahlukus/guitar_tabs/blob/jlp-search-bar/test/backend/songs/searched_songs/presentation/searched_song_page_test.dart#L230
using flutter test test/backend/songs/searched_songs/presentation/searched_song_page_test.dart --update-goldens
Update how Theme is propagated, especially when using a custom pumpWidget
.
I think theming in the golden test should be handled as follows t:
Achieve a better API that would make the library more Flutter friendly. It makes it easier to migrate from regular golden testing to Alchemist, since on regular golden test theming is handled by the Widget tree and is not overridden as in the case of Alchemist.
No response
0.5.1
tl;dr What is the proper way to run a goldenTest in a Zone?
I want to mock DateTime.now() and for this I use the offical "clock" package.
withClock uses runZoned under the hood and can return the callback/ result so I thought it should be possible to put it in somewhere in "goldenTest" - I tried:
builder: () => withClock<Widget>(
Clock.fixed(DateTime(2022, 11, 17)),
() => MyFancyWidget)
pumpWidget: (tester, widget) async => withClock(
Clock.fixed(DateTime(2022, 11, 17)),
() async {
await tester.pumpWidget(widget);
},
),
both did not work and the current dateTime was used instead, suggesting that for some reason the Zone was not used.
I would expect both of the above examples to be valid.
This is an example of how withClock is used in a basic unit test:
test('returns a proper greeting on a Tuesday', () {
final greeting = withClock(
Clock.fixed(DateTime(2020, 09, 01)),
() => Greeter().greet(),
);
expect(greeting, 'Happy Tuesday, you!');
# example from: https://iiro.dev/controlling-time-with-package-clock/
No response
So this all turns out to be a question of "What is the proper way to run a goldenTest in a Zone?"
0.3.3
Since Flutter 3 update, when running a goldenTest
it outputs the following warning:
/opt/hostedtoolcache/flutter/3.0.4-stable/x64/.pub-cache/hosted/pub.dartlang.org/alchemist-0.3.3/lib/src/alchemist_test_variant.dart:39:5: Warning: Operand of null-aware operation '?.' has type 'ImageCache' which excludes null.
- 'ImageCache' is from 'package:flutter/src/painting/image_cache.dart' ('/opt/hostedtoolcache/flutter/3.0.4-stable/x64/packages/flutter/lib/src/painting/image_cache.dart').
imageCache?.clear();
^
goldenTest
import 'package:alchemist/alchemist.dart';
import 'package:flutter/material.dart';
void main() {
goldenTest(
'image_cache_warning_test',
fileName: 'image_cache_warning_test',
builder: () => GoldenTestScenario(
name: '',
child: Container(
height: 50.0,
width: 50.0,
color: Colors.green,
),
),
);
}
$> flutter test .\test\image_cache_warning_test.dart --update-goldens
00:01 +0: loading D:\Documents\Projects\flutter_dsfr\test\image_cache_warning_test.dart /C:/src/flutter/.pub-cache/hosted/pub.dartlang.org/alchemist-0.3.3/lib/src/alchemist_test_variant.dart:39:5: Warning: Operand of null-aware operation '?.' has type 'ImageCache' which excludes null.
- 'ImageCache' is from 'package:flutter/src/painting/image_cache.dart' ('/C:/src/flutter/packages/flutter/lib/src/painting/image_cache.dart').
imageCache?.clear();
^
00:02 +2: All tests passed!
$> flutter test .\test\image_cache_warning_test.dart
00:01 +0: loading D:\Documents\Projects\flutter_dsfr\test\image_cache_warning_test.dart /C:/src/flutter/.pub-cache/hosted/pub.dartlang.org/alchemist-0.3.3/lib/src/alchemist_test_variant.dart:39:5: Warning: Operand of null-aware operation '?.' has type 'ImageCache' which excludes null.
- 'ImageCache' is from 'package:flutter/src/painting/image_cache.dart' ('/C:/src/flutter/packages/flutter/lib/src/painting/image_cache.dart').
imageCache?.clear();
^
00:02 +2: All tests passed!
When running it should not display any warning to keep the log clear in case of a failed test.
No response
No response
Is there a way to call the setUp
method between GoldenTestScenario inside the same GoldenTestGroup?
Example:
group('Golden Tests', () {
setUp(() {
... some stuff
});
goldenTest(
'name',
fileName: 'fileanme',
pumpBeforeTest: precacheImages,
builder: () {
return GoldenTestGroup(
children: [
GoldenTestScenario(
name: 'Secenario 1',
child: Container(),
),
GoldenTestScenario(
name: 'Secenario 2,
child: Container(),
),
],
);
},
);
});
I would like to have the following calls:
Thanks in advance and thanks for the library :)
I would love if CI tests would check texts and icons.
It would be great if changing icons or texts would be caught by golden tests. I understand that currently text is not rendered as text to make CI tests stable between platforms, but maybe there is another solution to get the best of both worlds.
Take the following test file as an example. Note that both tests use the same file as golden image reference. The second golden test should fail because it contains a different icon than the first test, but the CI test passes because the icon (which is text as well) is rendered as a black box on both tests.
void main() {
AlchemistConfig.runWithConfig(
config: AlchemistConfig.current().merge(
const AlchemistConfig(
ciGoldensConfig: CiGoldensConfig(enabled: true),
platformGoldensConfig: PlatformGoldensConfig(enabled: false),
),
),
run: () {
goldenTest(
'should pass and passes',
fileName: 'icon_test',
builder: () => GoldenTestScenario(
name: 'icon A',
child: const Icon(Icons.thumb_up),
),
);
goldenTest(
'should fail, but passes too!',
// use same golden image as the previous test
fileName: 'icon_test',
builder: () => GoldenTestScenario(
name: 'icon B',
// but use a different icon
child: const Icon(Icons.bug_report),
),
);
},
);
}
This feature would make golden tests even more powerful by preventing more types of regressions.
My suggestion is the following:
During the replacement of text blocks with colored rectangles, write all blocked text blocks into a Map<Offset, List<String>> textBlocks
. At the end of a test, compare not only the golden image file but also the map containing the text blocks.
Add something like textBlocks.putIfAbsent(offset, () => []).add(child.text.toPlainText());
to the if(child is RenderParagraph)
block. Or maybe child.text.toStringDeep()
would be better because that also contains information on font family, color, etc.
alchemist/lib/src/blocked_text_image.dart
Lines 38 to 43 in f0de484
If a test is being run with --update-goldens
or forceUpdateGoldens: true
, save the Map<Offset, List> under goldens/ci/<golden_test_file_name>.texts
. Else compare the current textBlocks
map with the persisted golden textBlocks
map.
The map should be a Map<Offset, List<String>>
and not a Map<Offset, String>
because multiple texts can be drawn at the same offset. Another advantage of List
is that it also keeps track of the correct painting order.
0.2.1
An error is thrown when a CI test is run with a widget which contains a CompositedTransformFollower
.
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following _CastError was thrown while running async test code:
Null check operator used on a null value
When the exception was thrown, this was the stack:
#0 FollowerLayer.addToScene (package:flutter[/src/rendering/layer.dart:2554:22]())
#1 Layer._addToSceneWithRetainedRendering (package:flutter[/src/rendering/layer.dart:545:5]())
#2 ContainerLayer.addChildrenToScene (package:flutter[/src/rendering/layer.dart:1105:13]())
#3 PhysicalModelLayer.addToScene (package:flutter[/src/rendering/layer.dart:2085:5]())
#4 Layer._addToSceneWithRetainedRendering (package:flutter[/src/rendering/layer.dart:545:5]())
#5 ContainerLayer.addChildrenToScene (package:flutter[/src/rendering/layer.dart:1105:13]())
#6 OpacityLayer.addToScene (package:flutter[/src/rendering/layer.dart:1799:5]())
#7 Layer._addToSceneWithRetainedRendering (package:flutter[/src/rendering/layer.dart:545:5]())
#8 ContainerLayer.addChildrenToScene (package:flutter[/src/rendering/layer.dart:1105:13]())
#9 OffsetLayer.addToScene (package:flutter[/src/rendering/layer.dart:1239:5]())
#10 ContainerLayer.buildScene (package:flutter[/src/rendering/layer.dart:937:5]())
#11 OffsetLayer.toImage (package:flutter[/src/rendering/layer.dart:1276:28]())
#12 BlockedTextImageWidgetTesterExtensions.getBlockedTextImage (package:alchemist[/src/blocked_text_image.dart:33:18]())
#13 _generateAndCompare (package:alchemist[/src/golden_test.dart:338:48]())
<asynchronous suspension>
<asynchronous suspension>
(elided one frame from package:stack_trace)
════════════════════════════════════════════════════════════════════════════════════════════════════
Test failed. See exception logs above.
main.dart
with a widget MyApp
containing a CompositedTransformFollower
(used to display an introduction, example gif is given in the main.dart
section)broken_golden_test.dart
Example gif showing the use case of CompositedTransformFollower
to show an introduction overlay:
main.dart
:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
final bool initialShowIntroductionEnabled;
final int initialIntroIndex;
const MyApp({
this.initialIntroIndex = 0,
this.initialShowIntroductionEnabled = true,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(
initialIntroIndex: initialIntroIndex,
initialShowIntroductionEnabled: initialShowIntroductionEnabled,
),
);
}
}
class MyHomePage extends StatefulWidget {
final bool initialShowIntroductionEnabled;
final int initialIntroIndex;
const MyHomePage({
this.initialIntroIndex = 0,
this.initialShowIntroductionEnabled = false,
Key? key,
}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late bool showIntroduction;
late int introIndex;
@override
void initState() {
showIntroduction = widget.initialShowIntroductionEnabled;
introIndex = widget.initialIntroIndex;
super.initState();
}
@override
Widget build(BuildContext context) {
final myHomeBody = MyHomeBody();
void showNextStepOverlay() {
setState(() {
if (++introIndex >= myHomeBody.layerLinks.length) {
introIndex = 0;
}
});
}
return Scaffold(
appBar: AppBar(title: const Text('Demo')),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.help),
onPressed: () => setState(() => showIntroduction = !showIntroduction),
),
body: Stack(children: [
myHomeBody,
if (showIntroduction) ...[
MyIntroductionOverlay(layerLink: myHomeBody.layerLinks[introIndex]),
Positioned(
left: 0,
right: 0,
bottom: 0,
child: SafeArea(
child: Center(
child: ElevatedButton(
child: const Text('Next step'),
onPressed: showNextStepOverlay,
)),
),
)
]
]),
);
}
}
class MyHomeBody extends StatelessWidget {
MyHomeBody({Key? key}) : super(key: key);
final layerLinkFlutterLogo = LayerLink();
final layerLinkText = LayerLink();
final layerLinkButton = LayerLink();
final layerLinkIcon = LayerLink();
List<LayerLink> get layerLinks => [
layerLinkFlutterLogo,
layerLinkText,
layerLinkButton,
layerLinkIcon,
];
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
CompositedTransformTarget(
link: layerLinkFlutterLogo,
child: const FlutterLogo(),
),
CompositedTransformTarget(
link: layerLinkText,
child: const Text('hello world'),
),
CompositedTransformTarget(
link: layerLinkButton,
child: const ElevatedButton(
onPressed: null,
child: Text('this is a button'),
),
),
CompositedTransformTarget(
link: layerLinkIcon,
child: const Icon(Icons.help),
)
],
),
);
}
}
class MyIntroductionOverlay extends StatelessWidget {
final LayerLink layerLink;
const MyIntroductionOverlay({required this.layerLink, Key? key})
: super(key: key);
@override
Widget build(BuildContext context) {
return CompositedTransformFollower(
targetAnchor: Alignment.topCenter,
followerAnchor: Alignment.topCenter,
link: layerLink,
child: Container(
height: 65,
color: Colors.red.withOpacity(0.5),
alignment: Alignment.bottomCenter,
child: Text("overlay with helpful explanation"),
),
);
}
}
import 'package:alchemist/alchemist.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:scratches/main.dart';
void main() {
// This test is broken when both enableCiTests and enableIntroduction are true
const enableCiTests = true;
// when true, MyApp contains a CompositedTransformFollower
const enableIntroduction = true;
const phoneSize = Size(400, 900);
AlchemistConfig.runWithConfig(
config: const AlchemistConfig(
forceUpdateGoldenFiles: true,
ciGoldensConfig: CiGoldensConfig(enabled: enableCiTests),
platformGoldensConfig: PlatformGoldensConfig(enabled: true),
),
run: () => goldenTest(
'demo',
fileName: 'demo',
widget: GoldenTestGroup(
children: [
GoldenTestScenario(
name: 'introduction',
child: ConstrainedBox(
constraints: BoxConstraints.tight(phoneSize),
child: const MyApp(
initialShowIntroductionEnabled: enableIntroduction,
),
),
),
],
),
),
);
}
No exception should be thrown and the test should pass.
The test does work for platform tests. The problem only occurs for CI tests because only in that case BlockedTextImageWidgetTesterExtensions.getBlockedTextImage
is called which throws when a widget contains a CompositedTransformTarget
No response
No response
0.4.1
Our app have many, many golden test like following. The issue is about memory consumption, we are today at 40go every run. Do you know what in golden test took so much memory ? Any general good practice ?
goldenTest(
'renders texts correctly',
fileName:
'theme-texts-${flavor.runtimeType.toString().toLowerCase()}-${mode.name}',
builder: () => GoldenTestGroup(
columns: 1,
children: <GoldenTestScenario>[
GoldenTestScenario(
name: 'body text 1',
child: Text(
'Sample text',
style: textTheme.bodyText1,
),
),
GoldenTestScenario(
name: 'body text 2',
child: Text(
'Sample text',
style: textTheme.bodyText2,
),
),
GoldenTestScenario(
name: 'headline 1',
child: Text(
'Sample text',
style: textTheme.headline1,
),
),
GoldenTestScenario(
name: 'headline 2',
child: Text(
'Sample text',
style: textTheme.headline2,
),
),
GoldenTestScenario(
name: 'headline 3',
child: Text(
'Sample text',
style: textTheme.headline3,
),
),
GoldenTestScenario(
name: 'headline 4',
child: Text(
'Sample text',
style: textTheme.headline4,
),
),
GoldenTestScenario(
name: 'headline 5',
child: Text(
'Sample text',
style: textTheme.headline5,
),
),
GoldenTestScenario(
name: 'headline 6',
child: Text(
'Sample text',
style: textTheme.headline6,
),
),
GoldenTestScenario(
name: 'subtitle 1',
child: Text(
'Sample text',
style: textTheme.subtitle1,
),
),
GoldenTestScenario(
name: 'subtitle 2',
child: Text(
'Sample text',
style: textTheme.subtitle2,
),
),
],
),
);
run many golden test
As less memory as possible
No response
No response
0.6.1
During the creation of golden tests for our existing app, I've encountered following error executing said tests:
══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
The following assertion was thrown during performLayout():
LayoutBuilder does not support returning intrinsic dimensions.
Calculating the intrinsic dimensions would require running the layout callback speculatively, which
might mutate the live render object tree.
The relevant error-causing widget was:
Table
Table:~/Pub/Cache/hosted/pub.dev/alchemist-0.6.1/lib/src/golden_test_group.dart:117:14
When the exception was thrown, this was the stack:
#0 _RenderLayoutBuilder._debugThrowIfNotCheckingIntrinsics.<anonymous closure> (package:flutter/src/widgets/layout_builder.dart:345:9)
#1 _RenderLayoutBuilder._debugThrowIfNotCheckingIntrinsics (package:flutter/src/widgets/layout_builder.dart:352:6)
#2 _RenderLayoutBuilder.computeMaxIntrinsicHeight (package:flutter/src/widgets/layout_builder.dart:297:12)
#3 RenderBox._computeIntrinsicDimension.<anonymous closure> (package:flutter/src/rendering/box.dart:1409:23)
#4 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:535:23)
#5 RenderBox._computeIntrinsicDimension (package:flutter/src/rendering/box.dart:1407:57)
#6 RenderBox.getMaxIntrinsicHeight (package:flutter/src/rendering/box.dart:1746:12)
#7 RenderFlex.computeMaxIntrinsicHeight.<anonymous closure> (package:flutter/src/rendering/flex.dart:615:60)
#8 RenderFlex._getIntrinsicSize (package:flutter/src/rendering/flex.dart:573:58)
#9 RenderFlex.computeMaxIntrinsicHeight (package:flutter/src/rendering/flex.dart:612:12)
#10 RenderBox._computeIntrinsicDimension.<anonymous closure> (package:flutter/src/rendering/box.dart:1409:23)
#11 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:535:23)
#12 RenderBox._computeIntrinsicDimension (package:flutter/src/rendering/box.dart:1407:57)
#13 RenderBox.getMaxIntrinsicHeight (package:flutter/src/rendering/box.dart:1746:12)
#14 RenderFlex._getIntrinsicSize (package:flutter/src/rendering/flex.dart:554:32)
#15 RenderFlex.computeMaxIntrinsicWidth (package:flutter/src/rendering/flex.dart:594:12)
#16 RenderBox._computeIntrinsicDimension.<anonymous closure> (package:flutter/src/rendering/box.dart:1409:23)
#17 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:535:23)
#18 RenderBox._computeIntrinsicDimension (package:flutter/src/rendering/box.dart:1407:57)
#19 RenderBox.getMaxIntrinsicWidth (package:flutter/src/rendering/box.dart:1595:12)
#20 RenderProxyBoxMixin.computeMaxIntrinsicWidth (package:flutter/src/rendering/proxy_box.dart:82:21)
#21 RenderConstrainedBox.computeMaxIntrinsicWidth (package:flutter/src/rendering/proxy_box.dart:259:32)
#22 RenderBox._computeIntrinsicDimension.<anonymous closure> (package:flutter/src/rendering/box.dart:1409:23)
#23 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:535:23)
#24 RenderBox._computeIntrinsicDimension (package:flutter/src/rendering/box.dart:1407:57)
#25 RenderBox.getMaxIntrinsicWidth (package:flutter/src/rendering/box.dart:1595:12)
#26 RenderProxyBoxMixin.computeMaxIntrinsicWidth (package:flutter/src/rendering/proxy_box.dart:82:21)
#27 RenderConstrainedBox.computeMaxIntrinsicWidth (package:flutter/src/rendering/proxy_box.dart:259:32)
#28 RenderBox._computeIntrinsicDimension.<anonymous closure> (package:flutter/src/rendering/box.dart:1409:23)
#29 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:535:23)
#30 RenderBox._computeIntrinsicDimension (package:flutter/src/rendering/box.dart:1407:57)
#31 RenderBox.getMaxIntrinsicWidth (package:flutter/src/rendering/box.dart:1595:12)
#32 RenderFlex.computeMaxIntrinsicWidth.<anonymous closure> (package:flutter/src/rendering/flex.dart:597:60)
#33 RenderFlex._getIntrinsicSize (package:flutter/src/rendering/flex.dart:555:36)
#34 RenderFlex.computeMaxIntrinsicWidth (package:flutter/src/rendering/flex.dart:594:12)
#35 RenderBox._computeIntrinsicDimension.<anonymous closure> (package:flutter/src/rendering/box.dart:1409:23)
#36 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:535:23)
#37 RenderBox._computeIntrinsicDimension (package:flutter/src/rendering/box.dart:1407:57)
#38 RenderBox.getMaxIntrinsicWidth (package:flutter/src/rendering/box.dart:1595:12)
#39 RenderPadding.computeMaxIntrinsicWidth (package:flutter/src/rendering/shifted_box.dart:178:21)
#40 RenderBox._computeIntrinsicDimension.<anonymous closure> (package:flutter/src/rendering/box.dart:1409:23)
#41 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:535:23)
#42 RenderBox._computeIntrinsicDimension (package:flutter/src/rendering/box.dart:1407:57)
#43 RenderBox.getMaxIntrinsicWidth (package:flutter/src/rendering/box.dart:1595:12)
#44 IntrinsicColumnWidth.maxIntrinsicWidth (package:flutter/src/rendering/table.dart:116:38)
#45 RenderTable._computeColumnWidths (package:flutter/src/rendering/table.dart:877:52)
#46 RenderTable.performLayout (package:flutter/src/rendering/table.dart:1085:33)
#47 RenderObject.layout (package:flutter/src/rendering/object.dart:2395:7)
#48 RenderBox.layout (package:flutter/src/rendering/box.dart:2386:11)
#49 RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:238:12)
#50 RenderObject.layout (package:flutter/src/rendering/object.dart:2395:7)
#51 RenderBox.layout (package:flutter/src/rendering/box.dart:2386:11)
#52 RenderPositionedBox.performLayout (package:flutter/src/rendering/shifted_box.dart:438:14)
#53 RenderObject.layout (package:flutter/src/rendering/object.dart:2395:7)
#54 RenderBox.layout (package:flutter/src/rendering/box.dart:2386:11)
#55 RenderConstrainedOverflowBox.performLayout (package:flutter/src/rendering/shifted_box.dart:631:14)
#56 RenderObject.layout (package:flutter/src/rendering/object.dart:2395:7)
#57 RenderBox.layout (package:flutter/src/rendering/box.dart:2386:11)
#58 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:122:14)
#59 RenderObject.layout (package:flutter/src/rendering/object.dart:2395:7)
#60 RenderBox.layout (package:flutter/src/rendering/box.dart:2386:11)
#61 RenderPositionedBox.performLayout (package:flutter/src/rendering/shifted_box.dart:438:14)
#62 RenderObject.layout (package:flutter/src/rendering/object.dart:2395:7)
#63 RenderBox.layout (package:flutter/src/rendering/box.dart:2386:11)
#64 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:122:14)
#65 RenderObject.layout (package:flutter/src/rendering/object.dart:2395:7)
#66 RenderBox.layout (package:flutter/src/rendering/box.dart:2386:11)
#67 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:122:14)
#68 RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:554:11)
#69 RenderObject.layout (package:flutter/src/rendering/object.dart:2395:7)
#70 RenderBox.layout (package:flutter/src/rendering/box.dart:2386:11)
#71 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:122:14)
#72 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1449:11)
#73 RenderObject.layout (package:flutter/src/rendering/object.dart:2395:7)
#74 RenderBox.layout (package:flutter/src/rendering/box.dart:2386:11)
#75 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:122:14)
#76 RenderObject.layout (package:flutter/src/rendering/object.dart:2395:7)
#77 RenderBox.layout (package:flutter/src/rendering/box.dart:2386:11)
#78 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:122:14)
#79 RenderObject.layout (package:flutter/src/rendering/object.dart:2395:7)
#80 RenderBox.layout (package:flutter/src/rendering/box.dart:2386:11)
#81 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:122:14)
#82 RenderObject.layout (package:flutter/src/rendering/object.dart:2395:7)
#83 RenderBox.layout (package:flutter/src/rendering/box.dart:2386:11)
#84 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:122:14)
#85 RenderObject.layout (package:flutter/src/rendering/object.dart:2395:7)
#86 RenderBox.layout (package:flutter/src/rendering/box.dart:2386:11)
#87 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:122:14)
#88 RenderObject.layout (package:flutter/src/rendering/object.dart:2395:7)
#89 RenderBox.layout (package:flutter/src/rendering/box.dart:2386:11)
#90 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:122:14)
#91 RenderObject.layout (package:flutter/src/rendering/object.dart:2395:7)
#92 RenderBox.layout (package:flutter/src/rendering/box.dart:2386:11)
#93 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:122:14)
#94 RenderObject.layout (package:flutter/src/rendering/object.dart:2395:7)
#95 RenderBox.layout (package:flutter/src/rendering/box.dart:2386:11)
#96 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:122:14)
#97 RenderObject.layout (package:flutter/src/rendering/object.dart:2395:7)
#98 RenderBox.layout (package:flutter/src/rendering/box.dart:2386:11)
#99 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:122:14)
#100 RenderObject.layout (package:flutter/src/rendering/object.dart:2395:7)
#101 RenderBox.layout (package:flutter/src/rendering/box.dart:2386:11)
#102 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:122:14)
#103 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3751:13)
#104 RenderObject.layout (package:flutter/src/rendering/object.dart:2395:7)
#105 RenderBox.layout (package:flutter/src/rendering/box.dart:2386:11)
#106 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:122:14)
#107 RenderObject.layout (package:flutter/src/rendering/object.dart:2395:7)
#108 RenderBox.layout (package:flutter/src/rendering/box.dart:2386:11)
#109 _RenderTheaterMixin.performLayout (package:flutter/src/widgets/overlay.dart:832:15)
#110 RenderObject.layout (package:flutter/src/rendering/object.dart:2395:7)
#111 RenderBox.layout (package:flutter/src/rendering/box.dart:2386:11)
#112 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:122:14)
#113 RenderObject.layout (package:flutter/src/rendering/object.dart:2395:7)
#114 RenderBox.layout (package:flutter/src/rendering/box.dart:2386:11)
#115 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:122:14)
#116 RenderObject.layout (package:flutter/src/rendering/object.dart:2395:7)
#117 RenderBox.layout (package:flutter/src/rendering/box.dart:2386:11)
#118 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:122:14)
#119 RenderObject.layout (package:flutter/src/rendering/object.dart:2395:7)
#120 RenderBox.layout (package:flutter/src/rendering/box.dart:2386:11)
#121 RenderView.performLayout (package:flutter/src/rendering/view.dart:173:14)
#122 RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2234:7)
#123 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1016:18)
#124 AutomatedTestWidgetsFlutterBinding.drawFrame (package:flutter_test/src/binding.dart:1388:23)
#125 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:358:5)
#126 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1284:15)
#127 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1214:9)
#128 AutomatedTestWidgetsFlutterBinding.pump.<anonymous closure> (package:flutter_test/src/binding.dart:1236:9)
#131 TestAsyncUtils.guard (package:flutter_test/src/test_async_utils.dart:68:41)
#132 AutomatedTestWidgetsFlutterBinding.pump (package:flutter_test/src/binding.dart:1222:27)
#133 WidgetTester._pumpWidget (package:flutter_test/src/widget_tester.dart:592:20)
#134 WidgetTester.pumpWidget.<anonymous closure> (package:flutter_test/src/widget_tester.dart:577:14)
#137 TestAsyncUtils.guard (package:flutter_test/src/test_async_utils.dart:68:41)
#138 WidgetTester.pumpWidget (package:flutter_test/src/widget_tester.dart:576:27)
#139 onlyPumpWidget (package:alchemist/src/pumps.dart:74:17)
#140 FlutterGoldenTestAdapter.pumpGoldenTest (package:alchemist/src/golden_test_adapter.dart:238:21)
#141 FlutterGoldenTestRunner.run (package:alchemist/src/golden_test_runner.dart:78:31)
#142 goldenTest.<anonymous closure> (package:alchemist/src/golden_test.dart:169:30)
<asynchronous suspension>
<asynchronous suspension>
(elided 5 frames from dart:async and package:stack_trace)
The following RenderObject was being processed when the exception was fired: RenderTable#1ea5e relayoutBoundary=up3 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE:
creator: Table ← GoldenTestScenarioConstraints ← GoldenTestGroup ← Padding-[#04929] ← Center ←
OverflowBox ← ColoredBox ← Builder ← Align ← DefaultTextStyle ← AnimatedDefaultTextStyle ←
_InkFeatures-[GlobalKey#ae861 ink renderer] ← ⋯
parentData: offset=Offset(8.0, 8.0) (can use size)
constraints: BoxConstraints(unconstrained)
size: MISSING
border: TableBorder(BorderSide(width: 0.0, style: none), BorderSide(width: 0.0, style: none),
BorderSide(width: 0.0, style: none), BorderSide(width: 0.0, style: none), BorderSide(color:
Color(0x4d000000)), BorderSide(color: Color(0x4d000000)), BorderRadius.zero)
default column width: IntrinsicColumnWidth(flex: null)
table size: 1×1
column offsets: unknown
row offsets: []
This RenderObject had the following descendants (showing up to depth 5):
child (0, 0): RenderPadding#950d5 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
child: RenderFlex#f9517 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
child 1: RenderParagraph#f1a93 NEEDS-LAYOUT NEEDS-PAINT
text: TextSpan
child 2: RenderConstrainedBox#7de36 NEEDS-LAYOUT NEEDS-PAINT
child 3: RenderConstrainedBox#eaeab NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
child: RenderConstrainedBox#aaa9b NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
child: RenderFlex#64667 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
════════════════════════════════════════════════════════════════════════════════════════════════════
I've tried going down the tree of the tested components and identifying the root cause of these errors, but after isolating the affected widgets in widget-tests without using alchemist, I don't encounter them anymore. Also, the affected RenderObject seems to be within the alchemist source.
I've tried to produce a POC that enables the reproduction of the error, the possibility of a fault within my test structure I didn't notice is also very real.
Alchemist golden test:
void main() {
group('LegendItem Golden Tests', () {
goldenTest(
'LegendItem scenarios render correctly',
fileName: 'legend_item',
tags: ['golden'],
builder: () => GoldenTestGroup(
children: [
GoldenTestScenario(
name: 'scenario 1',
child: const ProviderScope(
child: LegendItem(
color: Colors.red,
text: 'alchemist text',
valueLabel: 'betterment value',
percentLabel: 'percentLabel',
),
),
),
],
),
);
});
}
Code for the tested widget:
class LegendItem extends StatelessWidget {
const LegendItem({
super.key,
required this.color,
required this.text,
this.size = 16,
this.textColor = const Color(0xff505050),
required this.valueLabel,
required this.percentLabel,
});
/// Legend item color
final Color color;
/// Legend indicator size
final double size;
/// Item description
final String text;
/// Color of [text]
final Color textColor;
/// Value label
final String valueLabel;
/// Label describing the percentage of the total value
final String percentLabel;
static const kSpacing = 2.0;
@override
Widget build(BuildContext context) {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
width: size,
height: size,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: color,
),
),
const SizedBox(width: kSpacing),
Flexible(
child: AutoSizeText(
text,
style: Theme.of(context).textTheme.labelSmall,
textAlign: TextAlign.start,
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(child: AutoSizeText(percentLabel)),
const SizedBox(width: kSpacing),
Flexible(
child: AutoSizeText(
valueLabel,
style: Theme.of(context).textTheme.titleSmall,
textAlign: TextAlign.start,
),
),
],
),
],
);
}
}
LegendItem
in alchemist golden testExpected behavior would include a successful compilation of the test as well as rendering of goldens for the current host platform.
No response
I can provide more information about the projects/my current setup if necessary. If the error is actually within alchemist, I would be happy to provide help regarding the identification and fixing of the bug.
Ability to perform actions for every test individually
GoldenTestScenario
should have whilePerforming
parameter, so every test could have different action. Currently, to create the same scenario but different actions, you have to create a second file.
I want all test to be in single file, because they all corresponds to the same widget.
Ability to disable text widget for csenario name in CI env
Config setting which when enabled removes Text widget with scenario.name parameter from CI image
Since in CI font is obscured for compativility, names doesn't make sense and just clutter image. Also, ahem font takes much more space and something like 30-35 long name is making CI image twice as wide
(this is 35 symbols including whitespaces)
No response
I would like to mock Image.network to support that in golden_tests
I want to test widgets that use Image.network
in golden tests. Right now if there is a widget trying to use Image.network
the following exception is thrown:
When the exception was thrown, this was the stack:
#0 NetworkImage._loadAsync (package:flutter/src/painting/_network_image_io.dart:98:9)
<asynchronous suspension>
<asynchronous suspension>
(elided one frame from package:stack_trace)
Image provider: NetworkImage("", scale: 1.0)
Image key: NetworkImage("", scale: 1.0)
Testing widgets with Network Images should be vital
I tried to wrap the goldenTest
with await mockNetworkImages(() async {
from https://github.com/felangel/mocktail/tree/main/packages/mocktail_image_network but that did not have the desired effect
I would like a possibility to remove the artificial border
Hi, the FlutterGoldenTestAdapter adds an 8 pixel border inside FlutterGoldenTestAdapter.pumpGoldenTest. What is the reason for it, and how can I disable it?
This would be useful, because I want my goldens matching my app as close as possible.
No response
v0.7.0
Hi 👋
After using the “alchemist” library, I noticed that our test execution on CI takes more time, and sometimes it hangs on the tearDownAll
function.
My use case of execution tests is a bit different. I run all the tests in one isolate, mainly to speed things up on CI. The testMain
during test execution is called only once, along with the testExecutable
at flutter_test_config
.
Let’s say I have 100 golden tests. For each of them, the loadFonts
function is called before the test, which takes time to execute. It is called 100 times. But should only once.
I would like to call this function only once before my tests execution, at flutter_test_config
.
I forked the library, removed the loadFonts
function call on every test execution, and moved it to the flutter_test_config
. The problem was resolved.
Actual behavior: The loadFonts
function is called ten times.
The loadFonts
function is called only once.
No response
Thanks for the library 🚀
0.7.0
Since recent Flutter upgrade to 3.16 I now have issues after regenerating goldens on my machine, some of them fail on CI due to slight differences.
My process:
PlatformGoldensConfig(enabled: true)
. All my golden files are generated correctly.PlatformGoldensConfig(enabled: false)
, then I get a lot (but not all) golden tests failing with a very slight diff percentage.Now I don't understand what is happening but what I can reproduce for sure is that all golden tests that contain multiple scenarii and hence multiple lines or columns, FAIL.
Take this golden file as an example that contains a dumb container with a border:
Code:
goldenTest(
'Simple container',
fileName: 'simple-container-one-column',
builder: () => GoldenTestGroup(
columns: 1,
scenarioConstraints: const BoxConstraints(
minWidth: 100,
maxWidth: 100,
minHeight: 50,
maxHeight: 50,
),
children: [
GoldenTestScenario(
name: '100x50 container with blue border',
child: _separator(Colors.blue),
),
],
),
);
✅ This golden file is correctly generated and asserted during CI tests.
Now take the same test that just duplicates previous scenario:
goldenTest(
'Simple container, two columns',
fileName: 'simple-containers-two-columns',
builder: () => GoldenTestGroup(
columns: 2,
scenarioConstraints: const BoxConstraints(
minWidth: 100,
maxWidth: 100,
minHeight: 50,
maxHeight: 50,
),
children: [
GoldenTestScenario(
name: '100x50 container with blue border',
child: _separator(Colors.blue),
),
GoldenTestScenario(
name: '100x50 container with blue border',
child: _separator(Colors.blue),
),
],
),
);
✅On my machine, everything runs as expected:
❌ But this time on the CI, I have a slight difference showing at t
he left border of my container for the second scenario (second column) as shown in the following golden failure masked & isolated diffs:
Same thing happens for goldens tests that contain a single column but multiple scenarii.
Take this example that runs smoothly on my machine :
❌ Now on the CI, I would get a very subtle one pixel diff at the end of the scenarii separator.
Here is the isolated diff:
I've pointed the actual 1 pixel difference with a big red arrow because the diff is very subtle 😅
What is happening here ? I would expect the CI test, that explicitly doesn't display fonts, would work well.
There seems to be an issue with how alchemist package separate the different scenarii in multiple lines or columns after upgrading to Flutter 3.16.
import 'package:alchemist/alchemist.dart';
import 'package:flutter/material.dart';
Widget _separator(
Color color, [
String? text,
]) =>
Container(
decoration: BoxDecoration(
border: Border.all(color: color, width: 2),
),
height: 25,
child: text != null
? Text(
text,
textAlign: TextAlign.center,
)
: null,
);
void main() {
goldenTest(
'Simple container',
fileName: 'simple-container-one-column',
builder: () => GoldenTestGroup(
columns: 1,
scenarioConstraints: const BoxConstraints(
minWidth: 100,
maxWidth: 100,
minHeight: 50,
maxHeight: 50,
),
children: [
GoldenTestScenario(
name: '100x50 container with blue border',
child: _separator(Colors.blue),
),
],
),
);
goldenTest(
'Simple container, two columns',
fileName: 'simple-containers-two-columns',
builder: () => GoldenTestGroup(
columns: 2,
scenarioConstraints: const BoxConstraints(
minWidth: 100,
maxWidth: 100,
minHeight: 50,
maxHeight: 50,
),
children: [
GoldenTestScenario(
name: '100x50 container with blue border',
child: _separator(Colors.blue),
),
GoldenTestScenario(
name: '100x50 container with blue border',
child: _separator(Colors.blue),
),
],
),
);
}
flutter test update-goldens
) on a first platform (e.g. a MacBook Pro or Windows machine)Golden tests should pass and we shouldn't have diffs that are introduced by alchemist library itself (on its separators).
No response
No response
Say I have a component that is re-used across mobile and desktop e.g. a button.
Hypothetically on desktop the button should be 32x32 and on mobile it should be 40x40, among other differences.
Assuming I make the distinction between platforms based on the foundation.dart
property: defaultTargetPlatform
in the button -- is there a way for me to run my golden tests/scenarios against both platforms?
I've looked into AlchemistConfig
but can find any way to specific these type of variation.
I also tried to hack it manually but it didn't work (I have the same golden images for both):
import 'package:alchemist/alchemist.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('Golden Tests', () async {
Future<void> runTests(String variant) async {
await goldenTest(
'should render correctly',
fileName: 'component_$variant',
constraints: const BoxConstraints(maxWidth: 800),
builder: () {
return GoldenTestGroup(
columnWidthBuilder: (_) => const FlexColumnWidth(),
children: [
GoldenTestScenario(
name: 'scenario 1',
child: ...,
),
GoldenTestScenario(
name: 'scenario w',
child: ...,
),
],
);
},
);
}
// Desktop
debugDefaultTargetPlatformOverride = TargetPlatform.macOS;
await runTests('desktop');
debugDefaultTargetPlatformOverride = null;
// Mobile
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await runTests('mobile');
debugDefaultTargetPlatformOverride = null;
});
}
Any advice on how to test goldens agains multiple target platforms in a nice way?
Or any idea why even my hack solution does not work?
Thanks in advance,
Cillian.
0.4.1
class BlockedTextCanvasAdapter implements Canvas, but I guess in Flutter 3.3 Canvas got some new members. I'm getting the following error:
../../../../../.pub-cache/hosted/pub.dartlang.org/alchemist-0.4.1/lib/src/blocked_text_image.dart:65:7: Error: The non-abstract class 'BlockedTextCanvasAdapter' is missing implementations for these members:
- Canvas.getDestinationClipBounds
- Canvas.getLocalClipBounds
- Canvas.getTransform
Try to either
- provide an implementation,
- inherit an implementation from a superclass or mixin,
- mark the class as abstract, or
- provide a 'noSuchMethod' implementation.
class BlockedTextCanvasAdapter implements Canvas {
^^^^^^^^^^^^^^^^^^^^^^^^
org-dartlang-sdk:///flutter/lib/ui/painting.dart:4588:8: Context: 'Canvas.getDestinationClipBounds' is defined here.
Rect getDestinationClipBounds() {
^^^^^^^^^^^^^^^^^^^^^^^^
org-dartlang-sdk:///flutter/lib/ui/painting.dart:4567:8: Context: 'Canvas.getLocalClipBounds' is defined here.
Rect getLocalClipBounds() {
^^^^^^^^^^^^^^^^^^
org-dartlang-sdk:///flutter/lib/ui/painting.dart:4457:15: Context: 'Canvas.getTransform' is defined here.
Float64List getTransform() {
^^^^^^^^^^^^
Just try to run golden tests in Flutter 3.3
Tests run
No response
No response
Since for the golden tests, you can add a comparator and make some tolerance: flutter/flutter#77014
This option should also be available for Alchemist, ideally in AlchemistConfig.
I wanted to do this as a workaround because our golden test are failing with 0.00% diff (there can be like 1 pixel of difference) since Flutter 3.7.0.
I don't know what's the reason for this failure, I'm not sure it's related to Alchemist so I didn't want to open a bug here.
I don't see how else I can fix this since on my local machine all tests work fine.
No response
I would like to be able to read the error message from the golden file.
As a developer, I would like to be able to read the error message from a golden file.
Allowing to view the error message from the golden file facilitates debugging and, hence makes the DX much nicer.
For example, the following image should have the error shown in a legible font (not Ahem):
No response
0.6.1
Running Alchemist golden tests in Flutter 3.13.0 throws an error:
: Error: A value of type 'void Function(String, Future<void> Function(WidgetTester), {int? retry, bool semanticsEnabled, bool? skip, dynamic tags, Timeout? timeout, TestVariant<Object?> variant})' can't be assigned to a variable of type 'FutureOr<void> Function(String, Future<void> Function(WidgetTester), {Duration? initialTimeout, bool semanticsEnabled, bool? skip, dynamic tags, Timeout? timeout, TestVariant<Object?> variant})'.
golden_test_adapter.dart:53
- 'Future' is from 'dart:async'.
- 'WidgetTester' is from 'package:flutter_test/src/widget_tester.dart' ('../../../../Development/flutter/packages/flutter_test/lib/src/widget_tester.dart').
widget_tester.dart:1
- 'Timeout' is from 'package:test_api/src/backend/configuration/timeout.dart' ('../../../../.pub-cache/hosted/pub.dev/test_api-0.6.0/lib/src/backend/configuration/timeout.dart').
timeout.dart:1
- 'TestVariant' is from 'package:flutter_test/src/widget_tester.dart' ('../../../../Development/flutter/packages/flutter_test/lib/src/widget_tester.dart').
widget_tester.dart:1
- 'Object' is from 'dart:core'.
- 'Duration' is from 'dart:core'.
TestWidgetsFn defaultTestWidgetsFn = testWidgets;
import 'package:alchemist/alchemist.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('ListTile Golden Tests', () {
goldenTest(
'renders correctly',
fileName: 'list_tile',
builder: () => GoldenTestGroup(
scenarioConstraints: const BoxConstraints(maxWidth: 600),
children: [
GoldenTestScenario(
name: 'with title',
child: ListTile(
title: Text('ListTile.title'),
),
),
GoldenTestScenario(
name: 'with title and subtitle',
child: ListTile(
title: Text('ListTile.title'),
subtitle: Text('ListTile.subtitle'),
),
),
GoldenTestScenario(
name: 'with trailing icon',
child: ListTile(
title: Text('ListTile.title'),
trailing: Icon(Icons.chevron_right_rounded),
),
),
],
),
);
});
}
Tests should run (and fail without adding the golden files first)
No response
0.6.1
When updating to the newest flutter version 3.13.1
, the golden tests are failing when widgets with custom RenderObjects are tested.
Previously the text and icons were visible in the golden images. Now nothing is displayed (see the screenshots).
import 'package:alchemist/alchemist.dart';
import 'package:flutter/material.dart';
void main() {
// ignore: discarded_futures,
goldenTest(
'golden test',
fileName: 'h4u_adaptive_text',
builder: () => const SizedBox(
height: 800,
width: 400,
child: CustomExampleRenderObject(),
),
);
}
class CustomExampleRenderObject extends LeafRenderObjectWidget {
const CustomExampleRenderObject({super.key});
@override
CustomExampleRenderBox createRenderObject(BuildContext context) {
return CustomExampleRenderBox();
}
}
class CustomExampleRenderBox extends RenderBox {
@override
void paint(PaintingContext context, Offset offset) {
final canvas = context.canvas;
canvas.save();
canvas.translate(offset.dx, offset.dy);
final textPainter = TextPainter(
text: const TextSpan(
text: 'text',
style: TextStyle(),
),
textDirection: TextDirection.ltr,
);
textPainter.layout();
textPainter.paint(canvas, Offset.zero);
canvas.restore();
}
@override
void performLayout() {
this.size = this.computeDryLayout(this.constraints);
}
@override
Size computeDryLayout(BoxConstraints constraints) {
return constraints.constrain(Size(
200.0,
constraints.maxHeight,
));
}
}
In the example, I would expect that my text is still shown in the images and in general I would expect that it still works with Custom RenderObjects.
CI Image with Flutter Version 3.10.6
:
CI Image with Flutter Version 3.13.1
:
No response
Generate goldens files with same structure as test files
I have a test file with path like test/widgets/helpers/simple_html_test.dart
.
I want to generate golden test image in test/goldens/widgets/helpers/simple_html_test.dart
.
Is it possible to achieve this without creating separate configuration for every directory or setting filename with path as goldenTest
argument?
Many packages that use build_runner
allows you to configure this, so
I would like to stay consistent with generated files in my project and don't mix test files with images.
It would be awesome to add a support for the localisation in the library
First of all, thanks for an awesome library and your work!
The problem is, I haven't found a proper way to add localisations delegate to the golden test, and this feature is extremely important to have in order to test any widget with localisation.
I've added localizationsDelegates param in my fork to enable localisation, and it actually worked. But the problem is, after adding an AppLocalizationDelegate
to the MaterialApp
, alchemist has stopped rendering any kind of images. Any asset or file image would become transparent. However, after removing the delegate, images appear again. I've tested adding the same AppLocalizationDelegate
to the MaterialApp with a golden_toolkit library, and there was no such problem (images were rendered and localisation worked as well).
Maybe you have any ideas on how to add a localizationsDelegates to the test in a way that prevents this issue with rendering images?
I think that supporting localisation in the library would greatly increase the usability
You can refer to my closed PR, where I've added the coreWrapper: #43
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.