diff --git a/.github/workflows/flutter-ci.yml b/.github/workflows/flutter-ci.yml index 52eb6b55..41e23a0e 100644 --- a/.github/workflows/flutter-ci.yml +++ b/.github/workflows/flutter-ci.yml @@ -58,6 +58,35 @@ jobs: - name: Check for any formatting issues run: dart format --set-exit-if-changed . + goldens: + runs-on: ubuntu-22.04 + steps: + + - uses: actions/checkout@v2 + - uses: subosito/flutter-action@v2 + with: + channel: 'stable' + flutter-version: '3.10.x' + + - name: Install apt dependencies + run: | + sudo apt update + sudo apt -y install clang cmake curl libgtk-3-dev ninja-build pkg-config unzip xvfb + sudo apt -y install fonts-noto-cjk fonts-ubuntu fonts-tibetan-machine + + - name: Get pub dependencies + run: flutter pub get + + - name: Run golden tests + run: xvfb-run -a -s '-screen 0 1280x800x24 +extension GLX' flutter test integration_test/golden_test.dart -d linux + working-directory: example/ + + - uses: actions/upload-artifact@v3 + if: failure() + with: + name: failures + path: example/integration_test/failures + pub: runs-on: ubuntu-20.04 steps: diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..274a0f24 --- /dev/null +++ b/Makefile @@ -0,0 +1,3 @@ +.PHONY: goldens +goldens: + cd example && GDK_BACKEND=x11 GDK_SCALE=1 flutter test integration_test/golden_test.dart -d linux --update-goldens diff --git a/example/integration_test/golden_test.dart b/example/integration_test/golden_test.dart new file mode 100644 index 00000000..0804ad9f --- /dev/null +++ b/example/integration_test/golden_test.dart @@ -0,0 +1,158 @@ +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; +import 'package:path/path.dart' as path; +import 'package:yaru/yaru.dart'; +import 'package:yaru_example/main.dart' as app; +import 'package:yaru_example/main.dart'; +import 'package:yaru_example/view/home_page.dart'; + +// NOTE: run `make goldens` to update golden images + +const _kGoldenDiffTolerance = 0.005; + +Future main() async { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + goldenFileComparator = GoldenDiffComparator( + path.join( + path.fromUri((goldenFileComparator as LocalFileComparator).basedir), + 'yaru.dart', + ), + tolerance: _kGoldenDiffTolerance, + ); + + testWidgets('fonts', (tester) async { + tester.runApp(); + await tester.pumpAndSettle(); + await tester.takeScreenshots('fonts'); + }); + + testWidgets('buttons', (tester) async { + tester.runApp(); + await tester.pumpAndSettle(); + await tester.tap(find.text('Controls')); + await tester.pump(); + await tester.takeScreenshots('buttons'); + }); + + testWidgets('checks', (tester) async { + tester.runApp(); + await tester.pumpAndSettle(); + await tester.tap(find.text('Controls')); + await tester.pump(); + await tester.tap(find.text('Checks')); + await tester.pump(); + await tester.takeScreenshots('checks'); + }); + + testWidgets('switches', (tester) async { + tester.runApp(); + await tester.pumpAndSettle(); + await tester.tap(find.text('Controls')); + await tester.pump(); + await tester.tap(find.text('Switches')); + await tester.pump(); + await tester.takeScreenshots('switches'); + }); + + testWidgets('text fields', (tester) async { + tester.runApp(); + await tester.pumpAndSettle(); + await tester.tap(find.text('Text Fields')); + await tester.pump(); + primaryFocus?.unfocus(); + await tester.pump(); + await tester.takeScreenshots('text-fields'); + }); + + testWidgets('containers', (tester) async { + tester.runApp(); + await tester.pumpAndSettle(); + await tester.tap(find.text('Containers')); + await tester.pump(); + await tester.takeScreenshots('containers'); + }); +} + +extension on WidgetTester { + void runApp() { + view.devicePixelRatio = 1; + view.physicalSize = const Size(600, 700); + app.main(); + } + + void selectTheme({ + YaruVariant? variant, + bool? highContrast, + ThemeMode? themeMode, + }) async { + final context = element(find.byType(HomePage)); + AppTheme.apply( + context, + variant: variant, + highContrast: highContrast, + themeMode: themeMode, + ); + } + + Future takeScreenshots(String screen) async { + for (final themeMode in [ThemeMode.light, ThemeMode.dark]) { + selectTheme( + variant: YaruVariant.orange, + themeMode: themeMode, + highContrast: false, + ); + await pumpAndSettle(); + await takeScreenshot(screen); + + selectTheme(themeMode: themeMode, highContrast: true); + await pumpAndSettle(); + await takeScreenshot(screen); + } + } + + Future takeScreenshot(String screen) async { + final context = element(find.byType(HomePage)); + final theme = AppTheme.of(context); + final suffix = [ + if (theme.highContrast == true) 'high-contrast' else theme.variant?.name, + theme.themeMode?.name, + ].join('-'); + + await expectLater( + find.byType(MaterialApp), + matchesGoldenFile('goldens/$screen-$suffix.png'), + ); + } +} + +class GoldenDiffComparator extends LocalFileComparator { + GoldenDiffComparator( + String testFile, { + required this.tolerance, + }) : super(Uri.parse(testFile)); + + final double tolerance; + + @override + Future compare(Uint8List imageBytes, Uri golden) async { + final ComparisonResult result = await GoldenFileComparator.compareLists( + imageBytes, + await getGoldenBytes(golden), + ); + + if (!result.passed && result.diffPercent > tolerance) { + final error = await generateFailureOutput(result, golden, basedir); + throw FlutterError(error); + } + if (!result.passed) { + debugPrint( + 'A tolerable difference of ${result.diffPercent * 100}% was found when comparing $golden.', + ); + } + return result.passed || result.diffPercent <= tolerance; + } +} diff --git a/example/integration_test/goldens/buttons-high-contrast-dark.png b/example/integration_test/goldens/buttons-high-contrast-dark.png new file mode 100644 index 00000000..422eb488 Binary files /dev/null and b/example/integration_test/goldens/buttons-high-contrast-dark.png differ diff --git a/example/integration_test/goldens/buttons-high-contrast-light.png b/example/integration_test/goldens/buttons-high-contrast-light.png new file mode 100644 index 00000000..f159f038 Binary files /dev/null and b/example/integration_test/goldens/buttons-high-contrast-light.png differ diff --git a/example/integration_test/goldens/buttons-orange-dark.png b/example/integration_test/goldens/buttons-orange-dark.png new file mode 100644 index 00000000..3d856f38 Binary files /dev/null and b/example/integration_test/goldens/buttons-orange-dark.png differ diff --git a/example/integration_test/goldens/buttons-orange-light.png b/example/integration_test/goldens/buttons-orange-light.png new file mode 100644 index 00000000..c53d7387 Binary files /dev/null and b/example/integration_test/goldens/buttons-orange-light.png differ diff --git a/example/integration_test/goldens/checks-high-contrast-dark.png b/example/integration_test/goldens/checks-high-contrast-dark.png new file mode 100644 index 00000000..73b64d77 Binary files /dev/null and b/example/integration_test/goldens/checks-high-contrast-dark.png differ diff --git a/example/integration_test/goldens/checks-high-contrast-light.png b/example/integration_test/goldens/checks-high-contrast-light.png new file mode 100644 index 00000000..993aa7df Binary files /dev/null and b/example/integration_test/goldens/checks-high-contrast-light.png differ diff --git a/example/integration_test/goldens/checks-orange-dark.png b/example/integration_test/goldens/checks-orange-dark.png new file mode 100644 index 00000000..c71b5a68 Binary files /dev/null and b/example/integration_test/goldens/checks-orange-dark.png differ diff --git a/example/integration_test/goldens/checks-orange-light.png b/example/integration_test/goldens/checks-orange-light.png new file mode 100644 index 00000000..8c35f0f4 Binary files /dev/null and b/example/integration_test/goldens/checks-orange-light.png differ diff --git a/example/integration_test/goldens/containers-high-contrast-dark.png b/example/integration_test/goldens/containers-high-contrast-dark.png new file mode 100644 index 00000000..b27358ca Binary files /dev/null and b/example/integration_test/goldens/containers-high-contrast-dark.png differ diff --git a/example/integration_test/goldens/containers-high-contrast-light.png b/example/integration_test/goldens/containers-high-contrast-light.png new file mode 100644 index 00000000..7e7007c0 Binary files /dev/null and b/example/integration_test/goldens/containers-high-contrast-light.png differ diff --git a/example/integration_test/goldens/containers-orange-dark.png b/example/integration_test/goldens/containers-orange-dark.png new file mode 100644 index 00000000..ceb903ad Binary files /dev/null and b/example/integration_test/goldens/containers-orange-dark.png differ diff --git a/example/integration_test/goldens/containers-orange-light.png b/example/integration_test/goldens/containers-orange-light.png new file mode 100644 index 00000000..c46c1323 Binary files /dev/null and b/example/integration_test/goldens/containers-orange-light.png differ diff --git a/example/integration_test/goldens/fonts-high-contrast-dark.png b/example/integration_test/goldens/fonts-high-contrast-dark.png new file mode 100644 index 00000000..4994d638 Binary files /dev/null and b/example/integration_test/goldens/fonts-high-contrast-dark.png differ diff --git a/example/integration_test/goldens/fonts-high-contrast-light.png b/example/integration_test/goldens/fonts-high-contrast-light.png new file mode 100644 index 00000000..51f2c57f Binary files /dev/null and b/example/integration_test/goldens/fonts-high-contrast-light.png differ diff --git a/example/integration_test/goldens/fonts-orange-dark.png b/example/integration_test/goldens/fonts-orange-dark.png new file mode 100644 index 00000000..f729a6fc Binary files /dev/null and b/example/integration_test/goldens/fonts-orange-dark.png differ diff --git a/example/integration_test/goldens/fonts-orange-light.png b/example/integration_test/goldens/fonts-orange-light.png new file mode 100644 index 00000000..30029df2 Binary files /dev/null and b/example/integration_test/goldens/fonts-orange-light.png differ diff --git a/example/integration_test/goldens/switches-high-contrast-dark.png b/example/integration_test/goldens/switches-high-contrast-dark.png new file mode 100644 index 00000000..f340960f Binary files /dev/null and b/example/integration_test/goldens/switches-high-contrast-dark.png differ diff --git a/example/integration_test/goldens/switches-high-contrast-light.png b/example/integration_test/goldens/switches-high-contrast-light.png new file mode 100644 index 00000000..f06b082c Binary files /dev/null and b/example/integration_test/goldens/switches-high-contrast-light.png differ diff --git a/example/integration_test/goldens/switches-orange-dark.png b/example/integration_test/goldens/switches-orange-dark.png new file mode 100644 index 00000000..0723c3de Binary files /dev/null and b/example/integration_test/goldens/switches-orange-dark.png differ diff --git a/example/integration_test/goldens/switches-orange-light.png b/example/integration_test/goldens/switches-orange-light.png new file mode 100644 index 00000000..cba91f64 Binary files /dev/null and b/example/integration_test/goldens/switches-orange-light.png differ diff --git a/example/integration_test/goldens/text-fields-high-contrast-dark.png b/example/integration_test/goldens/text-fields-high-contrast-dark.png new file mode 100644 index 00000000..9d53c061 Binary files /dev/null and b/example/integration_test/goldens/text-fields-high-contrast-dark.png differ diff --git a/example/integration_test/goldens/text-fields-high-contrast-light.png b/example/integration_test/goldens/text-fields-high-contrast-light.png new file mode 100644 index 00000000..5c7492ac Binary files /dev/null and b/example/integration_test/goldens/text-fields-high-contrast-light.png differ diff --git a/example/integration_test/goldens/text-fields-orange-dark.png b/example/integration_test/goldens/text-fields-orange-dark.png new file mode 100644 index 00000000..1559b9f5 Binary files /dev/null and b/example/integration_test/goldens/text-fields-orange-dark.png differ diff --git a/example/integration_test/goldens/text-fields-orange-light.png b/example/integration_test/goldens/text-fields-orange-light.png new file mode 100644 index 00000000..1796114c Binary files /dev/null and b/example/integration_test/goldens/text-fields-orange-light.png differ diff --git a/example/pubspec.yaml b/example/pubspec.yaml index a8bfbd64..4e5ef718 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -18,6 +18,9 @@ dev_dependencies: flutter_lints: ^2.0.1 flutter_test: sdk: flutter + integration_test: + sdk: flutter + path: ^1.8.3 flutter: uses-material-design: true