From cd708bbc8e46705376f9cf3bd438a59c0063b6e7 Mon Sep 17 00:00:00 2001 From: Blake Byrnes Date: Fri, 19 Nov 2021 11:48:16 -0500 Subject: [PATCH] fix(plugins): improve user agent selector --- commons/Logger.ts | 1 + .../lib/BrowserData.ts | 4 +++ .../lib/DataLoader.ts | 1 + .../lib/VersionUtils.ts | 1 + .../lib/helpers/selectUserAgentOption.ts | 32 +++++++++++++------ .../test/selectUserAgentOptions.test.ts | 29 +++++++++++++++++ 6 files changed, 58 insertions(+), 10 deletions(-) create mode 100644 plugins/default-browser-emulator/test/selectUserAgentOptions.test.ts diff --git a/commons/Logger.ts b/commons/Logger.ts index e5c6f72d4..4ffb70a1a 100644 --- a/commons/Logger.ts +++ b/commons/Logger.ts @@ -141,6 +141,7 @@ function translateToPrintable( value: true, }); result.error = value; + continue; } const printable = translateValueToPrintable(value); if (!printable) continue; diff --git a/plugins/default-browser-emulator/lib/BrowserData.ts b/plugins/default-browser-emulator/lib/BrowserData.ts index 264a8a52a..688926585 100644 --- a/plugins/default-browser-emulator/lib/BrowserData.ts +++ b/plugins/default-browser-emulator/lib/BrowserData.ts @@ -31,6 +31,10 @@ 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 776e65275..6a1b6ca6e 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 6719fc53b..2b439a4b5 100644 --- a/plugins/default-browser-emulator/lib/helpers/selectUserAgentOption.ts +++ b/plugins/default-browser-emulator/lib/helpers/selectUserAgentOption.ts @@ -15,10 +15,11 @@ export default function selectUserAgentOption( 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; + return ( + x.browserName === 'chrome' && + x.browserVersion.major === latestChromeBrowserVersion.major && + x.browserVersion.minor === latestChromeBrowserVersion.minor + ); }); return pickRandomUserAgentOption(filteredOptions); } @@ -45,6 +46,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 +74,19 @@ function isSelectorMatch(userAgentOption: IDataUserAgentOption, selectors: ISele version = browserVersion; } else if (name === userAgentOption.operatingSystemName) { version = operatingSystemVersion; - } else continue; + } else { + return false; + } - const isMatch = matches.every(match => - compareVersions.compare(version, match.version, match.operator), - ); - if (isMatch) return true; + for (const match of matches) { + if (match.version === '*.*.*') continue; + const isValid = compareVersions.compare(version, match.version, match.operator); + + // must match every selector + if (!isValid) return false; + } } - return false; + return true; } interface ISelectorMatch { @@ -135,10 +145,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..3ebec67ca --- /dev/null +++ b/plugins/default-browser-emulator/test/selectUserAgentOptions.test.ts @@ -0,0 +1,29 @@ +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) { + // eslint-disable-next-line jest/no-try-expect + expect(err.message).toMatch('No installed UserAgent'); + } +});