Skip to content

Commit

Permalink
feat(tests): Enabled unit testing
Browse files Browse the repository at this point in the history
  • Loading branch information
s-hoff committed Mar 22, 2017
1 parent 97e9af9 commit 19c59a1
Show file tree
Hide file tree
Showing 11 changed files with 606 additions and 51 deletions.
6 changes: 3 additions & 3 deletions lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ function determineWorkingDirectory(dir) {
return;
}

return fs.exists(path.join(dir, 'aurelia_project')).then(result => {
return result ? dir : determineWorkingDirectory(parent);
});
return fs.stat(path.join(dir, 'aurelia_project'))
.then(() => dir)
.catch(() => determineWorkingDirectory(parent));
}
21 changes: 21 additions & 0 deletions lib/file-system.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,31 @@ const fs = require('fs');
const nodePath = require('path');
const mkdirp = require('./mkdirp').mkdirp;

exports.fs = fs;

/**
* @deprecated
* fs.exists() is deprecated.
* See https://nodejs.org/api/fs.html#fs_fs_exists_path_callback.
* Functions using it can also not be properly tested.
*/
exports.exists = function(path) {
return new Promise((resolve, reject) => fs.exists(path, resolve));
};

exports.stat = function(path) {
return new Promise((resolve, reject) => {
fs.stat(path, (error, stats) => {
if(error) reject(error);
else resolve(stats);
});
});
};

exports.existsSync = function(path) {
return fs.existsSync(path);
};

exports.mkdir = function(path) {
return new Promise((resolve, reject) => {
fs.mkdir(path, (error, result) => {
Expand Down
86 changes: 41 additions & 45 deletions lib/project-item.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,12 @@ exports.ProjectItem = class {
let fullPath = relativeTo ? path.posix.join(relativeTo, this.name) : this.name;

if (this.isDirectory) {
return fs.exists(fullPath).then(result => {
let dirReady = result ? Promise.resolve() : fs.mkdir(fullPath);
return dirReady.then(() => {
return Promise.all(this.children.map(child => child.create(ui, fullPath)));
});
});
return fs.stat(fullPath)
.then(result => result)
.catch(() => fs.mkdir(fullPath))
.then(() => Promise.all(this.children.map(child =>
child.create(ui, fullPath)
)));
} else if (this.sourcePath) {
return fs.readFile(this.sourcePath).then(data => {
return this._write(fullPath, data, ui);
Expand All @@ -116,48 +116,44 @@ exports.ProjectItem = class {
content = this.transformers[i](content);
}

return fs.exists(fullPath).then(result => {
if (result) {
switch (this._fileExistsStrategy) {
case 'skip':
return Promise.resolve();
case 'merge':
if (this.name = 'package.json') {
return fs.readFile(fullPath).then(data => {
let json = JSON.parse(data.toString());
let merged = mergePackageJson(json, this.jsonObject);
return fs.writeFile(fullPath, JSON.stringify(merged, null, 2));
});
} else {
throw new Error(`cannot merge ${this.name}`);
}
case 'ask':
let question = `An existing file named '${this.name}' was found. What would you like to do?`;
let options = [
{
displayName: 'Keep It',
description: 'Keeps your existing file. You may need to update its contents to work with Aurelia.'
},
{
displayName: "Replace It",
description: "Replaces the existing file with a new one designed for Aurelia."
}
];

return ui.question(question, options).then(answer => {
if (answer == options[0]) {
return Promise.resolve();
}

return fs.writeFile(fullPath, content);
return fs.stat(fullPath).then(() => {
switch (this._fileExistsStrategy) {
case 'skip':
return Promise.resolve();
case 'merge':
if (this.name = 'package.json') {
return fs.readFile(fullPath).then(data => {
let json = JSON.parse(data.toString());
let merged = mergePackageJson(json, this.jsonObject);
return fs.writeFile(fullPath, JSON.stringify(merged, null, 2));
});
default:
} else {
throw new Error(`cannot merge ${this.name}`);
}
case 'ask':
let question = `An existing file named '${this.name}' was found. What would you like to do?`;
let options = [
{
displayName: 'Keep It',
description: 'Keeps your existing file. You may need to update its contents to work with Aurelia.'
},
{
displayName: "Replace It",
description: "Replaces the existing file with a new one designed for Aurelia."
}
];

return ui.question(question, options).then(answer => {
if (answer == options[0]) {
return Promise.resolve();
}

return fs.writeFile(fullPath, content);
}
});
default:
return fs.writeFile(fullPath, content);
}

return fs.writeFile(fullPath, content);
});
}).catch(() => fs.writeFile(fullPath, content));
}

static jsonObject(name, jsonObject) {
Expand Down
4 changes: 2 additions & 2 deletions lib/project.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,12 @@ exports.Project = class {

resolveGenerator(name) {
let potential = path.join(this.generatorDirectory, `${name}${this.model.transpiler.fileExtension}`);
return fs.exists(potential).then(result => result ? potential : null);
return fs.stat(potential).then(() => potential).catch(() => null);
}

resolveTask(name) {
let potential = path.join(this.taskDirectory, `${name}${this.model.transpiler.fileExtension}`);
return fs.exists(potential).then(result => result ? potential : null);
return fs.stat(potential).then(() => potential).catch(() => null);
}
}

Expand Down
9 changes: 8 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
"aurelia": "bin/aurelia-cli.js",
"au": "bin/aurelia-cli.js"
},
"scripts": {
"test": "jasmine",
"test:watch": "nodemon -x 'npm test'"
},
"license": "MIT",
"author": "Rob Eisenberg <rob@bluespire.com> (http://robeisenberg.com/)",
"main": "lib/index.js",
Expand All @@ -29,6 +33,9 @@
"npm": "^3.10.8"
},
"devDependencies": {
"aurelia-tools": "^0.2.2"
"aurelia-tools": "^0.2.2",
"jasmine": "^2.5.2",
"mock-fs": "^4.2.0",
"nodemon": "^1.11.0"
}
}
1 change: 1 addition & 0 deletions spec/helpers/polyfills.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require('aurelia-polyfills');
190 changes: 190 additions & 0 deletions spec/lib/cli.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
"use strict";
describe('The cli', () => {
let fs;
let path;
let mockfs;
let cli;
let Project;
let project;

let dir;
let aureliaProject;

beforeEach(() => {
fs = require('../../lib/file-system');
path = require('path');
cli = new (require('../../lib/cli').CLI)();
Project = require('../../lib/project').Project;
mockfs = require('mock-fs');
project = {};

dir = 'workspaces';
aureliaProject = 'aurelia_project';
const fsConfig = {};
fsConfig[dir] = {};
fsConfig['package.json'] = {};

mockfs(fsConfig);
});

afterEach(() => {
mockfs.restore();
});

describe('The _establishProject() function', () => {
let establish;

beforeEach(() => {
establish = spyOn(Project, 'establish').and.returnValue(project);
});

it('resolves to nothing', done => {
cli._establishProject({})
.then(project => {
expect(project).not.toBeDefined();
})
.catch(fail).then(done);
});

it('calls and resolves to Project.establish()', done => {
fs.mkdirp(path.join(process.cwd(), aureliaProject))
.then(() => cli._establishProject({
runningLocally: true
}))
.then(project => {
expect(Project.establish)
.toHaveBeenCalledWith(cli.ui, path.join(process.cwd()));
expect(project).toBe(project);
})
.catch(fail).then(done);
});

it('does not catch Project.establish()', done => {
establish.and.callFake(() => new Promise((resolve, reject) => reject()));

fs.mkdirp(path.join(process.cwd(), aureliaProject))
.then(() => cli._establishProject({
runningLocally: true
}))
.then(() => {
fail('expected promise to be rejected.');
done();
})
.catch(done);
});

it(`logs 'No Aurelia project found.'`, done => {
spyOn(cli.ui, 'log');
cli._establishProject({
runningLocally: true
}).then(() => {
expect(cli.ui.log).toHaveBeenCalledWith('No Aurelia project found.');
}).catch(fail).then(done);
});
});

describe('The createHelpCommand() function', () => {
it('gets the help command', () => {
mockfs({
'lib/commands/help/command.js': 'module.exports = {}'
});
spyOn(cli.container, 'get');

cli.createHelpCommand();
expect(cli.container.get)
.toHaveBeenCalledWith(require('../../lib/commands/help/command'));
});
});

describe('The configureContainer() function', () => {
it('registers the instances', () => {
const registerInstanceSpy = spyOn(cli.container, 'registerInstance');

cli.configureContainer();

expect(registerInstanceSpy.calls.count()).toBe(2);
});
});

describe('The run() function', () => {
function getVersionSpec(command) {
return () => {
beforeEach(() => {
mockfs({
'package.json': '{"version": "1.0.0"}'
})
spyOn(cli.ui, 'log')
.and.callFake(() => new Promise(resolve => resolve()));
});

it('logs the cli version', () => {
cli.run(command);
expect(cli.ui.log).toHaveBeenCalledWith('1.0.0');
});

it('returns an empty promise', done => {
cli.run(command).then(resolved => {
expect(resolved).not.toBeDefined();
}).catch(fail).then(done);
});
};
}

describe('The --version arg', getVersionSpec('--version'));

describe('The -v arg', getVersionSpec('-v'));

it('uses the _establishProject() function', done => {
// const project = {};
spyOn(cli, '_establishProject').and.returnValue(new Promise(resolve => {
resolve(project);
}));
spyOn(cli.container, 'registerInstance');
spyOn(cli, 'createCommand').and.returnValue({ execute: () => {} });

cli.run()
.then(() => {
expect(cli._establishProject).toHaveBeenCalledWith(cli.options);
}).catch(fail).then(done);
});

it('registers the project instance', done => {
spyOn(cli, '_establishProject').and.returnValue(new Promise(resolve => {
resolve(project);
}));
spyOn(cli.container, 'registerInstance');
spyOn(cli, 'createCommand').and.returnValue({ execute: () => {} });

cli.run().then(() => {
expect(cli.container.registerInstance)
.toHaveBeenCalledWith(Project, project);
}).catch(fail).then(done);
});

it('creates the command', done => {
const command = 'run';
const args = {};
spyOn(cli, 'createCommand').and.returnValue({ execute: () => {} });

cli.run(command, args).then(() => {
expect(cli.createCommand).toHaveBeenCalledWith(command, args);
}).catch(fail).then(done);
});

it('executes the command', done => {
const command = {
execute: () => {}
};
const args = {};
spyOn(cli, '_establishProject').and.returnValue(new Promise(resolve =>
resolve(project)
));
spyOn(command, 'execute').and.returnValue(new Promise(resolve => resolve({})));
spyOn(cli, 'createCommand').and.returnValue(command);

cli.run('run', args).then(() => {
expect(command.execute).toHaveBeenCalledWith(args);
}).catch(fail).then(done);
});
});
});
Loading

0 comments on commit 19c59a1

Please sign in to comment.