Evan You před 12 roky
rodič
revize
9ea607180e

+ 15 - 1
changes.md

@@ -157,4 +157,18 @@ By default the callback only fires when the value changes. If you want it to be
 ``` js
 vm.$watch('a', callback, true)
 // callback is fired immediately with current value of `a`
-``` 
+```
+
+## Simplified Transition API
+
+- no more distinctions between `v-transition`, `v-animation` or `v-effect`;
+- no more configuring enter/leave classes in `Vue.config`;
+- `Vue.effect` has been replaced with `Vue.transition`, the `effects` option has also been replaced by `transitions`.
+
+With `v-transition="my-transition"`, Vue will:
+
+1. Try to find a transition definition object registered either through `Vue.transition(id, def)` or passed in with the `transitions` option, with the id `"my-transition"`. If it finds it, it will use that definition object to perform the custom JavaScript based transition.
+
+2. If no custom JavaScript transition is found, it will automatically sniff whether the target element has CSS transitions or CSS animations applied, and add/remove the classes as before.
+
+3. If no transitions/animations are detected, the DOM manipulation is executed immediately instead of hung up waiting for an event.

+ 1 - 1
gruntfile.js

@@ -22,7 +22,7 @@ module.exports = function (grunt) {
         src: 'src/**/*.js'
       },
       test: {
-        src: 'test/**/*.js'
+        src: ['test/unit/specs/**/*.js']
       }
     },
 

+ 4 - 1
src/directives/transition.js

@@ -1,9 +1,12 @@
 module.exports = {
 
   priority: 1000,
+  isLiteral: true,
 
   bind: function () {
-    this.el.__vueTransition = this.expression
+    this.el.__v_trans = {
+      id: this.expression
+    }
   }
 
 }

+ 1 - 1
src/emitter.js

@@ -115,7 +115,7 @@ p.emit = function (event, a, b, c) {
 
 p.applyEmit = function (event) {
   this._cbs = this._cbs || {}
-  var callbacks = this._cbs[event], args
+  var callbacks = this._cbs[event]
   if (callbacks) {
     // avoid leaking arguments:
     // http://jsperf.com/closure-with-arguments

+ 23 - 5
src/instance/compile.js

@@ -39,7 +39,7 @@ exports._compileNode = function (node) {
 }
 
 /**
- * Compile an Element
+ * Compile an Element.
  *
  * @param {Element} node
  */
@@ -79,7 +79,10 @@ exports._compileElement = function (node) {
 }
 
 /**
- * Compile attribtues on an Element
+ * Compile attribtues on an Element.
+ * Collect directives, sort them by priority,
+ * then bind them. Also check normal directives for
+ * param attributes and interpolation bindings.
  *
  * @param {Element} node
  */
@@ -124,7 +127,13 @@ exports._compileAttrs = function (node) {
 }
 
 /**
- * Compile a TextNode
+ * Compile a TextNode.
+ * Possible interpolations include:
+ *
+ * - normal text binding,    e.g. {{text}}
+ * - unescaped html binding, e.g. {{{html}}}
+ * - one-time text binding,  e.g. {{*text}}
+ * - one-time html binding,  e.g. {{{*html}}}
  *
  * @param {TextNode} node
  */
@@ -166,7 +175,12 @@ exports._compileTextNode = function (node) {
 
 /**
  * Check for priority directives that would potentially
- * skip other directives.
+ * skip other directives. Each priority directive, once
+ * detected, will cause the compilation to skip the rest
+ * and let that directive handle the rest. This allows,
+ * for example, "v-repeat" to handle how it should handle
+ * the situation when "v-component" is also present, and
+ * "v-component" won't have to worry about that.
  *
  * @param {Element} node
  * @return {Boolean}
@@ -212,7 +226,11 @@ exports._bindDirective = function (name, value, node) {
 }
 
 /**
- * Check an attribute for potential bindings.
+ * Check a normal attribute for bindings.
+ * A normal attribute could potentially be:
+ *
+ * - a param attribute (only on root nodes)
+ * - an interpolated attribute, e.g. attr="{{data}}"
  */
 
 exports._bindAttr = function (node, attr) {

+ 128 - 0
src/transition/css.js

@@ -0,0 +1,128 @@
+var _ = require('../util')
+var Batcher = require('../batcher')
+var batcher = new Batcher()
+var transDurationProp = _.transitionProp + 'Duration'
+var animDurationProp = _.animationProp + 'Duration'
+
+/**
+ * Force layout before triggering transitions/animations
+ */
+
+batcher._preFlush = function () {
+  /* jshint unused: false */
+  var f = document.body.offsetHeight
+}
+
+/**
+ * Get an element's transition type based on the
+ * calculated styles
+ *
+ * @param {Element} el
+ * @return {Number}
+ *         1 - transition
+ *         2 - animation
+ */
+
+function getTransitionType (el) {
+  var styles = window.getComputedStyle(el)
+  if (styles[transDurationProp] !== '0s') {
+    return 1
+  } else if (styles[animDurationProp] !== '0s') {
+    return 2
+  }
+}
+
+/**
+ * Apply CSS transition to an element.
+ *
+ * @param {Element} el
+ * @param {Number} direction - 1: enter, -1: leave
+ * @param {Function} op - the actual DOM operation
+ * @param {Object} data - target element's transition data
+ */
+
+module.exports = function (el, direction, op, data) {
+  var classList = el.classList
+  var callback = data.callback
+  var prefix = data.id || 'v'
+  var enterClass = prefix + '-enter'
+  var leaveClass = prefix + '-leave'
+  // clean up potential previously running transitions
+  if (data.callback) {
+    el.removeEventListener(data.event, callback)
+    classList.remove(enterClass)
+    classList.remove(leaveClass)
+    data.event = data.callback = null
+  }
+  var transitionType, onEnd, endEvent
+
+  if (direction > 0) { // enter
+
+    classList.add(enterClass)
+    op()
+    transitionType = getTransitionType(el)
+    if (transitionType === 1) {
+      // Enter Transition
+      //
+      // We need to force a reflow to have the enterClass
+      // applied before removing it to trigger the
+      // transition, so they are batched to make sure
+      // there's only one reflow for everything.
+      batcher.push({
+        run: function () {
+          classList.remove(enterClass)
+        }
+      })
+    } else if (transitionType === 2) {
+      // Enter Animation
+      //
+      // Animations are triggered automatically as the
+      // element is inserted into the DOM, so we just
+      // listen for the animationend event.
+      endEvent = data.event = _.animationEndEvent
+      onEnd = data.callback = function (e) {
+        if (e.target === el) {
+          el.removeEventListener(endEvent, onEnd)
+          data.event = data.callback = null
+          classList.remove(enterClass)
+        }
+      }
+      el.addEventListener(endEvent, onEnd)
+    }
+
+  } else { // leave
+
+    transitionType = getTransitionType(el)
+    if (
+      transitionType &&
+      (el.offsetWidth || el.offsetHeight)
+    ) {
+      // Leave Transition/Animation
+      //
+      // We push it to the batcher to ensure it triggers
+      // in the same frame with other enter transitions
+      // happening at the same time.
+      batcher.push({
+        run: function () {
+          classList.add(leaveClass)
+        }
+      })
+      endEvent = data.event = transitionType === 1
+        ? _.transitionEndEvent
+        : _.animationEndEvent
+      onEnd = data.callback = function (e) {
+        if (e.target === el) {
+          el.removeEventListener(endEvent, onEnd)
+          data.event = data.callback = null
+          // actually remove node here
+          op()
+          classList.remove(leaveClass)
+        }
+      }
+      el.addEventListener(endEvent, onEnd)
+    } else {
+      op()
+    }
+
+  }
+}

+ 99 - 12
src/transition/index.js

@@ -1,28 +1,115 @@
 var _ = require('../util')
+var applyCSSTransition = require('./css')
+var applyJSTransition = require('./js')
 
-// TODO
-// placeholder for testing
+/**
+ * Append with transition.
+ *
+ * @oaram {Element} el
+ * @param {Element} target
+ * @param {Function} [cb]
+ * @param {Vue} vm
+ */
 
 exports.append = function (el, target, cb, vm) {
-  target.appendChild(el)
-  cb && cb()
+  apply(el, 1, function () {
+    target.appendChild(el)
+    if (cb) cb()
+  }, vm)
 }
 
+/**
+ * InsertBefore with transition.
+ *
+ * @oaram {Element} el
+ * @param {Element} target
+ * @param {Function} [cb]
+ * @param {Vue} vm
+ */
+
 exports.before = function (el, target, cb, vm) {
-  _.before(el, target)
-  cb && cb()
+  apply(el, 1, function () {
+    _.before(el, target)
+    if (cb) cb()
+  }, vm)
 }
 
+/**
+ * Remove with transition.
+ *
+ * @oaram {Element} el
+ * @param {Function} [cb]
+ * @param {Vue} vm
+ */
+
 exports.remove = function (el, cb, vm) {
-  _.remove(el)
-  cb && cb()
+  apply(el, -1, function () {
+    _.remove(el)
+    if (cb) cb()
+  }, vm)
 }
 
+/**
+ * Remove by appending to another parent with transition.
+ *
+ * @oaram {Element} el
+ * @param {Element} target
+ * @param {Function} [cb]
+ * @param {Vue} vm
+ */
+
 exports.removeThenAppend = function (el, target, cb, vm) {
-  target.appendChild(el)
-  cb && cb()
+  apply(el, -1, function () {
+    target.appendChild(el)
+    if (cb) cb()
+  }, vm)
 }
 
-exports.apply = function (el, direction, cb, vm) {
-  
+/**
+ * Apply transitions with an operation callback.
+ *
+ * @oaram {Element} el
+ * @param {Number} direction
+ *                  1: enter
+ *                 -1: leave
+ * @param {Function} op - the actual DOM operation
+ * @param {Vue} vm
+ */
+
+var apply = exports.apply = function (el, direction, op, vm) {
+  function applyOp () {
+    op()
+    vm._callHook(direction > 0 ? 'attached' : 'detached')
+  }
+  // if the vm is being manipulated by a parent directive
+  // during the parent's compilation phase, we skip the
+  // animation.
+  if (vm.$parent && !vm.$parent._isCompiled) {
+    applyOp()
+    return
+  }
+  // determine the transition type on the element
+  var transData = el.__v_trans
+  var registry = vm.$options.transitions
+  var jsTransition = transData && registry[transData.id]
+  if (jsTransition) {
+    // js
+    applyJSTransition(
+      el,
+      direction,
+      applyOp,
+      jsTransition
+    )
+  } else if (transData && _.transitionEndEvent) {
+    // css
+    applyCSSTransition(
+      el,
+      direction,
+      applyOp,
+      transData
+    )
+  } else {
+    // not applicable
+    applyOp()
+  }
 }

+ 3 - 0
src/transition/js.js

@@ -0,0 +1,3 @@
+module.exports = function () {
+  
+}

+ 23 - 26
src/util/env.js

@@ -1,7 +1,5 @@
 /**
- * Are we in a browser or in Node?
- * Calling toString on window has inconsistent results in
- * browsers so we do it on the document instead.
+ * Indicates we have a window
  *
  * @type {Boolean}
  */
@@ -43,30 +41,29 @@ exports.isIE9 =
   navigator.userAgent.indexOf('MSIE 9.0') > 0
 
 /**
- * Detect transition and animation end events.
+ * Sniff transition/animation events
  */
 
-var testElement = inBrowser
-  ? document.createElement('div')
-  : undefined
-
-exports.transitionEndEvent = (function () {
-  if (inBrowser) {
-    var map = {
-      'webkitTransition' : 'webkitTransitionEnd',
-      'transition'       : 'transitionend',
-      'mozTransition'    : 'transitionend'
-    }
-    for (var prop in map) {
-      if (testElement.style[prop] !== undefined) {
-        return map[prop]
-      }
-    }
+if (inBrowser) {
+  if (
+    window.ontransitionend === undefined &&
+    window.onwebkittransitionend !== undefined
+  ) {
+    exports.transitionProp = 'WebkitTransition'
+    exports.transitionEndEvent = 'webkitTransitionEnd'
+  } else {
+    exports.transitionProp = 'transition'
+    exports.transitionEndEvent = 'transitionend'
   }
-})()
 
-exports.animationEndEvent = inBrowser
-  ? testElement.style.animation !== undefined
-    ? 'animationend'
-    : 'webkitAnimationEnd'
-  : undefined
+  if (
+    window.onanimationend === undefined &&
+    window.onwebkitanimationend !== undefined
+  ) {
+    exports.animationProp = 'WebkitAnimation'
+    exports.animationEndEvent = 'webkitAnimationEnd'
+  } else {
+    exports.animationProp = 'animation'
+    exports.animationEndEvent = 'animationend'
+  }
+}

+ 2 - 1
src/watcher.js

@@ -71,10 +71,11 @@ p.initDeps = function (res) {
   this.isComputed = true
   this.value = this.get()
   var computed = this.vm.$options.computed
+  var exp = this.expression
   this.isComputed =
     this.filters || // filters may access instance data
     res.computed || // inline expression
-    (computed && computed[expression]) // computed property
+    (computed && computed[exp]) // computed property
 }
 
 /**

+ 6 - 4
test/.jshintrc

@@ -4,12 +4,13 @@
   "asi": true,
   "multistr": true,
   "undef": true,
-  "unused": true,
+  "unused": false,
   "trailing": true,
   "sub": true,
   "node": true,
   "laxbreak": true,
   "evil": true,
+  "proto": true,
   "globals": {
     "console": true,
     "it": true,
@@ -17,12 +18,13 @@
     "beforeEach": true,
     "afterEach": true,
     "expect": true,
-    "mock": true,
+    "jasmine": true,
+    "spyOn": true,
     "Vue": true,
-    "$": true,
     "mockHTMLEvent": true,
     "mockMouseEvent": true,
     "mockKeyEvent": true,
-    "casper": true
+    "casper": true,
+    "DocumentFragment": true
   }
 }

+ 9 - 0
test/unit/specs/batcher_spec.js

@@ -53,4 +53,13 @@ describe('Batcher', function () {
     })
   })
 
+  it('preFlush hook', function (done) {
+    batcher._preFlush = spy
+    batcher.push({ run: function () {}})
+    nextTick(function () {
+      expect(spy.calls.count()).toBe(1)
+      done()
+    })
+  })
+
 })

+ 1 - 2
test/unit/specs/emitter_spec.js

@@ -1,5 +1,4 @@
 var Emitter = require('../../../src/emitter')
-var u = undefined
 
 describe('Emitter', function () {
 
@@ -41,7 +40,7 @@ describe('Emitter', function () {
     e.emit('test1', 1)
     e.emit('test2', 2)
     expect(spy.calls.count()).toBe(1)
-    expect(spy).toHaveBeenCalledWith(2, u, u)
+    expect(spy).toHaveBeenCalledWith(2, undefined, undefined)
   })
 
   it('off event + fn', function () {

+ 12 - 13
test/unit/specs/instance/scope_spec.js

@@ -5,7 +5,6 @@
 
 var Vue = require('../../../../src/vue')
 var Observer = require('../../../../src/observe/observer')
-var u = undefined
 Observer.pathDelimiter = '.'
 
 describe('Scope', function () {
@@ -38,12 +37,12 @@ describe('Scope', function () {
       // set on scope
       vm.$scope.a = 2
       expect(spy.calls.count()).toBe(1)
-      expect(spy).toHaveBeenCalledWith('a', 2, u)
+      expect(spy).toHaveBeenCalledWith('a', 2, undefined)
 
       // set on vm
       vm.b.c = 3
       expect(spy.calls.count()).toBe(2)
-      expect(spy).toHaveBeenCalledWith('b.c', 3, u)
+      expect(spy).toHaveBeenCalledWith('b.c', 3, undefined)
     })
 
     it('should trigger add/delete events', function () {
@@ -55,12 +54,12 @@ describe('Scope', function () {
       // add on scope
       vm.$scope.$add('c', 123)
       expect(spy.calls.count()).toBe(1)
-      expect(spy).toHaveBeenCalledWith('c', 123, u)
+      expect(spy).toHaveBeenCalledWith('c', 123, undefined)
 
       // delete on scope
       vm.$scope.$delete('c')
       expect(spy.calls.count()).toBe(2)
-      expect(spy).toHaveBeenCalledWith('c', u, u)
+      expect(spy).toHaveBeenCalledWith('c', undefined, undefined)
 
       // vm $add/$delete are tested in the api suite
     })
@@ -162,19 +161,19 @@ describe('Scope', function () {
       child.$observer.on('set', spy)
       parent.c = 'c changed'
       expect(spy.calls.count()).toBe(1)
-      expect(spy).toHaveBeenCalledWith('c', 'c changed', u)
+      expect(spy).toHaveBeenCalledWith('c', 'c changed', undefined)
 
       spy = jasmine.createSpy('inheritance')
       child.$observer.on('add', spy)
       parent.$scope.$add('e', 123)
       expect(spy.calls.count()).toBe(1)
-      expect(spy).toHaveBeenCalledWith('e', 123, u)
+      expect(spy).toHaveBeenCalledWith('e', 123, undefined)
 
       spy = jasmine.createSpy('inheritance')
       child.$observer.on('delete', spy)
       parent.$scope.$delete('e')
       expect(spy.calls.count()).toBe(1)
-      expect(spy).toHaveBeenCalledWith('e', u, u)
+      expect(spy).toHaveBeenCalledWith('e', undefined, undefined)
 
       spy = jasmine.createSpy('inheritance')
       child.$observer.on('mutate', spy)
@@ -221,11 +220,11 @@ describe('Scope', function () {
       expect(parent.arr[0].a).toBe(3)
 
       expect(parentSpy.calls.count()).toBe(1)
-      expect(parentSpy).toHaveBeenCalledWith('arr.0.a', 3, u)
+      expect(parentSpy).toHaveBeenCalledWith('arr.0.a', 3, undefined)
 
       expect(childSpy.calls.count()).toBe(2)
-      expect(childSpy).toHaveBeenCalledWith('a', 3, u)
-      expect(childSpy).toHaveBeenCalledWith('arr.0.a', 3, u)
+      expect(childSpy).toHaveBeenCalledWith('a', 3, undefined)
+      expect(childSpy).toHaveBeenCalledWith('arr.0.a', 3, undefined)
     })
 
   })
@@ -250,8 +249,8 @@ describe('Scope', function () {
       expect(vm._data).toBe(newData)
       expect(vm.a).toBe(2)
       expect(vm.b).toBe(3)
-      expect(vmSpy).toHaveBeenCalledWith('a', 2, u)
-      expect(vmAddSpy).toHaveBeenCalledWith('b', 3, u)
+      expect(vmSpy).toHaveBeenCalledWith('a', 2, undefined)
+      expect(vmAddSpy).toHaveBeenCalledWith('b', 3, undefined)
     })
 
     it('should unsync old data', function () {

+ 26 - 29
test/unit/specs/observer_spec.js

@@ -4,9 +4,6 @@
 
 var Observer = require('../../../src/observe/observer')
 var _ = require('../../../src/util')
-// internal emitter has fixed 3 arguments
-// so we need to fill up the assetions with undefined
-var u = undefined
 Observer.pathDelimiter = '.'
 
 describe('Observer', function () {
@@ -30,12 +27,12 @@ describe('Observer', function () {
     ob.on('get', spy)
 
     var t = obj.a
-    expect(spy).toHaveBeenCalledWith('a', u, u)
+    expect(spy).toHaveBeenCalledWith('a', undefined, undefined)
     expect(spy.calls.count()).toBe(1)
 
     t = obj.b.c
-    expect(spy).toHaveBeenCalledWith('b', u, u)
-    expect(spy).toHaveBeenCalledWith('b.c', u, u)
+    expect(spy).toHaveBeenCalledWith('b', undefined, undefined)
+    expect(spy).toHaveBeenCalledWith('b.c', undefined, undefined)
     expect(spy.calls.count()).toBe(3)
 
     Observer.emitGet = false
@@ -52,17 +49,17 @@ describe('Observer', function () {
     ob.on('set', spy)
 
     obj.a = 3
-    expect(spy).toHaveBeenCalledWith('a', 3, u)
+    expect(spy).toHaveBeenCalledWith('a', 3, undefined)
     expect(spy.calls.count()).toBe(1)
 
     obj.b.c = 4
-    expect(spy).toHaveBeenCalledWith('b.c', 4, u)
+    expect(spy).toHaveBeenCalledWith('b.c', 4, undefined)
     expect(spy.calls.count()).toBe(2)
 
     // swap set
     var newB = { c: 5 }
     obj.b = newB
-    expect(spy).toHaveBeenCalledWith('b', newB, u)
+    expect(spy).toHaveBeenCalledWith('b', newB, undefined)
     expect(spy.calls.count()).toBe(3)
 
     // same value set should not emit events
@@ -116,8 +113,8 @@ describe('Observer', function () {
     ob.on('get', spy)
 
     var t = obj.arr[0].a
-    expect(spy).toHaveBeenCalledWith('arr', u, u)
-    expect(spy).toHaveBeenCalledWith('arr.0.a', u, u)
+    expect(spy).toHaveBeenCalledWith('arr', undefined, undefined)
+    expect(spy).toHaveBeenCalledWith('arr.0.a', undefined, undefined)
     expect(spy.calls.count()).toBe(2)
 
     Observer.emitGet = false
@@ -131,12 +128,12 @@ describe('Observer', function () {
     ob.on('set', spy)
 
     obj.arr[0].a = 2
-    expect(spy).toHaveBeenCalledWith('arr.0.a', 2, u)
+    expect(spy).toHaveBeenCalledWith('arr.0.a', 2, undefined)
 
     // set events after mutation
     obj.arr.reverse()
     obj.arr[0].a = 3
-    expect(spy).toHaveBeenCalledWith('arr.0.a', 3, u)
+    expect(spy).toHaveBeenCalledWith('arr.0.a', 3, undefined)
   })
 
   it('array push', function () {
@@ -156,7 +153,7 @@ describe('Observer', function () {
     // test index update after mutation
     ob.on('set', spy)
     arr[2].a = 4
-    expect(spy).toHaveBeenCalledWith('2.a', 4, u)
+    expect(spy).toHaveBeenCalledWith('2.a', 4, undefined)
   })
 
   it('array pop', function () {
@@ -194,7 +191,7 @@ describe('Observer', function () {
     // test index update after mutation
     ob.on('set', spy)
     arr[0].a = 4
-    expect(spy).toHaveBeenCalledWith('0.a', 4, u)
+    expect(spy).toHaveBeenCalledWith('0.a', 4, undefined)
   })
 
   it('array unshift', function () {
@@ -215,7 +212,7 @@ describe('Observer', function () {
     // test index update after mutation
     ob.on('set', spy)
     arr[1].a = 4
-    expect(spy).toHaveBeenCalledWith('1.a', 4, u)
+    expect(spy).toHaveBeenCalledWith('1.a', 4, undefined)
   })
 
   it('array splice', function () {
@@ -238,7 +235,7 @@ describe('Observer', function () {
     // test index update after mutation
     ob.on('set', spy)
     arr[1].a = 4
-    expect(spy).toHaveBeenCalledWith('1.a', 4, u)
+    expect(spy).toHaveBeenCalledWith('1.a', 4, undefined)
   })
 
   it('array sort', function () {
@@ -259,7 +256,7 @@ describe('Observer', function () {
     // test index update after mutation
     ob.on('set', spy)
     arr[1].a = 4
-    expect(spy).toHaveBeenCalledWith('1.a', 4, u)
+    expect(spy).toHaveBeenCalledWith('1.a', 4, undefined)
   })
 
   it('array reverse', function () {
@@ -278,7 +275,7 @@ describe('Observer', function () {
     // test index update after mutation
     ob.on('set', spy)
     arr[1].a = 4
-    expect(spy).toHaveBeenCalledWith('1.a', 4, u)
+    expect(spy).toHaveBeenCalledWith('1.a', 4, undefined)
   })
 
   it('object.$add', function () {
@@ -293,12 +290,12 @@ describe('Observer', function () {
     // add event
     var add = {d:2}
     obj.a.$add('c', add)
-    expect(spy).toHaveBeenCalledWith('a.c', add, u)
+    expect(spy).toHaveBeenCalledWith('a.c', add, undefined)
 
     // check if add object is properly observed
     ob.on('set', spy)
     obj.a.c.d = 3
-    expect(spy).toHaveBeenCalledWith('a.c.d', 3, u)
+    expect(spy).toHaveBeenCalledWith('a.c.d', 3, undefined)
   })
 
   it('object.$delete', function () {
@@ -311,7 +308,7 @@ describe('Observer', function () {
     expect(spy.calls.count()).toBe(0)
 
     obj.a.$delete('b')
-    expect(spy).toHaveBeenCalledWith('a.b', u, u)
+    expect(spy).toHaveBeenCalledWith('a.b', undefined, undefined)
   })
 
   it('array.$set', function () {
@@ -335,7 +332,7 @@ describe('Observer', function () {
 
     ob.on('set', spy)
     arr[1].a = 4
-    expect(spy).toHaveBeenCalledWith('1.a', 4, u)
+    expect(spy).toHaveBeenCalledWith('1.a', 4, undefined)
   })
 
   it('array.$set with out of bound length', function () {
@@ -366,7 +363,7 @@ describe('Observer', function () {
 
     ob.on('set', spy)
     arr[0].a = 3
-    expect(spy).toHaveBeenCalledWith('0.a', 3, u)
+    expect(spy).toHaveBeenCalledWith('0.a', 3, undefined)
   })
 
   it('array.$remove object', function () {
@@ -387,7 +384,7 @@ describe('Observer', function () {
 
     ob.on('set', spy)
     arr[0].a = 3
-    expect(spy).toHaveBeenCalledWith('0.a', 3, u)
+    expect(spy).toHaveBeenCalledWith('0.a', 3, undefined)
   })
 
   it('shared observe', function () {
@@ -400,14 +397,14 @@ describe('Observer', function () {
     obB.on('set', spy)
     obj.a = 2
     expect(spy.calls.count()).toBe(2)
-    expect(spy).toHaveBeenCalledWith('child1.a', 2, u)
-    expect(spy).toHaveBeenCalledWith('child2.a', 2, u)
+    expect(spy).toHaveBeenCalledWith('child1.a', 2, undefined)
+    expect(spy).toHaveBeenCalledWith('child2.a', 2, undefined)
     // test unobserve
     parentA.child1 = null
     obj.a = 3
     expect(spy.calls.count()).toBe(4)
-    expect(spy).toHaveBeenCalledWith('child1', null, u)
-    expect(spy).toHaveBeenCalledWith('child2.a', 3, u)
+    expect(spy).toHaveBeenCalledWith('child1', null, undefined)
+    expect(spy).toHaveBeenCalledWith('child2.a', 3, undefined)
   })
 
 })

+ 1 - 1
test/unit/specs/util/lang_spec.js

@@ -135,7 +135,7 @@ describe('Util - Language Enhancement', function () {
 
     _.define(obj, 'test2', 123, true)
     expect(obj.test2).toBe(123)
-    var desc = Object.getOwnPropertyDescriptor(obj, 'test2')
+    desc = Object.getOwnPropertyDescriptor(obj, 'test2')
     expect(desc.enumerable).toBe(true)
   })
 

+ 1 - 1
test/unit/specs/util/option_spec.js

@@ -9,7 +9,7 @@ describe('Util - Option merging', function () {
     var res = merge({replace:true}, {}).replace
     expect(res).toBe(true)
     // child overwrite
-    var res = merge({replace:true}, {replace:false}).replace
+    res = merge({replace:true}, {replace:false}).replace
     expect(res).toBe(false)
   })