[READ-ONLY] a fast, modern browser for the npm registry
at main 320 lines 9.7 kB view raw
1import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' 2import type { JsrPackageInfo } from '#shared/types/jsr' 3 4describe('useInstallCommand', () => { 5 beforeEach(() => { 6 // Reset localStorage and package manager state before each test 7 localStorage.clear() 8 // Reset the shared composable state to default 'npm' 9 const pm = useSelectedPackageManager() 10 pm.value = 'npm' 11 }) 12 13 afterEach(() => { 14 vi.unstubAllGlobals() 15 }) 16 17 describe('basic install commands', () => { 18 it('should generate npm install command by default', () => { 19 const { installCommand, installCommandParts, selectedPM } = useInstallCommand( 20 'vue', 21 null, 22 null, 23 null, 24 ) 25 26 expect(selectedPM.value).toBe('npm') 27 expect(installCommand.value).toBe('npm install vue') 28 expect(installCommandParts.value).toEqual(['npm', 'install', 'vue']) 29 }) 30 31 it('should include version when specified', () => { 32 const { installCommand, installCommandParts } = useInstallCommand('vue', '3.5.0', null, null) 33 34 expect(installCommand.value).toBe('npm install vue@3.5.0') 35 expect(installCommandParts.value).toEqual(['npm', 'install', 'vue@3.5.0']) 36 }) 37 38 it('should handle scoped packages', () => { 39 const { installCommand, installCommandParts } = useInstallCommand( 40 '@nuxt/kit', 41 null, 42 null, 43 null, 44 ) 45 46 expect(installCommand.value).toBe('npm install @nuxt/kit') 47 expect(installCommandParts.value).toEqual(['npm', 'install', '@nuxt/kit']) 48 }) 49 50 it('should handle null packageName', () => { 51 const { installCommand, installCommandParts } = useInstallCommand(null, null, null, null) 52 53 expect(installCommand.value).toBe('') 54 expect(installCommandParts.value).toEqual([]) 55 }) 56 }) 57 58 describe('package manager selection', () => { 59 it('should use pnpm when selected', () => { 60 const { installCommand, installCommandParts, selectedPM } = useInstallCommand( 61 'vue', 62 null, 63 null, 64 null, 65 ) 66 67 selectedPM.value = 'pnpm' 68 expect(installCommand.value).toBe('pnpm add vue') 69 expect(installCommandParts.value).toEqual(['pnpm', 'add', 'vue']) 70 }) 71 72 it('should use yarn when selected', () => { 73 const { installCommand, installCommandParts, selectedPM } = useInstallCommand( 74 'vue', 75 null, 76 null, 77 null, 78 ) 79 80 selectedPM.value = 'yarn' 81 expect(installCommand.value).toBe('yarn add vue') 82 expect(installCommandParts.value).toEqual(['yarn', 'add', 'vue']) 83 }) 84 85 it('should use bun when selected', () => { 86 const { installCommand, installCommandParts, selectedPM } = useInstallCommand( 87 'vue', 88 null, 89 null, 90 null, 91 ) 92 93 selectedPM.value = 'bun' 94 expect(installCommand.value).toBe('bun add vue') 95 expect(installCommandParts.value).toEqual(['bun', 'add', 'vue']) 96 }) 97 98 it('should use deno with npm: prefix when selected', () => { 99 const { installCommand, installCommandParts, selectedPM } = useInstallCommand( 100 'vue', 101 null, 102 null, 103 null, 104 ) 105 106 selectedPM.value = 'deno' 107 expect(installCommand.value).toBe('deno add npm:vue') 108 expect(installCommandParts.value).toEqual(['deno', 'add', 'npm:vue']) 109 }) 110 111 it('should use vlt when selected', () => { 112 const { installCommand, installCommandParts, selectedPM } = useInstallCommand( 113 'vue', 114 null, 115 null, 116 null, 117 ) 118 119 selectedPM.value = 'vlt' 120 expect(installCommand.value).toBe('vlt install vue') 121 expect(installCommandParts.value).toEqual(['vlt', 'install', 'vue']) 122 }) 123 }) 124 125 describe('deno with JSR', () => { 126 it('should use jsr: prefix when package exists on JSR', () => { 127 const jsrInfo: JsrPackageInfo = { 128 exists: true, 129 scope: 'std', 130 name: 'path', 131 url: 'https://jsr.io/@std/path', 132 } 133 134 const { installCommand, installCommandParts, selectedPM } = useInstallCommand( 135 '@std/path', 136 null, 137 jsrInfo, 138 null, 139 ) 140 141 selectedPM.value = 'deno' 142 expect(installCommand.value).toBe('deno add jsr:@std/path') 143 expect(installCommandParts.value).toEqual(['deno', 'add', 'jsr:@std/path']) 144 }) 145 146 it('should use npm: prefix for deno when package is not on JSR', () => { 147 const jsrInfo: JsrPackageInfo = { exists: false } 148 149 const { installCommand, installCommandParts, selectedPM } = useInstallCommand( 150 'lodash', 151 null, 152 jsrInfo, 153 null, 154 ) 155 156 selectedPM.value = 'deno' 157 expect(installCommand.value).toBe('deno add npm:lodash') 158 expect(installCommandParts.value).toEqual(['deno', 'add', 'npm:lodash']) 159 }) 160 }) 161 162 describe('@types packages', () => { 163 it('should generate @types install command parts', () => { 164 const { typesInstallCommandParts, showTypesInInstall } = useInstallCommand( 165 'express', 166 null, 167 null, 168 '@types/express', 169 ) 170 171 expect(showTypesInInstall.value).toBe(true) 172 expect(typesInstallCommandParts.value).toEqual(['npm', 'install', '-D', '@types/express']) 173 }) 174 175 it('should use -d flag for bun', () => { 176 const { typesInstallCommandParts, selectedPM } = useInstallCommand( 177 'express', 178 null, 179 null, 180 '@types/express', 181 ) 182 183 selectedPM.value = 'bun' 184 expect(typesInstallCommandParts.value).toEqual(['bun', 'add', '-d', '@types/express']) 185 }) 186 187 it('should use npm: prefix for deno @types', () => { 188 const { typesInstallCommandParts, selectedPM } = useInstallCommand( 189 'express', 190 null, 191 null, 192 '@types/express', 193 ) 194 195 selectedPM.value = 'deno' 196 expect(typesInstallCommandParts.value).toEqual(['deno', 'add', '-D', 'npm:@types/express']) 197 }) 198 199 it('should not show @types when typesPackageName is null', () => { 200 const { showTypesInInstall, typesInstallCommandParts } = useInstallCommand( 201 'express', 202 null, 203 null, 204 null, 205 ) 206 207 expect(showTypesInInstall.value).toBe(false) 208 expect(typesInstallCommandParts.value).toEqual([]) 209 }) 210 }) 211 212 describe('fullInstallCommand with @types', () => { 213 it('should include both commands when @types enabled', () => { 214 const { fullInstallCommand } = useInstallCommand('express', null, null, '@types/express') 215 216 expect(fullInstallCommand.value).toBe('npm install express; npm install -D @types/express') 217 }) 218 219 it('should only include main command when @types disabled via settings', () => { 220 // Get settings and disable includeTypesInInstall directly 221 const { settings } = useSettings() 222 settings.value.includeTypesInInstall = false 223 224 const { fullInstallCommand, showTypesInInstall } = useInstallCommand( 225 'express', 226 null, 227 null, 228 '@types/express', 229 ) 230 231 expect(showTypesInInstall.value).toBe(false) 232 expect(fullInstallCommand.value).toBe('npm install express') 233 }) 234 }) 235 236 describe('reactive updates', () => { 237 it('should update command when package manager changes', () => { 238 const { installCommand, selectedPM } = useInstallCommand('vue', null, null, null) 239 240 expect(installCommand.value).toBe('npm install vue') 241 242 selectedPM.value = 'pnpm' 243 expect(installCommand.value).toBe('pnpm add vue') 244 245 selectedPM.value = 'yarn' 246 expect(installCommand.value).toBe('yarn add vue') 247 }) 248 249 it('should update when using ref values', () => { 250 const packageName = shallowRef<string | null>('vue') 251 const version = shallowRef<string | null>(null) 252 253 const { installCommand } = useInstallCommand(packageName, version, null, null) 254 255 expect(installCommand.value).toBe('npm install vue') 256 257 packageName.value = 'react' 258 expect(installCommand.value).toBe('npm install react') 259 260 version.value = '18.2.0' 261 expect(installCommand.value).toBe('npm install react@18.2.0') 262 }) 263 264 it('should prefer installVersionOverride when provided', () => { 265 const requestedVersion = shallowRef<string | null>(null) 266 const installVersionOverride = shallowRef<string | null>('1.0.0') 267 268 const { installCommand } = useInstallCommand( 269 'foo', 270 requestedVersion, 271 null, 272 null, 273 installVersionOverride, 274 ) 275 276 expect(installCommand.value).toBe('npm install foo@1.0.0') 277 278 installVersionOverride.value = null 279 requestedVersion.value = '2.0.0' 280 expect(installCommand.value).toBe('npm install foo@2.0.0') 281 }) 282 }) 283 284 describe('copyInstallCommand', () => { 285 it('should copy command to clipboard and set copied state', async () => { 286 vi.useFakeTimers() 287 288 const { copyInstallCommand, copied, fullInstallCommand } = useInstallCommand( 289 'vue', 290 null, 291 null, 292 null, 293 ) 294 295 expect(fullInstallCommand.value).toBe('npm install vue') 296 expect(copied.value).toBe(false) 297 298 await copyInstallCommand() 299 300 // useClipboard sets copied to true after successful copy 301 expect(copied.value).toBe(true) 302 303 // Advance timers to reset copied (copiedDuring: 2000) 304 await vi.advanceTimersByTimeAsync(2100) 305 expect(copied.value).toBe(false) 306 307 vi.useRealTimers() 308 }) 309 310 it('should not copy when command is empty', async () => { 311 const { copyInstallCommand, copied } = useInstallCommand(null, null, null, null) 312 313 expect(copied.value).toBe(false) 314 await copyInstallCommand() 315 316 // Should remain false since there was nothing to copy 317 expect(copied.value).toBe(false) 318 }) 319 }) 320})