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/)
})
})