diff --git a/README.md b/README.md index 8397f0f..29f9e77 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![codecov](https://codecov.io/gh/pure-js/browser-detection/branch/master/graph/badge.svg)](https://codecov.io/gh/pure-js/browser-detection) Browser detection using the user agent. -Tested on most popular browser in the World on October 2017, statistic gets from StatCounter. +Tested on most popular browser in the World on October 2017 (and updated on July 2023), statistic gets from StatCounter. > It's worth re-iterating: it's very rarely a good idea to use user agent sniffing. You can almost always find a better, more broadly compatible way to solve your problem! > diff --git a/src/browser-detection.test.ts b/src/browser-detection.test.ts index 1ec48f7..f36dbfe 100644 --- a/src/browser-detection.test.ts +++ b/src/browser-detection.test.ts @@ -56,6 +56,20 @@ describe('Should correctly detect name & version of', () => { }); }); + test('Samsung Internet', () => { + const samsung = { + userAgent: `Mozilla/5.0 (Linux; Android 5.1.1; + SAMSUNG SM-G360T1 Build/LMY47X) + AppleWebKit/537.36 (KHTML, like Gecko) + SamsungBrowser/3.3 Chrome/38.0.2125.102 Mobile Safari/537.36`, + }; + + expect(detectBrowserNameAndVersion(samsung)).toEqual({ + name: 'Samsung Internet', + version: 3, + }); + }); + test('UC Browser', () => { const ucBrowser = { userAgent: `UCWEB/2.0 (Java; U; MIDP-2.0; Nokia203/20.37) @@ -93,16 +107,17 @@ describe('Should correctly detect name & version of', () => { }); }); - test('Internet Explorer', () => { - const ie = { - userAgent: `Mozilla/5.0 (Windows NT 10.0; WOW64; - Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; - .NET CLR 3.0.30729; .NET CLR 3.5.30729; rv:11.0) like Gecko`, + test('QQ Browser', () => { + const qqbrowser = { + userAgent: `Mozilla/5.0 (Linux; U; Android 11; zh-cn; 21091116UC Build/RP1A.200720.011) + AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 + Chrome/66.0.3359.126 MQQBrowser/10.8 Mobile Safari/537.36`, }; - expect(detectBrowserNameAndVersion(ie)).toEqual({ - name: 'IE', - version: 11, + expect(detectBrowserNameAndVersion(qqbrowser)).toEqual({ + name: 'QQ Browser', + // Version: 10.8, // TODO: add version after dot + version: 10, }); }); @@ -121,20 +136,6 @@ describe('Should correctly detect name & version of', () => { }); }); - test('Samsung Internet', () => { - const samsung = { - userAgent: `Mozilla/5.0 (Linux; Android 5.1.1; - SAMSUNG SM-G360T1 Build/LMY47X) - AppleWebKit/537.36 (KHTML, like Gecko) - SamsungBrowser/3.3 Chrome/38.0.2125.102 Mobile Safari/537.36`, - }; - - expect(detectBrowserNameAndVersion(samsung)).toEqual({ - name: 'Samsung Internet', - version: 3, - }); - }); - test('Android browser', () => { const android = { userAgent: `Mozilla/5.0 (Linux; U; Android 4.0.4; @@ -160,6 +161,19 @@ describe('Should correctly detect name & version of', () => { version: 15, }); }); + + test('Internet Explorer', () => { + const ie = { + userAgent: `Mozilla/5.0 (Windows NT 10.0; WOW64; + Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; + .NET CLR 3.0.30729; .NET CLR 3.5.30729; rv:11.0) like Gecko`, + }; + + expect(detectBrowserNameAndVersion(ie)).toEqual({ + name: 'IE', + version: 11, + }); + }); }); describe('Should not fail', () => { diff --git a/src/browser-detection.ts b/src/browser-detection.ts index 86dfb86..3d423c9 100644 --- a/src/browser-detection.ts +++ b/src/browser-detection.ts @@ -4,9 +4,10 @@ function isChrome(userAgent: string): boolean { return userAgent.includes('Chrome') && !userAgent.includes('Chromium') + && !userAgent.includes('SamsungBrowser') && !userAgent.includes('OPR') - && !userAgent.includes('Edge') - && !userAgent.includes('SamsungBrowser'); + && !userAgent.includes('MQQBrowser') + && !userAgent.includes('Edge'); } /** @@ -20,24 +21,10 @@ function isSafari(userAgent: string): boolean { } /** - * Detects UC browser - */ -function isUcBrowser(userAgent: string): boolean { - return userAgent.includes('UCBrowser'); -} - -/** - * Detects Firefox browser - */ -function isFirefox(userAgent: string): boolean { - return userAgent.includes('Firefox') && !userAgent.includes('Seamonkey'); -} - -/** - * Detects IE browser + * Detects Samsung browser */ -function isIe(userAgent: string): boolean { - return (/trident/i.test(userAgent)); +function isSamsungInternet(userAgent: string): boolean { + return userAgent.includes('SamsungBrowser'); } /** @@ -48,10 +35,10 @@ function isOpera(userAgent: string): boolean { } /** - * Detects Samsung browser + * Detects UC browser */ -function isSamsungInternet(userAgent: string): boolean { - return userAgent.includes('SamsungBrowser'); +function isUcBrowser(userAgent: string): boolean { + return userAgent.includes('UCBrowser'); } /** @@ -63,7 +50,28 @@ function isAndroidBrowser(userAgent: string): boolean { && userAgent.includes('AppleWebKit'); } -export type BrowserName = 'Chrome' | 'Safari' | 'UC Browser' | 'Firefox' | 'IE' | 'Opera' | 'Samsung Internet' | 'Android Browser' | 'Edge'; +/** + * Detects Firefox browser + */ +function isFirefox(userAgent: string): boolean { + return userAgent.includes('Firefox') && !userAgent.includes('Seamonkey'); +} + +/** + * Detects QQ browser + */ +function isQqBrowser(userAgent: string): boolean { + return userAgent.includes('MQQBrowser'); +} + +/** + * Detects IE browser + */ +function isIe(userAgent: string): boolean { + return (/trident/i.test(userAgent)); +} + +export type BrowserName = 'Chrome' | 'Safari' | 'Samsung Internet' | 'Opera' | 'UC Browser' | 'Android Browser' | 'Firefox' | 'QQ Browser' | 'Edge' | 'IE'; /** * Detects Edge browser @@ -74,8 +82,6 @@ function isEdge(userAgent: string): boolean { /** * Detects browser name - * @param {string} userAgent - window.navigator - * @return {string} browser name */ function detectBrowserName(userAgent: string): BrowserName | undefined { if (isChrome(userAgent)) { @@ -86,44 +92,48 @@ function detectBrowserName(userAgent: string): BrowserName | undefined { return 'Safari'; } - if (isUcBrowser(userAgent)) { - return 'UC Browser'; - } - - if (isFirefox(userAgent)) { - return 'Firefox'; - } - - if (isIe(userAgent)) { - return 'IE'; + if (isSamsungInternet(userAgent)) { + return 'Samsung Internet'; } if (isOpera(userAgent)) { return 'Opera'; } - if (isSamsungInternet(userAgent)) { - return 'Samsung Internet'; + if (isUcBrowser(userAgent)) { + return 'UC Browser'; } if (isAndroidBrowser(userAgent)) { return 'Android Browser'; } + if (isFirefox(userAgent)) { + return 'Firefox'; + } + + if (isQqBrowser(userAgent)) { + return 'QQ Browser'; + } + if (isEdge(userAgent)) { return 'Edge'; } + if (isIe(userAgent)) { + return 'IE'; + } + return undefined; } /** * Retrieve browser version */ -function retrieveVersion(name: string, str: string): number { - name += '/'; - const start = str.indexOf(name); - let preNum = str.substring(start + name.length); +function retrieveVersion(browserName: string, userAgent: string): number { + const name = `${browserName}/`; + const start = userAgent.indexOf(name); + let preNum = userAgent.substring(start + name.length); const index = preNum.indexOf(' '); if (index > 0) { preNum = preNum.substring(0, index); @@ -141,29 +151,26 @@ function retrieveVersion(name: string, str: string): number { return Number(num); } +export type UaBrowserName = 'SamsungBrowser' | 'OPR' | 'UCBrowser' | 'MQQBrowser'; + /** * Returns Association */ -function getBeautifulName(name: BrowserName | undefined): string | undefined { - let browserName; - +function getBrowserUaName(name: BrowserName | undefined): UaBrowserName | undefined { if (name) { switch (name) { case 'Opera': - browserName = 'OPR'; - break; + return 'OPR'; case 'UC Browser': - browserName = 'UCBrowser'; - break; + return 'UCBrowser'; case 'Samsung Internet': - browserName = 'SamsungBrowser'; - break; + return 'SamsungBrowser'; + case 'QQ Browser': + return 'MQQBrowser'; default: return undefined; } } - - return browserName; } /** @@ -189,7 +196,7 @@ function detectBrowserVersion(nav: { } } - const browserName = getBeautifulName(name); + const browserName = getBrowserUaName(name); if (browserName) { return retrieveVersion(browserName, userAgent);