javascript 測試載入器 abut v2

來源:互聯網
上載者:User

綜合眾人的意見,此版本做了許多改進,如對注釋抽取的最佳化,增加對script標籤的支援,即時性的測試等等。

// dom.abut v2 (annotations-based unit testing by 司徒正美)// http://www.cnblogs.com/rubylouvre/archive/2010/11/08/1868638.html(function(){    //ecma262新擴充    if(!Object.keys){        var  _dontEnum = ['propertyIsEnumerable', 'isPrototypeOf','hasOwnProperty','toLocaleString', 'toString', 'valueOf', 'constructor'];        for (var i in {            toString: 1        }) _dontEnum = false;        Object.keys = function(obj){//ecma262v5 15.2.3.14            var result = [],dontEnum = _dontEnum,length = dontEnum.length;            for(var key in obj ) if(obj.hasOwnProperty(key)){                result.push(key)            }            if(dontEnum){                while(length){                    key = dontEnum[--length];                    if(obj.hasOwnProperty(key)){                        result.push(key);                    }                }            }            return result;        }    }    if(!String.prototype.trim){        String.prototype.trim = function(){            return this.replace(/^[\s\xa0]+|[\s\xa0]+$/g, '');        }    }    if(!String.prototype.quote){        String.prototype.quote = (function () {            var meta = {                '\b': '\\b',                '\t': '\\t',                '\n': '\\n',                '\f': '\\f',                '\r': '\\r',                '"' : '\\"',                '\\': '\\\\'            }, reg = /[\\\"\x00-\x1f]/g,            regFn = function (a) {                var c = meta[a];                return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);            };            return  function(){                return '"' + this.replace(reg, regFn) + '"';            }        })();    }    var addEvent = (function () {        if (document.addEventListener) {            return function (el, type, fn) {                el.addEventListener(type, fn, false);            };        } else {            return function (el, type, fn) {                el.attachEvent('on' + type, function () {                    return fn.call(el, window.event);                });            }        }    })();    var applyIf = function(target,source){        for(var name in source)            if(!target[name] ){                target[name] = source[name];            }        return target;    }    //釋出命名空間對象    window.dom = window.dom || {};    applyIf(dom,{        // http://www.cnblogs.com/rubylouvre/archive/2010/01/20/1652646.html        type : (function(){            var reg = /^(\w)/,            regFn = function($,$1){                return $1.toUpperCase()            },            to_s = Object.prototype.toString;            return function(obj,str){                var result = (typeof obj).replace(reg,regFn);                if(result === 'Object' || (result === 'Function' && obj.exec) ){//safari chrome中 type /i/ 為function                    if(obj===null) result = 'Null';//Object,Function,Null,Undefined,Window,Arguments等等都為其構造器名稱                    else if(obj.window==obj) result = 'Window';                     else if(obj.callee) result = 'Arguments';                    else if(obj.nodeType === 9) result = 'Document';                    else if(obj.nodeName) result = (obj.nodeName+'').replace('#',''); //處理元素節點                    else if(!obj.constructor || !(obj instanceof Object)){                        if("send" in obj && "setRequestHeader" in obj){//處理IE5-8的宿主對象與節點集合                            result = "XMLHttpRequest"                        }else if("length" in obj && "item" in obj){                            result = "namedItem" in obj ?  'HTMLCollection' :'NodeList';                        }else{                            result = 'Unknown';                        }                    }else result = to_s.call(obj).slice(8,-1);                }                if(result === "Number" && isNaN(obj))  result = "NaN";                //safari chrome中 對 HTMLCollection與NodeList的to_s都為 "NodeList",此bug暫時無解                if(str){                    return str === result;                }                return result;            }        })(),        oneObject : function(array,val){            var result = {},value = val !== void 0 ? val :1;            for(var i=0,n=array.length;i >>>");            if(segment.indexOf(">>>>") !== -1){//這裡不使用el.length === 2是為了避開IE的split bug                bigClosure(els[0],resolving,obj);                if(els[1]){                    smartClosure(els[1],resolving,obj);                }            }else{                smartClosure(els[0],resolving,obj);            }        }        //構築單元測試系統的UI        var UL = document.createElement("UL");        abut.el = UL;        target.appendChild(UL);        UL.className ="dom-abut-result";        abut.render("dom-abut-title",'一共有'+obj.count+'個測試');        abut.recoder = document.getElementById( abut.ULID);        if(!arguments.callee.first){//保證這裡的代碼只執行一次            arguments.callee.first = true;            addEvent(target,"click",function(e){                var target = e.target || e.srcElement;                if(target.className ==="dom-abut-slide"){                    var blockquote =  target.parentNode.getElementsByTagName("blockquote")[0];                    if(blockquote){                        blockquote.style.display =  !!(blockquote.offsetHeight || blockquote.offestWidth) ? "none": "block";                    }                }            });            //添加樣式            dom.addSheet(".dom-abut-result {\            border:5px solid #00a7ea;\            padding:10px;\            background:#03c9fa;\            list-style-type:none;\        }\        .dom-abut-result li{\            padding:5px ;\            margin-bottom:1px;\            font-size:14px;\        }\        .dom-abut-slide{\            cursor: pointer;\        }\        .dom-abut-result li blockquote{\            margin:0;\            padding:5px;\            display:none;\        }\        .dom-abut-title{\            background:#008000;\        }\        .dom-abut-pass{\            background:#a9ea00;\        }\        .dom-abut-unpass{\            background:red;\            color:#fff;\        }\        .dom-abut-log{\            background:#c0c0c0;\        }\        .dom-abut-log blockquote{\            background:#808080;\        }");        }        try {            abut.isModify && eval(uneval);            eval(resolving.join(""));        } catch (e) {            return  abut.render("dom-abut-unpass","解析編譯測試代碼失敗");        }        for(var i=0,fn;fn= abut.closures[i++];){            try {                fn();            } catch (e) {                abut.render("dom-abut-unpass","第"+fn.lineNumber +"行測試代碼執行失敗");            }        }    }    applyIf(dom,{        abut:function(obj){            var key = obj.selector || obj.url,            target = obj.target || document.body,str;            if(dom.type(target,"String")){                target = document.getElementById(target);            }            if(obj.selector){                var el = document.getElementById(key);                if (!el) throw "can not find the target element";                str = el.text;            }else {                var xhr = dom.xhr();                xhr.open("GET",key+"?"+(new Date-0),false);                xhr.send(null);                str = xhr.responseText || "";                if (!str) throw "the target file does not exist";            }            evalCode(str,target)        },        getComments : function(text){            var m , result = [];            while(m = rcomments.exec(text)){                result.push((m[1] || m[2]).replace(rstar,function($,$1){                    return $1                }));            }            return result.join('\n');        },        addSheet : function(css){            if(!-[1,]){                css = css.replace(ropacity,function($,$1){                    $1 = parseFloat($1) * 100;                    if($1  100)                        return "";                    return "filter:alpha(opacity="+ $1 +");"                });            }            css += "\n";//增加末尾的分行符號,方便在firebug下的查看。            var doc = document, head = doc.getElementsByTagName("head")[0],            styles = head.getElementsByTagName("style"),style,media;            if(!styles.length){//如果不存在style元素則建立                style = doc.createElement('style');                style.setAttribute("type", "text/css");                head.insertBefore(style,null)            }            style = styles[0];            media = style.getAttribute("media");            if(media === null && !/screen/i.test(media) ){                style.setAttribute("media","all");            }            if(style.styleSheet){    //ie                style.styleSheet.cssText += css;//添加新的內部樣式            }else if(doc.getBoxObjectFor){                style.innerHTML += css;//Firefox支援直接innerHTML添加樣式表字串            }else{                style.appendChild(doc.createTextNode(css))            }        },        //比較對象是否相等或相似        isEqual: function(a, b) {            if (a === b) return true;            var atype = typeof(a), btype = typeof(b);            if (atype != btype) return false;            if (a == b) return true;            if ((!a && b) || (a && !b)) return false;            if (a.isEqual) return a.isEqual(b);            if (dom.type(a,"Date") && dom.type(b,"Date")) return a.valueOf() === b.valueOf();            if (dom.type(a,"NaN") && dom.type(b,"NaN")) return false;            if (dom.type(a,"RegExp") && dom.type(b,"RegExp"))                return a.source === b.source &&                a.global        === b.global &&                a.ignoreCase    === b.ignoreCase &&                a.multiline     === b.multiline;            if (atype !== 'object') return false;            if (a.length && (a.length !== b.length)) return false;            var aKeys = Object.keys(a), bKeys = Object.keys(b);            if (aKeys.length != bKeys.length) return false;            for (var key in a) if (!(key in b) || !dom.isEqual(a[key], b[key])) return false;            return true;        },        inspect : function(obj, indent) {            indent = indent || "";            if (obj === null)                return indent + "null";            if (obj === void 0)                return indent + "undefined";            if (obj.nodeType === 9)                return indent + "[object Document]";            if (obj.nodeType)                return indent + "[object " + (obj.tagName || "Node") +"]";            var arr = [],type = dom.type(obj),self = arguments.callee,next = indent +  "\t";            switch (type) {                case "Boolean":                case "Number":                case "NaN":                case "RegExp":                    return indent + obj;                case "String":                    return indent + obj.quote();                case "Function":                    return (indent + obj).replace(/\n/g, "\n" + indent);                case "Date":                    return indent + '(new Date(' + obj.valueOf() + '))';                case "Unknown":                case "XMLHttpRequest" :                case "Window" :                    return indent + "[object "+type +"]";                case "NodeList":                case "HTMLCollection":                case "Arguments":                case "Array":                    for (var i = 0, n = obj.length; i 第' + arguments.callee.lineNumber+"行日誌記錄  "+ (message || "") + "";            var testCode = "
"+dom.inspect(obj)+"

";
this.render("dom-abut-log",context,testCode);
},
prepareRender : function(bool,lineNumber,testCode){
var className = bool ? 'dom-abut-pass' : 'dom-abut-unpass',
context = '第'+ lineNumber+'行測試代碼: '+(bool ? '通過' :'不通過' )+"" ;
this.recoder.innerHTML = " 已完成第"+(++this.time)+"個測試";
this.render(className,context,testCode);
},
render : function(className,context,code){
var li = document.createElement("li");
li.className = className;
this.el.appendChild(li);
var blockquote = document.createElement("blockquote")
li.innerHTML = context;
if(code){
li.appendChild(blockquote);
blockquote.innerHTML = code;
}
}
});
})();

測試例子1:

var test1 = 1;/* * <<<< * $$$$log(a) * >>>> *//*            dsfds */// frgtretr         /**          * erwwer          *          */

<br /> var source = document.getElementById("test1").innerHTML;<br /> alert(source);<br /> alert(dom.getComments(source))<br />

運行代碼

測試例子2:

      var p = function(){}      // comment /* not-a-nested-comment      p('not-a-comment'); // comment */* still-a-comment      p('not-a-comment'); /* alert('commented-out-code');// still-a-comment */ p('not-a-comment');      var re= /\/* not-a-comment */; //* comment

<br /> var source = document.getElementById("test2").innerHTML;<br /> alert(source);<br /> alert(dom.getComments(source))<br />

運行代碼

abut v2增加了對script的支援,為此方法的參數由一個字串改為一個雜湊,雜湊有三個值,selector,url與target。selector就是指script標籤的id,通過來擷取其innerHTML進行測試。url指JS檔案的路徑,我們通過同步AJAX請求擷取responseText進行測試,由於是AJAX請求,就會受到同源策略的限制,因此v1我就無法放出樣本,因此以後樣本都使用selector方法。target是指將測試結果放到哪一個元素節點中,預設是document.body,此參數可選,並且如果是字串,它會自動當成標籤的ID進行尋找。

比如我頁面上有一個id為test3的script元素節點,其innerHTML如下:

      var Person = function(name,sex){        this.name = name;        this.sex = sex;        //####log(this.name);        //####log(this.sex);      }      var p = new Person("ruby","louvre");

想對其測試,只要引用abut.js,在頁面上運行如下指令碼即可:

        dom.abut({          selector:id,//要測試的script標籤          //url:url,//只限於同域的路徑          target:document.body //把測試結果添加到的位置(可以是元素節點,也可以是其id值)        });

運行代碼

在此例子中,我們也可以看到新的標識符####,它將取代原先的@@@@。v1中的@@@@目的是將閉包中或內建函式中的資料釋出全域範圍下,然後再用$$$$一系列方法對它進行測試。然後,實踐證明,這有點麻煩,為何不直接在原先的內部範圍中執行它呢?!####就是基於此目的開發出來,相對應,@@@@就沒有用了,被我廢棄掉了,移除了。####會對源碼進行修改再進行解釋執行,而$$$$則先解析執行源碼再對注釋中的測試範例進行修葺後執行,執行時機是完全不一樣的。$$$$可以跟eq,same,ok,log這四個函數名,####也完全一樣,但####暫時不支援寫在>>>之間。

例子4,對多行測試注釋的使用。

    var flatten = function(arr) {        var result = [],self = arguments.callee;        for(var i=0,n=arr.length,el;i >>>       */

運行代碼

例子5(截取自我架構的base模組)

      var      PROTO = "prototype",      CTOR = "constructor",      hasOwn = Object[PROTO].hasOwnProperty;      //用於取得資料的類型或判定資料的類型      // $$$$(dom.type(1,"Number"));      // $$$$(dom.type(NaN,"NaN"));      // $$$$(dom.type(void(0),"Undefined"));      // $$$$(dom.type("aaa","String"));      // $$$$(dom.type([1,2,3],"Array"));      // $$$$(dom.type(/i/,"RegExp"));      // $$$$(dom.type({},"Object"));      // $$$$(dom.type(document,"Document"));      // $$$$(dom.type(document.body,"BODY"));      // $$$$(dom.type(window,"Window"));      // $$$$(dom.type(true,"Boolean"));      // $$$$(dom.type(document.getElementsByTagName('script'),"HTMLCollection"));      dom.type = (function(){        var reg = /^(\w)/,        regFn = function($,$1){          return $1.toUpperCase()        },        to_s = Object[PROTO].toString;        return function(obj,str){          var result = (typeof obj).replace(reg,regFn);          if(result === 'Object' || (result === 'Function' && obj.exec) ){//safari chrome中 type /i/ 為function            if(obj===null) result = 'Null';            else if(obj.window==obj) result = 'Window'; //返回Window的構造器名字            else if(obj.callee) result = 'Arguments';            else if(obj.nodeType === 9) result = 'Document';            else if(obj.nodeName) result = (obj.nodeName+'').replace('#',''); //處理元素節點            else if(!obj.constructor || !(obj instanceof Object)){              if("send" in obj && "setRequestHeader" in obj){//處理IE5-8的宿主對象與節點集合                result = "XMLHttpRequest"              }else if("length" in obj && "item" in obj){                result = "namedItem" in obj ?  'HTMLCollection' :'NodeList';              }else{                result = 'Unknown';              }            }else result = to_s.call(obj).slice(8,-1);          }          if(result === "Number" && isNaN(obj))  result = "NaN";          //safari chrome中 對 HTMLCollection與NodeList的to_s都為 "NodeList",此bug暫時無解          if(str){            return str === result;          }          return result;        }      })()      //產生索引值統一的對象,用於高速化判定      // $$$$same(dom.oneObject(["aa","bb","cc"]),{"aa":1,"bb":1,"cc":1})      dom.oneObject = function(array,val){        var result = {},value = val !== void 0 ? val :1;        for(var i=0,n=array.length;i     

運行代碼

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.