Skip to content

Commit

Permalink
Merge pull request #666 from bugsnag/v7-pause-remove-session
Browse files Browse the repository at this point in the history
V7: Add methods to pause and resume sessions
  • Loading branch information
bengourley authored Dec 13, 2019
2 parents a9c3af3 + 62f2017 commit 8f3aaff
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
- Add `onBreadcrumb` and `onSession` callbacks. [#665](https://github.com/bugsnag/bugsnag-js/pull/665)
- Refactor `notify()` to not accept events (they go via `_notify()` instead). Consolidate `Event` static methods into a single `.create()` utility, used by all automatic errors detection components. [#664](https://github.com/bugsnag/bugsnag-js/pull/664)
- Refactor `notify()` to not accept events (they go via `_notify()` instead). Consolidate `Event` static methods into a single `.create()` utility, used by all automatic error detection components. [#664](https://github.com/bugsnag/bugsnag-js/pull/664)
- Add methods to pause and resume sessions [#666](https://github.com/bugsnag/bugsnag-js/pull/666)
- Add `pauseSession()` and `resumeSession()` methods to `Client` [#666](https://github.com/bugsnag/bugsnag-js/pull/666)

## 6.4.3 (2019-10-21)

Expand Down
8 changes: 8 additions & 0 deletions packages/core/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,14 @@ class BugsnagClient {
this._cbs.b = filter(this._cbs.b, f => f !== fn)
}

pauseSession () {
return this._sessionDelegate.pauseSession(this)
}

resumeSession () {
return this._sessionDelegate.resumeSession(this)
}

leaveBreadcrumb (message, metadata, type) {
// coerce bad values so that the defaults get set
message = typeof message === 'string' ? message : ''
Expand Down
1 change: 1 addition & 0 deletions packages/core/lib/clone-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ module.exports = (client) => {

clone._logger = client._logger
clone._delivery = client._delivery
clone._sessionDelegate = client._sessionDelegate

return clone
}
24 changes: 24 additions & 0 deletions packages/core/test/client.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,30 @@ describe('@bugsnag/core/client', () => {
})
})

describe('pause/resumeSession()', () => {
it('forwards on calls to the session delegate', () => {
const client = new Client({ apiKey: 'API_KEY' })
const sessionDelegate = {
startSession: () => {},
pauseSession: () => {},
resumeSession: () => {}
}
client._sessionDelegate = sessionDelegate

const startSpy = spyOn(sessionDelegate, 'startSession')
const pauseSpy = spyOn(sessionDelegate, 'pauseSession')
const resumeSpy = spyOn(sessionDelegate, 'resumeSession')
client._sessionDelegate = sessionDelegate

client.startSession()
expect(startSpy).toHaveBeenCalledTimes(1)
client.pauseSession()
expect(pauseSpy).toHaveBeenCalledTimes(1)
client.resumeSession()
expect(resumeSpy).toHaveBeenCalledTimes(1)
})
})

describe('getUser() / setUser()', () => {
it('sets and retrieves user properties', () => {
const c = new Client({ apiKey: 'aaaa' })
Expand Down
6 changes: 5 additions & 1 deletion packages/core/types/client.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ declare class Client {
public getUser(): { id?: string; email?: string; name?: string };
public setUser(id?: string, email?: string, name?: string): void;

// sessions
public startSession(): Client;
public pauseSession(): void;
public resumeSession(): Client;

public use(plugin: common.Plugin, ...args: any[]): Client;
public getPlugin(name: string): any;
public notify(
Expand All @@ -35,7 +40,6 @@ declare class Client {
cb?: (err: any, event: Event) => void,
): void;
public leaveBreadcrumb(message: string, metadata?: { [key: string]: common.BreadcrumbMetadataValue }, type?: string): void;
public startSession(): Client;
}

export default Client;
14 changes: 14 additions & 0 deletions packages/plugin-browser-session/session.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const sessionDelegate = {
startSession: (client, session) => {
const sessionClient = client
sessionClient._session = session
sessionClient._pausedSession = null

const releaseStage = inferReleaseStage(sessionClient)

Expand All @@ -32,5 +33,18 @@ const sessionDelegate = {
})

return sessionClient
},
resumeSession: (client) => {
if (client._pausedSession) {
client._session = client._pausedSession
client._pausedSession = null
return client
} else {
return client.startSession()
}
},
pauseSession: (client) => {
client._pausedSession = client._session
client._session = null
}
}
38 changes: 38 additions & 0 deletions packages/plugin-browser-session/test/session.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,42 @@ describe('plugin: sessions', () => {
/"endpoints" should be an object containing endpoint URLs { notify, sessions }/
)
})

it('supports pausing and resuming sessions', (done) => {
const payloads = []
const c = new Client({
apiKey: 'API_KEY'
})
c.use(plugin)
c._setDelivery(client => ({
sendEvent: (p, cb = () => {}) => {
payloads.push(p)
cb()
},
sendSession: (p, cb = () => {}) => cb()
}))
c.notify(new Error('1'))
c.startSession()
c.notify(new Error('2'))
c.pauseSession()
c.notify(new Error('3'))
c.resumeSession()
c.notify(new Error('4'))
c.startSession()
c.notify(new Error('5'))
c._pausedSession = c._session = null
c.resumeSession()
c.notify(new Error('6'))

setTimeout(() => {
expect(payloads.length).toBe(6)
expect(payloads[0].events[0].session).toBe(undefined)
expect(payloads[1].events[0].session).toBeDefined()
expect(payloads[2].events[0].session).toBe(undefined)
expect(payloads[3].events[0].session.id).toBe(payloads[1].events[0].session.id)
expect(payloads[4].events[0].session.id).not.toBe(payloads[3].events[0].session.id)
expect(payloads[5].events[0].session.id).not.toBe(payloads[4].events[0].session.id)
done()
}, 0)
})
})
14 changes: 14 additions & 0 deletions packages/plugin-server-session/session.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,22 @@ module.exports = {
startSession: (client, session) => {
const sessionClient = clone(client)
sessionClient._session = session
sessionClient._pausedSession = null
sessionTracker.track(sessionClient._session)
return sessionClient
},
pauseSession: (client) => {
client._pausedSession = client._session
client._session = null
},
resumeSession: (client) => {
if (client._pausedSession) {
client._session = client._pausedSession
client._pausedSession = null
return client
} else {
return client.startSession()
}
}
}
},
Expand Down
36 changes: 36 additions & 0 deletions packages/plugin-server-session/test/session.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,40 @@ describe('plugin: server sessions', () => {
expect(sessionClient.breadcrumbs.length).toBe(2)
expect(Object.keys(sessionClient._metadata).length).toBe(2)
})

it('should support pausing/resuming sessions', () => {
class TrackerMock extends Emitter {
start () {}
stop () {}
track () {}
}
const plugin = proxyquire('../session', { './tracker': TrackerMock })

const c = new Client({ apiKey: 'aaaa-aaaa-aaaa-aaaa' })
c.use(plugin)

// start a session and get its id
const sessionClient = c.startSession()
const sid0 = sessionClient._session.id

// ensure pausing the session clears the client._session property
sessionClient.pauseSession()
const s1 = sessionClient._session
const psid1 = sessionClient._pausedSession.id
expect(s1).toBe(null)
expect(psid1).toBe(sid0)

// ensure resuming the session gets back the original session (not a new one)
sessionClient.resumeSession()
const sid2 = sessionClient._session.id
expect(sid2).toBe(sid0)

// ensure resumeSession() starts a new one when no paused session exists
sessionClient._session = null
sessionClient._pausedSession = null
const resumedClient = sessionClient.resumeSession()
expect(resumedClient._session).toBeTruthy()
const sid3 = resumedClient._session.id
expect(sid3).not.toBe(sid0)
})
})

0 comments on commit 8f3aaff

Please sign in to comment.