Skip to content

Commit

Permalink
(plugin-electron-client-state-persistence) Add unit tests for disable…
Browse files Browse the repository at this point in the history
…d NativeClient
  • Loading branch information
yousif-bugsnag committed Nov 20, 2023
1 parent 61ce62d commit d37abc8
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 131 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@
"devDependencies": {
"@bugsnag/core": "^7.19.0",
"@bugsnag/plugin-electron-client-state-manager": "^7.19.0",
"@types/bindings": "^1.5.0"
"@types/bindings": "^1.5.0",
"@bugsnag/electron-test-helpers": "^7.19.0"
},
"peerDependencies": {
"@bugsnag/core": "^7.9.2"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,114 +1,94 @@
import Client from '@bugsnag/core/client'
import { plugin } from '../'
import { Breadcrumb, Logger } from '@bugsnag/core'
import { Breadcrumb } from '@bugsnag/core'
import stateManager from '@bugsnag/plugin-electron-client-state-manager'
import { makeClientForPlugin } from '@bugsnag/electron-test-helpers'

const schema = {
enabledErrorTypes: {
defaultValue: () => ({
unhandledExceptions: true,
unhandledRejections: true,
nativeCrashes: true
}),
allowPartialObject: true,
validate: value => true
}
}

function makeClient (NativeClient: object, config?: object) {
return makeClientForPlugin({ plugins: [stateManager, plugin(NativeClient)], schema, config })
}

describe('plugin: electron client sync', () => {
it('updates context', done => {
const c = new Client({
apiKey: 'api_key',
plugins: [
stateManager,
plugin({
updateContext: (update: any) => {
expect(update).toBe('1234')
done()
}
})
]
const { client } = makeClient({
updateContext: (update: any) => {
expect(update).toBe('1234')
done()
}
})
c.setContext('1234')
client.setContext('1234')
})

it('updates metadata', done => {
const c = new Client({
apiKey: 'api_key',
plugins: [
stateManager,
plugin({
updateMetadata: (key: string, updates: any) => {
expect(key).toBe('widget')
expect(updates).toEqual({
id: '14',
count: 340
})
done()
}
const { client } = makeClient({
updateMetadata: (key: string, updates: any) => {
expect(key).toBe('widget')
expect(updates).toEqual({
id: '14',
count: 340
})
]
done()
}
})
c.addMetadata('widget', { id: '14', count: 340 })
expect(c.getMetadata('widget')).toEqual({ id: '14', count: 340 })
client.addMetadata('widget', { id: '14', count: 340 })
expect(client.getMetadata('widget')).toEqual({ id: '14', count: 340 })
})

it('clears metadata', done => {
const c = new Client({
apiKey: 'api_key',
plugins: [
stateManager,
plugin({
addMetadata: () => {},
clearMetadata: () => {}
})
]
const { client } = makeClient({
addMetadata: () => {},
clearMetadata: () => {}
})
c.addMetadata('widget', { id: '14', count: 340 })
expect(c.getMetadata('widget')).toEqual({ id: '14', count: 340 })
c.clearMetadata('widget', 'count')
expect(c.getMetadata('widget', 'count')).toBeUndefined()
c.clearMetadata('widget')
expect(c.getMetadata('widget')).toBeUndefined()
client.addMetadata('widget', { id: '14', count: 340 })
expect(client.getMetadata('widget')).toEqual({ id: '14', count: 340 })
client.clearMetadata('widget', 'count')
expect(client.getMetadata('widget', 'count')).toBeUndefined()
client.clearMetadata('widget')
expect(client.getMetadata('widget')).toBeUndefined()
done()
})

it('updates user', done => {
const c = new Client({
apiKey: 'api_key',
plugins: [
stateManager,
plugin({
updateUser: (id: string, email: string, name: string) => {
expect(id).toBe('1234')
expect(name).toBe('Ben')
expect(email).toBe('[email protected]')
done()
}
})
]
const { client } = makeClient({
updateUser: (id: string, email: string, name: string) => {
expect(id).toBe('1234')
expect(name).toBe('Ben')
expect(email).toBe('[email protected]')
done()
}
})
c.setUser('1234', '[email protected]', 'Ben')
expect(c.getUser()).toEqual({ id: '1234', name: 'Ben', email: '[email protected]' })
client.setUser('1234', '[email protected]', 'Ben')
expect(client.getUser()).toEqual({ id: '1234', name: 'Ben', email: '[email protected]' })
})

it('syncs breadcrumbs', (done) => {
const c = new Client({
apiKey: 'api_key',
plugins: [
stateManager,
plugin({
leaveBreadcrumb: ({ message, metadata, type, timestamp }: Breadcrumb) => {
expect(message).toBe('Spin')
expect(type).toBe('manual')
expect(metadata).toEqual({ direction: 'ccw', deg: '90' })
expect(timestamp).toBeTruthy()
done()
}
})
]
const { client } = makeClient({
leaveBreadcrumb: ({ message, metadata, type, timestamp }: Breadcrumb) => {
expect(message).toBe('Spin')
expect(type).toBe('manual')
expect(metadata).toEqual({ direction: 'ccw', deg: '90' })
expect(timestamp).toBeTruthy()
done()
}
})
c.leaveBreadcrumb('Spin', { direction: 'ccw', deg: '90' })
client.leaveBreadcrumb('Spin', { direction: 'ccw', deg: '90' })
})

it('does not sync breadcrumbs that are cancelled by an onBreadcrumb callback', () => {
const NativeClient = { leaveBreadcrumb: jest.fn() }

const client = new Client({
apiKey: 'api_key',
plugins: [
stateManager,
plugin(NativeClient)
]
})
const { client } = makeClient(NativeClient)

client.addOnBreadcrumb(breadcrumb => {
if (breadcrumb.message === 'skip me') {
Expand Down Expand Up @@ -138,13 +118,7 @@ describe('plugin: electron client sync', () => {
it('updates feature flags', () => {
const updateFeatureFlags = jest.fn()

const client = new Client({
apiKey: 'api_key',
plugins: [
stateManager,
plugin({ updateFeatureFlags })
]
})
const { client } = makeClient({ updateFeatureFlags })

client.addFeatureFlag('a', 'b')
client.addFeatureFlags([{ name: 'c', variant: null }, { name: 'd', variant: 'e' }])
Expand All @@ -163,13 +137,7 @@ describe('plugin: electron client sync', () => {
it('clears a single feature flag', () => {
const updateFeatureFlags = jest.fn()

const client = new Client({
apiKey: 'api_key',
plugins: [
stateManager,
plugin({ updateFeatureFlags })
]
})
const { client } = makeClient({ updateFeatureFlags })

client.addFeatureFlag('a', 'b')
client.addFeatureFlags([{ name: 'c', variant: null }, { name: 'd', variant: 'e' }])
Expand All @@ -193,13 +161,7 @@ describe('plugin: electron client sync', () => {
it('clears all feature flags', () => {
const updateFeatureFlags = jest.fn()

const client = new Client({
apiKey: 'api_key',
plugins: [
stateManager,
plugin({ updateFeatureFlags })
]
})
const { client } = makeClient({ updateFeatureFlags })

client.addFeatureFlag('a', 'b')
client.addFeatureFlags([{ name: 'c', variant: null }, { name: 'd', variant: 'e' }])
Expand All @@ -217,81 +179,116 @@ describe('plugin: electron client sync', () => {
expect(updateFeatureFlags).toHaveBeenNthCalledWith(3, [])
})

function loggingClient (NativeClient: object): [Client, Logger] {
const logger = {
debug: jest.fn(),
warn: jest.fn(),
info: jest.fn(),
error: jest.fn()
}
const client = new Client({
apiKey: 'api_key',
plugins: [stateManager, plugin(NativeClient)],
logger
})
return [client, logger]
}

it('logs errors thrown from updating context', () => {
const [client, logger] = loggingClient({
// const [client, logger] = loggingClient({
// updateContext: () => { throw new Error('wrong thing') }
// })
const { client } = makeClient({
updateContext: () => { throw new Error('wrong thing') }
})

client.setContext('some invalid context')
const error = logger.error as jest.Mock<Function>
const error = client._logger.error as jest.Mock<Function>
expect(error.mock.calls.length).toBe(1)
expect(error.mock.calls[0][0].message).toContain('wrong thing')
})

it('logs errors thrown from adding breadcrumbs', () => {
const [client, logger] = loggingClient({
const { client } = makeClient({
leaveBreadcrumb: () => { throw new Error('wrong thing') }
})
client.leaveBreadcrumb('Spin', { direction: 'ccw', deg: '90' })
const error = logger.error as jest.Mock<Function>
const error = client._logger.error as jest.Mock<Function>
expect(error.mock.calls.length).toBe(1)
expect(error.mock.calls[0][0].message).toContain('wrong thing')
})

it('logs errors thrown from adding metadata', () => {
const [client, logger] = loggingClient({
const { client } = makeClient({
updateMetadata: () => { throw new Error('wrong thing') }
})
client.addMetadata('widget', { id: '14', count: 340 })
const error = logger.error as jest.Mock<Function>
const error = client._logger.error as jest.Mock<Function>
expect(error.mock.calls.length).toBe(1)
expect(error.mock.calls[0][0].message).toContain('wrong thing')
})

it('logs errors thrown from clearing metadata', () => {
const [client, logger] = loggingClient({
const { client } = makeClient({
updateMetadata: () => { throw new Error('wrong thing') }
})
client.clearMetadata('widget')
const error = logger.error as jest.Mock<Function>
const error = client._logger.error as jest.Mock<Function>
expect(error.mock.calls.length).toBe(1)
expect(error.mock.calls[0][0].message).toContain('wrong thing')
})

it('logs errors thrown from updating user info', () => {
const [client, logger] = loggingClient({
const { client } = makeClient({
updateUser: () => { throw new Error('wrong thing') }
})
client.setUser('404', '[email protected]', undefined)
const error = logger.error as jest.Mock<Function>
const error = client._logger.error as jest.Mock<Function>
expect(error.mock.calls.length).toBe(1)
expect(error.mock.calls[0][0].message).toContain('wrong thing')
})

it('logs errors thrown from updating feature flags', () => {
const [client, logger] = loggingClient({
const { client } = makeClient({
updateFeatureFlags: () => { throw new Error('wrong thing') }
})

client.addFeatureFlag('a', 'b')

const error = logger.error as jest.Mock<Function>
const error = client._logger.error as jest.Mock<Function>

expect(error.mock.calls.length).toBe(1)
expect(error.mock.calls[0][0].message).toContain('wrong thing')
})

it('does not sync data to the NativeClient if enabledErrorTypes.nativeCrashes is disabled', () => {
const NativeClient = {
leaveBreadcrumb: jest.fn(),
updateUser: jest.fn(),
updateContext: jest.fn(),
updateMetadata: jest.fn(),
updateFeatureFlags: jest.fn()
}

const { client } = makeClient(NativeClient, { enabledErrorTypes: { nativeCrashes: false } })
client.leaveBreadcrumb('no sync')
client.setUser('1234', '[email protected]', 'Ben')
client.setContext('no sync')
client.addMetadata('no sync', { id: '14', count: 340 })
client.addFeatureFlag('no', 'sync')

expect(NativeClient.leaveBreadcrumb).not.toHaveBeenCalled()
expect(NativeClient.updateUser).not.toHaveBeenCalled()
expect(NativeClient.updateContext).not.toHaveBeenCalled()
expect(NativeClient.updateMetadata).not.toHaveBeenCalled()
expect(NativeClient.updateFeatureFlags).not.toHaveBeenCalled()
})

it('does not sync data to the NativeClient if autoDetectErrors is disabled', () => {
const NativeClient = {
leaveBreadcrumb: jest.fn(),
updateUser: jest.fn(),
updateContext: jest.fn(),
updateMetadata: jest.fn(),
updateFeatureFlags: jest.fn()
}

const { client } = makeClient(NativeClient, { autoDetectErrors: false })
client.leaveBreadcrumb('no sync')
client.setUser('1234', '[email protected]', 'Ben')
client.setContext('no sync')
client.addMetadata('no sync', { id: '14', count: 340 })
client.addFeatureFlag('no', 'sync')

expect(NativeClient.leaveBreadcrumb).not.toHaveBeenCalled()
expect(NativeClient.updateUser).not.toHaveBeenCalled()
expect(NativeClient.updateContext).not.toHaveBeenCalled()
expect(NativeClient.updateMetadata).not.toHaveBeenCalled()
expect(NativeClient.updateFeatureFlags).not.toHaveBeenCalled()
})
})

0 comments on commit d37abc8

Please sign in to comment.