1const t = require('tap') 2const { load: loadMockNpm } = require('../../fixtures/mock-npm') 3const { cleanCwd } = require('../../fixtures/clean-snapshot.js') 4 5t.cleanSnapshot = (str) => cleanCwd(str) 6 7t.test('simple query', async t => { 8 const { npm, joinedOutput } = await loadMockNpm(t, { 9 prefixDir: { 10 node_modules: { 11 a: { 12 name: 'a', 13 version: '1.0.0', 14 }, 15 b: { 16 name: 'b', 17 version: '^2.0.0', 18 }, 19 }, 20 'package.json': JSON.stringify({ 21 name: 'project', 22 dependencies: { 23 a: '^1.0.0', 24 b: '^1.0.0', 25 }, 26 peerDependencies: { 27 c: '1.0.0', 28 }, 29 }), 30 }, 31 }) 32 await npm.exec('query', [':root, :root > *']) 33 t.matchSnapshot(joinedOutput(), 'should return root object and direct children') 34}) 35 36t.test('recursive tree', async t => { 37 const { npm, joinedOutput } = await loadMockNpm(t, { 38 prefixDir: { 39 node_modules: { 40 a: { 41 name: 'a', 42 version: '1.0.0', 43 }, 44 b: { 45 name: 'b', 46 version: '^2.0.0', 47 dependencies: { 48 a: '1.0.0', 49 }, 50 }, 51 }, 52 'package.json': JSON.stringify({ 53 name: 'project', 54 dependencies: { 55 a: '^1.0.0', 56 b: '^1.0.0', 57 }, 58 }), 59 }, 60 }) 61 await npm.exec('query', ['*']) 62 t.matchSnapshot(joinedOutput(), 'should return everything in the tree, accounting for recursion') 63}) 64 65t.test('workspace query', async t => { 66 const { npm, joinedOutput } = await loadMockNpm(t, { 67 config: { 68 workspace: ['c'], 69 }, 70 prefixDir: { 71 node_modules: { 72 a: { 73 name: 'a', 74 version: '1.0.0', 75 }, 76 b: { 77 name: 'b', 78 version: '^2.0.0', 79 }, 80 c: t.fixture('symlink', '../c'), 81 }, 82 c: { 83 'package.json': JSON.stringify({ 84 name: 'c', 85 version: '1.0.0', 86 }), 87 }, 88 'package.json': JSON.stringify({ 89 name: 'project', 90 workspaces: ['c'], 91 dependencies: { 92 a: '^1.0.0', 93 b: '^1.0.0', 94 }, 95 }), 96 }, 97 }) 98 await npm.exec('query', [':scope']) 99 t.matchSnapshot(joinedOutput(), 'should return workspace object') 100}) 101 102t.test('include-workspace-root', async t => { 103 const { npm, joinedOutput } = await loadMockNpm(t, { 104 config: { 105 'include-workspace-root': true, 106 workspace: ['c'], 107 }, 108 prefixDir: { 109 node_modules: { 110 a: { 111 name: 'a', 112 version: '1.0.0', 113 }, 114 b: { 115 name: 'b', 116 version: '^2.0.0', 117 }, 118 c: t.fixture('symlink', '../c'), 119 }, 120 c: { 121 'package.json': JSON.stringify({ 122 name: 'c', 123 version: '1.0.0', 124 }), 125 }, 126 'package.json': JSON.stringify({ 127 name: 'project', 128 workspaces: ['c'], 129 dependencies: { 130 a: '^1.0.0', 131 b: '^1.0.0', 132 }, 133 }), 134 }, 135 }) 136 await npm.exec('query', [':scope']) 137 t.matchSnapshot(joinedOutput(), 'should return workspace object and root object') 138}) 139t.test('linked node', async t => { 140 const { npm, joinedOutput } = await loadMockNpm(t, { 141 prefixDir: { 142 node_modules: { 143 a: t.fixture('symlink', '../a'), 144 }, 145 a: { 146 'package.json': JSON.stringify({ 147 name: 'a', 148 version: '1.0.0', 149 }), 150 }, 151 'package.json': JSON.stringify({ 152 name: 'project', 153 dependencies: { 154 a: 'file:./a', 155 }, 156 }), 157 }, 158 }) 159 await npm.exec('query', ['[name=a]']) 160 t.matchSnapshot(joinedOutput(), 'should return linked node res') 161}) 162 163t.test('global', async t => { 164 const { npm, joinedOutput } = await loadMockNpm(t, { 165 config: { 166 global: true, 167 }, 168 globalPrefixDir: { 169 node_modules: { 170 lorem: { 171 'package.json': JSON.stringify({ 172 name: 'lorem', 173 version: '2.0.0', 174 }), 175 }, 176 }, 177 178 }, 179 }) 180 await npm.exec('query', ['[name=lorem]']) 181 t.matchSnapshot(joinedOutput(), 'should return global package') 182}) 183 184t.test('package-lock-only', t => { 185 t.test('no package lock', async t => { 186 const { npm } = await loadMockNpm(t, { 187 config: { 188 'package-lock-only': true, 189 }, 190 prefixDir: { 191 'package.json': JSON.stringify({ 192 name: 'project', 193 dependencies: { 194 a: '^1.0.0', 195 }, 196 }), 197 }, 198 }) 199 await t.rejects(npm.exec('query', [':root, :root > *']), { code: 'EUSAGE' }) 200 }) 201 202 t.test('with package lock', async t => { 203 const { npm, joinedOutput } = await loadMockNpm(t, { 204 config: { 205 'package-lock-only': true, 206 }, 207 prefixDir: { 208 'package.json': JSON.stringify({ 209 name: 'project', 210 dependencies: { 211 a: '^1.0.0', 212 }, 213 }), 214 'package-lock.json': JSON.stringify({ 215 name: 'project', 216 lockfileVersion: 3, 217 requires: true, 218 packages: { 219 '': { 220 dependencies: { 221 a: '^1.0.0', 222 }, 223 }, 224 'node_modules/a': { 225 version: '1.2.3', 226 resolved: 'https://dummy.npmjs.org/a/-/a-1.2.3.tgz', 227 integrity: 'sha512-dummy', 228 engines: { 229 node: '>=14.17', 230 }, 231 }, 232 }, 233 }), 234 }, 235 }) 236 await npm.exec('query', ['*']) 237 t.matchSnapshot(joinedOutput(), 'should return valid response with only lock info') 238 }) 239 t.end() 240}) 241 242t.test('expect entries', t => { 243 const { exitCode } = process 244 t.afterEach(() => process.exitCode = exitCode) 245 const prefixDir = { 246 node_modules: { 247 a: { name: 'a', version: '1.0.0' }, 248 }, 249 'package.json': JSON.stringify({ 250 name: 'project', 251 dependencies: { a: '^1.0.0' }, 252 }), 253 } 254 t.test('false, has entries', async t => { 255 const { logs, npm, joinedOutput } = await loadMockNpm(t, { 256 prefixDir, 257 }) 258 npm.config.set('expect-results', false) 259 await npm.exec('query', ['#a']) 260 t.not(joinedOutput(), '[]', 'has entries') 261 t.same(logs.warn, [['query', 'Expected no results, got 1']]) 262 t.ok(process.exitCode, 'exits with code') 263 }) 264 t.test('false, no entries', async t => { 265 const { npm, joinedOutput } = await loadMockNpm(t, { 266 prefixDir, 267 }) 268 npm.config.set('expect-results', false) 269 await npm.exec('query', ['#b']) 270 t.equal(joinedOutput(), '[]', 'does not have entries') 271 t.notOk(process.exitCode, 'exits without code') 272 }) 273 t.test('true, has entries', async t => { 274 const { npm, joinedOutput } = await loadMockNpm(t, { 275 prefixDir, 276 }) 277 npm.config.set('expect-results', true) 278 await npm.exec('query', ['#a']) 279 t.not(joinedOutput(), '[]', 'has entries') 280 t.notOk(process.exitCode, 'exits without code') 281 }) 282 t.test('true, no entries', async t => { 283 const { logs, npm, joinedOutput } = await loadMockNpm(t, { 284 prefixDir, 285 }) 286 npm.config.set('expect-results', true) 287 await npm.exec('query', ['#b']) 288 t.equal(joinedOutput(), '[]', 'does not have entries') 289 t.same(logs.warn, [['query', 'Expected results, got 0']]) 290 t.ok(process.exitCode, 'exits with code') 291 }) 292 t.test('count, matches', async t => { 293 const { npm, joinedOutput } = await loadMockNpm(t, { 294 prefixDir, 295 }) 296 npm.config.set('expect-result-count', 1) 297 await npm.exec('query', ['#a']) 298 t.not(joinedOutput(), '[]', 'has entries') 299 t.notOk(process.exitCode, 'exits without code') 300 }) 301 t.test('count 1, does not match', async t => { 302 const { logs, npm, joinedOutput } = await loadMockNpm(t, { 303 prefixDir, 304 }) 305 npm.config.set('expect-result-count', 1) 306 await npm.exec('query', ['#b']) 307 t.equal(joinedOutput(), '[]', 'does not have entries') 308 t.same(logs.warn, [['query', 'Expected 1 result, got 0']]) 309 t.ok(process.exitCode, 'exits with code') 310 }) 311 t.test('count 3, does not match', async t => { 312 const { logs, npm, joinedOutput } = await loadMockNpm(t, { 313 prefixDir, 314 }) 315 npm.config.set('expect-result-count', 3) 316 await npm.exec('query', ['#b']) 317 t.equal(joinedOutput(), '[]', 'does not have entries') 318 t.same(logs.warn, [['query', 'Expected 3 results, got 0']]) 319 t.ok(process.exitCode, 'exits with code') 320 }) 321 t.end() 322}) 323