Files
pnpm/packages/npm-resolver/test/index.ts
2021-10-17 17:45:03 +03:00

1695 lines
51 KiB
TypeScript

/// <reference path="../../../typings/index.d.ts"/>
import path from 'path'
import PnpmError from '@pnpm/error'
import { createFetchFromRegistry } from '@pnpm/fetch'
import _createResolveFromNpm, {
RegistryResponseError,
NoMatchingVersionError,
} from '@pnpm/npm-resolver'
import loadJsonFile from 'load-json-file'
import nock from 'nock'
import exists from 'path-exists'
import tempy from 'tempy'
/* eslint-disable @typescript-eslint/no-explicit-any */
const isPositiveMeta = loadJsonFile.sync<any>(path.join(__dirname, 'meta', 'is-positive.json'))
const isPositiveMetaWithDeprecated = loadJsonFile.sync<any>(path.join(__dirname, 'meta', 'is-positive-with-deprecated.json'))
const isPositiveMetaFull = loadJsonFile.sync<any>(path.join(__dirname, 'meta', 'is-positive-full.json'))
const isPositiveBrokenMeta = loadJsonFile.sync<any>(path.join(__dirname, 'meta', 'is-positive-broken.json'))
const sindresorhusIsMeta = loadJsonFile.sync<any>(path.join(__dirname, 'meta', 'sindresorhus-is.json'))
const jsonMeta = loadJsonFile.sync<any>(path.join(__dirname, 'meta', 'JSON.json'))
const brokenIntegrity = loadJsonFile.sync<any>(path.join(__dirname, 'meta', 'broken-integrity.json'))
/* eslint-enable @typescript-eslint/no-explicit-any */
const registry = 'https://registry.npmjs.org/'
const delay = async (time: number) => new Promise<void>((resolve) => setTimeout(() => resolve(), time))
const fetch = createFetchFromRegistry({})
const getCredentials = () => ({ authHeaderValue: undefined, alwaysAuth: undefined })
const createResolveFromNpm = _createResolveFromNpm.bind(null, fetch, getCredentials)
async function retryLoadJsonFile<T> (filePath: string) {
let retry = 0
while (true) {
await delay(500)
try {
return await loadJsonFile<T>(filePath)
} catch (err: any) { // eslint-disable-line
if (retry > 2) throw err
retry++
}
}
}
test('resolveFromNpm()', async () => {
nock(registry)
.get('/is-positive')
.reply(200, isPositiveMeta)
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({
cacheDir,
})
const resolveResult = await resolve({ alias: 'is-positive', pref: '1.0.0' }, {
registry,
})
expect(resolveResult!.resolvedVia).toBe('npm-registry')
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/1.0.0')
expect(resolveResult!.latest!.split('.').length).toBe(3)
expect(resolveResult!.resolution).toStrictEqual({
integrity: 'sha512-9cI+DmhNhA8ioT/3EJFnt0s1yehnAECyIOXdT+2uQGzcEEBaj8oNmVWj33+ZjPndMIFRQh8JeJlEu1uv5/J7pQ==',
registry,
tarball: 'https://registry.npmjs.org/is-positive/-/is-positive-1.0.0.tgz',
})
expect(resolveResult!.manifest).toBeTruthy()
expect(resolveResult!.manifest!.name).toBe('is-positive')
expect(resolveResult!.manifest!.version).toBe('1.0.0')
// The resolve function does not wait for the package meta cache file to be saved
// so we must delay for a bit in order to read it
const meta = await retryLoadJsonFile<any>(path.join(cacheDir, 'metadata/registry.npmjs.org/is-positive.json')) // eslint-disable-line @typescript-eslint/no-explicit-any
expect(meta.name).toBeTruthy()
expect(meta.versions).toBeTruthy()
expect(meta['dist-tags']).toBeTruthy()
})
test('resolveFromNpm() should save metadata to a unique file when the package name has upper case letters', async () => {
nock(registry)
.get('/JSON')
.reply(200, jsonMeta)
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({
cacheDir,
})
const resolveResult = await resolve({ alias: 'JSON', pref: '1.0.0' }, {
registry,
})
expect(resolveResult!.resolvedVia).toBe('npm-registry')
expect(resolveResult!.id).toBe('registry.npmjs.org/JSON/1.0.0')
// The resolve function does not wait for the package meta cache file to be saved
// so we must delay for a bit in order to read it
const meta = await retryLoadJsonFile<any>(path.join(cacheDir, 'metadata/registry.npmjs.org/JSON_0ecd11c1d7a287401d148a23bbd7a2f8.json')) // eslint-disable-line @typescript-eslint/no-explicit-any
expect(meta.name).toBeTruthy()
expect(meta.versions).toBeTruthy()
expect(meta['dist-tags']).toBeTruthy()
})
test('relative workspace protocol is skipped', async () => {
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({
cacheDir,
})
const resolveResult = await resolve({ pref: 'workspace:../is-positive' }, {
projectDir: '/home/istvan/src',
registry,
})
expect(resolveResult).toBe(null)
})
test('dry run', async () => {
nock(registry)
.get('/is-positive')
.reply(200, isPositiveMeta)
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({
cacheDir,
})
const resolveResult = await resolve({ alias: 'is-positive', pref: '1.0.0' }, {
dryRun: true,
registry,
})
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/1.0.0')
expect(resolveResult!.latest!.split('.').length).toBe(3)
expect(resolveResult!.resolution).toStrictEqual({
integrity: 'sha512-9cI+DmhNhA8ioT/3EJFnt0s1yehnAECyIOXdT+2uQGzcEEBaj8oNmVWj33+ZjPndMIFRQh8JeJlEu1uv5/J7pQ==',
registry,
tarball: 'https://registry.npmjs.org/is-positive/-/is-positive-1.0.0.tgz',
})
expect(resolveResult!.manifest).toBeTruthy()
expect(resolveResult!.manifest!.name).toBe('is-positive')
expect(resolveResult!.manifest!.version).toBe('1.0.0')
// The resolve function does not wait for the package meta cache file to be saved
// so we must delay for a bit in order to read it
await delay(500)
expect(await exists(path.join(cacheDir, resolveResult!.id, '..', 'index.json'))).toBeFalsy()
})
test('resolve to latest when no pref specified', async () => {
nock(registry)
.get('/is-positive')
.reply(200, isPositiveMeta)
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const resolveResult = await resolveFromNpm({ alias: 'is-positive' }, {
registry,
})
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/3.1.0')
})
test('resolve to defaultTag when no pref specified', async () => {
nock(registry)
.get('/is-positive')
.reply(200, isPositiveMeta)
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const resolveResult = await resolveFromNpm({ alias: 'is-positive' }, {
defaultTag: 'stable',
registry,
})
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/3.0.0')
})
test('resolve to biggest non-deprecated version that satisfies the range', async () => {
nock(registry)
.get('/is-positive')
.reply(200, isPositiveMetaWithDeprecated)
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const resolveResult = await resolveFromNpm({ alias: 'is-positive', pref: '3' }, {
registry,
})
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/3.0.0')
})
test('resolve to a deprecated version if there are no non-deprecated ones that satisfy the range', async () => {
nock(registry)
.get('/is-positive')
.reply(200, isPositiveMetaWithDeprecated)
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const resolveResult = await resolveFromNpm({ alias: 'is-positive', pref: '2' }, {
registry,
})
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/2.0.0')
})
test('can resolve aliased dependency', async () => {
nock(registry)
.get('/is-positive')
.reply(200, isPositiveMeta)
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const resolveResult = await resolveFromNpm({ alias: 'positive', pref: 'npm:is-positive@1.0.0' }, {
registry,
})
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/1.0.0')
})
test('can resolve aliased dependency w/o version specifier', async () => {
nock(registry)
.get('/is-positive')
.reply(200, isPositiveMeta)
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const resolveResult = await resolveFromNpm({ alias: 'positive', pref: 'npm:is-positive' }, {
registry,
})
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/3.1.0')
})
test('can resolve aliased dependency w/o version specifier to default tag', async () => {
nock(registry)
.get('/is-positive')
.reply(200, isPositiveMeta)
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const resolveResult = await resolveFromNpm({ alias: 'positive', pref: 'npm:is-positive' }, {
defaultTag: 'stable',
registry,
})
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/3.0.0')
})
test('can resolve aliased scoped dependency', async () => {
nock(registry)
.get('/@sindresorhus%2Fis')
.reply(200, sindresorhusIsMeta)
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const resolveResult = await resolveFromNpm({ alias: 'is', pref: 'npm:@sindresorhus/is@0.6.0' }, {
registry,
})
expect(resolveResult!.id).toBe('registry.npmjs.org/@sindresorhus/is/0.6.0')
})
test('can resolve aliased scoped dependency w/o version specifier', async () => {
nock(registry)
.get('/@sindresorhus%2Fis')
.reply(200, sindresorhusIsMeta)
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const resolveResult = await resolveFromNpm({ alias: 'is', pref: 'npm:@sindresorhus/is' }, {
registry,
})
expect(resolveResult!.id).toBe('registry.npmjs.org/@sindresorhus/is/0.7.0')
})
test('can resolve package with version prefixed with v', async () => {
nock(registry)
.get('/is-positive')
.reply(200, isPositiveMeta)
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const resolveResult = await resolveFromNpm({ alias: 'is-positive', pref: 'v1.0.0' }, {
registry,
})
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/1.0.0')
})
test('can resolve package version loosely', async () => {
nock(registry)
.get('/is-positive')
.reply(200, isPositiveMeta)
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const resolveResult = await resolveFromNpm({ alias: 'is-positive', pref: '= 1.0.0' }, {
registry,
})
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/1.0.0')
})
test("resolves to latest if it's inside the wanted range. Even if there are newer versions available inside the range", async () => {
nock(registry)
.get('/is-positive')
.reply(200, {
...isPositiveMeta,
'dist-tags': { latest: '3.0.0' },
})
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const resolveResult = await resolveFromNpm({
alias: 'is-positive',
pref: '^3.0.0',
}, {
registry,
})
// 3.1.0 is available but latest is 3.0.0, so preferring it
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/3.0.0')
})
test("resolves to latest if it's inside the preferred range. Even if there are newer versions available inside the preferred range", async () => {
nock(registry)
.get('/is-positive')
.reply(200, {
...isPositiveMeta,
'dist-tags': { latest: '3.0.0' },
})
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const resolveResult = await resolveFromNpm({
alias: 'is-positive',
pref: '^3.0.0',
}, {
preferredVersions: {
'is-positive': { '^3.0.0': 'range' },
},
registry,
})
// 3.1.0 is available but latest is 3.0.0, so preferring it
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/3.0.0')
})
test("resolve using the wanted range, when it doesn't intersect with the preferred range. Even if the preferred range contains the latest version", async () => {
nock(registry)
.get('/is-positive')
.reply(200, {
...isPositiveMeta,
'dist-tags': { latest: '2.0.0' },
})
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const resolveResult = await resolveFromNpm({
alias: 'is-positive',
pref: '^3.0.0',
}, {
preferredVersions: {
'is-positive': { '^2.0.0': 'range' },
},
registry,
})
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/3.1.0')
})
test("use the preferred version if it's inside the wanted range", async () => {
nock(registry)
.get('/is-positive')
.reply(200, {
...isPositiveMeta,
'dist-tags': { latest: '3.1.0' },
})
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const resolveResult = await resolveFromNpm({
alias: 'is-positive',
pref: '^3.0.0',
}, {
preferredVersions: {
'is-positive': { '3.0.0': 'version' },
},
registry,
})
// 3.1.0 is the latest but we prefer the 3.0.0
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/3.0.0')
})
test("ignore the preferred version if it's not inside the wanted range", async () => {
nock(registry)
.get('/is-positive')
.reply(200, {
...isPositiveMeta,
'dist-tags': { latest: '3.1.0' },
})
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const resolveResult = await resolveFromNpm({
alias: 'is-positive',
pref: '^3.0.0',
}, {
preferredVersions: {
'is-positive': { '2.0.0': 'version' },
},
registry,
})
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/3.1.0')
})
test('use the preferred range if it intersects with the wanted range', async () => {
nock(registry)
.get('/is-positive')
.reply(200, {
...isPositiveMeta,
'dist-tags': { latest: '1.0.0' },
})
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const resolveResult = await resolveFromNpm({
alias: 'is-positive',
pref: '>=1.0.0',
}, {
preferredVersions: {
'is-positive': { '^3.0.0': 'range' },
},
registry,
})
// 1.0.0 is the latest but we prefer a version that is also in the preferred range
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/3.1.0')
})
test('use the preferred range if it intersects with the wanted range (an array of preferred versions is passed)', async () => {
nock(registry)
.get('/is-positive')
.reply(200, {
...isPositiveMeta,
'dist-tags': { latest: '1.0.0' },
})
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const resolveResult = await resolveFromNpm({
alias: 'is-positive',
pref: '>=1.0.0',
}, {
preferredVersions: {
'is-positive': {
'3.0.0': 'version',
'3.1.0': 'version',
},
},
registry,
})
// 1.0.0 is the latest but we prefer a version that is also in the preferred range
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/3.1.0')
})
test("ignore the preferred range if it doesn't intersect with the wanted range", async () => {
nock(registry)
.get('/is-positive')
.reply(200, {
...isPositiveMeta,
'dist-tags': { latest: '3.1.0' },
})
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const resolveResult = await resolveFromNpm({
alias: 'is-positive',
pref: '^3.0.0',
}, {
preferredVersions: {
'is-positive': { '^2.0.0': 'range' },
},
registry,
})
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/3.1.0')
})
test("use the preferred dist-tag if it's inside the wanted range", async () => {
nock(registry)
.get('/is-positive')
.reply(200, {
...isPositiveMeta,
'dist-tags': {
latest: '3.1.0',
stable: '3.0.0',
},
})
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const resolveResult = await resolveFromNpm({
alias: 'is-positive',
pref: '^3.0.0',
}, {
preferredVersions: {
'is-positive': { stable: 'tag' },
},
registry,
})
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/3.0.0')
})
test("ignore the preferred dist-tag if it's not inside the wanted range", async () => {
nock(registry)
.get('/is-positive')
.reply(200, {
...isPositiveMeta,
'dist-tags': {
latest: '3.1.0',
stable: '2.0.0',
},
})
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const resolveResult = await resolveFromNpm({
alias: 'is-positive',
pref: '^3.0.0',
}, {
preferredVersions: {
'is-positive': { stable: 'tag' },
},
registry,
})
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/3.1.0')
})
test("prefer a version that is both inside the wanted and preferred ranges. Even if it's not the latest of any of them", async () => {
nock(registry)
.get('/is-positive')
.reply(200, {
...isPositiveMeta,
'dist-tags': {
latest: '3.0.0',
},
})
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const resolveResult = await resolveFromNpm({
alias: 'is-positive',
pref: '1.0.0 || 2.0.0',
}, {
preferredVersions: {
'is-positive': { '1.0.0 || 3.0.0': 'range' },
},
registry,
})
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/1.0.0')
})
test('offline resolution fails when package meta not found in the store', async () => {
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({
offline: true,
cacheDir,
})
await expect(resolve({ alias: 'is-positive', pref: '1.0.0' }, { registry })).rejects
.toThrow(
new PnpmError('NO_OFFLINE_META', `Failed to resolve is-positive@1.0.0 in package mirror ${path.join(cacheDir, 'metadata/registry.npmjs.org/is-positive.json')}`)
)
})
test('offline resolution succeeds when package meta is found in the store', async () => {
nock(registry)
.get('/is-positive')
.reply(200, isPositiveMeta)
const cacheDir = tempy.directory()
{
const resolve = createResolveFromNpm({
offline: false,
cacheDir,
})
// This request will save the package's meta in the store
await resolve({ alias: 'is-positive', pref: '1.0.0' }, { registry })
}
{
const resolve = createResolveFromNpm({
offline: true,
cacheDir,
})
const resolveResult = await resolve({ alias: 'is-positive', pref: '1.0.0' }, { registry })
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/1.0.0')
}
})
test('prefer offline resolution does not fail when package meta not found in the store', async () => {
nock(registry)
.get('/is-positive')
.reply(200, isPositiveMeta)
const resolve = createResolveFromNpm({
preferOffline: true,
cacheDir: tempy.directory(),
})
const resolveResult = await resolve({ alias: 'is-positive', pref: '1.0.0' }, { registry })
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/1.0.0')
})
test('when prefer offline is used, meta from store is used, where latest might be out-of-date', async () => {
nock(registry)
.get('/is-positive')
.reply(200, {
...isPositiveMeta,
'dist-tags': { latest: '3.0.0' },
})
const cacheDir = tempy.directory()
{
const resolve = createResolveFromNpm({
cacheDir,
})
// This request will save the package's meta in the store
await resolve({ alias: 'is-positive', pref: '1.0.0' }, { registry })
}
nock(registry)
.get('/is-positive')
.reply(200, {
...isPositiveMeta,
'dist-tags': { latest: '3.1.0' },
})
{
const resolve = createResolveFromNpm({
preferOffline: true,
cacheDir,
})
const resolveResult = await resolve({ alias: 'is-positive', pref: '^3.0.0' }, { registry })
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/3.0.0')
}
nock.cleanAll()
})
test('error is thrown when package is not found in the registry', async () => {
const notExistingPackage = 'foo'
nock(registry)
.get(`/${notExistingPackage}`)
.reply(404, {})
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
await expect(resolveFromNpm({ alias: notExistingPackage, pref: '1.0.0' }, { registry })).rejects
.toThrow(
new RegistryResponseError(
{
url: `${registry}${notExistingPackage}`,
},
{
status: 404,
// statusText: 'Not Found',
statusText: '',
},
notExistingPackage
)
)
})
test('error is thrown when registry not responding', async () => {
const notExistingPackage = 'foo'
const notExistingRegistry = 'http://not-existing.pnpm.io'
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
retry: { retries: 1 },
})
await expect(resolveFromNpm({ alias: notExistingPackage, pref: '1.0.0' }, { registry: notExistingRegistry })).rejects
.toThrow(new PnpmError('META_FETCH_FAIL', `GET ${notExistingRegistry}/${notExistingPackage}: request to ${notExistingRegistry}/${notExistingPackage} failed, reason: getaddrinfo ENOTFOUND not-existing.pnpm.io`, { attempts: 1 }))
})
test('extra info is shown if package has valid semver appended', async () => {
const notExistingPackage = 'foo1.0.0'
nock(registry)
.get(`/${notExistingPackage}`)
.reply(404, {})
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
await expect(resolveFromNpm({ alias: notExistingPackage, pref: '1.0.0' }, { registry })).rejects
.toThrow(
new RegistryResponseError(
{
url: `${registry}${notExistingPackage}`,
},
{
status: 404,
// statusText: 'Not Found',
statusText: '',
},
notExistingPackage
)
)
})
test('error is thrown when there is no package found for the requested version', async () => {
nock(registry)
.get('/is-positive')
.reply(200, isPositiveMeta)
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const wantedDependency = { alias: 'is-positive', pref: '1000.0.0' }
await expect(resolveFromNpm(wantedDependency, { registry })).rejects
.toThrow(
new NoMatchingVersionError({
wantedDependency,
packageMeta: isPositiveMeta,
})
)
})
test('error is thrown when package needs authorization', async () => {
nock(registry)
.get('/needs-auth')
.reply(403)
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
await expect(resolveFromNpm({ alias: 'needs-auth', pref: '*' }, { registry })).rejects
.toThrow(
new RegistryResponseError(
{
url: `${registry}needs-auth`,
},
{
status: 403,
// statusText: 'Forbidden',
statusText: '',
},
'needs-auth'
)
)
})
test('error is thrown when there is no package found for the requested range', async () => {
nock(registry)
.get('/is-positive')
.reply(200, isPositiveMeta)
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const wantedDependency = { alias: 'is-positive', pref: '^1000.0.0' }
await expect(resolveFromNpm(wantedDependency, { registry })).rejects
.toThrow(
new NoMatchingVersionError({
wantedDependency,
packageMeta: isPositiveMeta,
})
)
})
test('error is thrown when there is no package found for the requested tag', async () => {
nock(registry)
.get('/is-positive')
.reply(200, isPositiveMeta)
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const wantedDependency = { alias: 'is-positive', pref: 'unknown-tag' }
await expect(resolveFromNpm(wantedDependency, { registry })).rejects
.toThrow(
new NoMatchingVersionError({
wantedDependency,
packageMeta: isPositiveMeta,
})
)
})
test('resolveFromNpm() loads full metadata even if non-full metadata is alread cached in store', async () => {
nock(registry)
.get('/is-positive')
.reply(200, isPositiveMeta)
.get('/is-positive')
.reply(200, isPositiveMetaFull)
const cacheDir = tempy.directory()
{
const resolve = createResolveFromNpm({
fullMetadata: false,
cacheDir,
})
const resolveResult = await resolve({ alias: 'is-positive', pref: '1.0.0' }, {
registry,
})
expect(resolveResult!.manifest!['scripts']).toBeFalsy()
}
{
const resolve = createResolveFromNpm({
fullMetadata: true,
cacheDir,
})
const resolveResult = await resolve({ alias: 'is-positive', pref: '1.0.0' }, {
registry,
})
expect(resolveResult!.manifest!['scripts']).toBeTruthy()
}
})
test('resolve when tarball URL is requested from the registry', async () => {
nock(registry)
.get('/is-positive')
.reply(200, isPositiveMeta)
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({
cacheDir,
})
const resolveResult = await resolve({ alias: 'is-positive', pref: `${registry}is-positive/-/is-positive-1.0.0.tgz` }, {
registry,
})
expect(resolveResult!.resolvedVia).toBe('npm-registry')
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/1.0.0')
expect(resolveResult!.latest!.split('.').length).toBe(3)
expect(resolveResult!.resolution).toStrictEqual({
integrity: 'sha512-9cI+DmhNhA8ioT/3EJFnt0s1yehnAECyIOXdT+2uQGzcEEBaj8oNmVWj33+ZjPndMIFRQh8JeJlEu1uv5/J7pQ==',
registry,
tarball: 'https://registry.npmjs.org/is-positive/-/is-positive-1.0.0.tgz',
})
expect(resolveResult!.manifest).toBeTruthy()
expect(resolveResult!.manifest!.name).toBe('is-positive')
expect(resolveResult!.manifest!.version).toBe('1.0.0')
expect(resolveResult!.normalizedPref).toBe(`${registry}is-positive/-/is-positive-1.0.0.tgz`)
// The resolve function does not wait for the package meta cache file to be saved
// so we must delay for a bit in order to read it
const meta = await retryLoadJsonFile<any>(path.join(cacheDir, 'metadata/registry.npmjs.org/is-positive.json')) // eslint-disable-line @typescript-eslint/no-explicit-any
expect(meta.name).toBeTruthy()
expect(meta.versions).toBeTruthy()
expect(meta['dist-tags']).toBeTruthy()
})
test('resolve when tarball URL is requested from the registry and alias is not specified', async () => {
nock(registry)
.get('/is-positive')
.reply(200, isPositiveMeta)
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({
cacheDir,
})
const resolveResult = await resolve({ pref: `${registry}is-positive/-/is-positive-1.0.0.tgz` }, {
registry,
})
expect(resolveResult!.resolvedVia).toBe('npm-registry')
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/1.0.0')
expect(resolveResult!.latest!.split('.').length).toBe(3)
expect(resolveResult!.resolution).toStrictEqual({
integrity: 'sha512-9cI+DmhNhA8ioT/3EJFnt0s1yehnAECyIOXdT+2uQGzcEEBaj8oNmVWj33+ZjPndMIFRQh8JeJlEu1uv5/J7pQ==',
registry,
tarball: 'https://registry.npmjs.org/is-positive/-/is-positive-1.0.0.tgz',
})
expect(resolveResult!.manifest).toBeTruthy()
expect(resolveResult!.manifest!.name).toBe('is-positive')
expect(resolveResult!.manifest!.version).toBe('1.0.0')
expect(resolveResult!.normalizedPref).toBe(`${registry}is-positive/-/is-positive-1.0.0.tgz`)
// The resolve function does not wait for the package meta cache file to be saved
// so we must delay for a bit in order to read it
const meta = await retryLoadJsonFile<any>(path.join(cacheDir, 'metadata/registry.npmjs.org/is-positive.json')) // eslint-disable-line @typescript-eslint/no-explicit-any
expect(meta.name).toBeTruthy()
expect(meta.versions).toBeTruthy()
expect(meta['dist-tags']).toBeTruthy()
})
test('resolve from local directory when it matches the latest version of the package', async () => {
nock(registry)
.get('/is-positive')
.reply(200, isPositiveMeta)
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({
cacheDir,
})
const resolveResult = await resolve({ alias: 'is-positive', pref: '1.0.0' }, {
projectDir: '/home/istvan/src',
registry,
workspacePackages: {
'is-positive': {
'1.0.0': {
dir: '/home/istvan/src/is-positive',
manifest: {
name: 'is-positive',
version: '1.0.0',
},
},
},
},
})
expect(resolveResult!.resolvedVia).toBe('local-filesystem')
expect(resolveResult!.id).toBe('link:is-positive')
expect(resolveResult!.latest!.split('.').length).toBe(3)
expect(resolveResult!.resolution).toStrictEqual({
directory: '/home/istvan/src/is-positive',
type: 'directory',
})
expect(resolveResult!.manifest).toBeTruthy()
expect(resolveResult!.manifest!.name).toBe('is-positive')
expect(resolveResult!.manifest!.version).toBe('1.0.0')
})
test('do not resolve from local directory when alwaysTryWorkspacePackages is false', async () => {
nock(registry)
.get('/is-positive')
.reply(200, isPositiveMeta)
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({
cacheDir,
})
const resolveResult = await resolve({ alias: 'is-positive', pref: '1.0.0' }, {
alwaysTryWorkspacePackages: false,
projectDir: '/home/istvan/src',
registry,
workspacePackages: {
'is-positive': {
'1.0.0': {
dir: '/home/istvan/src/is-positive',
manifest: {
name: 'is-positive',
version: '1.0.0',
},
},
},
},
})
expect(resolveResult!.resolvedVia).toBe('npm-registry')
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/1.0.0')
expect(resolveResult!.latest!.split('.').length).toBe(3)
expect(resolveResult!.resolution).toStrictEqual({
integrity: 'sha512-9cI+DmhNhA8ioT/3EJFnt0s1yehnAECyIOXdT+2uQGzcEEBaj8oNmVWj33+ZjPndMIFRQh8JeJlEu1uv5/J7pQ==',
registry,
tarball: 'https://registry.npmjs.org/is-positive/-/is-positive-1.0.0.tgz',
})
expect(resolveResult!.manifest).toBeTruthy()
expect(resolveResult!.manifest!.name).toBe('is-positive')
expect(resolveResult!.manifest!.version).toBe('1.0.0')
})
test('resolve from local directory when alwaysTryWorkspacePackages is false but workspace: is used', async () => {
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({
cacheDir,
})
const resolveResult = await resolve({ alias: 'is-positive', pref: 'workspace:*' }, {
alwaysTryWorkspacePackages: false,
projectDir: '/home/istvan/src',
registry,
workspacePackages: {
'is-positive': {
'1.0.0': {
dir: '/home/istvan/src/is-positive',
manifest: {
name: 'is-positive',
version: '1.0.0',
},
},
},
},
})
expect(resolveResult!.resolvedVia).toBe('local-filesystem')
expect(resolveResult!.id).toBe('link:is-positive')
expect(resolveResult!.resolution).toStrictEqual({
directory: '/home/istvan/src/is-positive',
type: 'directory',
})
expect(resolveResult!.manifest).toBeTruthy()
expect(resolveResult!.manifest!.name).toBe('is-positive')
expect(resolveResult!.manifest!.version).toBe('1.0.0')
})
test('resolve from local directory when alwaysTryWorkspacePackages is false but workspace: is used with a different package name', async () => {
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({
cacheDir,
})
const resolveResult = await resolve({ alias: 'positive', pref: 'workspace:is-positive@*' }, {
alwaysTryWorkspacePackages: false,
projectDir: '/home/istvan/src',
registry,
workspacePackages: {
'is-positive': {
'1.0.0': {
dir: '/home/istvan/src/is-positive',
manifest: {
name: 'is-positive',
version: '1.0.0',
},
},
},
},
})
expect(resolveResult!.resolvedVia).toBe('local-filesystem')
expect(resolveResult!.id).toBe('link:is-positive')
expect(resolveResult!.resolution).toStrictEqual({
directory: '/home/istvan/src/is-positive',
type: 'directory',
})
expect(resolveResult!.manifest).toBeTruthy()
expect(resolveResult!.manifest!.name).toBe('is-positive')
expect(resolveResult!.manifest!.version).toBe('1.0.0')
})
test('use version from the registry if it is newer than the local one', async () => {
nock(registry)
.get('/is-positive')
.reply(200, {
...isPositiveMeta,
'dist-tags': { latest: '3.1.0' },
})
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const resolveResult = await resolveFromNpm({
alias: 'is-positive',
pref: '^3.0.0',
}, {
projectDir: '/home/istvan/src',
registry,
workspacePackages: {
'is-positive': {
'3.0.0': {
dir: '/home/istvan/src/is-positive',
manifest: {
name: 'is-positive',
version: '3.0.0',
},
},
},
},
})
expect(resolveResult!.resolvedVia).toBe('npm-registry')
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/3.1.0')
expect(resolveResult!.latest!.split('.').length).toBe(3)
expect(resolveResult!.resolution).toStrictEqual({
integrity: 'sha512-9Qa5b+9n69IEuxk4FiNcavXqkixb9lD03BLtdTeu2bbORnLZQrw+pR/exiSg7SoODeu08yxS47mdZa9ddodNwQ==',
registry,
tarball: 'https://registry.npmjs.org/is-positive/-/is-positive-3.1.0.tgz',
})
expect(resolveResult!.manifest).toBeTruthy()
expect(resolveResult!.manifest!.name).toBe('is-positive')
expect(resolveResult!.manifest!.version).toBe('3.1.0')
})
test('preferWorkspacePackages: use version from the workspace even if there is newer version in the registry', async () => {
nock(registry)
.get('/is-positive')
.reply(200, {
...isPositiveMeta,
'dist-tags': { latest: '3.1.0' },
})
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const resolveResult = await resolveFromNpm({
alias: 'is-positive',
pref: '^3.0.0',
}, {
preferWorkspacePackages: true,
projectDir: '/home/istvan/src',
registry,
workspacePackages: {
'is-positive': {
'3.0.0': {
dir: '/home/istvan/src/is-positive',
manifest: {
name: 'is-positive',
version: '3.0.0',
},
},
},
},
})
expect(resolveResult).toStrictEqual(
expect.objectContaining({
resolvedVia: 'local-filesystem',
id: 'link:is-positive',
latest: '3.1.0',
})
)
})
test('use local version if it is newer than the latest in the registry', async () => {
nock(registry)
.get('/is-positive')
.reply(200, {
...isPositiveMeta,
'dist-tags': { latest: '3.1.0' },
})
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
const resolveResult = await resolveFromNpm({
alias: 'is-positive',
pref: '^3.0.0',
}, {
projectDir: '/home/istvan/src',
registry,
workspacePackages: {
'is-positive': {
'3.2.0': {
dir: '/home/istvan/src/is-positive',
manifest: {
name: 'is-positive',
version: '3.2.0',
},
},
},
},
})
expect(resolveResult!.resolvedVia).toBe('local-filesystem')
expect(resolveResult!.id).toBe('link:is-positive')
expect(resolveResult!.latest!.split('.').length).toBe(3)
expect(resolveResult!.resolution).toStrictEqual({
directory: '/home/istvan/src/is-positive',
type: 'directory',
})
expect(resolveResult!.manifest).toBeTruthy()
expect(resolveResult!.manifest!.name).toBe('is-positive')
expect(resolveResult!.manifest!.version).toBe('3.2.0')
})
test('resolve from local directory when package is not found in the registry', async () => {
nock(registry)
.get('/is-positive')
.reply(404, {})
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({
cacheDir,
})
const resolveResult = await resolve({ alias: 'is-positive', pref: '1' }, {
projectDir: '/home/istvan/src/foo',
registry,
workspacePackages: {
'is-positive': {
'1.0.0': {
dir: '/home/istvan/src/is-positive-1.0.0',
manifest: {
name: 'is-positive',
version: '1.0.0',
},
},
'1.1.0': {
dir: '/home/istvan/src/is-positive',
manifest: {
name: 'is-positive',
version: '1.1.0',
},
},
'2.0.0': {
dir: '/home/istvan/src/is-positive-2.0.0',
manifest: {
name: 'is-positive',
version: '2.0.0',
},
},
},
},
})
expect(resolveResult!.resolvedVia).toBe('local-filesystem')
expect(resolveResult!.id).toBe('link:../is-positive')
expect(resolveResult!.latest).toBeFalsy()
expect(resolveResult!.resolution).toStrictEqual({
directory: '/home/istvan/src/is-positive',
type: 'directory',
})
expect(resolveResult!.manifest).toBeTruthy()
expect(resolveResult!.manifest!.name).toBe('is-positive')
expect(resolveResult!.manifest!.version).toBe('1.1.0')
})
test('resolve from local directory when package is not found in the registry and latest installed', async () => {
nock(registry)
.get('/is-positive')
.reply(404, {})
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({
cacheDir,
})
const resolveResult = await resolve({ alias: 'is-positive', pref: 'latest' }, {
projectDir: '/home/istvan/src',
registry,
workspacePackages: {
'is-positive': {
'1.0.0': {
dir: '/home/istvan/src/is-positive-1.0.0',
manifest: {
name: 'is-positive',
version: '1.0.0',
},
},
'1.1.0': {
dir: '/home/istvan/src/is-positive',
manifest: {
name: 'is-positive',
version: '1.1.0',
},
},
'2.0.0': {
dir: '/home/istvan/src/is-positive-2.0.0',
manifest: {
name: 'is-positive',
version: '2.0.0',
},
},
},
},
})
expect(resolveResult!.resolvedVia).toBe('local-filesystem')
expect(resolveResult!.id).toBe('link:is-positive-2.0.0')
expect(resolveResult!.latest).toBeFalsy()
expect(resolveResult!.resolution).toStrictEqual({
directory: '/home/istvan/src/is-positive-2.0.0',
type: 'directory',
})
expect(resolveResult!.manifest).toBeTruthy()
expect(resolveResult!.manifest!.name).toBe('is-positive')
expect(resolveResult!.manifest!.version).toBe('2.0.0')
})
test('resolve from local directory when package is not found in the registry and specific version is requested', async () => {
nock(registry)
.get('/is-positive')
.reply(404, {})
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({
cacheDir,
})
const resolveResult = await resolve({ alias: 'is-positive', pref: '1.1.0' }, {
projectDir: '/home/istvan/src/foo',
registry,
workspacePackages: {
'is-positive': {
'1.0.0': {
dir: '/home/istvan/src/is-positive-1.0.0',
manifest: {
name: 'is-positive',
version: '1.0.0',
},
},
'1.1.0': {
dir: '/home/istvan/src/is-positive',
manifest: {
name: 'is-positive',
version: '1.1.0',
},
},
'2.0.0': {
dir: '/home/istvan/src/is-positive-2.0.0',
manifest: {
name: 'is-positive',
version: '2.0.0',
},
},
},
},
})
expect(resolveResult!.resolvedVia).toBe('local-filesystem')
expect(resolveResult!.id).toBe('link:../is-positive')
expect(resolveResult!.latest).toBeFalsy()
expect(resolveResult!.resolution).toStrictEqual({
directory: '/home/istvan/src/is-positive',
type: 'directory',
})
expect(resolveResult!.manifest).toBeTruthy()
expect(resolveResult!.manifest!.name).toBe('is-positive')
expect(resolveResult!.manifest!.version).toBe('1.1.0')
})
test('resolve from local directory when the requested version is not found in the registry but is available locally', async () => {
nock(registry)
.get('/is-positive')
.reply(200, isPositiveMeta)
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({
cacheDir,
})
const resolveResult = await resolve({ alias: 'is-positive', pref: '100.0.0' }, {
projectDir: '/home/istvan/src/foo',
registry,
workspacePackages: {
'is-positive': {
'100.0.0': {
dir: '/home/istvan/src/is-positive',
manifest: {
name: 'is-positive',
version: '100.0.0',
},
},
},
},
})
expect(resolveResult!.resolvedVia).toBe('local-filesystem')
expect(resolveResult!.id).toBe('link:../is-positive')
expect(resolveResult!.latest).toBeFalsy()
expect(resolveResult!.resolution).toStrictEqual({
directory: '/home/istvan/src/is-positive',
type: 'directory',
})
expect(resolveResult!.manifest).toBeTruthy()
expect(resolveResult!.manifest!.name).toBe('is-positive')
expect(resolveResult!.manifest!.version).toBe('100.0.0')
})
test('workspace protocol: resolve from local directory even when it does not match the latest version of the package', async () => {
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({
cacheDir,
})
const resolveResult = await resolve({ alias: 'is-positive', pref: 'workspace:^3.0.0' }, {
projectDir: '/home/istvan/src',
registry,
workspacePackages: {
'is-positive': {
'3.0.0': {
dir: '/home/istvan/src/is-positive',
manifest: {
name: 'is-positive',
version: '3.0.0',
},
},
},
},
})
expect(resolveResult!.resolvedVia).toBe('local-filesystem')
expect(resolveResult!.id).toBe('link:is-positive')
expect(resolveResult!.latest).toBeFalsy()
expect(resolveResult!.resolution).toStrictEqual({
directory: '/home/istvan/src/is-positive',
type: 'directory',
})
expect(resolveResult!.manifest).toBeTruthy()
expect(resolveResult!.manifest!.name).toBe('is-positive')
expect(resolveResult!.manifest!.version).toBe('3.0.0')
})
test('workspace protocol: resolve from local package that has a pre-release version', async () => {
nock(registry)
.get('/is-positive')
.reply(200, isPositiveMeta)
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({
cacheDir,
})
const resolveResult = await resolve({ alias: 'is-positive', pref: 'workspace:*' }, {
projectDir: '/home/istvan/src',
registry,
workspacePackages: {
'is-positive': {
'3.0.0-alpha.1.2.3': {
dir: '/home/istvan/src/is-positive',
manifest: {
name: 'is-positive',
version: '3.0.0-alpha.1.2.3',
},
},
},
},
})
expect(resolveResult!.resolvedVia).toBe('local-filesystem')
expect(resolveResult!.id).toBe('link:is-positive')
expect(resolveResult!.latest).toBeFalsy()
expect(resolveResult!.resolution).toStrictEqual({
directory: '/home/istvan/src/is-positive',
type: 'directory',
})
expect(resolveResult!.manifest).toBeTruthy()
expect(resolveResult!.manifest!.name).toBe('is-positive')
expect(resolveResult!.manifest!.version).toBe('3.0.0-alpha.1.2.3')
})
test("workspace protocol: don't resolve from local package that has a pre-release version that don't satisfy the range", async () => {
nock(registry)
.get('/is-positive')
.reply(200, isPositiveMeta)
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({
cacheDir,
})
const resolveResult = await resolve({ alias: 'is-positive', pref: '2' }, {
projectDir: '/home/istvan/src',
registry,
workspacePackages: {
'is-positive': {
'3.0.0-alpha.1.2.3': {
dir: '/home/istvan/src/is-positive',
manifest: {
name: 'is-positive',
version: '3.0.0-alpha.1.2.3',
},
},
},
},
})
expect(resolveResult!.resolvedVia).toBe('npm-registry')
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/2.0.0')
expect(resolveResult!.latest).toBeTruthy()
expect(resolveResult!.manifest).toBeTruthy()
expect(resolveResult!.manifest!.name).toBe('is-positive')
expect(resolveResult!.manifest!.version).toBe('2.0.0')
})
test('workspace protocol: resolution fails if there is no matching local package', async () => {
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({
cacheDir,
})
const projectDir = '/home/istvan/src'
let err!: Error
try {
await resolve({ alias: 'is-positive', pref: 'workspace:^3.0.0' }, {
projectDir,
registry,
workspacePackages: {},
})
} catch (_err: any) { // eslint-disable-line
err = _err
}
expect(err).toBeTruthy()
expect(err['code']).toBe('ERR_PNPM_NO_MATCHING_VERSION_INSIDE_WORKSPACE')
expect(err.message).toBe(`In ${path.relative(process.cwd(), projectDir)}: No matching version found for is-positive@^3.0.0 inside the workspace`)
})
test('workspace protocol: resolution fails if there are no local packages', async () => {
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({
cacheDir,
})
let err!: Error
try {
await resolve({ alias: 'is-positive', pref: 'workspace:^3.0.0' }, {
projectDir: '/home/istvan/src',
registry,
})
} catch (_err: any) { // eslint-disable-line
err = _err
}
expect(err).toBeTruthy()
expect(err.message).toBe('Cannot resolve package from workspace because opts.workspacePackages is not defined')
})
test('throws error when package name has "/" but not starts with @scope', async () => {
const resolveFromNpm = createResolveFromNpm({
cacheDir: tempy.directory(),
})
await expect(resolveFromNpm({ alias: 'regenerator/runtime' }, { registry })).rejects
.toThrow(
new PnpmError('INVALID_PACKAGE_NAME', 'Package name regenerator/runtime is invalid, it should have a @scope')
)
})
test('resolveFromNpm() should always return the name of the package that is specified in the root of the meta', async () => {
nock(registry)
.get('/is-positive')
.reply(200, isPositiveBrokenMeta)
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({
cacheDir,
})
const resolveResult = await resolve({ alias: 'is-positive', pref: '3.1.0' }, {
registry,
})
expect(resolveResult!.resolvedVia).toBe('npm-registry')
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/3.1.0')
expect(resolveResult!.latest!.split('.').length).toBe(3)
expect(resolveResult!.resolution).toStrictEqual({
integrity: 'sha512-9Qa5b+9n69IEuxk4FiNcavXqkixb9lD03BLtdTeu2bbORnLZQrw+pR/exiSg7SoODeu08yxS47mdZa9ddodNwQ==',
registry,
tarball: 'https://registry.npmjs.org/is-positive/-/is-positive-3.1.0.tgz',
})
expect(resolveResult!.manifest).toBeTruthy()
expect(resolveResult!.manifest!.name).toBe('is-positive')
expect(resolveResult!.manifest!.version).toBe('3.1.0')
// The resolve function does not wait for the package meta cache file to be saved
// so we must delay for a bit in order to read it
const meta = await retryLoadJsonFile<any>(path.join(cacheDir, 'metadata/registry.npmjs.org/is-positive.json')) // eslint-disable-line @typescript-eslint/no-explicit-any
expect(meta.name).toBeTruthy()
expect(meta.versions).toBeTruthy()
expect(meta['dist-tags']).toBeTruthy()
})
test('request to metadata is retried if the received JSON is broken', async () => {
const registry = 'https://registry1.com/'
nock(registry)
.get('/is-positive')
.reply(200, '{')
nock(registry)
.get('/is-positive')
.reply(200, isPositiveMeta)
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({
retry: { retries: 1 },
cacheDir,
})
const resolveResult = await resolve({ alias: 'is-positive', pref: '1.0.0' }, {
registry,
})!
expect(resolveResult?.id).toBe('registry.npmjs.org/is-positive/1.0.0')
})
test('request to a package with malformed metadata', async () => {
nock(registry)
.get('/code-snippet')
.reply(200, loadJsonFile.sync(path.join(__dirname, 'meta/malformed.json')))
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({ cacheDir })
await expect(resolve({ alias: 'code-snippet' }, { registry })).rejects
.toThrow(
new PnpmError('MALFORMED_METADATA', 'Received malformed metadata for "code-snippet"')
)
})
test('resolve workspace:^', async () => {
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({
cacheDir,
})
const resolveResult = await resolve({ alias: 'is-positive', pref: 'workspace:^' }, {
projectDir: '/home/istvan/src',
registry,
workspacePackages: {
'is-positive': {
'1.0.0': {
dir: '/home/istvan/src/is-positive',
manifest: {
name: 'is-positive',
version: '1.0.0',
},
},
},
},
})
expect(resolveResult!.resolvedVia).toBe('local-filesystem')
expect(resolveResult!.id).toBe('link:is-positive')
expect(resolveResult!.resolution).toStrictEqual({
directory: '/home/istvan/src/is-positive',
type: 'directory',
})
expect(resolveResult!.manifest).toBeTruthy()
expect(resolveResult!.manifest!.name).toBe('is-positive')
expect(resolveResult!.manifest!.version).toBe('1.0.0')
})
test('resolve workspace:~', async () => {
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({
cacheDir,
})
const resolveResult = await resolve({ alias: 'is-positive', pref: 'workspace:~' }, {
projectDir: '/home/istvan/src',
registry,
workspacePackages: {
'is-positive': {
'1.0.0': {
dir: '/home/istvan/src/is-positive',
manifest: {
name: 'is-positive',
version: '1.0.0',
},
},
},
},
})
expect(resolveResult!.resolvedVia).toBe('local-filesystem')
expect(resolveResult!.id).toBe('link:is-positive')
expect(resolveResult!.resolution).toStrictEqual({
directory: '/home/istvan/src/is-positive',
type: 'directory',
})
expect(resolveResult!.manifest).toBeTruthy()
expect(resolveResult!.manifest!.name).toBe('is-positive')
expect(resolveResult!.manifest!.version).toBe('1.0.0')
})
test('resolveFromNpm() does not fail if the meta file contains no integrity information', async () => {
nock(registry)
.get('/is-positive')
.reply(200, brokenIntegrity)
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({
cacheDir,
})
const resolveResult = await resolve({ alias: 'is-positive', pref: '2.0.0' }, {
registry,
})
expect(resolveResult!.resolvedVia).toBe('npm-registry')
expect(resolveResult!.id).toBe('registry.npmjs.org/is-positive/2.0.0')
expect(resolveResult!.latest!.split('.').length).toBe(3)
expect(resolveResult!.resolution).toStrictEqual({
integrity: undefined,
registry,
tarball: 'https://registry.npmjs.org/is-positive/-/is-positive-2.0.0.tgz',
})
expect(resolveResult!.manifest).toBeTruthy()
expect(resolveResult!.manifest!.name).toBe('is-positive')
expect(resolveResult!.manifest!.version).toBe('2.0.0')
})
test('resolveFromNpm() fails if the meta file contains invalid shasum', async () => {
nock(registry)
.get('/is-positive')
.reply(200, brokenIntegrity)
const cacheDir = tempy.directory()
const resolve = createResolveFromNpm({
cacheDir,
})
await expect(
resolve({ alias: 'is-positive', pref: '1.0.0' }, { registry })
).rejects.toThrow('Tarball "https://registry.npmjs.org/is-positive/-/is-positive-1.0.0.tgz" has invalid shasum specified in its metadata: a')
})