Skip to content

Commit

Permalink
test(tests): increase test coverage on util modules
Browse files Browse the repository at this point in the history
  • Loading branch information
MarshallOfSound authored and malept committed Jan 30, 2017
1 parent 6d15c62 commit 6c63aaf
Show file tree
Hide file tree
Showing 7 changed files with 281 additions and 5 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"mocha": "^3.2.0",
"nodemon": "^1.11.0",
"nyc": "^10.0.0",
"proxyquire": "^1.7.10",
"sinon": "^1.17.7"
},
"babel": {
Expand Down
7 changes: 5 additions & 2 deletions src/util/ora-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class MockOra {
stop() { return this; }
}

const asyncOra = (initalOraValue, asyncFn) => {
const asyncOra = (initalOraValue, asyncFn, processExitFn = process.exit) => {
let fnOra = new MockOra();
if (asyncOra.interactive) {
fnOra = ora(initalOraValue).start();
Expand All @@ -28,7 +28,10 @@ const asyncOra = (initalOraValue, asyncFn) => {
console.error('\nElectron forge was terminated:'.red);
console.error(colors.red(typeof err === 'string' ? err : JSON.stringify(err)));
}
process.exit(1);
processExitFn(1);
// If the process is still alive we should continue because either something went really wrong
// or we are testing this function
setTimeout(() => resolve(), 500);
} else {
reject(err);
}
Expand Down
3 changes: 2 additions & 1 deletion test/.eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"mocha": true
},
"rules": {
"import/no-extraneous-dependencies": 0
"import/no-extraneous-dependencies": 0,
"class-methods-use-this": 0
}
}
12 changes: 12 additions & 0 deletions test/fast/config_spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { expect } from 'chai';
import fs from 'fs-promise';

import config from '../../src/util/config';

Expand All @@ -16,4 +17,15 @@ describe('cross-process config', () => {
config.reset();
expect(config.get('foobar')).to.equal(undefined);
});

it('should not have issues if the config file is cleaned up', async () => {
await fs.remove(config._path);
expect(config.get('foobar')).to.equal(undefined);
config.set('foobar', '123');
expect(config.get('foobar')).to.equal('123');
});

after(() => {
config.reset();
});
});
49 changes: 47 additions & 2 deletions test/fast/github_spec.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,30 @@
import { expect } from 'chai';

import GitHub from '../../src/util/github';
import proxyquire from 'proxyquire';
import sinon from 'sinon';

describe('GitHub', () => {
let GitHub;
let gitHubSpy;
let gitHubAuthSpy;
let MockGitHub;

beforeEach(() => {
gitHubSpy = sinon.spy();
gitHubAuthSpy = sinon.spy();
MockGitHub = class {
constructor() {
gitHubSpy();
}

authenticate() {
gitHubAuthSpy();
}
};
GitHub = proxyquire.noCallThru().load('../../src/util/github', {
github: MockGitHub,
}).default;
});

it('should read token from constructor', () => {
expect(new GitHub('token1').token).to.equal('token1');
});
Expand All @@ -12,4 +34,27 @@ describe('GitHub', () => {
expect(new GitHub().token).to.equal('abc123');
delete process.env.GITHUB_TOKEN;
});

describe('getGitHub', () => {
it('should create a new GitHubAPI', () => {
const gh = new GitHub();
expect(gitHubSpy.callCount).to.equal(0);
gh.getGitHub();
expect(gitHubSpy.callCount).to.equal(1);
});

it('should authenticate if a token is present', () => {
const gh = new GitHub('token');
expect(gitHubAuthSpy.callCount).to.equal(0);
gh.getGitHub();
expect(gitHubAuthSpy.callCount).to.equal(1);
});

it('should not authenticate if a token is not present', () => {
const gh = new GitHub();
expect(gitHubAuthSpy.callCount).to.equal(0);
gh.getGitHub();
expect(gitHubAuthSpy.callCount).to.equal(0);
});
});
});
99 changes: 99 additions & 0 deletions test/fast/install-dependencies_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { expect } from 'chai';
import proxyquire from 'proxyquire';
import sinon from 'sinon';

describe('GitHub', () => {
let install;
let spawnSpy;
let hasYarnSpy;
let exitHandler;

beforeEach(() => {
const outOn = (s, fn) => fn('a');
const errOn = outOn;
spawnSpy = sinon.stub();
spawnSpy.returns({
stdout: { on: outOn },
stderr: { on: errOn },
on: (s, fn) => { exitHandler = fn; },
});
hasYarnSpy = sinon.stub();
install = proxyquire.noCallThru().load('../../src/util/install-dependencies', {
'yarn-or-npm': {
spawn: spawnSpy,
hasYarn: hasYarnSpy,
},
}).default;
});

it('should immediately resolve if no deps are provided', async () => {
await install('mydir', []);
expect(spawnSpy.callCount).to.equal(0);
});

it('should reject if reject the promise if exit code is not 0', (done) => {
const p = install('void', ['electron']);
p.then(() => done(new Error('expected install to be rejected')))
.catch(() => done());
exitHandler(1);
});

it('should resolve if reject the promise if exit code is 0', (done) => {
const p = install('void', ['electron']);
p.then(() => done())
.catch(() => done(new Error('expected install to be resolved')));
exitHandler(0);
});

describe('with yarn', () => {
beforeEach(() => {
hasYarnSpy.returns(true);
});

it('should install prod deps', () => {
install('mydir', ['react']);
expect(spawnSpy.firstCall.args[0]).to.be.deep.equal(['add', 'react']);
});

it('should install dev deps', () => {
install('mydir', ['eslint'], true);
expect(spawnSpy.firstCall.args[0]).to.be.deep.equal(['add', 'eslint', '--dev']);
});

it('should install exact deps', () => {
install('mydir', ['react-dom'], false, true);
expect(spawnSpy.firstCall.args[0]).to.be.deep.equal(['add', 'react-dom', '--exact']);
});

it('should install exact dev deps', () => {
install('mydir', ['mocha'], true, true);
expect(spawnSpy.firstCall.args[0]).to.be.deep.equal(['add', 'mocha', '--dev', '--exact']);
});
});

describe('with npm', () => {
beforeEach(() => {
hasYarnSpy.returns(false);
});

it('should install prod deps', () => {
install('mydir', ['react']);
expect(spawnSpy.firstCall.args[0]).to.be.deep.equal(['install', 'react', '--save']);
});

it('should install dev deps', () => {
install('mydir', ['eslint'], true);
expect(spawnSpy.firstCall.args[0]).to.be.deep.equal(['install', 'eslint', '--save-dev']);
});

it('should install exact deps', () => {
install('mydir', ['react-dom'], false, true);
expect(spawnSpy.firstCall.args[0]).to.be.deep.equal(['install', 'react-dom', '--save-exact', '--save']);
});

it('should install exact dev deps', () => {
install('mydir', ['mocha'], true, true);
expect(spawnSpy.firstCall.args[0]).to.be.deep.equal(['install', 'mocha', '--save-exact', '--save-dev']);
});
});
});
115 changes: 115 additions & 0 deletions test/fast/ora-handler_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { expect } from 'chai';
import proxyquire from 'proxyquire';
import sinon from 'sinon';

describe('asyncOra', () => {
let asyncOra;
let MockOra;
let currentOra;

beforeEach(() => {
currentOra = undefined;
MockOra = (text) => {
currentOra = {
start() {
this.started = true;
return currentOra;
},
succeed() {
this.succeeded = true;
return currentOra;
},
fail() {
this.failed = true;
return currentOra;
},
get text() {
return currentOra._text;
},
set text(newText) {
currentOra._text = newText;
},
};
currentOra.succeeded = false;
currentOra.failed = false;
currentOra._text = text;
return currentOra;
};
asyncOra = proxyquire.noCallThru().load('../../src/util/ora-handler', {
ora: { ora: MockOra },
}).default;
});

it('should create an ora with an inital value', () => {
asyncOra('say this first', async () => {});
expect(currentOra).to.not.equal(undefined);
expect(currentOra.text).to.equal('say this first');
});

it('should not create an ora when in non-interactive mode', () => {
asyncOra.interactive = false;
asyncOra('say this again', async () => {});
expect(currentOra).to.equal(undefined);
});

it('should call the provided async function', async () => {
const spy = sinon.spy();
await asyncOra('random text', async () => {
spy();
});
expect(spy.callCount).to.equal(1);
});

it('should succeed the ora if the async fn passes', async () => {
await asyncOra('random text', async () => {
if (2 + 2 === 5) console.error('Big brother is at it again');
});
expect(currentOra.succeeded).to.equal(true);
expect(currentOra.failed).to.equal(false);
});

it('should fail the ora if the async fn throws', async () => {
await asyncOra('this is gonna end badly', async () => {
throw { message: 'Not an error', stack: 'No Stack - Not an error' }; // eslint-disable-line
}, () => {});
expect(currentOra.succeeded).to.equal(false);
expect(currentOra.failed).to.equal(true);
});

it('should exit the process with status 1 if the async fn throws', async () => {
const processExitSpy = sinon.spy();
await asyncOra('this is dodge', async () => {
throw 'woops'; // eslint-disable-line
}, processExitSpy);
expect(processExitSpy.callCount).to.equal(1);
expect(processExitSpy.firstCall.args).to.deep.equal([1]);
});

it('should exit the process with status 1 if the async fn throws a number', async () => {
const processExitSpy = sinon.spy();
await asyncOra('this is dodge', async () => {
throw 42; // eslint-disable-line
}, processExitSpy);
expect(processExitSpy.callCount).to.equal(1);
expect(processExitSpy.firstCall.args).to.deep.equal([1]);
});

it('should just reject the promise in non-interactive mode if the fn throws', (done) => {
asyncOra.interactive = false;
asyncOra('doo-wop', async () => {
throw new Error('uh oh');
}).then(() => done(new Error('expected asyncOra to be rejected')))
.catch(() => done());
});

it('should provide a fully functioning mock ora in non-interactive mode', async () => {
asyncOra.interactive = false;
await asyncOra('ora-magic', async (spinner) => {
expect(spinner).to.have.property('start');
expect(spinner).to.have.property('stop');
expect(spinner).to.have.property('succeed');
expect(spinner).to.have.property('fail');
expect(spinner.start().stop().fail().succeed()).to.equal(spinner);
});
});
});

0 comments on commit 6c63aaf

Please sign in to comment.