From 4c311ceaed58fdafd28444d8d96e8d00ec5de8c3 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Mon, 30 Oct 2023 19:02:03 +0000 Subject: [PATCH] chore: test browser/version code --- src/__tests__/utils/event-utils.test.ts | 166 ++++++++++++++++++++++++ src/utils/event-utils.ts | 24 ++-- 2 files changed, 180 insertions(+), 10 deletions(-) diff --git a/src/__tests__/utils/event-utils.test.ts b/src/__tests__/utils/event-utils.test.ts index 013df2ae7..b54f8fb43 100644 --- a/src/__tests__/utils/event-utils.test.ts +++ b/src/__tests__/utils/event-utils.test.ts @@ -29,4 +29,170 @@ describe(`event-utils`, () => { expect(properties['$raw_user_agent'].length).toBe(1000) expect(properties['$raw_user_agent'].substring(995)).toBe('aa...') }) + + // can use https://user-agents.net/ or $raw_user_agent property on events to get new test cases + const browserTestcases: { + name: string + userAgent: string + vendor: string + expectedVersion: number | null + expectedBrowser: string + }[] = [ + { + name: 'Chrome 91', + userAgent: + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', + vendor: '', + expectedVersion: 91.0, + expectedBrowser: 'Chrome', + }, + + { + name: 'Firefox 89', + userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0', + vendor: '', + expectedVersion: 89.0, + expectedBrowser: 'Firefox', + }, + + { + name: 'unknown browser', + userAgent: 'UnknownBrowser/5.0', + vendor: '', + expectedVersion: null, + expectedBrowser: '', + }, + + { + name: 'invalid chrome', + userAgent: + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome Safari/537.36', + vendor: '', + expectedVersion: null, + expectedBrowser: 'Chrome', + }, + + { + name: 'Internet Explorer Mobile', + userAgent: + 'Mozilla/5.0 (Windows Phone 8.1; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; 909) like Gecko', + vendor: '', + expectedVersion: 11.0, + expectedBrowser: 'Internet Explorer Mobile', + }, + + { + name: 'should return correct version for Microsoft Edge', + userAgent: + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Edge/44.17763.831.0', + vendor: '', + expectedVersion: 44.17763, + expectedBrowser: 'Microsoft Edge', + }, + + { + name: 'should return correct version for Chrome iOS', + userAgent: + 'Mozilla/5.0 (iPhone; U; CPU iPhone OS 5_1_1 like Mac OS X; en) AppleWebKit/534.46.0 (KHTML, like Gecko) CriOS/21.0.1180.82 Mobile/9B206 Safari/7534.48.3', + vendor: '', + expectedVersion: 21.0, + expectedBrowser: 'Chrome iOS', + }, + + { + name: 'should return correct UC Browser version', + userAgent: + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-US; Micromax A116 Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 UCBrowser/10.7.5.658 U3/0.8.0 Mobile Safari/534.30', + vendor: '', + expectedVersion: 10.7, + expectedBrowser: 'UC Browser', + }, + + { + name: 'should return correct Safari version', + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Safari/605.1.15', + vendor: 'Apple', + expectedVersion: 17.1, + expectedBrowser: 'Safari', + }, + + { + name: 'should return correct Opera version', + userAgent: + 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.69 Safari/537.36 OPR/34.0.2036.25', + vendor: '', + expectedVersion: 34.0, + expectedBrowser: 'Opera', + }, + + { + name: 'should return correct Firefox iOS version', + userAgent: + 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) FxiOS/8.3b5826 Mobile/14E5239e Safari/602.1.50', + vendor: '', + expectedVersion: 8.3, + expectedBrowser: 'Firefox iOS', + }, + + { + name: 'should return correct Konqueror version', + userAgent: 'Mozilla/5.0 (X11; U; U; DragonFly amd64) KIO/5.97 konqueror/22.08.0', + vendor: '', + expectedVersion: 22.08, + expectedBrowser: 'Konqueror', + }, + + { + name: 'should return 7.1 for BlackBerry Bold 9790 version', + userAgent: + 'Mozilla/5.0 (BlackBerry; U; BlackBerry 9790; es) AppleWebKit/534.11+ (KHTML, like Gecko) Version/7.1.0.569 Mobile Safari/534.11+', + vendor: '', + // TODO is this a bug we match 9790 the model and not 7.1 the browser version + expectedVersion: 9790, + expectedBrowser: 'BlackBerry', + }, + + { + name: 'should return 10.1 for BlackBerry BB10 version', + userAgent: + 'Mozilla/5.0 (BB10; Kbd) AppleWebKit/537.10+ (KHTML, like Gecko) Version/10.1.0.1720 Mobile Safari/537.10+', + vendor: '', + expectedVersion: 10.1, + expectedBrowser: 'BlackBerry', + }, + + { + name: 'should return correct Android Mobile version', + userAgent: + 'Mozilla/5.0 (Linux; StarOS Must use __system_property_read_callback() to read; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4896.127 Mobile Safari/537.36', + vendor: '', + expectedVersion: 4.0, + expectedBrowser: 'Android Mobile', + }, + + { + name: 'should return correct Samsung Internet version', + userAgent: + 'Mozilla/5.0 (Linux; Android 5.0.2; SAMSUNG SM-T550 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/3.5 Chrome/38.0.2125.102 Safari/537.36', + vendor: '', + expectedVersion: 3.5, + expectedBrowser: 'Samsung Internet', + }, + { + name: 'should return correct Internet Explorer version', + userAgent: 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)', + vendor: '', + expectedVersion: 10.0, + expectedBrowser: 'Internet Explorer', + }, + ] + + test.each(browserTestcases)('browser version %s', ({ userAgent, vendor, expectedVersion }) => { + expect(_info.browserVersion(userAgent, vendor, '')).toBe(expectedVersion) + }) + + test.each(browserTestcases)('browser %s', ({ userAgent, vendor, expectedBrowser }) => { + expect(_info.browser(userAgent, vendor, '')).toBe(expectedBrowser) + }) }) diff --git a/src/utils/event-utils.ts b/src/utils/event-utils.ts index 9b46ee3de..958a5f3a1 100644 --- a/src/utils/event-utils.ts +++ b/src/utils/event-utils.ts @@ -5,6 +5,10 @@ import Config from '../config' import { _each, _extend, _includes, _strip_empty_properties, _timestamp } from './index' import { document, userAgent } from './globals' +function matchReferrer(pattern: string): boolean { + return document.referrer.search('https?://(.*)' + pattern) === 0 +} + export const _info = { campaignParams: function (customParams?: string[]): Record { const campaign_keywords = [ @@ -33,13 +37,13 @@ export const _info = { const referrer = document.referrer if (!referrer) { return null - } else if (referrer.search('https?://(.*)google.([^/?]*)') === 0) { + } else if (matchReferrer('google.([^/?]*)')) { return 'google' - } else if (referrer.search('https?://(.*)bing.com') === 0) { + } else if (matchReferrer('bing.com')) { return 'bing' - } else if (referrer.search('https?://(.*)yahoo.com') === 0) { + } else if (matchReferrer('yahoo.com')) { return 'yahoo' - } else if (referrer.search('https?://(.*)duckduckgo.com') === 0) { + } else if (matchReferrer('duckduckgo.com')) { return 'duckduckgo' } else { return null @@ -68,7 +72,7 @@ export const _info = { * The order of the checks are important since many user agents * include key words used in later checks. */ - browser: function (user_agent: string, vendor: string, opera?: any): string { + browser: function (user_agent: string, vendor: string | undefined, opera?: any): string { vendor = vendor || '' // vendor is undefined for at least IE9 if (opera || _includes(user_agent, ' OPR/')) { if (_includes(user_agent, 'Mini')) { @@ -101,7 +105,7 @@ export const _info = { return 'Safari' } else if (_includes(user_agent, 'Android')) { return 'Android Mobile' - } else if (_includes(user_agent, 'Konqueror')) { + } else if (_includes(user_agent, 'Konqueror') || _includes(user_agent, 'konqueror')) { return 'Konqueror' } else if (_includes(user_agent, 'Firefox')) { return 'Firefox' @@ -119,9 +123,9 @@ export const _info = { * parsing major and minor version (e.g., 42.1). User agent strings from: * http://www.useragentstring.com/pages/useragentstring.php */ - browserVersion: function (userAgent: string, vendor: string, opera: string): number | null { + browserVersion: function (userAgent: string, vendor: string | undefined, opera: string): number | null { const browser = _info.browser(userAgent, vendor, opera) - const versionRegexs = { + const versionRegexes = { 'Internet Explorer Mobile': /rv:(\d+(\.\d+)?)/, 'Microsoft Edge': /Edge?\/(\d+(\.\d+)?)/, Chrome: /Chrome\/(\d+(\.\d+)?)/, @@ -132,14 +136,14 @@ export const _info = { Opera: /(Opera|OPR)\/(\d+(\.\d+)?)/, Firefox: /Firefox\/(\d+(\.\d+)?)/, 'Firefox iOS': /FxiOS\/(\d+(\.\d+)?)/, - Konqueror: /Konqueror:(\d+(\.\d+)?)/, + Konqueror: /Konqueror[://]?(\d+(\.\d+)?)/i, BlackBerry: /BlackBerry (\d+(\.\d+)?)/, 'Android Mobile': /android\s(\d+(\.\d+)?)/, 'Samsung Internet': /SamsungBrowser\/(\d+(\.\d+)?)/, 'Internet Explorer': /(rv:|MSIE )(\d+(\.\d+)?)/, Mozilla: /rv:(\d+(\.\d+)?)/, } - const regex: RegExp | undefined = versionRegexs[browser as keyof typeof versionRegexs] + const regex: RegExp | undefined = versionRegexes[browser as keyof typeof versionRegexes] if (_isUndefined(regex)) { return null }