Skip to content

Commit

Permalink
Add unit tests for the Material widget (for clipping and elevation) (f…
Browse files Browse the repository at this point in the history
  • Loading branch information
amirh authored Jan 30, 2018
1 parent 3001b33 commit 178ad8a
Show file tree
Hide file tree
Showing 2 changed files with 303 additions and 0 deletions.
163 changes: 163 additions & 0 deletions packages/flutter/test/material/material_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -165,4 +165,167 @@ void main() {
final RenderPhysicalModel modelE = getShadow(tester);
expect(modelE.shadowColor, equals(const Color(0xFFFF0000)));
});

group('Transparency clipping', () {
testWidgets('clips to bounding rect by default', (WidgetTester tester) async {
final GlobalKey materialKey = new GlobalKey();
await tester.pumpWidget(
new Material(
key: materialKey,
type: MaterialType.transparency,
child: const SizedBox(width: 100.0, height: 100.0)
)
);

expect(find.byKey(materialKey), clipsWithBoundingRect);
});

testWidgets('clips to rounded rect when borderRadius provided', (WidgetTester tester) async {
final GlobalKey materialKey = new GlobalKey();
await tester.pumpWidget(
new Material(
key: materialKey,
type: MaterialType.transparency,
borderRadius: const BorderRadius.all(const Radius.circular(10.0)),
child: const SizedBox(width: 100.0, height: 100.0)
)
);

expect(
find.byKey(materialKey),
clipsWithBoundingRRect(
borderRadius: const BorderRadius.all(const Radius.circular(10.0))
),
);
});
});

group('PhysicalModels', () {
testWidgets('canvas', (WidgetTester tester) async {
final GlobalKey materialKey = new GlobalKey();
await tester.pumpWidget(
new Material(
key: materialKey,
type: MaterialType.canvas,
child: const SizedBox(width: 100.0, height: 100.0)
)
);

expect(find.byKey(materialKey), rendersOnPhysicalModel(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.zero,
elevation: 0.0,
));
});

testWidgets('canvas with borderRadius and elevation', (WidgetTester tester) async {
final GlobalKey materialKey = new GlobalKey();
await tester.pumpWidget(
new Material(
key: materialKey,
type: MaterialType.canvas,
borderRadius: const BorderRadius.all(const Radius.circular(5.0)),
child: const SizedBox(width: 100.0, height: 100.0),
elevation: 1.0,
)
);

expect(find.byKey(materialKey), rendersOnPhysicalModel(
shape: BoxShape.rectangle,
borderRadius: const BorderRadius.all(const Radius.circular(5.0)),
elevation: 1.0,
));
});

testWidgets('card', (WidgetTester tester) async {
final GlobalKey materialKey = new GlobalKey();
await tester.pumpWidget(
new Material(
key: materialKey,
type: MaterialType.card,
child: const SizedBox(width: 100.0, height: 100.0),
)
);

expect(find.byKey(materialKey), rendersOnPhysicalModel(
shape: BoxShape.rectangle,
borderRadius: const BorderRadius.all(const Radius.circular(2.0)),
elevation: 0.0,
));
});

testWidgets('card with borderRadius and elevation', (WidgetTester tester) async {
final GlobalKey materialKey = new GlobalKey();
await tester.pumpWidget(
new Material(
key: materialKey,
type: MaterialType.card,
borderRadius: const BorderRadius.all(const Radius.circular(5.0)),
elevation: 5.0,
child: const SizedBox(width: 100.0, height: 100.0),
)
);

expect(find.byKey(materialKey), rendersOnPhysicalModel(
shape: BoxShape.rectangle,
borderRadius: const BorderRadius.all(const Radius.circular(5.0)),
elevation: 5.0,
));
});

testWidgets('circle', (WidgetTester tester) async {
final GlobalKey materialKey = new GlobalKey();
await tester.pumpWidget(
new Material(
key: materialKey,
type: MaterialType.circle,
child: const SizedBox(width: 100.0, height: 100.0),
color: const Color(0xFF0000FF),
)
);

expect(find.byKey(materialKey), rendersOnPhysicalModel(
shape: BoxShape.circle,
elevation: 0.0,
));
});

testWidgets('button', (WidgetTester tester) async {
final GlobalKey materialKey = new GlobalKey();
await tester.pumpWidget(
new Material(
key: materialKey,
type: MaterialType.button,
child: const SizedBox(width: 100.0, height: 100.0),
color: const Color(0xFF0000FF),
)
);

expect(find.byKey(materialKey), rendersOnPhysicalModel(
shape: BoxShape.rectangle,
borderRadius: const BorderRadius.all(const Radius.circular(2.0)),
elevation: 0.0,
));
});

testWidgets('button with elevation and borderRadius', (WidgetTester tester) async {
final GlobalKey materialKey = new GlobalKey();
await tester.pumpWidget(
new Material(
key: materialKey,
type: MaterialType.button,
child: const SizedBox(width: 100.0, height: 100.0),
color: const Color(0xFF0000FF),
borderRadius: const BorderRadius.all(const Radius.circular(6.0)),
elevation: 4.0,
)
);

expect(find.byKey(materialKey), rendersOnPhysicalModel(
shape: BoxShape.rectangle,
borderRadius: const BorderRadius.all(const Radius.circular(6.0)),
elevation: 4.0,
));
});
});
}
140 changes: 140 additions & 0 deletions packages/flutter_test/lib/src/matchers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import 'dart:math' as math;

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:meta/meta.dart';
import 'package:test/test.dart';
Expand Down Expand Up @@ -780,3 +781,142 @@ class _IsMethodCall extends Matcher {
}
}

/// Asserts that a [Finder] locates a single object whose root RenderObject
/// is a [RenderClipRect] with no clipper set.
const Matcher clipsWithBoundingRect = const _ClipsWithBoundingRect();

/// Asserts that a [Finder] locates a single object whose root RenderObject
/// is a [RenderClipRRect] with no clipper set, and border radius equals to
/// [borderRadius].
Matcher clipsWithBoundingRRect({@required BorderRadius borderRadius}) {
return new _ClipsWithBoundingRRect(borderRadius: borderRadius);
}

/// Asserts that a [Finder] locates a single object whose root RenderObject
/// is a [RenderPhysicalModel].
///
/// - If [shape] is non null asserts that [RenderPhysicalModel.shape] is equal to
/// [shape].
/// - If [borderRadius] is non null asserts that [RenderPhysicalModel.borderRadius] is equal to
/// [borderRadius].
/// - If [elevation] is non null asserts that [RenderPhysicalModel.elevation] is equal to
/// [elevation].
Matcher rendersOnPhysicalModel({
BoxShape shape,
BorderRadius borderRadius,
double elevation,
}) {
return new _RendersOnPhysicalModel(
shape: shape,
borderRadius: borderRadius,
elevation: elevation,
);
}

abstract class _MatchRenderObject<T extends RenderObject> extends Matcher {
const _MatchRenderObject();

bool renderObjectMatches(Map<dynamic, dynamic> matchState, T renderObject);

@override
bool matches(covariant Finder finder, Map<dynamic, dynamic> matchState) {
final Iterable<Element> nodes = finder.evaluate();
if (nodes.length != 1)
return failWithDescription(matchState, 'did not have a exactly one child element');
final RenderObject renderObject = nodes.single.renderObject;
if (renderObject.runtimeType != T)
return failWithDescription(matchState, 'had a root render object of type: ${renderObject.runtimeType}');

return renderObjectMatches(matchState, renderObject);
}

bool failWithDescription(Map<dynamic, dynamic> matchState, String description) {
matchState['failure'] = description;
return false;
}

@override
Description describeMismatch(
dynamic item,
Description mismatchDescription,
Map<dynamic, dynamic> matchState,
bool verbose
) {
return mismatchDescription.add(matchState['failure']);
}
}

class _RendersOnPhysicalModel extends _MatchRenderObject<RenderPhysicalModel> {
const _RendersOnPhysicalModel({
this.shape,
this.borderRadius,
this.elevation,
});

final BoxShape shape;
final BorderRadius borderRadius;
final double elevation;

@override
bool renderObjectMatches(Map<dynamic, dynamic> matchState, RenderPhysicalModel renderObject) {
if (shape != null && renderObject.shape != shape)
return failWithDescription(matchState, 'had shape: ${renderObject.shape}');

if (borderRadius != null && renderObject.borderRadius != borderRadius)
return failWithDescription(matchState, 'had borderRadius: ${renderObject.borderRadius}');

if (elevation != null && renderObject.elevation != elevation)
return failWithDescription(matchState, 'had elevation: ${renderObject.elevation}');

return true;
}

@override
Description describe(Description description) {
description.add('renders on a physical model');
if (shape != null)
description.add(' with shape $shape');
if (borderRadius != null)
description.add(' with borderRadius $borderRadius');
if (elevation != null)
description.add(' with elevation $elevation');
return description;
}
}

class _ClipsWithBoundingRect extends _MatchRenderObject<RenderClipRect> {
const _ClipsWithBoundingRect();

@override
bool renderObjectMatches(Map<dynamic, dynamic> matchState, RenderClipRect renderObject) {
if (renderObject.clipper != null)
return failWithDescription(matchState, 'had a non null clipper ${renderObject.clipper}');
return true;
}

@override
Description describe(Description description) =>
description.add('clips with bounding rectangle');
}

class _ClipsWithBoundingRRect extends _MatchRenderObject<RenderClipRRect> {
const _ClipsWithBoundingRRect({@required this.borderRadius});

final BorderRadius borderRadius;


@override
bool renderObjectMatches(Map<dynamic, dynamic> matchState, RenderClipRRect renderObject) {
if (renderObject.clipper != null)
return failWithDescription(matchState, 'had a non null clipper ${renderObject.clipper}');

if (renderObject.borderRadius != borderRadius)
return failWithDescription(matchState, 'had borderRadius: ${renderObject.borderRadius}');

return true;
}

@override
Description describe(Description description) =>
description.add('clips with bounding rounded rectangle with borderRadius: $borderRadius');
}

0 comments on commit 178ad8a

Please sign in to comment.