Skip to content

Commit 4297324

Browse files
ref(e2e): Fetch received event in the tested app (#4209)
1 parent 23d9465 commit 4297324

File tree

8 files changed

+113
-59
lines changed

8 files changed

+113
-59
lines changed

dev-packages/e2e-tests/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@
22
*.log
33
*.app
44
*.apk
5+
6+
react-native-versions

dev-packages/e2e-tests/cli.mjs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,12 @@ if (actions.includes('create')) {
112112
env: Object.assign(env, { YARN_ENABLE_IMMUTABLE_INSTALLS: false }),
113113
});
114114

115-
console.log(`done`);
116-
117-
console.log(`done2`);
115+
execSync(`yarn add [email protected]`, {
116+
stdio: 'inherit',
117+
cwd: appDir,
118+
// yarn v3 run immutable install by default in CI
119+
env: Object.assign(env, { YARN_ENABLE_IMMUTABLE_INSTALLS: false }),
120+
});
118121

119122
// Patch the app
120123
execSync(`patch --verbose --strip=0 --force --ignore-whitespace --fuzz 4 < ${patchScriptsDir}/rn.patch`, {
@@ -138,9 +141,11 @@ if (actions.includes('create')) {
138141
cwd: `${appDir}/ios`,
139142
env: env,
140143
});
141-
console.log(`done3`);
142144

143145
if (fs.existsSync(`${appDir}/Gemfile`)) {
146+
// TMP Fix for https://github.com/CocoaPods/Xcodeproj/issues/989
147+
fs.appendFileSync(`${appDir}/Gemfile`, "gem 'xcodeproj', '< 1.26.0'\n");
148+
144149
execSync(`bundle install`, { stdio: 'inherit', cwd: appDir, env: env });
145150
execSync('bundle exec pod install --repo-update', { stdio: 'inherit', cwd: `${appDir}/ios`, env: env });
146151
} else {

dev-packages/e2e-tests/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,16 @@
2323
"jest": "^29.7.0",
2424
"react": "18.3.1",
2525
"react-native": "0.75.4",
26+
"react-native-launch-arguments": "^4.0.2",
2627
"typescript": "4.9.5",
2728
"webdriverio": "^8.27.0"
2829
},
2930
"dependencies": {
3031
"minimist": "1.2.8",
3132
"semver": "7.6.3",
3233
"xcode": "3.0.1"
34+
},
35+
"peerDependencies": {
36+
"react-native-launch-arguments": "^4.0.2"
3337
}
3438
}

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

Lines changed: 76 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,101 @@
1-
/* eslint-disable import/no-unresolved, @typescript-eslint/no-unsafe-member-access */
21
import * as Sentry from '@sentry/react-native';
32
import * as React from 'react';
43
import { Text, View } from 'react-native';
4+
import { LaunchArguments } from "react-native-launch-arguments";
55

66
import { getTestProps } from './utils/getTestProps';
7+
import { fetchEvent } from './utils/fetchEvent';
8+
9+
const getSentryAuthToken = ():
10+
| { token: string }
11+
| { error: string } => {
12+
const { sentryAuthToken } = LaunchArguments.value<{
13+
sentryAuthToken: unknown;
14+
}>();
15+
16+
if (typeof sentryAuthToken !== 'string') {
17+
return { error: 'Sentry Auth Token is required' };
18+
}
19+
20+
if (sentryAuthToken.length === 0) {
21+
return { error: 'Sentry Auth Token must not be empty' };
22+
}
23+
24+
return { token: sentryAuthToken };
25+
};
726

8-
export { getTestProps };
9-
/**
10-
* This screen is for internal end-to-end testing purposes only. Do not use.
11-
* Not visible through the UI (no button to load it).
12-
*/
13-
// Deprecated in https://github.com/DefinitelyTyped/DefinitelyTyped/commit/f1b25591890978a92c610ce575ea2ba2bbde6a89
14-
// eslint-disable-next-line deprecation/deprecation
1527
const EndToEndTestsScreen = (): JSX.Element => {
1628
const [eventId, setEventId] = React.useState<string | null | undefined>();
29+
const [error, setError] = React.useState<string>('No error');
30+
31+
async function assertEventReceived(eventId: string | undefined) {
32+
if (!eventId) {
33+
setError('Event ID is required');
34+
return;
35+
}
36+
37+
const value = getSentryAuthToken();
38+
if ('error' in value) {
39+
setError(value.error);
40+
return;
41+
}
42+
43+
await fetchEvent(eventId, value.token);
44+
45+
setEventId(eventId);
46+
}
1747

18-
// !!! WARNING: This is only for testing purposes.
19-
// We only do this to render the eventId onto the UI for end to end tests.
2048
React.useEffect(() => {
2149
const client: Sentry.ReactNativeClient | undefined = Sentry.getClient();
50+
51+
if (!client) {
52+
setError('Client is not initialized');
53+
return;
54+
}
55+
56+
// WARNING: This is only for testing purposes.
57+
// We only do this to render the eventId onto the UI for end to end tests.
2258
client.getOptions().beforeSend = (e) => {
23-
setEventId(e.event_id || null);
59+
assertEventReceived(e.event_id);
2460
return e;
2561
};
2662
}, []);
2763

64+
const testCases = [
65+
{
66+
id: 'captureMessage',
67+
name: 'Capture Message',
68+
action: () => Sentry.captureMessage('React Native Test Message'),
69+
},
70+
{
71+
id: 'captureException',
72+
name: 'Capture Exception',
73+
action: () => Sentry.captureException(new Error('captureException test')),
74+
},
75+
{
76+
id: 'unhandledPromiseRejection',
77+
name: 'Unhandled Promise Rejection',
78+
action: async () => await Promise.reject(new Error('Unhandled Promise Rejection')),
79+
},
80+
{
81+
id: 'close',
82+
name: 'Close',
83+
action: async () => await Sentry.close(),
84+
},
85+
];
86+
2887
return (
2988
<View>
89+
<Text>{error}</Text>
3090
<Text {...getTestProps('eventId')}>{eventId}</Text>
3191
<Text {...getTestProps('clearEventId')} onPress={() => setEventId('')}>
3292
Clear Event Id
3393
</Text>
34-
<Text
35-
{...getTestProps('captureMessage')}
36-
onPress={() => {
37-
Sentry.captureMessage('React Native Test Message');
38-
}}>
39-
captureMessage
40-
</Text>
41-
<Text
42-
{...getTestProps('captureException')}
43-
onPress={() => {
44-
Sentry.captureException(new Error('captureException test'));
45-
}}>
46-
captureException
47-
</Text>
48-
<Text
49-
onPress={async () => {
50-
await Promise.reject(new Error('Unhandled Promise Rejection'));
51-
}}
52-
{...getTestProps('unhandledPromiseRejection')}>
53-
Unhandled Promise Rejection
54-
</Text>
55-
<Text
56-
{...getTestProps('close')}
57-
onPress={async () => {
58-
await Sentry.close();
59-
}}>
60-
close
61-
</Text>
94+
{testCases.map((testCase) => (
95+
<Text key={testCase.id} {...getTestProps(testCase.id)} onPress={testCase.action}>
96+
{testCase.name}
97+
</Text>
98+
))}
6299
</View>
63100
);
64101
};

dev-packages/e2e-tests/test/utils/fetchEvent.ts renamed to dev-packages/e2e-tests/src/utils/fetchEvent.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,13 @@ interface ApiEvent extends Event {
1313
const RETRY_COUNT = 600;
1414
const RETRY_INTERVAL = 1000;
1515

16-
const fetchEvent = async (eventId: string): Promise<ApiEvent> => {
16+
const fetchEvent = async (eventId: string, authToken: string): Promise<ApiEvent> => {
1717
const url = `https://${domain}${eventEndpoint}${eventId}/`;
1818

19-
expect(process.env.SENTRY_AUTH_TOKEN).toBeDefined();
20-
expect(process.env.SENTRY_AUTH_TOKEN?.length).toBeGreaterThan(0);
21-
2219
const request = () =>
2320
fetch(url, {
2421
headers: {
25-
Authorization: `Bearer ${process.env.SENTRY_AUTH_TOKEN}`,
22+
Authorization: `Bearer ${authToken}`,
2623
'Content-Type': 'application/json',
2724
},
2825
method: 'GET',
@@ -47,6 +44,7 @@ const fetchEvent = async (eventId: string): Promise<ApiEvent> => {
4744
reject(new Error('Could not fetch event within retry limit.'));
4845
}
4946
} else {
47+
console.log('Fetched event', jsonResponse.detail);
5048
resolve(jsonResponse);
5149
}
5250
});

dev-packages/e2e-tests/test/e2e.test.ts

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import path from 'path';
33
import type { RemoteOptions } from 'webdriverio';
44
import { remote } from 'webdriverio';
55

6-
import { fetchEvent } from './utils/fetchEvent';
76
import { waitForTruthyResult } from './utils/waitFor';
7+
import { expect, jest, beforeAll, afterAll, beforeEach, afterEach, describe, test } from '@jest/globals';
88

99
const DRIVER_NOT_INITIALIZED = 'Driver not initialized';
1010

@@ -58,6 +58,7 @@ beforeAll(async () => {
5858
platformName: 'Android',
5959
'appium:automationName': 'UIAutomator2',
6060
'appium:app': process.env.APPIUM_APP,
61+
'appium:optionalIntentArguments': `--es sentryAuthToken '${process.env.SENTRY_AUTH_TOKEN}'`,
6162
};
6263
} else {
6364
conf.capabilities = {
@@ -68,6 +69,7 @@ beforeAll(async () => {
6869
'appium:derivedDataPath': path.resolve(process.env.APPIUM_DERIVED_DATA || ''),
6970
'appium:showXcodeLog': true,
7071
'appium:usePrebuiltWDA': true,
72+
'appium:processArguments': { args: ['-sentryAuthToken', `${process.env.SENTRY_AUTH_TOKEN}`] },
7173
};
7274
}
7375

@@ -117,27 +119,21 @@ describe('End to end tests for common events', () => {
117119
const element = await getElement('captureMessage');
118120
await element.click();
119121

120-
const eventId = await waitForEventId();
121-
const sentryEvent = await fetchEvent(eventId);
122-
expect(sentryEvent.eventID).toMatch(eventId);
122+
await waitForEventId();
123123
});
124124

125125
test('captureException', async () => {
126126
const element = await getElement('captureException');
127127
await element.click();
128128

129-
const eventId = await waitForEventId();
130-
const sentryEvent = await fetchEvent(eventId);
131-
expect(sentryEvent.eventID).toMatch(eventId);
129+
await waitForEventId();
132130
});
133131

134132
test('unhandledPromiseRejection', async () => {
135133
const element = await getElement('unhandledPromiseRejection');
136134
await element.click();
137135

138-
const eventId = await waitForEventId();
139-
const sentryEvent = await fetchEvent(eventId);
140-
expect(sentryEvent.eventID).toMatch(eventId);
136+
await waitForEventId();
141137
});
142138

143139
test('close', async () => {

test/react-native/versions/0.65.3

Lines changed: 0 additions & 1 deletion
This file was deleted.

yarn.lock

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21142,6 +21142,16 @@ __metadata:
2114221142
languageName: node
2114321143
linkType: hard
2114421144

21145+
"react-native-launch-arguments@npm:^4.0.2":
21146+
version: 4.0.2
21147+
resolution: "react-native-launch-arguments@npm:4.0.2"
21148+
peerDependencies:
21149+
react: ">=16.8.1"
21150+
react-native: ">=0.60.0-rc.0 <1.0.x"
21151+
checksum: 5a73cfa27c603a743939c7fbc98fef3eb790dfc1043ecfe60855d30f238c41251ba1a47775cb660b37ef86f96961b5643f6ff48480f0d60efb0235488d43ff05
21152+
languageName: node
21153+
linkType: hard
21154+
2114521155
"react-native-macos@npm:0.73.34":
2114621156
version: 0.73.34
2114721157
resolution: "react-native-macos@npm:0.73.34"
@@ -22685,10 +22695,13 @@ __metadata:
2268522695
minimist: 1.2.8
2268622696
react: 18.3.1
2268722697
react-native: 0.75.4
22698+
react-native-launch-arguments: ^4.0.2
2268822699
semver: 7.6.3
2268922700
typescript: 4.9.5
2269022701
webdriverio: ^8.27.0
2269122702
xcode: 3.0.1
22703+
peerDependencies:
22704+
react-native-launch-arguments: ^4.0.2
2269222705
languageName: unknown
2269322706
linkType: soft
2269422707

0 commit comments

Comments
 (0)