Procházet zdrojové kódy

instance methods tests

Evan You před 10 roky
rodič
revize
20758d554f

+ 5 - 1
src/core/instance/lifecycle.js

@@ -29,6 +29,7 @@ export function lifecycleMixin (Vue: Class<Component>) {
     if (!vm.$options.render) {
       vm.$options.render = () => emptyVNode
       if (process.env.NODE_ENV !== 'production') {
+        /* istanbul ignore if */
         if (vm.$options.template) {
           warn(
             'You are using the runtime-only build of Vue where the template ' +
@@ -120,7 +121,7 @@ export function lifecycleMixin (Vue: Class<Component>) {
 
   Vue.prototype.$destroy = function () {
     const vm: Component = this
-    if (vm._isDestroyed) {
+    if (vm._isBeingDestroyed) {
       return
     }
     callHook(vm, 'beforeDestroy')
@@ -131,6 +132,9 @@ export function lifecycleMixin (Vue: Class<Component>) {
       remove(parent.$children, vm)
     }
     // teardown watchers
+    if (vm._watcher) {
+      vm._watcher.teardown()
+    }
     let i = vm._watchers.length
     while (i--) {
       vm._watchers[i].teardown()

+ 59 - 0
test/unit/features/instance/methods-events.spec.js

@@ -0,0 +1,59 @@
+import Vue from 'vue'
+
+describe('Instance methods events', () => {
+  let vm, spy
+  beforeEach(() => {
+    vm = new Vue()
+    spy = jasmine.createSpy('emitter')
+  })
+
+  it('$on', () => {
+    vm.$on('test', function () {
+      // expect correct context
+      expect(this).toBe(vm)
+      spy.apply(this, arguments)
+    })
+    vm.$emit('test', 1, 2, 3, 4)
+    expect(spy.calls.count()).toBe(1)
+    expect(spy).toHaveBeenCalledWith(1, 2, 3, 4)
+  })
+
+  it('$once', () => {
+    vm.$once('test', spy)
+    vm.$emit('test', 1, 2, 3)
+    vm.$emit('test', 2, 3, 4)
+    expect(spy.calls.count()).toBe(1)
+    expect(spy).toHaveBeenCalledWith(1, 2, 3)
+  })
+
+  it('$off', () => {
+    vm.$on('test1', spy)
+    vm.$on('test2', spy)
+    vm.$off()
+    vm.$emit('test1')
+    vm.$emit('test2')
+    expect(spy).not.toHaveBeenCalled()
+  })
+
+  it('$off event', () => {
+    vm.$on('test1', spy)
+    vm.$on('test2', spy)
+    vm.$off('test1')
+    vm.$off('test1') // test off something that's already off
+    vm.$emit('test1', 1)
+    vm.$emit('test2', 2)
+    expect(spy.calls.count()).toBe(1)
+    expect(spy).toHaveBeenCalledWith(2)
+  })
+
+  it('$off event + fn', () => {
+    var spy2 = jasmine.createSpy('emitter')
+    vm.$on('test', spy)
+    vm.$on('test', spy2)
+    vm.$off('test', spy)
+    vm.$emit('test', 1, 2, 3)
+    expect(spy).not.toHaveBeenCalled()
+    expect(spy2.calls.count()).toBe(1)
+    expect(spy2).toHaveBeenCalledWith(1, 2, 3)
+  })
+})

+ 113 - 0
test/unit/features/instance/methods-lifecycle.spec.js

@@ -0,0 +1,113 @@
+import Vue from 'vue'
+
+describe('Instance methods lifecycle', () => {
+  describe('$mount', () => {
+    it('empty mount', () => {
+      const vm = new Vue({
+        data: { msg: 'hi' },
+        template: '<div>{{ msg }}</div>'
+      }).$mount()
+      expect(vm.$el.tagName).toBe('DIV')
+      expect(vm.$el.textContent).toBe('hi')
+    })
+
+    it('mount to existing element', () => {
+      const el = document.createElement('div')
+      el.innerHTML = '{{ msg }}'
+      const vm = new Vue({
+        data: { msg: 'hi' }
+      }).$mount(el)
+      expect(vm.$el.tagName).toBe('DIV')
+      expect(vm.$el.textContent).toBe('hi')
+    })
+
+    it('mount to id', () => {
+      const el = document.createElement('div')
+      el.id = 'mount-test'
+      el.innerHTML = '{{ msg }}'
+      document.body.appendChild(el)
+      const vm = new Vue({
+        data: { msg: 'hi' }
+      }).$mount('#mount-test')
+      expect(vm.$el.tagName).toBe('DIV')
+      expect(vm.$el.textContent).toBe('hi')
+    })
+  })
+
+  describe('$destroy', () => {
+    it('remove self from parent', () => {
+      const vm = new Vue({
+        template: '<test></test>',
+        components: {
+          test: { template: '<div></div>' }
+        }
+      }).$mount()
+      vm.$children[0].$destroy()
+      expect(vm.$children.length).toBe(0)
+    })
+
+    it('teardown watchers', () => {
+      const vm = new Vue({
+        data: { a: 123 },
+        template: '<div></div>'
+      }).$mount()
+      vm.$watch('a', () => {})
+      vm.$destroy()
+      expect(vm._watcher.active).toBe(false)
+      expect(vm._watchers.every(w => !w.active)).toBe(true)
+    })
+
+    it('remove self from data observer', () => {
+      const vm = new Vue({ data: { a: 1 }})
+      vm.$destroy()
+      expect(vm.$data.__ob__.vms.length).toBe(0)
+    })
+
+    it('avoid duplicate calls', () => {
+      const spy = jasmine.createSpy('destroy')
+      const vm = new Vue({
+        beforeDestroy: spy
+      })
+      vm.$destroy()
+      vm.$destroy()
+      expect(spy.calls.count()).toBe(1)
+    })
+  })
+
+  describe('$forceUpdate', () => {
+    it('should force update', done => {
+      const vm = new Vue({
+        data: {
+          a: {}
+        },
+        template: '<div>{{ a.b }}</div>'
+      }).$mount()
+      expect(vm.$el.textContent).toBe('')
+      vm.a.b = 'foo'
+      waitForUpdate(() => {
+        // should not work because adding new property
+        expect(vm.$el.textContent).toBe('')
+        vm.$forceUpdate()
+      }).then(() => {
+        expect(vm.$el.textContent).toBe('foo')
+      }).then(done)
+    })
+  })
+
+  describe('$nextTick', () => {
+    it('should be called after DOM update in correct context', done => {
+      const vm = new Vue({
+        template: '<div>{{ msg }}</div>',
+        data: {
+          msg: 'foo'
+        }
+      }).$mount()
+      vm.msg = 'bar'
+      vm.$nextTick(function () {
+        expect(this).toBe(vm)
+        expect(vm.$el.textContent).toBe('bar')
+        done()
+      })
+    })
+  })
+})

+ 70 - 0
test/unit/features/instance/methods-watch.spec.js

@@ -0,0 +1,70 @@
+import Vue from 'vue'
+
+describe('Instance methods watch', () => {
+  let vm, spy
+  beforeEach(() => {
+    vm = new Vue({
+      data: {
+        a: {
+          b: 1
+        }
+      }
+    })
+    spy = jasmine.createSpy('watch')
+  })
+
+  it('basic usage', done => {
+    vm.$watch('a.b', spy)
+    vm.a.b = 2
+    waitForUpdate(() => {
+      expect(spy.calls.count()).toBe(1)
+      expect(spy).toHaveBeenCalledWith(2, 1)
+      vm.a = { b: 3 }
+    }).then(() => {
+      expect(spy.calls.count()).toBe(2)
+      expect(spy).toHaveBeenCalledWith(3, 2)
+    }).then(done)
+  })
+
+  it('immediate', () => {
+    vm.$watch('a.b', spy, { immediate: true })
+    expect(spy.calls.count()).toBe(1)
+    expect(spy).toHaveBeenCalledWith(1)
+  })
+
+  it('unwatch', done => {
+    const unwatch = vm.$watch('a.b', spy)
+    unwatch()
+    vm.a.b = 2
+    waitForUpdate(() => {
+      expect(spy.calls.count()).toBe(0)
+    }).then(done)
+  })
+
+  it('function watch', done => {
+    vm.$watch(function () {
+      return this.a.b
+    }, spy)
+    vm.a.b = 2
+    waitForUpdate(() => {
+      expect(spy).toHaveBeenCalledWith(2, 1)
+    }).then(done)
+  })
+
+  it('deep watch', done => {
+    var oldA = vm.a
+    vm.$watch('a', spy, { deep: true })
+    vm.a.b = 2
+    waitForUpdate(() => {
+      expect(spy).toHaveBeenCalledWith(oldA, oldA)
+      vm.a = { b: 3 }
+    }).then(() => {
+      expect(spy).toHaveBeenCalledWith(vm.a, oldA)
+    }).then(done)
+  })
+
+  it('warn expresssion', () => {
+    vm.$watch('a + b', spy)
+    expect('Watcher only accepts simple dot-delimited paths').toHaveBeenWarned()
+  })
+})

+ 0 - 0
test/unit/features/instance/methods.spec.js


+ 0 - 0
test/unit/features/instance/properties.spec.js