mass Framework spec模块 v2

对于一个框架的成长来说,测试是必不可少的,像用手来点来点去的测试基本不算测试,只有基于代码的单元测试才能让人安心。因此我不断地升级我的测试工具,从早期的abut到现在的spec模块。它不断地添加测试函数:eq, ok, same,contains, match...最近添加的方法是near,是专门用于测试CSS样式值,像width, height, opacity, border-top-width等值在各浏览器下总差1,2像素,更有甚者,webkit系的连浮点数也出来了。由于一个框架拥有许多模块,因此测试显示区也分为许多版块,如何处理同步与异步的关系非常重要,前一版本专门搞了个Deferred异步列队,但我发现其实mass的模块加载模块中的ready列队就是现成的异步列队,因此这版本就省下许多代码。本版本还处理了中文显示问题,这主要是因为FF私自对函体内的中文进行转码,我搞了uni2hanzi把它还原回来了。

CSS部分


@CHARSET "UTF-8";
 
#dom-spec-result {
    border:5px solid #00a7ea;
    padding:10px;
    background:#03c9fa;
    list-style-type:none;
}
.dom-spec-summary {
    height: 2em;
    line-height: 2em;
    margin: 0;
    font-size: 13px;
    font-weight: bold;
    text-indent: 2em;
    background:#008000;
    color:#fff;
}
.dom-spec-detail{
    list-style: none;
    margin: 0;
    padding: 0;
}
.dom-spec-detail li{
    margin: 0;
    padding:0;
    border: 2px solid #03c9fa;
    text-indent: 1em;
}
.dom-spec-pass{
    background:#a9ea00;
}
.dom-spec-unpass{
    background:#cd0000;
    color:#fff;
}
.dom-spec-detail pre{
    margin: 1em;
    text-indent: 0;
    font-style: normal;
    background: #F0F8FF;
    padding: 2px;
    color:#000;
    border:2px outset #c0c0c0;
}
.dom-spec-error{
    background: #000;
    color:#fff;
}
.dom-spec-log{
    background: #cc9!important;
}
/*用于点击展开*/
.dom-spec-slide {
    background:#a9ea00;
    text-indent: 2em;
    line-height: 1.4em;
    height: 1.4em;
    margin: 0;
}
.dom-spec-diff {
    background: red;
    margin: 1em;
}
.dom-spec-diff div{
    45%;
    float: left;
}
.dom-spec-diff pre{
    background: #00cc00;
}
/* new clearfix */
.clearfix:after {
    visibility: hidden;
    display: block;
    font-size: 0;
    content: " ";
    clear: both;
    height: 0;
}
* html .clearfix             { zoom: 1; } /* IE6 */
*:first-child+html .clearfix { zoom: 1; } /* IE7 */

JS部分


//==================================================
// 测试模块
//==================================================
(function(global,DOC){
    var dom = global[DOC.URL.replace(/(#.+|\W)/g,'')];
    dom.define("first/spec", function(){
        dom.log("已加载spec模块")
        //模块为dom添加如下方法:
        //quote isEqual dump Deferred runTest addTestModule
        //在全局命名空间下多添加一个函数 expect
        dom.mix(dom,{
            //在字符串两端加上引号,并对其内部一些字符进行转义,用于JSON与引用
            quote :global.JSON && JSON.stringify || String.quote ||  (function(){
                var meta = {
                    '\t':'t',
                    '\n':'n',
                    '\v':'v',
                    'f':'f',
                    '\r':'\r',
                    '\'':'\'',
                    '\"':'\"',
                    '\\':'\\'
                },
                reg = /[\x00-\x1F\'\"\\\u007F-\uFFFF]/g,
                regFn = function(c){
                    if (c in meta) return '\\' + meta[c];
                    var ord = c.charCodeAt(0);
                    return ord < 0x20   ? '\\x0' + ord.toString(16)
                    :  ord < 0x7F   ? '\\'   + c
                    :  ord < 0x100  ? '\\x'  + ord.toString(16)
                    :  ord < 0x1000 ? '\\u0' + ord.toString(16)
                    : '\\u'  + ord.toString(16)
                };
                return function (str) {
                    return    '"' + str.replace(reg, regFn)+ '"';
                }
            })(),
            //比较对象是否相等或相似
            isEqual: function(a, b) {
                if (a === b) {
                    return true;
                } else if (a === null || b === null || typeof a === "undefined" || typeof b === "undefined" || dom.type(a) !== dom.type(b)) {
                    return false; // don't lose time with error prone cases
                } else {
                    switch(dom.type(a)){
                        case "String":
                        case "Boolean":
                        case "Number":
                        case "Null":
                        case "Undefined":
                            //处理简单类型的伪对象与字面值相比较的情况,如1 v new Number(1)
                            if (b instanceof a.constructor || a instanceof b.constructor) {
                                return a == b;
                            }
                            return a === b;
                        case "NaN":
                            return isNaN(b);
                        case "Date":
                            return  a.valueOf() === b.valueOf();
                        case "NodeList":
                        case "Arguments":
                        case "Array":
                            var len = a.length;
                            if (len !== b.length)
                                return false;
                            for (var i = 0; i < len; i++) {
                                if (!this.isEqual(a[i], b[i])) {
                                    return false;
                                }
                            }
                            return true;
                        default:
                            for (var key in b) {
                                if (!this.isEqual(a[key], b[key])) {
                                    return false;
                                }
                            }
                            return true;
                    }
                }
            },
            //用于查看对象的内部构造
            dump : 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 + dom.quote(obj);
                    case "Function":
                        return (indent + obj).replace(/\n/g, "\n" + indent);
                    case "Date":
                        return indent + '(new Date(' + obj.valueOf() + '))';
                    case "XMLHttpRequest" :
                    case "Window" :
                        return indent + "[object "+type +"]";
                    case "NodeList":
                    case "Arguments":
                    case "Array":
                        for (var i = 0, n = obj.length; i < n; ++i)
                            arr.push(self(obj[i], next).replace(/^\s* /g, next));
                        return indent + "[\n" + arr.join(",\n") + "\n" + indent + "]";
                    default:
                        for ( i in obj) {
                            arr.push(next + self(i) + ": " + self(obj[i], next).replace(/^\s+/g, ""));
                        }
                        return indent + "{\n" + arr.join(",\n") + "\n" + indent + "}";
                }
            }

        });
        //这里尽量不依赖其他核主模块
        var $ = function(id) {
            return DOC.getElementById(id);
        };
        var parseHTML = function() {//用于生成元素节点,注意第一层只能用一个元素
            var div = DOC.createElement("div");
            return function(html) {
                div.innerHTML = html;
                return div.firstChild;
            };
        }();
        //在字符串嵌入表达式 http://www.cnblogs.com/rubylouvre/archive/2011/03/06/1972176.html
        var reg_format = /\\?\#{([^{}]+)\}/gm;
        var format = function(str, object){
            var array = dom.slice(arguments,1);
            return str.replace(reg_format, function(match, name){
                if (match.charAt(0) == '\\')
                    return match.slice(1);
                var index = Number(name)
                if(index >=0 )
                    return array[index];
                if(object && object[name] !== void 0)
                    return  object[name];
                return  '' ; ;
            });
        }
        var Expect = function(actual){
            return this instanceof Expect ? this.init(actual) : new Expect(actual);
        }
        function getUnpassExpect(str){
            var boolIndex = 1,ret = "error!",section = 0, qualifier = "("
            for(var j=1;j < str.length;j++){
                if(str.charAt(j) == "("){
                    boolIndex++
                }else if(str.charAt(j) == ")"){
                    boolIndex--
                }else if(str.charAt(j) != qualifier && boolIndex == 0){
                    section++
                    if(section == 1){
                        qualifier = ")"//取得expect(...)中的部分
                        boolIndex = -1
                    }else if(section == 2){
                        boolIndex = 1;//取得ok,eq,match,log等函数名
                        qualifier = ")"
                    }else if(section == 3){//取得最后的函数体,并返回整个匹配项
                        ret = "expect" + str.slice(0,j)
                        break
                    }
                }
            }
            return ret;
        }
    
        dom.require("ready",function(){
            var html = ['<div id="dom-spec-result"><p class="dom-spec-summary">',
            '<span id="dom-spec-failures" title="0">0</span> failures ',
            '<span id="dom-spec-errors" title="0">0</span> errors ',
            '<span id="dom-spec-done" title="0">0</span>% done ',
            '<span id="dom-spec-time" title="0">0</span>ms </p>',
            '<p class="dom-spec-summary">',global.navigator.userAgent,
            '</p><div id="dom-spec-cases"><div id="loading">正在加载测试数据中,请耐心等特</div></div></div>'];
            //div#dom-spec-result为整个系统的容器
            //div#dom-spec-summary用于放置各种统计
            //div#dom-spec-cases用于放置测试模块
            DOC.body.appendChild(parseHTML(html.join("")));
        });

        dom.mix(Expect,{
            refreshTime : function(){//刷新花费时间
                var el = $("dom-spec-time");
                var times = parseInt(el.title,10) + (new Date - Expect.now);
                el.title = times;
                el.innerHTML = times
            },
            addTestModule : function(title, cases) {   
                dom.require("ready",function(){
                    var moduleId = "dom-spec-"+title, names = [];
                    if(!$(moduleId)){//在主显示区中添加一个版块
                        /**   =================每个模块大抵是下面的样子===============
                    <div class="dom-spec-case" id="dom-spec-dom.js">
                    <p><a href="javascript:void(0)">JS文件名字</a></p>
                    <ul style="display: none;" class="dom-spec-detail">
                    测试结果
                    </ul>
                    </div>
                     */
                        var html = ['<div id="#{0}" class="dom-spec-case">',
                        '<p class="dom-spec-slide"><a href="javascript:void(0)">#{1}</a></p>',
                        '<ul class="dom-spec-detail" style="display:none;"></ul></div>'].join('');
                        $("dom-spec-cases").appendChild(parseHTML(format(html, moduleId, title)));
                       
                    }
                    for(var name in cases){//取得describe第二个参数的那个对象所包含的所有函数,并放到异步列队中逐一执行它们
                        if(cases.hasOwnProperty(name)){
                            names.push(name);
                        }
                    };
                    (function runTest(){
                        if((name = names.shift())){
                            var suite = cases[name],//测试函数
                            caseId = "dom-spec-case-"+name.replace(/\./g,"-");
                            if(!Expect.removeLoading){
                                var loading = $("loading");
                                loading.parentNode.removeChild(loading);
                                Expect.removeLoading = 1
                            }        
                            if(!$(caseId)){//对应一个方法
                                var parentNode = $(moduleId).getElementsByTagName("ul")[0];
                                //处理函数体的显示 
                                var safe = (suite+"").replace(/</g,"<").replace(/>/g,">");
                                //从函数体内分解出所有测试单元
                                Expect.expectArray = safe.split("expect");
                                //函数体本身
                                var node = parseHTML(format('<li id="#{0}">#{1}<pre>#{2}</pre></li>',caseId,name,uni2hanzi(safe)));
                                parentNode.appendChild(node);
                            }
                            Expect.Client = $(caseId);//对应一个LI元素
                            Expect.PASS = 1;//用于判定此测试套件有没有通过
                            Expect.boolIndex = 0;//用于记录当前是执行到第几条测试
                            Expect.totalIndex = 0;
                            Expect.now = new Date;
                            try{
                                suite();//执行测试套件
                            }catch(err){
                                Expect.PASS = 2;
                                var htm = ["第",Expect.boolIndex,"行测试发生错误\n",Expect.Msgs[Expect.boolIndex],"\n"];
                                for(var e in err){
                                    htm.push(e+" "+(err[e]+"").slice(0,100)+"\n");
                                }
                                htm = '<pre title="error">'+htm.join("").replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>')+"</pre>";
                                Expect.Client.appendChild(parseHTML(htm));
                                var errors = $("dom-spec-errors");
                                errors.title++;
                                errors.innerHTML = errors.title;
                            }
                            $(caseId).className = Expect.CLASS[Expect.PASS];
                            Expect.refreshTime();//更新测试所花的时间
                            setTimeout(runTest,16);
                        }
                    })();
                });
            },
            CLASS : {
                0:"dom-spec-unpass",
                1:"dom-spec-pass",
                2:"dom-spec-error"
            },
            Msgs:{},
            prototype:{
                init:function(actual){//传入一个目标值以进行比较或打印
                    this.actual = actual;
                    return this;
                },
                ok:function(msg){//判定是否返回true
                    this._should("ok",void 0,msg);
                },
                ng:function(msg){//判定是否返回false
                    this._should("ng",void 0,msg);
                },
                log:function(msg){//不做判断,只打印结果,用于随机数等肉眼验证
                    this._should("log",msg);
                },
                eq:function(expected,msg){//判定目标值与expected是否全等
                    this._should("eq", expected, msg);
                },
                near:function(expected, msg){
                    this._should("near", expected, msg);
                },
                match:function(fn,msg){//判定目标值与expected是否全等
                    this._should("match", fn, msg);
                },
                not:function(expected,msg){//判定目标值与expected是否非全等
                    this._should("not", expected,msg);
                },
                has:function(prop,msg){//判定目标值是否包含prop属性
                    this._should("has", prop,msg);
                },
                contains:function(el,msg){//判定目标值是否包含el这个元素(用于数组或类数组)
                    this._should("contains", el,msg);
                },
                same: function(expected,msg){//判定结果是否与expected相似(用于数组或对象或函数等复合类型)
                    this._should("same", expected,msg);
                },
                _should:function(method,expected, msg){//上面方法的内部实现,比较真伪,并渲染结果到页面
                    var actual = this.actual,bool = false;
                    if(method != "log"){
                        Expect.Msgs[Expect.boolIndex] = msg;
                        Expect.boolIndex++;
                    }
                    Expect.totalIndex++
                    switch(method){
                        case "ok"://布尔真测试
                            bool = actual === true;
                            expected = true;
                            break;
                        case "ng"://布尔非测试
                            bool = actual === false;
                            expected = false;
                            break;
                        case "eq"://同一性真测试
                            bool = actual == expected;
                            break;
                        case "near":
                            var threshold = arguments[3] | 0;
                            return Math.abs(parseFloat(this.actual) - parseFloat(expected)) <= threshold;
                            break;
                        case "not"://同一性非测试
                            bool = actual != expected;
                            break;
                        case "same":
                            bool = dom.isEqual(actual, expected);
                            break
                        case "has":
                            bool = Object.prototype.hasOwnProperty.call(actual, expected);
                            break;
                        case "match":
                            bool = expected(actual);
                            break;
                        case "contains":
                            for(var i = 0,n = actual.length; i < n ;i++ ){
                                if(actual === expected ){
                                    bool = true;
                                    break;
                                }
                            }
                            break;
                        case "log":
                            bool = "";
                            Expect.Client.appendChild(parseHTML('<pre class="dom-spec-log" title="log">'+(expected||"")+"  "+dom.dump(actual)+'</pre>'));
                            break;
                    }
                    // Expect.Msgs[Expect.boolIndex] = msg;
                    //修改统计栏的数值
                    var done = $("dom-spec-done");
                    var errors = $("dom-spec-errors");
                    var failures = $("dom-spec-failures");
                    if(typeof bool === "boolean"){
                        Expect.PASS = ~~bool;
                        if(!bool){//如果没有通过
                            failures.title++;
                            failures.innerHTML = failures.title;
                            var statement = getUnpassExpect((Expect.expectArray[Expect.totalIndex] || ""))
                            var html = ['<div class="dom-spec-diff clearfix">'+(msg ? "<p>"+msg+"</p>" : "")+'<p>本测试套件中第',Expect.boolIndex,
                            '条测试出错: ',statement,'</p><div>actual:<pre title="actual">'+dom.type(actual)+" : "+dom.dump(actual)+'</pre></div>',
                            '<div>expected:<pre title="expected">'+dom.type(expected)+" : "+dom.dump(expected)+'</pre></div>',
                            '</div>'];
                            Expect.Client.appendChild(parseHTML(html.join('')));
                        }
                        done.title++;
                        done.innerHTML = (((done.title-errors.title-failures.title)/done.title)*100).toFixed(0);
                    }
                }
            }
        });
        //用于收起或展开详细测试结果
        dom.bind(DOC,"click",function(e){
            var target = e && e.target || event.srcElement;
           
            if(target.tagName === "A"){
                var parent = target.parentNode.parentNode;
                if(parent.className== "dom-spec-case"){//用于切换详情面板
                    var ul = parent.getElementsByTagName("ul")[0];
                    var display = ul.style.display;
                    ul.style.display = display === "none" ? "" : "none";
                }
            }
        });
        //shortcut
        //暴露到全局作用域
        global.expect = Expect;
        dom.addTestModule = Expect.addTestModule;
        //此函数是解决FF无法显示函数体内的汉字问题
        var uni2hanzi = global.netscape ? function(s){
            return  unescape(s.replace(/\\u/g,'%u'));
        }: function(s){
            return s
        }
        
    })
})(this,this.document);
//2011.8.9    增加getUnpassExpect函数,用于取得没有通过的expect并显示出来
//2011.10.26  优化format与quote
//2011.10.27   runTest添加参数,用于等特一定做量的测试模块都加载完毕才执行
//2011.10.31 去掉deferred模块的依赖,依靠ready列队自行添加测试的模块

用法:

//主页面引用
           dom.require("ready,test/dom,test/lang", dom.noop);

测试用的JS文件:

//    test/dom.js

dom.define("test/dom","first/spec",function(){
    dom.isWindow = function(obj){//单独提出来,专门用于测试对window的判定
        return dom.type(obj,"Window")
    };
    dom.addTestModule('模块加载模块-dom', {
        'type': function() {
            expect(dom.type("string")).eq("String");
            expect(dom.type(1)).eq("Number");
            expect(dom.type(!1)).eq("Boolean");
            expect(dom.type(NaN)).eq("NaN");
            expect(dom.type(/test/i)).eq("RegExp");
            expect(dom.type(dom.noop)).eq("Function");
            expect(dom.type(null)).eq("Null");
            expect(dom.type({})).eq("Object");
            expect(dom.type([])).eq("Array");
            expect(dom.type(new Date)).eq("Date");
            expect(dom.type(window)).eq("Window");
            expect(dom.type(document)).eq("Document");
            expect(dom.type(document.documentElement)).eq("HTML");
            expect(dom.type(document.body)).eq("BODY");
            expect(dom.type(document.childNodes)).eq("NodeList");
            expect(dom.type(document.getElementsByTagName("*"))).eq("NodeList");
            expect(dom.type(arguments)).eq("Arguments");
            expect(dom.type(1,"Number")).eq(true);
        },
        "isWindow" : function(){
            var test1 = {};
            test1.window = test1;
            test1.document = document;
            expect(dom.isWindow(test1)).ng();
            var test2 = {};
            test2.window = window;
            test2.document = document;
            expect(dom.isWindow(test1)).ng();
            expect(dom.isWindow(window)).ok();
            var iframe = document.createElement("iframe");
            document.body.appendChild(iframe);
            var iwin = iframe.contentWindow || iframe.contentDocument.parentWindow;
            expect(dom.isWindow(iwin)).ok();
            document.body.removeChild(iframe);

            var wg = {
                document : {}
            }, wgdoc = wg.document;
            wg.window = wg;
            wgdoc.createElement = function(){
                return wg;
            };
            wgdoc.getElementsByTagName = function(){
                return [wg];
            };
            wgdoc.parentWindow = wg;
            wg.insertBefore = function(){};
            wg.firstChild = wg.firstChild;
            wg.removeChild = function(){};
            expect(dom.isWindow(wg)).ng();//false
        },

        "oneObject":function(){
            expect(dom.oneObject("aa,bb,cc")).same({
                "aa":1,
                "bb":1,
                "cc":1
            });
            expect(dom.oneObject([1,2,3],false)).same({
                "1":false,
                "2":false,
                "3":false
            });
        }
    });
});
//    test/lang.js

dom.define("test/lang","lang,first/spec",function(dom, $$){
    dom.addTestModule("语言扩展模块-lang",{ 
        "dom.isPlainObject": function() {
            expect(dom.isPlainObject([])).ng();//false
            expect(dom.isPlainObject(1)).ng();//false
            expect(dom.isPlainObject(null)).ng();//false
            expect(dom.isPlainObject(void 0)).ng();//false
            expect(dom.isPlainObject(window)).ng();//false
            expect(dom.isPlainObject(document.body)).ng();//false
            expect(window.location).log();
            expect(dom.isPlainObject(window.location)).ng();//false
            var fn = function(){}
            expect(dom.isPlainObject(fn)).ng();//false
            fn.prototype = {
                someMethod: function(){}
            };
            expect(dom.isPlainObject(new fn)).ng();//false
            expect(dom.isPlainObject({})).ok();//true
            expect(dom.isPlainObject({
                aa:"aa",
                bb:"bb",
                cc:"cc"
            })).ok();//true
            expect(dom.isPlainObject(new Object)).ok();//true
        },
        "dom.isArrayLike":function(){
            expect(dom.isArrayLike(arguments)).ok();//1
            expect(dom.isArrayLike(document.links)).ok();//2
            expect(dom.isArrayLike(document.documentElement.childNodes)).ok();
            expect(dom.isArrayLike({
                0:"a",
                1:"b",
                length:2
            })).ok();
            
            var tag = dom.tag
            var html = tag("select",tag("option","aaa") + tag("option","bbb")+ tag("option","ccc"))
            var div = document.createElement("div");
            div.innerHTML = html;
            var select = div.firstChild;
            expect(dom.isArrayLike(select)).ng();

        },
        "dom.isNative":function(){
            expect(dom.isNative(Array.prototype,"slice")).ok();
            expect(dom.isNative(Array.prototype,"indexOf")).log();
            expect(dom.isNative(Array.prototype,"forEach")).log();
            expect(dom.isNative(String.prototype,"quote")).log();
            expect(dom.isNative(String.prototype,"trim")).log();
            expect(dom.isNative(Function.prototype,"bind")).log();
        },
        "dom.range":function(){
            expect(dom.range(10)).same([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
            expect(dom.range(1, 11)).same([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
            expect(dom.range(0, 30, 5)).same([0, 5, 10, 15, 20, 25]);
            expect(dom.range(0, -10, -1)).same([0, -1, -2, -3, -4, -5, -6, -7, -8, -9]);
            expect(dom.range(0)).same([]);
        },
        "dom.format":function(){
            expect(dom.format("pi is #{0}", Math.PI)).eq("pi is 3.141592653589793");
            
            var a = dom.format("style.#{name}=((isEnd ? #{end} : adapter.#{type}( #{from}, #{change},'#{easing}',per ))|0)+'#{unit}';",{
                name:"width",
                end:"0",
                type:"_default",
                from:"200",
                change:"200",
                easing:"linear",
                unit:"px"
            })   ;
           
            expect(a).eq("style.width=((isEnd ? 0 : adapter._default( 200, 200,'linear',per ))|0)+'px';");

        },
        "dom.tag":function(){
            var tag = dom.tag
            var html = tag("h1 title='aaa'","sss")
            ('a href=#' ,
                tag("img src='http://www.google.com.hk/images/nav_logo83.png'")
                ('br')
                ('' ,"View larger image") );
            expect(html+"").eq("<h1 title='aaa'>sss</h1><a href=#><img src='http://www.google.com.hk/images/nav_logo83.png'><br>View larger image</a>");
        },
        "dom.parseXML":function(){
            var str = "<note><to>Tove</to><from>Jani</from><heading>Reminder</heading><body>Don't forget me this weekend!</body></note>"
            expect(dom.parseXML(str).nodeType).eq(9)//[object XMLDocument]
        },
        
        "String2":function(){
            expect($$("aaabbbcc").contains("bbb")).ok();
            expect($$('http://index').startsWith('http')).ok();
            expect($$('image.gif').endsWith('.gif')).ok();
            expect($$('image.gif').endsWith('.GIF')).ng();
            expect($$('image.gif').endsWith(".GIF",true)).ok();

            expect($$('司徒正美').byteLen()).eq(8);

            expect($$('').empty()).ok();
            expect($$(' ').empty()).ng();

            expect($$(' ').blank()).ok();
            expect($$('').blank()).ok();
            expect($$('\n').blank()).ok();
            expect($$(' a').blank()).ng();

            expect($$("this is a test test").truncate(10)).eq("this is...");

            expect($$("foo-bar").camelize()).eq("fooBar");

            expect($$("boo boo boo").capitalize()).eq("Boo boo boo");

            expect($$("fooBar").underscored()).eq("foo_bar");
            expect($$("foo-bar").underscored()).eq("foo_bar");

            expect($$("10.23").toInt()).eq(10);
            expect($$("1.23").toFloat()).eq(1.23);

            expect($$("animals.sheep[1]").escapeRegExp()).eq("animals\\.sheep\\[1\\]");

            expect($$("2").padLeft(4)).eq("0002");

            expect($$("2").padRight(4," ")).eq("2   ");
            expect($$("ruby").times(2)).eq("rubyruby");
        },
        "Array2":function(){
            var a = ["aaa",1,2,undefined,3,4,null,{
                2:2
            }];
            //复制一个副本
            var b = $$(a).clone();
            expect(a).same(b);//1
            expect(a).not(b);//2

            expect($$(a).first()).eq('aaa');//3
            expect($$(a).first(function(el){//4
                return el >1
            })).eq(2);
            expect($$(a).last()).same({//5
                2:2
            });
            expect($$(a).last(function(el){//6
                return el >1
            })).eq(4);

            expect($$(a).contains(2)).ok();//7

            expect($$(a).diff([1,2,3])).same(["aaa",undefined,4,null,{
                2:2
            }]);
            expect($$(b).remove(1)).same([1]);
            expect($$(b).removeAt(1)).same([2]);
            expect($$(a).shuffle()).log();
            expect($$(a).random()).log();
            expect($$(a).compact()).same(["aaa",1,2,3,4,{
                2:2
            }]);
            expect($$(a).ensure(3,4,5)).same(["aaa",1,2,undefined,3,4,null,{
                2:2
            },5]);
            var c = [3,4,6,1,45,9,5,3,4,22,3];
            expect($$(c).min()).eq(1);
            expect($$(c).max()).eq(45);
            expect($$(c).unique()).same([6,1,45,9,5,4,22,3]);
            expect($$([1, 2, 1, 3, 1, 4]).unique()).same([2,3,1,4]);

            var d =['frank', ['bob', 'lisa'], ['jill', ['tom', 'sally']]];
            expect($$(d).flatten()).same(['frank', 'bob', 'lisa', 'jill', 'tom', 'sally']);

            var e = ['hello', 'world', 'this', 'is', 'nice'];
            expect($$(e).pluck("length")).same([5, 5, 4, 2, 4]);
            expect($$(e).sortBy(function(s) {
                return s.length;
            })).same(["is","this","nice","hello","world"]);

            var f = [0,1,2,9];
            var g = [0,5,2];
            expect($$(f).diff(g)).same([1,9]);

            var h = [1,2,3];
            h = $$(h).union([2,3,4,5,6]);//取并集
            expect(h).same([1,2,3,4,5,6]);
            var j = [1, 2, 3, "a"];
            j = $$(j).intersect([1, "a", 2]);//取交集
            expect(j).same([1, 2, "a"]);
            
        },
        "Number2" : function(){
            var a = [];
            $$(8).downto(4, function(i) {
                a.push(i);
            });
            expect(a).same([8,7,6,5,4]);

            expect($$(4.444).round(1)).eq(4.4);
            expect($$(4.444).round(2)).eq(4.44);
            expect($$(4.444).round(3)).eq(4.444);
            expect($$(7).constrain(3,5)).eq(5);
            expect($$(4).constrain(3,5)).eq(4);
            expect($$(4).nearer(3,9)).eq(3);
            expect($$(454).nearer(-4543,6576)).eq(-4543);
        },
        "Object2":function(){

            var a = {
                a:"one",
                b:"two",
                c:"three"
            };
            expect($$(a).subset(["a","c"])).same({
                a: 'one',
                c: 'three'
            });
            a = {
                first: 'Sunday',
                second: 'Monday',
                third: 'Tuesday'
            };
            var b = [];
            $$(a).forEach(function(value,key){
                b.push(value);
            });
            expect(b).same(["Sunday","Monday","Tuesday"]);
            a = {
                e:1,
                b:"aaa",
                c:[1,2,3],
                d:{
                    bb:"bb"
                }
            };

            expect($$(a).clone()).same(a);
            var obj1 = {
                a: 0,
                b: 1
            };
            var obj2 = {
                c: 2,
                d: 3
            };
            var obj3 = {
                a: 4,
                d: 5
            };
            var merged  = $$(obj1).merge(obj2, obj3);
            expect(obj1).same(merged);
            var nestedObj1 = {
                a: {
                    b: 1,
                    c: 1
                }
            };
            var nestedObj2 = {
                a: {
                    b: 2
                }
            };
            var nested  = $$(nestedObj1).merge(nestedObj2);
            expect(nested).same({
                a: {
                    b: 2,
                    c: 1
                }
            });

            a = {
                a:1,
                b:2,
                c:3
            };
            expect($$(a).without("a")).same({
                b:2,
                c:3
            });
        }
    });
});
   


相关链接

dom Framework spec模块

原文地址:https://www.cnblogs.com/rubylouvre/p/2230836.html