import Vue from 'vue' describe('Instance properties', () => { it('$data', () => { const data = { a: 1 } const vm = new Vue({ data }) expect(vm.a).toBe(1) expect(vm.$data).toBe(data) // vm -> data vm.a = 2 expect(data.a).toBe(2) // data -> vm data.a = 3 expect(vm.a).toBe(3) }) it('$options', () => { const A = Vue.extend({ methods: { a() {} } }) const vm = new A({ methods: { b() {} } }) expect(typeof vm.$options.methods?.a).toBe('function') expect(typeof vm.$options.methods?.b).toBe('function') }) it('$root/$children', done => { const vm = new Vue({ template: '
', data: { ok: true }, components: { test: { template: '
' } } }).$mount() expect(vm.$root).toBe(vm) expect(vm.$children.length).toBe(1) expect(vm.$children[0].$root).toBe(vm) vm.ok = false waitForUpdate(() => { expect(vm.$children.length).toBe(0) vm.ok = true }) .then(() => { expect(vm.$children.length).toBe(1) expect(vm.$children[0].$root).toBe(vm) }) .then(done) }) it('$parent', () => { const calls: any[] = [] const makeOption = name => ({ name, template: `
`, created() { calls.push(`${name}:${this.$parent.$options.name}`) } }) new Vue({ template: `
`, components: { outer: makeOption('outer'), middle: makeOption('middle'), inner: makeOption('inner'), next: makeOption('next') } }).$mount() expect(calls).toEqual([ 'outer:undefined', 'middle:outer', 'inner:middle', 'next:undefined' ]) }) it('$props', done => { const Comp = Vue.extend({ props: ['msg'], template: '
{{ msg }} {{ $props.msg }}
' }) const vm = new Comp({ propsData: { msg: 'foo' } }).$mount() // check render expect(vm.$el.textContent).toContain('foo foo') // warn set vm.$props = {} expect('$props is readonly').toHaveBeenWarned() // check existence expect(vm.$props.msg).toBe('foo') // check change vm.msg = 'bar' expect(vm.$props.msg).toBe('bar') waitForUpdate(() => { expect(vm.$el.textContent).toContain('bar bar') }) .then(() => { vm.$props.msg = 'baz' expect(vm.msg).toBe('baz') }) .then(() => { expect(vm.$el.textContent).toContain('baz baz') }) .then(done) }) it('warn mutating $props', () => { const Comp = { props: ['msg'], render() {}, mounted() { expect(this.$props.msg).toBe('foo') this.$props.msg = 'bar' } } new Vue({ template: ``, components: { Comp } }).$mount() expect(`Avoid mutating a prop`).toHaveBeenWarned() }) it('$attrs', done => { const vm = new Vue({ template: ``, data: { foo: 'foo' }, components: { foo: { props: ['bar'], template: `
` } } }).$mount() expect(vm.$el.children[0].id).toBe('foo') expect(vm.$el.children[0].hasAttribute('bar')).toBe(false) vm.foo = 'bar' waitForUpdate(() => { expect(vm.$el.children[0].id).toBe('bar') expect(vm.$el.children[0].hasAttribute('bar')).toBe(false) }).then(done) }) // #6263 it('$attrs should not be undefined when no props passed in', () => { const vm = new Vue({ template: ``, data: { foo: 'foo' }, components: { foo: { template: `
foo
` } } }).$mount() expect(vm.$refs.foo.$attrs).toBeDefined() }) it('warn mutating $attrs', () => { const vm = new Vue() vm.$attrs = {} expect(`$attrs is readonly`).toHaveBeenWarned() }) it('$listeners', done => { const spyA = vi.fn() const spyB = vi.fn() const vm = new Vue({ template: ``, data: { foo: spyA }, components: { foo: { template: `
` } } }).$mount() // has to be in dom for test to pass in IE document.body.appendChild(vm.$el) triggerEvent(vm.$el, 'click') expect(spyA.mock.calls.length).toBe(1) expect(spyB.mock.calls.length).toBe(0) vm.foo = spyB waitForUpdate(() => { triggerEvent(vm.$el, 'click') expect(spyA.mock.calls.length).toBe(1) expect(spyB.mock.calls.length).toBe(1) document.body.removeChild(vm.$el) }).then(done) }) it('warn mutating $listeners', () => { const vm = new Vue() vm.$listeners = {} expect(`$listeners is readonly`).toHaveBeenWarned() }) })