Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

Update bugsnag-android to [v6.22.0](https//github.com/bugsnag/bugsnag-android/releases/tag/v6.22.0) [#2656](https://github.com/bugsnag/bugsnag-js/pull/2656)

### Fixed

(plugin-network-instrumentation) Report HTTP Errors as handled [#2662](https://github.com/bugsnag/bugsnag-js/pull/2662)

## [8.8.1] - 2026-01-26

### Fixed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ module.exports = (config = {}, global = window) => {

const handledState = {
severity: 'error',
unhandled: true,
unhandled: false,
severityReason: { type: 'httpError' }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ describe('plugin-network-instrumentation', () => {
expect(event.exceptions[0].errorMessage).toBe('404: https://api.example.com/users/123')
expect(event.context).toBe('POST api.example.com')
expect(event.severity).toBe('error')
expect(event.unhandled).toBe(true)
expect(event.unhandled).toBe(false)
expect(event.severityReason.type).toBe('httpError')

// Verify request metadata
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ describe('plugin-network-instrumentation', () => {
expect(event.exceptions[0].errorMessage).toBe('404: https://example.com/api/users')
expect(event.context).toBe('GET example.com')
expect(event.severity).toBe('error')
expect(event.unhandled).toBe(true)
expect(event.unhandled).toBe(false)
expect(event.severityReason.type).toBe('httpError')
expect(event.request.url).toBe('https://example.com/api/users')
expect(event.request.httpMethod).toBe('GET')
Expand Down
3 changes: 2 additions & 1 deletion scripts/generate-react-native-fixture.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ const replacementFilesDir = resolve(ROOT_DIR, 'test/react-native/features/fixtur

const INTERNAL_DEPENDENCIES = [
'@bugsnag/react-native',
'@bugsnag/request-tracker'
'@bugsnag/request-tracker',
'@bugsnag/plugin-network-instrumentation'
]

// make sure we install a compatible versions of peer dependencies
Expand Down
7 changes: 7 additions & 0 deletions test/react-native/features/breadcrumbs.feature
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,10 @@ Scenario: Manual breadcrumbs (Native)
| ios | NSException |
And the exception "message" equals "BreadcrumbsNativeManualScenario"
And the event contains a breadcrumb matching the JSON fixture in "features/fixtures/expected_breadcrumbs/NativeManualScenario.json"

Scenario: Network breadcrumbs (JS)
When I run "NetworkBreadcrumbsJsScenario"
Then I wait to receive an error
And the exception "errorClass" equals "Error"
And the exception "message" equals "NetworkBreadcrumbsJsScenario"
And the event contains a breadcrumb matching the JSON fixture in "features/fixtures/expected_breadcrumbs/NetworkJsScenario.json"
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"type": "request",
"name": "XMLHttpRequest succeeded",
"timestamp": "^\\d{4}\\-\\d{2}\\-\\d{2}T\\d{2}:\\d{2}:[\\d\\.]+Z?$",
"metaData": {
"status": "NUMBER",
"method": "GET",
"url": "^http:\/\/[0-9.:]*\/reflect$",
"duration": "NUMBER"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[
{
"message": "^401: .*\/reflect\/[?]status=401$",
"errorClass": "HTTPError",
"type": "reactnativejs",
"stacktrace": "IGNORE"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[
{
"message": "^500: .*\/reflect\/[?]status=500$",
"errorClass": "HTTPError",
"type": "reactnativejs",
"stacktrace": "IGNORE"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Scenario from './Scenario'
import Bugsnag from '@bugsnag/react-native'

export class NetworkBreadcrumbsJsScenario extends Scenario {
constructor (nativeConfig, jsConfig, scenarioData) {
super()
this.reflectEndpoint = nativeConfig.endpoints.notify.replace('/notify', '/reflect')
}

run () {
fetch(this.reflectEndpoint).then(() => {
Bugsnag.notify(new Error('NetworkBreadcrumbsJsScenario'))
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import Scenario from './Scenario'
import Bugsnag from '@bugsnag/react-native'
import BugsnagPluginNetworkInstrumentation from '@bugsnag/plugin-network-instrumentation'

export class NetworkRequestScenario extends Scenario {
constructor (nativeConfig, jsConfig, scenarioData) {
super()
this.reflectEndpoint = nativeConfig.endpoints.notify.replace('/notify', '/reflect')
this.statusCode = scenarioData

const plugin = new BugsnagPluginNetworkInstrumentation({
maxRequestSize: 1024,
maxResponseSize: 1024
})

jsConfig.plugins = jsConfig.plugins || []
jsConfig.plugins.push(plugin)
}

run () {
const url = new URL(this.reflectEndpoint)
url.searchParams.append('status', this.statusCode)
fetch(url).catch((err) => {
Bugsnag.notify(err)
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export { BreadcrumbsAutomaticErrorScenario } from './BreadcrumbsAutomaticErrorSc
export { BreadcrumbsJsManualScenario } from './BreadcrumbsJsManualScenario'
export { BreadcrumbsNativeManualScenario } from './BreadcrumbsNativeManualScenario'
export { BreadcrumbsNullEnabledBreadcrumbTypesScenario } from './BreadcrumbsNullEnabledBreadcrumbTypesScenario'
export { NetworkBreadcrumbsJsScenario } from './NetworkBreadcrumbsJsScenario'

// device.feature
export { DeviceJsHandledScenario } from './DeviceJsHandledScenario'
Expand Down Expand Up @@ -80,3 +81,6 @@ export { ReactNativeErrorBoundaryScenario } from './ReactNativeErrorBoundaryScen
// grouping-discriminator.feature
export { GroupingDiscriminatorScenario } from './GroupingDiscriminatorScenario'
export { GroupingDiscriminatorNativeScenario } from './GroupingDiscriminatorNativeScenario'

// http_errors.feature
export { NetworkRequestScenario } from './NetworkRequestScenario'
19 changes: 19 additions & 0 deletions test/react-native/features/http_errors.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Feature: HTTP Errors

Scenario Outline: Error is reported for network requests with error status code
When I run "NetworkRequestScenario" with data "<status_code>"
And I wait to receive an error
Then the error payload field "events.0.context" matches the regex "^GET [0-9.]*:[0-9]{4}$"
And the error payload field "events.0.exceptions" matches the JSON fixture in "features/fixtures/expected_http_errors/<status_code>.json"
Examples:
| status_code |
| 401 |
| 500 |

Scenario Outline: Error is not reported for successful network requests
When I run "NetworkRequestScenario" with data "<status_code>"
Then I should receive no errors
Examples:
| status_code |
| 200 |
| 307 |