From 53a316d1c3e1d6530d0647c28af9df3e3ad7f955 Mon Sep 17 00:00:00 2001 From: Rhys Arkins <rhys@keylocation.sg> Date: Thu, 22 Jun 2017 21:35:32 +0200 Subject: [PATCH] Improve test coverage (#338) * Fix github api coverage * Fix npm api coverage * Fix renovate init function coverage * Start gitlab tests * gitlab initRepo tests * findFilePaths * Add branchExists tests * Fix branch worker coverage * pr worker * Refactor repository functions * Refactor gitlab getRepos --- lib/workers/repository.js | 15 +- test/api/__snapshots__/gitlab.spec.js.snap | 118 ++++++++++++ test/api/github.spec.js | 11 ++ test/api/gitlab.spec.js | 207 +++++++++++++++++++++ test/api/npm.spec.js | 3 + test/renovate.spec.js | 10 + test/workers/branch.spec.js | 4 +- test/workers/pr.spec.js | 5 + test/workers/repository.spec.js | 2 + 9 files changed, 368 insertions(+), 7 deletions(-) create mode 100644 test/api/__snapshots__/gitlab.spec.js.snap create mode 100644 test/api/gitlab.spec.js create mode 100644 test/renovate.spec.js diff --git a/lib/workers/repository.js b/lib/workers/repository.js index 7329ee5cfb..b4e80398df 100644 --- a/lib/workers/repository.js +++ b/lib/workers/repository.js @@ -17,6 +17,11 @@ module.exports = { processRepo, processUpgrades, removeStandaloneBranches, + mergeRenovateJson, + checkIfOnboarded, + setNpmrc, + detectPackageFiles, + getAllRepoUpgrades, }; // This will be github or others @@ -48,17 +53,17 @@ async function processRepo(config) { logger ); // Override settings with renovate.json if present - await mergeRenovateJson(config); + await module.exports.mergeRenovateJson(config); // Check that the repository is onboarded - const isOnboarded = await checkIfOnboarded(config); + const isOnboarded = await module.exports.checkIfOnboarded(config); if (isOnboarded === false) { return; } // Check for presence of .npmrc in repository - await setNpmrc(config); + await module.exports.setNpmrc(config); // Detect package files if none already configured - await detectPackageFiles(config); - const upgrades = await getAllRepoUpgrades(config); + await module.exports.detectPackageFiles(config); + const upgrades = await module.exports.getAllRepoUpgrades(config); await module.exports.processUpgrades(upgrades); } catch (error) { throw error; diff --git a/test/api/__snapshots__/gitlab.spec.js.snap b/test/api/__snapshots__/gitlab.spec.js.snap new file mode 100644 index 0000000000..d54a7bf421 --- /dev/null +++ b/test/api/__snapshots__/gitlab.spec.js.snap @@ -0,0 +1,118 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`api/gitlab getRepos should return an array of repos 1`] = ` +Array [ + Array [ + "projects", + ], +] +`; + +exports[`api/gitlab getRepos should return an array of repos 2`] = ` +Array [ + "a/b", + "c/d", +] +`; + +exports[`api/gitlab getRepos should support a custom endpoint 1`] = ` +Array [ + Array [ + "projects", + ], +] +`; + +exports[`api/gitlab getRepos should support a custom endpoint 2`] = ` +Array [ + "a/b", + "c/d", +] +`; + +exports[`api/gitlab initRepo should initialise the config for the repo - 0 1`] = ` +Array [ + Array [ + "projects/owned", + ], + Array [ + "projects/some%2Frepo", + ], + Array [ + "user", + ], +] +`; + +exports[`api/gitlab initRepo should initialise the config for the repo - 0 2`] = ` +Object { + "apiVersion": "v3", + "defaultBranch": "master", + "email": "a@b.com", + "repoName": "some%2Frepo", +} +`; + +exports[`api/gitlab initRepo should initialise the config for the repo - 1 1`] = ` +Array [ + Array [ + "projects/owned", + ], + Array [ + "projects/some%2Frepo", + ], + Array [ + "user", + ], +] +`; + +exports[`api/gitlab initRepo should initialise the config for the repo - 1 2`] = ` +Object { + "apiVersion": "v3", + "defaultBranch": "master", + "email": "a@b.com", + "repoName": "some%2Frepo", +} +`; + +exports[`api/gitlab initRepo should initialise the config for the repo - 2 1`] = ` +Array [ + Array [ + "projects/owned", + ], + Array [ + "projects/some%2Frepo", + ], + Array [ + "user", + ], +] +`; + +exports[`api/gitlab initRepo should initialise the config for the repo - 2 2`] = ` +Object { + "apiVersion": "v3", + "defaultBranch": "master", + "email": "a@b.com", + "repoName": "some%2Frepo", +} +`; + +exports[`api/gitlab initRepo should use api v4 1`] = ` +Object { + "apiVersion": "v4", + "defaultBranch": "master", + "email": "a@b.com", + "repoName": "some%2Frepo", +} +`; + +exports[`api/gitlab initRepo uses provided logger 1`] = ` +Object { + "apiVersion": "v3", + "defaultBranch": "master", + "email": "a@b.com", + "repoName": "some%2Frepo", +} +`; diff --git a/test/api/github.spec.js b/test/api/github.spec.js index 1358929696..8405d97049 100644 --- a/test/api/github.spec.js +++ b/test/api/github.spec.js @@ -1,3 +1,11 @@ +const bunyan = require('bunyan'); + +const logger = bunyan.createLogger({ + name: 'test', + stream: process.stdout, + level: 'fatal', +}); + describe('api/github', () => { let github; let ghGot; @@ -175,6 +183,9 @@ describe('api/github', () => { expect(process.env.GITHUB_ENDPOINT).toBe(endpoint); }); }); + it('uses provided logger', async () => { + await initRepo('some/repo', 'some_token', 'an_endpoint', logger); + }); it('should throw an error if no token is provided', async () => { let err; try { diff --git a/test/api/gitlab.spec.js b/test/api/gitlab.spec.js new file mode 100644 index 0000000000..a02d24eccd --- /dev/null +++ b/test/api/gitlab.spec.js @@ -0,0 +1,207 @@ +const bunyan = require('bunyan'); + +const logger = bunyan.createLogger({ + name: 'test', + stream: process.stdout, + level: 'fatal', +}); + +describe('api/gitlab', () => { + let gitlab; + let glGot; + beforeEach(() => { + // clean up env + delete process.env.GITLAB_TOKEN; + delete process.env.GITLAB_ENDPOINT; + + // reset module + jest.resetModules(); + jest.mock('gl-got'); + gitlab = require('../../lib/api/gitlab'); + glGot = require('gl-got'); + }); + + describe('getRepos', () => { + async function getRepos(...args) { + // repo info + glGot.mockImplementationOnce(() => ({ + body: [ + { + path_with_namespace: 'a/b', + }, + { + path_with_namespace: 'c/d', + }, + ], + })); + return gitlab.getRepos(...args); + } + it('should throw an error if no token is provided', async () => { + let err; + try { + await gitlab.getRepos(); + } catch (e) { + err = e; + } + expect(err.message).toBe('No token found for getRepos'); + }); + it('should throw an error if it receives an error', async () => { + glGot.mockImplementation(() => { + throw new Error('getRepos error'); + }); + let err; + try { + await gitlab.getRepos('sometoken'); + } catch (e) { + err = e; + } + expect(err.message).toBe('getRepos error'); + }); + it('should return an array of repos', async () => { + const repos = await getRepos('sometoken'); + expect(glGot.mock.calls).toMatchSnapshot(); + expect(repos).toMatchSnapshot(); + }); + it('should support a custom endpoint', async () => { + const repos = await getRepos('sometoken', 'someendpoint'); + expect(glGot.mock.calls).toMatchSnapshot(); + expect(repos).toMatchSnapshot(); + }); + }); + + async function initRepo(...args) { + // projects/owned + glGot.mockImplementationOnce(); + // projects/${config.repoName + glGot.mockImplementationOnce(() => ({ + body: { + default_branch: 'master', + }, + })); + // user + glGot.mockImplementationOnce(() => ({ + body: { + email: 'a@b.com', + }, + })); + return gitlab.initRepo(...args); + } + + describe('initRepo', () => { + [ + [undefined, ['mytoken'], 'mytoken', undefined], + [ + undefined, + ['mytoken', 'https://my.custom.endpoint/'], + 'mytoken', + 'https://my.custom.endpoint/', + ], + ['myenvtoken', [], 'myenvtoken', undefined], + ].forEach(([envToken, args, token, endpoint], i) => { + it(`should initialise the config for the repo - ${i}`, async () => { + if (envToken !== undefined) { + process.env.GITLAB_TOKEN = envToken; + } + const config = await initRepo('some/repo', ...args); + expect(glGot.mock.calls).toMatchSnapshot(); + expect(config).toMatchSnapshot(); + expect(process.env.GITLAB_TOKEN).toBe(token); + expect(process.env.GITLAB_ENDPOINT).toBe(endpoint); + }); + }); + it('uses provided logger', async () => { + const config = await initRepo( + 'some/repo', + 'some_token', + 'an_endpoint', + logger + ); + expect(config).toMatchSnapshot(); + }); + it('should throw an error if no token is provided', async () => { + let err; + try { + await gitlab.initRepo('some/repo'); + } catch (e) { + err = e; + } + expect(err.message).toBe( + 'No token found for GitLab repository some/repo' + ); + }); + it('should throw an error if receiving an error', async () => { + glGot.mockImplementation(() => { + throw new Error('always error'); + }); + let err; + try { + await gitlab.initRepo('some/repo', 'sometoken'); + } catch (e) { + err = e; + } + expect(err.message).toBe('always error'); + }); + it('should use api v4', async () => { + // projects/owned + glGot.mockImplementationOnce(() => { + throw new Error('any error'); + }); + // projects/${config.repoName + glGot.mockImplementationOnce(() => ({ + body: { + default_branch: 'master', + }, + })); + // user + glGot.mockImplementationOnce(() => ({ + body: { + email: 'a@b.com', + }, + })); + const config = await initRepo('some/repo', 'some_token'); + expect(config).toMatchSnapshot(); + }); + }); + describe('findFilePaths(fileName)', () => { + it('should return the fileName', async () => { + await initRepo('some/repo', 'token'); + const files = await gitlab.findFilePaths('package.json'); + expect(files).toEqual(['package.json']); + }); + }); + describe('branchExists(branchName)', () => { + it('should return true if 200 OK', async () => { + glGot.mockImplementationOnce(() => ({ statusCode: 200 })); + const branchExists = await gitlab.branchExists('foo'); + expect(branchExists).toBe(true); + }); + it('should return false if not 200 OK', async () => { + glGot.mockImplementationOnce(() => ({ statusCode: 500 })); + const branchExists = await gitlab.branchExists('foo'); + expect(branchExists).toBe(false); + }); + it('should return false if 404 error received', async () => { + glGot.mockImplementationOnce(() => + Promise.reject({ + statusCode: 404, + }) + ); + const branchExists = await gitlab.branchExists('foo'); + expect(branchExists).toBe(false); + }); + it('should return error if non-404 error thrown', async () => { + glGot.mockImplementationOnce(() => + Promise.reject({ + statusCode: 500, + }) + ); + let e; + try { + await gitlab.branchExists('foo'); + } catch (err) { + e = err; + } + expect(e.statusCode).toBe(500); + }); + }); +}); diff --git a/test/api/npm.spec.js b/test/api/npm.spec.js index a3f8e7331a..0989b12b6d 100644 --- a/test/api/npm.spec.js +++ b/test/api/npm.spec.js @@ -58,4 +58,7 @@ describe('api/npm', () => { const call = got.mock.calls[0]; expect(call).toMatchSnapshot(); }); + it('sets .npmrc', () => { + npm.setNpmrc('input'); + }); }); diff --git a/test/renovate.spec.js b/test/renovate.spec.js new file mode 100644 index 0000000000..2d93861f8c --- /dev/null +++ b/test/renovate.spec.js @@ -0,0 +1,10 @@ +const renovateWorker = require('../lib/workers'); + +renovateWorker.start = jest.fn(); + +describe('renovate', () => { + it('starts', () => { + require('../lib/renovate'); + expect(renovateWorker.start.mock.calls.length).toBe(1); + }); +}); diff --git a/test/workers/branch.spec.js b/test/workers/branch.spec.js index 20d5ad7e5d..a740fb4438 100644 --- a/test/workers/branch.spec.js +++ b/test/workers/branch.spec.js @@ -333,8 +333,8 @@ describe('workers/branch', () => { config.api = { checkForClosedPr: jest.fn(), }; - branchWorker.ensureBranch = jest.fn(); - prWorker.ensurePr = jest.fn(); + branchWorker.ensureBranch = jest.fn(() => true); + prWorker.ensurePr = jest.fn(() => true); }); it('returns immediately if closed PR found', async () => { config.api.checkForClosedPr.mockReturnValue(true); diff --git a/test/workers/pr.spec.js b/test/workers/pr.spec.js index fb43fbefe7..deff4e1fbc 100644 --- a/test/workers/pr.spec.js +++ b/test/workers/pr.spec.js @@ -223,5 +223,10 @@ describe('workers/pr', () => { const pr = await prWorker.ensurePr([config], logger); expect(pr).toBe(null); }); + it('handles duplicate upgrades', async () => { + config.api.getBranchPr = jest.fn(); + const pr = await prWorker.ensurePr([config, config], logger); + expect(pr).toMatchObject({ displayNumber: 'New Pull Request' }); + }); }); }); diff --git a/test/workers/repository.spec.js b/test/workers/repository.spec.js index f99ddc6252..2babfd8c83 100644 --- a/test/workers/repository.spec.js +++ b/test/workers/repository.spec.js @@ -4,6 +4,8 @@ const branchWorker = require('../../lib/workers/branch'); jest.mock('../../lib/workers/branch'); jest.mock('../../lib/workers/pr'); jest.mock('../../lib/api/npm'); +jest.mock('../../lib/api/github'); +jest.mock('../../lib/api/gitlab'); jest.mock('../../lib/helpers/versions'); describe('repositoryWorker', () => { -- GitLab