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