Skip to content

Commit 14bd3d0

Browse files
Merge #4726 Feedback Widget Drop 2
2 parents 5060f2d + 5c627e6 commit 14bd3d0

38 files changed

+5538
-315
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,17 @@
88
99
## Unreleased
1010

11+
### Features
12+
13+
- Adds the `FeedbackButton` component that shows the Feedback Widget ([#4378](https://github.com/getsentry/sentry-react-native/pull/4378))
14+
- Adds the `ScreenshotButton` component that takes a screenshot ([#4714](https://github.com/getsentry/sentry-react-native/issues/4714))
15+
- Add Feedback Widget theming ([#4677](https://github.com/getsentry/sentry-react-native/pull/4677))
16+
1117
### Fixes
1218

1319
- crashedLastRun now returns the correct value ([#4829](https://github.com/getsentry/sentry-react-native/pull/4829))
1420
- Use engine-specific promise rejection tracking ([#4826](https://github.com/getsentry/sentry-react-native/pull/4826))
21+
- Fixes Feedback Widget accessibility issue on iOS ([#4739](https://github.com/getsentry/sentry-react-native/pull/4739))
1522

1623
## 6.14.0
1724

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
appId: ${APP_ID}
2+
jsEngine: graaljs
3+
---
4+
- runFlow: utils/launchTestAppClear.yml
5+
6+
7+
# The following tests are happy path tests for the feedback widget on both iOS and Android.
8+
# They verify that the feedback form can be opened, filled out, and submitted successfully.
9+
# The tests are separate because iOS tests work better with `testID` and Android tests work better with `text`.
10+
11+
- runFlow:
12+
file: feedback/happyFlow-ios.yml
13+
when:
14+
platform: iOS
15+
16+
- runFlow:
17+
file: feedback/happyFlow-android.yml
18+
when:
19+
platform: Android
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# This is a happy path test for the feedback widget on Android.
2+
# It verifies that the feedback form can be opened, filled out, and submitted successfully
3+
appId: ${APP_ID}
4+
jsEngine: graaljs
5+
---
6+
7+
# Show feedback button
8+
- tapOn: 'Feedback'
9+
10+
# Open feedback widget
11+
- tapOn: 'Report a Bug'
12+
13+
# Assert that the feedback form is visible
14+
- extendedWaitUntil:
15+
visible: 'Report a Bug'
16+
timeout: 5_000
17+
18+
# Fill out name field
19+
- tapOn: 'Your Name'
20+
- inputText: 'John Doe'
21+
22+
# Fill out email field
23+
24+
- inputText: '[email protected]'
25+
26+
# Fill out message field
27+
- tapOn: "What's the bug? What did you expect?"
28+
- inputText: 'This is a test feedback message from CI e2e tests'
29+
30+
# Submit feedback
31+
- scrollUntilVisible:
32+
element:
33+
text: 'Send Bug Report'
34+
- tapOn: 'Send Bug Report'
35+
- assertVisible: 'Thank you for your report!'
36+
- tapOn: 'OK'
37+
38+
# Verify feedback form is closed and the home screen is visible
39+
- assertVisible: 'Welcome to React Native'
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# This is a happy path test for the feedback widget on iOS.
2+
# It verifies that the feedback form can be opened, filled out, and submitted successfully
3+
appId: ${APP_ID}
4+
jsEngine: graaljs
5+
---
6+
7+
# Show feedback button
8+
- tapOn: 'Feedback'
9+
10+
# Open feedback widget
11+
- tapOn:
12+
id: 'sentry-feedback-button'
13+
14+
# Assert that the feedback form is visible
15+
- extendedWaitUntil:
16+
visible:
17+
id: 'sentry-feedback-form-title'
18+
timeout: 5_000
19+
20+
# Fill out name field
21+
- tapOn:
22+
id: 'sentry-feedback-name-input'
23+
- inputText: 'John Doe'
24+
25+
# Fill out email field
26+
- tapOn:
27+
id: 'sentry-feedback-email-input'
28+
- inputText: '[email protected]'
29+
30+
# Fill out message field
31+
- tapOn:
32+
id: 'sentry-feedback-message-input'
33+
- inputText: 'This is a test feedback message from CI e2e tests'
34+
35+
# Submit feedback
36+
- scrollUntilVisible:
37+
element:
38+
id: 'sentry-feedback-submit-button'
39+
- tapOn:
40+
id: 'sentry-feedback-submit-button'
41+
- assertVisible: 'Thank you for your report!'
42+
- tapOn: 'OK'
43+
44+
# Verify feedback form is closed and the home screen is visible
45+
- assertVisible: 'Welcome to React Native'

dev-packages/e2e-tests/patch-scripts/rn.patch.app.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const e2eComponentPatch = '<EndToEndTestsScreen />';
3939
const lastImportRex = /^([^]*)(import\s+[^;]*?;$)/m;
4040
const patchRex = '@sentry/react-native';
4141
const headerComponentRex = /<ScrollView/gm;
42+
const exportDefaultRex = /export\s+default\s+App;/m;
4243

4344
const jsPath = path.join(args.app, 'App.js');
4445
const tsxPath = path.join(args.app, 'App.tsx');
@@ -50,7 +51,8 @@ const isPatched = app.match(patchRex);
5051
if (!isPatched) {
5152
const patched = app
5253
.replace(lastImportRex, m => m + initPatch)
53-
.replace(headerComponentRex, m => e2eComponentPatch + m);
54+
.replace(headerComponentRex, m => e2eComponentPatch + m)
55+
.replace(exportDefaultRex, 'export default Sentry.wrap(App);');
5456

5557
fs.writeFileSync(appPath, patched);
5658
logger.info('Patched RN App.(js|tsx) successfully!');

dev-packages/e2e-tests/src/EndToEndTests.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ const EndToEndTestsScreen = (): JSX.Element => {
6262
name: 'Unhandled Promise Rejection',
6363
action: async () => await Promise.reject(new Error('Unhandled Promise Rejection')),
6464
},
65+
{
66+
id: 'feedback',
67+
name: 'Feedback',
68+
action: () => Sentry.showFeedbackButton(),
69+
},
6570
{
6671
id: 'close',
6772
name: 'Close',

packages/core/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.facebook.react.bridge.Arguments;
2121
import com.facebook.react.bridge.Promise;
2222
import com.facebook.react.bridge.ReactApplicationContext;
23+
import com.facebook.react.bridge.ReadableArray;
2324
import com.facebook.react.bridge.ReadableMap;
2425
import com.facebook.react.bridge.ReadableMapKeySetIterator;
2526
import com.facebook.react.bridge.ReadableType;
@@ -1038,6 +1039,15 @@ public void getDataFromUri(String uri, Promise promise) {
10381039
}
10391040
}
10401041

1042+
public void encodeToBase64(ReadableArray array, Promise promise) {
1043+
byte[] bytes = new byte[array.size()];
1044+
for (int i = 0; i < array.size(); i++) {
1045+
bytes[i] = (byte) array.getInt(i);
1046+
}
1047+
String base64String = android.util.Base64.encodeToString(bytes, android.util.Base64.DEFAULT);
1048+
promise.resolve(base64String);
1049+
}
1050+
10411051
public void crashedLastRun(Promise promise) {
10421052
promise.resolve(Sentry.isCrashedLastRun());
10431053
}

packages/core/android/src/newarch/java/io/sentry/react/RNSentryModule.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,11 @@ public void getDataFromUri(String uri, Promise promise) {
183183
this.impl.getDataFromUri(uri, promise);
184184
}
185185

186+
@Override
187+
public void encodeToBase64(ReadableArray array, Promise promise) {
188+
this.impl.encodeToBase64(array, promise);
189+
}
190+
186191
@Override
187192
public void popTimeToDisplayFor(String key, Promise promise) {
188193
this.impl.popTimeToDisplayFor(key, promise);

packages/core/android/src/oldarch/java/io/sentry/react/RNSentryModule.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,11 @@ public void getDataFromUri(String uri, Promise promise) {
183183
this.impl.getDataFromUri(uri, promise);
184184
}
185185

186+
@ReactMethod
187+
public void encodeToBase64(ReadableArray array, Promise promise) {
188+
this.impl.encodeToBase64(array, promise);
189+
}
190+
186191
@ReactMethod
187192
public void popTimeToDisplayFor(String key, Promise promise) {
188193
this.impl.popTimeToDisplayFor(key, promise);

packages/core/ios/RNSentry.mm

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -970,4 +970,28 @@ + (SentryUser *_Nullable)userFrom:(NSDictionary *)userKeys
970970
return @YES; // The return ensures that the method is synchronous
971971
}
972972

973+
RCT_EXPORT_METHOD(encodeToBase64
974+
: (NSArray *)array resolver
975+
: (RCTPromiseResolveBlock)resolve rejecter
976+
: (RCTPromiseRejectBlock)reject)
977+
{
978+
NSUInteger count = array.count;
979+
uint8_t *bytes = (uint8_t *)malloc(count);
980+
981+
if (!bytes) {
982+
reject(@"encodeToBase64", @"Memory allocation failed", nil);
983+
return;
984+
}
985+
986+
for (NSUInteger i = 0; i < count; i++) {
987+
bytes[i] = (uint8_t)[array[i] unsignedCharValue];
988+
}
989+
990+
NSData *data = [NSData dataWithBytes:bytes length:count];
991+
free(bytes);
992+
993+
NSString *base64String = [data base64EncodedStringWithOptions:0];
994+
resolve(base64String);
995+
}
996+
973997
@end

0 commit comments

Comments
 (0)