import os from 'node:os' import path from 'node:path' import url from 'node:url' import cp from 'node:child_process' import fs from 'node:fs' import { describe, it, expect, vi, beforeEach } from 'vitest' import { canDownload, resolveBuildId, detectBrowserPlatform } from '@puppeteer/browsers' import { locateChrome, locateApp } from 'locate-app' import { parseParams, getBuildIdByChromePath, getBuildIdByFirefoxPath, setupPuppeteerBrowser, canAccess } from '../../src/node/utils.js' const __dirname = path.dirname(url.fileURLToPath(import.meta.url)) vi.mock('fs', () => import(path.join(process.cwd(), '__mocks__', 'fs'))) vi.mock('node:os', () => ({ default: { tmpdir: vi.fn().mockReturnValue('/tmp'), platform: vi.fn().mockReturnValue('darwin') } })) vi.mock('locate-app', () => ({ locateChrome: vi.fn().mockResolvedValue('/path/to/chrome'), locateFirefox: vi.fn().mockResolvedValue('/path/to/firefox'), locateApp: vi.fn().mockResolvedValue('/path/to/chromium') })) vi.mock('node:fs', () => ({ default: { accessSync: vi.fn(), readdirSync: vi.fn().mockReturnValue([ '114.0.5735.199', '115.0.5790.110', 'chrome.exe', 'chrome.VisualElementsManifest.xml', 'chrome_proxy.exe', 'master_preferences', 'new_chrome.exe', 'new_chrome_proxy.exe', 'SetupMetrics' ]) } })) vi.mock('node:fs/promises', () => ({ default: { mkdir: vi.fn().mockResolvedValue({}), access: vi.fn().mockResolvedValue({}), readFile: vi.fn(async () => { const { readFileSync } = await vi.importActual('node:fs') return readFileSync(path.resolve(__dirname, '__fixtures__', 'application.ini')) }) } })) vi.mock('node:child_process', () => ({ default: { execSync: vi.fn(), spawnSync: vi.fn() } })) vi.mock('@puppeteer/browsers', () => ({ Browser: { CHROME: 'chrome', FIREFOX: 'firefox', CHROMIUM: 'chromium' }, ChromeReleaseChannel: { STABLE: 'stable' }, detectBrowserPlatform: vi.fn(), resolveBuildId: vi.fn().mockReturnValue('116.0.5845.110'), canDownload: vi.fn().mockResolvedValue(true), computeExecutablePath: vi.fn().mockReturnValue('/foo/bar/executable'), install: vi.fn().mockResolvedValue({}) })) describe('driver utils', () => { beforeEach(() => { vi.mocked(cp.spawnSync).mockReturnValue({ pid: 123, output: [], stdout: 'Google Chrome 116.0.5845.110 \n', stderr: '', status: 0, signal: null }) }) it('should parse params', () => { expect(parseParams({ baseUrl: 'foobar', silent: true, verbose: false, allowedIps: ['123', '321'] })) .toMatchSnapshot() }) it('getBuildIdByChromePath', () => { expect(getBuildIdByChromePath()).toBe(undefined) expect(getBuildIdByChromePath('/foo/bar')).toBe('116.0.5845.110') expect(cp.spawnSync).toBeCalledWith('/foo/bar', ['--version', '--no-sandbox'], expect.any(Object)) vi.mocked(cp.spawnSync).mockReturnValue({ pid: 123, output: [], stdout: 'Chromium 117.0.5938.88 Fedora Project \n', stderr: '', status: 0, signal: null }) expect(getBuildIdByChromePath('/foo/bar')).toBe('117.0.5938.88') vi.mocked(cp.spawnSync).mockReturnValue({ pid: 123, output: [], stdout: 'Chromium 117.0.5938.92 snap \n', stderr: '', status: 0, signal: null }) expect(getBuildIdByChromePath('/foo/bar')).toBe('117.0.5938.92') vi.mocked(os.platform).mockReturnValueOnce('win32') expect(getBuildIdByChromePath('/foo/bar')).toBe('115.0.5790.110') }) it('getBuildIdByFirefoxPath', async () => { expect(await getBuildIdByFirefoxPath()).toBe(undefined) expect(await getBuildIdByFirefoxPath('/foo/bar')).toBe('116.0.5845.110') vi.mocked(os.platform).mockReturnValueOnce('win32') expect(await getBuildIdByFirefoxPath('/foo/bar')).toBe('116.0.3') }) describe('setupPuppeteerBrowser', () => { beforeEach(() => { vi.mocked(resolveBuildId).mockClear() }) it('should throw if platform is not supported', async () => { vi.mocked(detectBrowserPlatform).mockReturnValueOnce(undefined) await expect(setupPuppeteerBrowser('/foo/bar', { browserName: 'chrome' })).rejects.toThrow('The current platform is not supported.') }) it('should run setup for local chrome if browser version is omitted', async () => { vi.mocked(detectBrowserPlatform).mockReturnValueOnce('mac' as any) await expect(setupPuppeteerBrowser('/foo/bar', {})).resolves.toEqual({ browserVersion: '116.0.5845.110', executablePath: '/path/to/chrome' }) }) it('should do nothing if browser binary is defined within caps', async () => { await expect(setupPuppeteerBrowser('/foo/bar', { 'goog:chromeOptions': { binary: '/my/chrome' } })).resolves.toEqual({ browserVersion: '116.0.5845.110', executablePath: '/my/chrome' }) await expect(setupPuppeteerBrowser('/foo/bar', { browserVersion: '1.2.3', 'goog:chromeOptions': { binary: '/my/chrome' } })).resolves.toEqual({ browserVersion: '1.2.3', executablePath: '/my/chrome' }) }) it('should install chrome stable if browser is not found', async () => { vi.mocked(detectBrowserPlatform).mockReturnValueOnce('windows' as any) vi.mocked(locateChrome).mockResolvedValue('/path/to/stable') await expect(setupPuppeteerBrowser('/foo/bar', {})).resolves.toEqual({ browserVersion: '116.0.5845.110', executablePath: '/path/to/stable' }) expect(resolveBuildId).toBeCalledTimes(0) }) it('should look for Chromium browser if defined as browser name', async () => { vi.mocked(detectBrowserPlatform).mockReturnValueOnce('windows' as any) vi.mocked(locateApp).mockResolvedValue('') const caps = { browserName: 'chromium' } await expect(setupPuppeteerBrowser('/foo/bar', caps)).resolves.toEqual( { browserVersion: '116.0.5845.110', executablePath: '/foo/bar/executable' }) expect(caps.browserName).toBe('chrome') expect(resolveBuildId).toBeCalledTimes(2) expect(resolveBuildId).toBeCalledWith('chromium', 'windows', 'latest') expect(resolveBuildId).toBeCalledWith('chrome', 'windows', 'latest') }) it('should throw if browser version is not found', async () => { vi.mocked(detectBrowserPlatform).mockReturnValueOnce('windows' as any) vi.mocked(canDownload).mockResolvedValueOnce(false) vi.mocked(locateChrome).mockRejectedValueOnce(new Error('not found')) await expect(setupPuppeteerBrowser('/foo/bar', { browserName: 'chrome' })) .rejects.toThrow(/Couldn't find a matching chrome browser/) }) it('should install chrome browser with specific version provided', async () => { vi.mocked(detectBrowserPlatform).mockReturnValueOnce('windows' as any) await expect(setupPuppeteerBrowser('/foo/bar', { browserVersion: '1.2.3' })).resolves.toEqual({ browserVersion: '116.0.5845.110', executablePath: '/foo/bar/executable', }) expect(resolveBuildId).toBeCalledWith('chrome', 'windows', '1.2.3') }) }) }) describe('utils:canAccess', () => { it('canAccess', () => { expect(canAccess('/foobar')).toBe(true) expect(fs.accessSync).toBeCalledWith('/foobar') // @ts-ignore fs.accessSync.mockImplementation(() => { throw new Error('upps') }) expect(canAccess('/foobar')).toBe(false) }) })