From cd4b6afd67b2932f22c21e8069c25e9f07f1e74f Mon Sep 17 00:00:00 2001 From: Blake Byrnes Date: Tue, 23 Nov 2021 12:53:16 -0500 Subject: [PATCH] fix(plugins): improve user agent selector --- .../lib/BrowserData.ts | 3 ++ .../lib/DataLoader.ts | 1 + .../lib/VersionUtils.ts | 1 + .../lib/helpers/selectUserAgentOption.ts | 34 ++++++++++++------- .../test/selectUserAgentOptions.test.ts | 28 +++++++++++++++ 5 files changed, 55 insertions(+), 12 deletions(-) create mode 100644 plugins/default-browser-emulator/test/selectUserAgentOptions.test.ts diff --git a/plugins/default-browser-emulator/lib/BrowserData.ts b/plugins/default-browser-emulator/lib/BrowserData.ts index 32f20f6b3..2cd4e4974 100644 --- a/plugins/default-browser-emulator/lib/BrowserData.ts +++ b/plugins/default-browser-emulator/lib/BrowserData.ts @@ -31,6 +31,9 @@ export default class BrowserData implements IBrowserData { this.osDataDir = `${this.baseDataDir}/as-${os.name}-${os.version}`; if (!this.dataLoader.isSupportedEmulator(this.osDataDir)) { const otherVersions = this.dataLoader.getBrowserOperatingSystemVersions(browserId, os.name); + if (!otherVersions.length) { + throw new Error(`${browserId} has no emulation data for ${os.name}`); + } const closestVersionMatch = findClosestVersionMatch(os.version, otherVersions); this.osDataDir = `${this.baseDataDir}/as-${os.name}-${closestVersionMatch}`; } diff --git a/plugins/default-browser-emulator/lib/DataLoader.ts b/plugins/default-browser-emulator/lib/DataLoader.ts index 1bedd18ae..70827651c 100644 --- a/plugins/default-browser-emulator/lib/DataLoader.ts +++ b/plugins/default-browser-emulator/lib/DataLoader.ts @@ -62,6 +62,7 @@ export default class DataLoader implements IDataCore { } public getBrowserOperatingSystemVersions(browserId: string, osName: string): string[] { + if (!this.browserOsEmulatorsByVersion[`as-${browserId}`]) return []; return this.browserOsEmulatorsByVersion[`as-${browserId}`][osName]; } } diff --git a/plugins/default-browser-emulator/lib/VersionUtils.ts b/plugins/default-browser-emulator/lib/VersionUtils.ts index e008008d1..ed5c83323 100644 --- a/plugins/default-browser-emulator/lib/VersionUtils.ts +++ b/plugins/default-browser-emulator/lib/VersionUtils.ts @@ -11,6 +11,7 @@ export function convertMacOsVersionString(versionString: string) { export function findClosestVersionMatch(versionToMatch: string, versions: string[]) { if (versions.length === 1 && versions[0] === 'ALL') return 'ALL'; + if (!versions.length) return null; // there is no guarantee we have an exact match, so let's get the closest const versionTree = convertVersionsToTree(versions); diff --git a/plugins/default-browser-emulator/lib/helpers/selectUserAgentOption.ts b/plugins/default-browser-emulator/lib/helpers/selectUserAgentOption.ts index 0cf07ff0a..b470140ff 100644 --- a/plugins/default-browser-emulator/lib/helpers/selectUserAgentOption.ts +++ b/plugins/default-browser-emulator/lib/helpers/selectUserAgentOption.ts @@ -14,12 +14,12 @@ export default function selectUserAgentOption( if (userAgentSelector === 'chrome-latest') userAgentSelector = ''; if (!userAgentSelector) { - const filteredOptions = dataUserAgentOptions.filter(x => { - if (x.browserName !== 'chrome') return false; - if (x.browserVersion.major !== latestChromeBrowserVersion.major) return false; - if (x.browserVersion.minor !== latestChromeBrowserVersion.minor) return false; - return true; - }); + const filteredOptions = dataUserAgentOptions.filter( + x => + x.browserName === 'chrome' && + x.browserVersion.major === latestChromeBrowserVersion.major && + x.browserVersion.minor === latestChromeBrowserVersion.minor, + ); return pickRandomUserAgentOption(filteredOptions); } @@ -45,6 +45,10 @@ function findUserAgentOption( return isSelectorMatch(userAgentOption, selectors); }); + if (!filteredOptions.length) { + throw new Error(`No installed UserAgent Emulators match your criteria (${userAgentSelector})`); + } + const dataUserAgentOption = pickRandom(filteredOptions); return convertToUserAgentOption(dataUserAgentOption); } @@ -69,14 +73,18 @@ function isSelectorMatch(userAgentOption: IDataUserAgentOption, selectors: ISele version = browserVersion; } else if (name === userAgentOption.operatingSystemName) { version = operatingSystemVersion; - } else continue; + } else { + return false; + } + for (const match of matches) { + if (match.version === '*.*.*') continue; + const isValid = compareVersions.compare(version, match.version, match.operator); - const isMatch = matches.every(match => - compareVersions.compare(version, match.version, match.operator), - ); - if (isMatch) return true; + // must match every selector + if (!isValid) return false; + } } - return false; + return true; } interface ISelectorMatch { @@ -135,10 +143,12 @@ function cleanupName(name: string) { } function cleanupOperator(operator: string) { + if (!operator) return '='; return operator.replace(/[^<>=]+/g, ''); } function cleanupVersion(version: string) { + if (!version) return '*'; return version.trim().replace(/[^0-9x*]+/g, '.'); } diff --git a/plugins/default-browser-emulator/test/selectUserAgentOptions.test.ts b/plugins/default-browser-emulator/test/selectUserAgentOptions.test.ts new file mode 100644 index 000000000..90ae7f6df --- /dev/null +++ b/plugins/default-browser-emulator/test/selectUserAgentOptions.test.ts @@ -0,0 +1,28 @@ +import selectUserAgentOption from '../lib/helpers/selectUserAgentOption'; +import DataLoader from '../lib/DataLoader'; + +const dataLoader = new DataLoader(`${__dirname}/..`); + +test('should support choosing a specific useragent', async () => { + const options = selectUserAgentOption( + '~ chrome >= 88 && chrome < 89', + dataLoader.userAgentOptions, + ); + expect(options.browserVersion.major).toBe('88'); +}); + +test('should support choosing a specific OS', async () => { + const options = selectUserAgentOption('~ mac & chrome >= 88', dataLoader.userAgentOptions); + expect(parseInt(options.browserVersion.major, 10)).toBeGreaterThanOrEqual(88); + expect(options.operatingSystemName).toBe('mac-os'); +}); + +test('should throw an error for a non-installed pattern', async () => { + try { + expect( + selectUserAgentOption('~ mac & chrome >= 500000', dataLoader.userAgentOptions), + ).not.toBeTruthy(); + } catch (err) { + expect(err.message).toMatch('No installed UserAgent'); + } +});