diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cae9ae6..8e0e196f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [Unreleased] + +### Fixed + +- (expo-cli) Support App.txs files in `bugsnag-expo-cli` [#206](https://github.com/bugsnag/bugsnag-expo/pull/206) + ## [52.0.0] - 2024-11-28 This release adds support for Expo 52 diff --git a/packages/expo-cli/lib/insert.js b/packages/expo-cli/lib/insert.js index 653d2d85..dc0c287f 100644 --- a/packages/expo-cli/lib/insert.js +++ b/packages/expo-cli/lib/insert.js @@ -26,10 +26,12 @@ module.exports = async (projectRoot) => { if (checkFileExists('App.ts')) { return await writeBugsnagImport('App.ts') + } else if (checkFileExists('App.tsx')) { + return await writeBugsnagImport('App.tsx') } else if (checkFileExists('App.js')) { return await writeBugsnagImport('App.js') } else { - throw new Error(`Couldn’t find App.js or App.ts in "${projectRoot}". Is this the root of your Expo project?`) + throw new Error(`Couldn’t find App.js or App.ts/tsx in "${projectRoot}". Is this the root of your Expo project?`) } } diff --git a/packages/expo-cli/lib/test/fixtures/already-configured-ts-import/App.tsx b/packages/expo-cli/lib/test/fixtures/already-configured-ts-import/App.tsx new file mode 100644 index 00000000..bbab26dc --- /dev/null +++ b/packages/expo-cli/lib/test/fixtures/already-configured-ts-import/App.tsx @@ -0,0 +1,24 @@ +import Bugsnag from '@bugsnag/expo' +import React from 'react' +import { StyleSheet, Text, View } from 'react-native' + +Bugsnag.start() + +export default class App extends React.Component { + render () { + return ( + + Hello Expo! + + ) + } +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: '#fff', + alignItems: 'center', + justifyContent: 'center' + } +}) diff --git a/packages/expo-cli/lib/test/fixtures/already-configured-ts-require/App.tsx b/packages/expo-cli/lib/test/fixtures/already-configured-ts-require/App.tsx new file mode 100644 index 00000000..157e69a8 --- /dev/null +++ b/packages/expo-cli/lib/test/fixtures/already-configured-ts-require/App.tsx @@ -0,0 +1,24 @@ +const Bugsnag = require('@bugsnag/expo') +const React = require('react') +const { StyleSheet, Text, View } = require('react-native') + +Bugsnag.start() + +export default class App extends React.Component { + render () { + return ( + + Hello Expo! + + ) + } +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: '#fff', + alignItems: 'center', + justifyContent: 'center' + } +}) diff --git a/packages/expo-cli/lib/test/fixtures/already-configured-tsx-import/App.tsx b/packages/expo-cli/lib/test/fixtures/already-configured-tsx-import/App.tsx new file mode 100644 index 00000000..bbab26dc --- /dev/null +++ b/packages/expo-cli/lib/test/fixtures/already-configured-tsx-import/App.tsx @@ -0,0 +1,24 @@ +import Bugsnag from '@bugsnag/expo' +import React from 'react' +import { StyleSheet, Text, View } from 'react-native' + +Bugsnag.start() + +export default class App extends React.Component { + render () { + return ( + + Hello Expo! + + ) + } +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: '#fff', + alignItems: 'center', + justifyContent: 'center' + } +}) diff --git a/packages/expo-cli/lib/test/fixtures/already-configured-tsx-import/app.json b/packages/expo-cli/lib/test/fixtures/already-configured-tsx-import/app.json new file mode 100644 index 00000000..e22e88e7 --- /dev/null +++ b/packages/expo-cli/lib/test/fixtures/already-configured-tsx-import/app.json @@ -0,0 +1,39 @@ +{ + "expo": { + "name": "Bugsnag test fixture", + "slug": "bugsnag-test-fixture", + "privacy": "unlisted", + "sdkVersion": "32.0.0", + "platforms": [ + "ios", + "android" + ], + "version": "1.0.0", + "orientation": "portrait", + "icon": "./assets/icon.png", + "splash": { + "image": "./assets/splash.png", + "resizeMode": "contain", + "backgroundColor": "#ffffff" + }, + "updates": { + "fallbackToCacheTimeout": 0 + }, + "assetBundlePatterns": [ + "**/*" + ], + "extra": { + "bugsnag": { + "apiKey": "XoXoXoXoXoXo" + } + }, + "hooks": { + "postPublish": [ + { + "file": "@bugsnag/expo/hooks/post-publish.js", + "config": {} + } + ] + } + } +} diff --git a/packages/expo-cli/lib/test/fixtures/already-configured-tsx-import/package.json b/packages/expo-cli/lib/test/fixtures/already-configured-tsx-import/package.json new file mode 100644 index 00000000..903f973c --- /dev/null +++ b/packages/expo-cli/lib/test/fixtures/already-configured-tsx-import/package.json @@ -0,0 +1,8 @@ +{ + "name": "already-configured-ts-import", + "private": "true", + "version": "0.0.0", + "dependencies": { + "@bugsnag/expo": "7.0.0" + } +} diff --git a/packages/expo-cli/lib/test/fixtures/already-configured-tsx-require/App.tsx b/packages/expo-cli/lib/test/fixtures/already-configured-tsx-require/App.tsx new file mode 100644 index 00000000..157e69a8 --- /dev/null +++ b/packages/expo-cli/lib/test/fixtures/already-configured-tsx-require/App.tsx @@ -0,0 +1,24 @@ +const Bugsnag = require('@bugsnag/expo') +const React = require('react') +const { StyleSheet, Text, View } = require('react-native') + +Bugsnag.start() + +export default class App extends React.Component { + render () { + return ( + + Hello Expo! + + ) + } +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: '#fff', + alignItems: 'center', + justifyContent: 'center' + } +}) diff --git a/packages/expo-cli/lib/test/fixtures/already-configured-tsx-require/app.json b/packages/expo-cli/lib/test/fixtures/already-configured-tsx-require/app.json new file mode 100644 index 00000000..e22e88e7 --- /dev/null +++ b/packages/expo-cli/lib/test/fixtures/already-configured-tsx-require/app.json @@ -0,0 +1,39 @@ +{ + "expo": { + "name": "Bugsnag test fixture", + "slug": "bugsnag-test-fixture", + "privacy": "unlisted", + "sdkVersion": "32.0.0", + "platforms": [ + "ios", + "android" + ], + "version": "1.0.0", + "orientation": "portrait", + "icon": "./assets/icon.png", + "splash": { + "image": "./assets/splash.png", + "resizeMode": "contain", + "backgroundColor": "#ffffff" + }, + "updates": { + "fallbackToCacheTimeout": 0 + }, + "assetBundlePatterns": [ + "**/*" + ], + "extra": { + "bugsnag": { + "apiKey": "XoXoXoXoXoXo" + } + }, + "hooks": { + "postPublish": [ + { + "file": "@bugsnag/expo/hooks/post-publish.js", + "config": {} + } + ] + } + } +} diff --git a/packages/expo-cli/lib/test/fixtures/already-configured-tsx-require/package.json b/packages/expo-cli/lib/test/fixtures/already-configured-tsx-require/package.json new file mode 100644 index 00000000..d1a6e79e --- /dev/null +++ b/packages/expo-cli/lib/test/fixtures/already-configured-tsx-require/package.json @@ -0,0 +1,8 @@ +{ + "name": "already-configured-ts-require", + "private": "true", + "version": "0.0.0", + "dependencies": { + "@bugsnag/expo": "7.0.0" + } +} diff --git a/packages/expo-cli/lib/test/fixtures/blank-tsx/App.tsx b/packages/expo-cli/lib/test/fixtures/blank-tsx/App.tsx new file mode 100644 index 00000000..6d256168 --- /dev/null +++ b/packages/expo-cli/lib/test/fixtures/blank-tsx/App.tsx @@ -0,0 +1,21 @@ +import React from 'react' +import { StyleSheet, Text, View } from 'react-native' + +export default class App extends React.Component { + render () { + return ( + + Hello Expo! + + ) + } +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: '#fff', + alignItems: 'center', + justifyContent: 'center' + } +}) diff --git a/packages/expo-cli/lib/test/fixtures/blank-tsx/app.json b/packages/expo-cli/lib/test/fixtures/blank-tsx/app.json new file mode 100644 index 00000000..d88f23f9 --- /dev/null +++ b/packages/expo-cli/lib/test/fixtures/blank-tsx/app.json @@ -0,0 +1,26 @@ +{ + "expo": { + "name": "Bugsnag test fixture", + "slug": "bugsnag-test-fixture", + "privacy": "unlisted", + "sdkVersion": "32.0.0", + "platforms": [ + "ios", + "android" + ], + "version": "1.0.0", + "orientation": "portrait", + "icon": "./assets/icon.png", + "splash": { + "image": "./assets/splash.png", + "resizeMode": "contain", + "backgroundColor": "#ffffff" + }, + "updates": { + "fallbackToCacheTimeout": 0 + }, + "assetBundlePatterns": [ + "**/*" + ] + } +} diff --git a/packages/expo-cli/lib/test/fixtures/blank-tsx/package.json b/packages/expo-cli/lib/test/fixtures/blank-tsx/package.json new file mode 100644 index 00000000..b70fda29 --- /dev/null +++ b/packages/expo-cli/lib/test/fixtures/blank-tsx/package.json @@ -0,0 +1,5 @@ +{ + "name": "bugsnag-test-fixture-blank-ts-and-js", + "private": "true", + "version": "0.0.0" +} diff --git a/packages/expo-cli/lib/test/insert.test.js b/packages/expo-cli/lib/test/insert.test.js index cb98a599..ce0e1cae 100644 --- a/packages/expo-cli/lib/test/insert.test.js +++ b/packages/expo-cli/lib/test/insert.test.js @@ -26,6 +26,16 @@ describe('expo-cli: insert', () => { }) }) + it('should work on a fresh .tsx project', async () => { + await withFixture('blank-tsx', async (projectRoot) => { + const msg = await insert(projectRoot) + expect(msg).toBe(undefined) + + const appJs = await readFile(`${projectRoot}/App.tsx`, 'utf8') + expect(appJs).toMatch(/^import Bugsnag from '@bugsnag\/expo';\sBugsnag.start\(\);\s/) + }) + }) + it('shouldn’t insert if @bugsnag/expo is already imported (import, js)', async () => { await withFixture('already-configured-js-import', async (projectRoot) => { const appJsBefore = await readFile(`${projectRoot}/App.js`, 'utf8') @@ -70,9 +80,31 @@ describe('expo-cli: insert', () => { }) }) - it('should provide a reasonable error when there is no App.js or App.ts', async () => { + it('shouldn’t insert if @bugsnag/expo is already imported (import, tsx)', async () => { + await withFixture('already-configured-tsx-import', async (projectRoot) => { + const appTsBefore = await readFile(`${projectRoot}/App.tsx`, 'utf8') + const msg = await insert(projectRoot) + expect(msg).toMatch(/already/) + + const appTsAfter = await readFile(`${projectRoot}/App.tsx`, 'utf8') + expect(appTsAfter).toBe(appTsBefore) + }) + }) + + it('shouldn’t insert if @bugsnag/expo is already imported (require, tsx)', async () => { + await withFixture('already-configured-tsx-require', async (projectRoot) => { + const appTsBefore = await readFile(`${projectRoot}/App.tsx`, 'utf8') + const msg = await insert(projectRoot) + expect(msg).toMatch(/already/) + + const appTsAfter = await readFile(`${projectRoot}/App.tsx`, 'utf8') + expect(appTsAfter).toBe(appTsBefore) + }) + }) + + it('should provide a reasonable error when there is no App.js or App.ts/tsx', async () => { await withFixture('empty-00', async (projectRoot) => { - await expect(insert(projectRoot)).rejects.toThrow(/^Couldn’t find App\.js or App\.ts in/) + await expect(insert(projectRoot)).rejects.toThrow(/^Couldn’t find App\.js or App\.ts\/tsx in/) }) })