test/unit/features/options/lifecycle.spec.ts TYPESCRIPT 339 lines View on github.com → Search inside
1import Vue from 'vue'23describe('Options lifecycle hooks', () => {4  let spy5  beforeEach(() => {6    spy = vi.fn()7  })89  describe('beforeCreate', () => {10    it('should allow modifying options', () => {11      const vm = new Vue({12        data: {13          a: 114        },15        beforeCreate() {16          spy()17          expect(this.a).toBeUndefined()18          this.$options.computed = {19            b() {20              return this.a + 121            }22          }23        }24      })25      expect(spy).toHaveBeenCalled()26      expect(vm.b).toBe(2)27    })28  })2930  describe('created', () => {31    it('should have completed observation', () => {32      new Vue({33        data: {34          a: 135        },36        created() {37          expect(this.a).toBe(1)38          spy()39        }40      })41      expect(spy).toHaveBeenCalled()42    })43  })4445  describe('beforeMount', () => {46    it('should not have mounted', () => {47      const vm = new Vue({48        render() {},49        beforeMount() {50          spy()51          expect(this._isMounted).toBe(false)52          expect(this.$el).toBeUndefined() // due to empty mount53          expect(this._vnode).toBeNull()54          expect(this._watcher).toBeNull()55        }56      })57      expect(spy).not.toHaveBeenCalled()58      vm.$mount()59      expect(spy).toHaveBeenCalled()60    })61  })6263  describe('mounted', () => {64    it('should have mounted', () => {65      const vm = new Vue({66        template: '<div></div>',67        mounted() {68          spy()69          expect(this._isMounted).toBe(true)70          expect(this.$el.tagName).toBe('DIV')71          expect(this._vnode.tag).toBe('div')72        }73      })74      expect(spy).not.toHaveBeenCalled()75      vm.$mount()76      expect(spy).toHaveBeenCalled()77    })7879    // #389880    it('should call for manually mounted instance with parent', () => {81      const parent = new Vue()82      expect(spy).not.toHaveBeenCalled()83      new Vue({84        parent,85        template: '<div></div>',86        mounted() {87          spy()88        }89      }).$mount()90      expect(spy).toHaveBeenCalled()91    })9293    it('should mount child parent in correct order', () => {94      const calls: any[] = []95      new Vue({96        template: '<div><test></test></div>',97        mounted() {98          calls.push('parent')99        },100        components: {101          test: {102            template: '<nested></nested>',103            mounted() {104              expect(this.$el.parentNode).toBeTruthy()105              calls.push('child')106            },107            components: {108              nested: {109                template: '<div></div>',110                mounted() {111                  expect(this.$el.parentNode).toBeTruthy()112                  calls.push('nested')113                }114              }115            }116          }117        }118      }).$mount()119      expect(calls).toEqual(['nested', 'child', 'parent'])120    })121  })122123  describe('beforeUpdate', () => {124    it('should be called before update', done => {125      const vm = new Vue({126        template: '<div>{{ msg }}</div>',127        data: { msg: 'foo' },128        beforeUpdate() {129          spy()130          expect(this.$el.textContent).toBe('foo')131        }132      }).$mount()133      expect(spy).not.toHaveBeenCalled()134      vm.msg = 'bar'135      expect(spy).not.toHaveBeenCalled() // should be async136      waitForUpdate(() => {137        expect(spy).toHaveBeenCalled()138      }).then(done)139    })140141    it('should be called before render and allow mutating state', done => {142      const vm = new Vue({143        template: '<div>{{ msg }}</div>',144        data: { msg: 'foo' },145        beforeUpdate() {146          this.msg += '!'147        }148      }).$mount()149      expect(vm.$el.textContent).toBe('foo')150      vm.msg = 'bar'151      waitForUpdate(() => {152        expect(vm.$el.textContent).toBe('bar!')153      }).then(done)154    })155156    // #8076157    it('should not be called after destroy', done => {158      const beforeUpdate = vi.fn()159      const destroyed = vi.fn()160161      Vue.component('todo', {162        template: '<div>{{todo.done}}</div>',163        props: ['todo'],164        destroyed,165        beforeUpdate166      })167168      const vm = new Vue({169        template: `170          <div>171            <todo v-for="t in pendingTodos" :todo="t" :key="t.id"></todo>172          </div>173        `,174        data() {175          return {176            todos: [{ id: 1, done: false }]177          }178        },179        computed: {180          pendingTodos() {181            return this.todos.filter(t => !t.done)182          }183        }184      }).$mount()185186      vm.todos[0].done = true187      waitForUpdate(() => {188        expect(destroyed).toHaveBeenCalled()189        expect(beforeUpdate).not.toHaveBeenCalled()190      }).then(done)191    })192  })193194  describe('updated', () => {195    it('should be called after update', done => {196      const vm = new Vue({197        template: '<div>{{ msg }}</div>',198        data: { msg: 'foo' },199        updated() {200          spy()201          expect(this.$el.textContent).toBe('bar')202        }203      }).$mount()204      expect(spy).not.toHaveBeenCalled()205      vm.msg = 'bar'206      expect(spy).not.toHaveBeenCalled() // should be async207      waitForUpdate(() => {208        expect(spy).toHaveBeenCalled()209      }).then(done)210    })211212    it('should be called after children are updated', done => {213      const calls: any[] = []214      const vm = new Vue({215        template: '<div><test ref="child">{{ msg }}</test></div>',216        data: { msg: 'foo' },217        components: {218          test: {219            template: `<div><slot></slot></div>`,220            updated() {221              expect(this.$el.textContent).toBe('bar')222              calls.push('child')223            }224          }225        },226        updated() {227          expect(this.$el.textContent).toBe('bar')228          calls.push('parent')229        }230      }).$mount()231232      expect(calls).toEqual([])233      vm.msg = 'bar'234      expect(calls).toEqual([])235      waitForUpdate(() => {236        expect(calls).toEqual(['child', 'parent'])237      }).then(done)238    })239240    // #8076241    it('should not be called after destroy', done => {242      const updated = vi.fn()243      const destroyed = vi.fn()244245      Vue.component('todo', {246        template: '<div>{{todo.done}}</div>',247        props: ['todo'],248        destroyed,249        updated250      })251252      const vm = new Vue({253        template: `254          <div>255            <todo v-for="t in pendingTodos" :todo="t" :key="t.id"></todo>256          </div>257        `,258        data() {259          return {260            todos: [{ id: 1, done: false }]261          }262        },263        computed: {264          pendingTodos() {265            return this.todos.filter(t => !t.done)266          }267        }268      }).$mount()269270      vm.todos[0].done = true271      waitForUpdate(() => {272        expect(destroyed).toHaveBeenCalled()273        expect(updated).not.toHaveBeenCalled()274      }).then(done)275    })276  })277278  describe('beforeDestroy', () => {279    it('should be called before destroy', () => {280      const vm = new Vue({281        render() {},282        beforeDestroy() {283          spy()284          expect(this._isBeingDestroyed).toBe(false)285          expect(this._isDestroyed).toBe(false)286        }287      }).$mount()288      expect(spy).not.toHaveBeenCalled()289      vm.$destroy()290      vm.$destroy()291      expect(spy).toHaveBeenCalled()292      expect(spy.mock.calls.length).toBe(1)293    })294  })295296  describe('destroyed', () => {297    it('should be called after destroy', () => {298      const vm = new Vue({299        render() {},300        destroyed() {301          spy()302          expect(this._isBeingDestroyed).toBe(true)303          expect(this._isDestroyed).toBe(true)304        }305      }).$mount()306      expect(spy).not.toHaveBeenCalled()307      vm.$destroy()308      vm.$destroy()309      expect(spy).toHaveBeenCalled()310      expect(spy.mock.calls.length).toBe(1)311    })312  })313314  it('should emit hook events', () => {315    const created = vi.fn()316    const mounted = vi.fn()317    const destroyed = vi.fn()318    const vm = new Vue({319      render() {},320      beforeCreate() {321        this.$on('hook:created', created)322        this.$on('hook:mounted', mounted)323        this.$on('hook:destroyed', destroyed)324      }325    })326327    expect(created).toHaveBeenCalled()328    expect(mounted).not.toHaveBeenCalled()329    expect(destroyed).not.toHaveBeenCalled()330331    vm.$mount()332    expect(mounted).toHaveBeenCalled()333    expect(destroyed).not.toHaveBeenCalled()334335    vm.$destroy()336    expect(destroyed).toHaveBeenCalled()337  })338})

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.