import fs from 'node:fs/promises'
import { vi, describe, it, expect, afterEach, beforeEach } from 'vitest'
import { yargs } from 'yargs'
import * as installCmd from '../../src/cli/install.js'
import * as configCmd from '../../src/cli/config.js'
import * as utils from '../../src/utils.js'
import { installPackages } from '../../src/install.js'
vi.mock('yargs')
vi.mock('node:fs/promises', async (orig) => ({
...(await orig()) as any,
default: {
access: vi.fn().mockResolvedValue({}),
readFile: vi.fn().mockResolvedValue('export const config = {}'),
writeFile: vi.fn().mockResolvedValue({})
}
}))
vi.mock('../../src/install', () => ({
installPackages: vi.fn(),
getInstallCommand: vi.fn().mockReturnValue('npm install foo bar --save-dev')
}))
vi.mock('../../src/utils', async (origMod) => {
const orig: any = await origMod()
return {
...orig,
detectPackageManager: vi.fn().mockReturnValue('npm'),
}
})
const findInConfigMock = vi.spyOn(utils, 'findInConfig')
describe('Command: install', () => {
beforeEach(() => {
vi.spyOn(console, 'log')
vi.spyOn(process, 'exit').mockImplementation(((code?: number): never => code as never) as any)
vi.spyOn(configCmd, 'missingConfigurationPrompt').mockImplementation(() => Promise.resolve() as any)
vi.spyOn(utils, 'addServiceDeps')
vi.spyOn(utils, 'replaceConfig').mockReturnValueOnce({ foo: 123 } as any)
})
it('it should properly build command', () => {
installCmd.builder(yargs)
expect(yargs.options).toHaveBeenCalled()
expect(yargs.example).toHaveBeenCalled()
expect(yargs.epilogue).toHaveBeenCalled()
expect(yargs.help).toHaveBeenCalled()
})
it('should log out when an unknown installation type is passed', async () => {
await installCmd.handler({ type: 'foobar', config: './wdio.conf.js' } as any)
expect(console.log).toHaveBeenCalled()
expect(console.log).toHaveBeenCalledWith('Type foobar is not supported.')
})
it('should log out when unknown package name is used', async () => {
await installCmd.handler({ type: 'service', name: 'foobar', config: './wdio.conf.js' } as any)
expect(console.log).toHaveBeenCalled()
expect(console.log).toHaveBeenCalledWith(
expect.stringContaining('Error: foobar is not a supported service.')
)
})
it('should prompt missing configuration', async () => {
vi.spyOn(utils, 'formatConfigFilePaths').mockReturnValue({ fullPath: '/absolute/path/to/wdio.conf.js', fullPathNoExtension: '/absolute/path/to/wdio.conf' } as any)
vi.spyOn(configCmd, 'missingConfigurationPrompt').mockImplementation(() => Promise.reject())
vi.mocked(fs.access).mockRejectedValue(new Error('Doesn\'t exist'))
await installCmd.handler({ type: 'service', name: 'vite', config: './wdio.conf.js' } as any)
expect(configCmd.missingConfigurationPrompt).toHaveBeenCalledWith(
'install',
'/absolute/path/to/wdio.conf'
)
})
it('should verify if configuration already has desired installation', async () => {
findInConfigMock.mockReturnValue(['vite'])
vi.mocked(fs.access).mockResolvedValue()
await installCmd.handler({ type: 'service', name: 'vite', config: './wdio.conf.js' } as any)
expect(console.log).toHaveBeenCalledWith('The service vite is already part of your configuration.')
})
it('should correctly install packages', async () => {
findInConfigMock.mockReturnValue([''])
vi.mocked(fs.access).mockResolvedValue()
vi.mocked(fs.readFile).mockResolvedValue('module.config = {}')
vi.mocked(installPackages).mockResolvedValue(true)
await installCmd.handler({ type: 'service', name: 'vite', config: './wdio.conf.js' } as any)
expect(console.log).toHaveBeenCalledWith('Installing "wdio-vite-service" using npm.')
expect(console.log).toHaveBeenCalledWith('Package "wdio-vite-service" installed successfully.')
expect(utils.replaceConfig).toHaveBeenCalled()
expect(fs.writeFile).toHaveBeenCalled()
expect(console.log).toHaveBeenCalledWith('Your wdio.conf.js file has been updated.')
expect(process.exit).toHaveBeenCalledWith(0)
})
it('should fail if config could not be updated', async () => {
findInConfigMock.mockReturnValue([''])
vi.mocked(fs.readFile).mockResolvedValue('module.config = {}')
vi.mocked(installPackages).mockResolvedValue(true)
vi.mocked(utils.replaceConfig).mockRestore()
vi.spyOn(utils, 'replaceConfig').mockReturnValue('')
const err = await installCmd.handler({ type: 'service', name: 'vite', config: './wdio.conf.js' } as any)
.catch((err: Error) => err) as Error
expect(err.message).toBe('Couldn\'t find "service" property in wdio.conf.js')
})
it('allows for custom config location', async () => {
findInConfigMock.mockReturnValue([''])
vi.mocked(fs.access).mockResolvedValue()
vi.mocked(fs.readFile).mockResolvedValue('module.config = {}')
vi.mocked(installPackages).mockResolvedValue(true)
await installCmd.handler({ type: 'service', name: 'vite', config: './path/to/wdio.conf.js' } as any)
expect(console.log).toHaveBeenCalledWith('Installing "wdio-vite-service" using npm.')
expect(console.log).toHaveBeenCalledWith('Package "wdio-vite-service" installed successfully.')
expect(utils.replaceConfig).toHaveBeenCalled()
expect(fs.writeFile).toHaveBeenCalled()
expect(console.log).toHaveBeenCalledWith('Your wdio.conf.js file has been updated.')
expect(process.exit).toHaveBeenCalledWith(0)
})
it('should exit if there is an error while installing', async () => {
findInConfigMock.mockReturnValue([''])
vi.mocked(fs.access).mockResolvedValue()
vi.mocked(installPackages).mockResolvedValue(false)
await installCmd.handler({ type: 'service', name: 'vite', config: './wdio.conf.js' } as any)
expect(process.exit).toHaveBeenCalledWith(1)
})
afterEach(() => {
vi.mocked(console.log).mockClear()
vi.mocked(process.exit).mockClear()
vi.mocked(fs.readFile).mockClear()
vi.mocked(fs.access).mockClear()
vi.mocked(fs.writeFile).mockClear()
vi.mocked(utils.findInConfig).mockClear()
vi.mocked(utils.addServiceDeps).mockClear()
vi.mocked(utils.replaceConfig).mockClear()
vi.mocked(configCmd.missingConfigurationPrompt).mockClear()
})
})