/ bin / install-root.test.js
install-root.test.js
  1  'use strict'
  2  /* eslint-disable @typescript-eslint/no-require-imports */
  3  
  4  const test = require('node:test')
  5  const assert = require('node:assert/strict')
  6  const fs = require('node:fs')
  7  const os = require('node:os')
  8  const path = require('node:path')
  9  
 10  const {
 11    candidateDirsFromArgv1,
 12    detectGlobalInstallManagerForRoot,
 13    findLocalInstallProjectRoot,
 14    resolvePackageRoot,
 15    resolveStateHome,
 16  } = require('./install-root.js')
 17  
 18  test('candidateDirsFromArgv1 includes the package directory for node_modules/.bin launchers', () => {
 19    const launcher = path.join('/tmp', 'example', 'node_modules', '.bin', 'swarmclaw')
 20    const candidates = candidateDirsFromArgv1(launcher)
 21    assert.deepEqual(candidates, [
 22      path.join('/tmp', 'example', 'node_modules', '.bin'),
 23      path.join('/tmp', 'example', 'node_modules', 'swarmclaw'),
 24    ])
 25  })
 26  
 27  test('resolvePackageRoot finds the package root from argv1 candidates', () => {
 28    const rootDir = fs.mkdtempSync(path.join(os.tmpdir(), 'swarmclaw-install-root-'))
 29    const pkgRoot = path.join(rootDir, 'node_modules', '@swarmclawai', 'swarmclaw')
 30    const binPath = path.join(rootDir, 'node_modules', '.bin', 'swarmclaw')
 31    const actualBin = path.join(pkgRoot, 'bin', 'swarmclaw.js')
 32  
 33    fs.mkdirSync(path.join(pkgRoot, 'bin'), { recursive: true })
 34    fs.mkdirSync(path.dirname(binPath), { recursive: true })
 35    fs.writeFileSync(path.join(pkgRoot, 'package.json'), JSON.stringify({ name: '@swarmclawai/swarmclaw' }), 'utf8')
 36    fs.writeFileSync(actualBin, '#!/usr/bin/env node\n', 'utf8')
 37    fs.symlinkSync(actualBin, binPath)
 38  
 39    assert.equal(resolvePackageRoot({ argv1: binPath, cwd: rootDir }), fs.realpathSync(pkgRoot))
 40  
 41    fs.rmSync(rootDir, { recursive: true, force: true })
 42  })
 43  
 44  test('detectGlobalInstallManagerForRoot matches the owning global root by realpath', () => {
 45    const rootDir = fs.mkdtempSync(path.join(os.tmpdir(), 'swarmclaw-global-root-'))
 46    const npmGlobalRoot = path.join(rootDir, 'npm-global')
 47    const pnpmGlobalRoot = path.join(rootDir, 'pnpm-global')
 48    const pkgRoot = path.join(pnpmGlobalRoot, '@swarmclawai', 'swarmclaw')
 49  
 50    fs.mkdirSync(path.join(npmGlobalRoot, '@swarmclawai'), { recursive: true })
 51    fs.mkdirSync(path.join(pnpmGlobalRoot, '@swarmclawai'), { recursive: true })
 52    fs.mkdirSync(pkgRoot, { recursive: true })
 53  
 54    const execImpl = (command, args) => {
 55      if (command === 'npm' && args.join(' ') === 'root -g') return npmGlobalRoot
 56      if (command === 'pnpm' && args.join(' ') === 'root -g') return pnpmGlobalRoot
 57      throw new Error(`unexpected command: ${command} ${args.join(' ')}`)
 58    }
 59  
 60    assert.equal(detectGlobalInstallManagerForRoot(pkgRoot, execImpl), 'pnpm')
 61  
 62    fs.rmSync(rootDir, { recursive: true, force: true })
 63  })
 64  
 65  test('findLocalInstallProjectRoot returns the project root for nested pnpm installs', () => {
 66    const pkgRoot = path.join(
 67      '/tmp',
 68      'example',
 69      'node_modules',
 70      '.pnpm',
 71      '@swarmclawai+swarmclaw@1.0.1',
 72      'node_modules',
 73      '@swarmclawai',
 74      'swarmclaw',
 75    )
 76  
 77    assert.equal(findLocalInstallProjectRoot(pkgRoot), path.join('/tmp', 'example'))
 78  })
 79  
 80  test('resolveStateHome prefers the local project .swarmclaw directory for local installs', () => {
 81    const projectRoot = path.join('/tmp', 'example')
 82    const pkgRoot = path.join(projectRoot, 'node_modules', '@swarmclawai', 'swarmclaw')
 83    const execImpl = () => {
 84      throw new Error('unexpected global root lookup')
 85    }
 86  
 87    assert.equal(
 88      resolveStateHome({
 89        pkgRoot,
 90        env: {},
 91        execImpl,
 92      }),
 93      path.join(projectRoot, '.swarmclaw'),
 94    )
 95  })
 96  
 97  test('resolveStateHome keeps global installs under the user home directory', () => {
 98    const rootDir = fs.mkdtempSync(path.join(os.tmpdir(), 'swarmclaw-state-home-'))
 99    const npmGlobalRoot = path.join(rootDir, 'npm-global')
100    const pkgRoot = path.join(npmGlobalRoot, '@swarmclawai', 'swarmclaw')
101  
102    fs.mkdirSync(path.join(npmGlobalRoot, '@swarmclawai'), { recursive: true })
103    fs.mkdirSync(pkgRoot, { recursive: true })
104  
105    const execImpl = (command, args) => {
106      if (command === 'npm' && args.join(' ') === 'root -g') return npmGlobalRoot
107      if (command === 'pnpm' && args.join(' ') === 'root -g') return path.join(rootDir, 'pnpm-global')
108      throw new Error(`unexpected command: ${command} ${args.join(' ')}`)
109    }
110  
111    assert.equal(
112      resolveStateHome({
113        pkgRoot,
114        env: {},
115        execImpl,
116      }),
117      path.join(os.homedir(), '.swarmclaw'),
118    )
119  
120    fs.rmSync(rootDir, { recursive: true, force: true })
121  })