Some checks failed
CI / Windows build (push) Has been cancelled
A stylus pass through a committed stroke in eraser mode fires onEraseStroke for it; a pass far from any stroke erases nothing. Locks in the eraser path (the user reported eraser reliability issues) as a regression guard without a device. flutter analyze lib/editor clean; 237/237 tests (+2). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
102 lines
3.2 KiB
Dart
102 lines
3.2 KiB
Dart
// Device-independent widget test of the eraser path (the user reported eraser
|
|
// reliability issues). A stylus drag through a committed stroke in eraser mode
|
|
// must fire onEraseStroke for that stroke.
|
|
|
|
import 'package:flutter/gestures.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
import 'package:badnote/editor/canvas/pen_canvas.dart';
|
|
import 'package:badnote/editor/canvas/pen_stroke.dart';
|
|
|
|
void main() {
|
|
const pageSize = Size(400, 600);
|
|
|
|
// A horizontal stroke through the normalized center (0.5, 0.5).
|
|
PenStroke centerStroke() => PenStroke(
|
|
points: const [
|
|
PenPoint(0.4, 0.5, 0.5),
|
|
PenPoint(0.5, 0.5, 0.5),
|
|
PenPoint(0.6, 0.5, 0.5),
|
|
],
|
|
color: 0xFF000000,
|
|
width: 0.004,
|
|
kind: PenStrokeKind.pen,
|
|
);
|
|
|
|
Widget host({
|
|
required List<PenStroke> strokes,
|
|
required void Function(int, List<PenStroke>) onErase,
|
|
required TransformationController controller,
|
|
}) =>
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
body: Center(
|
|
child: SizedBox(
|
|
width: pageSize.width,
|
|
height: pageSize.height,
|
|
child: PenCanvas(
|
|
pageWidget: Container(color: const Color(0xFFEEEEEE)),
|
|
pageSize: pageSize,
|
|
strokes: strokes,
|
|
transformationController: controller,
|
|
tool: CanvasTool.eraser,
|
|
color: const Color(0xFF000000),
|
|
strokeWidth: 0.004,
|
|
onStrokeComplete: (_) {},
|
|
onEraseStroke: onErase,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
testWidgets('eraser tool: a stylus pass over a stroke fires onEraseStroke',
|
|
(tester) async {
|
|
final erased = <int>[];
|
|
final controller = TransformationController();
|
|
addTearDown(controller.dispose);
|
|
|
|
await tester.pumpWidget(host(
|
|
strokes: [centerStroke()],
|
|
onErase: (i, _) => erased.add(i),
|
|
controller: controller,
|
|
));
|
|
|
|
// Drag a stylus vertically through the screen center (= normalized 0.5,0.5,
|
|
// where the stroke sits).
|
|
final center = tester.getCenter(find.byType(PenCanvas));
|
|
final g = await tester.startGesture(center + const Offset(0, -20),
|
|
kind: PointerDeviceKind.stylus);
|
|
await g.moveBy(const Offset(0, 20));
|
|
await g.moveBy(const Offset(0, 20));
|
|
await g.up();
|
|
await tester.pump();
|
|
|
|
expect(erased, contains(0), reason: 'the center stroke should be erased');
|
|
});
|
|
|
|
testWidgets('eraser tool: a pass far from any stroke erases nothing',
|
|
(tester) async {
|
|
final erased = <int>[];
|
|
final controller = TransformationController();
|
|
addTearDown(controller.dispose);
|
|
|
|
await tester.pumpWidget(host(
|
|
strokes: [centerStroke()],
|
|
onErase: (i, _) => erased.add(i),
|
|
controller: controller,
|
|
));
|
|
|
|
// Drag in the top-left corner, far from the centered stroke.
|
|
final topLeft = tester.getTopLeft(find.byType(PenCanvas));
|
|
final g = await tester.startGesture(topLeft + const Offset(10, 10),
|
|
kind: PointerDeviceKind.stylus);
|
|
await g.moveBy(const Offset(5, 5));
|
|
await g.up();
|
|
await tester.pump();
|
|
|
|
expect(erased, isEmpty);
|
|
});
|
|
}
|