alloy
Version:
TiDev Titanium MVC Framework
190 lines (172 loc) • 4.96 kB
JavaScript
var exec = require('child_process').exec,
fs = require('fs-extra'),
os = require('os'),
path = require('path'),
JsDiff = require('diff'),
_ = require('lodash'),
babylon = require('@babel/parser'),
U = require('../../Alloy/utils'),
styler = require('../../Alloy/commands/compile/styler');
var alloyRoot = path.join(__dirname,'..','..');
var IS_WIN = /^win/i.test(os.platform());
exports.TIMEOUT_DEFAULT = IS_WIN ? 5000 : 3500;
exports.paths = {
templates: path.join(alloyRoot,'Alloy','template'),
harnessTemplate: path.join(alloyRoot,'test','projects','HarnessTemplate'),
harness: path.join(alloyRoot,'test','projects','Harness')
};
function createEnv () {
return Object.assign(process.env, { PATH: `${path.join(process.cwd(), 'bin')}${path.delimiter}${process.env.PATH}`})
}
// Recreate the test app harness
//
// Params:
// * callback: the callback function to be executed when the harness
// is successfully recreated.
function resetTestApp(callback) {
var paths = exports.paths;
fs.removeSync(paths.harness);
fs.mkdirpSync(paths.harness);
fs.copySync(paths.harnessTemplate, paths.harness);
exec('alloy new "' + paths.harness + '"', {env: createEnv() }, function(error, stdout, stderr) {
if (error) {
console.error('Failed to create new alloy project at ' + paths.harness);
console.error(stderr);
process.exit(1);
}
callback();
});
}
// Turns the arguments given to the callback of the exec() function
// into an object literal.
//
// Params:
// * args: The "arguments" object from the callback of an exec() call
//
// Return: An object literal with the error, stdout, and stderr
function getExecObject(args) {
args = Array.prototype.slice.call(args, 0);
return {
error: args[0],
stdout: args[1],
stderr: args[2]
};
}
// Convenience function for handling asynchronous tests that rely on the
// exec() function. The output values from the first runs() block will
// be available as this.output in the second runs() block where the
// actual tests are evaluated.
//
// Params:
// * cmd: The command to run through exec()
// * opts: An object that can contain the following parameters:
// * timeout: How long to wait for the command to execute before declaring
// the test failed
// * test: The actual test function to execute on output returned from exec()
// * reset: If truthy, recreate the default test harness before executing
//
// Return: none
exports.asyncExecTest = function(cmd, opts) {
opts = opts || {};
runs(function() {
var self = this;
self.done = false;
var asyncFunc = function() {
exec(cmd, { env: createEnv() }, function() {
self.done = true;
self.output = getExecObject(arguments);
});
};
if (opts.reset) {
resetTestApp(function() {
asyncFunc();
});
} else {
asyncFunc();
}
});
waitsFor(
function() { return this.done; },
'exec("' + cmd + '") timed out', opts.timeout || exports.TIMEOUT_DEFAULT
);
runs(opts.test || function() {
expect(this.output.error).toBeNull();
});
};
// Matchers for Jasmine
function toBeTssFile(expected) {
var actual = this.actual;
var style;
try {
var die = U.die;
U.die = function(msg, e) {
U.die = die;
throw U.createErrorOutput(msg, e);
};
style = styler.loadStyle(actual);
U.die = die;
} catch (e) {
U.die = die || U.die;
return false;
}
if (_.isObject(style)) {
return true;
}
return false;
}
function toBeJavascript(expected) {
try {
babylon.parse(this.actual);
return true;
} catch (e) {
console.error(e);
return false;
}
}
function toBeJavascriptFile(expected) {
var actual = this.actual;
var notText = this.isNot ? " not" : "";
this.message = function () {
return "Expected " + actual + notText + " to be a Javascript file";
};
try {
var js = fs.readFileSync(this.actual,'utf8');
return toBeJavascript.call({actual:js}, expected);
} catch (e) {
return false;
}
}
exports.addMatchers = function() {
beforeEach(function() {
this.addMatchers({
toBeJavascript: toBeJavascript,
toBeJavascriptFile: toBeJavascriptFile,
toBeTssFile: toBeTssFile,
toHaveNoUndefinedStyles: function() {
return !_.find(this.actual, function(o) {
return o.key === 'undefined' && o.isApi;
});
},
toHaveSameContentAs: function(expected) {
return U.normalizeReturns(fs.readFileSync(this.actual,'utf8')) ===
U.normalizeReturns(fs.readFileSync(expected,'utf8'));
},
toExist: function(expected) {
return path.existsSync(this.actual);
},
toBeArray: function(expected) {
return _.isArray(this.actual);
},
toBeObject: function(expected) {
return _.isObject(this.actual);
},
toNotDiff: function(expected, filename) {
var pass = this.actual === expected;
this.message = function() {
return ["Expected to have no diff, but it does: \n\n" + JsDiff.createPatch(filename, expected, this.actual)];
};
return pass;
}
});
});
};