diff --git a/lib/src/core/wiredash_controller.dart b/lib/src/core/wiredash_controller.dart index ed987d03..38a1e666 100644 --- a/lib/src/core/wiredash_controller.dart +++ b/lib/src/core/wiredash_controller.dart @@ -150,6 +150,7 @@ class WiredashController { bool? inheritCupertinoTheme, WiredashFeedbackOptions? options, }) async { + print(options != null); _captureAppTheme(inheritMaterialTheme, inheritCupertinoTheme); _captureSessionMetaData(); _model.feedbackOptionsOverride = options; @@ -173,6 +174,11 @@ class WiredashController { final result = FeedbackResult( hasSubmittedFeedback: hasSubmittedFeedback, ); + + // reset the metadata at the end of the feedback flow to avoid leaking metadata between feedbacks + _model.customizableMetaData = + _model.customizableMetaData.copyWith(custom: {}); + return result; } diff --git a/test/issues/issue_393_test.dart b/test/issues/issue_393_test.dart new file mode 100644 index 00000000..2577c550 --- /dev/null +++ b/test/issues/issue_393_test.dart @@ -0,0 +1,316 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:wiredash/src/feedback/feedback_model.dart'; +import 'package:wiredash/wiredash.dart'; + +import '../util/invocation_catcher.dart'; +import '../util/robot.dart'; + +void main() { + group('issue 393', () { + group('collectMetaData', () { + testWidgets( + 'metadata should be encapsulated per opened Wiredash Feedback and be merged with collectMetaData and modifyMetaData', + (tester) async { + final robot = WiredashTestRobot(tester); + + MapEntry customMetaData = const MapEntry('foo', 'bar'); + + await robot.launchApp( + collectMetaData: (metaData) { + return metaData + ..userEmail = "user@mail.com" + ..userId = "123" + ..custom['foz'] = 'baz'; + }, + builder: (context) { + return Scaffold( + body: Column( + children: [ + GestureDetector( + onTap: () async { + final wiredash = Wiredash.of(context); + + wiredash.modifyMetaData( + (metaData) { + return metaData + ..custom[customMetaData.key] = customMetaData.value; + }, + ); + wiredash.show(); + }, + child: const Text('Feedback'), + ), + ], + ), + ); + }, + ); + + await robot.submitMinimalFeedback(); + AssertableInvocation latestCall = + robot.mockServices.mockApi.sendFeedbackInvocations.latest; + final firstFeedback = latestCall[0] as FeedbackItem?; + + expect(firstFeedback!.metadata.userEmail, 'user@mail.com'); + expect(firstFeedback.metadata.userId, '123'); + expect(firstFeedback.metadata.custom!['foz'], 'baz'); + expect(firstFeedback.metadata.custom!['foo'], 'bar'); + + customMetaData = const MapEntry('bar', 'foo'); + + await robot.submitMinimalFeedback(); + latestCall = robot.mockServices.mockApi.sendFeedbackInvocations.latest; + final secondFeedback = latestCall[0] as FeedbackItem?; + expect(secondFeedback!.metadata.custom, hasLength(2)); + + expect(secondFeedback.metadata.userEmail, 'user@mail.com'); + expect(secondFeedback.metadata.userId, '123'); + expect(secondFeedback.metadata.custom!['foz'], 'baz'); + expect(secondFeedback.metadata.custom!['bar'], 'foo'); + }); + + testWidgets( + 'metadata should be encapsulated per opened Wiredash Feedback and be merged with collectMetaData', + (tester) async { + final robot = WiredashTestRobot(tester); + + MapEntry customMetaData = const MapEntry('foo', 'bar'); + + int collectMetaDataFunctionCalls = 0; + + await robot.launchApp( + collectMetaData: (metaData) { + return metaData + ..userEmail = "user@mail.com" + ..userId = "123" + ..custom['foz'] = 'baz'; + }, + builder: (context) { + return Scaffold( + body: Column( + children: [ + GestureDetector( + onTap: () async { + final wiredash = Wiredash.of(context); + wiredash.show( + options: WiredashFeedbackOptions( + collectMetaData: (metaData) { + collectMetaDataFunctionCalls++; + return metaData + ..custom[customMetaData.key] = + customMetaData.value; + }, + ), + ); + }, + child: const Text('Feedback'), + ), + ], + ), + ); + }, + ); + + await robot.submitMinimalFeedback(); + AssertableInvocation latestCall = + robot.mockServices.mockApi.sendFeedbackInvocations.latest; + final firstFeedback = latestCall[0] as FeedbackItem?; + + expect(collectMetaDataFunctionCalls, 1); // we fail here + + expect(firstFeedback!.metadata.userEmail, 'user@mail.com'); + expect(firstFeedback.metadata.userId, '123'); + expect(firstFeedback.metadata.custom!['foz'], 'baz'); + expect(firstFeedback.metadata.custom!['foo'], 'bar'); + + customMetaData = const MapEntry('bar', 'foo'); + + await robot.submitMinimalFeedback(); + latestCall = robot.mockServices.mockApi.sendFeedbackInvocations.latest; + final secondFeedback = latestCall[0] as FeedbackItem?; + + expect(secondFeedback!.metadata.custom, hasLength(2)); + expect(secondFeedback.metadata.userEmail, 'user@mail.com'); + expect(secondFeedback.metadata.userId, '123'); + expect(secondFeedback.metadata.custom!['foz'], 'baz'); + expect(secondFeedback.metadata.custom!['bar'], 'foo'); + }); + }); + group('WiredashFeedbackOptions.collectMetaData', () { + testWidgets(''' + metadata should be encapsulated per opened Wiredash Feedback + and be merged with WiredashFeedbackOptions.collectMetaData when calling modifyMetaData''', + (tester) async { + final robot = WiredashTestRobot(tester); + + MapEntry customMetaData = const MapEntry('foo', 'bar'); + + await robot.launchApp( + feedbackOptions: WiredashFeedbackOptions( + collectMetaData: (metaData) { + return metaData + ..userEmail = "user@mail.com" + ..userId = "123" + ..custom['foz'] = 'baz'; + }, + ), + builder: (context) { + return Scaffold( + body: Column( + children: [ + GestureDetector( + onTap: () async { + final wiredash = Wiredash.of(context); + wiredash.modifyMetaData( + (metaData) { + return metaData + ..custom[customMetaData.key] = customMetaData.value; + }, + ); + wiredash.show(); + }, + child: const Text('Feedback'), + ), + ], + ), + ); + }, + ); + + await robot.submitMinimalFeedback(); + AssertableInvocation latestCall = + robot.mockServices.mockApi.sendFeedbackInvocations.latest; + final firstFeedback = latestCall[0] as FeedbackItem?; + + expect(firstFeedback!.metadata.userEmail, 'user@mail.com'); + expect(firstFeedback.metadata.userId, '123'); + expect(firstFeedback.metadata.custom!['foz'], 'baz'); + expect(firstFeedback.metadata.custom!['foo'], 'bar'); + + customMetaData = const MapEntry('bar', 'foo'); + + await robot.submitMinimalFeedback(); + latestCall = robot.mockServices.mockApi.sendFeedbackInvocations.latest; + final secondFeedback = latestCall[0] as FeedbackItem?; + expect(secondFeedback!.metadata.custom, hasLength(2)); + expect(secondFeedback.metadata.userEmail, 'user@mail.com'); + expect(secondFeedback.metadata.userId, '123'); + expect(secondFeedback.metadata.custom!['foz'], 'baz'); + expect(secondFeedback.metadata.custom!['bar'], 'foo'); + }); + + testWidgets(''' + metadata should be encapsulated per opened Wiredash Feedback + and feedbackOptions of show should override WiredashFeedbackOptions.collectMetaData''', + (tester) async { + final robot = WiredashTestRobot(tester); + + MapEntry customMetaData = const MapEntry('foo', 'bar'); + + await robot.launchApp( + feedbackOptions: WiredashFeedbackOptions( + collectMetaData: (metaData) { + return metaData + ..userEmail = "user@mail.com" + ..userId = "123" + ..custom['foz'] = 'baz'; + }, + ), + builder: (context) { + return Scaffold( + body: Column( + children: [ + GestureDetector( + onTap: () async { + final wiredash = Wiredash.of(context); + wiredash.show( + options: WiredashFeedbackOptions( + collectMetaData: (metaData) { + return metaData + ..custom[customMetaData.key] = + customMetaData.value; + }, + ), + ); + }, + child: const Text('Feedback'), + ), + ], + ), + ); + }, + ); + + await robot.submitMinimalFeedback(); + AssertableInvocation latestCall = + robot.mockServices.mockApi.sendFeedbackInvocations.latest; + final firstFeedback = latestCall[0] as FeedbackItem?; + + expect(firstFeedback!.metadata.custom!['foo'], 'bar'); + + customMetaData = const MapEntry('bar', 'foo'); + + await robot.submitMinimalFeedback(); + latestCall = robot.mockServices.mockApi.sendFeedbackInvocations.latest; + final secondFeedback = latestCall[0] as FeedbackItem?; + expect(secondFeedback!.metadata.custom, hasLength(1)); + expect(secondFeedback.metadata.custom!['bar'], 'foo'); + }); + }); + + testWidgets( + 'metadata should be encapsulated per opened Wiredash Feedback and be merged with setUserData', + (tester) async { + final robot = WiredashTestRobot(tester); + + MapEntry customMetaData = const MapEntry('foo', 'bar'); + + await robot.launchApp( + builder: (context) { + return Scaffold( + body: Column( + children: [ + GestureDetector( + onTap: () async { + final wiredash = Wiredash.of(context); + wiredash.show(options: WiredashFeedbackOptions( + collectMetaData: (metaData) { + return metaData + ..custom[customMetaData.key] = customMetaData.value; + }, + )); + }, + child: const Text('Feedback'), + ), + ], + ), + ); + }, + ); + + robot.wiredashController.setUserProperties( + userEmail: "user@mail.com", + userId: "123", + ); + + await robot.submitMinimalFeedback(); + AssertableInvocation latestCall = + robot.mockServices.mockApi.sendFeedbackInvocations.latest; + final firstFeedback = latestCall[0] as FeedbackItem?; + expect(firstFeedback!.metadata.userEmail, 'user@mail.com'); + expect(firstFeedback.metadata.userId, '123'); + expect(firstFeedback.metadata.custom!['foo'], 'bar'); + + customMetaData = const MapEntry('bar', 'foo'); + + await robot.submitMinimalFeedback(); + latestCall = robot.mockServices.mockApi.sendFeedbackInvocations.latest; + final secondFeedback = latestCall[0] as FeedbackItem?; + expect(secondFeedback!.metadata.custom, hasLength(1)); + expect(secondFeedback.metadata.userEmail, 'user@mail.com'); + expect(secondFeedback.metadata.userId, '123'); + expect(secondFeedback.metadata.custom!['bar'], 'foo'); + }); + }); +}