From bf71b34fca73ed14eeb23616682799ff545fc371 Mon Sep 17 00:00:00 2001 From: Alex Rudenko Date: Tue, 20 Feb 2024 16:02:13 +0100 Subject: [PATCH] feat: allow comparing browser versions (#11954) Co-authored-by: Nikolay Vitkov <34244704+Lightning00Blade@users.noreply.github.com> --- .../browsers.getversioncomparator.md | 25 ++++++++++++++++ docs/browsers-api/index.md | 29 ++++++++++--------- package-lock.json | 6 ++-- packages/browsers/package.json | 3 +- .../browsers/src/browser-data/browser-data.ts | 20 +++++++++++++ .../src/browser-data/chrome-headless-shell.ts | 2 +- packages/browsers/src/browser-data/chrome.ts | 18 ++++++++++++ .../browsers/src/browser-data/chromedriver.ts | 2 +- .../browsers/src/browser-data/chromium.ts | 4 +++ packages/browsers/src/browser-data/firefox.ts | 5 ++++ packages/browsers/src/main.ts | 1 + .../test/src/chrome/chrome-data.spec.ts | 7 +++++ .../test/src/chromium/chromium-data.spec.ts | 7 +++++ .../test/src/firefox/firefox-data.spec.ts | 7 +++++ 14 files changed, 115 insertions(+), 21 deletions(-) create mode 100644 docs/browsers-api/browsers.getversioncomparator.md diff --git a/docs/browsers-api/browsers.getversioncomparator.md b/docs/browsers-api/browsers.getversioncomparator.md new file mode 100644 index 00000000000..75c6612fc1f --- /dev/null +++ b/docs/browsers-api/browsers.getversioncomparator.md @@ -0,0 +1,25 @@ +--- +sidebar_label: getVersionComparator +--- + +# getVersionComparator() function + +Returns a version comparator for the given browser that can be used to sort browser versions. + +#### Signature: + +```typescript +export declare function getVersionComparator( + browser: Browser +): (a: string, b: string) => number; +``` + +## Parameters + +| Parameter | Type | Description | +| --------- | -------------------------------- | ----------- | +| browser | [Browser](./browsers.browser.md) | | + +**Returns:** + +(a: string, b: string) => number diff --git a/docs/browsers-api/index.md b/docs/browsers-api/index.md index 3610af4962a..fcc4c73bbf5 100644 --- a/docs/browsers-api/index.md +++ b/docs/browsers-api/index.md @@ -50,20 +50,21 @@ The programmatic API allows installing and launching browsers from your code. Se ## Functions -| Function | Description | -| --------------------------------------------------------------------------------- | ----------------------------------------------------------------- | -| [canDownload(options)](./browsers.candownload.md) | | -| [computeExecutablePath(options)](./browsers.computeexecutablepath.md) | | -| [computeSystemExecutablePath(options)](./browsers.computesystemexecutablepath.md) | | -| [createProfile(browser, opts)](./browsers.createprofile.md) | | -| [detectBrowserPlatform()](./browsers.detectbrowserplatform.md) | | -| [getInstalledBrowsers(options)](./browsers.getinstalledbrowsers.md) | Returns metadata about browsers installed in the cache directory. | -| [install(options)](./browsers.install.md) | | -| [install(options)](./browsers.install_1.md) | | -| [launch(opts)](./browsers.launch.md) | | -| [makeProgressCallback(browser, buildId)](./browsers.makeprogresscallback.md) | | -| [resolveBuildId(browser, platform, tag)](./browsers.resolvebuildid.md) | | -| [uninstall(options)](./browsers.uninstall.md) | | +| Function | Description | +| --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | +| [canDownload(options)](./browsers.candownload.md) | | +| [computeExecutablePath(options)](./browsers.computeexecutablepath.md) | | +| [computeSystemExecutablePath(options)](./browsers.computesystemexecutablepath.md) | | +| [createProfile(browser, opts)](./browsers.createprofile.md) | | +| [detectBrowserPlatform()](./browsers.detectbrowserplatform.md) | | +| [getInstalledBrowsers(options)](./browsers.getinstalledbrowsers.md) | Returns metadata about browsers installed in the cache directory. | +| [getVersionComparator(browser)](./browsers.getversioncomparator.md) | Returns a version comparator for the given browser that can be used to sort browser versions. | +| [install(options)](./browsers.install.md) | | +| [install(options)](./browsers.install_1.md) | | +| [launch(opts)](./browsers.launch.md) | | +| [makeProgressCallback(browser, buildId)](./browsers.makeprogresscallback.md) | | +| [resolveBuildId(browser, platform, tag)](./browsers.resolvebuildid.md) | | +| [uninstall(options)](./browsers.uninstall.md) | | ## Interfaces diff --git a/package-lock.json b/package-lock.json index 9839cdb732a..c5d83a37a24 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6716,7 +6716,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -9163,7 +9162,6 @@ "version": "7.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -10953,8 +10951,7 @@ "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yargs": { "version": "16.2.0", @@ -11083,6 +11080,7 @@ "extract-zip": "2.0.1", "progress": "2.0.3", "proxy-agent": "6.4.0", + "semver": "7.6.0", "tar-fs": "3.0.5", "unbzip2-stream": "1.4.3", "yargs": "17.7.2" diff --git a/packages/browsers/package.json b/packages/browsers/package.json index 1334173eff7..e7ae80b2068 100644 --- a/packages/browsers/package.json +++ b/packages/browsers/package.json @@ -101,7 +101,8 @@ "proxy-agent": "6.4.0", "tar-fs": "3.0.5", "unbzip2-stream": "1.4.3", - "yargs": "17.7.2" + "yargs": "17.7.2", + "semver": "7.6.0" }, "devDependencies": { "@types/debug": "4.1.12", diff --git a/packages/browsers/src/browser-data/browser-data.ts b/packages/browsers/src/browser-data/browser-data.ts index 67bb4990b2f..3e78030aa75 100644 --- a/packages/browsers/src/browser-data/browser-data.ts +++ b/packages/browsers/src/browser-data/browser-data.ts @@ -43,6 +43,14 @@ export const executablePathByBrowser = { [Browser.FIREFOX]: firefox.relativeExecutablePath, }; +export const versionComparators = { + [Browser.CHROMEDRIVER]: chromedriver.compareVersions, + [Browser.CHROMEHEADLESSSHELL]: chromeHeadlessShell.compareVersions, + [Browser.CHROME]: chrome.compareVersions, + [Browser.CHROMIUM]: chromium.compareVersions, + [Browser.FIREFOX]: firefox.compareVersions, +}; + export {Browser, BrowserPlatform, ChromeReleaseChannel}; /** @@ -185,3 +193,15 @@ export function resolveSystemExecutablePath( return chrome.resolveSystemExecutablePath(platform, channel); } } + +/** + * Returns a version comparator for the given browser that can be used to sort + * browser versions. + * + * @public + */ +export function getVersionComparator( + browser: Browser +): (a: string, b: string) => number { + return versionComparators[browser]; +} diff --git a/packages/browsers/src/browser-data/chrome-headless-shell.ts b/packages/browsers/src/browser-data/chrome-headless-shell.ts index ee29f60aafa..f5f65cdbd43 100644 --- a/packages/browsers/src/browser-data/chrome-headless-shell.ts +++ b/packages/browsers/src/browser-data/chrome-headless-shell.ts @@ -66,4 +66,4 @@ export function relativeExecutablePath( } } -export {resolveBuildId} from './chrome.js'; +export {resolveBuildId, compareVersions} from './chrome.js'; diff --git a/packages/browsers/src/browser-data/chrome.ts b/packages/browsers/src/browser-data/chrome.ts index 9fbd3afdf00..c7975163fcd 100644 --- a/packages/browsers/src/browser-data/chrome.ts +++ b/packages/browsers/src/browser-data/chrome.ts @@ -6,6 +6,8 @@ import path from 'path'; +import semver from 'semver'; + import {getJSON} from '../httpUtil.js'; import {BrowserPlatform, ChromeReleaseChannel} from './types.js'; @@ -193,3 +195,19 @@ export function resolveSystemExecutablePath( `Unable to detect browser executable path for '${channel}' on ${platform}.` ); } + +export function compareVersions(a: string, b: string): number { + if (!semver.valid(a)) { + throw new Error(`Version ${a} is not a valid semver version`); + } + if (!semver.valid(b)) { + throw new Error(`Version ${b} is not a valid semver version`); + } + if (semver.gt(a, b)) { + return 1; + } else if (semver.lt(a, b)) { + return -1; + } else { + return 0; + } +} diff --git a/packages/browsers/src/browser-data/chromedriver.ts b/packages/browsers/src/browser-data/chromedriver.ts index 12913fef4e9..2f1242b249b 100644 --- a/packages/browsers/src/browser-data/chromedriver.ts +++ b/packages/browsers/src/browser-data/chromedriver.ts @@ -53,4 +53,4 @@ export function relativeExecutablePath( } } -export {resolveBuildId} from './chrome.js'; +export {resolveBuildId, compareVersions} from './chrome.js'; diff --git a/packages/browsers/src/browser-data/chromium.ts b/packages/browsers/src/browser-data/chromium.ts index 09cfc987a8c..820e76d0185 100644 --- a/packages/browsers/src/browser-data/chromium.ts +++ b/packages/browsers/src/browser-data/chromium.ts @@ -86,3 +86,7 @@ export async function resolveBuildId( ) ); } + +export function compareVersions(a: string, b: string): number { + return Number(a) - Number(b); +} diff --git a/packages/browsers/src/browser-data/firefox.ts b/packages/browsers/src/browser-data/firefox.ts index ccc30fa1b50..6c221930135 100644 --- a/packages/browsers/src/browser-data/firefox.ts +++ b/packages/browsers/src/browser-data/firefox.ts @@ -328,3 +328,8 @@ async function writePreferences(options: ProfileOptions): Promise { await fs.promises.copyFile(prefsPath, prefsBackupPath); } } + +export function compareVersions(a: string, b: string): number { + // TODO: this is a not very reliable check. + return parseInt(a.replace('.', ''), 16) - parseInt(b.replace('.', ''), 16); +} diff --git a/packages/browsers/src/main.ts b/packages/browsers/src/main.ts index df93de530dc..c03c0c00904 100644 --- a/packages/browsers/src/main.ts +++ b/packages/browsers/src/main.ts @@ -37,6 +37,7 @@ export { BrowserPlatform, ChromeReleaseChannel, createProfile, + getVersionComparator, } from './browser-data/browser-data.js'; export {CLI, makeProgressCallback} from './CLI.js'; export {Cache, InstalledBrowser} from './Cache.js'; diff --git a/packages/browsers/test/src/chrome/chrome-data.spec.ts b/packages/browsers/test/src/chrome/chrome-data.spec.ts index 2ad2af9482e..4d5bc980b18 100644 --- a/packages/browsers/test/src/chrome/chrome-data.spec.ts +++ b/packages/browsers/test/src/chrome/chrome-data.spec.ts @@ -16,6 +16,7 @@ import { relativeExecutablePath, resolveSystemExecutablePath, resolveBuildId, + compareVersions, } from '../../../lib/cjs/browser-data/chrome.js'; describe('Chrome', () => { @@ -116,4 +117,10 @@ describe('Chrome', () => { it('should resolve build prefix', async () => { assert.strictEqual(await resolveBuildId('115.0.5790'), '115.0.5790.170'); }); + + it('should compare versions', async () => { + assert.ok(compareVersions('115.0.5790', '115.0.5789') >= 1); + assert.ok(compareVersions('115.0.5789', '115.0.5790') <= -1); + assert.ok(compareVersions('115.0.5790', '115.0.5790') === 0); + }); }); diff --git a/packages/browsers/test/src/chromium/chromium-data.spec.ts b/packages/browsers/test/src/chromium/chromium-data.spec.ts index 601efccc474..ecb7946c996 100644 --- a/packages/browsers/test/src/chromium/chromium-data.spec.ts +++ b/packages/browsers/test/src/chromium/chromium-data.spec.ts @@ -11,6 +11,7 @@ import {BrowserPlatform} from '../../../lib/cjs/browser-data/browser-data.js'; import { resolveDownloadUrl, relativeExecutablePath, + compareVersions, } from '../../../lib/cjs/browser-data/chromium.js'; describe('Chromium', () => { @@ -59,4 +60,10 @@ describe('Chromium', () => { path.join('chrome-win', 'chrome.exe') ); }); + + it('should compare versions', async () => { + assert.ok(compareVersions('12372323', '12372322') >= 1); + assert.ok(compareVersions('12372322', '12372323') <= -1); + assert.ok(compareVersions('12372323', '12372323') === 0); + }); }); diff --git a/packages/browsers/test/src/firefox/firefox-data.spec.ts b/packages/browsers/test/src/firefox/firefox-data.spec.ts index d0bb056090b..b5dd2db0b33 100644 --- a/packages/browsers/test/src/firefox/firefox-data.spec.ts +++ b/packages/browsers/test/src/firefox/firefox-data.spec.ts @@ -11,6 +11,7 @@ import path from 'path'; import {BrowserPlatform} from '../../../lib/cjs/browser-data/browser-data.js'; import { + compareVersions, createProfile, relativeExecutablePath, resolveDownloadUrl, @@ -94,4 +95,10 @@ describe('Firefox', () => { assert.ok(text.includes(`user_pref("test", 1);`)); // custom preference. }); }); + + it('should compare versions', async () => { + assert.ok(compareVersions('111.0a1', '110.0a1') >= 1); + assert.ok(compareVersions('110.0a1', '111.0a1') <= -1); + assert.ok(compareVersions('111.0a1', '111.0a1') === 0); + }); });