webdriverio/packages/create-wdio/tests/index.test.ts
mato533 3f1e7ef93a
feat: integrate the create-wdio package (#14618)
* chore: create sub-package of `create-wdio`

* docs: copy and adjustment for changing repository

* chore: copy a code of create-wdio

* chore: update compiler plugin

* chore: adjust npm script

* chore(wdio-cli): delete the code copied to `create-wdio`

* chore: remove compiler plugin for @wdio/cli

* docs: update root readme

* chore: update package.json

* style: apply format rule

* fix: remove unnecessary export `installPackages`

* test: remove unnecessary mocking in wdio-cli

---------

Co-authored-by: Christian Bromann <git@bromann.dev>
2025-07-08 16:13:28 -07:00

333 lines
11 KiB
TypeScript

import fs from 'node:fs/promises'
import semver from 'semver'
import { resolve } from 'import-meta-resolve'
import { vi, test, expect, beforeEach, afterEach, describe, it } from 'vitest'
import { Command } from 'commander'
import { execSync } from 'node:child_process'
import { execa } from 'execa'
import { run, createWebdriverIO } from '../src/index.js'
import { runProgram } from '../src/utils.js'
import type { ProgramOpts } from '../src/types.js'
import { getInstallCommand, installPackages } from '../src/install.js'
vi.mock('node:fs/promises', () => ({
default: {
access: vi.fn(),
mkdir: vi.fn(),
writeFile: vi.fn()
}
}))
vi.mock('node:child_process', () => ({
execSync: vi.fn()
}))
vi.mock('import-meta-resolve', () => ({
resolve: vi.fn()
}))
vi.mock('commander')
vi.mock('semver', () => ({
default: {
satisfies: vi.fn().mockReturnValue(true)
}
}))
vi.mock('../src/utils.js', async (importActual) => {
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
const actual = await importActual<typeof import('../src/utils.js')>()
return {
...actual,
runProgram: vi.fn(),
colorItBold: vi.fn((log) => log),
colorIt: vi.fn((log) => log),
getPackageVersion: vi.fn().mockReturnValue('0.1.1'),
shouldUseYarn: vi.fn().mockReturnValue(true)
}
})
const consoleLog = console.log.bind(console)
beforeEach(() => {
console.log = vi.fn()
vi.mocked(runProgram).mockClear()
vi.mocked(resolve).mockImplementation(() => {
throw new Error('foo')
})
vi.mocked(execSync).mockReturnValue(`
├── corepack@0.20.0
├── npm@10.2.0
└── yarn@1.22.19
`)
vi.mocked(fs.access).mockResolvedValue()
})
test('run', async () => {
const op = vi.fn().mockResolvedValue({})
await run(op)
expect(op).toBeCalledTimes(1)
expect(op).toBeCalledWith('foobar')
expect(new Command().arguments).toBeCalledWith('[project-path]')
expect(console.log).toBeCalledTimes(1)
expect(vi.mocked(console.log).mock.calls[0][0]).toContain('oooooooooooo')
expect(vi.mocked(console.log).mock.calls[0][1]).toContain('Next-gen browser and mobile automation')
})
test('does not run if Node.js version is too low', async () => {
const consoleLog = vi.spyOn(console, 'log')
vi.mocked(semver.satisfies).mockReturnValue(false)
const op = vi.fn().mockResolvedValue({})
await run(op)
expect(op).toBeCalledTimes(0)
expect(consoleLog).toBeCalledWith(expect.stringContaining('Please update to Node.js v20 to continue.'))
})
test('createWebdriverIO with Yarn', async () => {
vi.stubEnv('npm_config_user_agent', 'yarn/4.5.0 npm/? node/v20.11.0 darwin arm64')
await createWebdriverIO({ npmTag: 'latest' } as ProgramOpts)
expect(runProgram).toBeCalledWith(
'yarn',
['add', '@wdio/cli@latest'],
expect.any(Object)
)
expect(runProgram).toBeCalledWith(
'yarn',
['exec', 'wdio', 'config', '--npm-tag', 'latest'],
expect.any(Object)
)
expect(runProgram).toBeCalledTimes(2)
expect(fs.mkdir).toBeCalledTimes(0)
expect(fs.writeFile).toBeCalledTimes(0)
})
test('createWebdriverIO with NPM', async () => {
vi.stubEnv('npm_config_user_agent', 'npm/10.2.4 node/v20.11.0 darwin arm64 workspaces/false')
await createWebdriverIO({ npmTag: 'latest' } as ProgramOpts)
expect(runProgram).toBeCalledWith(
'npm',
['install', '@wdio/cli@latest'],
expect.any(Object)
)
expect(runProgram).toBeCalledWith(
'npx',
['wdio', 'config', '--npm-tag', 'latest'],
expect.any(Object)
)
expect(runProgram).toBeCalledTimes(2)
expect(fs.mkdir).toBeCalledTimes(0)
expect(fs.writeFile).toBeCalledTimes(0)
})
test('createWebdriverIO with invalid agent should run npm commands', async () => {
vi.stubEnv('npm_config_user_agent', 'invalid/10.2.4 node/v20.11.0 darwin arm64 workspaces/false')
await createWebdriverIO({ npmTag: 'latest' } as ProgramOpts)
expect(runProgram).toBeCalledWith(
'npm',
['install', '@wdio/cli@latest'],
expect.any(Object)
)
expect(runProgram).toBeCalledWith(
'npx',
['wdio', 'config', '--npm-tag', 'latest'],
expect.any(Object)
)
expect(runProgram).toBeCalledTimes(2)
expect(fs.mkdir).toBeCalledTimes(0)
expect(fs.writeFile).toBeCalledTimes(0)
})
test('createWebdriverIO with no npm user agent should run npm commands', async () => {
vi.stubEnv('npm_config_user_agent', '')
await createWebdriverIO({ npmTag: 'latest' } as ProgramOpts)
expect(runProgram).toBeCalledWith(
'npm',
['install', '@wdio/cli@latest'],
expect.any(Object)
)
expect(runProgram).toBeCalledWith(
'npx',
['wdio', 'config', '--npm-tag', 'latest'],
expect.any(Object)
)
expect(runProgram).toBeCalledTimes(2)
expect(fs.mkdir).toBeCalledTimes(0)
expect(fs.writeFile).toBeCalledTimes(0)
})
test('createWebdriverIO with pnpm', async () => {
vi.stubEnv('npm_config_user_agent', 'pnpm/9.10.0 npm/? node/v20.11.0 darwin arm64')
await createWebdriverIO({ npmTag: 'latest' } as ProgramOpts)
expect(runProgram).toBeCalledWith(
'pnpm',
['add', '@wdio/cli@latest'],
expect.any(Object)
)
expect(runProgram).toBeCalledWith(
'pnpm',
['exec', 'wdio', 'config', '--npm-tag', 'latest'],
expect.any(Object)
)
expect(runProgram).toBeCalledTimes(2)
expect(fs.mkdir).toBeCalledTimes(0)
expect(fs.writeFile).toBeCalledTimes(0)
})
test('createWebdriverIO with bun', async () => {
vi.stubEnv('npm_config_user_agent', 'bun/1.1.27 npm/? node/v22.6.0 darwin arm64')
await createWebdriverIO({ npmTag: 'latest' } as ProgramOpts)
expect(runProgram).toBeCalledWith(
'bun',
['install', '@wdio/cli@latest'],
expect.any(Object)
)
expect(runProgram).toBeCalledWith(
'bunx',
['wdio', 'config', '--npm-tag', 'latest'],
expect.any(Object)
)
expect(runProgram).toBeCalledTimes(2)
expect(fs.mkdir).toBeCalledTimes(0)
expect(fs.writeFile).toBeCalledTimes(0)
})
test('creates a directory if it does not exist', async () => {
vi.stubEnv('npm_config_user_agent', 'npm/10.2.4 node/v20.11.0 darwin arm64 workspaces/false')
await createWebdriverIO({ npmTag: 'latest', dev: true } as ProgramOpts)
expect(runProgram).toBeCalledWith(
'npm',
['install', '--save-dev', '@wdio/cli@latest'],
expect.any(Object)
)
expect(runProgram).toBeCalledWith(
'npx',
['wdio', 'config', '--npm-tag', 'latest'],
expect.any(Object)
)
expect(runProgram).toBeCalledTimes(2)
expect(fs.mkdir).toBeCalledTimes(0)
expect(fs.writeFile).toBeCalledTimes(0)
})
test('does not install the @wdio/cli package when the @wdio/cli package is already installed in the current project', async () => {
vi.stubEnv('npm_config_user_agent', 'npm/10.2.4 node/v20.11.0 darwin arm64 workspaces/false')
vi.mocked(resolve).mockReturnValue('/Users/user/dev/my-monorepo/package.json')
await createWebdriverIO({ npmTag: 'latest' } as ProgramOpts)
expect(runProgram).toBeCalledWith(
'npx',
['wdio', 'config', '--npm-tag', 'latest'],
expect.any(Object)
)
expect(runProgram).toBeCalledTimes(1)
expect(fs.mkdir).toBeCalledTimes(0)
expect(fs.writeFile).toBeCalledTimes(0)
})
test('does not install the @wdio/cli package when the @wdio/cli package is already installed globally', async () => {
vi.stubEnv('npm_config_user_agent', 'npm/10.2.4 node/v20.11.0 darwin arm64 workspaces/false')
vi.mocked(execSync).mockReturnValue(`
├── @wdio/cli@8.24.3
├── corepack@0.20.0
├── npm@10.2.0
└── yarn@1.22.19
`)
await createWebdriverIO({ npmTag: 'latest' } as ProgramOpts)
expect(runProgram).toBeCalledWith(
'npx',
['wdio', 'config', '--npm-tag', 'latest'],
expect.any(Object)
)
expect(runProgram).toBeCalledTimes(1)
expect(fs.mkdir).toBeCalledTimes(0)
expect(fs.writeFile).toBeCalledTimes(0)
})
test('runs the wdio config command with --yes when the yes option is set to true', async () => {
vi.stubEnv('npm_config_user_agent', 'npm/10.2.4 node/v20.11.0 darwin arm64 workspaces/false')
await createWebdriverIO({ npmTag: 'latest', yes: true } as ProgramOpts)
expect(runProgram).toBeCalledWith(
'npm',
['install', '@wdio/cli@latest'],
expect.any(Object)
)
expect(runProgram).toBeCalledWith(
'npx',
['wdio', 'config', '--yes', '--npm-tag', 'latest'],
expect.any(Object)
)
expect(runProgram).toBeCalledTimes(2)
expect(fs.mkdir).toBeCalledTimes(0)
expect(fs.writeFile).toBeCalledTimes(0)
})
test('does create a package.json to be used by the wdio config command when one does not exist', async () => {
vi.stubEnv('npm_config_user_agent', 'npm/10.2.4 node/v20.11.0 darwin arm64 workspaces/false')
vi.mocked(fs.access).mockRejectedValue(new Error('not existing'))
await createWebdriverIO({ npmTag: 'next' } as ProgramOpts)
expect(runProgram).toBeCalledWith(
'npm',
['install', '@wdio/cli@next'],
expect.any(Object)
)
expect(runProgram).toBeCalledWith(
'npx',
['wdio', 'config', '--npm-tag', 'next'],
expect.any(Object)
)
expect(runProgram).toBeCalledTimes(2)
expect(fs.mkdir).toBeCalledTimes(1)
expect(fs.writeFile).toBeCalledTimes(1)
expect(fs.writeFile).toBeCalledWith(
expect.any(String),
JSON.stringify({ name: 'someProjectName', type: 'module' }, null, 2),
)
})
test('installs the next version when the npmTag option is set to "next"', async () => {
vi.stubEnv('npm_config_user_agent', 'npm/10.2.4 node/v20.11.0 darwin arm64 workspaces/false')
await createWebdriverIO({ npmTag: 'next' } as ProgramOpts)
expect(runProgram).toBeCalledWith(
'npm',
['install', '@wdio/cli@next'],
expect.any(Object)
)
expect(runProgram).toBeCalledWith(
'npx',
['wdio', 'config', '--npm-tag', 'next'],
expect.any(Object)
)
expect(runProgram).toBeCalledTimes(2)
expect(fs.mkdir).toBeCalledTimes(0)
expect(fs.writeFile).toBeCalledTimes(0)
})
afterEach(() => {
vi.mocked(fs.access).mockClear()
vi.mocked(fs.mkdir).mockClear()
vi.mocked(fs.writeFile).mockClear()
vi.mocked(runProgram).mockClear()
vi.mocked(resolve).mockClear()
vi.mocked(execSync).mockClear()
console.log = consoleLog
})
vi.mock('execa', () => ({
execa: vi.fn().mockResolvedValue({ stdout: 'foo', stderr: 'bar', exitCode: 0 })
}))
vi.mock('detect', () => ({
detect: vi.fn().mockResolvedValue('pnpm')
}))
describe('install', () => {
it('installPackages passing', async () => {
expect(await installPackages('/foo/bar', ['foo', 'bar'], true))
.toBe(true)
})
it('installPackages failing', async () => {
vi.mocked(execa).mockResolvedValue({ stdout: 'foo', stderr: 'bar', exitCode: 1 } as any)
expect(await installPackages('/foo/bar', ['foo', 'bar'], false))
.toBe(false)
})
it('getInstallCommand', () => {
expect(getInstallCommand('pnpm', ['foo', 'bar'], true))
.toBe('pnpm add foo bar --save-dev')
})
})