Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions smoke-tests/test/bundled-deps-resolve.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
const t = require('tap')
const { join } = require('node:path')
const fs = require('node:fs')
const { createRequire } = require('node:module')
const setup = require('./fixtures/setup.js')

// Walk an installed package tree and assert that every non-optional
// production dependency of every bundled package resolves from that
// package's own directory. This catches deps that were dropped from the
// hoisted bundle at pack time (e.g. a dev-only copy shadowing the real
// production version), which unit tests miss because they run against the
// source tree where a nested copy still resolves. See PR #9740 / #9722
// where `sigstore` went missing from the packed bundle.
const findMissingDeps = (npmRoot) => {
const req = createRequire(join(npmRoot, 'package.json'))
const missing = []
const seen = new Set()
const stack = [npmRoot]

while (stack.length) {
const dir = stack.pop()
if (seen.has(dir)) {
continue
}
seen.add(dir)

let pkg
try {
pkg = JSON.parse(fs.readFileSync(join(dir, 'package.json'), 'utf8'))
} catch {
continue
}

const optional = new Set(Object.keys(pkg.optionalDependencies || {}))
for (const dep of Object.keys(pkg.dependencies || {})) {
if (optional.has(dep)) {
continue
}
try {
req.resolve(dep, { paths: [dir] })
} catch {
missing.push(`${pkg.name || dir} -> ${dep}`)
}
}

const nodeModules = join(dir, 'node_modules')
let entries
try {
entries = fs.readdirSync(nodeModules, { withFileTypes: true })
} catch {
continue
}
for (const entry of entries) {
if (entry.name === '.bin') {
continue
}
const entryPath = join(nodeModules, entry.name)
if (entry.name.startsWith('@')) {
for (const scoped of fs.readdirSync(entryPath, { withFileTypes: true })) {
stack.push(join(entryPath, scoped.name))
}
} else {
stack.push(entryPath)
}
}
}

return missing.sort()
}

t.test('bundled production deps all resolve from the packed bundle', async t => {
const {
npm,
npmLocalTarball,
paths: { globalNodeModules },
} = await setup(t, {
testdir: {
project: {
'package.json': { name: 'npm', version: '999.999.999' },
},
},
})

const tarball = await npmLocalTarball()
await npm('install', tarball, '--global')

const npmRoot = join(globalNodeModules, 'npm')
const missing = findMissingDeps(npmRoot)

t.strictSame(
missing,
[],
'every non-optional production dependency resolves in the packed bundle'
)
})
Loading