11cb0ef41Sopenharmony_ciconst t = require('tap')
21cb0ef41Sopenharmony_ciconst { resolve } = require('path')
31cb0ef41Sopenharmony_ciconst mockNpm = require('../../fixtures/mock-npm.js')
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ciconst mockExplain = async (t, opts) => {
61cb0ef41Sopenharmony_ci  const mock = await mockNpm(t, {
71cb0ef41Sopenharmony_ci    command: 'explain',
81cb0ef41Sopenharmony_ci    mocks: {
91cb0ef41Sopenharmony_ci      // keep the snapshots pared down a bit, since this has its own tests.
101cb0ef41Sopenharmony_ci      '{LIB}/utils/explain-dep.js': {
111cb0ef41Sopenharmony_ci        explainNode: (expl, depth, chalk) => {
121cb0ef41Sopenharmony_ci          const color = chalk.level !== 0
131cb0ef41Sopenharmony_ci          return `${expl.name}@${expl.version} depth=${depth} color=${color}`
141cb0ef41Sopenharmony_ci        },
151cb0ef41Sopenharmony_ci      },
161cb0ef41Sopenharmony_ci    },
171cb0ef41Sopenharmony_ci    ...opts,
181cb0ef41Sopenharmony_ci  })
191cb0ef41Sopenharmony_ci
201cb0ef41Sopenharmony_ci  return mock
211cb0ef41Sopenharmony_ci}
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_cit.test('no args throws usage', async t => {
241cb0ef41Sopenharmony_ci  const { explain } = await mockExplain(t)
251cb0ef41Sopenharmony_ci  await t.rejects(
261cb0ef41Sopenharmony_ci    explain.exec([]),
271cb0ef41Sopenharmony_ci    explain.usage
281cb0ef41Sopenharmony_ci  )
291cb0ef41Sopenharmony_ci})
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_cit.test('no match throws not found', async t => {
321cb0ef41Sopenharmony_ci  const { explain } = await mockExplain(t)
331cb0ef41Sopenharmony_ci  await t.rejects(
341cb0ef41Sopenharmony_ci    explain.exec(['foo@1.2.3', 'node_modules/baz']),
351cb0ef41Sopenharmony_ci    'No dependencies found matching foo@1.2.3, node_modules/baz'
361cb0ef41Sopenharmony_ci  )
371cb0ef41Sopenharmony_ci})
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_cit.test('invalid package name throws not found', async t => {
401cb0ef41Sopenharmony_ci  const { explain } = await mockExplain(t)
411cb0ef41Sopenharmony_ci  const badName = ' not a valid package name '
421cb0ef41Sopenharmony_ci  await t.rejects(
431cb0ef41Sopenharmony_ci    explain.exec([`${badName}@1.2.3`]),
441cb0ef41Sopenharmony_ci    `No dependencies found matching ${badName}@1.2.3`
451cb0ef41Sopenharmony_ci  )
461cb0ef41Sopenharmony_ci})
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_cit.test('explain some nodes', async t => {
491cb0ef41Sopenharmony_ci  const mockNodes = async (t, config = {}) => {
501cb0ef41Sopenharmony_ci    const mock = await mockExplain(t, {
511cb0ef41Sopenharmony_ci      prefixDir: {
521cb0ef41Sopenharmony_ci        node_modules: {
531cb0ef41Sopenharmony_ci          foo: {
541cb0ef41Sopenharmony_ci            'package.json': JSON.stringify({
551cb0ef41Sopenharmony_ci              name: 'foo',
561cb0ef41Sopenharmony_ci              version: '1.2.3',
571cb0ef41Sopenharmony_ci              dependencies: {
581cb0ef41Sopenharmony_ci                bar: '*',
591cb0ef41Sopenharmony_ci              },
601cb0ef41Sopenharmony_ci            }),
611cb0ef41Sopenharmony_ci          },
621cb0ef41Sopenharmony_ci          bar: {
631cb0ef41Sopenharmony_ci            'package.json': JSON.stringify({
641cb0ef41Sopenharmony_ci              name: 'bar',
651cb0ef41Sopenharmony_ci              version: '1.2.3',
661cb0ef41Sopenharmony_ci            }),
671cb0ef41Sopenharmony_ci          },
681cb0ef41Sopenharmony_ci          baz: {
691cb0ef41Sopenharmony_ci            'package.json': JSON.stringify({
701cb0ef41Sopenharmony_ci              name: 'baz',
711cb0ef41Sopenharmony_ci              version: '1.2.3',
721cb0ef41Sopenharmony_ci              dependencies: {
731cb0ef41Sopenharmony_ci                foo: '*',
741cb0ef41Sopenharmony_ci                bar: '2',
751cb0ef41Sopenharmony_ci              },
761cb0ef41Sopenharmony_ci            }),
771cb0ef41Sopenharmony_ci            node_modules: {
781cb0ef41Sopenharmony_ci              bar: {
791cb0ef41Sopenharmony_ci                'package.json': JSON.stringify({
801cb0ef41Sopenharmony_ci                  name: 'bar',
811cb0ef41Sopenharmony_ci                  version: '2.3.4',
821cb0ef41Sopenharmony_ci                }),
831cb0ef41Sopenharmony_ci              },
841cb0ef41Sopenharmony_ci              extra: {
851cb0ef41Sopenharmony_ci                'package.json': JSON.stringify({
861cb0ef41Sopenharmony_ci                  name: 'extra',
871cb0ef41Sopenharmony_ci                  version: '99.9999.999999',
881cb0ef41Sopenharmony_ci                  description: 'extraneous package',
891cb0ef41Sopenharmony_ci                }),
901cb0ef41Sopenharmony_ci              },
911cb0ef41Sopenharmony_ci            },
921cb0ef41Sopenharmony_ci          },
931cb0ef41Sopenharmony_ci        },
941cb0ef41Sopenharmony_ci        'package.json': JSON.stringify({
951cb0ef41Sopenharmony_ci          dependencies: {
961cb0ef41Sopenharmony_ci            baz: '1',
971cb0ef41Sopenharmony_ci          },
981cb0ef41Sopenharmony_ci        }),
991cb0ef41Sopenharmony_ci      },
1001cb0ef41Sopenharmony_ci      config: {
1011cb0ef41Sopenharmony_ci        color: 'always',
1021cb0ef41Sopenharmony_ci        ...config,
1031cb0ef41Sopenharmony_ci      },
1041cb0ef41Sopenharmony_ci    })
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ci    return mock
1071cb0ef41Sopenharmony_ci  }
1081cb0ef41Sopenharmony_ci
1091cb0ef41Sopenharmony_ci  t.test('works with the location', async t => {
1101cb0ef41Sopenharmony_ci    const path = 'node_modules/foo'
1111cb0ef41Sopenharmony_ci    const { explain, joinedOutput } = await mockNodes(t)
1121cb0ef41Sopenharmony_ci    await explain.exec([path])
1131cb0ef41Sopenharmony_ci    t.strictSame(joinedOutput(), 'foo@1.2.3 depth=Infinity color=true')
1141cb0ef41Sopenharmony_ci  })
1151cb0ef41Sopenharmony_ci
1161cb0ef41Sopenharmony_ci  t.test('works with a full actual path', async t => {
1171cb0ef41Sopenharmony_ci    const { npm, explain, joinedOutput } = await mockNodes(t)
1181cb0ef41Sopenharmony_ci    const path = resolve(npm.prefix, 'node_modules/foo')
1191cb0ef41Sopenharmony_ci    await explain.exec([path])
1201cb0ef41Sopenharmony_ci    t.strictSame(joinedOutput(), 'foo@1.2.3 depth=Infinity color=true')
1211cb0ef41Sopenharmony_ci  })
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci  t.test('finds all nodes by name', async t => {
1241cb0ef41Sopenharmony_ci    const { explain, joinedOutput } = await mockNodes(t)
1251cb0ef41Sopenharmony_ci    await explain.exec(['bar'])
1261cb0ef41Sopenharmony_ci    t.strictSame(joinedOutput(),
1271cb0ef41Sopenharmony_ci      'bar@1.2.3 depth=Infinity color=true\n\n' +
1281cb0ef41Sopenharmony_ci      'bar@2.3.4 depth=Infinity color=true'
1291cb0ef41Sopenharmony_ci    )
1301cb0ef41Sopenharmony_ci  })
1311cb0ef41Sopenharmony_ci
1321cb0ef41Sopenharmony_ci  t.test('finds only nodes that match the spec', async t => {
1331cb0ef41Sopenharmony_ci    const { explain, joinedOutput } = await mockNodes(t)
1341cb0ef41Sopenharmony_ci    await explain.exec(['bar@1'])
1351cb0ef41Sopenharmony_ci    t.strictSame(joinedOutput(), 'bar@1.2.3 depth=Infinity color=true')
1361cb0ef41Sopenharmony_ci  })
1371cb0ef41Sopenharmony_ci
1381cb0ef41Sopenharmony_ci  t.test('finds extraneous nodes', async t => {
1391cb0ef41Sopenharmony_ci    const { explain, joinedOutput } = await mockNodes(t)
1401cb0ef41Sopenharmony_ci    await explain.exec(['extra'])
1411cb0ef41Sopenharmony_ci    t.strictSame(joinedOutput(), 'extra@99.9999.999999 depth=Infinity color=true')
1421cb0ef41Sopenharmony_ci  })
1431cb0ef41Sopenharmony_ci
1441cb0ef41Sopenharmony_ci  t.test('json output', async t => {
1451cb0ef41Sopenharmony_ci    const { explain, joinedOutput } = await mockNodes(t, { json: true })
1461cb0ef41Sopenharmony_ci    await explain.exec(['node_modules/foo'])
1471cb0ef41Sopenharmony_ci    t.match(JSON.parse(joinedOutput()), [{
1481cb0ef41Sopenharmony_ci      name: 'foo',
1491cb0ef41Sopenharmony_ci      version: '1.2.3',
1501cb0ef41Sopenharmony_ci      dependents: Array,
1511cb0ef41Sopenharmony_ci    }])
1521cb0ef41Sopenharmony_ci  })
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_ci  t.test('report if no nodes found', async t => {
1551cb0ef41Sopenharmony_ci    const { explain } = await mockNodes(t)
1561cb0ef41Sopenharmony_ci    await t.rejects(
1571cb0ef41Sopenharmony_ci      explain.exec(['asdf/foo/bar', 'quux@1.x']),
1581cb0ef41Sopenharmony_ci      'No dependencies found matching asdf/foo/bar, quux@1.x'
1591cb0ef41Sopenharmony_ci    )
1601cb0ef41Sopenharmony_ci  })
1611cb0ef41Sopenharmony_ci})
1621cb0ef41Sopenharmony_ci
1631cb0ef41Sopenharmony_cit.test('workspaces', async t => {
1641cb0ef41Sopenharmony_ci  const mockWorkspaces = async (t, exec = [], workspaces = true) => {
1651cb0ef41Sopenharmony_ci    const mock = await mockExplain(t, {
1661cb0ef41Sopenharmony_ci      prefixDir: {
1671cb0ef41Sopenharmony_ci        'package.json': JSON.stringify({
1681cb0ef41Sopenharmony_ci          name: 'workspaces-project',
1691cb0ef41Sopenharmony_ci          version: '1.0.0',
1701cb0ef41Sopenharmony_ci          workspaces: ['packages/*'],
1711cb0ef41Sopenharmony_ci          dependencies: {
1721cb0ef41Sopenharmony_ci            abbrev: '^1.0.0',
1731cb0ef41Sopenharmony_ci          },
1741cb0ef41Sopenharmony_ci        }),
1751cb0ef41Sopenharmony_ci        node_modules: {
1761cb0ef41Sopenharmony_ci          a: t.fixture('symlink', '../packages/a'),
1771cb0ef41Sopenharmony_ci          b: t.fixture('symlink', '../packages/b'),
1781cb0ef41Sopenharmony_ci          c: t.fixture('symlink', '../packages/c'),
1791cb0ef41Sopenharmony_ci          once: {
1801cb0ef41Sopenharmony_ci            'package.json': JSON.stringify({
1811cb0ef41Sopenharmony_ci              name: 'once',
1821cb0ef41Sopenharmony_ci              version: '1.0.0',
1831cb0ef41Sopenharmony_ci              dependencies: {
1841cb0ef41Sopenharmony_ci                wrappy: '2.0.0',
1851cb0ef41Sopenharmony_ci              },
1861cb0ef41Sopenharmony_ci            }),
1871cb0ef41Sopenharmony_ci          },
1881cb0ef41Sopenharmony_ci          abbrev: {
1891cb0ef41Sopenharmony_ci            'package.json': JSON.stringify({
1901cb0ef41Sopenharmony_ci              name: 'abbrev',
1911cb0ef41Sopenharmony_ci              version: '1.0.0',
1921cb0ef41Sopenharmony_ci            }),
1931cb0ef41Sopenharmony_ci          },
1941cb0ef41Sopenharmony_ci          wrappy: {
1951cb0ef41Sopenharmony_ci            'package.json': JSON.stringify({
1961cb0ef41Sopenharmony_ci              name: 'wrappy',
1971cb0ef41Sopenharmony_ci              version: '2.0.0',
1981cb0ef41Sopenharmony_ci            }),
1991cb0ef41Sopenharmony_ci          },
2001cb0ef41Sopenharmony_ci        },
2011cb0ef41Sopenharmony_ci        packages: {
2021cb0ef41Sopenharmony_ci          a: {
2031cb0ef41Sopenharmony_ci            'package.json': JSON.stringify({
2041cb0ef41Sopenharmony_ci              name: 'a',
2051cb0ef41Sopenharmony_ci              version: '1.0.0',
2061cb0ef41Sopenharmony_ci              dependencies: {
2071cb0ef41Sopenharmony_ci                once: '1.0.0',
2081cb0ef41Sopenharmony_ci              },
2091cb0ef41Sopenharmony_ci            }),
2101cb0ef41Sopenharmony_ci          },
2111cb0ef41Sopenharmony_ci          b: {
2121cb0ef41Sopenharmony_ci            'package.json': JSON.stringify({
2131cb0ef41Sopenharmony_ci              name: 'b',
2141cb0ef41Sopenharmony_ci              version: '1.0.0',
2151cb0ef41Sopenharmony_ci              dependencies: {
2161cb0ef41Sopenharmony_ci                abbrev: '^1.0.0',
2171cb0ef41Sopenharmony_ci              },
2181cb0ef41Sopenharmony_ci            }),
2191cb0ef41Sopenharmony_ci          },
2201cb0ef41Sopenharmony_ci          c: {
2211cb0ef41Sopenharmony_ci            'package.json': JSON.stringify({
2221cb0ef41Sopenharmony_ci              name: 'c',
2231cb0ef41Sopenharmony_ci              version: '1.0.0',
2241cb0ef41Sopenharmony_ci            }),
2251cb0ef41Sopenharmony_ci          },
2261cb0ef41Sopenharmony_ci        },
2271cb0ef41Sopenharmony_ci      },
2281cb0ef41Sopenharmony_ci      config: {
2291cb0ef41Sopenharmony_ci        ...(typeof workspaces === 'boolean' ? { workspaces } : { workspace: workspaces }),
2301cb0ef41Sopenharmony_ci        color: 'always',
2311cb0ef41Sopenharmony_ci      },
2321cb0ef41Sopenharmony_ci    })
2331cb0ef41Sopenharmony_ci
2341cb0ef41Sopenharmony_ci    await mock.explain.exec(exec)
2351cb0ef41Sopenharmony_ci
2361cb0ef41Sopenharmony_ci    return mock.joinedOutput()
2371cb0ef41Sopenharmony_ci  }
2381cb0ef41Sopenharmony_ci
2391cb0ef41Sopenharmony_ci  t.test('should explain workspaces deps', async t => {
2401cb0ef41Sopenharmony_ci    const OUTPUT = await mockWorkspaces(t, ['wrappy'])
2411cb0ef41Sopenharmony_ci    t.strictSame(
2421cb0ef41Sopenharmony_ci      OUTPUT,
2431cb0ef41Sopenharmony_ci      'wrappy@2.0.0 depth=Infinity color=true'
2441cb0ef41Sopenharmony_ci    )
2451cb0ef41Sopenharmony_ci  })
2461cb0ef41Sopenharmony_ci
2471cb0ef41Sopenharmony_ci  t.test('should explain deps when filtering to a single ws', async t => {
2481cb0ef41Sopenharmony_ci    const OUTPUT = await mockWorkspaces(t, ['wrappy'], ['a'])
2491cb0ef41Sopenharmony_ci    t.strictSame(
2501cb0ef41Sopenharmony_ci      OUTPUT,
2511cb0ef41Sopenharmony_ci      'wrappy@2.0.0 depth=Infinity color=true'
2521cb0ef41Sopenharmony_ci    )
2531cb0ef41Sopenharmony_ci  })
2541cb0ef41Sopenharmony_ci
2551cb0ef41Sopenharmony_ci  t.test('should explain deps of workspaces only', async t => {
2561cb0ef41Sopenharmony_ci    const OUTPUT = await mockWorkspaces(t, ['abbrev'])
2571cb0ef41Sopenharmony_ci    t.strictSame(
2581cb0ef41Sopenharmony_ci      OUTPUT,
2591cb0ef41Sopenharmony_ci      'abbrev@1.0.0 depth=Infinity color=true'
2601cb0ef41Sopenharmony_ci    )
2611cb0ef41Sopenharmony_ci  })
2621cb0ef41Sopenharmony_ci
2631cb0ef41Sopenharmony_ci  t.test('should throw usage if dep not found within filtered ws', async t => {
2641cb0ef41Sopenharmony_ci    await t.rejects(
2651cb0ef41Sopenharmony_ci      mockWorkspaces(t, ['abbrev'], ['a']),
2661cb0ef41Sopenharmony_ci      'No dependencies found matching abbrev'
2671cb0ef41Sopenharmony_ci    )
2681cb0ef41Sopenharmony_ci  })
2691cb0ef41Sopenharmony_ci
2701cb0ef41Sopenharmony_ci  t.test('workspaces disabled', async t => {
2711cb0ef41Sopenharmony_ci    await t.rejects(
2721cb0ef41Sopenharmony_ci      mockWorkspaces(t, ['once'], false),
2731cb0ef41Sopenharmony_ci      'No dependencies found matching once',
2741cb0ef41Sopenharmony_ci      'should throw usage if dep not found when excluding ws'
2751cb0ef41Sopenharmony_ci    )
2761cb0ef41Sopenharmony_ci  })
2771cb0ef41Sopenharmony_ci})
278