diff --git a/.circleci/config.yml b/.circleci/config.yml index 52f57ccc4..0d5343223 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -237,7 +237,7 @@ jobs: - setup_flutter - android/start-emulator-and-run-tests: run-tests-working-directory: e2e - additional-avd-args: --device 3 + additional-avd-args: --device 25 system-image: system-images;android-33;default;x86_64 post-emulator-launch-assemble-command: cd packages/instabug_flutter/example && flutter build apk --debug test-command: dotnet test diff --git a/e2e/BugReportingTests.cs b/e2e/BugReportingTests.cs index 640016254..f48afbf3b 100644 --- a/e2e/BugReportingTests.cs +++ b/e2e/BugReportingTests.cs @@ -1,9 +1,9 @@ -using System.Drawing; using E2E.Utils; using Xunit; using Instabug.Captain; using NoSuchElementException = OpenQA.Selenium.NoSuchElementException; +using System.Drawing; namespace E2E; @@ -46,6 +46,9 @@ public void ReportABug() [Fact] public void FloatingButtonInvocationEvent() { + + Console.WriteLine("FloatingButtonInvocationEvent"); + captain.FindById( android: "instabug_floating_button", ios: "IBGFloatingButtonAccessibilityIdentifier" @@ -57,11 +60,13 @@ public void FloatingButtonInvocationEvent() [Fact] public void ShakeInvocationEvent() { + + Console.WriteLine("ShakeInvocationEvent"); + if (!Platform.IsIOS) return; - ScrollUp(); - captain.FindByText("Shake").Tap(); + captain.FindByTextScroll("Shake").Tap(); captain.Shake(); @@ -71,10 +76,12 @@ public void ShakeInvocationEvent() [Fact] public void TwoFingersSwipeLeftInvocationEvent() { - if (!Platform.IsIOS){ - ScrollUp(); - } - captain.FindByText("Two Fingers Swipe Left").Tap(); + + Console.WriteLine("TwoFingersSwipeLeftInvocationEvent"); + + + + captain.FindByTextScroll("Two Fingers Swipe Left").Tap(); Thread.Sleep(500); @@ -93,7 +100,11 @@ public void TwoFingersSwipeLeftInvocationEvent() [Fact] public void NoneInvocationEvent() { - captain.FindByText("None").Tap(); + + Console.WriteLine("NoneInvocationEvent"); + + + captain.FindByTextScroll("None").Tap(); captain.WaitForAssertion(() => Assert.Throws(() => @@ -109,7 +120,13 @@ public void NoneInvocationEvent() [Fact] public void ManualInvocation() { - captain.FindByText("Invoke").Tap(); + + + Console.WriteLine("ManualInvocation"); + + + + captain.FindByTextScroll("Invoke").Tap(); AssertOptionsPromptIsDisplayed(); } @@ -117,14 +134,24 @@ public void ManualInvocation() [Fact] public void MultipleScreenshotsInReproSteps() { - Dispose(); - ScrollDownLittle(); - captain.FindByText("Enter screen name").Tap(); + + + Console.WriteLine("MultipleScreenshotsInReproSteps"); + + + + +captain.FindByTextScroll("Enter screen name").Tap(); captain.Type("My Screen"); captain.HideKeyboard(); - captain.FindByText("Report Screen Change").Tap(); - captain.FindByText("Send Bug Report").Tap(); + captain.HideKeyboard(); + Thread.Sleep(500); + + captain.FindByTextScroll("Report Screen Change")?.Tap(); + Thread.Sleep(500); + captain.FindByTextScroll("Send Bug Report")?.Tap(); + captain.FindById( android: "instabug_text_view_repro_steps_disclaimer", ios: "IBGBugVCReproStepsDisclaimerAccessibilityIdentifier" @@ -140,27 +167,30 @@ public void MultipleScreenshotsInReproSteps() [Fact(Skip = "The test is flaky on iOS so we're skipping it to unblock the v13.2.0 release")] public void ChangeReportTypes() { - ScrollUp(); - captain.FindByText("Bug", exact: true).Tap(); + + Console.WriteLine("ChangeReportTypes"); + + + captain.FindByTextScroll("Bug", exact: true).Tap(); if (Platform.IsAndroid) { - captain.FindByText("Invoke").Tap(); + captain.FindByTextScroll("Invoke").Tap(); // Shows bug reporting screen Assert.True(captain.FindById("ib_bug_scroll_view").Displayed); // Close bug reporting screen captain.GoBack(); - captain.FindByText("DISCARD").Tap(); + captain.FindByTextScroll("DISCARD").Tap(); Thread.Sleep(500); } - captain.FindByText("Feedback").Tap(); + captain.FindByTextScroll("Feedback").Tap(); - captain.FindByText("Invoke").Tap(); + captain.FindByTextScroll("Invoke").Tap(); // Shows both bug reporting and feature requests in prompt options AssertOptionsPromptIsDisplayed(); @@ -173,10 +203,12 @@ public void ChangeReportTypes() [Fact] public void ChangeFloatingButtonEdge() { - ScrollDown(); - captain.FindByText("Move Floating Button to Left").Tap(); - Thread.Sleep(500); + Console.WriteLine("ChangeFloatingButtonEdge"); + + + captain.FindByTextScroll("Move Floating Button to Left",false,false)?.Tap(); + captain.WaitForAssertion(() => { @@ -193,16 +225,16 @@ public void ChangeFloatingButtonEdge() [Fact] public void OnDismissCallbackIsCalled() { - ScrollDownLittle(); - captain.FindByText("Set On Dismiss Callback").Tap(); - captain.FindByText("Invoke").Tap(); + captain.FindByTextScroll("Set On Dismiss Callback",false,false).Tap(); + captain.FindByTextScroll("Invoke",false,false).Tap(); AssertOptionsPromptIsDisplayed(); - captain.FindByText("Cancel").Tap(); + captain.FindByTextScroll("Cancel").Tap(); var popUpText = captain.FindByText("onDismiss callback called with DismissType.cancel and ReportType.other"); Assert.True(popUpText.Displayed); + } } diff --git a/e2e/FeatureRequestsTests.cs b/e2e/FeatureRequestsTests.cs index 41c97f684..724758bee 100644 --- a/e2e/FeatureRequestsTests.cs +++ b/e2e/FeatureRequestsTests.cs @@ -10,10 +10,10 @@ public class FeatureRequestsTests : CaptainTest [Fact] public void ShowFeatureRequetsScreen() { - ScrollDown(); - ScrollDown(); - captain.FindByText("Show Feature Requests").Tap(); + Console.WriteLine("ShowFeatureRequetsScreen"); + + captain.FindByTextScroll("Show Feature Requests",false,false).Tap(); var screenTitle = captain.FindById( android: "ib_fr_toolbar_main", diff --git a/e2e/InstabugTests.cs b/e2e/InstabugTests.cs index 839c0f78b..e376f87bf 100644 --- a/e2e/InstabugTests.cs +++ b/e2e/InstabugTests.cs @@ -11,21 +11,16 @@ public class InstabugTests : CaptainTest [Fact] public void ChangePrimaryColor() { - ScrollUp(); - ScrollUp(); -ScrollUp(); - ScrollUp(); -ScrollUp(); - ScrollUp(); + Console.WriteLine("ChangePrimaryColor"); var color = "#FF0000"; var expected = Color.FromArgb(255, 0, 0); - captain.FindByText("Enter primary color").Tap(); + captain.FindByTextScroll("Enter primary color").Tap(); captain.Type(color); captain.HideKeyboard(); - captain.FindByText("Change Primary Color").Tap(); + captain.FindByTextScroll("Change Primary Color").Tap(); captain.WaitForAssertion(() => { diff --git a/e2e/SurveysTests.cs b/e2e/SurveysTests.cs index 1ed0eba48..0d67f99ab 100644 --- a/e2e/SurveysTests.cs +++ b/e2e/SurveysTests.cs @@ -10,8 +10,9 @@ public class SurveysTests : CaptainTest [Fact] public void ShowManualSurvey() { - ScrollDownLittle(); - captain.FindByText("Show Manual Survey").Tap(); + Console.WriteLine("ShowManualSurvey"); + + captain.FindByTextScroll("Show Manual Survey",false,false).Tap(); captain.WaitForAssertion(() => { diff --git a/e2e/Utils/CaptainTest.cs b/e2e/Utils/CaptainTest.cs index 533bd6ca1..e32255d4b 100644 --- a/e2e/Utils/CaptainTest.cs +++ b/e2e/Utils/CaptainTest.cs @@ -1,5 +1,7 @@ using System.Drawing; using Instabug.Captain; +using OpenQA.Selenium; +using OpenQA.Selenium.Appium.MultiTouch; namespace E2E.Utils; @@ -10,6 +12,7 @@ public class CaptainTest : IDisposable AndroidApp = Path.GetFullPath("../../../../packages/instabug_flutter/example/build/app/outputs/flutter-apk/app-debug.apk"), AndroidAppId = "com.instabug.flutter.example", AndroidVersion = "13", + IosApp = Path.GetFullPath("../../../../packages/instabug_flutter/example/build/ios/iphonesimulator/Runner.app"), IosAppId = "com.instabug.InstabugSample", IosVersion = "17.2", @@ -28,28 +31,5 @@ public void Dispose() captain.RestartApp(); } - protected void ScrollDown() - { - captain.Swipe( - start: new Point(captain.Window.Size.Width / 2, captain.Window.Size.Height - 200), - end: new Point(captain.Window.Size.Width / 2, 300) - ); - } - - protected void ScrollDownLittle() - { - captain.Swipe( - start: new Point(captain.Window.Size.Width / 2, captain.Window.Size.Height - 200), - end: new Point(captain.Window.Size.Width / 2, captain.Window.Size.Height - 250) - ); - } - - protected void ScrollUp() - { - captain.Swipe( - start: new Point(captain.Window.Size.Width / 2, 300), - end: new Point(captain.Window.Size.Width / 2, captain.Window.Size.Height - 200) - ); - } } diff --git a/packages/instabug_flutter/android/build.gradle b/packages/instabug_flutter/android/build.gradle index c941b05da..b27e1d76d 100644 --- a/packages/instabug_flutter/android/build.gradle +++ b/packages/instabug_flutter/android/build.gradle @@ -51,7 +51,7 @@ android { } dependencies { - api 'com.instabug.library:instabug:14.2.0.6611053-SNAPSHOT' + api 'com.instabug.library:instabug:14.2.0.6611388-SNAPSHOT' testImplementation 'junit:junit:4.13.2' testImplementation "org.mockito:mockito-inline:3.12.1" diff --git a/packages/instabug_flutter/example/ios/Runner.xcodeproj/project.pbxproj b/packages/instabug_flutter/example/ios/Runner.xcodeproj/project.pbxproj index dc590bf18..89e630a84 100644 --- a/packages/instabug_flutter/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/instabug_flutter/example/ios/Runner.xcodeproj/project.pbxproj @@ -567,7 +567,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = com.instabug.InstabugSample2; + PRODUCT_BUNDLE_IDENTIFIER = com.instabug.InstabugSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -706,7 +706,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = com.instabug.InstabugSample2; + PRODUCT_BUNDLE_IDENTIFIER = com.instabug.InstabugSample; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -738,7 +738,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = com.instabug.InstabugSample2; + PRODUCT_BUNDLE_IDENTIFIER = com.instabug.InstabugSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; diff --git a/packages/instabug_flutter/example/lib/main.dart b/packages/instabug_flutter/example/lib/main.dart index 3a7459199..95c49a49a 100644 --- a/packages/instabug_flutter/example/lib/main.dart +++ b/packages/instabug_flutter/example/lib/main.dart @@ -49,6 +49,9 @@ void main() { debugLogsLevel: LogLevel.none, ); + Instabug.setWelcomeMessageMode(WelcomeMessageMode.disabled); + + FlutterError.onError = (FlutterErrorDetails details) { Zone.current.handleUncaughtError(details.exception, details.stack!); }; diff --git a/packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/modules/PrivateViewManager.java b/packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/modules/PrivateViewManager.java index 6b8abb152..d1d25d416 100644 --- a/packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/modules/PrivateViewManager.java +++ b/packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/modules/PrivateViewManager.java @@ -121,19 +121,23 @@ private void processScreenshot(ScreenshotResult result, AtomicReference privateViews) { - if (privateViews == null || privateViews.isEmpty()) return; - - Bitmap bitmap = result.getScreenshot(); - float pixelRatio = result.getPixelRatio(); - Canvas canvas = new Canvas(bitmap); - Paint paint = new Paint(); // Default color is black - - for (int i = 0; i < privateViews.size(); i += 4) { - float left = privateViews.get(i).floatValue() * pixelRatio; - float top = privateViews.get(i + 1).floatValue() * pixelRatio; - float right = privateViews.get(i + 2).floatValue() * pixelRatio; - float bottom = privateViews.get(i + 3).floatValue() * pixelRatio; - canvas.drawRect(left, top, right, bottom, paint); // Mask private view + try { + if (privateViews == null || privateViews.isEmpty()) return; + + Bitmap bitmap = result.getScreenshot(); + float pixelRatio = result.getPixelRatio(); + Canvas canvas = new Canvas(bitmap); + Paint paint = new Paint(); // Default color is black + + for (int i = 0; i < privateViews.size(); i += 4) { + float left = privateViews.get(i).floatValue() * pixelRatio; + float top = privateViews.get(i + 1).floatValue() * pixelRatio; + float right = privateViews.get(i + 2).floatValue() * pixelRatio; + float bottom = privateViews.get(i + 3).floatValue() * pixelRatio; + canvas.drawRect(left, top, right, bottom, paint); // Mask private view + } + } catch (Exception e){ +e.printStackTrace(); } } } \ No newline at end of file diff --git a/packages/instabug_private_views/example/lib/main.dart b/packages/instabug_private_views/example/lib/main.dart index 9ae8442dd..b379ba005 100644 --- a/packages/instabug_private_views/example/lib/main.dart +++ b/packages/instabug_private_views/example/lib/main.dart @@ -22,7 +22,7 @@ void main() { }; enableInstabugMaskingPrivateViews(); - runApp(const PrivateViewPage()); + runApp(const InstabugUserSteps(child:PrivateViewPage())); }, CrashReporting.reportCrash, ); diff --git a/packages/instabug_private_views/example/lib/private_view_page.dart b/packages/instabug_private_views/example/lib/private_view_page.dart index be01f1ba3..7c60f5bba 100644 --- a/packages/instabug_private_views/example/lib/private_view_page.dart +++ b/packages/instabug_private_views/example/lib/private_view_page.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; import 'package:instabug_private_views/instabug_private_view.dart'; +import 'package:instabug_private_views_example/widget/instabug_button.dart'; +import 'package:instabug_private_views_example/widget/section_title.dart'; import 'package:video_player/video_player.dart'; class PrivateViewPage extends StatefulWidget { @@ -11,6 +13,23 @@ class PrivateViewPage extends StatefulWidget { class _PrivateViewPageState extends State { late VideoPlayerController _controller; + double _currentSliderValue = 20.0; + + RangeValues _currentRangeValues = const RangeValues(40, 80); + + String? _sliderStatus; + + bool? isChecked = true; + + int? _selectedValue = 1; + + bool light = true; + double _scale = 1.0; // Initial scale of the image + + TextEditingController _controller2 = TextEditingController(); + + String _currentValue = ''; + List _items = List.generate(20, (index) => 'Item ${index + 1}'); @override void initState() { @@ -21,6 +40,11 @@ class _PrivateViewPageState extends State { )..initialize().then((_) { setState(() {}); }); + _controller2.addListener(() { + setState(() { + _currentValue = _controller2.text; + }); + }); } @override @@ -29,6 +53,12 @@ class _PrivateViewPageState extends State { super.dispose(); } + void _handleRadioValueChanged(int? value) { + setState(() { + _selectedValue = value; + }); + } + @override Widget build(BuildContext context) { return MaterialApp( @@ -62,6 +92,210 @@ class _PrivateViewPageState extends State { ), ), const SizedBox(height: 16), + BackButton(), + NotificationListener( + onNotification: (ScrollNotification notification) { + return false; + }, + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: List.generate( + 100, + (_) => InkWell( + onTap: () {}, + child: Container( + width: 100, + height: 100, + color: Colors.red, + margin: EdgeInsets.all(8), + ), + ), + ), + ), + ), + ), + SectionTitle('Sliders'), + Slider( + value: _currentSliderValue, + max: 100, + divisions: 5, + label: _currentSliderValue.round().toString(), + onChanged: (double value) { + setState(() { + _currentSliderValue = value; + }); + }, + ), + RangeSlider( + values: _currentRangeValues, + max: 100, + divisions: 5, + labels: RangeLabels( + _currentRangeValues.start.round().toString(), + _currentRangeValues.end.round().toString(), + ), + onChanged: (RangeValues values) { + setState(() { + _currentRangeValues = values; + }); + }, + ), + SectionTitle('Images'), + Row( + children: [ + Image.asset( + 'assets/img.png', + height: 100, + ), + Image.network( + "https://t3.ftcdn.net/jpg/00/50/07/64/360_F_50076454_TCvZEw37VyB5ZhcwEjkJHddtuV1cFmKY.jpg", + height: 100, + ), + ], + ), + InstabugButton(text: "I'm a button"), + ElevatedButton(onPressed: () {}, child: Text("data")), + SectionTitle('Toggles'), + Row( + children: [ + Checkbox( + tristate: true, + value: isChecked, + onChanged: (bool? value) { + setState(() { + isChecked = value; + }); + }, + ), + Radio( + value: 0, + groupValue: _selectedValue, + onChanged: _handleRadioValueChanged, + ), + Switch( + value: light, + activeColor: Colors.red, + onChanged: (bool value) { + setState(() { + light = value; + }); + }, + ), + ], + ), + GestureDetector( + onScaleUpdate: (details) { + setState(() { + _scale = details.scale; + _scale = _scale.clamp(1.0, + 3.0); // Limit zoom between 1x and 3x// Update scale based on pinch gesture + }); + }, + onScaleEnd: (details) { + // You can add logic to reset or clamp the scale if needed + if (_scale < 1.0) { + _scale = 1.0; // Prevent shrinking below original size + } + }, + child: Transform.scale( + scale: _scale, // Apply the scale transformation + child: Image.asset( + "assets/img.png", + height: 300, + ), + ), + ), + SectionTitle('TextInput'), + Column( + children: [ + Padding( + padding: EdgeInsets.all(16.0), // Set the padding value + child: Column( + children: [ + TextField( + key: Key('text_field'), + controller: _controller2, + // Bind the controller to the TextField + decoration: InputDecoration( + labelText: "Type something in a text field with key", + border: OutlineInputBorder(), + ), + ), + InstabugPrivateView( + child: TextField( + controller: _controller2, + // Bind the controller to the TextField + decoration: InputDecoration( + labelText: "Private view", + border: OutlineInputBorder(), + ), + ), + ), + InstabugPrivateView( + child: TextField( + controller: _controller2, + // Bind the controller to the TextField + obscureText: true, + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Password', + ), + ), + ), + TextFormField( + obscureText: true, + controller: _controller2, + // Bind the controller to the TextField + decoration: const InputDecoration( + icon: Icon(Icons.person), + hintText: 'What do people call you?', + labelText: 'Name *', + ), + onSaved: (String? value) { + // This optional block of code can be used to run + // code when the user saves the form. + }, + validator: (String? value) { + return (value != null && value.contains('@')) + ? 'Do not use the @ char.' + : null; + }, + ), + ], + ), + ), + ListView.builder( + itemCount: _items.length, + shrinkWrap: true, + itemBuilder: (context, index) { + return Dismissible( + key: Key(_items[index]), + // Unique key for each item + onDismissed: (direction) { + // Remove the item from the list + setState(() { + _items.removeAt(index); + }); + + // Show a snackbar or other UI feedback on dismissal + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Item dismissed')), + ); + }, + background: Container(color: Colors.red), + // Background color when swiped + direction: DismissDirection.endToStart, + // Swipe direction (left to right) + child: ListTile( + title: Text(_items[index]), + ), + ); + }, + ), + ], + ), + InstabugPrivateView( child: Image.asset( 'assets/img.png',