Initial commit: Krow Worker App
This commit is contained in:
195
test/widgets_test.dart
Normal file
195
test/widgets_test.dart
Normal file
@@ -0,0 +1,195 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:krow_worker_app/core/theme.dart';
|
||||
import 'package:krow_worker_app/widgets/common.dart';
|
||||
import 'package:krow_worker_app/widgets/glass_segments.dart';
|
||||
import 'package:krow_worker_app/widgets/krow_nav_bar.dart';
|
||||
|
||||
Widget wrap(Widget child) => MaterialApp(
|
||||
theme: buildKrowTheme(),
|
||||
home: Scaffold(body: child),
|
||||
);
|
||||
|
||||
void main() {
|
||||
group('KrowNavBar', () {
|
||||
const items = [
|
||||
KrowNavItem(icon: Icons.home, label: 'Today'),
|
||||
KrowNavItem(icon: Icons.work, label: 'Shifts'),
|
||||
KrowNavItem(icon: Icons.timer, label: 'Clock', showDot: true),
|
||||
];
|
||||
|
||||
testWidgets('renders every label', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
wrap(KrowNavBar(items: items, currentIndex: 0, onSelect: (_) {})),
|
||||
);
|
||||
|
||||
expect(find.text('Today'), findsOneWidget);
|
||||
expect(find.text('Shifts'), findsOneWidget);
|
||||
expect(find.text('Clock'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('reports the tapped index', (tester) async {
|
||||
var selected = -1;
|
||||
await tester.pumpWidget(
|
||||
wrap(
|
||||
KrowNavBar(
|
||||
items: items,
|
||||
currentIndex: 0,
|
||||
onSelect: (i) => selected = i,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.text('Clock'));
|
||||
expect(selected, 2);
|
||||
});
|
||||
|
||||
testWidgets('announces a tab that needs attention', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
wrap(KrowNavBar(items: items, currentIndex: 0, onSelect: (_) {})),
|
||||
);
|
||||
|
||||
// The dot is not readable, so the state has to reach the semantics tree.
|
||||
expect(find.bySemanticsLabel('Clock, needs attention'), findsOneWidget);
|
||||
expect(find.bySemanticsLabel('Today'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('the indicator travels rather than jumping', (tester) async {
|
||||
var index = 0;
|
||||
await tester.pumpWidget(
|
||||
wrap(
|
||||
StatefulBuilder(
|
||||
builder: (context, setState) => KrowNavBar(
|
||||
items: items,
|
||||
currentIndex: index,
|
||||
onSelect: (i) => setState(() => index = i),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Rect pillRect() => tester.getRect(find.byKey(KrowNavBar.indicatorKey));
|
||||
|
||||
final start = pillRect().center.dx;
|
||||
await tester.tap(find.text('Clock'));
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(milliseconds: 120));
|
||||
|
||||
// Part way through it should be between the two tabs, not already there.
|
||||
final middle = pillRect().center.dx;
|
||||
expect(middle, greaterThan(start));
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
final end = pillRect().center.dx;
|
||||
expect(end, greaterThan(middle));
|
||||
});
|
||||
});
|
||||
|
||||
group('StatSlabRow', () {
|
||||
// Every real use sits in a scrolling column, where the height is
|
||||
// unbounded. Testing it against a bounded Scaffold body hides exactly the
|
||||
// layout errors this row is prone to.
|
||||
Widget inScrollable(Widget child) =>
|
||||
wrap(ListView(children: [const SizedBox(height: 8), child]));
|
||||
|
||||
testWidgets('lays out inside a scrollable', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
inScrollable(
|
||||
const StatSlabRow(
|
||||
slabs: [
|
||||
StatSlab('Clock in', '6:01 PM'),
|
||||
StatSlab('Clock out', '11:50 PM'),
|
||||
StatSlab('Hours', '5h 19m'),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(tester.takeException(), isNull);
|
||||
// A row that tried to fill unbounded height would be enormous.
|
||||
expect(tester.getSize(find.byType(StatSlabRow)).height, lessThan(120));
|
||||
});
|
||||
|
||||
testWidgets('keeps every card the same height, however long the text', (
|
||||
tester,
|
||||
) async {
|
||||
await tester.pumpWidget(
|
||||
inScrollable(
|
||||
const StatSlabRow(
|
||||
slabs: [
|
||||
// The middle one is what used to wrap on both lines and push
|
||||
// its card taller than the two beside it.
|
||||
StatSlab('Clock in', '6:01 PM'),
|
||||
StatSlab('Clock out', '11:50 PM'),
|
||||
StatSlab('Hours', '5h 19m'),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final heights = tester
|
||||
.widgetList<StatSlab>(find.byType(StatSlab))
|
||||
.map((slab) => tester.getSize(find.byWidget(slab)).height)
|
||||
.toSet();
|
||||
|
||||
expect(heights.length, 1, reason: 'cards should be one height');
|
||||
});
|
||||
|
||||
testWidgets('scales long values down instead of wrapping', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
inScrollable(
|
||||
const StatSlabRow(
|
||||
slabs: [
|
||||
StatSlab('Paid', r'$1,234.56'),
|
||||
StatSlab('Rate', r'$21.00/hr'),
|
||||
StatSlab('Hours', '5h 19m'),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
for (final text in tester.widgetList<Text>(find.byType(Text))) {
|
||||
expect(text.maxLines, 1);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
group('GlassSegments', () {
|
||||
testWidgets('reports the tapped segment', (tester) async {
|
||||
String? picked;
|
||||
await tester.pumpWidget(
|
||||
wrap(
|
||||
GlassSegments<String>(
|
||||
segments: const [('a', 'Week'), ('b', 'Month'), ('c', 'Year')],
|
||||
value: 'a',
|
||||
onChanged: (v) => picked = v,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.text('Year'));
|
||||
expect(picked, 'c');
|
||||
});
|
||||
|
||||
testWidgets('ignores a tap on the segment already selected', (
|
||||
tester,
|
||||
) async {
|
||||
var calls = 0;
|
||||
await tester.pumpWidget(
|
||||
wrap(
|
||||
GlassSegments<String>(
|
||||
segments: const [('a', 'Week'), ('b', 'Month')],
|
||||
value: 'a',
|
||||
onChanged: (_) => calls++,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.text('Week'));
|
||||
expect(calls, 0);
|
||||
|
||||
await tester.tap(find.text('Month'));
|
||||
expect(calls, 1);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user