137 lines
4.9 KiB
Dart
137 lines
4.9 KiB
Dart
import 'dart:ui' as ui;
|
|
import 'package:flutter/gestures.dart' show kSecondaryMouseButton;
|
|
import 'dart:typed_data';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:image/image.dart' as img;
|
|
|
|
import 'package:pdf_signature/ui/features/pdf/widgets/pdf_screen.dart';
|
|
import 'package:pdf_signature/ui/features/pdf/view_model/view_model.dart';
|
|
import 'package:pdf_signature/data/services/export_providers.dart';
|
|
import 'package:pdf_signature/l10n/app_localizations.dart';
|
|
|
|
void main() {
|
|
// Open the active overlay context menu robustly (mouse right-click, fallback to long-press)
|
|
Future<void> _openActiveMenuAndConfirm(WidgetTester tester) async {
|
|
final overlay = find.byKey(const Key('signature_overlay'));
|
|
expect(overlay, findsOneWidget);
|
|
// Ensure visible before interacting
|
|
await tester.ensureVisible(overlay);
|
|
await tester.pumpAndSettle();
|
|
|
|
// Try right-click first
|
|
final center = tester.getCenter(overlay);
|
|
final TestGesture mouse = await tester.createGesture(
|
|
kind: ui.PointerDeviceKind.mouse,
|
|
buttons: kSecondaryMouseButton,
|
|
);
|
|
await mouse.addPointer(location: center);
|
|
addTearDown(mouse.removePointer);
|
|
await tester.pump();
|
|
await mouse.down(center);
|
|
await tester.pump(const Duration(milliseconds: 30));
|
|
await mouse.up();
|
|
await tester.pumpAndSettle();
|
|
|
|
// If menu didn't appear, try long-press
|
|
if (find.byKey(const Key('ctx_active_confirm')).evaluate().isEmpty) {
|
|
await tester.longPress(overlay, warnIfMissed: false);
|
|
await tester.pumpAndSettle();
|
|
}
|
|
await tester.tap(find.byKey(const Key('ctx_active_confirm')));
|
|
await tester.pumpAndSettle();
|
|
}
|
|
|
|
// Build a simple in-memory PNG as a signature image
|
|
Uint8List _makeSig() {
|
|
final canvas = img.Image(width: 80, height: 40);
|
|
img.fill(canvas, color: img.ColorUint8.rgb(255, 255, 255));
|
|
img.drawLine(
|
|
canvas,
|
|
x1: 6,
|
|
y1: 20,
|
|
x2: 74,
|
|
y2: 20,
|
|
color: img.ColorUint8.rgb(0, 0, 0),
|
|
);
|
|
return Uint8List.fromList(img.encodePng(canvas));
|
|
}
|
|
|
|
testWidgets('E2E: select, place default, and confirm signature', (
|
|
tester,
|
|
) async {
|
|
final sigBytes = _makeSig();
|
|
|
|
await tester.pumpWidget(
|
|
ProviderScope(
|
|
overrides: [
|
|
// Open a PDF
|
|
pdfProvider.overrideWith(
|
|
(ref) => PdfController()..openPicked(path: 'test.pdf'),
|
|
),
|
|
// Provide one signature asset in the library
|
|
signatureLibraryProvider.overrideWith((ref) {
|
|
final c = SignatureLibraryController();
|
|
c.add(sigBytes, name: 'image');
|
|
return c;
|
|
}),
|
|
// Use mock continuous viewer for deterministic layout in widget tests
|
|
useMockViewerProvider.overrideWithValue(true),
|
|
],
|
|
child: MaterialApp(
|
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
|
supportedLocales: AppLocalizations.supportedLocales,
|
|
home: const PdfSignatureHomePage(),
|
|
),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
|
|
// Tap the signature card to set it as active overlay
|
|
final card = find.byKey(const Key('gd_signature_card_area')).first;
|
|
expect(card, findsOneWidget);
|
|
await tester.tap(card);
|
|
await tester.pump();
|
|
|
|
// Active overlay should appear
|
|
final active = find.byKey(const Key('signature_overlay'));
|
|
expect(active, findsOneWidget);
|
|
final sizeBefore = tester.getSize(active);
|
|
|
|
// Bring the overlay into the viewport (it's near the bottom of the page by default)
|
|
final listFinder = find.byKey(const Key('pdf_continuous_mock_list'));
|
|
if (listFinder.evaluate().isNotEmpty) {
|
|
// Ensure the active overlay is fully visible within the scrollable viewport
|
|
await tester.ensureVisible(active);
|
|
await tester.pumpAndSettle();
|
|
}
|
|
|
|
// Open context menu and confirm using a robust flow
|
|
await _openActiveMenuAndConfirm(tester);
|
|
|
|
// Verify active overlay gone and placed overlay shown
|
|
expect(find.byKey(const Key('signature_overlay')), findsNothing);
|
|
final placed = find.byKey(const Key('placed_signature_0'));
|
|
expect(placed, findsOneWidget);
|
|
final sizeAfter = tester.getSize(placed);
|
|
|
|
// Compare sizes: should be roughly equal (allowing small layout variance)
|
|
expect(
|
|
(sizeAfter.width - sizeBefore.width).abs() < sizeBefore.width * 0.15,
|
|
isTrue,
|
|
);
|
|
expect(
|
|
(sizeAfter.height - sizeBefore.height).abs() < sizeBefore.height * 0.15,
|
|
isTrue,
|
|
);
|
|
|
|
// Verify provider state reflects one placement on current page
|
|
final ctx = tester.element(find.byType(PdfSignatureHomePage));
|
|
final container = ProviderScope.containerOf(ctx);
|
|
final pdf = container.read(pdfProvider);
|
|
final list = pdf.placementsByPage[pdf.currentPage] ?? const [];
|
|
expect(list.length, 1);
|
|
});
|
|
}
|