blanket
Version:
seamless js code coverage
286 lines (264 loc) • 11.8 kB
JavaScript
(function(_blanket){
var oldOptions = _blanket.options;
_blanket.extend({
outstandingRequireFiles:[],
options: function(key,value){
var newVal={};
if (typeof key !== "string"){
//key is key/value map
oldOptions(key);
newVal = key;
}else if (typeof value === 'undefined'){
//accessor
return oldOptions(key);
}else{
//setter
oldOptions(key,value);
newVal[key] = value;
}
if (newVal.adapter){
_blanket._loadFile(newVal.adapter);
}
if (newVal.loader){
_blanket._loadFile(newVal.loader);
}
},
requiringFile: function(filename,done){
if (typeof filename === "undefined"){
_blanket.outstandingRequireFiles=[];
}else if (typeof done === "undefined"){
_blanket.outstandingRequireFiles.push(filename);
}else{
_blanket.outstandingRequireFiles.splice(_blanket.outstandingRequireFiles.indexOf(filename),1);
}
},
requireFilesLoaded: function(){
return _blanket.outstandingRequireFiles.length === 0;
},
showManualLoader: function(){
if (document.getElementById("blanketLoaderDialog")){
return;
}
//copied from http://blog.avtex.com/2012/01/26/cross-browser-css-only-modal-box/
var loader = "<div class='blanketDialogOverlay'>";
loader += " </div>";
loader += "<div class='blanketDialogVerticalOffset'>";
loader += "<div class='blanketDialogBox'>";
loader += "<b>Error:</b> Blanket.js encountered a cross origin request error while instrumenting the source files. ";
loader += "<br><br>This is likely caused by the source files being referenced locally (using the file:// protocol). ";
loader += "<br><br>Some solutions include <a href='http://askubuntu.com/questions/160245/making-google-chrome-option-allow-file-access-from-files-permanent' target='_blank'>starting Chrome with special flags</a>, <a target='_blank' href='https://github.com/remy/servedir'>running a server locally</a>, or using a browser without these CORS restrictions (Safari).";
loader += "<br>";
if (typeof FileReader !== "undefined"){
loader += "<br>Or, try the experimental loader. When prompted, simply click on the directory containing all the source files you want covered.";
loader += "<a href='javascript:document.getElementById(\"fileInput\").click();'>Start Loader</a>";
loader += "<input type='file' type='application/x-javascript' accept='application/x-javascript' webkitdirectory id='fileInput' multiple onchange='window.blanket.manualFileLoader(this.files)' style='visibility:hidden;position:absolute;top:-50;left:-50'/>";
}
loader += "<br><span style='float:right;cursor:pointer;' onclick=document.getElementById('blanketLoaderDialog').style.display='none';>Close</span>";
loader += "<div style='clear:both'></div>";
loader += "</div></div>";
var css = ".blanketDialogWrapper {";
css += "display:block;";
css += "position:fixed;";
css += "z-index:40001; }";
css += ".blanketDialogOverlay {";
css += "position:fixed;";
css += "width:100%;";
css += "height:100%;";
css += "background-color:black;";
css += "opacity:.5; ";
css += "-ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=50)'; ";
css += "filter:alpha(opacity=50); ";
css += "z-index:40001; }";
css += ".blanketDialogVerticalOffset { ";
css += "position:fixed;";
css += "top:30%;";
css += "width:100%;";
css += "z-index:40002; }";
css += ".blanketDialogBox { ";
css += "width:405px; ";
css += "position:relative;";
css += "margin:0 auto;";
css += "background-color:white;";
css += "padding:10px;";
css += "border:1px solid black; }";
var dom = document.createElement("style");
dom.innerHTML = css;
document.head.appendChild(dom);
var div = document.createElement("div");
div.id = "blanketLoaderDialog";
div.className = "blanketDialogWrapper";
div.innerHTML = loader;
document.body.insertBefore(div,document.body.firstChild);
},
manualFileLoader: function(files){
var toArray =Array.prototype.slice;
files = toArray.call(files).filter(function(item){
return item.type !== "";
});
var sessionLength = files.length-1;
var sessionIndx=0;
var sessionArray = {};
if (sessionStorage["blanketSessionLoader"]){
sessionArray = JSON.parse(sessionStorage["blanketSessionLoader"]);
}
var fileLoader = function(event){
var fileContent = event.currentTarget.result;
var file = files[sessionIndx];
var filename = file.webkitRelativePath && file.webkitRelativePath !== '' ? file.webkitRelativePath : file.name;
sessionArray[filename] = fileContent;
sessionIndx++;
if (sessionIndx === sessionLength){
sessionStorage.setItem("blanketSessionLoader", JSON.stringify(sessionArray));
document.location.reload();
}else{
readFile(files[sessionIndx]);
}
};
function readFile(file){
var reader = new FileReader();
reader.onload = fileLoader;
reader.readAsText(file);
}
readFile(files[sessionIndx]);
},
_loadFile: function(path){
if (typeof path !== "undefined"){
var request = new XMLHttpRequest();
request.open('GET', path, false);
request.send();
_blanket._addScript(request.responseText);
}
},
_addScript: function(data){
var script = document.createElement("script");
script.type = "text/javascript";
script.text = data;
(document.body || document.getElementsByTagName('head')[0]).appendChild(script);
},
hasAdapter: function(callback){
return _blanket.options("adapter") !== null;
},
report: function(coverage_data){
if (!document.getElementById("blanketLoaderDialog")){
//all found, clear it
_blanket.blanketSession = null;
}
coverage_data.files = window._$blanket;
var require = blanket.options("commonJS") ? blanket._commonjs.require : window.require;
// Check if we have any covered files that requires reporting
// otherwise just exit gracefully.
if (!coverage_data.files || !Object.keys(coverage_data.files).length) {
if (_blanket.options("debug")) {console.log("BLANKET-Reporting No files were instrumented.");}
return;
}
if (typeof coverage_data.files.branchFcn !== "undefined"){
delete coverage_data.files.branchFcn;
}
if (typeof _blanket.options("reporter") === "string"){
_blanket._loadFile(_blanket.options("reporter"));
_blanket.customReporter(coverage_data,_blanket.options("reporter_options"));
}else if (typeof _blanket.options("reporter") === "function"){
_blanket.options("reporter")(coverage_data,_blanket.options("reporter_options"));
}else if (typeof _blanket.defaultReporter === 'function'){
_blanket.defaultReporter(coverage_data,_blanket.options("reporter_options"));
}else{
throw new Error("no reporter defined.");
}
},
_bindStartTestRunner: function(bindEvent,startEvent){
if (bindEvent){
bindEvent(startEvent);
}else{
if (document.readyState === "complete") {
startEvent();
} else {
window.addEventListener("load",startEvent,false);
}
}
},
_loadSourceFiles: function(callback){
var require = blanket.options("commonJS") ? blanket._commonjs.require : window.require;
function copy(o){
var _copy = Object.create( Object.getPrototypeOf(o) );
var propNames = Object.getOwnPropertyNames(o);
propNames.forEach(function(name){
var desc = Object.getOwnPropertyDescriptor(o, name);
Object.defineProperty(_copy, name, desc);
});
return _copy;
}
if (_blanket.options("debug")) {console.log("BLANKET-Collecting page scripts");}
var scripts = _blanket.utils.collectPageScripts();
//_blanket.options("filter",scripts);
if (scripts.length === 0){
callback();
}else{
//check session state
if (sessionStorage["blanketSessionLoader"]){
_blanket.blanketSession = JSON.parse(sessionStorage["blanketSessionLoader"]);
}
scripts.forEach(function(file,indx){
_blanket.utils.cache[file]={
loaded:false
};
});
var currScript=-1;
_blanket.utils.loadAll(function(test){
if (test){
return typeof scripts[currScript+1] !== 'undefined';
}
currScript++;
if (currScript >= scripts.length){
return null;
}
return scripts[currScript];
},callback);
}
},
beforeStartTestRunner: function(opts){
opts = opts || {};
opts.checkRequirejs = typeof opts.checkRequirejs === "undefined" ? true : opts.checkRequirejs;
opts.callback = opts.callback || function() { };
opts.coverage = typeof opts.coverage === "undefined" ? true : opts.coverage;
if (opts.coverage) {
_blanket._bindStartTestRunner(opts.bindEvent,
function(){
_blanket._loadSourceFiles(function() {
var allLoaded = function(){
return opts.condition ? opts.condition() : _blanket.requireFilesLoaded();
};
var check = function() {
if (allLoaded()) {
if (_blanket.options("debug")) {console.log("BLANKET-All files loaded, init start test runner callback.");}
var cb = _blanket.options("testReadyCallback");
if (cb){
if (typeof cb === "function"){
cb(opts.callback);
}else if (typeof cb === "string"){
_blanket._addScript(cb);
opts.callback();
}
}else{
opts.callback();
}
} else {
setTimeout(check, 13);
}
};
check();
});
});
}else{
opts.callback();
}
},
utils: {
qualifyURL: function (url) {
//http://stackoverflow.com/questions/470832/getting-an-absolute-url-from-a-relative-one-ie6-issue
var a = document.createElement('a');
a.href = url;
return a.href;
}
}
});
})(blanket);