Skip to content
Snippets Groups Projects
Select Git revision
  • 292993f0c6ad0e12ada4eae54281727110145808
  • main default protected
  • next
  • fix/36615b-branch-reuse-no-cache
  • renovate/main-redis-5.x
  • chore/punycode
  • refactor/pin-new-value
  • feat/36219--git-x509-signing
  • feat/structured-logger
  • hotfix/39.264.1
  • feat/skip-dangling
  • gh-readonly-queue/next/pr-36034-7a061c4ca1024a19e2c295d773d9642625d1c2be
  • hotfix/39.238.3
  • refactor/gitlab-auto-approve
  • feat/template-strings
  • gh-readonly-queue/next/pr-35654-137d934242c784e0c45d4b957362214f0eade1d7
  • fix/32307-global-extends-merging
  • fix/32307-global-extends-repositories
  • gh-readonly-queue/next/pr-35009-046ebf7cb84ab859f7fefceb5fa53a54ce9736f8
  • gh-readonly-queue/next/pr-35009-9d5e583b7d7251148ab0d11ee8dd38149618d162
  • gh-readonly-queue/next/pr-35009-a70e4ea7c6484aef873585a7f22ee2f796c58cb5
  • 41.42.9
  • 41.42.8
  • 41.42.7
  • 41.42.6
  • 41.42.5
  • 41.42.4
  • 41.42.3
  • 41.42.2
  • 41.42.1
  • 41.42.0
  • 41.41.0
  • 41.40.0
  • 41.39.0
  • 41.38.2
  • 41.38.1
  • 41.38.0
  • 41.37.12
  • 41.37.11
  • 41.37.10
  • 41.37.9
41 results

index.spec.ts

Blame
  • user avatar
    Michael Kriese authored and GitHub committed
    26c03731
    History
    index.spec.ts 12.55 KiB
    import _registryAuthToken from 'registry-auth-token';
    import nock from 'nock';
    import moment from 'moment';
    import * as npm from '.';
    import { DATASOURCE_FAILURE } from '../../constants/error-messages';
    
    jest.mock('registry-auth-token');
    jest.mock('delay');
    
    const registryAuthToken: any = _registryAuthToken;
    let npmResponse: any;
    
    function getRelease(
      dependency: { releases: { version: string; canBeUnpublished?: boolean }[] },
      version: string
    ) {
      return dependency.releases.find(
        (release: { version: string }) => release.version === version
      );
    }
    
    describe('api/npm', () => {
      delete process.env.NPM_TOKEN;
      beforeEach(() => {
        jest.resetAllMocks();
        global.repoCache = {};
        global.trustLevel = 'low';
        npm.resetCache();
        npmResponse = {
          name: 'foobar',
          versions: {
            '0.0.1': {
              foo: 1,
            },
            '0.0.2': {
              foo: 2,
            },
          },
          repository: {
            type: 'git',
            url: 'git://github.com/renovateapp/dummy.git',
            directory: 'src/a',
          },
          homepage: 'https://github.com/renovateapp/dummy',
          'dist-tags': {
            latest: '0.0.1',
          },
          time: {
            '0.0.1': '2018-05-06T07:21:53+02:00',
            '0.0.2': '2018-05-07T07:21:53+02:00',
          },
        };
        nock.cleanAll();
        return global.renovateCache.rmAll();
      });
      afterEach(() => {
        delete process.env.RENOVATE_CACHE_NPM_MINUTES;
      });
      it('should return null for no versions', async () => {
        const missingVersions = { ...npmResponse };
        missingVersions.versions = {};
        nock('https://registry.npmjs.org')
          .get('/foobar')
          .reply(200, missingVersions);
        const res = await npm.getPkgReleases({ lookupName: 'foobar' });
        expect(res).toBeNull();
      });
      it('should fetch package info from npm', async () => {
        nock('https://registry.npmjs.org')
          .get('/foobar')
          .reply(200, npmResponse);
        const res = await npm.getPkgReleases({ lookupName: 'foobar' });
        expect(res).toMatchSnapshot();
        expect(getRelease(res, '0.0.1').canBeUnpublished).toBe(false);
        expect(getRelease(res, '0.0.2').canBeUnpublished).toBe(false);
      });
      it('should throw if no package', async () => {
        nock('https://registry.npmjs.org')
          .get('/foobar')
          .reply(404);
        await expect(npm.getPreset('foobar', 'default')).rejects.toThrow(
          /dep not found/
        );
      });
      it('should throw if no renovate-config', async () => {
        const presetPackage = {
          name: 'foobar',
          versions: {
            '0.0.1': {
              foo: 1,
            },
            '0.0.2': {
              foo: 2,
              deprecated: 'This is deprecated',
            },
          },
          repository: {
            type: 'git',
            url: 'git://github.com/renovateapp/dummy.git',
          },
          'dist-tags': {
            latest: '0.0.2',
          },
          time: {
            '0.0.1': '2018-05-06T07:21:53+02:00',
            '0.0.2': '2018-05-07T07:21:53+02:00',
          },
        };
        nock('https://registry.npmjs.org')
          .get('/foobar')
          .reply(200, presetPackage);
        await expect(npm.getPreset('foobar', 'default')).rejects.toThrow(
          /preset renovate-config not found/
        );
      });
      it('should throw if no preset name not found', async () => {
        const presetPackage = {
          name: 'foobar',
          versions: {
            '0.0.1': {
              foo: 1,
            },
            '0.0.2': {
              foo: 2,
              deprecated: 'This is deprecated',
              'renovate-config': { default: { rangeStrategy: 'auto' } },
            },
          },
          repository: {
            type: 'git',
            url: 'git://github.com/renovateapp/dummy.git',
          },
          'dist-tags': {
            latest: '0.0.2',
          },
          time: {
            '0.0.1': '2018-05-06T07:21:53+02:00',
            '0.0.2': '2018-05-07T07:21:53+02:00',
          },
        };
        nock('https://registry.npmjs.org')
          .get('/foobar')
          .reply(200, presetPackage);
        await expect(npm.getPreset('foobar', 'missing')).rejects.toThrow(
          /preset not found/
        );
      });
      it('should return preset', async () => {
        const presetPackage = {
          name: 'foobar',
          versions: {
            '0.0.1': {
              foo: 1,
            },
            '0.0.2': {
              foo: 2,
              deprecated: 'This is deprecated',
              'renovate-config': { default: { rangeStrategy: 'auto' } },
            },
          },
          repository: {
            type: 'git',
            url: 'https://github.com/renovateapp/dummy.git',
          },
          'dist-tags': {
            latest: '0.0.2',
          },
          time: {
            '0.0.1': '2018-05-06T07:21:53+02:00',
            '0.0.2': '2018-05-07T07:21:53+02:00',
          },
        };
        nock('https://registry.npmjs.org')
          .get('/foobar')
          .reply(200, presetPackage);
        const res = await npm.getPreset('foobar');
        expect(res).toMatchSnapshot();
      });
      it('should parse repo url', async () => {
        const pkg = {
          name: 'foobar',
          versions: {
            '0.0.1': {
              foo: 1,
            },
          },
          repository: {
            type: 'git',
            url: 'git:github.com/renovateapp/dummy',
          },
          'dist-tags': {
            latest: '0.0.1',
          },
          time: {
            '0.0.1': '2018-05-06T07:21:53+02:00',
          },
        };
        nock('https://registry.npmjs.org')
          .get('/foobar')
          .reply(200, pkg);
        const res = await npm.getPkgReleases({ lookupName: 'foobar' });
        expect(res).toMatchSnapshot();
        expect(res.sourceUrl).toBeDefined();
      });
    
      it('should parse repo url (string)', async () => {
        const pkg = {
          name: 'foobar',
          versions: {
            '0.0.1': {
              repository: 'git:github.com/renovateapp/dummy',
            },
          },
          'dist-tags': {
            latest: '0.0.1',
          },
          time: {
            '0.0.1': '2018-05-06T07:21:53+02:00',
          },
        };
        nock('https://registry.npmjs.org')
          .get('/foobar')
          .reply(200, pkg);
        const res = await npm.getPkgReleases({ lookupName: 'foobar' });
        expect(res).toMatchSnapshot();
        expect(res.sourceUrl).toBeDefined();
      });
      it('should return deprecated', async () => {
        const deprecatedPackage = {
          name: 'foobar',
          versions: {
            '0.0.1': {
              foo: 1,
            },
            '0.0.2': {
              foo: 2,
              deprecated: 'This is deprecated',
            },
          },
          repository: {
            type: 'git',
            url: 'git://github.com/renovateapp/dummy.git',
          },
          'dist-tags': {
            latest: '0.0.2',
          },
          time: {
            '0.0.1': '2018-05-06T07:21:53+02:00',
            '0.0.2': '2018-05-07T07:21:53+02:00',
          },
        };
        nock('https://registry.npmjs.org')
          .get('/foobar')
          .reply(200, deprecatedPackage);
        const res = await npm.getPkgReleases({ lookupName: 'foobar' });
        expect(res).toMatchSnapshot();
        expect(res.deprecationMessage).toMatchSnapshot();
      });
      it('should handle foobar', async () => {
        nock('https://registry.npmjs.org')
          .get('/foobar')
          .reply(200, npmResponse);
        const res = await npm.getPkgReleases({ lookupName: 'foobar' });
        expect(res).toMatchSnapshot();
      });
      it('should reject name mismatch', async () => {
        nock('https://registry.npmjs.org')
          .get('/different')
          .reply(200, npmResponse);
        const res = await npm.getPkgReleases({ lookupName: 'different' });
        expect(res).toBeNull();
      });
      it('should handle no time', async () => {
        delete npmResponse.time['0.0.2'];
        nock('https://registry.npmjs.org')
          .get('/foobar')
          .reply(200, npmResponse);
        const res = await npm.getPkgReleases({ lookupName: 'foobar' });
        expect(res).toMatchSnapshot();
        expect(getRelease(res, '0.0.1').canBeUnpublished).toBe(false);
        expect(getRelease(res, '0.0.2').canBeUnpublished).toBeUndefined();
      });
      it('should return canBeUnpublished=true', async () => {
        npmResponse.time['0.0.2'] = moment()
          .subtract(6, 'hours')
          .format();
        nock('https://registry.npmjs.org')
          .get('/foobar')
          .reply(200, npmResponse);
        const res = await npm.getPkgReleases({ lookupName: 'foobar' });
        expect(getRelease(res, '0.0.1').canBeUnpublished).toBe(false);
        expect(getRelease(res, '0.0.2').canBeUnpublished).toBe(true);
      });
      it('should return null if lookup fails 401', async () => {
        nock('https://registry.npmjs.org')
          .get('/foobar')
          .reply(401);
        const res = await npm.getPkgReleases({ lookupName: 'foobar' });
        expect(res).toBeNull();
      });
      it('should return null if lookup fails', async () => {
        nock('https://registry.npmjs.org')
          .get('/foobar')
          .reply(404);
        const res = await npm.getPkgReleases({ lookupName: 'foobar' });
        expect(res).toBeNull();
      });
      it('should throw error for unparseable', async () => {
        nock('https://registry.npmjs.org')
          .get('/foobar')
          .reply(200, 'oops');
        await expect(
          npm.getPkgReleases({ lookupName: 'foobar' })
        ).rejects.toThrow();
      });
      it('should throw error for 429', async () => {
        nock('https://registry.npmjs.org')
          .get('/foobar')
          .reply(429);
        nock('https://registry.npmjs.org')
          .get('/foobar')
          .reply(429);
        await expect(
          npm.getPkgReleases({ lookupName: 'foobar' })
        ).rejects.toThrow();
      });
      it('should throw error for 5xx', async () => {
        nock('https://registry.npmjs.org')
          .get('/foobar')
          .reply(503);
        await expect(npm.getPkgReleases({ lookupName: 'foobar' })).rejects.toThrow(
          Error(DATASOURCE_FAILURE)
        );
      });
      it('should throw error for 408', async () => {
        nock('https://registry.npmjs.org')
          .get('/foobar')
          .reply(408);
        await expect(npm.getPkgReleases({ lookupName: 'foobar' })).rejects.toThrow(
          Error(DATASOURCE_FAILURE)
        );
      });
      it('should throw error for others', async () => {
        nock('https://registry.npmjs.org')
          .get('/foobar')
          .reply(451);
        await expect(
          npm.getPkgReleases({ lookupName: 'foobar' })
        ).rejects.toThrow();
      });
      it('should send an authorization header if provided', async () => {
        registryAuthToken.mockImplementation(() => ({
          type: 'Basic',
          token: '1234',
        }));
        nock('https://registry.npmjs.org')
          .get('/foobar')
          .reply(200, npmResponse);
        const res = await npm.getPkgReleases({ lookupName: 'foobar' });
        expect(res).toMatchSnapshot();
      });
      it('should use NPM_TOKEN if provided', async () => {
        nock('https://registry.npmjs.org')
          .get('/foobar')
          .reply(200, npmResponse);
        const oldToken = process.env.NPM_TOKEN;
        process.env.NPM_TOKEN = 'some-token';
        const res = await npm.getPkgReleases({ lookupName: 'foobar' });
        process.env.NPM_TOKEN = oldToken;
        expect(res).toMatchSnapshot();
      });
      it('resets npmrc', () => {
        npm.setNpmrc('something=something');
        npm.setNpmrc('something=something');
        npm.setNpmrc();
      });
      it('should use default registry if missing from npmrc', async () => {
        nock('https://registry.npmjs.org')
          .get('/foobar')
          .reply(200, npmResponse);
        const npmrc = 'foo=bar';
        const res = await npm.getPkgReleases({ lookupName: 'foobar', npmrc });
        expect(res).toMatchSnapshot();
      });
      it('should cache package info from npm', async () => {
        nock('https://registry.npmjs.org')
          .get('/foobar')
          .reply(200, npmResponse);
        const npmrc = '//registry.npmjs.org/:_authToken=abcdefghijklmnopqrstuvwxyz';
        const res1 = await npm.getPkgReleases({ lookupName: 'foobar', npmrc });
        const res2 = await npm.getPkgReleases({ lookupName: 'foobar', npmrc });
        expect(res1).not.toBeNull();
        expect(res1).toEqual(res2);
      });
      it('should fetch package info from custom registry', async () => {
        nock('https://npm.mycustomregistry.com')
          .get('/foobar')
          .reply(200, npmResponse);
        const npmrc =
          'registry=https://npm.mycustomregistry.com/\n//npm.mycustomregistry.com/:_auth = ' +
          Buffer.from('abcdef').toString('base64');
        const res = await npm.getPkgReleases({ lookupName: 'foobar', npmrc });
        expect(res).toMatchSnapshot();
      });
      it('should replace any environment variable in npmrc', async () => {
        nock('https://registry.from-env.com')
          .get('/foobar')
          .reply(200, npmResponse);
        process.env.REGISTRY = 'https://registry.from-env.com';
        process.env.RENOVATE_CACHE_NPM_MINUTES = '15';
        global.trustLevel = 'high';
        // eslint-disable-next-line no-template-curly-in-string
        const npmrc = 'registry=${REGISTRY}';
        const res = await npm.getPkgReleases({ lookupName: 'foobar', npmrc });
        expect(res).toMatchSnapshot();
      });
      it('should throw error if necessary env var is not present', () => {
        global.trustLevel = 'high';
        // eslint-disable-next-line no-template-curly-in-string
        expect(() => npm.setNpmrc('registry=${REGISTRY_MISSING}')).toThrow(
          Error('env-replace')
        );
      });
    });