Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions integration_test/smoke_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,20 @@ void main() {
/// Onboarding's Continue is dead until its controller accepts the answer, so
/// a walk that taps on the frame after choosing taps nothing at all — and
/// `tap` on a disabled button succeeds, which is the silent failure again.
Finder liveButton(String label) => find.byWidgetPredicate(
(widget) =>
widget is FilledButton &&
widget.onPressed != null &&
widget.child is Text &&
(widget.child! as Text).data == label,
description: 'an enabled "$label" button',
///
/// ⚠️ **The label is looked for anywhere under the button, never as its
/// direct child.** This read `child is Text` until the button grew an
/// optional trailing mark and wrapped its label in a `Row` — after which
/// every wait here timed out against a button that was on screen the whole
/// time, and the gate stayed red across five merges. What the walk needs is
/// *an enabled button that says this*; how the button lays its label out is
/// the button's business.
Finder liveButton(String label) => find.ancestor(
of: find.text(label),
matching: find.byWidgetPredicate(
(widget) => widget is FilledButton && widget.onPressed != null,
description: 'an enabled "$label" button',
),
);

/// Launches the app and skips the wake-up, leaving the caller on whatever
Expand Down
72 changes: 72 additions & 0 deletions test/widget/core/widgets/primary_button_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import 'package:brew_path/app/app_theme.dart';
import 'package:brew_path/core/icons/app_icon.dart';
import 'package:brew_path/core/widgets/primary_button.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

/// The contract the smoke walk depends on: **an enabled button can be found
/// by what it says.**
///
/// `integration_test/smoke_test.dart` drives onboarding by waiting for an
/// enabled button carrying a label. It used to find one by reading the
/// button's direct child as a `Text`; when the button grew an optional
/// trailing mark and wrapped its label in a `Row`, every wait timed out
/// against a button that was on screen, and main's smoke gate stayed red
/// across five merges.
///
/// **The smoke job only runs on main**, so no pull request could catch that.
/// This runs on every one. It asserts the relationship, not the layout: how
/// the button arranges its label is the button's business, and this is free to
/// keep passing while that changes.
void main() {
/// The button that says [label], enabled — the shape the smoke walk uses.
Finder liveButton(String label) => find.ancestor(
of: find.text(label),
matching: find.byWidgetPredicate(
(widget) => widget is FilledButton && widget.onPressed != null,
),
);

Future<void> pump(WidgetTester tester, Widget button) => tester.pumpWidget(
MaterialApp(
theme: AppTheme.cupping,
home: Scaffold(body: Center(child: button)),
),
);

testWidgets('an enabled button is found by its label', (tester) async {
await pump(
tester,
PrimaryButton(label: 'Start learning', onPressed: () {}),
);

expect(liveButton('Start learning'), findsOneWidget);
});

testWidgets('a label beside a trailing mark is still found', (tester) async {
// The case that broke it: the mark is what put a `Row` between the button
// and its words.
await pump(
tester,
PrimaryButton(
label: 'Turn it over',
onPressed: () {},
trailingMark: AppIcon.chevron,
),
);

expect(liveButton('Turn it over'), findsOneWidget);
});

testWidgets('a disabled button is not live', (tester) async {
// The distinction the walk exists to make: tapping a disabled button
// succeeds and does nothing, so waiting for one must not resolve.
await pump(
tester,
const PrimaryButton(label: 'Continue', onPressed: null),
);

expect(find.text('Continue'), findsOneWidget);
expect(liveButton('Continue'), findsNothing);
});
}
Loading