Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.

Commit b53252c

Browse files
authored
fix: improve package manager detection (#804)
* chore: formating index.ts * feat: improve package manager detection
1 parent b0c8605 commit b53252c

2 files changed

Lines changed: 65 additions & 20 deletions

File tree

src/index.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ import { resolve } from 'import-meta-resolve'
1111
import { runProgram, getPackageVersion } from './utils.js'
1212
import {
1313
ASCII_ROBOT, PROGRAM_TITLE, UNSUPPORTED_NODE_VERSION, DEFAULT_NPM_TAG,
14-
INSTALL_COMMAND, DEV_FLAG, PMs, EXECUTER,EXECUTE_COMMAND
14+
INSTALL_COMMAND, DEV_FLAG, PMs, EXECUTER, EXECUTE_COMMAND
1515
} from './constants.js'
1616
import type { ProgramOpts } from './types'
1717

1818
const WDIO_COMMAND = 'wdio'
1919
let projectDir: string | undefined
2020

21-
export async function run (operation = createWebdriverIO) {
21+
export async function run(operation = createWebdriverIO) {
2222
const version = await getPackageVersion()
2323

2424
/**
@@ -54,21 +54,30 @@ export async function run (operation = createWebdriverIO) {
5454
return operation(program.opts())
5555
}
5656

57+
/**
58+
* detects the package manager that was used
59+
* uses the environment variable `npm_config_user_agent` to detect the package manager
60+
* falls back to `npm` if no package manager could be detected
61+
*/
62+
function detectPackageManager() {
63+
if (!process.env.npm_config_user_agent) {
64+
return 'npm'
65+
}
66+
const detectedPM = process.env.npm_config_user_agent.split('/')[0].toLowerCase()
67+
68+
const matchedPM = PMs.find(pm => pm.toLowerCase() === detectedPM)
69+
70+
return matchedPM || 'npm'
71+
}
72+
5773
export async function createWebdriverIO(opts: ProgramOpts) {
5874
const npmTag = opts.npmTag.startsWith('@') ? opts.npmTag : `@${opts.npmTag}`
5975
const root = path.resolve(process.cwd(), projectDir || '')
6076

6177
/**
6278
* find package manager that was used to create project
6379
*/
64-
const pm = PMs.find((pm) => (
65-
// for pnpm check "~/Library/pnpm/store/v3/..."
66-
// for NPM check "~/.npm/npx/..."
67-
// for Yarn check "~/.yarn/bin/create-wdio"
68-
// for Bun check "~/.bun/bin/create-wdio"
69-
process.argv[1].includes(`${path.sep}${pm}${path.sep}`) ||
70-
process.argv[1].includes(`${path.sep}.${pm}${path.sep}`)
71-
)) || 'npm'
80+
const pm = detectPackageManager()
7281

7382
const hasPackageJson = await fs.access(path.resolve(root, 'package.json')).then(() => true).catch(() => false)
7483
if (!hasPackageJson) {

tests/index.test.ts

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ test('does not run if Node.js version is too low', async () => {
7171
})
7272

7373
test('createWebdriverIO with Yarn', async () => {
74-
process.argv = ['', '~/.yarn/bin/create-wdio']
74+
vi.stubEnv('npm_config_user_agent', 'yarn/4.5.0 npm/? node/v20.11.0 darwin arm64')
7575
await createWebdriverIO({ npmTag: 'latest' } as ProgramOpts)
7676
expect(runProgram).toBeCalledWith(
7777
'yarn',
@@ -89,7 +89,43 @@ test('createWebdriverIO with Yarn', async () => {
8989
})
9090

9191
test('createWebdriverIO with NPM', async () => {
92-
process.argv = ['', '~/.npm/npx/...']
92+
vi.stubEnv('npm_config_user_agent', 'npm/10.2.4 node/v20.11.0 darwin arm64 workspaces/false')
93+
await createWebdriverIO({ npmTag: 'latest' } as ProgramOpts)
94+
expect(runProgram).toBeCalledWith(
95+
'npm',
96+
['install', '@wdio/cli@latest'],
97+
expect.any(Object)
98+
)
99+
expect(runProgram).toBeCalledWith(
100+
'npx',
101+
['wdio', 'config', '--npm-tag', 'latest'],
102+
expect.any(Object)
103+
)
104+
expect(runProgram).toBeCalledTimes(2)
105+
expect(fs.mkdir).toBeCalledTimes(0)
106+
expect(fs.writeFile).toBeCalledTimes(0)
107+
})
108+
109+
test('createWebdriverIO with invalid agent should run npm commands', async () => {
110+
vi.stubEnv('npm_config_user_agent', 'invalid/10.2.4 node/v20.11.0 darwin arm64 workspaces/false')
111+
await createWebdriverIO({ npmTag: 'latest' } as ProgramOpts)
112+
expect(runProgram).toBeCalledWith(
113+
'npm',
114+
['install', '@wdio/cli@latest'],
115+
expect.any(Object)
116+
)
117+
expect(runProgram).toBeCalledWith(
118+
'npx',
119+
['wdio', 'config', '--npm-tag', 'latest'],
120+
expect.any(Object)
121+
)
122+
expect(runProgram).toBeCalledTimes(2)
123+
expect(fs.mkdir).toBeCalledTimes(0)
124+
expect(fs.writeFile).toBeCalledTimes(0)
125+
})
126+
127+
test('createWebdriverIO with no npm user agent should run npm commands', async () => {
128+
vi.stubEnv('npm_config_user_agent', undefined)
93129
await createWebdriverIO({ npmTag: 'latest' } as ProgramOpts)
94130
expect(runProgram).toBeCalledWith(
95131
'npm',
@@ -107,7 +143,7 @@ test('createWebdriverIO with NPM', async () => {
107143
})
108144

109145
test('createWebdriverIO with pnpm', async () => {
110-
process.argv = ['', '~/Library/pnpm/store/v3/...']
146+
vi.stubEnv('npm_config_user_agent', 'pnpm/9.10.0 npm/? node/v20.11.0 darwin arm64')
111147
await createWebdriverIO({ npmTag: 'latest' } as ProgramOpts)
112148
expect(runProgram).toBeCalledWith(
113149
'pnpm',
@@ -125,7 +161,7 @@ test('createWebdriverIO with pnpm', async () => {
125161
})
126162

127163
test('createWebdriverIO with bun', async () => {
128-
process.argv = ['', '~/.bun/bin/create-wdio']
164+
vi.stubEnv('npm_config_user_agent', 'bun/1.1.27 npm/? node/v22.6.0 darwin arm64')
129165
await createWebdriverIO({ npmTag: 'latest' } as ProgramOpts)
130166
expect(runProgram).toBeCalledWith(
131167
'bun',
@@ -143,7 +179,7 @@ test('createWebdriverIO with bun', async () => {
143179
})
144180

145181
test('creates a directory if it does not exist', async () => {
146-
process.argv = ['', '~/.npm/npx/...']
182+
vi.stubEnv('npm_config_user_agent', 'npm/10.2.4 node/v20.11.0 darwin arm64 workspaces/false')
147183
await createWebdriverIO({ npmTag: 'latest', dev: true } as ProgramOpts)
148184
expect(runProgram).toBeCalledWith(
149185
'npm',
@@ -161,7 +197,7 @@ test('creates a directory if it does not exist', async () => {
161197
})
162198

163199
test('does not install the @wdio/cli package when the @wdio/cli package is already installed in the current project', async () => {
164-
process.argv = ['', '~/.npm/npx/...']
200+
vi.stubEnv('npm_config_user_agent', 'npm/10.2.4 node/v20.11.0 darwin arm64 workspaces/false')
165201
vi.mocked(resolve).mockReturnValue('/Users/user/dev/my-monorepo/package.json')
166202
await createWebdriverIO({ npmTag: 'latest' } as ProgramOpts)
167203
expect(runProgram).toBeCalledWith(
@@ -175,7 +211,7 @@ test('does not install the @wdio/cli package when the @wdio/cli package is alrea
175211
})
176212

177213
test('does not install the @wdio/cli package when the @wdio/cli package is already installed globally', async () => {
178-
process.argv = ['', '~/.npm/npx/...']
214+
vi.stubEnv('npm_config_user_agent', 'npm/10.2.4 node/v20.11.0 darwin arm64 workspaces/false')
179215
vi.mocked(execSync).mockReturnValue(`
180216
├── @wdio/[email protected]
181217
@@ -194,7 +230,7 @@ test('does not install the @wdio/cli package when the @wdio/cli package is alrea
194230
})
195231

196232
test('runs the wdio config command with --yes when the yes option is set to true', async () => {
197-
process.argv = ['', '~/.npm/npx/...']
233+
vi.stubEnv('npm_config_user_agent', 'npm/10.2.4 node/v20.11.0 darwin arm64 workspaces/false')
198234
await createWebdriverIO({ npmTag: 'latest', yes: true } as ProgramOpts)
199235
expect(runProgram).toBeCalledWith(
200236
'npm',
@@ -212,7 +248,7 @@ test('runs the wdio config command with --yes when the yes option is set to true
212248
})
213249

214250
test('does create a package.json to be used by the wdio config command when one does not exist', async () => {
215-
process.argv = ['', '~/.npm/npx/...']
251+
vi.stubEnv('npm_config_user_agent', 'npm/10.2.4 node/v20.11.0 darwin arm64 workspaces/false')
216252
vi.mocked(fs.access).mockRejectedValue(new Error('not existing'))
217253
await createWebdriverIO({ npmTag: 'next' } as ProgramOpts)
218254
expect(runProgram).toBeCalledWith(
@@ -235,7 +271,7 @@ test('does create a package.json to be used by the wdio config command when one
235271
})
236272

237273
test('installs the next version when the npmTag option is set to "next"', async () => {
238-
process.argv = ['', '~/.npm/npx/...']
274+
vi.stubEnv('npm_config_user_agent', 'npm/10.2.4 node/v20.11.0 darwin arm64 workspaces/false')
239275
await createWebdriverIO({ npmTag: 'next' } as ProgramOpts)
240276
expect(runProgram).toBeCalledWith(
241277
'npm',

0 commit comments

Comments
 (0)