diff --git a/lib/src/core/wiredash_model.dart b/lib/src/core/wiredash_model.dart index 56ef20e7..95d163f1 100644 --- a/lib/src/core/wiredash_model.dart +++ b/lib/src/core/wiredash_model.dart @@ -131,19 +131,23 @@ class WiredashModel with ChangeNotifier { Future hide({ bool discardFeedback = false, }) async { - await services.backdropController.animateToClosed(); - isWiredashActive = false; - - // reset options from show() call - themeFromContext = null; - feedbackOptionsOverride = null; - - if (discardFeedback) { - services.discardFeedback(); + try { + await services.backdropController.animateToClosed(); + + isWiredashActive = false; + // reset options from show() call + themeFromContext = null; + feedbackOptionsOverride = null; + } catch (e) { + // might fail when the user holds the app open while hide is called + } finally { + if (discardFeedback) { + services.discardFeedback(); + } + // always discard promoter score rating on close + services.discardPs(); + notifyListeners(); } - // always discard promoter score rating on close - services.discardPs(); - notifyListeners(); } /// Collects metadata from the user via [Wiredash.collectMetaData] or diff --git a/lib/src/feedback/feedback_backdrop.dart b/lib/src/feedback/feedback_backdrop.dart index 7d856550..bd3711f0 100644 --- a/lib/src/feedback/feedback_backdrop.dart +++ b/lib/src/feedback/feedback_backdrop.dart @@ -27,7 +27,7 @@ class FeedbackBackdrop extends StatelessWidget { contentBuilder: (context) { return WiredashFeedbackFlow( // this allows discarding feedback in the message step - key: ValueKey(context.feedbackModel), + key: ValueKey(context.watchFeedbackModel), ); }, foregroundLayerBuilder: (c, r, mq) { @@ -67,7 +67,7 @@ Widget? _buildForegroundLayer( return BackButtonAction.consumed; } - context.feedbackModel.cancelScreenshotCapturingMode(); + context.readFeedbackModel.cancelScreenshotCapturingMode(); return BackButtonAction.consumed; } return BackButtonAction.ignored; @@ -109,7 +109,7 @@ Widget? _buildForegroundLayer( ), offset: Offset( 0, - context.feedbackModel.feedbackFlowStatus == + context.watchFeedbackModel.feedbackFlowStatus == FeedbackFlowStatus.screenshotDrawing ? 0 : 1, @@ -178,7 +178,7 @@ Widget? _buildBackgroundLayer( ), offset: Offset( 0, - context.feedbackModel.feedbackFlowStatus == + context.watchFeedbackModel.feedbackFlowStatus == FeedbackFlowStatus.screenshotNavigating ? 0 : 4, diff --git a/lib/src/feedback/feedback_flow.dart b/lib/src/feedback/feedback_flow.dart index 197da024..f0b2f493 100644 --- a/lib/src/feedback/feedback_flow.dart +++ b/lib/src/feedback/feedback_flow.dart @@ -22,19 +22,18 @@ class _WiredashFeedbackFlowState extends State @override void initState() { super.initState(); - _index = - FeedbackModelProvider.of(context, listen: false).currentStepIndex ?? 0; + _index = context.readFeedbackModel.currentStepIndex ?? 0; } @override void didChangeDependencies() { super.didChangeDependencies(); - if (_index >= context.feedbackModel.steps.length) { - _index = context.feedbackModel.steps.length - 1; + if (_index >= context.watchFeedbackModel.steps.length) { + _index = context.watchFeedbackModel.steps.length - 1; } final oldIndex = _index; - final newIndex = context.feedbackModel.currentStepIndex; + final newIndex = context.watchFeedbackModel.currentStepIndex; if (newIndex == null) { // state not in stack, stay at current page return; @@ -52,31 +51,31 @@ class _WiredashFeedbackFlowState extends State @override Widget build(BuildContext context) { - final feedbackModel = context.feedbackModel; final larryPageView = LarryPageView( key: _lpvKey, - stepCount: feedbackModel.steps.length, + stepCount: context.watchFeedbackModel.steps.length, pageIndex: _index, onPageChanged: (index) { setState(() { _index = index; - final stepIndex = feedbackModel.currentStepIndex; + final stepIndex = context.readFeedbackModel.currentStepIndex; if (stepIndex == null) { return; } if (stepIndex < _index) { - feedbackModel.goToNextStep(); + context.readFeedbackModel.goToNextStep(); } if (stepIndex > _index) { - feedbackModel.goToPreviousStep(); + context.readFeedbackModel.goToPreviousStep(); } }); }, builder: (context) { final index = _index; final FeedbackFlowStatus status = () { + final feedbackModel = context.watchFeedbackModel; if (feedbackModel.steps.length <= index) { final stackIndex = feedbackModel.currentStepIndex; if (stackIndex == null) { @@ -125,11 +124,11 @@ class _WiredashFeedbackFlowState extends State if (_index == 0) { return BackButtonAction.ignored; } - feedbackModel.goToPreviousStep(); + context.readFeedbackModel.goToPreviousStep(); return BackButtonAction.consumed; }, child: Form( - key: feedbackModel.stepFormKey, + key: context.watchFeedbackModel.stepFormKey, child: larryPageView, ), ), @@ -154,7 +153,7 @@ class FeedbackProgressIndicator extends StatefulWidget { class _FeedbackProgressIndicatorState extends State { @override Widget build(BuildContext context) { - final feedbackModel = context.feedbackModel; + final feedbackModel = context.watchFeedbackModel; final stepIndex = feedbackModel.indexForFlowStatus(widget.flowStatus); var currentStep = stepIndex + 1; final total = feedbackModel.maxSteps; diff --git a/lib/src/feedback/feedback_model_provider.dart b/lib/src/feedback/feedback_model_provider.dart index 580e0caa..e2254e76 100644 --- a/lib/src/feedback/feedback_model_provider.dart +++ b/lib/src/feedback/feedback_model_provider.dart @@ -7,20 +7,12 @@ class FeedbackModelProvider extends InheritedNotifier { required FeedbackModel feedbackModel, required super.child, }) : super(notifier: feedbackModel); - - static FeedbackModel of(BuildContext context, {bool listen = true}) { - if (listen) { - return context - .dependOnInheritedWidgetOfExactType()! - .notifier!; - } else { - return context - .findAncestorWidgetOfExactType()! - .notifier!; - } - } } extension FeedbackModelExtension on BuildContext { - FeedbackModel get feedbackModel => FeedbackModelProvider.of(this); + FeedbackModel get watchFeedbackModel => + dependOnInheritedWidgetOfExactType()!.notifier!; + + FeedbackModel get readFeedbackModel => + findAncestorWidgetOfExactType()!.notifier!; } diff --git a/lib/src/feedback/steps/step_1_feedback_message.dart b/lib/src/feedback/steps/step_1_feedback_message.dart index cd18352a..9572da2f 100644 --- a/lib/src/feedback/steps/step_1_feedback_message.dart +++ b/lib/src/feedback/steps/step_1_feedback_message.dart @@ -18,11 +18,11 @@ class _Step1FeedbackMessageState extends State void initState() { super.initState(); _controller = TextEditingController( - text: FeedbackModelProvider.of(context, listen: false).feedbackMessage, + text: context.readFeedbackModel.feedbackMessage, )..addListener(() { final text = _controller.text; - if (context.feedbackModel.feedbackMessage != text) { - context.feedbackModel.feedbackMessage = text; + if (context.watchFeedbackModel.feedbackMessage != text) { + context.watchFeedbackModel.feedbackMessage = text; } }); } @@ -116,9 +116,9 @@ class _Step1FeedbackMessageState extends State child: TronButton( label: context.l10n.feedbackNextButton, trailingIcon: Wirecons.arrow_right, - onTap: context.feedbackModel.feedbackMessage == null - ? context.feedbackModel.validateForm - : context.feedbackModel.goToNextStep, + onTap: context.readFeedbackModel.feedbackMessage == null + ? context.readFeedbackModel.validateForm + : context.readFeedbackModel.goToNextStep, ), ), ], diff --git a/lib/src/feedback/steps/step_2_labels.dart b/lib/src/feedback/steps/step_2_labels.dart index 39bb2cad..0b853999 100644 --- a/lib/src/feedback/steps/step_2_labels.dart +++ b/lib/src/feedback/steps/step_2_labels.dart @@ -14,7 +14,7 @@ class _Step2LabelsState extends State with TickerProviderStateMixin { @override Widget build(BuildContext context) { - final feedbackModel = context.feedbackModel; + final feedbackModel = context.watchFeedbackModel; final selectedLabels = feedbackModel.selectedLabels; return StepPageScaffold( indicator: const FeedbackProgressIndicator( @@ -54,12 +54,12 @@ class _Step2LabelsState extends State color: context.theme.secondaryColor, leadingIcon: Wirecons.arrow_left, label: context.l10n.feedbackBackButton, - onTap: context.feedbackModel.goToPreviousStep, + onTap: context.readFeedbackModel.goToPreviousStep, ), TronButton( label: context.l10n.feedbackNextButton, trailingIcon: Wirecons.arrow_right, - onTap: context.feedbackModel.goToNextStep, + onTap: context.readFeedbackModel.goToNextStep, ), ], ), diff --git a/lib/src/feedback/steps/step_3_screenshot_overview.dart b/lib/src/feedback/steps/step_3_screenshot_overview.dart index 782d6ae6..c2d16f6a 100644 --- a/lib/src/feedback/steps/step_3_screenshot_overview.dart +++ b/lib/src/feedback/steps/step_3_screenshot_overview.dart @@ -22,7 +22,7 @@ class _Step3ScreenshotOverviewState extends State { WiredashBackdrop.maybeOf(context)?.animateSizeChange = true; }, child: () { - if (!context.feedbackModel.hasAttachments) { + if (!context.watchFeedbackModel.hasAttachments) { return const Step3NoAttachments(); } return const Step3WithGallery(); @@ -66,7 +66,7 @@ class _Step3NoAttachmentsState extends State { color: context.theme.secondaryColor, leadingIcon: Wirecons.arrow_left, label: context.l10n.feedbackBackButton, - onTap: context.feedbackModel.goToPreviousStep, + onTap: context.watchFeedbackModel.goToPreviousStep, ), const SizedBox(width: 10), Expanded( @@ -84,7 +84,7 @@ class _Step3NoAttachmentsState extends State { trailingIcon: Wirecons.chevron_double_right, onTap: () async { if (!mounted) return; - await context.feedbackModel.skipScreenshot(); + await context.readFeedbackModel.skipScreenshot(); }, ), TronButton( @@ -92,7 +92,7 @@ class _Step3NoAttachmentsState extends State { .feedbackStep3ScreenshotOverviewAddScreenshotButton, trailingIcon: Wirecons.arrow_right, maxWidth: 250, - onTap: () => context.feedbackModel + onTap: () => context.readFeedbackModel .enterScreenshotCapturingMode(), ), ], @@ -138,7 +138,8 @@ class Step3WithGallery extends StatelessWidget { child: Center( child: Row( children: [ - for (final att in context.feedbackModel.attachments) + for (final att + in context.watchFeedbackModel.attachments) ConstrainedBox( constraints: BoxConstraints( maxWidth: constraints.maxWidth / 2.5, @@ -148,7 +149,7 @@ class Step3WithGallery extends StatelessWidget { child: AttachmentPreview(attachment: att), ), ), - if (context.feedbackModel.attachments.length < 3) + if (context.watchFeedbackModel.attachments.length < 3) const NewAttachment(), ], ), @@ -163,12 +164,12 @@ class Step3WithGallery extends StatelessWidget { color: context.theme.secondaryColor, leadingIcon: Wirecons.arrow_left, label: context.l10n.feedbackBackButton, - onTap: context.feedbackModel.goToPreviousStep, + onTap: context.readFeedbackModel.goToPreviousStep, ), TronButton( label: context.l10n.feedbackNextButton, trailingIcon: Wirecons.arrow_right, - onTap: context.feedbackModel.goToNextStep, + onTap: context.readFeedbackModel.goToNextStep, ), ], ), @@ -213,7 +214,7 @@ class AttachmentPreview extends StatelessWidget { child: TronButton( color: context.theme.primaryContainerColor, onTap: () { - context.feedbackModel.deleteAttachment(attachment); + context.readFeedbackModel.deleteAttachment(attachment); }, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 4), @@ -239,7 +240,7 @@ class NewAttachment extends StatelessWidget { aspectRatio: context.theme.windowSize.aspectRatio, child: AnimatedClickTarget( onTap: () { - context.feedbackModel.enterScreenshotCapturingMode(); + context.readFeedbackModel.enterScreenshotCapturingMode(); }, builder: (context, state, anims) { Color hoverColorAdjustment(Color color) { diff --git a/lib/src/feedback/steps/step_5_email.dart b/lib/src/feedback/steps/step_5_email.dart index 82652517..3e664283 100644 --- a/lib/src/feedback/steps/step_5_email.dart +++ b/lib/src/feedback/steps/step_5_email.dart @@ -18,23 +18,22 @@ class _Step5EmailState extends State with TickerProviderStateMixin { @override void initState() { super.initState(); - final feedbackModel = FeedbackModelProvider.of(context, listen: false); _controller = TextEditingController( // read, not watch, because initState - text: feedbackModel.hasEmailBeenEdited - ? feedbackModel.userEmail + text: context.readFeedbackModel.hasEmailBeenEdited + ? context.readFeedbackModel.userEmail : WiredashModelProvider.of(context, listen: false) .customizableMetaData .userEmail, )..addListener(() { final text = _controller.text; - if (context.feedbackModel.userEmail != text) { - context.feedbackModel.userEmail = text; + if (context.readFeedbackModel.userEmail != text) { + context.readFeedbackModel.userEmail = text; } }); widgetsBindingInstance.addPostFrameCallback((_) { if (!mounted) return; - feedbackModel.userEmail = _controller.text; + context.readFeedbackModel.userEmail = _controller.text; }); } @@ -74,8 +73,8 @@ class _Step5EmailState extends State with TickerProviderStateMixin { cursorColor: context.theme.primaryColor, style: context.text.input.onSurface, onFieldSubmitted: (_) { - if (context.feedbackModel.validateForm()) { - context.feedbackModel.goToNextStep(); + if (context.readFeedbackModel.validateForm()) { + context.readFeedbackModel.goToNextStep(); } }, validator: (data) { @@ -115,14 +114,14 @@ class _Step5EmailState extends State with TickerProviderStateMixin { color: context.theme.secondaryColor, leadingIcon: Wirecons.arrow_left, label: context.l10n.feedbackBackButton, - onTap: context.feedbackModel.goToPreviousStep, + onTap: context.readFeedbackModel.goToPreviousStep, ), TronButton( label: context.l10n.feedbackNextButton, trailingIcon: Wirecons.arrow_right, onTap: () { try { - context.feedbackModel.goToNextStep(); + context.readFeedbackModel.goToNextStep(); } on FormValidationException { // validator triggered, TextFormField shows error } diff --git a/lib/src/feedback/steps/step_6_submit.dart b/lib/src/feedback/steps/step_6_submit.dart index c0fbd824..f0aff244 100644 --- a/lib/src/feedback/steps/step_6_submit.dart +++ b/lib/src/feedback/steps/step_6_submit.dart @@ -38,13 +38,13 @@ class _Step6SubmitState extends State { color: context.theme.secondaryColor, leadingIcon: Wirecons.arrow_left, label: context.l10n.feedbackBackButton, - onTap: context.feedbackModel.goToPreviousStep, + onTap: context.readFeedbackModel.goToPreviousStep, ), TronButton( label: context.l10n.feedbackStep6SubmitSubmitButton, leadingIcon: Wirecons.check, onTap: () { - context.feedbackModel.submitFeedback(); + context.readFeedbackModel.submitFeedback(); }, ), ], @@ -79,7 +79,7 @@ class _Step6SubmitState extends State { } Widget feedbackDetails() { - final model = context.feedbackModel; + final model = context.watchFeedbackModel; return Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), child: ListTileTheme( diff --git a/lib/src/feedback/steps/step_7_submitting.dart b/lib/src/feedback/steps/step_7_submitting.dart index b66ab1cc..09a3a742 100644 --- a/lib/src/feedback/steps/step_7_submitting.dart +++ b/lib/src/feedback/steps/step_7_submitting.dart @@ -18,12 +18,12 @@ class _Step7SubmittingAndErrorState extends State { alignment: Alignment.topCenter, duration: const Duration(milliseconds: 800), child: () { - final submitting = context.feedbackModel.submitting; + final submitting = context.watchFeedbackModel.submitting; if (submitting) { return const _Submitting(); } - final error = context.feedbackModel.submissionError; + final error = context.watchFeedbackModel.submissionError; if (error != null) { return _Error( error: error, @@ -149,7 +149,7 @@ class _Error extends StatelessWidget { child: TronButton( leadingIcon: Wirecons.refresh, onTap: () { - context.feedbackModel.submitFeedback(); + context.readFeedbackModel.submitFeedback(); }, child: Text(context.l10n.feedbackStep7SubmissionRetryButton), ), diff --git a/lib/src/feedback/ui/screenshot_bar.dart b/lib/src/feedback/ui/screenshot_bar.dart index 90cfeda1..9fcfe73b 100644 --- a/lib/src/feedback/ui/screenshot_bar.dart +++ b/lib/src/feedback/ui/screenshot_bar.dart @@ -10,7 +10,7 @@ class ScreenshotBar extends StatelessWidget { @override Widget build(BuildContext context) { - final feedbackStatus = context.feedbackModel.feedbackFlowStatus; + final feedbackStatus = context.watchFeedbackModel.feedbackFlowStatus; Widget? trailing; if (feedbackStatus == FeedbackFlowStatus.screenshotNavigating) { @@ -20,7 +20,7 @@ class ScreenshotBar extends StatelessWidget { leadingIcon: Wirecons.camera, iconOffset: const Offset(-.15, 0), label: context.l10n.feedbackStep3ScreenshotBarCaptureButton, - onTap: () => context.feedbackModel.captureScreenshot(), + onTap: () => context.readFeedbackModel.captureScreenshot(), ); } @@ -38,7 +38,7 @@ class ScreenshotBar extends StatelessWidget { : context.l10n.feedbackStep3ScreenshotBarOkButton, onTap: () { if (feedbackStatus == FeedbackFlowStatus.screenshotDrawing) { - return () => context.feedbackModel.createMasterpiece(); + return () => context.readFeedbackModel.createMasterpiece(); } if (feedbackStatus == FeedbackFlowStatus.screenshotSaving) { return () {/* show enabled while closing */}; @@ -61,7 +61,7 @@ class ScreenshotBar extends StatelessWidget { leadingIcon: Wirecons.arrow_left, color: context.theme.secondaryColor, onTap: () { - context.feedbackModel.cancelScreenshotCapturingMode(); + context.readFeedbackModel.cancelScreenshotCapturingMode(); }, ), if (constraints.maxWidth > 720) ...[ diff --git a/lib/src/promoterscore/ps_flow.dart b/lib/src/promoterscore/ps_flow.dart index ed8826b3..5a6daedc 100644 --- a/lib/src/promoterscore/ps_flow.dart +++ b/lib/src/promoterscore/ps_flow.dart @@ -16,25 +16,25 @@ class _PromoterScoreFlowState extends State { @override Widget build(BuildContext context) { - final psModel = context.psModel; final lpv = LarryPageView( key: _lpvKey, stepCount: () { - if (psModel.score == null) { + if (context.watchPsModel.score == null) { return 1; } - if (psModel.submitting) { + if (context.watchPsModel.submitting) { return 1; } return 2; }(), - pageIndex: psModel.index, + pageIndex: context.watchPsModel.index, onPageChanged: (index) { setState(() { - psModel.index = index; + context.readPsModel.index = index; }); }, builder: (context) { + final psModel = context.watchPsModel; if (psModel.submitting) { return const PsStep3Thanks(); } diff --git a/lib/src/promoterscore/ps_model_provider.dart b/lib/src/promoterscore/ps_model_provider.dart index 61e682f0..f79b0f47 100644 --- a/lib/src/promoterscore/ps_model_provider.dart +++ b/lib/src/promoterscore/ps_model_provider.dart @@ -7,20 +7,11 @@ class PsModelProvider extends InheritedNotifier { required PsModel psModel, required super.child, }) : super(notifier: psModel); - - static PsModel of(BuildContext context, {bool listen = true}) { - if (listen) { - return context - .dependOnInheritedWidgetOfExactType()! - .notifier!; - } else { - return context - .findAncestorWidgetOfExactType()! - .notifier!; - } - } } extension PsModelExtension on BuildContext { - PsModel get psModel => PsModelProvider.of(this); + PsModel get watchPsModel => + dependOnInheritedWidgetOfExactType()!.notifier!; + PsModel get readPsModel => + findAncestorWidgetOfExactType()!.notifier!; } diff --git a/lib/src/promoterscore/step_1_rating.dart b/lib/src/promoterscore/step_1_rating.dart index 6a755813..cd93c5f4 100644 --- a/lib/src/promoterscore/step_1_rating.dart +++ b/lib/src/promoterscore/step_1_rating.dart @@ -19,7 +19,7 @@ class _PsStep1RatingState extends State { @override Widget build(BuildContext context) { final question = context.l10n.promoterScoreStep1Question; - context.psModel.questionInUI = question; + context.readPsModel.questionInUI = question; return StepPageScaffold( title: Text(question), @@ -37,10 +37,10 @@ class _PsStep1RatingState extends State { Text(context.l10n.promoterScoreStep1Description), const SizedBox(height: 32), _PsRater( - score: context.psModel.score?.intValue, + score: context.watchPsModel.score?.intValue, onSelected: (score) async { final rating = score?.let((it) => createPsRating(it)); - context.psModel.score = rating; + context.watchPsModel.score = rating; if (rating != null) { final lpv = diff --git a/lib/src/promoterscore/step_2_message.dart b/lib/src/promoterscore/step_2_message.dart index b600913b..dc6fece3 100644 --- a/lib/src/promoterscore/step_2_message.dart +++ b/lib/src/promoterscore/step_2_message.dart @@ -19,12 +19,11 @@ class _PsStep2MessageState extends State @override void initState() { super.initState(); - _controller = TextEditingController( - text: PsModelProvider.of(context, listen: false).message, - )..addListener(() { + _controller = TextEditingController(text: context.readPsModel.message) + ..addListener(() { final text = _controller.text; - if (context.psModel.message != text) { - context.psModel.message = text; + if (context.readPsModel.message != text) { + context.readPsModel.message = text; } }); } @@ -46,7 +45,7 @@ class _PsStep2MessageState extends State title: Text(context.l10n.promoterScoreStep2MessageTitle), description: Text( context.l10n.promoterScoreStep2MessageDescription( - context.psModel.score!.intValue, + context.watchPsModel.score!.intValue, ), ), child: Column( @@ -104,7 +103,7 @@ class _PsStep2MessageState extends State label: context.l10n.promoterScoreSubmitButton, trailingIcon: Wirecons.check, onTap: () { - context.psModel.submit(); + context.readPsModel.submit(); }, ), ], diff --git a/lib/src/promoterscore/step_3_thanks.dart b/lib/src/promoterscore/step_3_thanks.dart index 70615023..b0aebf5d 100644 --- a/lib/src/promoterscore/step_3_thanks.dart +++ b/lib/src/promoterscore/step_3_thanks.dart @@ -25,7 +25,7 @@ class PsStep3Thanks extends StatelessWidget { ), Text( () { - final rating = context.psModel.score!; + final rating = context.watchPsModel.score!; switch (rating) { case PromoterScoreRating.rating0: case PromoterScoreRating.rating1: diff --git a/test/feedback_flow_test.dart b/test/feedback_flow_test.dart index aedb8278..6b1ed156 100644 --- a/test/feedback_flow_test.dart +++ b/test/feedback_flow_test.dart @@ -9,6 +9,7 @@ import 'package:wiredash/src/feedback/feedback_backdrop.dart'; import 'package:wiredash/wiredash.dart'; import 'util/robot.dart'; +import 'util/wiredash_tester.dart'; void main() { group('Feedback', () { @@ -484,6 +485,51 @@ void main() { await tester.pumpAndSettle(); spot().doesNotExist(); }); + + testWidgets('Hold app while submitting feedback resets form', + (tester) async { + // verifies issue https://github.com/wiredashio/wiredash-sdk/issues/310 + final robot = await WiredashTestRobot(tester).launchApp(); + + await robot.openWiredash(); + await robot.enterFeedbackMessage('test message'); + await robot.goToNextStep(); + await robot.skipScreenshot(); + await robot.skipEmail(); + + // touch and move the app a bit but don't lift the finger + final topRight = tester.getTopRight(find.byType(MaterialApp)); + final gesture = + await tester.startGesture(Offset(topRight.dx / 2, topRight.dy + 20)); + await tester.pump(const Duration(milliseconds: 10)); + await gesture.moveBy( + const Offset(0, 10), + timeStamp: const Duration(milliseconds: 10), + ); + await tester.pump(const Duration(milliseconds: 10)); + await gesture.moveBy( + const Offset(0, 10), + timeStamp: const Duration(milliseconds: 20), + ); + await tester.pump(const Duration(milliseconds: 10)); + + await robot.submitFeedback(); + + // wait for the success screen + await tester.waitUntil( + find.text('l10n.feedbackStep7SubmissionSuccessMessage'), + findsOneWidget, + ); + spotSingle().doesNotExist(); + + // wait for wiredash hide() after 1s delay + await tester.pumpAndSettle(const Duration(seconds: 1)); + + // back on first step, the form got reset + spotSingle().existsOnce(); + + await gesture.up(); // let go of the app + }); }); } diff --git a/test/promoterscore_flow_test.dart b/test/promoterscore_flow_test.dart index 57fe1604..4e872c2e 100644 --- a/test/promoterscore_flow_test.dart +++ b/test/promoterscore_flow_test.dart @@ -1,8 +1,9 @@ -import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:spot/spot.dart'; +import 'package:wiredash/src/_ps.dart'; import 'package:wiredash/src/_wiredash_internal.dart'; -import 'package:wiredash/src/promoterscore/ps_model.dart'; import 'util/robot.dart'; @@ -168,5 +169,42 @@ void main() { await robot.waitUntilWiredashIsClosed(); expect(caught.exception.toString(), contains('No internet')); }); + + testWidgets('Hold app while submitting ps resets form', (tester) async { + // verifies issue https://github.com/wiredashio/wiredash-sdk/issues/310 + final robot = await WiredashTestRobot(tester).launchApp(); + + await robot.openPromoterScore(); + await robot.ratePromoterScore(7); + + // touch and move the app a bit but don't lift the finger + final topRight = tester.getTopRight(find.byType(MaterialApp)); + final gesture = + await tester.startGesture(Offset(topRight.dx / 2, topRight.dy + 20)); + await tester.pump(const Duration(milliseconds: 10)); + await gesture.moveBy( + const Offset(0, 10), + timeStamp: const Duration(milliseconds: 10), + ); + await tester.pump(const Duration(milliseconds: 10)); + await gesture.moveBy( + const Offset(0, 10), + timeStamp: const Duration(milliseconds: 20), + ); + await tester.pump(const Duration(milliseconds: 10)); + + await robot.submitPromoterScore(); + await robot.showsPromoterScoreThanksMessage(); + + spotSingle().doesNotExist(); + + // wait for wiredash hide() after 2s delay + await tester.pumpAndSettle(const Duration(seconds: 3)); + + // back on first step, the form got reset + spotSingle().existsOnce(); + + await gesture.up(); // let go of the app + }); }); }