1const t = require('tap') 2const mockNpm = require('../../fixtures/mock-npm.js') 3const { sep } = require('path') 4 5const fixture = { 6 'package.json': JSON.stringify({ 7 name: 'thispkg', 8 version: '1.2.3', 9 repository: 'https://example.com/thispkg.git', 10 }), 11 norepo: { 12 'package.json': JSON.stringify({ 13 name: 'norepo', 14 version: '1.2.3', 15 }), 16 }, 17 'repoobbj-nourl': { 18 'package.json': JSON.stringify({ 19 name: 'repoobj-nourl', 20 repository: { no: 'url' }, 21 }), 22 }, 23 hostedgit: { 24 'package.json': JSON.stringify({ 25 repository: 'git://github.com/foo/hostedgit', 26 }), 27 }, 28 hostedgitat: { 29 'package.json': JSON.stringify({ 30 repository: 'git@github.com:foo/hostedgitat', 31 }), 32 }, 33 hostedssh: { 34 'package.json': JSON.stringify({ 35 repository: 'ssh://git@github.com/foo/hostedssh', 36 }), 37 }, 38 hostedgitssh: { 39 'package.json': JSON.stringify({ 40 repository: 'git+ssh://git@github.com/foo/hostedgitssh', 41 }), 42 }, 43 hostedgithttp: { 44 'package.json': JSON.stringify({ 45 repository: 'git+http://github.com/foo/hostedgithttp', 46 }), 47 }, 48 hostedgithttps: { 49 'package.json': JSON.stringify({ 50 repository: 'git+https://github.com/foo/hostedgithttps', 51 }), 52 }, 53 hostedgitobj: { 54 'package.json': JSON.stringify({ 55 repository: { url: 'git://github.com/foo/hostedgitobj' }, 56 }), 57 }, 58 hostedgitatobj: { 59 'package.json': JSON.stringify({ 60 repository: { url: 'git@github.com:foo/hostedgitatobj' }, 61 }), 62 }, 63 hostedsshobj: { 64 'package.json': JSON.stringify({ 65 repository: { url: 'ssh://git@github.com/foo/hostedsshobj' }, 66 }), 67 }, 68 hostedgitsshobj: { 69 'package.json': JSON.stringify({ 70 repository: { url: 'git+ssh://git@github.com/foo/hostedgitsshobj' }, 71 }), 72 }, 73 hostedgithttpobj: { 74 'package.json': JSON.stringify({ 75 repository: { url: 'git+http://github.com/foo/hostedgithttpobj' }, 76 }), 77 }, 78 hostedgithttpsobj: { 79 'package.json': JSON.stringify({ 80 repository: { url: 'git+https://github.com/foo/hostedgithttpsobj' }, 81 }), 82 }, 83 unhostedgit: { 84 'package.json': JSON.stringify({ 85 repository: 'git://gothib.com/foo/unhostedgit', 86 }), 87 }, 88 unhostedgitat: { 89 'package.json': JSON.stringify({ 90 repository: 'git@gothib.com:foo/unhostedgitat', 91 }), 92 }, 93 unhostedssh: { 94 'package.json': JSON.stringify({ 95 repository: 'ssh://git@gothib.com/foo/unhostedssh', 96 }), 97 }, 98 unhostedgitssh: { 99 'package.json': JSON.stringify({ 100 repository: 'git+ssh://git@gothib.com/foo/unhostedgitssh', 101 }), 102 }, 103 unhostedgithttp: { 104 'package.json': JSON.stringify({ 105 repository: 'git+http://gothib.com/foo/unhostedgithttp', 106 }), 107 }, 108 unhostedgithttps: { 109 'package.json': JSON.stringify({ 110 repository: 'git+https://gothib.com/foo/unhostedgithttps', 111 }), 112 }, 113 unhostedgitobj: { 114 'package.json': JSON.stringify({ 115 repository: { url: 'git://gothib.com/foo/unhostedgitobj' }, 116 }), 117 }, 118 unhostedgitatobj: { 119 'package.json': JSON.stringify({ 120 repository: { url: 'git@gothib.com:foo/unhostedgitatobj' }, 121 }), 122 }, 123 unhostedsshobj: { 124 'package.json': JSON.stringify({ 125 repository: { url: 'ssh://git@gothib.com/foo/unhostedsshobj' }, 126 }), 127 }, 128 unhostedgitsshobj: { 129 'package.json': JSON.stringify({ 130 repository: { url: 'git+ssh://git@gothib.com/foo/unhostedgitsshobj' }, 131 }), 132 }, 133 unhostedgithttpobj: { 134 'package.json': JSON.stringify({ 135 repository: { url: 'git+http://gothib.com/foo/unhostedgithttpobj' }, 136 }), 137 }, 138 unhostedgithttpsobj: { 139 'package.json': JSON.stringify({ 140 repository: { url: 'git+https://gothib.com/foo/unhostedgithttpsobj' }, 141 }), 142 }, 143 directory: { 144 'package.json': JSON.stringify({ 145 repository: { 146 type: 'git', 147 url: 'git+https://github.com/foo/test-repo-with-directory.git', 148 directory: 'some/directory', 149 }, 150 }), 151 }, 152} 153 154const workspaceFixture = { 155 'package.json': JSON.stringify({ 156 name: 'workspaces-test', 157 version: '1.2.3-test', 158 workspaces: ['workspace-a', 'workspace-b', 'workspace-c'], 159 repository: 'https://github.com/npm/workspaces-test', 160 }), 161 'workspace-a': { 162 'package.json': JSON.stringify({ 163 name: 'workspace-a', 164 version: '1.2.3-a', 165 repository: 'http://repo.workspace-a/', 166 }), 167 }, 168 'workspace-b': { 169 'package.json': JSON.stringify({ 170 name: 'workspace-b', 171 version: '1.2.3-n', 172 repository: 'https://github.com/npm/workspace-b', 173 }), 174 }, 175 'workspace-c': JSON.stringify({ 176 'package.json': { 177 name: 'workspace-n', 178 version: '1.2.3-n', 179 }, 180 }), 181} 182 183const loadMockNpm = async (t, prefixDir, config = {}) => { 184 // keep a tally of which urls got opened 185 const opened = {} 186 187 const mock = await mockNpm(t, { 188 command: 'repo', 189 mocks: { 190 '{LIB}/utils/open-url.js': async (_, url) => { 191 opened[url] = opened[url] || 0 192 opened[url]++ 193 }, 194 }, 195 config, 196 prefixDir, 197 }) 198 199 return { 200 ...mock, 201 opened, 202 } 203} 204 205t.test('open repo urls', async t => { 206 const { repo, opened } = await loadMockNpm(t, fixture) 207 const expect = { 208 hostedgit: 'https://github.com/foo/hostedgit', 209 hostedgitat: 'https://github.com/foo/hostedgitat', 210 hostedssh: 'https://github.com/foo/hostedssh', 211 hostedgitssh: 'https://github.com/foo/hostedgitssh', 212 hostedgithttp: 'https://github.com/foo/hostedgithttp', 213 hostedgithttps: 'https://github.com/foo/hostedgithttps', 214 hostedgitobj: 'https://github.com/foo/hostedgitobj', 215 hostedgitatobj: 'https://github.com/foo/hostedgitatobj', 216 hostedsshobj: 'https://github.com/foo/hostedsshobj', 217 hostedgitsshobj: 'https://github.com/foo/hostedgitsshobj', 218 hostedgithttpobj: 'https://github.com/foo/hostedgithttpobj', 219 hostedgithttpsobj: 'https://github.com/foo/hostedgithttpsobj', 220 unhostedgit: 'https://gothib.com/foo/unhostedgit', 221 unhostedssh: 'https://gothib.com/foo/unhostedssh', 222 unhostedgitssh: 'https://gothib.com/foo/unhostedgitssh', 223 unhostedgithttp: 'http://gothib.com/foo/unhostedgithttp', 224 unhostedgithttps: 'https://gothib.com/foo/unhostedgithttps', 225 unhostedgitobj: 'https://gothib.com/foo/unhostedgitobj', 226 unhostedsshobj: 'https://gothib.com/foo/unhostedsshobj', 227 unhostedgitsshobj: 'https://gothib.com/foo/unhostedgitsshobj', 228 unhostedgithttpobj: 'http://gothib.com/foo/unhostedgithttpobj', 229 unhostedgithttpsobj: 'https://gothib.com/foo/unhostedgithttpsobj', 230 directory: 'https://github.com/foo/test-repo-with-directory/tree/HEAD/some/directory', 231 '.': 'https://example.com/thispkg', 232 } 233 for (const [pkg, url] of Object.entries(expect)) { 234 await repo.exec([['.', pkg].join(sep)]) 235 t.equal(opened[url], 1, `opened ${url}`) 236 } 237}) 238 239t.test('fail if cannot figure out repo url', async t => { 240 const { repo } = await loadMockNpm(t, fixture) 241 242 const cases = [ 243 'norepo', 244 'repoobbj-nourl', 245 'unhostedgitat', 246 'unhostedgitatobj', 247 ] 248 249 for (const pkg of cases) { 250 await t.rejects( 251 repo.exec([['.', pkg].join(sep)]), 252 { pkgid: pkg } 253 ) 254 } 255}) 256 257t.test('open default package if none specified', async t => { 258 const { repo, opened } = await loadMockNpm(t, fixture) 259 await repo.exec([]) 260 t.equal(opened['https://example.com/thispkg'], 1, 'opened expected url', { opened }) 261}) 262 263t.test('workspaces', async t => { 264 const mockWorkspaces = (t, config) => loadMockNpm(t, workspaceFixture, config) 265 266 t.test('include workspace root', async (t) => { 267 const { opened, repo } = await mockWorkspaces(t, { 268 workspaces: true, 269 'include-workspace-root': true, 270 }) 271 await repo.exec([]) 272 t.match({ 273 'https://github.com/npm/workspaces-test': 1, 274 'https://repo.workspace-a/': 1, // Gets translated to https! 275 'https://github.com/npm/workspace-b': 1, 276 }, opened, 'opened two valid repo urls') 277 }) 278 279 t.test('all workspaces', async (t) => { 280 const { opened, repo } = await mockWorkspaces(t, { 281 workspaces: true, 282 }) 283 await repo.exec([]) 284 t.match({ 285 'https://repo.workspace-a/': 1, // Gets translated to https! 286 'https://github.com/npm/workspace-b': 1, 287 }, opened, 'opened two valid repo urls') 288 }) 289 290 t.test('one workspace', async (t) => { 291 const { opened, repo } = await mockWorkspaces(t, { 292 workspace: ['workspace-a'], 293 }) 294 await repo.exec([]) 295 t.match({ 296 'https://repo.workspace-a/': 1, 297 }, opened, 'opened one requested repo urls') 298 }) 299 300 t.test('invalid workspace', async (t) => { 301 const { opened, repo } = await mockWorkspaces(t, { 302 workspace: ['workspace-x'], 303 }) 304 await t.rejects( 305 repo.exec([]), 306 /workspace-x/ 307 ) 308 t.match({}, opened, 'opened no repo urls') 309 }) 310 311 t.test('package arg and workspace', async (t) => { 312 const { opened, repo } = await mockWorkspaces(t, { 313 workspace: ['workspace-x'], 314 }) 315 await repo.exec(['.']) 316 t.match({ 317 'https://github.com/npm/workspaces-test': 1, 318 }, opened, 'opened url for package arg, not workspace') 319 }) 320}) 321