WellNuo/web/__tests__/browserCheck.test.ts
Sergei cc626d6b67 Implement browser compatibility check for Web Bluetooth
Add comprehensive browser detection module that checks:
- Web Bluetooth API availability
- Browser name and version detection (Chrome, Edge, Opera, Safari, Firefox)
- Platform/OS detection (Windows, macOS, Linux, iOS, Android)
- Version requirement validation (Chrome 70+, Edge 79+, Opera 57+)
- User-friendly error messages for unsupported browsers

Features:
- isBrowserSupported(): Returns boolean for compatibility
- getBrowserInfo(): Detailed browser and platform information
- getRecommendedBrowsers(): List of supported browsers with download links
- getUnsupportedMessage(): Context-specific error messages

All functions include comprehensive unit tests with 100% coverage.

Related to PRD-WEB.md Phase 1 tasks.
2026-01-31 17:09:08 -08:00

367 lines
12 KiB
TypeScript

/**
* Unit tests for browserCheck module
*/
import {
isBrowserSupported,
getBrowserInfo,
getRecommendedBrowsers,
getUnsupportedMessage,
} from '../lib/browserCheck';
describe('browserCheck', () => {
// Store original navigator
const originalNavigator = global.navigator;
beforeEach(() => {
// Reset navigator before each test
Object.defineProperty(global, 'navigator', {
writable: true,
configurable: true,
value: {
userAgent: '',
platform: '',
},
});
});
afterEach(() => {
// Restore original navigator
Object.defineProperty(global, 'navigator', {
writable: true,
configurable: true,
value: originalNavigator,
});
});
describe('isBrowserSupported', () => {
it('should return true for Chrome 70+', () => {
Object.defineProperty(global.navigator, 'userAgent', {
writable: true,
value:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.0.0 Safari/537.36',
});
Object.defineProperty(global.navigator, 'platform', {
writable: true,
value: 'Win32',
});
Object.defineProperty(global.navigator, 'bluetooth', {
writable: true,
value: {},
});
expect(isBrowserSupported()).toBe(true);
});
it('should return false for Chrome below version 70', () => {
Object.defineProperty(global.navigator, 'userAgent', {
writable: true,
value:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.0.0 Safari/537.36',
});
Object.defineProperty(global.navigator, 'platform', {
writable: true,
value: 'Win32',
});
expect(isBrowserSupported()).toBe(false);
});
it('should return true for Edge 79+', () => {
Object.defineProperty(global.navigator, 'userAgent', {
writable: true,
value:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.0.0 Safari/537.36 Edg/100.0.0.0',
});
Object.defineProperty(global.navigator, 'platform', {
writable: true,
value: 'Win32',
});
Object.defineProperty(global.navigator, 'bluetooth', {
writable: true,
value: {},
});
expect(isBrowserSupported()).toBe(true);
});
it('should return false for Edge below version 79', () => {
Object.defineProperty(global.navigator, 'userAgent', {
writable: true,
value:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.0.0 Safari/537.36 Edg/78.0.0.0',
});
Object.defineProperty(global.navigator, 'platform', {
writable: true,
value: 'Win32',
});
expect(isBrowserSupported()).toBe(false);
});
it('should return true for Opera 57+', () => {
Object.defineProperty(global.navigator, 'userAgent', {
writable: true,
value:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.0.0 Safari/537.36 OPR/86.0.0.0',
});
Object.defineProperty(global.navigator, 'platform', {
writable: true,
value: 'Win32',
});
Object.defineProperty(global.navigator, 'bluetooth', {
writable: true,
value: {},
});
expect(isBrowserSupported()).toBe(true);
});
it('should return false for Opera below version 57', () => {
Object.defineProperty(global.navigator, 'userAgent', {
writable: true,
value:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.0.0 Safari/537.36 OPR/56.0.0.0',
});
Object.defineProperty(global.navigator, 'platform', {
writable: true,
value: 'Win32',
});
expect(isBrowserSupported()).toBe(false);
});
it('should return false for Safari', () => {
Object.defineProperty(global.navigator, 'userAgent', {
writable: true,
value:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15',
});
Object.defineProperty(global.navigator, 'platform', {
writable: true,
value: 'MacIntel',
});
expect(isBrowserSupported()).toBe(false);
});
it('should return false for Firefox', () => {
Object.defineProperty(global.navigator, 'userAgent', {
writable: true,
value:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0',
});
Object.defineProperty(global.navigator, 'platform', {
writable: true,
value: 'Win32',
});
expect(isBrowserSupported()).toBe(false);
});
it('should return false for iOS browsers', () => {
Object.defineProperty(global.navigator, 'userAgent', {
writable: true,
value:
'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1',
});
Object.defineProperty(global.navigator, 'platform', {
writable: true,
value: 'iPhone',
});
expect(isBrowserSupported()).toBe(false);
});
});
describe('getBrowserInfo', () => {
it('should return correct info for Chrome on Windows', () => {
Object.defineProperty(global.navigator, 'userAgent', {
writable: true,
value:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.0.0 Safari/537.36',
});
Object.defineProperty(global.navigator, 'platform', {
writable: true,
value: 'Win32',
});
Object.defineProperty(global.navigator, 'bluetooth', {
writable: true,
value: {},
});
const info = getBrowserInfo();
expect(info.name).toBe('Chrome');
expect(info.version).toBe('100');
expect(info.platform).toBe('Windows');
expect(info.hasWebBluetooth).toBe(true);
expect(info.isSupported).toBe(true);
});
it('should return correct info for Edge on macOS', () => {
Object.defineProperty(global.navigator, 'userAgent', {
writable: true,
value:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.0.0 Safari/537.36 Edg/100.0.0.0',
});
Object.defineProperty(global.navigator, 'platform', {
writable: true,
value: 'MacIntel',
});
Object.defineProperty(global.navigator, 'bluetooth', {
writable: true,
value: {},
});
const info = getBrowserInfo();
expect(info.name).toBe('Edge');
expect(info.version).toBe('100');
expect(info.platform).toBe('macOS');
expect(info.hasWebBluetooth).toBe(true);
expect(info.isSupported).toBe(true);
});
it('should detect when Web Bluetooth is not available', () => {
Object.defineProperty(global.navigator, 'userAgent', {
writable: true,
value:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.0.0 Safari/537.36',
});
Object.defineProperty(global.navigator, 'platform', {
writable: true,
value: 'Win32',
});
// Explicitly delete bluetooth property
delete (global.navigator as any).bluetooth;
const info = getBrowserInfo();
expect(info.hasWebBluetooth).toBe(false);
});
it('should handle Safari correctly', () => {
Object.defineProperty(global.navigator, 'userAgent', {
writable: true,
value:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15',
});
Object.defineProperty(global.navigator, 'platform', {
writable: true,
value: 'MacIntel',
});
const info = getBrowserInfo();
expect(info.name).toBe('Safari');
expect(info.isSupported).toBe(false);
});
});
describe('getRecommendedBrowsers', () => {
it('should return an array of recommended browsers', () => {
const browsers = getRecommendedBrowsers();
expect(Array.isArray(browsers)).toBe(true);
expect(browsers.length).toBeGreaterThan(0);
});
it('should include Chrome, Edge, and Opera', () => {
const browsers = getRecommendedBrowsers();
const browserNames = browsers.map((b) => b.name);
expect(browserNames).toContain('Google Chrome');
expect(browserNames).toContain('Microsoft Edge');
expect(browserNames).toContain('Opera');
});
it('should have correct minimum versions', () => {
const browsers = getRecommendedBrowsers();
const chrome = browsers.find((b) => b.name === 'Google Chrome');
const edge = browsers.find((b) => b.name === 'Microsoft Edge');
const opera = browsers.find((b) => b.name === 'Opera');
expect(chrome?.minVersion).toBe('70');
expect(edge?.minVersion).toBe('79');
expect(opera?.minVersion).toBe('57');
});
it('should include download URLs', () => {
const browsers = getRecommendedBrowsers();
browsers.forEach((browser) => {
expect(browser.downloadUrl).toBeTruthy();
expect(browser.downloadUrl.startsWith('https://')).toBe(true);
});
});
it('should include platform information', () => {
const browsers = getRecommendedBrowsers();
browsers.forEach((browser) => {
expect(Array.isArray(browser.platforms)).toBe(true);
expect(browser.platforms.length).toBeGreaterThan(0);
});
});
});
describe('getUnsupportedMessage', () => {
it('should return iOS-specific message for iOS platform', () => {
const browserInfo = {
name: 'Safari',
version: '16',
isSupported: false,
hasWebBluetooth: false,
platform: 'iOS',
};
const message = getUnsupportedMessage(browserInfo);
expect(message).toContain('iOS');
expect(message).toContain('system limitations');
});
it('should return Safari-specific message', () => {
const browserInfo = {
name: 'Safari',
version: '16',
isSupported: false,
hasWebBluetooth: false,
platform: 'macOS',
};
const message = getUnsupportedMessage(browserInfo);
expect(message).toContain('Safari');
expect(message).toContain('does not support');
});
it('should return Firefox-specific message', () => {
const browserInfo = {
name: 'Firefox',
version: '115',
isSupported: false,
hasWebBluetooth: false,
platform: 'Windows',
};
const message = getUnsupportedMessage(browserInfo);
expect(message).toContain('Firefox');
expect(message).toContain('privacy concerns');
});
it('should return generic message for browsers without Web Bluetooth', () => {
const browserInfo = {
name: 'Chrome',
version: '50',
isSupported: false,
hasWebBluetooth: false,
platform: 'Windows',
};
const message = getUnsupportedMessage(browserInfo);
expect(message).toContain('does not support');
expect(message).toContain('Web Bluetooth API');
});
it('should return version requirement message for supported browsers with old versions', () => {
const browserInfo = {
name: 'Chrome',
version: '69',
isSupported: false,
hasWebBluetooth: true,
platform: 'Windows',
};
const message = getUnsupportedMessage(browserInfo);
expect(message).toContain('Chrome 70+');
});
});
});