look 1.1.0 look: ^1.1.0 copied to clipboard
Look helps you to work on a single widget in your real life app. Add the @look annoation, generate sources, run the look file and enjoy!
Look #
Look is a Flutter package for Widget preview.
It gives the possibility to start only the widget to preview and not the whole application.
Purpose #
Imagine you are working on a Flutter application and you want to work and edit only a specific Widget, page, or whatever.
Most of the concrete applications have many pages, many widgets, and many other things like athentication, state management, routing, API, etc.
Let's suppose that you want to work on a deep page in the app. You have to start the whole app, maybe having to generate some data, beeing connected to an API or a server, etc.
But:
- You just want to work on a specific widget
- You don't really need to start the whole app, maybe generate data or be connected to an API or a server with authentication
- You don't really need to waiste time on all of these things
You main goal is only to work on this deep page.
Look was made for you !
Look package gives you the possibility to run only the widget you want to preview with no pre-requisites.
Getting started #
Add look, look_generator and build_runner to your app dependencies:
flutter pub add look
flutter pub add --dev look_generator build_runner
Features #
Previewing a widget #
Just add the @look
annotation to the widget you want to preview.
// my_widget.dart
@look
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container();
}
}
Generate sources using build_runner
using the fancy command line that everyone know now:
flutter pub run build_runner build --delete-conflicting-outputs
A brand new file has been generated beside the original one. Search for the file *.look.dart
.
Run it, and voilà !
Passing parameters #
Use a builder method to pass parameters to your widget.
@Look('myBuilderMethod')
class MyWidget extends StatelessWidget {
final String text;
final MyData data;
final MyController controller;
final AnyOtherWidget child;
MyWidget({
required this.text,
required this.data,
required this.controller,
required this.child,
});
@override
Widget build(BuildContext context) {
// ...
}
}
myBuilderMethod() => MyWidget(
text: 'Hello World',
data: MyData(),
controller: MyController(),
child: AnyOtherWidget(),
// ...
);
Golden tests with look #
Look is also a golden tests factory.
First, create a new dart file in the test
folder.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:example/pages/home.dart';
import 'package:look/look.dart';
part 'home_page_test.lookgolden.dart';
@LookGolden(type: MyHomePage)
main() => lookGoldens();
Then, generate test sources using the following command:
flutter pub run build_runner build --delete-conflicting-outputs
Look will generate golden tests for you.
// home_page_test.lookgolden.dart
// GENERATED CODE - DO NOT MODIFY BY HAND
// **************************************************************************
// GoldenGenerator
// **************************************************************************
part of 'home_page_test.dart';
lookGoldens() => group('MyHomePage golden tests', () {
testWidgets('1080x2340 MyHomePage light theme',
(WidgetTester tester) async {
tester.binding.window.physicalSizeTestValue =
const Size(1080.0, 2340.0);
await tester.pumpWidget(
MaterialApp(theme: ThemeData(), home: const MyHomePage()));
await expectLater(find.byType(MyHomePage),
matchesGoldenFile('goldens/MyHomePage_golden_1080x2340_.png'));
});
});
Available options for @LookGolden #
Option | Type | Description |
---|---|---|
type | DartType | The type of the widget to test |
builder | Function | Method reference of the builder function |
lightTheme | String | Method reference of the light theme builder function |
darkTheme | String | Method reference of the dark theme builder function |
name | String | The name of the golden file |
dimensions | List | The dimension list of the golden to test (format: 'width:height'; example: '800x600') |
Example with options
// test/golden_shape_test.dart
import 'package:example/pages/widgets/shape.dart';
import 'package:example/theme.dart';
import 'package:look/look.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
part 'golden_shape_test.lookgolden.dart';
@LookGolden(
type: DynamicShape,
builder: dynamicShapeBuilder,
lightTheme: lightTheme,
darkTheme: darkTheme,
name: 'goldens/DynamicShape_golden.png',
dimensions: ['400x600', '800x600', '800x1200', '1600x1200'],
)
main() => lookGoldens();
Complex example result
// golden_shape_test.lookgolden.dart
// GENERATED CODE - DO NOT MODIFY BY HAND
// **************************************************************************
// GoldenGenerator
// **************************************************************************
part of 'golden_shape_test.dart';
lookGoldens() => group('DynamicShape golden tests', () {
testWidgets('400x600 DynamicShape light theme',
(WidgetTester tester) async {
tester.binding.window.physicalSizeTestValue = const Size(400.0, 600.0);
await tester.pumpWidget(
MaterialApp(theme: lightTheme(), home: dynamicShapeBuilder()));
await expectLater(find.byType(DynamicShape),
matchesGoldenFile('goldens/DynamicShape_golden_400x600_.png'));
});
testWidgets('800x600 DynamicShape light theme',
(WidgetTester tester) async {
tester.binding.window.physicalSizeTestValue = const Size(800.0, 600.0);
await tester.pumpWidget(
MaterialApp(theme: lightTheme(), home: dynamicShapeBuilder()));
await expectLater(find.byType(DynamicShape),
matchesGoldenFile('goldens/DynamicShape_golden_800x600_.png'));
});
testWidgets('800x1200 DynamicShape light theme',
(WidgetTester tester) async {
tester.binding.window.physicalSizeTestValue = const Size(800.0, 1200.0);
await tester.pumpWidget(
MaterialApp(theme: lightTheme(), home: dynamicShapeBuilder()));
await expectLater(find.byType(DynamicShape),
matchesGoldenFile('goldens/DynamicShape_golden_800x1200_.png'));
});
testWidgets('1600x1200 DynamicShape light theme',
(WidgetTester tester) async {
tester.binding.window.physicalSizeTestValue =
const Size(1600.0, 1200.0);
await tester.pumpWidget(
MaterialApp(theme: lightTheme(), home: dynamicShapeBuilder()));
await expectLater(find.byType(DynamicShape),
matchesGoldenFile('goldens/DynamicShape_golden_1600x1200_.png'));
});
testWidgets('400x600 DynamicShape dark theme',
(WidgetTester tester) async {
tester.binding.window.physicalSizeTestValue = const Size(400.0, 600.0);
await tester.pumpWidget(
MaterialApp(theme: darkTheme(), home: dynamicShapeBuilder()));
await expectLater(find.byType(DynamicShape),
matchesGoldenFile('goldens/DynamicShape_golden_400x600__dark.png'));
});
testWidgets('800x600 DynamicShape dark theme',
(WidgetTester tester) async {
tester.binding.window.physicalSizeTestValue = const Size(800.0, 600.0);
await tester.pumpWidget(
MaterialApp(theme: darkTheme(), home: dynamicShapeBuilder()));
await expectLater(find.byType(DynamicShape),
matchesGoldenFile('goldens/DynamicShape_golden_800x600__dark.png'));
});
testWidgets('800x1200 DynamicShape dark theme',
(WidgetTester tester) async {
tester.binding.window.physicalSizeTestValue = const Size(800.0, 1200.0);
await tester.pumpWidget(
MaterialApp(theme: darkTheme(), home: dynamicShapeBuilder()));
await expectLater(
find.byType(DynamicShape),
matchesGoldenFile(
'goldens/DynamicShape_golden_800x1200__dark.png'));
});
testWidgets('1600x1200 DynamicShape dark theme',
(WidgetTester tester) async {
tester.binding.window.physicalSizeTestValue =
const Size(1600.0, 1200.0);
await tester.pumpWidget(
MaterialApp(theme: darkTheme(), home: dynamicShapeBuilder()));
await expectLater(
find.byType(DynamicShape),
matchesGoldenFile(
'goldens/DynamicShape_golden_1600x1200__dark.png'));
});
});