-
Notifications
You must be signed in to change notification settings - Fork 142
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* β [RUM-1863] add tests on browser detection * π [RUM-1863] fix iOS webview detection * π add a bit of documentation
- Loading branch information
1 parent
5d5935c
commit 874ebff
Showing
2 changed files
with
174 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
import { combine } from '../mergeInto' | ||
import { Browser, detectBrowser } from './browserDetection' | ||
|
||
describe('browserDetection', () => { | ||
it('detects IE', () => { | ||
expect( | ||
detectBrowser( | ||
fakeWindowWithDefaults({ | ||
navigator: { | ||
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', | ||
}, | ||
document: { documentMode: 11 }, | ||
}) | ||
) | ||
).toBe(Browser.IE) | ||
}) | ||
|
||
it('detects Safari', () => { | ||
expect( | ||
detectBrowser( | ||
fakeWindowWithDefaults({ | ||
navigator: { | ||
userAgent: | ||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Safari/605.1.15', | ||
vendor: 'Apple Computer, Inc.', | ||
}, | ||
}) | ||
) | ||
).toBe(Browser.SAFARI) | ||
|
||
// Emulates Safari detection if 'navigator.vendor' is removed one day | ||
expect( | ||
detectBrowser( | ||
fakeWindowWithDefaults({ | ||
navigator: { | ||
userAgent: | ||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Safari/605.1.15', | ||
}, | ||
}) | ||
) | ||
).toBe(Browser.SAFARI) | ||
|
||
// Webview on iOS | ||
expect( | ||
detectBrowser( | ||
fakeWindowWithDefaults({ | ||
navigator: { | ||
userAgent: | ||
'Mozilla/5.0 (iPhone; CPU iPhone OS 16_1_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/20B110 [FBAN/FBIOS;FBDV/iPhone14,5;FBMD/iPhone;FBSN/iOS;FBSV/16.1.2;FBSS/3;FBID/phone;FBLC/en_US;FBOP/5]', | ||
vendor: 'Apple Computer, Inc.', | ||
}, | ||
}) | ||
) | ||
).toBe(Browser.SAFARI) | ||
}) | ||
|
||
it('detects Chromium', () => { | ||
// Google Chrome 118 | ||
expect( | ||
detectBrowser( | ||
fakeWindowWithDefaults({ | ||
navigator: { | ||
userAgent: | ||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36', | ||
vendor: 'Google Inc.', | ||
}, | ||
chrome: {}, | ||
}) | ||
) | ||
).toBe(Browser.CHROMIUM) | ||
|
||
// Headless chrome | ||
expect( | ||
detectBrowser( | ||
fakeWindowWithDefaults({ | ||
navigator: { | ||
userAgent: | ||
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/92.0.4512.0 Safari/537.36', | ||
vendor: 'Google Inc.', | ||
}, | ||
}) | ||
) | ||
).toBe(Browser.CHROMIUM) | ||
|
||
// Microsoft Edge 89 | ||
expect( | ||
detectBrowser( | ||
fakeWindowWithDefaults({ | ||
navigator: { | ||
userAgent: | ||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36 Edg/89.0.774.54', | ||
vendor: 'Google Inc.', | ||
}, | ||
chrome: {}, | ||
}) | ||
) | ||
).toBe(Browser.CHROMIUM) | ||
}) | ||
|
||
it('other browsers', () => { | ||
// Firefox 10 | ||
expect( | ||
detectBrowser( | ||
fakeWindowWithDefaults({ | ||
navigator: { userAgent: 'Mozilla/5.0 (X11; Linux i686; rv:10.0) Gecko/20100101 Firefox/10.0' }, | ||
}) | ||
) | ||
).toBe(Browser.OTHER) | ||
|
||
// Firefox 120 | ||
expect( | ||
detectBrowser( | ||
fakeWindowWithDefaults({ | ||
navigator: { | ||
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:120.0) Gecko/20100101 Firefox/120.0', | ||
}, | ||
}) | ||
) | ||
).toBe(Browser.OTHER) | ||
}) | ||
|
||
function fakeWindowWithDefaults(partial: any): Window { | ||
return combine( | ||
{ | ||
navigator: { | ||
userAgent: '', | ||
}, | ||
document: {}, | ||
}, | ||
partial | ||
) as Window | ||
} | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,48 @@ | ||
let browserIsIE: boolean | undefined | ||
// Exported only for tests | ||
export const enum Browser { | ||
IE, | ||
CHROMIUM, | ||
SAFARI, | ||
OTHER, | ||
} | ||
|
||
export function isIE() { | ||
return browserIsIE ?? (browserIsIE = Boolean((document as any).documentMode)) | ||
return detectBrowserCached() === Browser.IE | ||
} | ||
|
||
let browserIsChromium: boolean | undefined | ||
export function isChromium() { | ||
return ( | ||
browserIsChromium ?? | ||
(browserIsChromium = !!(window as any).chrome || /HeadlessChrome/.test(window.navigator.userAgent)) | ||
) | ||
return detectBrowserCached() === Browser.CHROMIUM | ||
} | ||
|
||
let browserIsSafari: boolean | undefined | ||
export function isSafari() { | ||
return browserIsSafari ?? (browserIsSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent)) | ||
return detectBrowserCached() === Browser.SAFARI | ||
} | ||
|
||
let browserCache: Browser | undefined | ||
function detectBrowserCached() { | ||
return browserCache ?? (browserCache = detectBrowser()) | ||
} | ||
|
||
// Exported only for tests | ||
export function detectBrowser(browserWindow: Window = window) { | ||
const userAgent = browserWindow.navigator.userAgent | ||
if ((browserWindow as any).chrome || /HeadlessChrome/.test(userAgent)) { | ||
return Browser.CHROMIUM | ||
} | ||
|
||
if ( | ||
// navigator.vendor is deprecated, but it is the most resilient way we found to detect | ||
// "Apple maintained browsers" (AKA Safari). If one day it gets removed, we still have the | ||
// useragent test as a semi-working fallback. | ||
browserWindow.navigator.vendor?.indexOf('Apple') === 0 || | ||
(/safari/i.test(userAgent) && !/chrome|android/i.test(userAgent)) | ||
) { | ||
return Browser.SAFARI | ||
} | ||
|
||
if ((browserWindow.document as any).documentMode) { | ||
return Browser.IE | ||
} | ||
|
||
return Browser.OTHER | ||
} |