@sentry/wizard 5.1.0 → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/e2e-tests/tests/expo.test.js +19 -9
- package/dist/e2e-tests/tests/expo.test.js.map +1 -1
- package/dist/e2e-tests/tests/react-native.test.js +19 -13
- package/dist/e2e-tests/tests/react-native.test.js.map +1 -1
- package/dist/e2e-tests/utils/index.d.ts +16 -0
- package/dist/e2e-tests/utils/index.js +72 -1
- package/dist/e2e-tests/utils/index.js.map +1 -1
- package/dist/src/nextjs/nextjs-wizard.js +14 -10
- package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
- package/dist/src/nextjs/templates.d.ts +7 -2
- package/dist/src/nextjs/templates.js +23 -14
- package/dist/src/nextjs/templates.js.map +1 -1
- package/dist/src/nuxt/templates.js +29 -12
- package/dist/src/nuxt/templates.js.map +1 -1
- package/dist/src/remix/sdk-example.js +20 -5
- package/dist/src/remix/sdk-example.js.map +1 -1
- package/dist/src/sveltekit/templates.js +13 -6
- package/dist/src/sveltekit/templates.js.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/version.js.map +1 -1
- package/dist/test/nextjs/templates.test.js +78 -0
- package/dist/test/nextjs/templates.test.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 5.2.0
|
|
4
|
+
|
|
5
|
+
- fix(nextjs): Update jsx/tsx snippets ([#1015](https://github.com/getsentry/sentry-wizard/pull/1015))
|
|
6
|
+
- feat(nextjs): deactivate error button when adblocker is detected ([#1010](https://github.com/getsentry/sentry-wizard/pull/1010))
|
|
7
|
+
- feat(remix): deactivate error button when adblocker is detected ([#1017](https://github.com/getsentry/sentry-wizard/pull/1017))
|
|
8
|
+
- feat(sveltekit): deactivate error button when adblocker is detected ([#1018](https://github.com/getsentry/sentry-wizard/pull/1018))
|
|
9
|
+
- feat(nuxt): deactivate error button when adblocker is detected ([#1019](https://github.com/getsentry/sentry-wizard/pull/1019))
|
|
10
|
+
|
|
3
11
|
## 5.1.0
|
|
4
12
|
|
|
5
13
|
- feat(nextjs): Add template for generateMetadata in App router for next@14 ([#1003](https://github.com/getsentry/sentry-wizard/pull/1003))
|
|
@@ -26,14 +26,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
26
26
|
const path = __importStar(require("node:path"));
|
|
27
27
|
const Constants_1 = require("../../lib/Constants");
|
|
28
28
|
const utils_1 = require("../utils");
|
|
29
|
-
const utils_2 = require("../utils");
|
|
30
|
-
const utils_3 = require("../utils");
|
|
31
29
|
const vitest_1 = require("vitest");
|
|
32
30
|
(0, vitest_1.describe)('Expo', () => {
|
|
33
31
|
const integration = Constants_1.Integration.reactNative;
|
|
34
32
|
const projectDir = path.resolve(__dirname, '../test-applications/react-native-expo-test-app');
|
|
35
33
|
(0, vitest_1.beforeAll)(async () => {
|
|
36
|
-
const wizardInstance = (0,
|
|
34
|
+
const wizardInstance = (0, utils_1.startWizardInstance)(integration, projectDir);
|
|
37
35
|
const packageManagerPrompted = await wizardInstance.waitForOutput('Please select your package manager.');
|
|
38
36
|
const sessionReplayPrompted = packageManagerPrompted &&
|
|
39
37
|
(await wizardInstance.sendStdinAndWaitForOutput(
|
|
@@ -58,10 +56,10 @@ const vitest_1 = require("vitest");
|
|
|
58
56
|
(0, utils_1.cleanupGit)(projectDir);
|
|
59
57
|
});
|
|
60
58
|
(0, vitest_1.test)('package.json is updated correctly', () => {
|
|
61
|
-
(0,
|
|
59
|
+
(0, utils_1.checkFileContents)(`${projectDir}/package.json`, `@sentry/react-native`);
|
|
62
60
|
});
|
|
63
61
|
(0, vitest_1.test)('_layout.tsx is updated correctly', () => {
|
|
64
|
-
(0,
|
|
62
|
+
(0, utils_1.checkFileContents)(`${projectDir}/app/_layout.tsx`, `import * as Sentry from '@sentry/react-native';
|
|
65
63
|
|
|
66
64
|
Sentry.init({
|
|
67
65
|
dsn: 'https://public@dsn.ingest.sentry.io/1337',
|
|
@@ -78,10 +76,10 @@ Sentry.init({
|
|
|
78
76
|
// uncomment the line below to enable Spotlight (https://spotlightjs.com)
|
|
79
77
|
// spotlight: __DEV__,
|
|
80
78
|
});`);
|
|
81
|
-
(0,
|
|
79
|
+
(0, utils_1.checkFileContents)(`${projectDir}/app/_layout.tsx`, `export default Sentry.wrap(function RootLayout() {`);
|
|
82
80
|
});
|
|
83
81
|
(0, vitest_1.test)('app.json is updated correctly', () => {
|
|
84
|
-
(0,
|
|
82
|
+
(0, utils_1.checkFileContents)(`${projectDir}/app.json`, `"@sentry/react-native/expo",
|
|
85
83
|
{
|
|
86
84
|
"url": "https://sentry.io/",
|
|
87
85
|
"project": "${utils_1.TEST_ARGS.PROJECT_SLUG}",
|
|
@@ -90,14 +88,26 @@ Sentry.init({
|
|
|
90
88
|
});
|
|
91
89
|
(0, vitest_1.test)('metro.config.js is added', () => {
|
|
92
90
|
(0, utils_1.checkFileExists)(`${projectDir}/metro.config.js`);
|
|
93
|
-
(0,
|
|
91
|
+
(0, utils_1.checkFileContents)(`${projectDir}/metro.config.js`, `const { getSentryExpoConfig } = require("@sentry/react-native/metro");
|
|
94
92
|
|
|
95
93
|
const config = getSentryExpoConfig(__dirname);
|
|
96
94
|
|
|
97
95
|
module.exports = config;`);
|
|
98
96
|
});
|
|
99
97
|
(0, vitest_1.test)('.gitignore is updated correctly', () => {
|
|
100
|
-
(0,
|
|
98
|
+
(0, utils_1.checkFileContents)(`${projectDir}/.gitignore`, `.env.local`);
|
|
99
|
+
});
|
|
100
|
+
(0, vitest_1.test)('android project is bundled correctly', async () => {
|
|
101
|
+
const bundled = await (0, utils_1.checkIfExpoBundles)(projectDir, 'android');
|
|
102
|
+
(0, vitest_1.expect)(bundled).toBe(true);
|
|
103
|
+
});
|
|
104
|
+
(0, vitest_1.test)('ios project is bundled correctly', async () => {
|
|
105
|
+
const bundled = await (0, utils_1.checkIfExpoBundles)(projectDir, 'ios');
|
|
106
|
+
(0, vitest_1.expect)(bundled).toBe(true);
|
|
107
|
+
});
|
|
108
|
+
(0, vitest_1.test)('web project is bundled correctly', async () => {
|
|
109
|
+
const bundled = await (0, utils_1.checkIfExpoBundles)(projectDir, 'web');
|
|
110
|
+
(0, vitest_1.expect)(bundled).toBe(true);
|
|
101
111
|
});
|
|
102
112
|
});
|
|
103
113
|
//# sourceMappingURL=expo.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expo.test.js","sourceRoot":"","sources":["../../../e2e-tests/tests/expo.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAAA,gDAAkC;AAClC,mDAAkD;AAClD,
|
|
1
|
+
{"version":3,"file":"expo.test.js","sourceRoot":"","sources":["../../../e2e-tests/tests/expo.test.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'node:path';\nimport { Integration } from '../../lib/Constants';\nimport {\n KEYS,\n TEST_ARGS,\n checkFileContents,\n checkFileExists,\n checkIfExpoBundles,\n cleanupGit,\n revertLocalChanges,\n startWizardInstance,\n} from '../utils';\nimport { afterAll, beforeAll, describe, test, expect } from 'vitest';\n\ndescribe('Expo', () => {\n const integration = Integration.reactNative;\n const projectDir = path.resolve(\n __dirname,\n '../test-applications/react-native-expo-test-app',\n );\n\n beforeAll(async () => {\n const wizardInstance = startWizardInstance(integration, projectDir);\n const packageManagerPrompted = await wizardInstance.waitForOutput(\n 'Please select your package manager.',\n );\n const sessionReplayPrompted =\n packageManagerPrompted &&\n (await wizardInstance.sendStdinAndWaitForOutput(\n // Selecting `yarn` as the package manager\n [KEYS.DOWN, KEYS.DOWN, KEYS.ENTER],\n 'Do you want to enable Session Replay to help debug issues? (See https://docs.sentry.io/platforms/react-native/session-replay/)',\n ));\n const feedbackWidgetPrompted =\n sessionReplayPrompted &&\n (await wizardInstance.sendStdinAndWaitForOutput(\n // Enable session replay\n [KEYS.ENTER],\n 'Do you want to enable the Feedback Widget to collect feedback from your users? (See https://docs.sentry.io/platforms/react-native/user-feedback/)',\n ));\n const testEventPrompted =\n feedbackWidgetPrompted &&\n (await wizardInstance.sendStdinAndWaitForOutput(\n // Enable feedback widget\n [KEYS.ENTER],\n 'Have you successfully sent a test event?',\n ));\n testEventPrompted &&\n (await wizardInstance.sendStdinAndWaitForOutput(\n // Respond that test event was sent\n [KEYS.ENTER],\n 'Everything is set up!',\n ));\n wizardInstance.kill();\n });\n\n afterAll(() => {\n revertLocalChanges(projectDir);\n cleanupGit(projectDir);\n });\n\n test('package.json is updated correctly', () => {\n checkFileContents(`${projectDir}/package.json`, `@sentry/react-native`);\n });\n\n test('_layout.tsx is updated correctly', () => {\n checkFileContents(\n `${projectDir}/app/_layout.tsx`,\n `import * as Sentry from '@sentry/react-native';\n\nSentry.init({\n dsn: 'https://public@dsn.ingest.sentry.io/1337',\n\n // Adds more context data to events (IP address, cookies, user, etc.)\n // For more information, visit: https://docs.sentry.io/platforms/react-native/data-management/data-collected/\n sendDefaultPii: true,\n\n // Configure Session Replay\n replaysSessionSampleRate: 0.1,\n replaysOnErrorSampleRate: 1,\n integrations: [Sentry.mobileReplayIntegration(), Sentry.feedbackIntegration()],\n\n // uncomment the line below to enable Spotlight (https://spotlightjs.com)\n // spotlight: __DEV__,\n});`,\n );\n checkFileContents(\n `${projectDir}/app/_layout.tsx`,\n `export default Sentry.wrap(function RootLayout() {`,\n );\n });\n\n test('app.json is updated correctly', () => {\n checkFileContents(\n `${projectDir}/app.json`,\n `\"@sentry/react-native/expo\",\n {\n \"url\": \"https://sentry.io/\",\n \"project\": \"${TEST_ARGS.PROJECT_SLUG}\",\n \"organization\": \"${TEST_ARGS.ORG_SLUG}\"\n }`,\n );\n });\n\n test('metro.config.js is added', () => {\n checkFileExists(`${projectDir}/metro.config.js`);\n checkFileContents(\n `${projectDir}/metro.config.js`,\n `const { getSentryExpoConfig } = require(\"@sentry/react-native/metro\");\n\nconst config = getSentryExpoConfig(__dirname);\n\nmodule.exports = config;`,\n );\n });\n\n test('.gitignore is updated correctly', () => {\n checkFileContents(`${projectDir}/.gitignore`, `.env.local`);\n });\n\n test('android project is bundled correctly', async () => {\n const bundled = await checkIfExpoBundles(projectDir, 'android');\n expect(bundled).toBe(true);\n });\n\n test('ios project is bundled correctly', async () => {\n const bundled = await checkIfExpoBundles(projectDir, 'ios');\n expect(bundled).toBe(true);\n });\n\n test('web project is bundled correctly', async () => {\n const bundled = await checkIfExpoBundles(projectDir, 'web');\n expect(bundled).toBe(true);\n });\n});\n"]}
|
|
@@ -26,15 +26,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
26
26
|
const path = __importStar(require("node:path"));
|
|
27
27
|
const Constants_1 = require("../../lib/Constants");
|
|
28
28
|
const utils_1 = require("../utils");
|
|
29
|
-
const utils_2 = require("../utils");
|
|
30
|
-
const utils_3 = require("../utils");
|
|
31
29
|
const vitest_1 = require("vitest");
|
|
32
30
|
(0, vitest_1.describe)('ReactNative', () => {
|
|
33
31
|
const integration = Constants_1.Integration.reactNative;
|
|
34
32
|
const projectDir = path.resolve(__dirname, '../test-applications/react-native-test-app');
|
|
35
33
|
let podInstallPrompted = false;
|
|
36
34
|
(0, vitest_1.beforeAll)(async () => {
|
|
37
|
-
const wizardInstance = (0,
|
|
35
|
+
const wizardInstance = (0, utils_1.startWizardInstance)(integration, projectDir);
|
|
38
36
|
const packageManagerPrompted = await wizardInstance.waitForOutput('Please select your package manager.');
|
|
39
37
|
const sessionReplayPrompted = packageManagerPrompted &&
|
|
40
38
|
(await wizardInstance.sendStdinAndWaitForOutput(
|
|
@@ -71,16 +69,16 @@ const vitest_1 = require("vitest");
|
|
|
71
69
|
(0, utils_1.cleanupGit)(projectDir);
|
|
72
70
|
});
|
|
73
71
|
(0, vitest_1.test)('package.json is updated correctly', () => {
|
|
74
|
-
(0,
|
|
72
|
+
(0, utils_1.checkFileContents)(`${projectDir}/package.json`, `@sentry/react-native`);
|
|
75
73
|
});
|
|
76
74
|
(0, vitest_1.test)('metro.config.js is updated correctly', () => {
|
|
77
|
-
(0,
|
|
75
|
+
(0, utils_1.checkFileContents)(`${projectDir}/metro.config.js`, `const {
|
|
78
76
|
withSentryConfig
|
|
79
77
|
} = require("@sentry/react-native/metro");`);
|
|
80
|
-
(0,
|
|
78
|
+
(0, utils_1.checkFileContents)(`${projectDir}/metro.config.js`, `module.exports = withSentryConfig(mergeConfig(getDefaultConfig(__dirname), config));`);
|
|
81
79
|
});
|
|
82
80
|
(0, vitest_1.test)('App.tsx is updated correctly', () => {
|
|
83
|
-
(0,
|
|
81
|
+
(0, utils_1.checkFileContents)(`${projectDir}/App.tsx`, `import * as Sentry from '@sentry/react-native';
|
|
84
82
|
|
|
85
83
|
Sentry.init({
|
|
86
84
|
dsn: 'https://public@dsn.ingest.sentry.io/1337',
|
|
@@ -97,13 +95,13 @@ Sentry.init({
|
|
|
97
95
|
// uncomment the line below to enable Spotlight (https://spotlightjs.com)
|
|
98
96
|
// spotlight: __DEV__,
|
|
99
97
|
});`);
|
|
100
|
-
(0,
|
|
98
|
+
(0, utils_1.checkFileContents)(`${projectDir}/App.tsx`, `export default Sentry.wrap(App);`);
|
|
101
99
|
});
|
|
102
100
|
(0, vitest_1.test)('ios/sentry.properties is added', () => {
|
|
103
101
|
if (!podInstallPrompted) {
|
|
104
102
|
return;
|
|
105
103
|
}
|
|
106
|
-
(0,
|
|
104
|
+
(0, utils_1.checkFileContents)(`${projectDir}/ios/sentry.properties`, `auth.token=${utils_1.TEST_ARGS.AUTH_TOKEN}
|
|
107
105
|
|
|
108
106
|
defaults.org=${utils_1.TEST_ARGS.ORG_SLUG}
|
|
109
107
|
defaults.project=${utils_1.TEST_ARGS.PROJECT_SLUG}
|
|
@@ -111,7 +109,7 @@ defaults.project=${utils_1.TEST_ARGS.PROJECT_SLUG}
|
|
|
111
109
|
defaults.url=https://sentry.io/`);
|
|
112
110
|
});
|
|
113
111
|
(0, vitest_1.test)('android/sentry.properties is added', () => {
|
|
114
|
-
(0,
|
|
112
|
+
(0, utils_1.checkFileContents)(`${projectDir}/android/sentry.properties`, `auth.token=${utils_1.TEST_ARGS.AUTH_TOKEN}
|
|
115
113
|
|
|
116
114
|
defaults.org=${utils_1.TEST_ARGS.ORG_SLUG}
|
|
117
115
|
defaults.project=${utils_1.TEST_ARGS.PROJECT_SLUG}
|
|
@@ -119,14 +117,22 @@ defaults.project=${utils_1.TEST_ARGS.PROJECT_SLUG}
|
|
|
119
117
|
defaults.url=https://sentry.io/`);
|
|
120
118
|
});
|
|
121
119
|
(0, vitest_1.test)('build.gradle is updated correctly', () => {
|
|
122
|
-
(0,
|
|
120
|
+
(0, utils_1.checkFileContents)(`${projectDir}/android/app/build.gradle`, `apply from: new File(["node", "--print", "require.resolve('@sentry/react-native/package.json')"].execute().text.trim(), "../sentry.gradle")`);
|
|
123
121
|
});
|
|
124
122
|
(0, vitest_1.test)('xcode project is updated correctly', () => {
|
|
125
123
|
if (!podInstallPrompted) {
|
|
126
124
|
return;
|
|
127
125
|
}
|
|
128
|
-
(0,
|
|
129
|
-
(0,
|
|
126
|
+
(0, utils_1.checkFileContents)(`${projectDir}/ios/reactnative078.xcodeproj/project.pbxproj`, `../node_modules/@sentry/react-native/scripts/sentry-xcode.sh`);
|
|
127
|
+
(0, utils_1.checkFileContents)(`${projectDir}/ios/reactnative078.xcodeproj/project.pbxproj`, `../node_modules/@sentry/react-native/scripts/sentry-xcode-debug-files.sh`);
|
|
128
|
+
});
|
|
129
|
+
(0, vitest_1.test)('android project is bundled correctly', async () => {
|
|
130
|
+
const bundled = await (0, utils_1.checkIfReactNativeBundles)(projectDir, 'android');
|
|
131
|
+
(0, vitest_1.expect)(bundled).toBe(true);
|
|
132
|
+
});
|
|
133
|
+
(0, vitest_1.test)('ios project is bundled correctly', async () => {
|
|
134
|
+
const bundled = await (0, utils_1.checkIfReactNativeBundles)(projectDir, 'ios');
|
|
135
|
+
(0, vitest_1.expect)(bundled).toBe(true);
|
|
130
136
|
});
|
|
131
137
|
});
|
|
132
138
|
//# sourceMappingURL=react-native.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react-native.test.js","sourceRoot":"","sources":["../../../e2e-tests/tests/react-native.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAAA,gDAAkC;AAClC,mDAAkD;AAClD,
|
|
1
|
+
{"version":3,"file":"react-native.test.js","sourceRoot":"","sources":["../../../e2e-tests/tests/react-native.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAAA,gDAAkC;AAClC,mDAAkD;AAClD,oCAQkB;AAClB,mCAAqE;AAErE,IAAA,iBAAQ,EAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,MAAM,WAAW,GAAG,uBAAW,CAAC,WAAW,CAAC;IAC5C,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAC7B,SAAS,EACT,4CAA4C,CAC7C,CAAC;IAEF,IAAI,kBAAkB,GAAG,KAAK,CAAC;IAE/B,IAAA,kBAAS,EAAC,KAAK,IAAI,EAAE;QACnB,MAAM,cAAc,GAAG,IAAA,2BAAmB,EAAC,WAAW,EAAE,UAAU,CAAC,CAAC;QACpE,MAAM,sBAAsB,GAAG,MAAM,cAAc,CAAC,aAAa,CAC/D,qCAAqC,CACtC,CAAC;QACF,MAAM,qBAAqB,GACzB,sBAAsB;YACtB,CAAC,MAAM,cAAc,CAAC,yBAAyB;YAC7C,0CAA0C;YAC1C,CAAC,YAAI,CAAC,IAAI,EAAE,YAAI,CAAC,IAAI,EAAE,YAAI,CAAC,KAAK,CAAC,EAClC,gIAAgI,CACjI,CAAC,CAAC;QAEL,MAAM,sBAAsB,GAC1B,qBAAqB;YACrB,CAAC,MAAM,cAAc,CAAC,yBAAyB;YAC7C,wBAAwB;YACxB,CAAC,YAAI,CAAC,KAAK,CAAC,EACZ,mJAAmJ,CACpJ,CAAC,CAAC;QAEL,kBAAkB;YAChB,sBAAsB;gBACtB,CAAC,MAAM,cAAc,CAAC,yBAAyB;gBAC7C,yBAAyB;gBACzB,CAAC,YAAI,CAAC,KAAK,CAAC,EACZ,uCAAuC,EACvC;oBACE,QAAQ,EAAE,IAAI;oBACd,OAAO,EAAE,IAAI;iBACd,CACF,CAAC,CAAC;QAEL,MAAM,gBAAgB,GACpB,kBAAkB;YAClB,CAAC,MAAM,cAAc,CAAC,yBAAyB;YAC7C,mBAAmB;YACnB,CAAC,YAAI,CAAC,IAAI,EAAE,YAAI,CAAC,KAAK,CAAC,EACvB,oFAAoF,CACrF,CAAC,CAAC;QAEL,MAAM,iBAAiB,GACrB,gBAAgB;YAChB,CAAC,MAAM,cAAc,CAAC,yBAAyB;YAC7C,gBAAgB;YAChB,CAAC,YAAI,CAAC,IAAI,EAAE,YAAI,CAAC,KAAK,CAAC,EACvB,0CAA0C,CAC3C,CAAC,CAAC;QAEL,iBAAiB;YACf,CAAC,MAAM,cAAc,CAAC,yBAAyB;YAC7C,mCAAmC;YACnC,CAAC,YAAI,CAAC,KAAK,CAAC,EACZ,uBAAuB,CACxB,CAAC,CAAC;QACL,cAAc,CAAC,IAAI,EAAE,CAAC;IACxB,CAAC,CAAC,CAAC;IAEH,IAAA,iBAAQ,EAAC,GAAG,EAAE;QACZ,IAAA,0BAAkB,EAAC,UAAU,CAAC,CAAC;QAC/B,IAAA,kBAAU,EAAC,UAAU,CAAC,CAAC;IACzB,CAAC,CAAC,CAAC;IAEH,IAAA,aAAI,EAAC,mCAAmC,EAAE,GAAG,EAAE;QAC7C,IAAA,yBAAiB,EAAC,GAAG,UAAU,eAAe,EAAE,sBAAsB,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,IAAA,aAAI,EAAC,sCAAsC,EAAE,GAAG,EAAE;QAChD,IAAA,yBAAiB,EACf,GAAG,UAAU,kBAAkB,EAC/B;;2CAEqC,CACtC,CAAC;QACF,IAAA,yBAAiB,EACf,GAAG,UAAU,kBAAkB,EAC/B,sFAAsF,CACvF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,IAAA,aAAI,EAAC,8BAA8B,EAAE,GAAG,EAAE;QACxC,IAAA,yBAAiB,EACf,GAAG,UAAU,UAAU,EACvB;;;;;;;;;;;;;;;;IAgBF,CACC,CAAC;QACF,IAAA,yBAAiB,EACf,GAAG,UAAU,UAAU,EACvB,kCAAkC,CACnC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,IAAA,aAAI,EAAC,gCAAgC,EAAE,GAAG,EAAE;QAC1C,IAAI,CAAC,kBAAkB,EAAE;YACvB,OAAO;SACR;QACD,IAAA,yBAAiB,EACf,GAAG,UAAU,wBAAwB,EACrC,cAAc,iBAAS,CAAC,UAAU;;eAEzB,iBAAS,CAAC,QAAQ;mBACd,iBAAS,CAAC,YAAY;;gCAET,CAC3B,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,IAAA,aAAI,EAAC,oCAAoC,EAAE,GAAG,EAAE;QAC9C,IAAA,yBAAiB,EACf,GAAG,UAAU,4BAA4B,EACzC,cAAc,iBAAS,CAAC,UAAU;;eAEzB,iBAAS,CAAC,QAAQ;mBACd,iBAAS,CAAC,YAAY;;gCAET,CAC3B,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,IAAA,aAAI,EAAC,mCAAmC,EAAE,GAAG,EAAE;QAC7C,IAAA,yBAAiB,EACf,GAAG,UAAU,2BAA2B,EACxC,6IAA6I,CAC9I,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,IAAA,aAAI,EAAC,oCAAoC,EAAE,GAAG,EAAE;QAC9C,IAAI,CAAC,kBAAkB,EAAE;YACvB,OAAO;SACR;QACD,IAAA,yBAAiB,EACf,GAAG,UAAU,+CAA+C,EAC5D,8DAA8D,CAC/D,CAAC;QACF,IAAA,yBAAiB,EACf,GAAG,UAAU,+CAA+C,EAC5D,0EAA0E,CAC3E,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,IAAA,aAAI,EAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACtD,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAyB,EAAC,UAAU,EAAE,SAAS,CAAC,CAAC;QACvE,IAAA,eAAM,EAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,IAAA,aAAI,EAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QAClD,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAyB,EAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QACnE,IAAA,eAAM,EAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import * as path from 'node:path';\nimport { Integration } from '../../lib/Constants';\nimport {\n KEYS,\n TEST_ARGS,\n cleanupGit,\n checkFileContents,\n checkIfReactNativeBundles,\n revertLocalChanges,\n startWizardInstance\n} from '../utils';\nimport { afterAll, beforeAll, describe, test, expect } from 'vitest';\n\ndescribe('ReactNative', () => {\n const integration = Integration.reactNative;\n const projectDir = path.resolve(\n __dirname,\n '../test-applications/react-native-test-app',\n );\n\n let podInstallPrompted = false;\n\n beforeAll(async () => {\n const wizardInstance = startWizardInstance(integration, projectDir);\n const packageManagerPrompted = await wizardInstance.waitForOutput(\n 'Please select your package manager.',\n );\n const sessionReplayPrompted =\n packageManagerPrompted &&\n (await wizardInstance.sendStdinAndWaitForOutput(\n // Selecting `yarn` as the package manager\n [KEYS.DOWN, KEYS.DOWN, KEYS.ENTER],\n 'Do you want to enable Session Replay to help debug issues? (See https://docs.sentry.io/platforms/react-native/session-replay/)',\n ));\n\n const feedbackWidgetPrompted =\n sessionReplayPrompted &&\n (await wizardInstance.sendStdinAndWaitForOutput(\n // Enable session replay\n [KEYS.ENTER],\n 'Do you want to enable the Feedback Widget to collect feedback from your users? (See https://docs.sentry.io/platforms/react-native/user-feedback/)',\n ));\n\n podInstallPrompted =\n feedbackWidgetPrompted &&\n (await wizardInstance.sendStdinAndWaitForOutput(\n // Enable feedback widget\n [KEYS.ENTER],\n 'Do you want to run `pod install` now?',\n {\n optional: true,\n timeout: 5000,\n },\n ));\n\n const prettierPrompted =\n podInstallPrompted &&\n (await wizardInstance.sendStdinAndWaitForOutput(\n // Skip pod install\n [KEYS.DOWN, KEYS.ENTER],\n 'Looks like you have Prettier in your project. Do you want to run it on your files?',\n ));\n\n const testEventPrompted =\n prettierPrompted &&\n (await wizardInstance.sendStdinAndWaitForOutput(\n // Skip prettier\n [KEYS.DOWN, KEYS.ENTER],\n 'Have you successfully sent a test event?',\n ));\n\n testEventPrompted &&\n (await wizardInstance.sendStdinAndWaitForOutput(\n // Respond that test event was sent\n [KEYS.ENTER],\n 'Everything is set up!',\n ));\n wizardInstance.kill();\n });\n\n afterAll(() => {\n revertLocalChanges(projectDir);\n cleanupGit(projectDir);\n });\n\n test('package.json is updated correctly', () => {\n checkFileContents(`${projectDir}/package.json`, `@sentry/react-native`);\n });\n\n test('metro.config.js is updated correctly', () => {\n checkFileContents(\n `${projectDir}/metro.config.js`,\n `const {\n withSentryConfig\n} = require(\"@sentry/react-native/metro\");`,\n );\n checkFileContents(\n `${projectDir}/metro.config.js`,\n `module.exports = withSentryConfig(mergeConfig(getDefaultConfig(__dirname), config));`,\n );\n });\n\n test('App.tsx is updated correctly', () => {\n checkFileContents(\n `${projectDir}/App.tsx`,\n `import * as Sentry from '@sentry/react-native';\n\nSentry.init({\n dsn: 'https://public@dsn.ingest.sentry.io/1337',\n\n // Adds more context data to events (IP address, cookies, user, etc.)\n // For more information, visit: https://docs.sentry.io/platforms/react-native/data-management/data-collected/\n sendDefaultPii: true,\n\n // Configure Session Replay\n replaysSessionSampleRate: 0.1,\n replaysOnErrorSampleRate: 1,\n integrations: [Sentry.mobileReplayIntegration(), Sentry.feedbackIntegration()],\n\n // uncomment the line below to enable Spotlight (https://spotlightjs.com)\n // spotlight: __DEV__,\n});`,\n );\n checkFileContents(\n `${projectDir}/App.tsx`,\n `export default Sentry.wrap(App);`,\n );\n });\n\n test('ios/sentry.properties is added', () => {\n if (!podInstallPrompted) {\n return;\n }\n checkFileContents(\n `${projectDir}/ios/sentry.properties`,\n `auth.token=${TEST_ARGS.AUTH_TOKEN}\n\ndefaults.org=${TEST_ARGS.ORG_SLUG}\ndefaults.project=${TEST_ARGS.PROJECT_SLUG}\n\ndefaults.url=https://sentry.io/`,\n );\n });\n\n test('android/sentry.properties is added', () => {\n checkFileContents(\n `${projectDir}/android/sentry.properties`,\n `auth.token=${TEST_ARGS.AUTH_TOKEN}\n\ndefaults.org=${TEST_ARGS.ORG_SLUG}\ndefaults.project=${TEST_ARGS.PROJECT_SLUG}\n\ndefaults.url=https://sentry.io/`,\n );\n });\n\n test('build.gradle is updated correctly', () => {\n checkFileContents(\n `${projectDir}/android/app/build.gradle`,\n `apply from: new File([\"node\", \"--print\", \"require.resolve('@sentry/react-native/package.json')\"].execute().text.trim(), \"../sentry.gradle\")`,\n );\n });\n\n test('xcode project is updated correctly', () => {\n if (!podInstallPrompted) {\n return;\n }\n checkFileContents(\n `${projectDir}/ios/reactnative078.xcodeproj/project.pbxproj`,\n `../node_modules/@sentry/react-native/scripts/sentry-xcode.sh`,\n );\n checkFileContents(\n `${projectDir}/ios/reactnative078.xcodeproj/project.pbxproj`,\n `../node_modules/@sentry/react-native/scripts/sentry-xcode-debug-files.sh`,\n );\n });\n\n test('android project is bundled correctly', async () => {\n const bundled = await checkIfReactNativeBundles(projectDir, 'android');\n expect(bundled).toBe(true);\n });\n\n test('ios project is bundled correctly', async () => {\n const bundled = await checkIfReactNativeBundles(projectDir, 'ios');\n expect(bundled).toBe(true);\n });\n});\n"]}
|
|
@@ -160,6 +160,22 @@ export declare function checkIfBuilds(projectDir: string): Promise<void>;
|
|
|
160
160
|
* @param projectDir
|
|
161
161
|
*/
|
|
162
162
|
export declare function checkIfFlutterBuilds(projectDir: string, expectedOutput: string, debug?: boolean): Promise<void>;
|
|
163
|
+
/**
|
|
164
|
+
* Check if the React Native project bundles successfully for the specified platform.
|
|
165
|
+
* Returns a boolean indicating if the process exits with status code 0.
|
|
166
|
+
* @param projectDir The root directory of the React Native project.
|
|
167
|
+
* @param platform The platform to bundle for ('ios' or 'android').
|
|
168
|
+
* @param debug runs the command in debug mode if true
|
|
169
|
+
*/
|
|
170
|
+
export declare function checkIfReactNativeBundles(projectDir: string, platform: 'ios' | 'android', debug?: boolean): Promise<boolean>;
|
|
171
|
+
/**
|
|
172
|
+
* Check if the Expo project exports successfully for the specified platform.
|
|
173
|
+
* Returns a boolean indicating if the process exits with status code 0.
|
|
174
|
+
* @param projectDir The root directory of the Expo project.
|
|
175
|
+
* @param platform The platform to export for ('ios', 'android', or 'web').
|
|
176
|
+
* @param debug runs the command in debug mode if true
|
|
177
|
+
*/
|
|
178
|
+
export declare function checkIfExpoBundles(projectDir: string, platform: 'ios' | 'android' | 'web', debug?: boolean): Promise<boolean>;
|
|
163
179
|
/**
|
|
164
180
|
* Check if the project runs on dev mode
|
|
165
181
|
* @param projectDir
|
|
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.checkIfRunsOnProdMode = exports.checkIfRunsOnDevMode = exports.checkIfFlutterBuilds = exports.checkIfBuilds = exports.checkSentryProperties = exports.checkEnvBuildPlugin = exports.checkSentryCliRc = exports.checkPackageJson = exports.checkFileExists = exports.checkFileContents = exports.checkFileDoesNotContain = exports.modifyFile = exports.createFile = exports.startWizardInstance = exports.getWizardCommand = exports.revertLocalChanges = exports.cleanupGit = exports.initGit = exports.WizardTestEnv = exports.log = exports.TEST_ARGS = exports.KEYS = void 0;
|
|
26
|
+
exports.checkIfRunsOnProdMode = exports.checkIfRunsOnDevMode = exports.checkIfExpoBundles = exports.checkIfReactNativeBundles = exports.checkIfFlutterBuilds = exports.checkIfBuilds = exports.checkSentryProperties = exports.checkEnvBuildPlugin = exports.checkSentryCliRc = exports.checkPackageJson = exports.checkFileExists = exports.checkFileContents = exports.checkFileDoesNotContain = exports.modifyFile = exports.createFile = exports.startWizardInstance = exports.getWizardCommand = exports.revertLocalChanges = exports.cleanupGit = exports.initGit = exports.WizardTestEnv = exports.log = exports.TEST_ARGS = exports.KEYS = void 0;
|
|
27
27
|
const fs = __importStar(require("node:fs"));
|
|
28
28
|
const path = __importStar(require("node:path"));
|
|
29
29
|
const node_child_process_1 = require("node:child_process");
|
|
@@ -425,6 +425,77 @@ async function checkIfFlutterBuilds(projectDir, expectedOutput, debug = false) {
|
|
|
425
425
|
(0, vitest_1.expect)(outputReceived).toBe(true);
|
|
426
426
|
}
|
|
427
427
|
exports.checkIfFlutterBuilds = checkIfFlutterBuilds;
|
|
428
|
+
/**
|
|
429
|
+
* Check if the React Native project bundles successfully for the specified platform.
|
|
430
|
+
* Returns a boolean indicating if the process exits with status code 0.
|
|
431
|
+
* @param projectDir The root directory of the React Native project.
|
|
432
|
+
* @param platform The platform to bundle for ('ios' or 'android').
|
|
433
|
+
* @param debug runs the command in debug mode if true
|
|
434
|
+
*/
|
|
435
|
+
async function checkIfReactNativeBundles(projectDir, platform, debug = false) {
|
|
436
|
+
const entryFile = 'index.js';
|
|
437
|
+
const dev = 'false'; // Test a production-like bundle
|
|
438
|
+
let bundleOutput;
|
|
439
|
+
let assetsDest;
|
|
440
|
+
if (platform === 'ios') {
|
|
441
|
+
bundleOutput = './ios/main.jsbundle';
|
|
442
|
+
assetsDest = './ios';
|
|
443
|
+
}
|
|
444
|
+
else {
|
|
445
|
+
// android
|
|
446
|
+
bundleOutput = './android/app/src/main/assets/index.android.bundle';
|
|
447
|
+
assetsDest = './android/app/src/main/res';
|
|
448
|
+
}
|
|
449
|
+
const bundleCommandArgs = [
|
|
450
|
+
'react-native',
|
|
451
|
+
'bundle',
|
|
452
|
+
'--entry-file',
|
|
453
|
+
entryFile,
|
|
454
|
+
'--platform',
|
|
455
|
+
platform,
|
|
456
|
+
'--dev',
|
|
457
|
+
dev,
|
|
458
|
+
'--bundle-output',
|
|
459
|
+
bundleOutput,
|
|
460
|
+
'--assets-dest',
|
|
461
|
+
assetsDest,
|
|
462
|
+
];
|
|
463
|
+
const testEnv = new WizardTestEnv('npx', bundleCommandArgs, {
|
|
464
|
+
cwd: projectDir,
|
|
465
|
+
debug: debug,
|
|
466
|
+
});
|
|
467
|
+
const builtSuccessfully = await testEnv.waitForStatusCode(0, {
|
|
468
|
+
timeout: 300000,
|
|
469
|
+
});
|
|
470
|
+
testEnv.kill();
|
|
471
|
+
return builtSuccessfully;
|
|
472
|
+
}
|
|
473
|
+
exports.checkIfReactNativeBundles = checkIfReactNativeBundles;
|
|
474
|
+
/**
|
|
475
|
+
* Check if the Expo project exports successfully for the specified platform.
|
|
476
|
+
* Returns a boolean indicating if the process exits with status code 0.
|
|
477
|
+
* @param projectDir The root directory of the Expo project.
|
|
478
|
+
* @param platform The platform to export for ('ios', 'android', or 'web').
|
|
479
|
+
* @param debug runs the command in debug mode if true
|
|
480
|
+
*/
|
|
481
|
+
async function checkIfExpoBundles(projectDir, platform, debug = false) {
|
|
482
|
+
const exportCommandArgs = [
|
|
483
|
+
'expo',
|
|
484
|
+
'export',
|
|
485
|
+
'--platform',
|
|
486
|
+
platform,
|
|
487
|
+
];
|
|
488
|
+
const testEnv = new WizardTestEnv('npx', exportCommandArgs, {
|
|
489
|
+
cwd: projectDir,
|
|
490
|
+
debug: debug,
|
|
491
|
+
});
|
|
492
|
+
const builtSuccessfully = await testEnv.waitForStatusCode(0, {
|
|
493
|
+
timeout: 300000,
|
|
494
|
+
});
|
|
495
|
+
testEnv.kill();
|
|
496
|
+
return builtSuccessfully;
|
|
497
|
+
}
|
|
498
|
+
exports.checkIfExpoBundles = checkIfExpoBundles;
|
|
428
499
|
/**
|
|
429
500
|
* Check if the project runs on dev mode
|
|
430
501
|
* @param projectDir
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../e2e-tests/utils/index.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport type { Integration } from '../../lib/Constants';\nimport { spawn, execSync } from 'node:child_process';\nimport type { ChildProcess } from 'node:child_process';\nimport { dim, green, red } from '../../lib/Helper/Logging';\nimport { expect } from 'vitest';\n\nexport const KEYS = {\n UP: '\\u001b[A',\n DOWN: '\\u001b[B',\n LEFT: '\\u001b[D',\n RIGHT: '\\u001b[C',\n ENTER: '\\r',\n SPACE: ' ',\n};\n\nexport const TEST_ARGS = {\n AUTH_TOKEN: process.env.SENTRY_TEST_AUTH_TOKEN || 'TEST_AUTH_TOKEN',\n PROJECT_DSN:\n process.env.SENTRY_TEST_DSN || 'https://public@dsn.ingest.sentry.io/1337',\n ORG_SLUG: process.env.SENTRY_TEST_ORG || 'TEST_ORG_SLUG',\n PROJECT_SLUG: process.env.SENTRY_TEST_PROJECT || 'TEST_PROJECT_SLUG',\n};\n\nexport const log = {\n success: (message: string) => {\n green(`[SUCCESS] ${message}`);\n },\n info: (message: string) => {\n dim(`[INFO] ${message}`);\n },\n error: (message: unknown) => {\n function formatMessage(message: unknown, depth: number): string {\n if (depth > 3) {\n return '...';\n }\n\n if (message instanceof Error) {\n return JSON.stringify(\n {\n name: message.name,\n message: message.message,\n stack: message.stack,\n ...(message.cause\n ? {\n cause: formatMessage(message.cause, depth + 1),\n }\n : {}),\n },\n null,\n 2,\n );\n }\n return String(message);\n }\n red(`[ERROR] ${formatMessage(message, 0)}`);\n },\n};\n\nexport class WizardTestEnv {\n taskHandle: ChildProcess;\n\n constructor(\n cmd: string,\n args: string[],\n opts?: {\n cwd?: string;\n debug?: boolean;\n },\n ) {\n this.taskHandle = spawn(cmd, args, { cwd: opts?.cwd, stdio: 'pipe' });\n\n if (opts?.debug) {\n this.taskHandle.stdout?.pipe(process.stdout);\n this.taskHandle.stderr?.pipe(process.stderr);\n }\n }\n\n sendStdin(input: string) {\n this.taskHandle.stdin?.write(input);\n }\n\n /**\n * Sends the input and waits for the output.\n * @returns a promise that resolves when the output was found\n * @throws an error when the output was not found within the timeout\n */\n sendStdinAndWaitForOutput(\n input: string | string[],\n output: string,\n options?: { timeout?: number; optional?: boolean },\n ) {\n const outputPromise = this.waitForOutput(output, options);\n\n if (Array.isArray(input)) {\n for (const i of input) {\n this.sendStdin(i);\n }\n } else {\n this.sendStdin(input);\n }\n return outputPromise;\n }\n\n /**\n * Waits for the task to exit with a given `statusCode`.\n *\n * @returns a promise that resolves to `true` if the run ends with the status\n * code, or it rejects when the `timeout` was reached.\n */\n waitForStatusCode(\n statusCode: number | null,\n options: {\n /** Timeout in ms */\n timeout?: number;\n } = {},\n ) {\n const { timeout } = {\n timeout: 60_000,\n ...options,\n };\n\n return new Promise<boolean>((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n this.kill();\n reject(\n new Error(`Timeout waiting for status code: ${statusCode ?? 'null'}`),\n );\n }, timeout);\n\n this.taskHandle.on('error', (err: Error) => {\n clearTimeout(timeoutId);\n reject(err);\n });\n\n this.taskHandle.on('exit', (code: number | null) => {\n clearTimeout(timeoutId);\n resolve(code === statusCode);\n });\n });\n }\n\n /**\n * Waits for the provided output with `.includes()` logic.\n *\n * @returns a promise that resolves to `true` if the output was found, `false` if the output was not found within the\n * timeout and `optional: true` is set, or it rejects when the timeout was reached with `optional: false`\n */\n waitForOutput(\n output: string,\n options: {\n /** Timeout in ms */\n timeout?: number;\n /** Whether to always resolve after the timeout, no matter whether the input was actually found or not. */\n optional?: boolean;\n } = {},\n ) {\n const { timeout, optional } = {\n timeout: 60_000,\n optional: false,\n ...options,\n };\n\n return new Promise<boolean>((resolve, reject) => {\n let outputBuffer = '';\n const timeoutId = setTimeout(() => {\n this.taskHandle.off('error', errorListener);\n this.taskHandle.stdout?.off('data', dataListener);\n\n this.kill();\n if (optional) {\n // The output is not found but it's optional so we can resolve the promise with false\n resolve(false);\n } else {\n reject(\n new Error(\n `Timeout waiting for output: ${output}. Got the following instead: ${outputBuffer}`,\n ),\n );\n }\n }, timeout);\n\n const dataListener = (data: string) => {\n outputBuffer += data;\n if (outputBuffer.includes(output)) {\n clearTimeout(timeoutId);\n this.taskHandle.off('error', errorListener);\n this.taskHandle.stdout?.off('data', dataListener);\n // The output is found so we can resolve the promise with true\n resolve(true);\n }\n };\n\n const errorListener = (err: Error) => {\n this.taskHandle.off('error', errorListener);\n this.taskHandle.stdout?.off('data', dataListener);\n clearTimeout(timeoutId);\n reject(err);\n };\n\n this.taskHandle.on('error', errorListener);\n this.taskHandle.stdout?.on('data', dataListener);\n });\n }\n\n kill() {\n this.taskHandle.stdin?.destroy();\n this.taskHandle.stderr?.destroy();\n this.taskHandle.stdout?.destroy();\n this.taskHandle.kill('SIGINT');\n this.taskHandle.unref();\n }\n}\n\n/**\n * Initialize a git repository in the given directory\n * @param projectDir\n */\nexport function initGit(projectDir: string): void {\n try {\n execSync('git init', { cwd: projectDir });\n // Add all files to the git repo\n execSync('git add -A', { cwd: projectDir });\n // Add author info to avoid git commit error\n execSync('git config user.email test@test.sentry.io', { cwd: projectDir });\n execSync('git config user.name Test', { cwd: projectDir });\n execSync('git commit -m init', { cwd: projectDir });\n } catch (e) {\n log.error('Error initializing git');\n log.error(e);\n }\n}\n\n/**\n * Cleanup the git repository in the given directory\n *\n * Caution! Make sure `projectDir` is a test project directory,\n * if in doubt, please commit your local non-test changes first!\n * @param projectDir\n */\nexport function cleanupGit(projectDir: string): void {\n try {\n // Remove the .git directory\n execSync(`rm -rf ${projectDir}/.git`);\n } catch (e) {\n log.error('Error cleaning up git');\n log.error(e);\n }\n}\n\n/**\n * Revert local changes in the given directory\n *\n * Caution! Make sure `projectDir` is a test project directory,\n * if in doubt, please commit your local non-test changes first!\n *\n * @param projectDir\n */\nexport function revertLocalChanges(projectDir: string): void {\n try {\n // Revert tracked files\n execSync('git restore .', { cwd: projectDir });\n // Revert untracked files\n execSync('git clean -fd .', { cwd: projectDir });\n // Remove node_modules and dist (.gitignore'd and therefore not removed via git clean)\n execSync('rm -rf node_modules', { cwd: projectDir });\n execSync('rm -rf dist', { cwd: projectDir });\n } catch (e) {\n log.error('Error reverting local changes');\n log.error(e);\n }\n}\n\nexport function getWizardCommand(integration: Integration): string {\n const binName = process.env.SENTRY_WIZARD_E2E_TEST_BIN\n ? ['dist-bin', `sentry-wizard-${process.platform}-${process.arch}`]\n : ['dist', 'bin.js'];\n const binPath = path.join(__dirname, '..', '..', ...binName);\n\n const args = [\n '--debug',\n '-i',\n integration,\n '--preSelectedProject.authToken',\n TEST_ARGS.AUTH_TOKEN,\n '--preSelectedProject.dsn',\n TEST_ARGS.PROJECT_DSN,\n '--preSelectedProject.orgSlug',\n TEST_ARGS.ORG_SLUG,\n '--preSelectedProject.projectSlug',\n TEST_ARGS.PROJECT_SLUG,\n '--disable-telemetry',\n ];\n\n return `${binPath} ${args.join(' ')}`;\n}\n\n/**\n * Start the wizard instance with the given integration and project directory\n * @param integration\n * @param projectDir\n *\n * @returns WizardTestEnv\n */\nexport function startWizardInstance(\n integration: Integration,\n projectDir: string,\n debug = false,\n): WizardTestEnv {\n const binName = process.env.SENTRY_WIZARD_E2E_TEST_BIN\n ? ['dist-bin', `sentry-wizard-${process.platform}-${process.arch}`]\n : ['dist', 'bin.js'];\n const binPath = path.join(__dirname, '..', '..', ...binName);\n\n revertLocalChanges(projectDir);\n cleanupGit(projectDir);\n initGit(projectDir);\n\n return new WizardTestEnv(\n binPath,\n [\n '--debug',\n '-i',\n integration,\n '--preSelectedProject.authToken',\n TEST_ARGS.AUTH_TOKEN,\n '--preSelectedProject.dsn',\n TEST_ARGS.PROJECT_DSN,\n '--preSelectedProject.orgSlug',\n TEST_ARGS.ORG_SLUG,\n '--preSelectedProject.projectSlug',\n TEST_ARGS.PROJECT_SLUG,\n '--disable-telemetry',\n ],\n { cwd: projectDir, debug },\n );\n}\n\n/**\n * Create a file with the given content\n *\n * @param filePath\n * @param content\n */\nexport function createFile(filePath: string, content?: string) {\n return fs.writeFileSync(filePath, content || '');\n}\n\n/**\n * Modify the file with the new content\n *\n * @param filePath\n * @param oldContent\n * @param newContent\n */\nexport function modifyFile(\n filePath: string,\n replaceMap: Record<string, string>,\n) {\n const fileContent = fs.readFileSync(filePath, 'utf-8');\n let newFileContent = fileContent;\n\n for (const [oldContent, newContent] of Object.entries(replaceMap)) {\n newFileContent = newFileContent.replace(oldContent, newContent);\n }\n\n fs.writeFileSync(filePath, newFileContent);\n}\n\n/**\n * Read the file contents and check if it does not contain the given content\n *\n * @param {string} filePath\n * @param {(string | string[])} content\n */\nexport function checkFileDoesNotContain(\n filePath: string,\n content: string | string[],\n) {\n const fileContent = fs.readFileSync(filePath, 'utf-8');\n const contentArray = Array.isArray(content) ? content : [content];\n\n for (const c of contentArray) {\n expect(fileContent).not.toContain(c);\n }\n}\n\n/**\n * Read the file contents and check if it contains the given content\n *\n * @param {string} filePath\n * @param {(string | string[])} content\n */\nexport function checkFileContents(\n filePath: string,\n content: string | string[],\n) {\n const fileContent = fs.readFileSync(filePath, 'utf-8');\n const contentArray = Array.isArray(content) ? content : [content];\n\n for (const c of contentArray) {\n expect(fileContent).toContain(c);\n }\n}\n\n/**\n * Check if the file exists\n *\n * @param filePath\n */\nexport function checkFileExists(filePath: string) {\n expect(fs.existsSync(filePath)).toBe(true);\n}\n\n/**\n * Check if the package.json contains the given integration\n *\n * @param projectDir\n * @param integration\n */\nexport function checkPackageJson(projectDir: string, integration: Integration) {\n checkFileContents(`${projectDir}/package.json`, `@sentry/${integration}`);\n}\n\n/**\n * Check if the .sentryclirc contains the auth token\n *\n * @param projectDir\n */\nexport function checkSentryCliRc(projectDir: string) {\n checkFileContents(\n `${projectDir}/.sentryclirc`,\n `token=${TEST_ARGS.AUTH_TOKEN}`,\n );\n}\n\n/**\n * Check if the .env.sentry-build-plugin contains the auth token\n * @param projectDir\n */\nexport function checkEnvBuildPlugin(projectDir: string) {\n checkFileContents(\n `${projectDir}/.env.sentry-build-plugin`,\n `SENTRY_AUTH_TOKEN=${TEST_ARGS.AUTH_TOKEN}`,\n );\n}\n\n/**\n * Check if the sentry.properties contains the auth token\n * @param projectDir\n */\nexport function checkSentryProperties(projectDir: string) {\n checkFileContents(\n `${projectDir}/sentry.properties`,\n `auth_token=${TEST_ARGS.AUTH_TOKEN}`,\n );\n}\n\n/**\n * Check if the project builds\n * Check if the project builds and ends with status code 0.\n * @param projectDir\n */\nexport async function checkIfBuilds(projectDir: string) {\n const testEnv = new WizardTestEnv('npm', ['run', 'build'], {\n cwd: projectDir,\n });\n\n const builtSuccessfully = await testEnv.waitForStatusCode(0, {\n timeout: 120_000,\n });\n\n expect(builtSuccessfully).toBe(true);\n}\n\n/**\n * Check if the flutter project builds\n * @param projectDir\n */\nexport async function checkIfFlutterBuilds(\n projectDir: string,\n expectedOutput: string,\n debug = false,\n) {\n const testEnv = new WizardTestEnv('flutter', ['build', 'web'], {\n cwd: projectDir,\n debug: debug,\n });\n\n const outputReceived = await testEnv.waitForOutput(expectedOutput, {\n timeout: 120_000,\n });\n\n expect(outputReceived).toBe(true);\n}\n\n/**\n * Check if the project runs on dev mode\n * @param projectDir\n * @param expectedOutput\n */\nexport async function checkIfRunsOnDevMode(\n projectDir: string,\n expectedOutput: string,\n) {\n const testEnv = new WizardTestEnv('npm', ['run', 'dev'], { cwd: projectDir });\n\n expect(\n await testEnv.waitForOutput(expectedOutput, {\n timeout: 120_000,\n }),\n ).toBe(true);\n\n testEnv.kill();\n}\n\n/**\n * Check if the project runs on prod mode\n * @param projectDir\n * @param expectedOutput\n */\nexport async function checkIfRunsOnProdMode(\n projectDir: string,\n expectedOutput: string,\n startCommand = 'start',\n) {\n const testEnv = new WizardTestEnv('npm', ['run', startCommand], {\n cwd: projectDir,\n });\n\n expect(\n await testEnv.waitForOutput(expectedOutput, {\n timeout: 120_000,\n }),\n ).toBe(true);\n\n testEnv.kill();\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../e2e-tests/utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,4CAA8B;AAC9B,gDAAkC;AAGlC,2DAAqD;AAErD,sDAA2D;AAC3D,mCAAgC;AAEnB,QAAA,IAAI,GAAG;IAClB,EAAE,EAAE,UAAU;IACd,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,UAAU;IACjB,KAAK,EAAE,IAAI;IACX,KAAK,EAAE,GAAG;CACX,CAAC;AAEW,QAAA,SAAS,GAAG;IACvB,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,iBAAiB;IACnE,WAAW,EACT,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,0CAA0C;IAC3E,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,eAAe;IACxD,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,mBAAmB;CACrE,CAAC;AAEW,QAAA,GAAG,GAAG;IACjB,OAAO,EAAE,CAAC,OAAe,EAAE,EAAE;QAC3B,IAAA,eAAK,EAAC,aAAa,OAAO,EAAE,CAAC,CAAC;IAChC,CAAC;IACD,IAAI,EAAE,CAAC,OAAe,EAAE,EAAE;QACxB,IAAA,aAAG,EAAC,UAAU,OAAO,EAAE,CAAC,CAAC;IAC3B,CAAC;IACD,KAAK,EAAE,CAAC,OAAgB,EAAE,EAAE;QAC1B,SAAS,aAAa,CAAC,OAAgB,EAAE,KAAa;YACpD,IAAI,KAAK,GAAG,CAAC,EAAE;gBACb,OAAO,KAAK,CAAC;aACd;YAED,IAAI,OAAO,YAAY,KAAK,EAAE;gBAC5B,OAAO,IAAI,CAAC,SAAS,CACnB;oBACE,IAAI,EAAE,OAAO,CAAC,IAAI;oBAClB,OAAO,EAAE,OAAO,CAAC,OAAO;oBACxB,KAAK,EAAE,OAAO,CAAC,KAAK;oBACpB,GAAG,CAAC,OAAO,CAAC,KAAK;wBACf,CAAC,CAAC;4BACE,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC;yBAC/C;wBACH,CAAC,CAAC,EAAE,CAAC;iBACR,EACD,IAAI,EACJ,CAAC,CACF,CAAC;aACH;YACD,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC;QACzB,CAAC;QACD,IAAA,aAAG,EAAC,WAAW,aAAa,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IAC9C,CAAC;CACF,CAAC;AAEF,MAAa,aAAa;IACxB,UAAU,CAAe;IAEzB,YACE,GAAW,EACX,IAAc,EACd,IAGC;QAED,IAAI,CAAC,UAAU,GAAG,IAAA,0BAAK,EAAC,GAAG,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAEtE,IAAI,IAAI,EAAE,KAAK,EAAE;YACf,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAC7C,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;SAC9C;IACH,CAAC;IAED,SAAS,CAAC,KAAa;QACrB,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC;IAED;;;;OAIG;IACH,yBAAyB,CACvB,KAAwB,EACxB,MAAc,EACd,OAAkD;QAElD,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAE1D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YACxB,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE;gBACrB,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;aACnB;SACF;aAAM;YACL,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;SACvB;QACD,OAAO,aAAa,CAAC;IACvB,CAAC;IAED;;;;;OAKG;IACH,iBAAiB,CACf,UAAyB,EACzB,UAGI,EAAE;QAEN,MAAM,EAAE,OAAO,EAAE,GAAG;YAClB,OAAO,EAAE,KAAM;YACf,GAAG,OAAO;SACX,CAAC;QAEF,OAAO,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC9C,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;gBAChC,IAAI,CAAC,IAAI,EAAE,CAAC;gBACZ,MAAM,CACJ,IAAI,KAAK,CAAC,oCAAoC,UAAU,IAAI,MAAM,EAAE,CAAC,CACtE,CAAC;YACJ,CAAC,EAAE,OAAO,CAAC,CAAC;YAEZ,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAU,EAAE,EAAE;gBACzC,YAAY,CAAC,SAAS,CAAC,CAAC;gBACxB,MAAM,CAAC,GAAG,CAAC,CAAC;YACd,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAmB,EAAE,EAAE;gBACjD,YAAY,CAAC,SAAS,CAAC,CAAC;gBACxB,OAAO,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC;YAC/B,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACH,aAAa,CACX,MAAc,EACd,UAKI,EAAE;QAEN,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG;YAC5B,OAAO,EAAE,KAAM;YACf,QAAQ,EAAE,KAAK;YACf,GAAG,OAAO;SACX,CAAC;QAEF,OAAO,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC9C,IAAI,YAAY,GAAG,EAAE,CAAC;YACtB,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;gBAChC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;gBAC5C,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;gBAElD,IAAI,CAAC,IAAI,EAAE,CAAC;gBACZ,IAAI,QAAQ,EAAE;oBACZ,qFAAqF;oBACrF,OAAO,CAAC,KAAK,CAAC,CAAC;iBAChB;qBAAM;oBACL,MAAM,CACJ,IAAI,KAAK,CACP,+BAA+B,MAAM,gCAAgC,YAAY,EAAE,CACpF,CACF,CAAC;iBACH;YACH,CAAC,EAAE,OAAO,CAAC,CAAC;YAEZ,MAAM,YAAY,GAAG,CAAC,IAAY,EAAE,EAAE;gBACpC,YAAY,IAAI,IAAI,CAAC;gBACrB,IAAI,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE;oBACjC,YAAY,CAAC,SAAS,CAAC,CAAC;oBACxB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;oBAC5C,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;oBAClD,8DAA8D;oBAC9D,OAAO,CAAC,IAAI,CAAC,CAAC;iBACf;YACH,CAAC,CAAC;YAEF,MAAM,aAAa,GAAG,CAAC,GAAU,EAAE,EAAE;gBACnC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;gBAC5C,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;gBAClD,YAAY,CAAC,SAAS,CAAC,CAAC;gBACxB,MAAM,CAAC,GAAG,CAAC,CAAC;YACd,CAAC,CAAC;YAEF,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;YAC3C,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC;IACL,CAAC;IAED,IAAI;QACF,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC;QACjC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;QAClC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;QAClC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC/B,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IAC1B,CAAC;CACF;AAzJD,sCAyJC;AAED;;;GAGG;AACH,SAAgB,OAAO,CAAC,UAAkB;IACxC,IAAI;QACF,IAAA,6BAAQ,EAAC,UAAU,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;QAC1C,gCAAgC;QAChC,IAAA,6BAAQ,EAAC,YAAY,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;QAC5C,4CAA4C;QAC5C,IAAA,6BAAQ,EAAC,2CAA2C,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;QAC3E,IAAA,6BAAQ,EAAC,2BAA2B,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;QAC3D,IAAA,6BAAQ,EAAC,oBAAoB,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;KACrD;IAAC,OAAO,CAAC,EAAE;QACV,WAAG,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;QACpC,WAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;KACd;AACH,CAAC;AAbD,0BAaC;AAED;;;;;;GAMG;AACH,SAAgB,UAAU,CAAC,UAAkB;IAC3C,IAAI;QACF,4BAA4B;QAC5B,IAAA,6BAAQ,EAAC,UAAU,UAAU,OAAO,CAAC,CAAC;KACvC;IAAC,OAAO,CAAC,EAAE;QACV,WAAG,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACnC,WAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;KACd;AACH,CAAC;AARD,gCAQC;AAED;;;;;;;GAOG;AACH,SAAgB,kBAAkB,CAAC,UAAkB;IACnD,IAAI;QACF,uBAAuB;QACvB,IAAA,6BAAQ,EAAC,eAAe,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;QAC/C,yBAAyB;QACzB,IAAA,6BAAQ,EAAC,iBAAiB,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;QACjD,sFAAsF;QACtF,IAAA,6BAAQ,EAAC,qBAAqB,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;QACrD,IAAA,6BAAQ,EAAC,aAAa,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;KAC9C;IAAC,OAAO,CAAC,EAAE;QACV,WAAG,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;QAC3C,WAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;KACd;AACH,CAAC;AAbD,gDAaC;AAED,SAAgB,gBAAgB,CAAC,WAAwB;IACvD,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,0BAA0B;QACpD,CAAC,CAAC,CAAC,UAAU,EAAE,iBAAiB,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACnE,CAAC,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACvB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,CAAC;IAE7D,MAAM,IAAI,GAAG;QACX,SAAS;QACT,IAAI;QACJ,WAAW;QACX,gCAAgC;QAChC,iBAAS,CAAC,UAAU;QACpB,0BAA0B;QAC1B,iBAAS,CAAC,WAAW;QACrB,8BAA8B;QAC9B,iBAAS,CAAC,QAAQ;QAClB,kCAAkC;QAClC,iBAAS,CAAC,YAAY;QACtB,qBAAqB;KACtB,CAAC;IAEF,OAAO,GAAG,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;AACxC,CAAC;AAtBD,4CAsBC;AAED;;;;;;GAMG;AACH,SAAgB,mBAAmB,CACjC,WAAwB,EACxB,UAAkB,EAClB,KAAK,GAAG,KAAK;IAEb,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,0BAA0B;QACpD,CAAC,CAAC,CAAC,UAAU,EAAE,iBAAiB,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACnE,CAAC,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACvB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,CAAC;IAE7D,kBAAkB,CAAC,UAAU,CAAC,CAAC;IAC/B,UAAU,CAAC,UAAU,CAAC,CAAC;IACvB,OAAO,CAAC,UAAU,CAAC,CAAC;IAEpB,OAAO,IAAI,aAAa,CACtB,OAAO,EACP;QACE,SAAS;QACT,IAAI;QACJ,WAAW;QACX,gCAAgC;QAChC,iBAAS,CAAC,UAAU;QACpB,0BAA0B;QAC1B,iBAAS,CAAC,WAAW;QACrB,8BAA8B;QAC9B,iBAAS,CAAC,QAAQ;QAClB,kCAAkC;QAClC,iBAAS,CAAC,YAAY;QACtB,qBAAqB;KACtB,EACD,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,CAC3B,CAAC;AACJ,CAAC;AAhCD,kDAgCC;AAED;;;;;GAKG;AACH,SAAgB,UAAU,CAAC,QAAgB,EAAE,OAAgB;IAC3D,OAAO,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC;AACnD,CAAC;AAFD,gCAEC;AAED;;;;;;GAMG;AACH,SAAgB,UAAU,CACxB,QAAgB,EAChB,UAAkC;IAElC,MAAM,WAAW,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACvD,IAAI,cAAc,GAAG,WAAW,CAAC;IAEjC,KAAK,MAAM,CAAC,UAAU,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE;QACjE,cAAc,GAAG,cAAc,CAAC,OAAO,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;KACjE;IAED,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;AAC7C,CAAC;AAZD,gCAYC;AAED;;;;;GAKG;AACH,SAAgB,uBAAuB,CACrC,QAAgB,EAChB,OAA0B;IAE1B,MAAM,WAAW,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACvD,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAElE,KAAK,MAAM,CAAC,IAAI,YAAY,EAAE;QAC5B,IAAA,eAAM,EAAC,WAAW,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;KACtC;AACH,CAAC;AAVD,0DAUC;AAED;;;;;GAKG;AACH,SAAgB,iBAAiB,CAC/B,QAAgB,EAChB,OAA0B;IAE1B,MAAM,WAAW,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACvD,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAElE,KAAK,MAAM,CAAC,IAAI,YAAY,EAAE;QAC5B,IAAA,eAAM,EAAC,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;KAClC;AACH,CAAC;AAVD,8CAUC;AAED;;;;GAIG;AACH,SAAgB,eAAe,CAAC,QAAgB;IAC9C,IAAA,eAAM,EAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC7C,CAAC;AAFD,0CAEC;AAED;;;;;GAKG;AACH,SAAgB,gBAAgB,CAAC,UAAkB,EAAE,WAAwB;IAC3E,iBAAiB,CAAC,GAAG,UAAU,eAAe,EAAE,WAAW,WAAW,EAAE,CAAC,CAAC;AAC5E,CAAC;AAFD,4CAEC;AAED;;;;GAIG;AACH,SAAgB,gBAAgB,CAAC,UAAkB;IACjD,iBAAiB,CACf,GAAG,UAAU,eAAe,EAC5B,SAAS,iBAAS,CAAC,UAAU,EAAE,CAChC,CAAC;AACJ,CAAC;AALD,4CAKC;AAED;;;GAGG;AACH,SAAgB,mBAAmB,CAAC,UAAkB;IACpD,iBAAiB,CACf,GAAG,UAAU,2BAA2B,EACxC,qBAAqB,iBAAS,CAAC,UAAU,EAAE,CAC5C,CAAC;AACJ,CAAC;AALD,kDAKC;AAED;;;GAGG;AACH,SAAgB,qBAAqB,CAAC,UAAkB;IACtD,iBAAiB,CACf,GAAG,UAAU,oBAAoB,EACjC,cAAc,iBAAS,CAAC,UAAU,EAAE,CACrC,CAAC;AACJ,CAAC;AALD,sDAKC;AAED;;;;GAIG;AACI,KAAK,UAAU,aAAa,CAAC,UAAkB;IACpD,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE;QACzD,GAAG,EAAE,UAAU;KAChB,CAAC,CAAC;IAEH,MAAM,iBAAiB,GAAG,MAAM,OAAO,CAAC,iBAAiB,CAAC,CAAC,EAAE;QAC3D,OAAO,EAAE,MAAO;KACjB,CAAC,CAAC;IAEH,IAAA,eAAM,EAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACvC,CAAC;AAVD,sCAUC;AAED;;;GAGG;AACI,KAAK,UAAU,oBAAoB,CACxC,UAAkB,EAClB,cAAsB,EACtB,KAAK,GAAG,KAAK;IAEb,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE;QAC7D,GAAG,EAAE,UAAU;QACf,KAAK,EAAE,KAAK;KACb,CAAC,CAAC;IAEH,MAAM,cAAc,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,cAAc,EAAE;QACjE,OAAO,EAAE,MAAO;KACjB,CAAC,CAAC;IAEH,IAAA,eAAM,EAAC,cAAc,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC;AAfD,oDAeC;AAED;;;;;;GAMG;AACI,KAAK,UAAU,yBAAyB,CAC7C,UAAkB,EAClB,QAA2B,EAC3B,KAAK,GAAG,KAAK;IAEb,MAAM,SAAS,GAAG,UAAU,CAAC;IAC7B,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,gCAAgC;IACrD,IAAI,YAAoB,CAAC;IACzB,IAAI,UAAkB,CAAC;IAEvB,IAAI,QAAQ,KAAK,KAAK,EAAE;QACtB,YAAY,GAAG,qBAAqB,CAAC;QACrC,UAAU,GAAG,OAAO,CAAC;KACtB;SAAM;QACL,UAAU;QACV,YAAY,GAAG,oDAAoD,CAAC;QACpE,UAAU,GAAG,4BAA4B,CAAC;KAC3C;IAED,MAAM,iBAAiB,GAAG;QACxB,cAAc;QACd,QAAQ;QACR,cAAc;QACd,SAAS;QACT,YAAY;QACZ,QAAQ;QACR,OAAO;QACP,GAAG;QACH,iBAAiB;QACjB,YAAY;QACZ,eAAe;QACf,UAAU;KACX,CAAC;IAEF,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,KAAK,EAAE,iBAAiB,EAAE;QAC1D,GAAG,EAAE,UAAU;QACf,KAAK,EAAE,KAAK;KACb,CAAC,CAAC;IAEH,MAAM,iBAAiB,GAAG,MAAM,OAAO,CAAC,iBAAiB,CAAC,CAAC,EAAE;QAC3D,OAAO,EAAE,MAAO;KACjB,CAAC,CAAC;IAEH,OAAO,CAAC,IAAI,EAAE,CAAC;IAEf,OAAO,iBAAiB,CAAC;AAC3B,CAAC;AA9CD,8DA8CC;AAED;;;;;;GAMG;AACI,KAAK,UAAU,kBAAkB,CACtC,UAAkB,EAClB,QAAmC,EACnC,KAAK,GAAG,KAAK;IAEb,MAAM,iBAAiB,GAAG;QACxB,MAAM;QACN,QAAQ;QACR,YAAY;QACZ,QAAQ;KACT,CAAC;IAEF,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,KAAK,EAAE,iBAAiB,EAAE;QAC1D,GAAG,EAAE,UAAU;QACf,KAAK,EAAE,KAAK;KACb,CAAC,CAAC;IAEH,MAAM,iBAAiB,GAAG,MAAM,OAAO,CAAC,iBAAiB,CAAC,CAAC,EAAE;QAC3D,OAAO,EAAE,MAAO;KACjB,CAAC,CAAC;IAEH,OAAO,CAAC,IAAI,EAAE,CAAC;IACf,OAAO,iBAAiB,CAAC;AAC3B,CAAC;AAvBD,gDAuBC;AAED;;;;GAIG;AACI,KAAK,UAAU,oBAAoB,CACxC,UAAkB,EAClB,cAAsB;IAEtB,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;IAE9E,IAAA,eAAM,EACJ,MAAM,OAAO,CAAC,aAAa,CAAC,cAAc,EAAE;QAC1C,OAAO,EAAE,MAAO;KACjB,CAAC,CACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,OAAO,CAAC,IAAI,EAAE,CAAC;AACjB,CAAC;AAbD,oDAaC;AAED;;;;GAIG;AACI,KAAK,UAAU,qBAAqB,CACzC,UAAkB,EAClB,cAAsB,EACtB,YAAY,GAAG,OAAO;IAEtB,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC,EAAE;QAC9D,GAAG,EAAE,UAAU;KAChB,CAAC,CAAC;IAEH,IAAA,eAAM,EACJ,MAAM,OAAO,CAAC,aAAa,CAAC,cAAc,EAAE;QAC1C,OAAO,EAAE,MAAO;KACjB,CAAC,CACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,OAAO,CAAC,IAAI,EAAE,CAAC;AACjB,CAAC;AAhBD,sDAgBC","sourcesContent":["import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport type { Integration } from '../../lib/Constants';\nimport { spawn, execSync } from 'node:child_process';\nimport type { ChildProcess } from 'node:child_process';\nimport { dim, green, red } from '../../lib/Helper/Logging';\nimport { expect } from 'vitest';\n\nexport const KEYS = {\n UP: '\\u001b[A',\n DOWN: '\\u001b[B',\n LEFT: '\\u001b[D',\n RIGHT: '\\u001b[C',\n ENTER: '\\r',\n SPACE: ' ',\n};\n\nexport const TEST_ARGS = {\n AUTH_TOKEN: process.env.SENTRY_TEST_AUTH_TOKEN || 'TEST_AUTH_TOKEN',\n PROJECT_DSN:\n process.env.SENTRY_TEST_DSN || 'https://public@dsn.ingest.sentry.io/1337',\n ORG_SLUG: process.env.SENTRY_TEST_ORG || 'TEST_ORG_SLUG',\n PROJECT_SLUG: process.env.SENTRY_TEST_PROJECT || 'TEST_PROJECT_SLUG',\n};\n\nexport const log = {\n success: (message: string) => {\n green(`[SUCCESS] ${message}`);\n },\n info: (message: string) => {\n dim(`[INFO] ${message}`);\n },\n error: (message: unknown) => {\n function formatMessage(message: unknown, depth: number): string {\n if (depth > 3) {\n return '...';\n }\n\n if (message instanceof Error) {\n return JSON.stringify(\n {\n name: message.name,\n message: message.message,\n stack: message.stack,\n ...(message.cause\n ? {\n cause: formatMessage(message.cause, depth + 1),\n }\n : {}),\n },\n null,\n 2,\n );\n }\n return String(message);\n }\n red(`[ERROR] ${formatMessage(message, 0)}`);\n },\n};\n\nexport class WizardTestEnv {\n taskHandle: ChildProcess;\n\n constructor(\n cmd: string,\n args: string[],\n opts?: {\n cwd?: string;\n debug?: boolean;\n },\n ) {\n this.taskHandle = spawn(cmd, args, { cwd: opts?.cwd, stdio: 'pipe' });\n\n if (opts?.debug) {\n this.taskHandle.stdout?.pipe(process.stdout);\n this.taskHandle.stderr?.pipe(process.stderr);\n }\n }\n\n sendStdin(input: string) {\n this.taskHandle.stdin?.write(input);\n }\n\n /**\n * Sends the input and waits for the output.\n * @returns a promise that resolves when the output was found\n * @throws an error when the output was not found within the timeout\n */\n sendStdinAndWaitForOutput(\n input: string | string[],\n output: string,\n options?: { timeout?: number; optional?: boolean },\n ) {\n const outputPromise = this.waitForOutput(output, options);\n\n if (Array.isArray(input)) {\n for (const i of input) {\n this.sendStdin(i);\n }\n } else {\n this.sendStdin(input);\n }\n return outputPromise;\n }\n\n /**\n * Waits for the task to exit with a given `statusCode`.\n *\n * @returns a promise that resolves to `true` if the run ends with the status\n * code, or it rejects when the `timeout` was reached.\n */\n waitForStatusCode(\n statusCode: number | null,\n options: {\n /** Timeout in ms */\n timeout?: number;\n } = {},\n ) {\n const { timeout } = {\n timeout: 60_000,\n ...options,\n };\n\n return new Promise<boolean>((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n this.kill();\n reject(\n new Error(`Timeout waiting for status code: ${statusCode ?? 'null'}`),\n );\n }, timeout);\n\n this.taskHandle.on('error', (err: Error) => {\n clearTimeout(timeoutId);\n reject(err);\n });\n\n this.taskHandle.on('exit', (code: number | null) => {\n clearTimeout(timeoutId);\n resolve(code === statusCode);\n });\n });\n }\n\n /**\n * Waits for the provided output with `.includes()` logic.\n *\n * @returns a promise that resolves to `true` if the output was found, `false` if the output was not found within the\n * timeout and `optional: true` is set, or it rejects when the timeout was reached with `optional: false`\n */\n waitForOutput(\n output: string,\n options: {\n /** Timeout in ms */\n timeout?: number;\n /** Whether to always resolve after the timeout, no matter whether the input was actually found or not. */\n optional?: boolean;\n } = {},\n ) {\n const { timeout, optional } = {\n timeout: 60_000,\n optional: false,\n ...options,\n };\n\n return new Promise<boolean>((resolve, reject) => {\n let outputBuffer = '';\n const timeoutId = setTimeout(() => {\n this.taskHandle.off('error', errorListener);\n this.taskHandle.stdout?.off('data', dataListener);\n\n this.kill();\n if (optional) {\n // The output is not found but it's optional so we can resolve the promise with false\n resolve(false);\n } else {\n reject(\n new Error(\n `Timeout waiting for output: ${output}. Got the following instead: ${outputBuffer}`,\n ),\n );\n }\n }, timeout);\n\n const dataListener = (data: string) => {\n outputBuffer += data;\n if (outputBuffer.includes(output)) {\n clearTimeout(timeoutId);\n this.taskHandle.off('error', errorListener);\n this.taskHandle.stdout?.off('data', dataListener);\n // The output is found so we can resolve the promise with true\n resolve(true);\n }\n };\n\n const errorListener = (err: Error) => {\n this.taskHandle.off('error', errorListener);\n this.taskHandle.stdout?.off('data', dataListener);\n clearTimeout(timeoutId);\n reject(err);\n };\n\n this.taskHandle.on('error', errorListener);\n this.taskHandle.stdout?.on('data', dataListener);\n });\n }\n\n kill() {\n this.taskHandle.stdin?.destroy();\n this.taskHandle.stderr?.destroy();\n this.taskHandle.stdout?.destroy();\n this.taskHandle.kill('SIGINT');\n this.taskHandle.unref();\n }\n}\n\n/**\n * Initialize a git repository in the given directory\n * @param projectDir\n */\nexport function initGit(projectDir: string): void {\n try {\n execSync('git init', { cwd: projectDir });\n // Add all files to the git repo\n execSync('git add -A', { cwd: projectDir });\n // Add author info to avoid git commit error\n execSync('git config user.email test@test.sentry.io', { cwd: projectDir });\n execSync('git config user.name Test', { cwd: projectDir });\n execSync('git commit -m init', { cwd: projectDir });\n } catch (e) {\n log.error('Error initializing git');\n log.error(e);\n }\n}\n\n/**\n * Cleanup the git repository in the given directory\n *\n * Caution! Make sure `projectDir` is a test project directory,\n * if in doubt, please commit your local non-test changes first!\n * @param projectDir\n */\nexport function cleanupGit(projectDir: string): void {\n try {\n // Remove the .git directory\n execSync(`rm -rf ${projectDir}/.git`);\n } catch (e) {\n log.error('Error cleaning up git');\n log.error(e);\n }\n}\n\n/**\n * Revert local changes in the given directory\n *\n * Caution! Make sure `projectDir` is a test project directory,\n * if in doubt, please commit your local non-test changes first!\n *\n * @param projectDir\n */\nexport function revertLocalChanges(projectDir: string): void {\n try {\n // Revert tracked files\n execSync('git restore .', { cwd: projectDir });\n // Revert untracked files\n execSync('git clean -fd .', { cwd: projectDir });\n // Remove node_modules and dist (.gitignore'd and therefore not removed via git clean)\n execSync('rm -rf node_modules', { cwd: projectDir });\n execSync('rm -rf dist', { cwd: projectDir });\n } catch (e) {\n log.error('Error reverting local changes');\n log.error(e);\n }\n}\n\nexport function getWizardCommand(integration: Integration): string {\n const binName = process.env.SENTRY_WIZARD_E2E_TEST_BIN\n ? ['dist-bin', `sentry-wizard-${process.platform}-${process.arch}`]\n : ['dist', 'bin.js'];\n const binPath = path.join(__dirname, '..', '..', ...binName);\n\n const args = [\n '--debug',\n '-i',\n integration,\n '--preSelectedProject.authToken',\n TEST_ARGS.AUTH_TOKEN,\n '--preSelectedProject.dsn',\n TEST_ARGS.PROJECT_DSN,\n '--preSelectedProject.orgSlug',\n TEST_ARGS.ORG_SLUG,\n '--preSelectedProject.projectSlug',\n TEST_ARGS.PROJECT_SLUG,\n '--disable-telemetry',\n ];\n\n return `${binPath} ${args.join(' ')}`;\n}\n\n/**\n * Start the wizard instance with the given integration and project directory\n * @param integration\n * @param projectDir\n *\n * @returns WizardTestEnv\n */\nexport function startWizardInstance(\n integration: Integration,\n projectDir: string,\n debug = false,\n): WizardTestEnv {\n const binName = process.env.SENTRY_WIZARD_E2E_TEST_BIN\n ? ['dist-bin', `sentry-wizard-${process.platform}-${process.arch}`]\n : ['dist', 'bin.js'];\n const binPath = path.join(__dirname, '..', '..', ...binName);\n\n revertLocalChanges(projectDir);\n cleanupGit(projectDir);\n initGit(projectDir);\n\n return new WizardTestEnv(\n binPath,\n [\n '--debug',\n '-i',\n integration,\n '--preSelectedProject.authToken',\n TEST_ARGS.AUTH_TOKEN,\n '--preSelectedProject.dsn',\n TEST_ARGS.PROJECT_DSN,\n '--preSelectedProject.orgSlug',\n TEST_ARGS.ORG_SLUG,\n '--preSelectedProject.projectSlug',\n TEST_ARGS.PROJECT_SLUG,\n '--disable-telemetry',\n ],\n { cwd: projectDir, debug },\n );\n}\n\n/**\n * Create a file with the given content\n *\n * @param filePath\n * @param content\n */\nexport function createFile(filePath: string, content?: string) {\n return fs.writeFileSync(filePath, content || '');\n}\n\n/**\n * Modify the file with the new content\n *\n * @param filePath\n * @param oldContent\n * @param newContent\n */\nexport function modifyFile(\n filePath: string,\n replaceMap: Record<string, string>,\n) {\n const fileContent = fs.readFileSync(filePath, 'utf-8');\n let newFileContent = fileContent;\n\n for (const [oldContent, newContent] of Object.entries(replaceMap)) {\n newFileContent = newFileContent.replace(oldContent, newContent);\n }\n\n fs.writeFileSync(filePath, newFileContent);\n}\n\n/**\n * Read the file contents and check if it does not contain the given content\n *\n * @param {string} filePath\n * @param {(string | string[])} content\n */\nexport function checkFileDoesNotContain(\n filePath: string,\n content: string | string[],\n) {\n const fileContent = fs.readFileSync(filePath, 'utf-8');\n const contentArray = Array.isArray(content) ? content : [content];\n\n for (const c of contentArray) {\n expect(fileContent).not.toContain(c);\n }\n}\n\n/**\n * Read the file contents and check if it contains the given content\n *\n * @param {string} filePath\n * @param {(string | string[])} content\n */\nexport function checkFileContents(\n filePath: string,\n content: string | string[],\n) {\n const fileContent = fs.readFileSync(filePath, 'utf-8');\n const contentArray = Array.isArray(content) ? content : [content];\n\n for (const c of contentArray) {\n expect(fileContent).toContain(c);\n }\n}\n\n/**\n * Check if the file exists\n *\n * @param filePath\n */\nexport function checkFileExists(filePath: string) {\n expect(fs.existsSync(filePath)).toBe(true);\n}\n\n/**\n * Check if the package.json contains the given integration\n *\n * @param projectDir\n * @param integration\n */\nexport function checkPackageJson(projectDir: string, integration: Integration) {\n checkFileContents(`${projectDir}/package.json`, `@sentry/${integration}`);\n}\n\n/**\n * Check if the .sentryclirc contains the auth token\n *\n * @param projectDir\n */\nexport function checkSentryCliRc(projectDir: string) {\n checkFileContents(\n `${projectDir}/.sentryclirc`,\n `token=${TEST_ARGS.AUTH_TOKEN}`,\n );\n}\n\n/**\n * Check if the .env.sentry-build-plugin contains the auth token\n * @param projectDir\n */\nexport function checkEnvBuildPlugin(projectDir: string) {\n checkFileContents(\n `${projectDir}/.env.sentry-build-plugin`,\n `SENTRY_AUTH_TOKEN=${TEST_ARGS.AUTH_TOKEN}`,\n );\n}\n\n/**\n * Check if the sentry.properties contains the auth token\n * @param projectDir\n */\nexport function checkSentryProperties(projectDir: string) {\n checkFileContents(\n `${projectDir}/sentry.properties`,\n `auth_token=${TEST_ARGS.AUTH_TOKEN}`,\n );\n}\n\n/**\n * Check if the project builds\n * Check if the project builds and ends with status code 0.\n * @param projectDir\n */\nexport async function checkIfBuilds(projectDir: string) {\n const testEnv = new WizardTestEnv('npm', ['run', 'build'], {\n cwd: projectDir,\n });\n\n const builtSuccessfully = await testEnv.waitForStatusCode(0, {\n timeout: 120_000,\n });\n\n expect(builtSuccessfully).toBe(true);\n}\n\n/**\n * Check if the flutter project builds\n * @param projectDir\n */\nexport async function checkIfFlutterBuilds(\n projectDir: string,\n expectedOutput: string,\n debug = false,\n) {\n const testEnv = new WizardTestEnv('flutter', ['build', 'web'], {\n cwd: projectDir,\n debug: debug,\n });\n\n const outputReceived = await testEnv.waitForOutput(expectedOutput, {\n timeout: 120_000,\n });\n\n expect(outputReceived).toBe(true);\n}\n\n/**\n * Check if the React Native project bundles successfully for the specified platform.\n * Returns a boolean indicating if the process exits with status code 0.\n * @param projectDir The root directory of the React Native project.\n * @param platform The platform to bundle for ('ios' or 'android').\n * @param debug runs the command in debug mode if true\n */\nexport async function checkIfReactNativeBundles(\n projectDir: string,\n platform: 'ios' | 'android',\n debug = false,\n): Promise<boolean> {\n const entryFile = 'index.js';\n const dev = 'false'; // Test a production-like bundle\n let bundleOutput: string;\n let assetsDest: string;\n\n if (platform === 'ios') {\n bundleOutput = './ios/main.jsbundle';\n assetsDest = './ios';\n } else {\n // android\n bundleOutput = './android/app/src/main/assets/index.android.bundle';\n assetsDest = './android/app/src/main/res';\n }\n\n const bundleCommandArgs = [\n 'react-native',\n 'bundle',\n '--entry-file',\n entryFile,\n '--platform',\n platform,\n '--dev',\n dev,\n '--bundle-output',\n bundleOutput,\n '--assets-dest',\n assetsDest,\n ];\n\n const testEnv = new WizardTestEnv('npx', bundleCommandArgs, {\n cwd: projectDir,\n debug: debug,\n });\n\n const builtSuccessfully = await testEnv.waitForStatusCode(0, {\n timeout: 300_000,\n });\n\n testEnv.kill();\n\n return builtSuccessfully;\n}\n\n/**\n * Check if the Expo project exports successfully for the specified platform.\n * Returns a boolean indicating if the process exits with status code 0.\n * @param projectDir The root directory of the Expo project.\n * @param platform The platform to export for ('ios', 'android', or 'web').\n * @param debug runs the command in debug mode if true\n */\nexport async function checkIfExpoBundles(\n projectDir: string,\n platform: 'ios' | 'android' | 'web',\n debug = false,\n): Promise<boolean> {\n const exportCommandArgs = [\n 'expo',\n 'export',\n '--platform',\n platform,\n ];\n\n const testEnv = new WizardTestEnv('npx', exportCommandArgs, {\n cwd: projectDir,\n debug: debug,\n });\n\n const builtSuccessfully = await testEnv.waitForStatusCode(0, {\n timeout: 300_000,\n });\n\n testEnv.kill();\n return builtSuccessfully;\n}\n\n/**\n * Check if the project runs on dev mode\n * @param projectDir\n * @param expectedOutput\n */\nexport async function checkIfRunsOnDevMode(\n projectDir: string,\n expectedOutput: string,\n) {\n const testEnv = new WizardTestEnv('npm', ['run', 'dev'], { cwd: projectDir });\n\n expect(\n await testEnv.waitForOutput(expectedOutput, {\n timeout: 120_000,\n }),\n ).toBe(true);\n\n testEnv.kill();\n}\n\n/**\n * Check if the project runs on prod mode\n * @param projectDir\n * @param expectedOutput\n */\nexport async function checkIfRunsOnProdMode(\n projectDir: string,\n expectedOutput: string,\n startCommand = 'start',\n) {\n const testEnv = new WizardTestEnv('npm', ['run', startCommand], {\n cwd: projectDir,\n });\n\n expect(\n await testEnv.waitForOutput(expectedOutput, {\n timeout: 120_000,\n }),\n ).toBe(true);\n\n testEnv.kill();\n}\n"]}
|
|
@@ -105,8 +105,9 @@ async function runNextjsWizardWithTelemetry(options) {
|
|
|
105
105
|
? '_error.js'
|
|
106
106
|
: undefined;
|
|
107
107
|
if (!underscoreErrorPageFile) {
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
const underscoreErrorFileName = `_error.${typeScriptDetected ? 'tsx' : 'jsx'}`;
|
|
109
|
+
await fs.promises.writeFile(path.join(process.cwd(), ...pagesLocation, underscoreErrorFileName), (0, templates_1.getSentryDefaultUnderscoreErrorPage)(), { encoding: 'utf8', flag: 'w' });
|
|
110
|
+
prompts_1.default.log.success(`Created ${chalk_1.default.cyan(path.join(...pagesLocation, underscoreErrorFileName))}.`);
|
|
110
111
|
}
|
|
111
112
|
else if (fs
|
|
112
113
|
.readFileSync(path.join(process.cwd(), ...pagesLocation, underscoreErrorPageFile), 'utf8')
|
|
@@ -196,7 +197,7 @@ async function runNextjsWizardWithTelemetry(options) {
|
|
|
196
197
|
});
|
|
197
198
|
const shouldCreateExamplePage = await (0, clack_1.askShouldCreateExamplePage)();
|
|
198
199
|
if (shouldCreateExamplePage) {
|
|
199
|
-
await (0, telemetry_1.traceStep)('create-example-page', async () => createExamplePage(selfHosted, selectedProject, sentryUrl));
|
|
200
|
+
await (0, telemetry_1.traceStep)('create-example-page', async () => createExamplePage(selfHosted, selectedProject, sentryUrl, typeScriptDetected));
|
|
200
201
|
}
|
|
201
202
|
await (0, clack_1.addDotEnvSentryBuildPluginFile)(authToken);
|
|
202
203
|
const isLikelyUsingTurbopack = await checkIfLikelyIsUsingTurbopack();
|
|
@@ -546,14 +547,13 @@ function hasDirectoryPathFromRoot(dirnameOrDirs) {
|
|
|
546
547
|
: path.join(process.cwd(), dirnameOrDirs);
|
|
547
548
|
return fs.existsSync(dirPath) && fs.lstatSync(dirPath).isDirectory();
|
|
548
549
|
}
|
|
549
|
-
async function createExamplePage(selfHosted, selectedProject, sentryUrl) {
|
|
550
|
+
async function createExamplePage(selfHosted, selectedProject, sentryUrl, typeScriptDetected) {
|
|
550
551
|
const hasSrcDirectory = hasDirectoryPathFromRoot('src');
|
|
551
552
|
const hasRootAppDirectory = hasDirectoryPathFromRoot('app');
|
|
552
553
|
const hasRootPagesDirectory = hasDirectoryPathFromRoot('pages');
|
|
553
554
|
const hasSrcAppDirectory = hasDirectoryPathFromRoot(['src', 'app']);
|
|
554
555
|
const hasSrcPagesDirectory = hasDirectoryPathFromRoot(['src', 'pages']);
|
|
555
556
|
Sentry.setTag('nextjs-app-dir', hasRootAppDirectory || hasSrcAppDirectory);
|
|
556
|
-
const typeScriptDetected = (0, clack_1.isUsingTypeScript)();
|
|
557
557
|
// If `pages` or an `app` directory exists in the root, we'll put the example page there.
|
|
558
558
|
// `app` directory takes priority over `pages` directory when they coexist, so we prioritize that.
|
|
559
559
|
// https://nextjs.org/docs/app/building-your-application/routing#the-app-router
|
|
@@ -593,6 +593,7 @@ async function createExamplePage(selfHosted, selectedProject, sentryUrl) {
|
|
|
593
593
|
projectId: selectedProject.id,
|
|
594
594
|
sentryUrl,
|
|
595
595
|
useClient: true,
|
|
596
|
+
isTypeScript: typeScriptDetected,
|
|
596
597
|
});
|
|
597
598
|
fs.mkdirSync(path.join(appFolderPath, 'sentry-example-page'), {
|
|
598
599
|
recursive: true,
|
|
@@ -604,7 +605,7 @@ async function createExamplePage(selfHosted, selectedProject, sentryUrl) {
|
|
|
604
605
|
recursive: true,
|
|
605
606
|
});
|
|
606
607
|
const newRouteFileName = `route.${typeScriptDetected ? 'ts' : 'js'}`;
|
|
607
|
-
await fs.promises.writeFile(path.join(appFolderPath, 'api', 'sentry-example-api', newRouteFileName), (0, templates_1.getSentryExampleAppDirApiRoute)(), { encoding: 'utf8', flag: 'w' });
|
|
608
|
+
await fs.promises.writeFile(path.join(appFolderPath, 'api', 'sentry-example-api', newRouteFileName), (0, templates_1.getSentryExampleAppDirApiRoute)({ isTypeScript: typeScriptDetected }), { encoding: 'utf8', flag: 'w' });
|
|
608
609
|
prompts_1.default.log.success(`Created ${chalk_1.default.cyan(path.join(...appFolderLocation, 'api', 'sentry-example-api', newRouteFileName))}.`);
|
|
609
610
|
}
|
|
610
611
|
else if (pagesFolderLocation) {
|
|
@@ -614,14 +615,17 @@ async function createExamplePage(selfHosted, selectedProject, sentryUrl) {
|
|
|
614
615
|
projectId: selectedProject.id,
|
|
615
616
|
sentryUrl,
|
|
616
617
|
useClient: false,
|
|
618
|
+
isTypeScript: typeScriptDetected,
|
|
617
619
|
});
|
|
618
|
-
|
|
619
|
-
|
|
620
|
+
const examplePageFileName = `sentry-example-page.${typeScriptDetected ? 'tsx' : 'jsx'}`;
|
|
621
|
+
await fs.promises.writeFile(path.join(process.cwd(), ...pagesFolderLocation, examplePageFileName), examplePageContents, { encoding: 'utf8', flag: 'w' });
|
|
622
|
+
prompts_1.default.log.success(`Created ${chalk_1.default.cyan(path.join(...pagesFolderLocation, examplePageFileName))}.`);
|
|
620
623
|
fs.mkdirSync(path.join(process.cwd(), ...pagesFolderLocation, 'api'), {
|
|
621
624
|
recursive: true,
|
|
622
625
|
});
|
|
623
|
-
|
|
624
|
-
|
|
626
|
+
const apiRouteFileName = `sentry-example-api.${typeScriptDetected ? 'ts' : 'js'}`;
|
|
627
|
+
await fs.promises.writeFile(path.join(process.cwd(), ...pagesFolderLocation, 'api', apiRouteFileName), (0, templates_1.getSentryExamplePagesDirApiRoute)({ isTypeScript: typeScriptDetected }), { encoding: 'utf8', flag: 'w' });
|
|
628
|
+
prompts_1.default.log.success(`Created ${chalk_1.default.cyan(path.join(...pagesFolderLocation, 'api', apiRouteFileName))}.`);
|
|
625
629
|
}
|
|
626
630
|
}
|
|
627
631
|
/**
|