Commit 27ad7cbd authored by Vignesh Mohankumar's avatar Vignesh Mohankumar Committed by GitHub

test: move all tests to beforeSend (#6513)

* beforeSend tests

* fix

* refactor: filterKnownErrors -> shouldRejectError (#6547)

* refactor: filterKnownErrors -> shouldRejectError

* no unknown

* comments
parent 01e5de43
import { ErrorEvent, Event } from '@sentry/types' import { ErrorEvent, Event } from '@sentry/types'
import { beforeSend, filterKnownErrors } from './errors' import { beforeSend } from './errors'
Object.defineProperty(window.performance, 'getEntriesByType', { Object.defineProperty(window.performance, 'getEntriesByType', {
writable: true, writable: true,
...@@ -61,39 +61,36 @@ describe('beforeSend', () => { ...@@ -61,39 +61,36 @@ describe('beforeSend', () => {
expect((beforeSend(ERROR, { originalException }) as Event).tags?.chunkResponseStatus).toBe(200) expect((beforeSend(ERROR, { originalException }) as Event).tags?.chunkResponseStatus).toBe(200)
}) })
}) })
})
describe('filterKnownErrors', () => {
const ERROR = {} as ErrorEvent
it('propagates an error', () => { it('propagates an error', () => {
expect(filterKnownErrors(ERROR, {})).toBe(ERROR) expect(beforeSend(ERROR, {})).toBe(ERROR)
}) })
it('propagates an error with generic text', () => { it('propagates an error with generic text', () => {
const originalException = new Error('generic error copy') const originalException = new Error('generic error copy')
expect(filterKnownErrors(ERROR, { originalException })).toBe(ERROR) expect(beforeSend(ERROR, { originalException })).toBe(ERROR)
}) })
it('propagates user rejected request errors', () => { it('propagates user rejected request errors', () => {
const originalException = new Error('user rejected transaction') const originalException = new Error('user rejected transaction')
expect(filterKnownErrors(ERROR, { originalException })).toBe(ERROR) expect(beforeSend(ERROR, { originalException })).toBe(ERROR)
}) })
it('filters block number polling errors', () => { it('filters block number polling errors', () => {
const originalException = new (class extends Error { const originalException = new (class extends Error {
requestBody = JSON.stringify({ method: 'eth_blockNumber' }) requestBody = JSON.stringify({ method: 'eth_blockNumber' })
})() })()
expect(filterKnownErrors(ERROR, { originalException })).toBeNull() expect(beforeSend(ERROR, { originalException })).toBeNull()
}) })
it('filters network change errors', () => { it('filters network change errors', () => {
const originalException = new Error('underlying network changed') const originalException = new Error('underlying network changed')
expect(filterKnownErrors(ERROR, { originalException })).toBeNull() expect(beforeSend(ERROR, { originalException })).toBeNull()
}) })
it('filters invalid HTML response errors', () => { it('filters invalid HTML response errors', () => {
const originalException = new SyntaxError("Unexpected token '<'") const originalException = new SyntaxError("Unexpected token '<'")
expect(filterKnownErrors(ERROR, { originalException })).toBeNull() expect(beforeSend(ERROR, { originalException })).toBeNull()
}) })
it('filters chrome-extension errors', () => { it('filters chrome-extension errors', () => {
...@@ -104,7 +101,7 @@ describe('filterKnownErrors', () => { ...@@ -104,7 +101,7 @@ describe('filterKnownErrors', () => {
at da(chrome-extension://kbjhmlgclljgdhmhffjofbobmficicjp/proxy-window-evm.a5430696.js:22:212968) at da(chrome-extension://kbjhmlgclljgdhmhffjofbobmficicjp/proxy-window-evm.a5430696.js:22:212968)
at a(../../../../src/helpers.ts:98:1) at a(../../../../src/helpers.ts:98:1)
` `
expect(filterKnownErrors(ERROR, { originalException })).toBeNull() expect(beforeSend(ERROR, { originalException })).toBeNull()
}) })
describe('OneKey', () => { describe('OneKey', () => {
...@@ -115,7 +112,7 @@ describe('filterKnownErrors', () => { ...@@ -115,7 +112,7 @@ describe('filterKnownErrors', () => {
at JSON.parse(<anonymous>) at JSON.parse(<anonymous>)
at _d._handleAccountChange(/Applications/OneKey.app/Contents/Resources/static/preload.js:2:1634067) at _d._handleAccountChange(/Applications/OneKey.app/Contents/Resources/static/preload.js:2:1634067)
` `
expect(filterKnownErrors(ERROR, { originalException })).toBeNull() expect(beforeSend(ERROR, { originalException })).toBeNull()
}) })
it('filter OneKey errors (Windows users)', () => { it('filter OneKey errors (Windows users)', () => {
const originalException = new Error() const originalException = new Error()
...@@ -124,7 +121,7 @@ describe('filterKnownErrors', () => { ...@@ -124,7 +121,7 @@ describe('filterKnownErrors', () => {
at JSON.parse(<anonymous>) at JSON.parse(<anonymous>)
vd._handleAccountChange(C:\\Users\\example\\AppData\\Local\\Programs\\OneKey\\resources\\static\\preload.js:2:1626130 vd._handleAccountChange(C:\\Users\\example\\AppData\\Local\\Programs\\OneKey\\resources\\static\\preload.js:2:1626130
` `
expect(filterKnownErrors(ERROR, { originalException })).toBeNull() expect(beforeSend(ERROR, { originalException })).toBeNull()
}) })
}) })
...@@ -133,26 +130,26 @@ describe('filterKnownErrors', () => { ...@@ -133,26 +130,26 @@ describe('filterKnownErrors', () => {
const originalException = new Error( const originalException = new Error(
"Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: \"script-src 'self' https://www.google-analytics.com https://www.googletagmanager.com 'unsafe-inlin..." "Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: \"script-src 'self' https://www.google-analytics.com https://www.googletagmanager.com 'unsafe-inlin..."
) )
expect(filterKnownErrors(ERROR, { originalException })).toBeNull() expect(beforeSend(ERROR, { originalException })).toBeNull()
}) })
it('filters CSP unsafe-eval compile/instatiate errors', () => { it('filters CSP unsafe-eval compile/instatiate errors', () => {
const originalException = new Error( const originalException = new Error(
"Refused to compile or instantiate WebAssembly module because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: \"script-src 'self' https://www.google-a..." "Refused to compile or instantiate WebAssembly module because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: \"script-src 'self' https://www.google-a..."
) )
expect(filterKnownErrors(ERROR, { originalException })).toBeNull() expect(beforeSend(ERROR, { originalException })).toBeNull()
}) })
it('filters WebAssembly compilation errors', () => { it('filters WebAssembly compilation errors', () => {
const originalException = new Error( const originalException = new Error(
'Aborted(CompileError: WebAssembly.instantiate(): Wasm code generation disallowed by embedder). Build with -sASSERTIONS for more info.' 'Aborted(CompileError: WebAssembly.instantiate(): Wasm code generation disallowed by embedder). Build with -sASSERTIONS for more info.'
) )
expect(filterKnownErrors(ERROR, { originalException })).toBeNull() expect(beforeSend(ERROR, { originalException })).toBeNull()
}) })
}) })
it('filters AbortErrors', () => { it('filters AbortErrors', () => {
const originalException = new DOMException('The user aborted a request.', 'AbortError') const originalException = new DOMException('The user aborted a request.', 'AbortError')
expect(filterKnownErrors(ERROR, { originalException })).toBeNull() expect(beforeSend(ERROR, { originalException })).toBeNull()
}) })
}) })
...@@ -8,10 +8,19 @@ declare global { ...@@ -8,10 +8,19 @@ declare global {
} }
} }
export function beforeSend(event: ErrorEvent, hint: EventHint) { /**
* Filters known (ignorable) errors out before sending them to Sentry. Also, adds tags to the event.
* Intended as a {@link ClientOptions.beforeSend} callback. Returning null filters the error from Sentry.
*/
export const beforeSend: Required<ClientOptions>['beforeSend'] = (event: ErrorEvent, hint: EventHint) => {
if (shouldRejectError(hint.originalException)) {
return null
}
updateRequestUrl(event) updateRequestUrl(event)
addChunkResponseStatusTag(event, hint) addChunkResponseStatusTag(event, hint)
return filterKnownErrors(event, hint)
return event
} }
/** Identifies ethers request errors (as thrown by {@type import(@ethersproject/web).fetchJson}). */ /** Identifies ethers request errors (as thrown by {@type import(@ethersproject/web).fetchJson}). */
...@@ -62,52 +71,47 @@ function getChunkResponseStatus(asset?: string): number | undefined { ...@@ -62,52 +71,47 @@ function getChunkResponseStatus(asset?: string): number | undefined {
return resource?.responseStatus return resource?.responseStatus
} }
/** function shouldRejectError(error: EventHint['originalException']) {
* Filters known (ignorable) errors out before sending them to Sentry.
* Intended as a {@link ClientOptions.beforeSend} callback. Returning null filters the error from Sentry.
*/
export const filterKnownErrors: Required<ClientOptions>['beforeSend'] = (event: ErrorEvent, hint: EventHint) => {
const error = hint.originalException
if (error instanceof Error) { if (error instanceof Error) {
// ethers aggressively polls for block number, and it sometimes fails (whether spuriously or through rate-limiting). // ethers aggressively polls for block number, and it sometimes fails (whether spuriously or through rate-limiting).
// If block number polling, it should not be considered an exception. // If block number polling, it should not be considered an exception.
if (isEthersRequestError(error)) { if (isEthersRequestError(error)) {
const method = JSON.parse(error.requestBody).method const method = JSON.parse(error.requestBody).method
if (method === 'eth_blockNumber') return null if (method === 'eth_blockNumber') return true
} }
// If the error is a network change, it should not be considered an exception. // If the error is a network change, it should not be considered an exception.
if (error.message.match(/underlying network changed/)) return null if (error.message.match(/underlying network changed/)) return true
// This is caused by HTML being returned for a chunk from Cloudflare. // This is caused by HTML being returned for a chunk from Cloudflare.
// Usually, it's the result of a 499 exception right before it, which should be handled. // Usually, it's the result of a 499 exception right before it, which should be handled.
// Therefore, this can be ignored. // Therefore, this can be ignored.
if (error.message.match(/Unexpected token '<'/)) return null if (error.message.match(/Unexpected token '<'/)) return true
// Errors coming from a Chrome Extension can be ignored for now. These errors are usually caused by extensions injecting // Errors coming from a Chrome Extension can be ignored for now. These errors are usually caused by extensions injecting
// scripts into the page, which we cannot control. // scripts into the page, which we cannot control.
if (error.stack?.match(/chrome-extension:\/\//i)) return null if (error.stack?.match(/chrome-extension:\/\//i)) return true
// Errors coming from OneKey (a desktop wallet) can be ignored for now. // Errors coming from OneKey (a desktop wallet) can be ignored for now.
// These errors are either application-specific, or they will be thrown separately outside of OneKey. // These errors are either application-specific, or they will be thrown separately outside of OneKey.
if (error.stack?.match(/OneKey/i)) return null if (error.stack?.match(/OneKey/i)) return true
// Content security policy 'unsafe-eval' errors can be filtered out because there are expected failures. // Content security policy 'unsafe-eval' errors can be filtered out because there are expected failures.
// For example, if a user runs an eval statement in console this error would still get thrown. // For example, if a user runs an eval statement in console this error would still get thrown.
// TODO(INFRA-176): We should extend this to filter out any type of CSP error. // TODO(INFRA-176): We should extend this to filter out any type of CSP error.
if (error.message.match(/'unsafe-eval'.*content security policy/i)) { if (error.message.match(/'unsafe-eval'.*content security policy/i)) {
return null return true
} }
// WebAssembly compilation fails because we do not allow 'unsafe-eval' in our CSP. // WebAssembly compilation fails because we do not allow 'unsafe-eval' in our CSP.
// Any thrown errors are due to 3P extensions/applications, so we do not need to handle them. // Any thrown errors are due to 3P extensions/applications, so we do not need to handle them.
if (error.message.match(/WebAssembly.instantiate\(\): Wasm code generation disallowed by embedder/)) { if (error.message.match(/WebAssembly.instantiate\(\): Wasm code generation disallowed by embedder/)) {
return null return true
} }
// These are caused by user navigation away from the page before a request has finished. // These are caused by user navigation away from the page before a request has finished.
if (error instanceof DOMException && error.name === 'AbortError') return null if (error instanceof DOMException && error.name === 'AbortError') return true
} }
return event return false
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment