diff --git a/.buildkite/browser-pipeline.yml b/.buildkite/browser-pipeline.yml index 2fbad82a7f..beb18fb99a 100644 --- a/.buildkite/browser-pipeline.yml +++ b/.buildkite/browser-pipeline.yml @@ -16,6 +16,21 @@ steps: - docker-compose#v3.9.0: push: - browser-maze-runner:855461928731.dkr.ecr.us-west-1.amazonaws.com/js:ci-browser-${BRANCH_NAME} +# + - label: ':chrome: v30 Browser tests' + depends_on: "browser-maze-runner-image" + timeout_in_minutes: 20 + plugins: + docker-compose#v3.9.0: + pull: browser-maze-runner + run: browser-maze-runner + use-aliases: true + verbose: true + command: + - --farm=bs + - --browser=chrome_30 + concurrency: 5 + concurrency_group: 'browserstack' - label: ':chrome: v43 Browser tests' depends_on: "browser-maze-runner-image" @@ -29,7 +44,7 @@ steps: command: - --farm=bs - --browser=chrome_43 - concurrency: 5 + concurrency: 2 concurrency_group: 'browserstack' - label: ':chrome: v61 Browser tests' @@ -44,7 +59,7 @@ steps: command: - --farm=bs - --browser=chrome_61 - concurrency: 5 + concurrency: 2 concurrency_group: 'browserstack' - label: ':chrome: latest Browser tests' @@ -59,7 +74,7 @@ steps: command: - --farm=bs - --browser=chrome_latest - concurrency: 5 + concurrency: 2 concurrency_group: 'browserstack' - label: ':ie: v8 Browser tests' @@ -74,7 +89,7 @@ steps: command: - --farm=bs - --browser=ie_8 - concurrency: 5 + concurrency: 2 concurrency_group: 'browserstack' - label: ':ie: v9 Browser tests' @@ -89,7 +104,7 @@ steps: command: - --farm=bs - --browser=ie_9 - concurrency: 5 + concurrency: 2 concurrency_group: 'browserstack' - label: ':ie: v10 Browser tests' @@ -104,7 +119,7 @@ steps: command: - --farm=bs - --browser=ie_10 - concurrency: 5 + concurrency: 2 concurrency_group: 'browserstack' - label: ':ie: v11 Browser tests' @@ -121,7 +136,7 @@ steps: - --browser=ie_11 env: HOST: 'localhost' # IE11 needs the host set to localhost for some reason!ß - concurrency: 5 + concurrency: 2 concurrency_group: 'browserstack' - label: ':edge: v14 Browser tests' @@ -136,7 +151,7 @@ steps: command: - --farm=bs - --browser=edge_14 - concurrency: 5 + concurrency: 2 concurrency_group: 'browserstack' - label: ':edge: v15 Browser tests' @@ -151,7 +166,7 @@ steps: command: - --farm=bs - --browser=edge_15 - concurrency: 5 + concurrency: 2 concurrency_group: 'browserstack' - label: ':safari: v6 Browser tests' @@ -166,7 +181,7 @@ steps: command: - --farm=bs - --browser=safari_6 - concurrency: 5 + concurrency: 2 concurrency_group: 'browserstack' - label: ':safari: v10 Browser tests' @@ -181,7 +196,7 @@ steps: command: - --farm=bs - --browser=safari_10 - concurrency: 5 + concurrency: 2 concurrency_group: 'browserstack' - label: ':safari: v13 Browser tests' @@ -196,7 +211,7 @@ steps: command: - --farm=bs - --browser=safari_13 - concurrency: 5 + concurrency: 2 concurrency_group: 'browserstack' - label: ':safari: v15 Browser tests' @@ -211,7 +226,7 @@ steps: command: - --farm=bs - --browser=safari_15 - concurrency: 5 + concurrency: 2 concurrency_group: 'browserstack' - label: ':iphone: iOS 10.3 Browser tests' @@ -228,10 +243,27 @@ steps: - --browser=iphone_7 env: HOST: "bs-local.com" + concurrency: 2 + concurrency_group: 'browserstack' + + - label: ':iphone: iOS 15.4 Browser tests' + depends_on: "browser-maze-runner-image" + timeout_in_minutes: 20 + plugins: + docker-compose#v3.9.0: + pull: browser-maze-runner + run: browser-maze-runner + use-aliases: true + verbose: true + command: + - --farm=bs + - --browser=iphone_13 + env: + HOST: "bs-local.com" concurrency: 5 concurrency_group: 'browserstack' - - label: ':android: Samsung Galaxy S8 Browser tests' + - label: ':android: Android 4.4 Browser tests' depends_on: "browser-maze-runner-image" timeout_in_minutes: 20 plugins: @@ -242,10 +274,55 @@ steps: verbose: true command: - --farm=bs - - --browser=android_s8 + - --browser=android_nexus5 + concurrency: 5 + concurrency_group: 'browserstack' + + - label: ':android: Android 5.0 Browser tests' + depends_on: "browser-maze-runner-image" + timeout_in_minutes: 20 + plugins: + docker-compose#v3.9.0: + pull: browser-maze-runner + run: browser-maze-runner + use-aliases: true + verbose: true + command: + - --farm=bs + - --browser=android_s6 concurrency: 5 concurrency_group: 'browserstack' + - label: ':android: Android 6.0 Browser tests' + depends_on: "browser-maze-runner-image" + timeout_in_minutes: 20 + plugins: + docker-compose#v3.9.0: + pull: browser-maze-runner + run: browser-maze-runner + use-aliases: true + verbose: true + command: + - --farm=bs + - --browser=android_s7 + concurrency: 5 + concurrency_group: 'browserstack' + + - label: ':android: Android 7.0 Browser tests' + depends_on: "browser-maze-runner-image" + timeout_in_minutes: 20 + plugins: + docker-compose#v3.9.0: + pull: browser-maze-runner + run: browser-maze-runner + use-aliases: true + verbose: true + command: + - --farm=bs + - --browser=android_s8 + concurrency: 2 + concurrency_group: 'browserstack' + - label: ':firefox: v30 Browser tests' depends_on: "browser-maze-runner-image" timeout_in_minutes: 20 @@ -258,7 +335,7 @@ steps: command: - --farm=bs - --browser=firefox_30 - concurrency: 5 + concurrency: 2 concurrency_group: 'browserstack' - label: ':firefox: v56 Browser tests' @@ -273,7 +350,7 @@ steps: command: - --farm=bs - --browser=firefox_56 - concurrency: 5 + concurrency: 2 concurrency_group: 'browserstack' - label: ':firefox: latest Browser tests' @@ -288,5 +365,5 @@ steps: command: - --farm=bs - --browser=firefox_latest - concurrency: 5 + concurrency: 2 concurrency_group: 'browserstack' diff --git a/.buildkite/react-native-cli-pipeline.yml b/.buildkite/react-native-cli-pipeline.yml index de2be4a8c5..5674e5785d 100644 --- a/.buildkite/react-native-cli-pipeline.yml +++ b/.buildkite/react-native-cli-pipeline.yml @@ -487,7 +487,7 @@ steps: - --device=ANDROID_11_0 - --a11y-locator - features/run-app-tests - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -508,7 +508,7 @@ steps: - --device=ANDROID_11_0 - --a11y-locator - features/run-app-tests - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -529,7 +529,7 @@ steps: - --device=ANDROID_11_0 - --a11y-locator - features/run-app-tests - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -550,7 +550,7 @@ steps: - --device=ANDROID_11_0 - --a11y-locator - features/run-app-tests - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -571,7 +571,7 @@ steps: - --device=ANDROID_11_0 - --a11y-locator - features/run-app-tests - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -592,7 +592,7 @@ steps: - --device=ANDROID_11_0 - --a11y-locator - features/run-app-tests - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -613,7 +613,7 @@ steps: - --device=ANDROID_11_0 - --a11y-locator - features/run-app-tests - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -634,7 +634,7 @@ steps: - --device=ANDROID_11_0 - --a11y-locator - features/run-app-tests - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -655,7 +655,7 @@ steps: - --device=ANDROID_11_0 - --a11y-locator - features/run-app-tests - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -676,7 +676,7 @@ steps: - --device=ANDROID_12_0 - --a11y-locator - features/run-app-tests - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -700,7 +700,7 @@ steps: - --device=IOS_14 - --a11y-locator - features/run-app-tests - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -721,7 +721,7 @@ steps: - --device=IOS_14 - --a11y-locator - features/run-app-tests - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -742,7 +742,7 @@ steps: - --device=IOS_14 - --a11y-locator - features/run-app-tests - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -763,7 +763,7 @@ steps: - --device=IOS_14 - --a11y-locator - features/run-app-tests - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -784,7 +784,7 @@ steps: - --device=IOS_14 - --a11y-locator - features/run-app-tests - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -805,7 +805,7 @@ steps: - --device=IOS_14 - --a11y-locator - features/run-app-tests - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -826,7 +826,7 @@ steps: - --device=IOS_14 - --a11y-locator - features/run-app-tests - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -847,7 +847,7 @@ steps: - --device=IOS_14 - --a11y-locator - features/run-app-tests - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -868,7 +868,7 @@ steps: - --device=IOS_14 - --a11y-locator - features/run-app-tests - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -889,6 +889,6 @@ steps: - --device=IOS_14 - --a11y-locator - features/run-app-tests - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager diff --git a/.buildkite/react-native-pipeline.yml b/.buildkite/react-native-pipeline.yml index b899fdb001..ebbb9e75a9 100644 --- a/.buildkite/react-native-pipeline.yml +++ b/.buildkite/react-native-pipeline.yml @@ -270,7 +270,7 @@ steps: - --fail-fast env: SKIP_NAVIGATION_SCENARIOS: "true" - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -294,7 +294,7 @@ steps: - --fail-fast env: SKIP_NAVIGATION_SCENARIOS: "true" - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -317,7 +317,7 @@ steps: - --fail-fast env: SKIP_NAVIGATION_SCENARIOS: "true" - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -341,7 +341,7 @@ steps: env: SKIP_NAVIGATION_SCENARIOS: "true" HERMES: "true" - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -365,7 +365,7 @@ steps: env: SKIP_NAVIGATION_SCENARIOS: "true" HERMES: "true" - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -389,7 +389,7 @@ steps: - --fail-fast env: SKIP_NAVIGATION_SCENARIOS: "true" - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -414,7 +414,7 @@ steps: env: SKIP_NAVIGATION_SCENARIOS: "true" HERMES: "true" - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -439,7 +439,7 @@ steps: env: SKIP_NAVIGATION_SCENARIOS: "true" HERMES: "true" - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -461,7 +461,7 @@ steps: - --a11y-locator - --fail-fast - features/navigation.feature - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -486,7 +486,7 @@ steps: - --appium-version=1.18.0 - --fail-fast - features/navigation.feature - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -508,7 +508,7 @@ steps: - --a11y-locator - --fail-fast - features/navigation.feature - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -531,7 +531,7 @@ steps: - --appium-version=1.21.0 - --fail-fast - features/navigation.feature - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -553,7 +553,7 @@ steps: - --a11y-locator - --fail-fast - features/navigation.feature - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -578,7 +578,7 @@ steps: - --a11y-locator - --fail-fast - features/navigation.feature - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -600,7 +600,7 @@ steps: - --a11y-locator - --fail-fast - features/navigation.feature - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager @@ -625,6 +625,6 @@ steps: - --appium-version=1.18.0 - --fail-fast - features/navigation.feature - concurrency: 9 + concurrency: 24 concurrency_group: 'browserstack-app' concurrency_method: eager diff --git a/CHANGELOG.md b/CHANGELOG.md index 20276b1a9e..7206e58087 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ # Changelog +## v7.16.5 (2022-05-18) + +### Changed + +- (react-native) Update bugsnag-android to v5.22.3 + - Max reported threads can now be configured using manifest meta-data "com.bugsnag.android. MAX_REPORTED_THREADS" + [bugsnag-android#1655](https://github.com/bugsnag/bugsnag-android/pull/1655) + - Small improvement to startup performance (Bugsnag.start) + [bugsnag-android#1648](https://github.com/bugsnag/bugsnag-android/pull/1648) + - Fixed NDK stack-traces for libraries linked after `Bugsnag.start` was called + [bugsnag-android#1671](https://github.com/bugsnag/bugsnag-android/pull/1671) + - Fixed concurrency bug that could be triggered via the React Native plugin + [bugsnag-android#1679](https://github.com/bugsnag/bugsnag-android/pull/1679) + - Correctly report `device.locationStatus` on Android 12 onwards using `LocationManager.isLocationEnabled` + [bugsnag-android#1683](https://github.com/bugsnag/bugsnag-android/pull/1683) + - Small performance improvements to `Bugnag.start` + [bugsnag-android#1680](https://github.com/bugsnag/bugsnag-android/pull/1680) +- (react-native-cli) Fix 'insert' command with RN 0.68+ [#1726](https://github.com/bugsnag/bugsnag-js/pull/1726) +- (plugin-react|plugin-vue|plugin-react-navigation|plugin-react-native-navigation) Set `@bugsnag/core` to be an optional peer dependency to avoid unmet peer dependency warnings [#1735](https://github.com/bugsnag/bugsnag-js/pull/1735) +- (electron) Improved error message when no apiKey is provided to Bugsnag.start() [#1738](https://github.com/bugsnag/bugsnag-js/pull/1738) +- (plugin-simple-throttle) Warning message added when error handler has exceeded `maxEvents` [#1739](https://github.com/bugsnag/bugsnag-js/pull/1739) + ## v7.16.4 (2022-05-03) - (expo) This release marks a change in the version scheme used by `@bugsnag/expo` and a move to its own repo, [`bugsnag-expo`](https://github.com/bugsnag/bugsnag-expo) diff --git a/packages/electron/src/client/main.js b/packages/electron/src/client/main.js index 4effd5ebd0..1966f63566 100644 --- a/packages/electron/src/client/main.js +++ b/packages/electron/src/client/main.js @@ -16,6 +16,12 @@ const { schema } = require('../config/main') Event.__type = 'electronnodejs' module.exports = (opts) => { + // check api key has been provided as we need it to create the FileStore + // which happens before the API key is validated + if (typeof opts.apiKey !== 'string') { + throw new Error('No Bugsnag API Key set') + } + const filestore = new FileStore( opts.apiKey, electron.app.getPath('userCache'), diff --git a/packages/electron/src/client/test/client.test-main.ts b/packages/electron/src/client/test/client.test-main.ts new file mode 100644 index 0000000000..a3f2b27412 --- /dev/null +++ b/packages/electron/src/client/test/client.test-main.ts @@ -0,0 +1,13 @@ +import createClient from '../main' + +describe('@bugsnag/electron client', () => { + describe('createClient', () => { + it('throws an error when an apiKey is not provided', () => { + expect( + () => { + createClient({}) + } + ).toThrowError('No Bugsnag API Key set') + }) + }) +}) diff --git a/packages/plugin-react-native-navigation/package.json b/packages/plugin-react-native-navigation/package.json index 34f3026cc5..169c4cf9d1 100644 --- a/packages/plugin-react-native-navigation/package.json +++ b/packages/plugin-react-native-navigation/package.json @@ -27,6 +27,11 @@ "@bugsnag/core": "^7.0.0", "react-native-navigation": "2 - 7" }, + "peerDependenciesMeta": { + "@bugsnag/core": { + "optional": true + } + }, "scripts": { "test:types": "tsc -p tsconfig.json" } diff --git a/packages/plugin-react-navigation/package.json b/packages/plugin-react-navigation/package.json index 215c2a4b5d..302b0846ca 100644 --- a/packages/plugin-react-navigation/package.json +++ b/packages/plugin-react-navigation/package.json @@ -33,5 +33,10 @@ "peerDependencies": { "@bugsnag/core": "^7.0.0", "@react-navigation/native": "^5.0 || ^6.0" + }, + "peerDependenciesMeta": { + "@bugsnag/core": { + "optional": true + } } } diff --git a/packages/plugin-react/package.json b/packages/plugin-react/package.json index ffb9aec0d8..58b24726f5 100644 --- a/packages/plugin-react/package.json +++ b/packages/plugin-react/package.json @@ -28,5 +28,10 @@ }, "peerDependencies": { "@bugsnag/core": "^7.0.0" + }, + "peerDependenciesMeta": { + "@bugsnag/core": { + "optional": true + } } } diff --git a/packages/plugin-simple-throttle/test/throttle.test.ts b/packages/plugin-simple-throttle/test/throttle.test.ts index db1329fc86..32589456f4 100644 --- a/packages/plugin-simple-throttle/test/throttle.test.ts +++ b/packages/plugin-simple-throttle/test/throttle.test.ts @@ -3,11 +3,19 @@ import plugin from '../' import Client from '@bugsnag/core/client' describe('plugin: throttle', () => { + const payloads = [] + const c = new Client({ apiKey: 'aaaa-aaaa-aaaa-aaaa' }, undefined, [plugin]) + const mockWarn = jest.fn() + c._logger.warn = mockWarn + c._setDelivery(client => ({ sendEvent: (payload) => payloads.push(payload), sendSession: () => {} })) + it('prevents more than maxEvents being sent', () => { - const payloads = [] - const c = new Client({ apiKey: 'aaaa-aaaa-aaaa-aaaa' }, undefined, [plugin]) - c._setDelivery(client => ({ sendEvent: (payload) => payloads.push(payload), sendSession: () => {} })) for (let i = 0; i < 100; i++) c.notify(new Error('This is fail')) expect(payloads.length).toBe(10) + expect(mockWarn).toHaveBeenCalledTimes(90) + }) + + it('logs an appropriate error message', () => { + expect(mockWarn).toHaveBeenCalledWith('Cancelling event send due to maxEvents per session limit of 10 being reached') }) }) diff --git a/packages/plugin-simple-throttle/throttle.js b/packages/plugin-simple-throttle/throttle.js index d1333b8b28..3de502ec61 100644 --- a/packages/plugin-simple-throttle/throttle.js +++ b/packages/plugin-simple-throttle/throttle.js @@ -12,7 +12,10 @@ module.exports = { // add onError hook client.addOnError((event) => { // have max events been sent already? - if (n >= client._config.maxEvents) return false + if (n >= client._config.maxEvents) { + client._logger.warn(`Cancelling event send due to maxEvents per session limit of ${client._config.maxEvents} being reached`) + return false + } n++ }) diff --git a/packages/plugin-vue/package.json b/packages/plugin-vue/package.json index 4bedfa7137..99621e687c 100644 --- a/packages/plugin-vue/package.json +++ b/packages/plugin-vue/package.json @@ -28,5 +28,10 @@ }, "peerDependencies": { "@bugsnag/core": "^7.0.0" + }, + "peerDependenciesMeta": { + "@bugsnag/core": { + "optional": true + } } } diff --git a/packages/react-native-cli/src/lib/Insert.ts b/packages/react-native-cli/src/lib/Insert.ts index 53572e9256..31f78943a8 100644 --- a/packages/react-native-cli/src/lib/Insert.ts +++ b/packages/react-native-cli/src/lib/Insert.ts @@ -44,19 +44,34 @@ export async function insertJs (projectRoot: string, logger: Logger): Promise { logger.info('Adding Bugsnag to the iOS layer') + const iosDir = path.join(projectRoot, 'ios') - let xcodeprojDir + let appDelegatePath + try { - xcodeprojDir = (await fs.readdir(iosDir)).find(p => p.endsWith('.xcodeproj')) + const xcodeprojDir = (await fs.readdir(iosDir)).find(p => p.endsWith('.xcodeproj')) + if (!xcodeprojDir) { - logger.warn(FAIL_MSG('AppDelegate.m')) + logger.warn(FAIL_MSG('AppDelegate')) return } + + const appDelegateDirectory = path.join(iosDir, xcodeprojDir.replace(/\.xcodeproj$/, '')) + + // handle both AppDelegate.m and AppDelegate.mm (RN 0.68+) + const appDelegateFile = (await fs.readdir(appDelegateDirectory)).find(p => p.startsWith('AppDelegate.m')) + + if (!appDelegateFile) { + logger.warn(FAIL_MSG('AppDelegate')) + return + } + + appDelegatePath = path.join(iosDir, xcodeprojDir.replace(/\.xcodeproj$/, ''), appDelegateFile) } catch (e) { - logger.error(FAIL_MSG('AppDelegate.m')) + logger.error(FAIL_MSG('AppDelegate')) return } - const appDelegatePath = path.join(iosDir, xcodeprojDir.replace(/\.xcodeproj$/, ''), 'AppDelegate.m') + try { const appDelegate = await fs.readFile(appDelegatePath, 'utf8') @@ -67,14 +82,21 @@ export async function insertIos (projectRoot: string, logger: Logger): Promise { test('insertIos(): success', async () => { type readdir = (path: string) => Promise const readdirMock = fs.readdir as unknown as jest.MockedFunction - readdirMock.mockResolvedValue(['BugsnagReactNativeCliTest.xcodeproj']) + + readdirMock + .mockResolvedValueOnce(['BugsnagReactNativeCliTest.xcodeproj']) + .mockResolvedValueOnce(['a', 'b', 'AppDelegate.m', 'c', 'd']) const appDelegate = await loadFixture(path.join(__dirname, 'fixtures', 'AppDelegate-before.m')) const readFileMock = fs.readFile as jest.MockedFunction @@ -94,7 +97,10 @@ test('insertIos(): success', async () => { test('insertIos(): already present', async () => { type readdir = (path: string) => Promise const readdirMock = fs.readdir as unknown as jest.MockedFunction - readdirMock.mockResolvedValue(['BugsnagReactNativeCliTest.xcodeproj']) + + readdirMock + .mockResolvedValueOnce(['BugsnagReactNativeCliTest.xcodeproj']) + .mockResolvedValueOnce(['a', 'b', 'AppDelegate.mm', 'c', 'd']) const appDelegate = await loadFixture(path.join(__dirname, 'fixtures', 'AppDelegate-after.m')) const readFileMock = fs.readFile as jest.MockedFunction @@ -104,7 +110,7 @@ test('insertIos(): already present', async () => { writeFileMock.mockResolvedValue() await insertIos('/random/path', logger) - expect(readFileMock).toHaveBeenCalledWith('/random/path/ios/BugsnagReactNativeCliTest/AppDelegate.m', 'utf8') + expect(readFileMock).toHaveBeenCalledWith('/random/path/ios/BugsnagReactNativeCliTest/AppDelegate.mm', 'utf8') expect(writeFileMock).not.toHaveBeenCalled() expect(logger.warn).toHaveBeenCalledWith('Bugsnag is already included, skipping') @@ -113,7 +119,10 @@ test('insertIos(): already present', async () => { test('insertIos(): failure to locate file', async () => { type readdir = (path: string) => Promise const readdirMock = fs.readdir as unknown as jest.MockedFunction - readdirMock.mockResolvedValue(['BugsnagReactNativeCliTest.xcodeproj']) + + readdirMock + .mockResolvedValueOnce(['BugsnagReactNativeCliTest.xcodeproj']) + .mockResolvedValueOnce(['a', 'b', 'not-an-AppDelegate.x', 'c', 'd']) const readFileMock = fs.readFile as jest.MockedFunction readFileMock.mockRejectedValue(await generateNotFoundError()) @@ -121,10 +130,10 @@ test('insertIos(): failure to locate file', async () => { const writeFileMock = fs.writeFile as jest.MockedFunction await insertIos('/random/path', logger) - expect(readFileMock).toHaveBeenCalledWith('/random/path/ios/BugsnagReactNativeCliTest/AppDelegate.m', 'utf8') + expect(readFileMock).not.toHaveBeenCalled() expect(writeFileMock).not.toHaveBeenCalled() - expect(logger.error).toHaveBeenCalledWith(expect.stringContaining('Failed to update "AppDelegate.m" automatically.')) + expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining('Failed to update "AppDelegate" automatically.')) }) test('insertIos(): failure to locate project directory', async () => { @@ -139,7 +148,7 @@ test('insertIos(): failure to locate project directory', async () => { expect(readFileMock).not.toHaveBeenCalled() expect(writeFileMock).not.toHaveBeenCalled() - expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining('Failed to update "AppDelegate.m" automatically.')) + expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining('Failed to update "AppDelegate" automatically.')) }) test('insertIos(): project directory error', async () => { @@ -154,23 +163,26 @@ test('insertIos(): project directory error', async () => { expect(readFileMock).not.toHaveBeenCalled() expect(writeFileMock).not.toHaveBeenCalled() - expect(logger.error).toHaveBeenCalledWith(expect.stringContaining('Failed to update "AppDelegate.m" automatically.')) + expect(logger.error).toHaveBeenCalledWith(expect.stringContaining('Failed to update "AppDelegate" automatically.')) }) test('insertIos(): no identifiable app launch method', async () => { type readdir = (path: string) => Promise const readdirMock = fs.readdir as unknown as jest.MockedFunction - readdirMock.mockResolvedValue(['BugsnagReactNativeCliTest.xcodeproj']) + + readdirMock + .mockResolvedValueOnce(['BugsnagReactNativeCliTest.xcodeproj']) + .mockResolvedValueOnce(['a', 'b', 'AppDelegate.mm', 'c', 'd']) const readFileMock = fs.readFile as jest.MockedFunction readFileMock.mockResolvedValue('not good objective c') const writeFileMock = fs.writeFile as jest.MockedFunction await insertIos('/random/path', logger) - expect(readFileMock).toHaveBeenCalledWith('/random/path/ios/BugsnagReactNativeCliTest/AppDelegate.m', 'utf8') + expect(readFileMock).toHaveBeenCalledWith('/random/path/ios/BugsnagReactNativeCliTest/AppDelegate.mm', 'utf8') expect(writeFileMock).not.toHaveBeenCalled() - expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining('Failed to update "AppDelegate.m" automatically.')) + expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining('Failed to update "AppDelegate.mm" automatically.')) }) test('insertAndroid(): success', async () => { diff --git a/packages/react-native/android/build.gradle b/packages/react-native/android/build.gradle index 48a6d61d17..1abc83e067 100644 --- a/packages/react-native/android/build.gradle +++ b/packages/react-native/android/build.gradle @@ -39,8 +39,8 @@ android { } dependencies { - api "com.bugsnag:bugsnag-android:5.22.0" - api "com.bugsnag:bugsnag-plugin-react-native:5.22.0" + api "com.bugsnag:bugsnag-android:5.22.3" + api "com.bugsnag:bugsnag-plugin-react-native:5.22.3" implementation 'com.facebook.react:react-native:+' testImplementation "junit:junit:4.12" diff --git a/packages/react-native/prepare-android-vendor.config b/packages/react-native/prepare-android-vendor.config index dea08dd29f..ef078aa15b 100644 --- a/packages/react-native/prepare-android-vendor.config +++ b/packages/react-native/prepare-android-vendor.config @@ -1,2 +1,2 @@ version -5.22.0 +5.22.3 diff --git a/test/browser/features/fixtures/browser_errors.yml b/test/browser/features/fixtures/browser_errors.yml index 87a41a0d18..01d84246c9 100644 --- a/test/browser/features/fixtures/browser_errors.yml +++ b/test/browser/features/fixtures/browser_errors.yml @@ -281,6 +281,109 @@ iphone_7: lineNumber: 18 columnNumber: 25 +iphone_13: + handled: + errorClass: 'ReferenceError' + errorMessage: "Can't find variable: foo" + unhandled_syntax: + errorClass: 'SyntaxError' + errorMessage: "Unexpected token '!'. Parse error." + lineNumber: 18 + columnNumber: 0 + file: '/unhandled/script/a.html' + unhandled_thrown: + errorClass: 'Error' + errorMessage: "bad things" + lineNumber: 18 + columnNumber: 22 + unhandled_undefined_function: + errorClass: 'ReferenceError' + errorMessage: "Can't find variable: nevergoingtoexist_notinamillionyears" + lineNumber: 18 + columnNumber: 43 + unhandled_malformed_uri: + errorClass: 'URIError' + errorMessage: URI error + lineNumber: 18 + columnNumber: 25 +android_nexus5: + handled: + errorClass: 'ReferenceError' + errorMessage: 'foo is not defined' + unhandled_syntax: + errorClass: 'SyntaxError' + errorMessage: "Unexpected token '!'" + lineNumber: 18 + columnNumber: 13 + file: '/unhandled/script/a.html' + unhandled_thrown: + errorClass: 'Error' + errorMessage: "bad things" + lineNumber: 18 + columnNumber: 13 + unhandled_undefined_function: + errorClass: 'ReferenceError' + errorMessage: nevergoingtoexist_notinamillionyears is not defined + lineNumber: 18 + columnNumber: 7 + unhandled_malformed_uri: + errorClass: 'URIError' + errorMessage: URI malformed + lineNumber: 18 + columnNumber: 7 + +android_s6: + handled: + errorClass: 'ReferenceError' + errorMessage: 'foo is not defined' + unhandled_syntax: + errorClass: 'SyntaxError' + errorMessage: "Unexpected token '!'" + lineNumber: 18 + columnNumber: 13 + file: '/unhandled/script/a.html' + unhandled_thrown: + errorClass: 'Error' + errorMessage: "bad things" + lineNumber: 18 + columnNumber: 13 + unhandled_undefined_function: + errorClass: 'ReferenceError' + errorMessage: nevergoingtoexist_notinamillionyears is not defined + lineNumber: 18 + columnNumber: 7 + unhandled_malformed_uri: + errorClass: 'URIError' + errorMessage: URI malformed + lineNumber: 18 + columnNumber: 7 + +android_s7: + handled: + errorClass: 'ReferenceError' + errorMessage: 'foo is not defined' + unhandled_syntax: + errorClass: 'SyntaxError' + errorMessage: "Unexpected token '!'" + lineNumber: 18 + columnNumber: 13 + file: '/unhandled/script/a.html' + unhandled_thrown: + errorClass: 'Error' + errorMessage: "bad things" + lineNumber: 18 + columnNumber: 13 + unhandled_undefined_function: + errorClass: 'ReferenceError' + errorMessage: nevergoingtoexist_notinamillionyears is not defined + lineNumber: 18 + columnNumber: 7 + unhandled_malformed_uri: + errorClass: 'URIError' + errorMessage: URI malformed + lineNumber: 18 + columnNumber: 7 + android_s8: handled: errorClass: 'ReferenceError' @@ -381,6 +484,32 @@ firefox_latest: lineNumber: 18 columnNumber: 25 +chrome_30: + handled: + errorClass: 'ReferenceError' + errorMessage: 'foo is not defined' + unhandled_syntax: + errorClass: 'SyntaxError' + errorMessage: "Unexpected token !" + lineNumber: 18 + columnNumber: 12 + file: '/unhandled/script/a.html' + unhandled_thrown: + errorClass: 'Error' + errorMessage: "bad things" + lineNumber: 18 + columnNumber: 13 + unhandled_undefined_function: + errorClass: 'ReferenceError' + errorMessage: nevergoingtoexist_notinamillionyears is not defined + lineNumber: 18 + columnNumber: 7 + unhandled_malformed_uri: + errorClass: 'URIError' + errorMessage: URI malformed + lineNumber: 18 + columnNumber: 6 + chrome_43: handled: errorClass: 'ReferenceError' @@ -407,6 +536,7 @@ chrome_43: lineNumber: 18 columnNumber: 7 + chrome_61: handled: errorClass: 'ReferenceError'