Skip to content

Commit

Permalink
Adds DeviceBuilder class to generate single golden file for all Devic…
Browse files Browse the repository at this point in the history
…es/Scenarios

DeviceBuilder will create a single widget to lay out multiple scenarios vertically
and multiple devices for those scenarios horizontally. This single widget can then
be used to create one golden png file.

Updates workspace setting to include lineLength that is enforced by pr pipelines
  • Loading branch information
allicaDan authored and moonytoes29 committed Oct 27, 2020
1 parent c1028fd commit 869496e
Show file tree
Hide file tree
Showing 15 changed files with 742 additions and 15 deletions.
95 changes: 86 additions & 9 deletions packages/golden_toolkit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,23 @@ It is highly recommended to look at sample tests here: [golden_builder_test.dart

## Table of Contents

- [Key Features](#Key-Features)
- [GoldenBuilder](#goldenbuilder)
- [multiScreenGolden](#multiscreengolden)
- [Getting Started](#Getting-Started)
- [Setup](#Setup)
- [Loading Fonts](#Loading-Fonts)
- [testGoldens()](#testGoldens)
- [Pumping Widgets](#Pumping-Widgets)
- [Configuration](#Configuration)
- [Golden Toolkit](#golden-toolkit)
- [Table of Contents](#table-of-contents)
- [Key Features](#key-features)
- [GoldenBuilder](#goldenbuilder)
- [DeviceBuilder](#devicebuilder)
- [multiScreenGolden](#multiscreengolden)
- [Getting Started](#getting-started)
- [Setup](#setup)
- [Add the failures folder to .gitignore](#add-the-failures-folder-to-gitignore)
- [Configure VS Code](#configure-vs-code)
- [Loading Fonts](#loading-fonts)
- [Caveats](#caveats)
- [testGoldens()](#testgoldens)
- [Pumping Widgets](#pumping-widgets)
- [Configuration](#configuration)
- [License Information](#license-information)
- [3rd Party Software Included or Modified in Project](#3rd-party-software-included-or-modified-in-project)

## Key Features

Expand Down Expand Up @@ -66,6 +74,75 @@ The output of this test will be this golden file: `weather_accessibility.png`:

See tests for usage examples: [golden_builder_test.dart](example/test/golden_builder_test.dart)


### DeviceBuilder

DeviceBuilder class is like the GoldenBuilder except that it constrains scenario widget sizes to Device configurations. This removes the need
to specify a column or grid based layout.

It will generate a widget that lays out its scenarios vertically and the Device configurations of those scenarios horizontally. All in one single
golden png file.

In the case of a single scenario the helper method of (#multiDeviceGolden) can simplify DeviceBuilder usage. For multiple scenarios, DeviceBuilder
can help

```dart
testGoldens('DeviceBuilder - multiple scenarios - with onCreate',
(tester) async {
final builder = DeviceBuilder()
..overrideDevicesForAllScenarios(devices: [
Device.phone,
Device.iphone11,
Device.tabletPortrait,
Device.tabletLandscape,
])
..addScenario(
widget: FlutterDemoPage(),
name: 'default page',
)
..addScenario(
widget: FlutterDemoPage(),
name: 'tap once',
onCreate: (scenarioWidgetKey) async {
final finder = find.descendant(
of: find.byKey(scenarioWidgetKey),
matching: find.byIcon(Icons.add),
);
expect(finder, findsOneWidget);
await tester.tap(finder);
},
)
..addScenario(
widget: FlutterDemoPage(),
name: 'tap five times',
onCreate: (scenarioWidgetKey) async {
final finder = find.descendant(
of: find.byKey(scenarioWidgetKey),
matching: find.byIcon(Icons.add),
);
expect(finder, findsOneWidget);
await tester.tap(finder);
await tester.tap(finder);
await tester.tap(finder);
await tester.tap(finder);
await tester.tap(finder);
},
);
await tester.pumpDeviceBuilder(builder);
await screenMatchesGolden(tester, 'flutter_demo_page_multiple_scenarios');
});
```

This will generate the following golden:

`flutter_demo_page_multiple_scenarios.png`

![example widget captured](example/test/goldens/flutter_demo_page_multiple_scenarios.png)


### multiScreenGolden

The multiScreenGolden assertion is used to capture multiple goldens of a single widget using different simulated device sizes & characteristics.
Expand Down
1 change: 1 addition & 0 deletions packages/golden_toolkit/example/lib/example.dart
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export 'src/flutter_demo_page.dart';
export 'src/weather_widgets.dart';
63 changes: 63 additions & 0 deletions packages/golden_toolkit/example/lib/src/flutter_demo_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import 'package:flutter/material.dart';

/// Counter page from flutters default generated app
class FlutterDemoPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: const _MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}

class _MyHomePage extends StatefulWidget {
const _MyHomePage({Key key, this.title}) : super(key: key);

final String title;

@override
_MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<_MyHomePage> {
int _counter = 0;

void _incrementCounter() {
setState(() {
_counter++;
});
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
/// license that can be found in the LICENSE file or at
/// https://opensource.org/licenses/BSD-3-Clause
/// ***************************************************
// ignore_for_file: public_member_api_docs

import 'dart:ui';
Expand Down
85 changes: 85 additions & 0 deletions packages/golden_toolkit/example/test/flutter_demo_page_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:golden_toolkit/golden_toolkit.dart';

// ignore: avoid_relative_lib_imports
import '../lib/src/flutter_demo_page.dart';

void main() {
testGoldens('DeviceBuilder - one scenario - default devices', (tester) async {
final builder = DeviceBuilder()
..addScenario(
widget: FlutterDemoPage(),
name: 'default page',
);

await tester.pumpDeviceBuilder(builder);

await screenMatchesGolden(tester, 'flutter_demo_page_single_scenario');
});

testGoldens('DeviceBuilder - one scenario - override devices', (tester) async {
final builder = DeviceBuilder()
..overrideDevicesForAllScenarios(devices: [
Device.phone,
Device.iphone11,
Device.tabletPortrait,
Device.tabletLandscape,
])
..addScenario(
widget: FlutterDemoPage(),
name: 'default page',
);

await tester.pumpDeviceBuilder(builder);

await screenMatchesGolden(tester, 'flutter_demo_page_single_scenario_more_devices');
});

testGoldens('DeviceBuilder - multiple scenarios - with onCreate', (tester) async {
final builder = DeviceBuilder()
..overrideDevicesForAllScenarios(devices: [
Device.phone,
Device.iphone11,
Device.tabletPortrait,
Device.tabletLandscape,
])
..addScenario(
widget: FlutterDemoPage(),
name: 'default page',
)
..addScenario(
widget: FlutterDemoPage(),
name: 'tap once',
onCreate: (scenarioWidgetKey) async {
final finder = find.descendant(
of: find.byKey(scenarioWidgetKey),
matching: find.byIcon(Icons.add),
);
expect(finder, findsOneWidget);
await tester.tap(finder);
},
)
..addScenario(
widget: FlutterDemoPage(),
name: 'tap five times',
onCreate: (scenarioWidgetKey) async {
final finder = find.descendant(
of: find.byKey(scenarioWidgetKey),
matching: find.byIcon(Icons.add),
);
expect(finder, findsOneWidget);

await tester.tap(finder);
await tester.tap(finder);
await tester.tap(finder);
await tester.tap(finder);
await tester.tap(finder);
},
);

await tester.pumpDeviceBuilder(builder);

await screenMatchesGolden(tester, 'flutter_demo_page_multiple_scenarios');
});
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion packages/golden_toolkit/golden_toolkit.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"editor.tabSize": 2,
"editor.insertSpaces": false,
"editor.formatOnSave": true,
"editor.wordWrapColumn": 120
"editor.wordWrapColumn": 120,
"dart.lineLength": 120
}
}
1 change: 1 addition & 0 deletions packages/golden_toolkit/lib/golden_toolkit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ library golden_toolkit;

export 'src/configuration.dart';
export 'src/device.dart';
export 'src/device_builder.dart';
export 'src/font_loader.dart' show loadAppFonts;
export 'src/golden_builder.dart';
export 'src/multi_screen_golden.dart';
Expand Down
Loading

0 comments on commit 869496e

Please sign in to comment.