Skip to content

Commit 41aca91

Browse files
committed
chore: convert detect spect to vitest
1 parent 5a62b5e commit 41aca91

File tree

2 files changed

+283
-174
lines changed

2 files changed

+283
-174
lines changed
Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
import { describe, it, expect, beforeEach, vi } from 'vitest'
2+
import _ from 'lodash'
3+
import cp from 'child_process'
4+
import { EventEmitter } from 'stream'
5+
import { detect, detectByPath, getMajorVersion } from '../../lib/detect'
6+
import { goalBrowsers } from '../fixtures'
7+
import os from 'os'
8+
import { log } from '../log'
9+
import { detect as linuxDetect } from '../../lib/linux'
10+
import { detect as darwinDetect } from '../../lib/darwin'
11+
import { detect as windowsDetect } from '../../lib/windows'
12+
import type { Browser } from '@packages/types'
13+
14+
vi.mock('child_process', async (importActual) => {
15+
const actual = await importActual()
16+
17+
return {
18+
default: {
19+
// @ts-expect-error
20+
...actual.default,
21+
spawn: vi.fn(),
22+
},
23+
}
24+
})
25+
26+
vi.mock('../../lib/linux', async (importActual) => {
27+
const actual = await importActual()
28+
29+
return {
30+
// @ts-expect-error
31+
...actual,
32+
detect: vi.fn(),
33+
}
34+
})
35+
36+
vi.mock('../../lib/darwin', async (importActual) => {
37+
const actual = await importActual()
38+
39+
return {
40+
// @ts-expect-error
41+
...actual,
42+
detect: vi.fn(),
43+
}
44+
})
45+
46+
vi.mock('../../lib/windows', async (importActual) => {
47+
const actual = await importActual()
48+
49+
return {
50+
// @ts-expect-error
51+
...actual,
52+
detect: vi.fn(),
53+
}
54+
})
55+
56+
const isWindows = () => {
57+
return os.platform() === 'win32'
58+
}
59+
60+
describe('detect', () => {
61+
beforeEach(async () => {
62+
vi.unstubAllEnvs()
63+
vi.resetAllMocks()
64+
65+
const { detect: linuxDetectActual } = await vi.importActual<typeof import('../../lib/linux')>('../../lib/linux')
66+
const { detect: darwinDetectActual } = await vi.importActual<typeof import('../../lib/darwin')>('../../lib/darwin')
67+
const { detect: windowsDetectActual } = await vi.importActual<typeof import('../../lib/windows')>('../../lib/windows')
68+
69+
vi.mocked(linuxDetect).mockImplementation(linuxDetectActual)
70+
vi.mocked(darwinDetect).mockImplementation(darwinDetectActual)
71+
vi.mocked(windowsDetect).mockImplementation(windowsDetectActual)
72+
})
73+
74+
// making simple to debug tests
75+
// using DEBUG=... flag
76+
77+
// we are only going to run tests on platforms with at least
78+
// one browser. This test, is really E2E because it finds
79+
// real browsers
80+
it('detects available browsers', async () => {
81+
const browsers = await detect()
82+
83+
log('detected browsers %j', browsers)
84+
expect(browsers).toBeInstanceOf(Array)
85+
86+
const mainProps = browsers.map((val) => _.pick(val, ['name', 'version']))
87+
88+
log('%d browsers\n%j', browsers.length, mainProps)
89+
90+
if (isWindows()) {
91+
// we might not find any browsers on Windows CI
92+
expect(browsers.length).toBeGreaterThanOrEqual(0)
93+
} else {
94+
expect(browsers.length).toBeGreaterThan(0)
95+
}
96+
})
97+
98+
describe('#getMajorVersion', () => {
99+
it('parses major version from provided string', () => {
100+
expect(getMajorVersion('123.45.67')).toEqual('123')
101+
expect(getMajorVersion('Browser 77.1.0')).to.eq('Browser 77')
102+
expect(getMajorVersion('999')).toEqual('999')
103+
})
104+
})
105+
106+
describe('#detect', () => {
107+
const testBrowser = {
108+
name: 'test-browser',
109+
family: 'chromium',
110+
channel: 'test-channel',
111+
displayName: 'Test Browser',
112+
versionRegex: /Test Browser (\S+)/m,
113+
binary: 'test-browser-beta',
114+
}
115+
116+
it('validates browser with own validator property', async () => {
117+
// @ts-expect-error
118+
vi.mocked(linuxDetect).mockImplementation((browser) => {
119+
return Promise.resolve({
120+
name: browser.name,
121+
path: '/path/to/test-browser',
122+
version: '130',
123+
})
124+
})
125+
126+
vi.mocked(darwinDetect).mockImplementation((browser) => {
127+
return Promise.resolve({
128+
name: browser.name,
129+
path: '/path/to/test-browser',
130+
version: '130',
131+
})
132+
})
133+
134+
// @ts-expect-error
135+
vi.mocked(windowsDetect).mockImplementation((browser) => {
136+
return Promise.resolve({
137+
name: browser.name,
138+
path: '/path/to/test-browser',
139+
version: '130',
140+
})
141+
})
142+
143+
const mockValidator = vi.fn().mockReturnValue({ isSupported: true })
144+
145+
const foundBrowsers = await detect([{ ...testBrowser as Browser, validator: mockValidator }])
146+
147+
expect(foundBrowsers).toHaveLength(1)
148+
149+
const foundTestBrowser = foundBrowsers[0]
150+
151+
expect(foundTestBrowser.name).toEqual('test-browser')
152+
expect(foundTestBrowser.displayName).toEqual('Test Browser')
153+
expect(foundTestBrowser.majorVersion, 'majorVersion').toEqual('130')
154+
expect(foundTestBrowser.unsupportedVersion, 'unsupportedVersion').toBeUndefined()
155+
expect(foundTestBrowser.warning, 'warning').toBeUndefined()
156+
expect(mockValidator).toHaveBeenCalled()
157+
})
158+
})
159+
160+
describe('#detectByPath', () => {
161+
let cpSpawnCallback: (cmd: string, args: readonly string[], opts, cp: cp.ChildProcess) => void
162+
163+
beforeEach(() => {
164+
vi.unstubAllEnvs()
165+
vi.resetAllMocks()
166+
167+
vi.mocked(cp.spawn).mockImplementation((cmd, args, opts) => {
168+
const cpSpawnMock = {
169+
on: vi.fn(),
170+
stdout: new EventEmitter(),
171+
stderr: new EventEmitter(),
172+
kill: vi.fn(),
173+
}
174+
175+
cpSpawnMock.on.mockImplementation((event: string, callback: (...args: any[]) => void) => {
176+
if (event === 'exit') {
177+
setTimeout(() => callback(), 0)
178+
}
179+
180+
if (event === 'close') {
181+
setTimeout(() => callback(), 0)
182+
}
183+
})
184+
185+
cpSpawnCallback(cmd, args, opts, cpSpawnMock as unknown as cp.ChildProcess)
186+
187+
return cpSpawnMock as unknown as cp.ChildProcess
188+
})
189+
190+
cpSpawnCallback = (cmd, args, opts, cpSpawnMock) => {
191+
// FIXME: these tests really should be reworked to run the same regardless of OS/CPU architecture
192+
const command = os.arch() === 'arm64' ? args[0] : cmd
193+
194+
if (command === '/Applications/My Shiny New Browser.app') {
195+
setTimeout(() => {
196+
cpSpawnMock.stdout.emit('data', 'foo-browser v100.1.2.3')
197+
}, 0)
198+
199+
return
200+
}
201+
202+
if (command === '/foo/bar/browser') {
203+
setTimeout(() => {
204+
cpSpawnMock.stdout.emit('data', 'foo-browser v9001.1.2.3')
205+
}, 0)
206+
207+
return
208+
}
209+
210+
if (command === '/not/a/browser') {
211+
setTimeout(() => {
212+
cpSpawnMock.stdout.emit('data', 'not a browser version string')
213+
}, 0)
214+
215+
return
216+
}
217+
218+
if (command === '/not/a/real/path') {
219+
setTimeout(() => {
220+
cpSpawnMock.stdout.emit('data', '')
221+
}, 0)
222+
223+
return
224+
}
225+
}
226+
})
227+
228+
it('detects by path', async () => {
229+
// @ts-expect-error
230+
const foundBrowser = await detectByPath('/foo/bar/browser', goalBrowsers)
231+
232+
const expectedBrowser = goalBrowsers.find(({ name }) => name === 'foo-browser')
233+
234+
expect(foundBrowser).toEqual({
235+
...expectedBrowser,
236+
displayName: 'Custom Foo Browser',
237+
info: 'Loaded from /foo/bar/browser',
238+
custom: true,
239+
version: '9001.1.2.3',
240+
majorVersion: '9001',
241+
path: '/foo/bar/browser',
242+
})
243+
})
244+
245+
it('rejects when there was no matching versionRegex', () => {
246+
// @ts-ignore
247+
return detectByPath('/not/a/browser', goalBrowsers)
248+
.then(() => {
249+
throw Error('Should not find a browser')
250+
})
251+
.catch((err) => {
252+
expect(err.notDetectedAtPath).to.be.true
253+
})
254+
})
255+
256+
it('rejects when there was an error executing the command', async () => {
257+
try {
258+
// @ts-expect-error
259+
await detectByPath('/not/a/real/path', goalBrowsers)
260+
throw Error('Should not find a browser')
261+
} catch (err) {
262+
expect(err.notDetectedAtPath).toBe(true)
263+
}
264+
})
265+
266+
it('works with spaces in the path', async () => {
267+
// @ts-expect-error
268+
const foundBrowser = await detectByPath('/Applications/My Shiny New Browser.app', goalBrowsers)
269+
270+
const expectedBrowser = goalBrowsers.find(({ name }) => name === 'foo-browser')
271+
272+
expect(foundBrowser).toEqual({
273+
...expectedBrowser,
274+
displayName: 'Custom Foo Browser',
275+
info: 'Loaded from /Applications/My Shiny New Browser.app',
276+
custom: true,
277+
version: '100.1.2.3',
278+
majorVersion: '100',
279+
path: '/Applications/My Shiny New Browser.app',
280+
})
281+
})
282+
})
283+
})

0 commit comments

Comments
 (0)