🏡 index : quine-global/webdriverio.git

import fs from 'node:fs/promises'
import { vi, describe, it, expect, afterEach, beforeEach } from 'vitest'
// @ts-expect-error mock
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()
    })
})