Przeglądaj źródła

nextTick phantomjs fix, unit tests for batcher, config() api addition

Evan You 12 lat temu
rodzic
commit
c7b2d9ca34

+ 1 - 1
component.json

@@ -20,7 +20,7 @@
         "src/deps-parser.js",
         "src/filters.js",
         "src/transition.js",
-        "src/batch.js",
+        "src/batcher.js",
         "src/directives/index.js",
         "src/directives/if.js",
         "src/directives/repeat.js",

+ 1 - 1
src/batch.js → src/batcher.js

@@ -17,7 +17,7 @@ exports.queue = function (binding, method) {
         has[binding.id] = true
         if (!waiting) {
             waiting = true
-            setTimeout(flush, 0)
+            utils.nextTick(flush)
         }
     }
 }

+ 3 - 3
src/binding.js

@@ -1,4 +1,4 @@
-var batch = require('./batch'),
+var batcher = require('./batcher'),
     id = 0
 
 /**
@@ -28,7 +28,7 @@ var BindingProto = Binding.prototype
  */
 BindingProto.update = function (value) {
     this.value = value
-    batch.queue(this, 'update')
+    batcher.queue(this, 'update')
 }
 
 BindingProto._update = function () {
@@ -44,7 +44,7 @@ BindingProto._update = function () {
  *  Force all instances to re-evaluate themselves
  */
 BindingProto.refresh = function () {
-    batch.queue(this, 'refresh')
+    batcher.queue(this, 'refresh')
 }
 
 BindingProto._refresh = function () {

+ 36 - 11
src/config.js

@@ -1,11 +1,36 @@
-module.exports = {
-
-    prefix      : 'v',
-    async       : true,
-    debug       : false,
-    silent      : false,
-    enterClass  : 'v-enter',
-    leaveClass  : 'v-leave',
-    attrs       : {}
-    
-}
+var prefix = 'v',
+    specialAttributes = [
+        'pre',
+        'text',
+        'repeat',
+        'partial',
+        'component',
+        'component-id',
+        'transition'
+    ],
+    config = module.exports = {
+
+        async       : true,
+        debug       : false,
+        silent      : false,
+        enterClass  : 'v-enter',
+        leaveClass  : 'v-leave',
+        attrs       : {},
+
+        get prefix () {
+            return prefix
+        },
+        set prefix (val) {
+            prefix = val
+            updatePrefix()
+        }
+        
+    }
+
+function updatePrefix () {
+    specialAttributes.forEach(function (attr) {
+        config.attrs[attr] = prefix + '-' + attr
+    })
+}
+
+updatePrefix()

+ 8 - 26
src/main.js

@@ -7,10 +7,15 @@ var config      = require('./config'),
 /**
  *  Set config options
  */
-ViewModel.config = function (opts) {
-    if (opts) {
+ViewModel.config = function (opts, val) {
+    if (typeof opts === 'string') {
+        if (val === undefined) {
+            return config[opts]
+        } else {
+            config[opts] = val
+        }
+    } else {
         utils.extend(config, opts)
-        if (opts.prefix) updatePrefix()
     }
     return this
 }
@@ -151,27 +156,4 @@ function mergeHook (fn, parentFn) {
     }
 }
 
-/**
- *  Update prefix for some special directives
- *  that are used in compilation.
- */
-var specialAttributes = [
-    'pre',
-    'text',
-    'repeat',
-    'partial',
-    'component',
-    'component-id',
-    'transition'
-]
-
-function updatePrefix () {
-    specialAttributes.forEach(setPrefix)
-}
-
-function setPrefix (attr) {
-    config.attrs[attr] = config.prefix + '-' + attr
-}
-
-updatePrefix()
 module.exports = ViewModel

+ 15 - 0
src/utils.js

@@ -5,6 +5,14 @@ var config    = require('./config'),
     console   = window.console,
     ViewModel // late def
 
+// PhantomJS doesn't support rAF, yet it has the global
+// variable exposed. Use setTimeout so tests can work.
+var defer = navigator.userAgent.indexOf('PhantomJS') > -1
+    ? window.setTimeout
+    : (window.webkitRequestAnimationFrame ||
+        window.requestAnimationFrame ||
+        window.setTimeout)
+
 /**
  *  Create a prototype-less object
  *  which is a better hash/map
@@ -180,5 +188,12 @@ var utils = module.exports = {
         if (!config.silent && console) {
             console.warn(join.call(arguments, ' '))
         }
+    },
+
+    /**
+     *  used to defer batch updates
+     */
+    nextTick: function (cb) {
+        defer(cb, 0)
     }
 }

+ 6 - 5
src/viewmodel.js

@@ -1,7 +1,8 @@
 var Compiler   = require('./compiler'),
     utils      = require('./utils'),
     transition = require('./transition'),
-    def        = utils.defProtected
+    def        = utils.defProtected,
+    nextTick   = utils.nextTick
 
 /**
  *  ViewModel exposed to the user that holds data,
@@ -103,7 +104,7 @@ def(VMProto, '$appendTo', function (target, cb) {
     var el = this.$el
     transition(el, 1, function () {
         target.appendChild(el)
-        if (cb) setTimeout(cb, 0)
+        if (cb) nextTick(cb)
     }, this.$compiler)
 })
 
@@ -113,7 +114,7 @@ def(VMProto, '$remove', function (cb) {
     if (!parent) return
     transition(el, -1, function () {
         parent.removeChild(el)
-        if (cb) setTimeout(cb, 0)
+        if (cb) nextTick(cb)
     }, this.$compiler)
 })
 
@@ -124,7 +125,7 @@ def(VMProto, '$before', function (target, cb) {
     if (!parent) return
     transition(el, 1, function () {
         parent.insertBefore(el, target)
-        if (cb) setTimeout(cb, 0)
+        if (cb) nextTick(cb)
     }, this.$compiler)
 })
 
@@ -140,7 +141,7 @@ def(VMProto, '$after', function (target, cb) {
         } else {
             parent.appendChild(el)
         }
-        if (cb) setTimeout(cb, 0)
+        if (cb) nextTick(cb)
     }, this.$compiler)
 })
 

+ 1 - 0
test/unit/runner.html

@@ -47,6 +47,7 @@
 		<script src="specs/api.js"></script>
 		<script src="specs/viewmodel.js"></script>
         <script src="specs/transition.js"></script>
+        <script src="specs/batcher.js"></script>
 		<script>
 			if (navigator.userAgent.indexOf('PhantomJS') < 0) {
             	mocha.run(Cover.report)

+ 27 - 16
test/unit/specs/api.js

@@ -1,6 +1,11 @@
 describe('UNIT: API', function () {
 
+    var utils = require('vue/src/utils'),
+        nextTick = utils.nextTick
+
     describe('config()', function () {
+
+        var config = require('vue/src/config')
         
         it('should work when changing prefix', function () {
             var testId = 'config-1'
@@ -15,6 +20,15 @@ describe('UNIT: API', function () {
             assert.strictEqual(document.querySelector('#' + testId + ' span').innerHTML, testId)
         })
 
+        it('should get', function () {
+            assert.strictEqual(Vue.config('debug'), false)
+        })
+
+        it('should set', function () {
+            Vue.config('test', 1)
+            assert.strictEqual(config.test, 1)
+        })
+
         after(function () {
             Vue.config({
                 prefix: 'v'
@@ -109,8 +123,7 @@ describe('UNIT: API', function () {
                 className: 'hihi',
                 data: { hi: 'ok' }
             },
-            Test = Vue.extend(opts),
-            utils = require('vue/src/utils')
+            Test = Vue.extend(opts)
 
         it('should register a Component constructor', function () {
             Vue.component(testId, Test)
@@ -146,8 +159,7 @@ describe('UNIT: API', function () {
     describe('partial()', function () {
 
         var testId = 'api-partial-test',
-            partial = '<div class="partial-test"><a>{{hi}}</a></div><span>hahaha</span>',
-            utils = require('vue/src/utils')
+            partial = '<div class="partial-test"><a>{{hi}}</a></div><span>hahaha</span>'
 
         it('should register the partial as a dom fragment', function () {
             Vue.partial(testId, partial)
@@ -189,8 +201,7 @@ describe('UNIT: API', function () {
     describe('transition()', function () {
         
         var testId = 'api-trans-test',
-            transition = {},
-            utils = require('vue/src/utils')
+            transition = {}
 
         it('should register a transition object', function () {
             Vue.transition(testId, transition)
@@ -230,17 +241,17 @@ describe('UNIT: API', function () {
             document.body.appendChild(t.$el)
             
             t.show = true
-            setTimeout(function () {
+            nextTick(function () {
                 assert.ok(enterCalled)
                 assert.strictEqual(t.$el.style.display, '')
                 t.show = false
-                setTimeout(function () {
+                nextTick(function () {
                     assert.ok(leaveCalled)
                     assert.strictEqual(t.$el.style.display, 'none')
                     t.$destroy()
                     done()
-                }, 0)
-            }, 0)
+                })
+            })
         })
 
     })
@@ -509,10 +520,10 @@ describe('UNIT: API', function () {
                     })
                     assert.strictEqual(t.$el.innerHTML, 'YES')
                     t.ok = false
-                    setTimeout(function () {
+                    nextTick(function () {
                         assert.strictEqual(t.$el.innerHTML, 'NO')
                         done()
-                    }, 0)
+                    })
                 })
 
             })
@@ -635,17 +646,17 @@ describe('UNIT: API', function () {
                     document.body.appendChild(t.$el)
 
                     t.show = true
-                    setTimeout(function () {
+                    nextTick(function () {
                         assert.ok(enterCalled)
                         assert.strictEqual(t.$el.style.display, '')
                         t.show = false
-                        setTimeout(function () {
+                        nextTick(function () {
                             assert.ok(leaveCalled)
                             assert.strictEqual(t.$el.style.display, 'none')
                             t.$destroy()
                             done()
-                        }, 0)
-                    }, 0)
+                        })
+                    })
 
                 })
 

+ 73 - 0
test/unit/specs/batcher.js

@@ -0,0 +1,73 @@
+describe('Batcher', function () {
+
+    var batcher = require('vue/src/batcher'),
+        nextTick = require('vue/src/utils').nextTick
+
+    var updateCount = 0
+    function mockBinding (id, middleware) {
+        return {
+            id: id,
+            _update: function () {
+                updateCount++
+                this.updated = true
+                if (middleware) middleware()
+            }
+        }
+    }
+    
+    it('should queue bindings to be updated on nextTick', function (done) {
+        
+        updateCount = 0
+        var b1 = mockBinding(1),
+            b2 = mockBinding(2)
+        batcher.queue(b1, 'update')
+        batcher.queue(b2, 'update')
+        assert.strictEqual(updateCount, 0)
+        assert.notOk(b1.updated)
+        assert.notOk(b2.updated)
+
+        nextTick(function () {
+            assert.strictEqual(updateCount, 2)
+            assert.ok(b1.updated)
+            assert.ok(b2.updated)
+            done()
+        })
+
+    })
+
+    it('should not queue dupicate bindings', function (done) {
+        
+        updateCount = 0
+        var b1 = mockBinding(1),
+            b2 = mockBinding(1)
+        batcher.queue(b1, 'update')
+        batcher.queue(b2, 'update')
+
+        nextTick(function () {
+            assert.strictEqual(updateCount, 1)
+            assert.ok(b1.updated)
+            assert.notOk(b2.updated)
+            done()
+        })
+
+    })
+
+    it('should queue dependency bidnings triggered during flush', function () {
+        
+        updateCount = 0
+        var b1 = mockBinding(1),
+            b2 = mockBinding(2, function () {
+                batcher.queue(b1, 'update')
+            })
+        batcher.queue(b2, 'update')
+
+        nextTick(function () {
+            assert.strictEqual(updateCount, 2)
+            assert.ok(b1.updated)
+            assert.ok(b2.updated)
+            done()
+        })
+
+    })
+
+})

+ 16 - 3
test/unit/specs/binding.js

@@ -1,6 +1,7 @@
 describe('UNIT: Binding', function () {
 
-    var Binding = require('vue/src/binding')
+    var Binding = require('vue/src/binding'),
+        nextTick = require('vue/src/utils').nextTick
 
     describe('instantiation', function () {
 
@@ -46,7 +47,13 @@ describe('UNIT: Binding', function () {
         b.pub = function () {
             pubbed = true
         }
-        b.update(val)
+
+        before(function (done) {
+            b.update(val)
+            nextTick(function () {
+                done()
+            })
+        })
 
         it('should set the binding\'s value', function () {
             assert.strictEqual(b.value, val)
@@ -75,7 +82,13 @@ describe('UNIT: Binding', function () {
         for (var i = 0; i < numInstances; i++) {
             b.instances.push(instance)
         }
-        b.refresh()
+
+        before(function (done) {
+            b.refresh()
+            nextTick(function () {
+                done()
+            })
+        })
 
         it('should call refresh() of all instances', function () {
             assert.strictEqual(refreshed, numInstances)

+ 13 - 11
test/unit/specs/viewmodel.js

@@ -1,5 +1,7 @@
 describe('UNIT: ViewModel', function () {
 
+    var nextTick = require('vue/src/utils').nextTick
+
     mock('vm-test', '{{a.b.c}}')
     var data = {
             b: {
@@ -180,12 +182,12 @@ describe('UNIT: ViewModel', function () {
             var Bottom = Vue.extend({
                 ready: function () {
                     var self = this
-                    setTimeout(function () {
+                    nextTick(function () {
                         self.$emit('hello', msg)
                         assert.ok(topTriggered)
                         assert.ok(midTriggered)
                         done()
-                    }, 0)
+                    })
                 }
             })
             var Middle = Vue.extend({
@@ -253,10 +255,10 @@ describe('UNIT: ViewModel', function () {
             v.$appendTo(parent, cb)
             assert.strictEqual(v.$el.parentNode, parent)
             assert.ok(enterCalled)
-            setTimeout(function () {
+            nextTick(function () {
                 assert.ok(callbackCalled)
                 done()
-            }, 0)
+            })
         })
 
         it('$before', function (done) {
@@ -268,10 +270,10 @@ describe('UNIT: ViewModel', function () {
             assert.strictEqual(v.$el.parentNode, parent)
             assert.strictEqual(v.$el.nextSibling, ref)
             assert.ok(enterCalled)
-            setTimeout(function () {
+            nextTick(function () {
                 assert.ok(callbackCalled)
                 done()
-            }, 0)
+            })
         })
 
         it('$after', function (done) {
@@ -286,10 +288,10 @@ describe('UNIT: ViewModel', function () {
             assert.strictEqual(v.$el.nextSibling, ref2)
             assert.strictEqual(ref1.nextSibling, v.$el)
             assert.ok(enterCalled)
-            setTimeout(function () {
+            nextTick(function () {
                 assert.ok(callbackCalled)
                 next()
-            }, 0)
+            })
 
             function next () {
                 reset()
@@ -298,10 +300,10 @@ describe('UNIT: ViewModel', function () {
                 assert.notOk(v.$el.nextSibling)
                 assert.strictEqual(ref2.nextSibling, v.$el)
                 assert.ok(enterCalled)
-                setTimeout(function () {
+                nextTick(function () {
                     assert.ok(callbackCalled)
                     done()
-                }, 0)
+                })
             }
         })
 
@@ -313,7 +315,7 @@ describe('UNIT: ViewModel', function () {
             assert.notOk(v.$el.parentNode)
             assert.ok(enterCalled)
             assert.ok(leaveCalled)
-            setTimeout(function () {
+            nextTick(function () {
                 assert.ok(callbackCalled)
                 done()
             })