@sentry/wizard 3.22.3 → 3.23.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 +5 -0
- package/dist/package.json +1 -1
- package/dist/src/react-native/javascript.js +1 -1
- package/dist/src/react-native/javascript.js.map +1 -1
- package/dist/src/react-native/metro.d.ts +6 -1
- package/dist/src/react-native/metro.js +166 -17
- package/dist/src/react-native/metro.js.map +1 -1
- package/dist/src/react-native/react-native-wizard.d.ts +1 -0
- package/dist/src/react-native/react-native-wizard.js +19 -20
- package/dist/src/react-native/react-native-wizard.js.map +1 -1
- package/dist/src/utils/ast-utils.d.ts +1 -1
- package/dist/src/utils/ast-utils.js +2 -2
- package/dist/src/utils/ast-utils.js.map +1 -1
- package/dist/test/react-native/javascript.test.js +1 -1
- package/dist/test/react-native/javascript.test.js.map +1 -1
- package/dist/test/react-native/metro.test.js +115 -0
- package/dist/test/react-native/metro.test.js.map +1 -1
- package/package.json +1 -1
- package/src/react-native/javascript.ts +3 -0
- package/src/react-native/metro.ts +208 -18
- package/src/react-native/react-native-wizard.ts +24 -7
- package/src/utils/ast-utils.ts +2 -2
- package/test/react-native/javascript.test.ts +3 -0
- package/test/react-native/metro.test.ts +113 -0
|
@@ -25,11 +25,100 @@ const b = recast.types.builders;
|
|
|
25
25
|
|
|
26
26
|
const metroConfigPath = 'metro.config.js';
|
|
27
27
|
|
|
28
|
-
export async function
|
|
28
|
+
export async function patchMetroWithSentryConfig() {
|
|
29
29
|
const mod = await parseMetroConfig();
|
|
30
30
|
|
|
31
31
|
const showInstructions = () =>
|
|
32
|
-
showCopyPasteInstructions(
|
|
32
|
+
showCopyPasteInstructions(
|
|
33
|
+
metroConfigPath,
|
|
34
|
+
getMetroWithSentryConfigSnippet(true),
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
const success = await patchMetroWithSentryConfigInMemory(
|
|
38
|
+
mod,
|
|
39
|
+
showInstructions,
|
|
40
|
+
);
|
|
41
|
+
if (!success) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const saved = await writeMetroConfig(mod);
|
|
46
|
+
if (saved) {
|
|
47
|
+
clack.log.success(
|
|
48
|
+
chalk.green(`${chalk.cyan(metroConfigPath)} changes saved.`),
|
|
49
|
+
);
|
|
50
|
+
} else {
|
|
51
|
+
clack.log.warn(
|
|
52
|
+
`Could not save changes to ${chalk.cyan(
|
|
53
|
+
metroConfigPath,
|
|
54
|
+
)}, please follow the manual steps.`,
|
|
55
|
+
);
|
|
56
|
+
return await showInstructions();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export async function patchMetroWithSentryConfigInMemory(
|
|
61
|
+
mod: ProxifiedModule,
|
|
62
|
+
showInstructions: () => Promise<void>,
|
|
63
|
+
): Promise<boolean> {
|
|
64
|
+
if (hasSentryContent(mod.$ast as t.Program)) {
|
|
65
|
+
const shouldContinue = await confirmPathMetroConfig();
|
|
66
|
+
if (!shouldContinue) {
|
|
67
|
+
await showInstructions();
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const configExpression = getModuleExportsAssignmentRight(
|
|
73
|
+
mod.$ast as t.Program,
|
|
74
|
+
);
|
|
75
|
+
if (!configExpression) {
|
|
76
|
+
clack.log.warn(
|
|
77
|
+
'Could not find Metro config, please follow the manual steps.',
|
|
78
|
+
);
|
|
79
|
+
await showInstructions();
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const wrappedConfig = wrapWithSentryConfig(configExpression);
|
|
84
|
+
|
|
85
|
+
const replacedModuleExportsRight = replaceModuleExportsRight(
|
|
86
|
+
mod.$ast as t.Program,
|
|
87
|
+
wrappedConfig,
|
|
88
|
+
);
|
|
89
|
+
if (!replacedModuleExportsRight) {
|
|
90
|
+
clack.log.warn(
|
|
91
|
+
'Could not automatically wrap the config export, please follow the manual steps.',
|
|
92
|
+
);
|
|
93
|
+
await showInstructions();
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const addedSentryMetroImport = addSentryMetroRequireToMetroConfig(
|
|
98
|
+
mod.$ast as t.Program,
|
|
99
|
+
);
|
|
100
|
+
if (!addedSentryMetroImport) {
|
|
101
|
+
clack.log.warn(
|
|
102
|
+
'Could not add `@sentry/react-native/metro` import to Metro config, please follow the manual steps.',
|
|
103
|
+
);
|
|
104
|
+
await showInstructions();
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
clack.log.success(
|
|
109
|
+
`Added Sentry Metro plugin to ${chalk.cyan(metroConfigPath)}.`,
|
|
110
|
+
);
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export async function patchMetroConfigWithSentrySerializer() {
|
|
115
|
+
const mod = await parseMetroConfig();
|
|
116
|
+
|
|
117
|
+
const showInstructions = () =>
|
|
118
|
+
showCopyPasteInstructions(
|
|
119
|
+
metroConfigPath,
|
|
120
|
+
getMetroSentrySerializerSnippet(true),
|
|
121
|
+
);
|
|
33
122
|
|
|
34
123
|
if (hasSentryContent(mod.$ast as t.Program)) {
|
|
35
124
|
const shouldContinue = await confirmPathMetroConfig();
|
|
@@ -282,12 +371,51 @@ export function addSentrySerializerRequireToMetroConfig(
|
|
|
282
371
|
// insert after last require
|
|
283
372
|
program.body.splice(lastRequireIndex + 1, 0, sentrySerializerRequire);
|
|
284
373
|
} else {
|
|
285
|
-
// insert at the
|
|
286
|
-
program.body.
|
|
374
|
+
// insert at the beginning
|
|
375
|
+
program.body.unshift(sentrySerializerRequire);
|
|
376
|
+
}
|
|
377
|
+
return true;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
export function addSentryMetroRequireToMetroConfig(
|
|
381
|
+
program: t.Program,
|
|
382
|
+
): boolean {
|
|
383
|
+
const lastRequireIndex = getLastRequireIndex(program);
|
|
384
|
+
const sentryMetroRequire = createSentryMetroRequire();
|
|
385
|
+
const sentryImportIndex = lastRequireIndex + 1;
|
|
386
|
+
if (sentryImportIndex < program.body.length) {
|
|
387
|
+
// insert after last require
|
|
388
|
+
program.body.splice(lastRequireIndex + 1, 0, sentryMetroRequire);
|
|
389
|
+
} else {
|
|
390
|
+
// insert at the beginning
|
|
391
|
+
program.body.unshift(sentryMetroRequire);
|
|
287
392
|
}
|
|
288
393
|
return true;
|
|
289
394
|
}
|
|
290
395
|
|
|
396
|
+
function wrapWithSentryConfig(
|
|
397
|
+
configObj: t.Identifier | t.CallExpression | t.ObjectExpression,
|
|
398
|
+
): t.CallExpression {
|
|
399
|
+
return b.callExpression(b.identifier('withSentryConfig'), [configObj]);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
function replaceModuleExportsRight(
|
|
403
|
+
program: t.Program,
|
|
404
|
+
wrappedConfig: t.CallExpression,
|
|
405
|
+
): boolean {
|
|
406
|
+
const moduleExports = getModuleExports(program);
|
|
407
|
+
if (!moduleExports) {
|
|
408
|
+
return false;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
if (moduleExports.expression.type === 'AssignmentExpression') {
|
|
412
|
+
moduleExports.expression.right = wrappedConfig;
|
|
413
|
+
return true;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
|
|
291
419
|
/**
|
|
292
420
|
* Creates const {createSentryMetroSerializer} = require('@sentry/react-native/dist/js/tools/sentryMetroSerializer');
|
|
293
421
|
*/
|
|
@@ -308,6 +436,26 @@ function createSentrySerializerRequire() {
|
|
|
308
436
|
]);
|
|
309
437
|
}
|
|
310
438
|
|
|
439
|
+
/**
|
|
440
|
+
* Creates const {withSentryConfig} = require('@sentry/react-native/metro');
|
|
441
|
+
*/
|
|
442
|
+
function createSentryMetroRequire() {
|
|
443
|
+
return b.variableDeclaration('const', [
|
|
444
|
+
b.variableDeclarator(
|
|
445
|
+
b.objectPattern([
|
|
446
|
+
b.objectProperty.from({
|
|
447
|
+
key: b.identifier('withSentryConfig'),
|
|
448
|
+
value: b.identifier('withSentryConfig'),
|
|
449
|
+
shorthand: true,
|
|
450
|
+
}),
|
|
451
|
+
]),
|
|
452
|
+
b.callExpression(b.identifier('require'), [
|
|
453
|
+
b.literal('@sentry/react-native/metro'),
|
|
454
|
+
]),
|
|
455
|
+
),
|
|
456
|
+
]);
|
|
457
|
+
}
|
|
458
|
+
|
|
311
459
|
async function confirmPathMetroConfig() {
|
|
312
460
|
const shouldContinue = await abortIfCancelled(
|
|
313
461
|
clack.select({
|
|
@@ -361,8 +509,48 @@ export function getMetroConfigObject(
|
|
|
361
509
|
return configVariable.declarations[0].init;
|
|
362
510
|
}
|
|
363
511
|
|
|
512
|
+
return getModuleExportsObject(program);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
function getModuleExportsObject(
|
|
516
|
+
program: t.Program,
|
|
517
|
+
): t.ObjectExpression | undefined {
|
|
518
|
+
// check module.exports
|
|
519
|
+
const moduleExports = getModuleExportsAssignmentRight(program);
|
|
520
|
+
|
|
521
|
+
if (moduleExports?.type === 'ObjectExpression') {
|
|
522
|
+
return moduleExports;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
Sentry.setTag('metro-config', 'not-found');
|
|
526
|
+
return undefined;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
export function getModuleExportsAssignmentRight(
|
|
530
|
+
program: t.Program,
|
|
531
|
+
): t.Identifier | t.CallExpression | t.ObjectExpression | undefined {
|
|
364
532
|
// check module.exports
|
|
365
|
-
const moduleExports = program
|
|
533
|
+
const moduleExports = getModuleExports(program);
|
|
534
|
+
|
|
535
|
+
if (
|
|
536
|
+
moduleExports?.expression.type === 'AssignmentExpression' &&
|
|
537
|
+
(moduleExports.expression.right.type === 'ObjectExpression' ||
|
|
538
|
+
moduleExports.expression.right.type === 'CallExpression' ||
|
|
539
|
+
moduleExports.expression.right.type === 'Identifier')
|
|
540
|
+
) {
|
|
541
|
+
Sentry.setTag('metro-config', 'module-exports');
|
|
542
|
+
return moduleExports?.expression.right;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
Sentry.setTag('metro-config', 'not-found');
|
|
546
|
+
return undefined;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
function getModuleExports(
|
|
550
|
+
program: t.Program,
|
|
551
|
+
): t.ExpressionStatement | undefined {
|
|
552
|
+
// find module.exports
|
|
553
|
+
return program.body.find((s) => {
|
|
366
554
|
if (
|
|
367
555
|
s.type === 'ExpressionStatement' &&
|
|
368
556
|
s.expression.type === 'AssignmentExpression' &&
|
|
@@ -376,21 +564,9 @@ export function getMetroConfigObject(
|
|
|
376
564
|
}
|
|
377
565
|
return false;
|
|
378
566
|
}) as t.ExpressionStatement | undefined;
|
|
379
|
-
|
|
380
|
-
if (
|
|
381
|
-
(moduleExports?.expression as t.AssignmentExpression).right.type ===
|
|
382
|
-
'ObjectExpression'
|
|
383
|
-
) {
|
|
384
|
-
Sentry.setTag('metro-config', 'module-exports');
|
|
385
|
-
return (moduleExports?.expression as t.AssignmentExpression)
|
|
386
|
-
.right as t.ObjectExpression;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
Sentry.setTag('metro-config', 'not-found');
|
|
390
|
-
return undefined;
|
|
391
567
|
}
|
|
392
568
|
|
|
393
|
-
function
|
|
569
|
+
function getMetroSentrySerializerSnippet(colors: boolean) {
|
|
394
570
|
return makeCodeSnippet(colors, (unchanged, plus, _) =>
|
|
395
571
|
unchanged(`const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');";
|
|
396
572
|
${plus(
|
|
@@ -407,3 +583,17 @@ module.exports = mergeConfig(getDefaultConfig(__dirname), config);
|
|
|
407
583
|
`),
|
|
408
584
|
);
|
|
409
585
|
}
|
|
586
|
+
|
|
587
|
+
function getMetroWithSentryConfigSnippet(colors: boolean) {
|
|
588
|
+
return makeCodeSnippet(colors, (unchanged, plus, _) =>
|
|
589
|
+
unchanged(`const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');";
|
|
590
|
+
${plus("const {withSentryConfig} = require('@sentry/react-native/metro');")}
|
|
591
|
+
|
|
592
|
+
const config = {};
|
|
593
|
+
|
|
594
|
+
module.exports = ${plus(
|
|
595
|
+
'withSentryConfig(',
|
|
596
|
+
)}mergeConfig(getDefaultConfig(__dirname), config)${plus(')')};
|
|
597
|
+
`),
|
|
598
|
+
);
|
|
599
|
+
}
|
|
@@ -50,7 +50,10 @@ import { traceStep, withTelemetry } from '../telemetry';
|
|
|
50
50
|
import * as Sentry from '@sentry/node';
|
|
51
51
|
import { fulfillsVersionRange } from '../utils/semver';
|
|
52
52
|
import { getIssueStreamUrl } from '../utils/url';
|
|
53
|
-
import {
|
|
53
|
+
import {
|
|
54
|
+
patchMetroConfigWithSentrySerializer,
|
|
55
|
+
patchMetroWithSentryConfig,
|
|
56
|
+
} from './metro';
|
|
54
57
|
|
|
55
58
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
56
59
|
const xcode = require('xcode');
|
|
@@ -69,6 +72,10 @@ export const SDK_XCODE_SCRIPTS_SUPPORTED_SDK_RANGE = '>=5.11.0';
|
|
|
69
72
|
// The following SDK version ship with Sentry Metro plugin
|
|
70
73
|
export const SDK_SENTRY_METRO_PLUGIN_SUPPORTED_SDK_RANGE = '>=5.11.0';
|
|
71
74
|
|
|
75
|
+
// The following SDK version shipped `withSentryConfig`
|
|
76
|
+
export const SDK_SENTRY_METRO_WITH_SENTRY_CONFIG_SUPPORTED_SDK_RANGE =
|
|
77
|
+
'>=5.17.0';
|
|
78
|
+
|
|
72
79
|
export type RNCliSetupConfigContent = Pick<
|
|
73
80
|
Required<CliSetupConfigContent>,
|
|
74
81
|
'authToken' | 'org' | 'project' | 'url'
|
|
@@ -181,23 +188,33 @@ export async function runReactNativeWizardWithTelemetry(
|
|
|
181
188
|
}
|
|
182
189
|
}
|
|
183
190
|
|
|
184
|
-
|
|
191
|
+
function addSentryToMetroConfig({
|
|
185
192
|
sdkVersion,
|
|
186
193
|
}: {
|
|
187
194
|
sdkVersion: string | undefined;
|
|
188
195
|
}) {
|
|
189
196
|
if (
|
|
190
|
-
|
|
191
|
-
|
|
197
|
+
sdkVersion &&
|
|
198
|
+
fulfillsVersionRange({
|
|
192
199
|
version: sdkVersion,
|
|
193
|
-
acceptableVersions:
|
|
200
|
+
acceptableVersions:
|
|
201
|
+
SDK_SENTRY_METRO_WITH_SENTRY_CONFIG_SUPPORTED_SDK_RANGE,
|
|
194
202
|
canBeLatest: true,
|
|
195
203
|
})
|
|
196
204
|
) {
|
|
197
|
-
return;
|
|
205
|
+
return patchMetroWithSentryConfig();
|
|
198
206
|
}
|
|
199
207
|
|
|
200
|
-
|
|
208
|
+
if (
|
|
209
|
+
sdkVersion &&
|
|
210
|
+
fulfillsVersionRange({
|
|
211
|
+
version: sdkVersion,
|
|
212
|
+
acceptableVersions: SDK_SENTRY_METRO_PLUGIN_SUPPORTED_SDK_RANGE,
|
|
213
|
+
canBeLatest: true,
|
|
214
|
+
})
|
|
215
|
+
) {
|
|
216
|
+
return patchMetroConfigWithSentrySerializer();
|
|
217
|
+
}
|
|
201
218
|
}
|
|
202
219
|
|
|
203
220
|
async function addSentryInit({ dsn }: { dsn: string }) {
|
package/src/utils/ast-utils.ts
CHANGED
|
@@ -221,10 +221,10 @@ export function printJsonC(ast: t.Program): string {
|
|
|
221
221
|
* Walks the program body and returns index of the last variable assignment initialized by require statement.
|
|
222
222
|
* Only counts top level require statements.
|
|
223
223
|
*
|
|
224
|
-
* @returns index of the last `const foo = require('bar');` statement
|
|
224
|
+
* @returns index of the last `const foo = require('bar');` statement or -1 if none was found.
|
|
225
225
|
*/
|
|
226
226
|
export function getLastRequireIndex(program: t.Program): number {
|
|
227
|
-
let lastRequireIdex =
|
|
227
|
+
let lastRequireIdex = -1;
|
|
228
228
|
program.body.forEach((s, i) => {
|
|
229
229
|
if (
|
|
230
230
|
s.type === 'VariableDeclaration' &&
|
|
@@ -9,11 +9,124 @@ import {
|
|
|
9
9
|
addSentrySerializerRequireToMetroConfig,
|
|
10
10
|
addSentrySerializerToMetroConfig,
|
|
11
11
|
getMetroConfigObject,
|
|
12
|
+
patchMetroWithSentryConfigInMemory,
|
|
12
13
|
removeSentryRequire,
|
|
13
14
|
removeSentrySerializerFromMetroConfig,
|
|
14
15
|
} from '../../src/react-native/metro';
|
|
15
16
|
|
|
16
17
|
describe('patch metro config - sentry serializer', () => {
|
|
18
|
+
describe('patchMetroWithSentryConfigInMemory', () => {
|
|
19
|
+
it('patches react native 0.72 default metro config', async () => {
|
|
20
|
+
const mod =
|
|
21
|
+
parseModule(`const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Metro configuration
|
|
25
|
+
* https://reactnative.dev/docs/metro
|
|
26
|
+
*
|
|
27
|
+
* @type {import('metro-config').MetroConfig}
|
|
28
|
+
*/
|
|
29
|
+
const config = {};
|
|
30
|
+
|
|
31
|
+
module.exports = mergeConfig(getDefaultConfig(__dirname), config);`);
|
|
32
|
+
|
|
33
|
+
const result = await patchMetroWithSentryConfigInMemory(mod, async () => {
|
|
34
|
+
/* noop */
|
|
35
|
+
});
|
|
36
|
+
expect(result).toBe(true);
|
|
37
|
+
expect(generateCode(mod.$ast).code)
|
|
38
|
+
.toBe(`const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
|
|
39
|
+
|
|
40
|
+
const {
|
|
41
|
+
withSentryConfig
|
|
42
|
+
} = require("@sentry/react-native/metro");
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Metro configuration
|
|
46
|
+
* https://reactnative.dev/docs/metro
|
|
47
|
+
*
|
|
48
|
+
* @type {import('metro-config').MetroConfig}
|
|
49
|
+
*/
|
|
50
|
+
const config = {};
|
|
51
|
+
|
|
52
|
+
module.exports = withSentryConfig(mergeConfig(getDefaultConfig(__dirname), config));`);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('patches react native 0.65 default metro config', async () => {
|
|
56
|
+
const mod = parseModule(`/**
|
|
57
|
+
* Metro configuration for React Native
|
|
58
|
+
* https://github.com/facebook/react-native
|
|
59
|
+
*
|
|
60
|
+
* @format
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
module.exports = {
|
|
64
|
+
transformer: {
|
|
65
|
+
getTransformOptions: async () => ({
|
|
66
|
+
transform: {
|
|
67
|
+
experimentalImportSupport: false,
|
|
68
|
+
inlineRequires: true,
|
|
69
|
+
},
|
|
70
|
+
}),
|
|
71
|
+
},
|
|
72
|
+
};`);
|
|
73
|
+
|
|
74
|
+
const result = await patchMetroWithSentryConfigInMemory(mod, async () => {
|
|
75
|
+
/* noop */
|
|
76
|
+
});
|
|
77
|
+
expect(result).toBe(true);
|
|
78
|
+
expect(generateCode(mod.$ast).code).toBe(`const {
|
|
79
|
+
withSentryConfig
|
|
80
|
+
} = require("@sentry/react-native/metro");
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Metro configuration for React Native
|
|
84
|
+
* https://github.com/facebook/react-native
|
|
85
|
+
*
|
|
86
|
+
* @format
|
|
87
|
+
*/
|
|
88
|
+
|
|
89
|
+
module.exports = withSentryConfig({
|
|
90
|
+
transformer: {
|
|
91
|
+
getTransformOptions: async () => ({
|
|
92
|
+
transform: {
|
|
93
|
+
experimentalImportSupport: false,
|
|
94
|
+
inlineRequires: true,
|
|
95
|
+
},
|
|
96
|
+
}),
|
|
97
|
+
},
|
|
98
|
+
});`);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('patches react native metro config exported variable', async () => {
|
|
102
|
+
const mod = parseModule(`const testConfig = {};
|
|
103
|
+
|
|
104
|
+
module.exports = testConfig;`);
|
|
105
|
+
|
|
106
|
+
const result = await patchMetroWithSentryConfigInMemory(mod, async () => {
|
|
107
|
+
/* noop */
|
|
108
|
+
});
|
|
109
|
+
expect(result).toBe(true);
|
|
110
|
+
expect(generateCode(mod.$ast).code).toBe(`const {
|
|
111
|
+
withSentryConfig
|
|
112
|
+
} = require("@sentry/react-native/metro");
|
|
113
|
+
|
|
114
|
+
const testConfig = {};
|
|
115
|
+
|
|
116
|
+
module.exports = withSentryConfig(testConfig);`);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('does not patch react native metro config exported as factory function', async () => {
|
|
120
|
+
const mod = parseModule(`module.exports = () => ({});`);
|
|
121
|
+
|
|
122
|
+
const result = await patchMetroWithSentryConfigInMemory(mod, async () => {
|
|
123
|
+
/* noop */
|
|
124
|
+
});
|
|
125
|
+
expect(result).toBe(false);
|
|
126
|
+
expect(generateCode(mod.$ast).code).toBe(`module.exports = () => ({});`);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
17
130
|
describe('addSentrySerializerToMetroConfig', () => {
|
|
18
131
|
it('add to empty config', () => {
|
|
19
132
|
const mod = parseModule(`module.exports = {
|