UNPKG

@mate-academy/sourcebuster

Version:

Get sources of your site's visitors (utm / organic / referral / typein).

612 lines (491 loc) 20.2 kB
describe('utm_type override', () => { it('should override typ when utm_type is provided', () => { setLocation('https://example.com/?utm_type=organic&utm_source=google&utm_medium=organic'); const sbjs = require('./sourcebuster'); sbjs.init(); expect(sbjs.get.current.typ).toBe('organic'); }); it('should default to typ=utm when utm_type is not provided', () => { setLocation('https://example.com/?utm_source=facebook&utm_medium=cpc'); const sbjs = require('./sourcebuster'); sbjs.init(); expect(sbjs.get.current.typ).toBe('utm'); }); }); describe('traffic type detection', () => { it('should set typ to utm for gclid parameter', () => { setLocation('https://example.com/?gclid=abc123'); const sbjs = require('./sourcebuster'); sbjs.init(); expect(sbjs.get.current.typ).toBe('utm'); expect(sbjs.get.current.src).toBe('google'); }); it('should set typ to organic when referrer is google.com', () => { setLocation('https://example.com/'); setReferrer('https://www.google.com/'); const sbjs = require('./sourcebuster'); sbjs.init(); expect(sbjs.get.current.typ).toBe('organic'); expect(sbjs.get.current.src).toBe('google'); }); it('should set typ to referral when referrer is non-search domain', () => { setLocation('https://example.com/'); setReferrer('https://facebook.com/post'); const sbjs = require('./sourcebuster'); sbjs.init(); expect(sbjs.get.current.typ).toBe('referral'); expect(sbjs.get.current.src).toBe('facebook.com'); expect(sbjs.get.current.mdm).toBe('referral'); }); it('should set typ to typein when no referrer and no UTM', () => { setLocation('https://example.com/'); setReferrer(''); const sbjs = require('./sourcebuster'); sbjs.init(); expect(sbjs.get.current.typ).toBe('typein'); expect(sbjs.get.current.src).toBe('(direct)'); expect(sbjs.get.current.mdm).toBe('(none)'); }); }); describe('cookie persistence', () => { it('should store current visit data in sbjs_current cookie', () => { setLocation('https://example.com/?utm_source=test'); const sbjs = require('./sourcebuster'); sbjs.init(); const cookie = decodeURIComponent(getCookie('sbjs_current')); expect(cookie).toBeDefined(); expect(cookie).toContain('src=test'); }); it('should set sbjs_first only on first visit and never change it', () => { setLocation('https://example.com/?utm_source=google'); let sbjs = require('./sourcebuster'); sbjs.init(); expect(sbjs.get.first.src).toBe('google'); jest.resetModules(); setLocation('https://example.com/?utm_source=facebook'); sbjs = require('./sourcebuster'); sbjs.init(); expect(sbjs.get.first.src).toBe('google'); expect(sbjs.get.current.src).toBe('facebook'); }); }); describe('source overriding rules', () => { it('should allow UTM to override previous referral source', () => { setLocation('https://example.com/'); setReferrer('https://facebook.com/'); let sbjs = require('./sourcebuster'); sbjs.init(); expect(sbjs.get.current.typ).toBe('referral'); jest.resetModules(); clearCookies(); setCookie('sbjs_current', 'typ=referral|||src=facebook.com|||mdm=referral|||cmp=(none)|||cnt=(none)|||trm=(none)'); setLocation('https://example.com/?utm_source=google'); setReferrer(''); sbjs = require('./sourcebuster'); sbjs.init(); expect(sbjs.get.current.typ).toBe('utm'); expect(sbjs.get.current.src).toBe('google'); }); it('should allow organic to override previous referral source', () => { setLocation('https://example.com/'); setReferrer('https://facebook.com/'); let sbjs = require('./sourcebuster'); sbjs.init(); jest.resetModules(); clearCookies(); setCookie('sbjs_current', 'typ=referral|||src=facebook.com|||mdm=referral|||cmp=(none)|||cnt=(none)|||trm=(none)'); setLocation('https://example.com/'); setReferrer('https://www.google.com/'); sbjs = require('./sourcebuster'); sbjs.init(); expect(sbjs.get.current.typ).toBe('organic'); }); it('should not allow typein to override previous source', () => { setLocation('https://example.com/?utm_source=google'); let sbjs = require('./sourcebuster'); sbjs.init(); jest.resetModules(); clearCookies(); setCookie('sbjs_current', 'typ=utm|||src=google|||mdm=cpc|||cmp=(none)|||cnt=(none)|||trm=(none)'); setLocation('https://example.com/'); setReferrer(''); sbjs = require('./sourcebuster'); sbjs.init(); expect(sbjs.get.current.src).toBe('google'); }); it('should not allow referral to override within same session', () => { setLocation('https://example.com/?utm_source=google'); let sbjs = require('./sourcebuster'); sbjs.init(); jest.resetModules(); setLocation('https://example.com/page2'); setReferrer('https://facebook.com/'); sbjs = require('./sourcebuster'); sbjs.init(); expect(sbjs.get.current.src).toBe('google'); }); }); describe('UTM parameters capture', () => { it('should capture all standard UTM parameters', () => { setLocation('https://example.com/?utm_source=google&utm_medium=cpc&utm_campaign=summer&utm_content=banner&utm_term=shoes'); const sbjs = require('./sourcebuster'); sbjs.init(); expect(sbjs.get.current.src).toBe('google'); expect(sbjs.get.current.mdm).toBe('cpc'); expect(sbjs.get.current.cmp).toBe('summer'); expect(sbjs.get.current.cnt).toBe('banner'); expect(sbjs.get.current.trm).toBe('shoes'); }); it('should capture extended Google Ads UTM parameters', () => { setLocation('https://example.com/?gclid=abc&utm_id=67890'); const sbjs = require('./sourcebuster'); sbjs.init(); expect(sbjs.get.current.typ).toBe('utm'); expect(sbjs.get.current.src).toBe('google'); }); }); describe('session tracking', () => { it('should increment page views within same session', () => { setLocation('https://example.com/'); let sbjs = require('./sourcebuster'); sbjs.init(); expect(parseInt(sbjs.get.session.pgs)).toBe(1); jest.resetModules(); setLocation('https://example.com/about'); sbjs = require('./sourcebuster'); sbjs.init(); expect(parseInt(sbjs.get.session.pgs)).toBe(2); }); it('should create new session when UTM parameters change', () => { jest.useFakeTimers(); setLocation('https://example.com/?utm_source=google'); let sbjs = require('./sourcebuster'); sbjs.init(); const firstSessionId = sbjs.get.session.sid; jest.advanceTimersByTime(1); jest.resetModules(); setLocation('https://example.com/?utm_source=facebook'); sbjs = require('./sourcebuster'); sbjs.init(); expect(sbjs.get.session.sid).toBeDefined(); expect(firstSessionId).toBeDefined(); expect(sbjs.get.session.sid).not.toBe(firstSessionId); expect(parseInt(sbjs.get.session.pgs)).toBe(2); jest.useRealTimers(); }); }); describe('visit counting', () => { it('should increment visit counter only when session expires', () => { setLocation('https://example.com/?utm_source=google'); let sbjs = require('./sourcebuster'); sbjs.init(); expect(parseInt(sbjs.get.udata.vst)).toBe(1); jest.resetModules(); setLocation('https://example.com/page2'); sbjs = require('./sourcebuster'); sbjs.init(); expect(parseInt(sbjs.get.udata.vst)).toBe(1); jest.resetModules(); clearCookies(); setCookie('sbjs_current', 'typ=utm|||src=google|||mdm=cpc|||cmp=(none)|||cnt=(none)|||trm=(none)'); setCookie('sbjs_udata', 'vst=1|||uip=(none)|||uag=test'); setLocation('https://example.com/page3'); sbjs = require('./sourcebuster'); sbjs.init(); expect(parseInt(sbjs.get.udata.vst)).toBe(2); }); }); describe('click ID storage', () => { it('should store gclid in cookie when gclid param is present', () => { setLocation('https://example.com/?gclid=abc123'); const sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-gclid')).toBe('abc123'); }); it('should store gbraid in cookie when gbraid param is present', () => { setLocation('https://example.com/?gbraid=gb123'); const sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-gbraid')).toBe('gb123'); }); it('should store wbraid in cookie when wbraid param is present', () => { setLocation('https://example.com/?wbraid=wb123'); const sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-wbraid')).toBe('wb123'); }); it('should store fbclid in cookie when fbclid param is present', () => { setLocation('https://example.com/?fbclid=fb456'); const sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-fbclid')).toBe('fb456'); }); it('should store ttclid in cookie when ttclid param is present', () => { setLocation('https://example.com/?ttclid=tt789'); const sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-ttclid')).toBe('tt789'); }); it('should store sdclid in cookie when utm_source=sd param is present', () => { setLocation('https://example.com/?utm_source=sd&utm_term=sd123'); const sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-sdclid')).toBe('sd123'); }); it('should store ksclid in cookie when ks_click_id param is present', () => { setLocation('https://example.com/?ks_click_id=ks789'); const sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-ksclid')).toBe('ks789'); }); it('should overwrite existing gclid when new gclid param arrives', () => { setLocation('https://example.com/?gclid=gclid_old'); let sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-gclid')).toBe('gclid_old'); jest.resetModules(); setLocation('https://example.com/?gclid=gclid_new'); sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-gclid')).toBe('gclid_new'); }); it('should overwrite existing gbraid when new gbraid param arrives', () => { setLocation('https://example.com/?gbraid=gb_old'); let sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-gbraid')).toBe('gb_old'); jest.resetModules(); setLocation('https://example.com/?gbraid=gb_new'); sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-gbraid')).toBe('gb_new'); }); it('should overwrite existing wbraid when new wbraid param arrives', () => { setLocation('https://example.com/?wbraid=wb_old'); let sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-wbraid')).toBe('wb_old'); jest.resetModules(); setLocation('https://example.com/?wbraid=wb_new'); sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-wbraid')).toBe('wb_new'); }); it('should overwrite existing fbclid when new fbclid param arrives', () => { setLocation('https://example.com/?fbclid=fb_old'); let sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-fbclid')).toBe('fb_old'); jest.resetModules(); setLocation('https://example.com/?fbclid=fb_new'); sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-fbclid')).toBe('fb_new'); }); it('should overwrite existing ttclid when new ttclid param arrives', () => { setLocation('https://example.com/?ttclid=tt_old'); let sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-ttclid')).toBe('tt_old'); jest.resetModules(); setLocation('https://example.com/?ttclid=tt_new'); sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-ttclid')).toBe('tt_new'); }); it('should overwrite existing sdclid when new sdclid param arrives', () => { setLocation('https://example.com/?utm_source=sd&utm_term=sd_old'); let sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-sdclid')).toBe('sd_old'); jest.resetModules(); setLocation('https://example.com/?utm_source=sd&utm_term=sd_new'); sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-sdclid')).toBe('sd_new'); }); it('should overwrite existing ksclid when new ksclid param arrives', () => { setLocation('https://example.com/?ks_click_id=ks_old'); let sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-ksclid')).toBe('ks_old'); jest.resetModules(); setLocation('https://example.com/?ks_click_id=ks_new'); sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-ksclid')).toBe('ks_new'); }); it('should destroy sdclid and ksclid when gclid arrives', () => { setLocation('https://example.com/?utm_source=sd&utm_term=sd123'); let sbjs = require('./sourcebuster'); sbjs.init(); setCookie('_mate-ksclid', 'ks123'); jest.resetModules(); setLocation('https://example.com/?gclid=gclid456'); sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-sdclid') === undefined || getCookie('_mate-sdclid') === '').toBe(true); expect(getCookie('_mate-ksclid') === undefined || getCookie('_mate-ksclid') === '').toBe(true); expect(getCookie('_mate-gclid')).toBe('gclid456'); }); it('should destroy sdclid and ksclid when gbraid arrives', () => { setLocation('https://example.com/?utm_source=sd&utm_term=sd123'); let sbjs = require('./sourcebuster'); sbjs.init(); setCookie('_mate-ksclid', 'ks123'); jest.resetModules(); setLocation('https://example.com/?gbraid=gb456'); sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-sdclid') === undefined || getCookie('_mate-sdclid') === '').toBe(true); expect(getCookie('_mate-ksclid') === undefined || getCookie('_mate-ksclid') === '').toBe(true); expect(getCookie('_mate-gbraid')).toBe('gb456'); }); it('should destroy sdclid and ksclid when wbraid arrives', () => { setLocation('https://example.com/?utm_source=sd&utm_term=sd123'); let sbjs = require('./sourcebuster'); sbjs.init(); setCookie('_mate-ksclid', 'ks123'); jest.resetModules(); setLocation('https://example.com/?wbraid=wb456'); sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-sdclid') === undefined || getCookie('_mate-sdclid') === '').toBe(true); expect(getCookie('_mate-ksclid') === undefined || getCookie('_mate-ksclid') === '').toBe(true); expect(getCookie('_mate-wbraid')).toBe('wb456'); }); it('should destroy sdclid and ksclid when fbclid arrives', () => { setLocation('https://example.com/?utm_source=sd&utm_term=sd123'); let sbjs = require('./sourcebuster'); sbjs.init(); setCookie('_mate-ksclid', 'ks123'); jest.resetModules(); setLocation('https://example.com/?fbclid=fb456'); sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-sdclid') === undefined || getCookie('_mate-sdclid') === '').toBe(true); expect(getCookie('_mate-ksclid') === undefined || getCookie('_mate-ksclid') === '').toBe(true); expect(getCookie('_mate-fbclid')).toBe('fb456'); }); it('should destroy sdclid and ksclid when ttclid arrives', () => { setLocation('https://example.com/?utm_source=sd&utm_term=sd123'); let sbjs = require('./sourcebuster'); sbjs.init(); setCookie('_mate-ksclid', 'ks123'); jest.resetModules(); setLocation('https://example.com/?ttclid=tt456'); sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-sdclid') === undefined || getCookie('_mate-sdclid') === '').toBe(true); expect(getCookie('_mate-ksclid') === undefined || getCookie('_mate-ksclid') === '').toBe(true); expect(getCookie('_mate-ttclid')).toBe('tt456'); }); it('should destroy ksclid when sdclid arrives', () => { setLocation('https://example.com/?ks_click_id=ks123'); let sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-ksclid')).toBe('ks123'); jest.resetModules(); setLocation('https://example.com/?utm_source=sd&utm_term=sd456'); sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-ksclid') === undefined || getCookie('_mate-ksclid') === '').toBe(true); expect(getCookie('_mate-sdclid')).toBe('sd456'); }); it('should destroy sdclid when ksclid arrives', () => { setLocation('https://example.com/?utm_source=sd&utm_term=sd123'); let sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-sdclid')).toBe('sd123'); jest.resetModules(); setLocation('https://example.com/?ks_click_id=ks456'); sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookie('_mate-sdclid') === undefined || getCookie('_mate-sdclid') === '').toBe(true); expect(getCookie('_mate-ksclid')).toBe('ks456'); }); }); describe('affiliate cookie lifetime', () => { it('should set sdclid cookie with 30-day lifetime', () => { setLocation('https://example.com/?utm_source=sd&utm_term=sd123'); const sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookieLifetimeDays('_mate-sdclid')).toBe(30); }); it('should set ksclid cookie with 30-day lifetime', () => { setLocation('https://example.com/?ks_click_id=ks789'); const sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookieLifetimeDays('_mate-ksclid')).toBe(30); }); it('should set gclid cookie with default 6-month lifetime', () => { setLocation('https://example.com/?gclid=gclid123'); const sbjs = require('./sourcebuster'); sbjs.init(); expect(getCookieLifetimeDays('_mate-gclid')).toBe(180); }); }); describe('organic source detection', () => { it('should detect Bing organic traffic', () => { setLocation('https://example.com/'); setReferrer('https://www.bing.com/search?q=test'); const sbjs = require('./sourcebuster'); sbjs.init(); expect(sbjs.get.current.typ).toBe('organic'); expect(sbjs.get.current.src).toBe('bing'); }); it('should detect Yahoo organic traffic', () => { setLocation('https://example.com/'); setReferrer('https://search.yahoo.com/search?p=test'); const sbjs = require('./sourcebuster'); sbjs.init(); expect(sbjs.get.current.typ).toBe('organic'); expect(sbjs.get.current.src).toBe('yahoo'); }); }); describe('referral content tracking', () => { it('should store referrer path as utm_content for referral traffic', () => { setLocation('https://example.com/'); setReferrer('https://facebook.com/some/post/path'); const sbjs = require('./sourcebuster'); sbjs.init(); expect(sbjs.get.current.cnt).toBe('/some/post/path'); }); }); describe('custom configuration', () => { it('should respect custom typein attributes', () => { setLocation('https://example.com/'); setReferrer(''); const sbjs = require('./sourcebuster'); sbjs.init({ typein_attributes: { source: 'custom_direct', medium: 'custom_none' } }); expect(sbjs.get.current.src).toBe('custom_direct'); expect(sbjs.get.current.mdm).toBe('custom_none'); }); }); describe('sbjs:loaded event', () => { it('should dispatch sbjs:loaded event when module loads', () => { const eventHandler = jest.fn(); window.addEventListener('sbjs:loaded', eventHandler); jest.resetModules(); require('./sourcebuster'); expect(eventHandler).toHaveBeenCalledTimes(1); expect(eventHandler.mock.calls[0][0].type).toBe('sbjs:loaded'); window.removeEventListener('sbjs:loaded', eventHandler); }); it('should dispatch sbjs:loaded as CustomEvent', () => { let receivedEvent = null; const eventHandler = (event) => { receivedEvent = event; }; window.addEventListener('sbjs:loaded', eventHandler); jest.resetModules(); require('./sourcebuster'); expect(receivedEvent).toBeInstanceOf(CustomEvent); window.removeEventListener('sbjs:loaded', eventHandler); }); });