There is a tapOnText() method of the WidgetTester
class for taps (since maybe flutter 3.19?).
With that you can click on specific texts like this:
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('tapping part of a text', (tester) async {
// see my Example class below
await tester.pumpWidget(const MaterialApp(home: Example()));
await tester.tapOnText(find.textRange.ofSubstring('Tappable text'));
});
}
In the original example above, this pattern:
TextSpan(text: 'bbb', recognizer: TapGestureRecognizer()..onTap = () {})
...may cause a memory leak. The recognizer
property's docs say it does not dispose the provided gesture recognizer. So the right way is to use a StatefulWidget
instead where you create the gesture recognizer instance(s) once and then you call .dispose()
on them on the state's dispose()
method, like this:
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
class Example extends StatefulWidget {
const Example({super.key});
@override
State<Example> createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
late final TapGestureRecognizer _tapGestureRecognizer;
@override
void initState() {
super.initState();
_tapGestureRecognizer = TapGestureRecognizer()..onTap = _onTap;
}
@override
void dispose() {
_tapGestureRecognizer.dispose();
super.dispose();
}
void _onTap() {
// handle tap here
}
@override
Widget build(BuildContext context) {
return Text.rich(
TextSpan(
children: [
const TextSpan(text: 'Normal text '),
TextSpan(
text: 'Tappable text',
recognizer: _tapGestureRecognizer,
),
],
),
);
}
}