diff --git a/src/FormoAnalytics.ts b/src/FormoAnalytics.ts index f563dcc..cbe2224 100644 --- a/src/FormoAnalytics.ts +++ b/src/FormoAnalytics.ts @@ -86,7 +86,18 @@ export class FormoAnalytics implements IFormoAnalytics { this.detect = this.detect.bind(this); this.track = this.track.bind(this); this.screen = this.screen.bind(this); + this.reset = this.reset.bind(this); + this.cleanup = this.cleanup.bind(this); + this.flush = this.flush.bind(this); + this.setTrafficSourceFromUrl = this.setTrafficSourceFromUrl.bind(this); + this.optOutTracking = this.optOutTracking.bind(this); + this.optInTracking = this.optInTracking.bind(this); + this.hasOptedOutTracking = this.hasOptedOutTracking.bind(this); + this.pushNotificationReceived = this.pushNotificationReceived.bind(this); + this.pushNotificationTapped = this.pushNotificationTapped.bind(this); + this.pushNotificationBounced = this.pushNotificationBounced.bind(this); this.isAutocaptureEnabled = this.isAutocaptureEnabled.bind(this); + this.isAttributionEnabled = this.isAttributionEnabled.bind(this); // Initialize logger Logger.init({ diff --git a/src/__tests__/FormoAnalytics.test.ts b/src/__tests__/FormoAnalytics.test.ts index f445b84..76a18bf 100644 --- a/src/__tests__/FormoAnalytics.test.ts +++ b/src/__tests__/FormoAnalytics.test.ts @@ -405,6 +405,50 @@ describe('FormoAnalytics', () => { }); }); + describe('method binding', () => { + // useFormo consumers destructure methods off the instance + // (const { reset } = useFormo()), so every public interface method must + // be bound in the constructor or `this` is undefined at the call site. + const publicMethods = [ + 'identify', + 'connect', + 'disconnect', + 'chain', + 'signature', + 'transaction', + 'detect', + 'track', + 'screen', + 'reset', + 'cleanup', + 'flush', + 'setTrafficSourceFromUrl', + 'optOutTracking', + 'optInTracking', + 'hasOptedOutTracking', + 'pushNotificationReceived', + 'pushNotificationTapped', + 'pushNotificationBounced', + 'isAutocaptureEnabled', + 'isAttributionEnabled', + ] as const; + + it.each(publicMethods)('binds %s to the instance', (name) => { + expect(Object.prototype.hasOwnProperty.call(analytics, name)).toBe(true); + expect(analytics[name]).not.toBe(FormoAnalytics.prototype[name]); + }); + + it('reset works when destructured off the instance', () => { + analytics.currentUserId = 'user-1'; + + const { reset } = analytics; + + expect(() => reset()).not.toThrow(); + expect(mockSession.clear).toHaveBeenCalled(); + expect(analytics.currentUserId).toBeUndefined(); + }); + }); + describe('isAutocaptureEnabled()', () => { it('should return true by default', () => { expect(analytics.isAutocaptureEnabled('connect')).toBe(true);