Skip to content

Commit

Permalink
feat: Add helper function for creating golden tests (#1623)
Browse files Browse the repository at this point in the history
  • Loading branch information
st-pasha authored May 15, 2022
1 parent 843ddc3 commit d0faaad
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 20 deletions.
6 changes: 6 additions & 0 deletions melos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,9 @@ scripts:
select-package:
dir-exists: test
description: Generate coverage for the selected package.

update-goldens:
run: melos exec -- flutter test --update-goldens
select-package:
dir-exists: test
description: Re-generate all golden test files
13 changes: 3 additions & 10 deletions packages/flame/test/experimental/fixed_size_viewport_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import 'dart:ui';

import 'package:flame/components.dart';
import 'package:flame/experimental.dart';
import 'package:flame/game.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart';

Expand Down Expand Up @@ -46,9 +45,9 @@ void main() {
expect(viewport.containsLocalPoint(Vector2(300, 100)), true);
});

FlameTester(FlameGame.new).testGameWidget(
testGolden(
'Clipping behavior',
setUp: (game, tester) async {
(game) async {
final world = World();
final camera = CameraComponent(
world: world,
Expand All @@ -74,14 +73,8 @@ void main() {
)
]);
game.addAll([world, camera]);
await game.ready();
},
verify: (game, tester) async {
await expectLater(
find.byGame<FlameGame>(),
matchesGoldenFile('../_goldens/fixed_size_viewport_test_1.png'),
);
},
goldenFile: '../_goldens/fixed_size_viewport_test_1.png',
);
});
}
13 changes: 3 additions & 10 deletions packages/flame/test/sprite_test.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'dart:ui';

import 'package:flame/components.dart';
import 'package:flame/game.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
Expand All @@ -10,18 +9,12 @@ import '_resources/load_image.dart';

void main() {
group('Sprite', () {
FlameTester(FlameGame.new).testGameWidget(
testGolden(
'Render with anchor',
setUp: (game, tester) async {
(game) async {
game.add(MyComponent()..position = Vector2.all(25));
await game.ready();
},
verify: (game, tester) async {
await expectLater(
find.byGame<FlameGame>(),
matchesGoldenFile('_goldens/sprite_test_1.png'),
);
},
goldenFile: '_goldens/sprite_test_1.png',
);
});
}
Expand Down
1 change: 1 addition & 0 deletions packages/flame_test/lib/flame_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export 'src/mock_gesture_events.dart';
export 'src/mock_image.dart';
export 'src/random_test.dart';
export 'src/test_flame_game.dart';
export 'src/test_golden.dart' show testGolden;
51 changes: 51 additions & 0 deletions packages/flame_test/lib/src/test_golden.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import 'package:flame/game.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:meta/meta.dart';

/// Test that a game renders correctly.
///
/// The way golden tests work is as follows: you set up a scene in [testBody],
/// then the test framework renders your game widget into an image, and compares
/// that image against stored [goldenFile]. The test passes if two images are
/// identical, or fails if the images differ even in a single pixel.
///
/// The term _golden file_ refers to the true rendering of a given game scene,
/// captured at the creation of the test. In order to create a golden file, you
/// first specify its desired name in the [goldenFile] parameter, and then run
/// the tests using the command
/// ```
/// flutter test --update-goldens
/// ```
///
/// The [testBody] is given a `game` parameter (which is by default a new
/// [FlameGame] instance, but you can also supply your own [game] object), and
/// is expected to set up a scene for rendering. Usually this involves adding
/// necessary game components, and possibly advancing the game clock. As a
/// convenience, we will run `await game.ready()` before rendering, to ensure
/// that all components that might be pending are properly mounted.
@isTest
void testGolden(
String testName,
PrepareGameFunction testBody, {
required String goldenFile,
FlameGame? game,
}) {
testWidgets(testName, (tester) async {
final gameInstance = game ?? FlameGame();

await tester.runAsync(() async {
await tester.pumpWidget(GameWidget(game: gameInstance));
await tester.pump();
await testBody(gameInstance);
await gameInstance.ready();
await tester.pump();
});

await expectLater(
find.byWidgetPredicate((widget) => widget is GameWidget),
matchesGoldenFile(goldenFile),
);
});
}

typedef PrepareGameFunction = Future<void> Function(FlameGame game);
11 changes: 11 additions & 0 deletions packages/flame_test/test/golden_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,16 @@ void main() {
);
},
);

testGolden(
'Same test but with testGolden',
(game) async {
final paint = Paint()..color = Colors.white;
game.add(
CircleComponent(radius: 10, position: Vector2.all(100), paint: paint),
);
},
goldenFile: 'golden_test.png',
);
});
}

0 comments on commit d0faaad

Please sign in to comment.