blob: f45afb6539ff15c7caa40310046bcc17f5c2977c [file] [log] [blame]
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
const Key key = Key('testContainer');
const Color trueColor = Colors.red;
const Color falseColor = Colors.green;
/// Mock widget which plays the role of a button -- it can emit notifications
/// that [MaterialState] values are now in or out of play.
class _InnerWidget extends StatefulWidget {
const _InnerWidget({required this.onValueChanged, required this.controller});
final ValueChanged<bool> onValueChanged;
final StreamController<bool> controller;
@override
_InnerWidgetState createState() => _InnerWidgetState();
}
class _InnerWidgetState extends State<_InnerWidget> {
@override
void initState() {
super.initState();
widget.controller.stream.listen((bool val) => widget.onValueChanged(val));
}
@override
Widget build(BuildContext context) => Container();
}
class _MyWidget extends StatefulWidget {
const _MyWidget({
required this.controller,
required this.evaluator,
required this.materialState,
});
/// Wrapper around `MaterialStateMixin.isPressed/isHovered/isFocused/etc`.
final bool Function(_MyWidgetState state) evaluator;
/// Stream passed down to the child [_InnerWidget] to begin the process.
/// This plays the role of an actual user interaction in the wild, but allows
/// us to engage the system without mocking pointers/hovers etc.
final StreamController<bool> controller;
/// The value we're watching in the given test.
final MaterialState materialState;
@override
State createState() => _MyWidgetState();
}
class _MyWidgetState extends State<_MyWidget> with MaterialStateMixin {
@override
Widget build(BuildContext context) {
return ColoredBox(
key: key,
color: widget.evaluator(this) ? trueColor : falseColor,
child: _InnerWidget(
onValueChanged: updateMaterialState(widget.materialState),
controller: widget.controller,
),
);
}
}
void main() {
Future<void> verify(WidgetTester tester, Widget widget, StreamController<bool> controller,) async {
await tester.pumpWidget(MaterialApp(home: Scaffold(body: widget)));
// Set the value to True
controller.sink.add(true);
await tester.pumpAndSettle();
expect(tester.widget<ColoredBox>(find.byKey(key)).color, trueColor);
// Set the value to False
controller.sink.add(false);
await tester.pumpAndSettle();
expect(tester.widget<ColoredBox>(find.byKey(key)).color, falseColor);
}
testWidgetsWithLeakTracking('MaterialState.pressed is tracked', (WidgetTester tester) async {
final StreamController<bool> controller = StreamController<bool>();
final _MyWidget widget = _MyWidget(
controller: controller,
evaluator: (_MyWidgetState state) => state.isPressed,
materialState: MaterialState.pressed,
);
await verify(tester, widget, controller);
});
testWidgetsWithLeakTracking('MaterialState.focused is tracked', (WidgetTester tester) async {
final StreamController<bool> controller = StreamController<bool>();
final _MyWidget widget = _MyWidget(
controller: controller,
evaluator: (_MyWidgetState state) => state.isFocused,
materialState: MaterialState.focused,
);
await verify(tester, widget, controller);
});
testWidgetsWithLeakTracking('MaterialState.hovered is tracked', (WidgetTester tester) async {
final StreamController<bool> controller = StreamController<bool>();
final _MyWidget widget = _MyWidget(
controller: controller,
evaluator: (_MyWidgetState state) => state.isHovered,
materialState: MaterialState.hovered,
);
await verify(tester, widget, controller);
});
testWidgetsWithLeakTracking('MaterialState.disabled is tracked', (WidgetTester tester) async {
final StreamController<bool> controller = StreamController<bool>();
final _MyWidget widget = _MyWidget(
controller: controller,
evaluator: (_MyWidgetState state) => state.isDisabled,
materialState: MaterialState.disabled,
);
await verify(tester, widget, controller);
});
testWidgetsWithLeakTracking('MaterialState.selected is tracked', (WidgetTester tester) async {
final StreamController<bool> controller = StreamController<bool>();
final _MyWidget widget = _MyWidget(
controller: controller,
evaluator: (_MyWidgetState state) => state.isSelected,
materialState: MaterialState.selected,
);
await verify(tester, widget, controller);
});
testWidgetsWithLeakTracking('MaterialState.scrolledUnder is tracked', (WidgetTester tester) async {
final StreamController<bool> controller = StreamController<bool>();
final _MyWidget widget = _MyWidget(
controller: controller,
evaluator: (_MyWidgetState state) => state.isScrolledUnder,
materialState: MaterialState.scrolledUnder,
);
await verify(tester, widget, controller);
});
testWidgetsWithLeakTracking('MaterialState.dragged is tracked', (WidgetTester tester) async {
final StreamController<bool> controller = StreamController<bool>();
final _MyWidget widget = _MyWidget(
controller: controller,
evaluator: (_MyWidgetState state) => state.isDragged,
materialState: MaterialState.dragged,
);
await verify(tester, widget, controller);
});
testWidgetsWithLeakTracking('MaterialState.error is tracked', (WidgetTester tester) async {
final StreamController<bool> controller = StreamController<bool>();
final _MyWidget widget = _MyWidget(
controller: controller,
evaluator: (_MyWidgetState state) => state.isErrored,
materialState: MaterialState.error,
);
await verify(tester, widget, controller);
});
}