Files
BadNote/test/pen_zoom_widget_test.dart

97 lines
3.6 KiB
Dart
Raw Normal View History

// Behavioral test of the absolute-snapshot pinch fix (6829076) — device-
// independent (no pdfrx). Simulates a two-finger pinch over PenCanvas and
// samples the shared transform's scale each frame: a steady spread must grow
// the scale MONOTONICALLY, never spiking above the final value and snapping
// back (the reported flicker the fix removes).
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);
Widget host(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: const <PenStroke>[],
transformationController: controller,
tool: CanvasTool.pen,
color: const Color(0xFF000000),
strokeWidth: 0.004,
onStrokeComplete: (_) {},
onEraseStroke: (_, __) {},
),
),
),
),
);
testWidgets('a steady two-finger spread grows scale monotonically (no spike)',
(tester) async {
final controller = TransformationController();
addTearDown(controller.dispose);
await tester.pumpWidget(host(controller));
final center = tester.getCenter(find.byType(PenCanvas));
final f1 = await tester.startGesture(
center + const Offset(-20, 0), kind: PointerDeviceKind.touch);
final f2 = await tester.startGesture(
center + const Offset(20, 0), kind: PointerDeviceKind.touch);
final scales = <double>[];
for (var i = 0; i < 8; i++) {
// Spread the fingers apart symmetrically (pure zoom-in, focal steady).
await f1.moveBy(const Offset(-8, 0));
await f2.moveBy(const Offset(8, 0));
await tester.pump();
scales.add(controller.value.getMaxScaleOnAxis());
}
await f1.up();
await f2.up();
await tester.pump();
final maxScale = scales.reduce((a, b) => a > b ? a : b);
final finalScale = scales.last;
// Zoom actually happened.
expect(finalScale, greaterThan(1.0));
// No frame spiked ABOVE the final scale and snapped back — the fix's
// invariant. (Allow a tiny epsilon for fp.)
expect(maxScale, lessThanOrEqualTo(finalScale + 1e-6),
reason: 'a frame popped bigger than the final scale — flicker');
// Monotonic non-decreasing across the steady spread.
for (var i = 1; i < scales.length; i++) {
expect(scales[i], greaterThanOrEqualTo(scales[i - 1] - 1e-6),
reason: 'scale went backwards at frame $i: $scales');
}
});
testWidgets('the stylus never pans/zooms (excluded from the recognizer)',
(tester) async {
final controller = TransformationController();
addTearDown(controller.dispose);
await tester.pumpWidget(host(controller));
final center = tester.getCenter(find.byType(PenCanvas));
// A single stylus drag must DRAW, not pan — the transform stays identity.
final g = await tester.startGesture(center, kind: PointerDeviceKind.stylus);
await g.moveBy(const Offset(40, 40));
await g.up();
await tester.pump();
expect(controller.value.getMaxScaleOnAxis(), closeTo(1.0, 1e-9));
expect(controller.value.getTranslation().x, closeTo(0, 1e-6));
expect(controller.value.getTranslation().y, closeTo(0, 1e-6));
});
}