Skip to content

Commit

Permalink
fix(runtime-core): mixin options that rely on this context should be …
Browse files Browse the repository at this point in the history
…deferred

Also ensure consistent option apply order with Vue 2, close #1016, close #1029
  • Loading branch information
yyx990803 committed Apr 22, 2020
1 parent b0d4df9 commit ff4d1fc
Show file tree
Hide file tree
Showing 2 changed files with 267 additions and 187 deletions.
262 changes: 152 additions & 110 deletions packages/runtime-core/__tests__/apiOptions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,51 @@ describe('api: options', () => {
expect(serializeInner(root)).toBe(`<div>1,1,3</div>`)
})

// #1016
test('watcher initialization should be deferred in mixins', async () => {
const mixin1 = {
data() {
return {
mixin1Data: 'mixin1'
}
},
methods: {}
}

const watchSpy = jest.fn()
const mixin2 = {
watch: {
mixin3Data: watchSpy
}
}

const mixin3 = {
data() {
return {
mixin3Data: 'mixin3'
}
},
methods: {}
}

let vm: any
const Comp = {
mixins: [mixin1, mixin2, mixin3],
render() {},
created() {
vm = this
}
}

const root = nodeOps.createElement('div')
render(h(Comp), root)

// should have no warnings
vm.mixin3Data = 'hello'
await nextTick()
expect(watchSpy.mock.calls[0].slice(0, 2)).toEqual(['hello', 'mixin3'])
})

describe('warnings', () => {
mockWarn()

Expand Down Expand Up @@ -631,53 +676,34 @@ describe('api: options', () => {
).toHaveBeenWarned()
})

test('data property is already declared in props', () => {
const Comp = {
props: { foo: Number },
data: () => ({
foo: 1
}),
render() {}
}

const root = nodeOps.createElement('div')
render(h(Comp), root)
expect(
`Data property "foo" is already defined in Props.`
).toHaveBeenWarned()
})

test('computed property is already declared in data', () => {
test('inject property is already declared in props', () => {
const Comp = {
data: () => ({
foo: 1
}),
computed: {
foo() {}
data() {
return {
a: 1
}
},
render() {}
}

const root = nodeOps.createElement('div')
render(h(Comp), root)
expect(
`Computed property "foo" is already defined in Data.`
).toHaveBeenWarned()
})

test('computed property is already declared in props', () => {
const Comp = {
props: { foo: Number },
computed: {
foo() {}
provide() {
return {
a: this.a
}
},
render() {}
}
render() {
return [h(ChildA)]
}
} as any
const ChildA = {
props: { a: Number },
inject: ['a'],
render() {
return this.a
}
} as any

const root = nodeOps.createElement('div')
render(h(Comp), root)
expect(
`Computed property "foo" is already defined in Props.`
`Inject property "a" is already defined in Props.`
).toHaveBeenWarned()
})

Expand All @@ -697,11 +723,11 @@ describe('api: options', () => {
).toHaveBeenWarned()
})

test('methods property is already declared in data', () => {
test('methods property is already declared in props', () => {
const Comp = {
data: () => ({
foo: 2
}),
props: {
foo: Number
},
methods: {
foo() {}
},
Expand All @@ -711,50 +737,60 @@ describe('api: options', () => {
const root = nodeOps.createElement('div')
render(h(Comp), root)
expect(
`Methods property "foo" is already defined in Data.`
`Methods property "foo" is already defined in Props.`
).toHaveBeenWarned()
})

test('methods property is already declared in props', () => {
test('methods property is already declared in inject', () => {
const Comp = {
props: {
foo: Number
data() {
return {
a: 1
}
},
provide() {
return {
a: this.a
}
},
render() {
return [h(ChildA)]
}
} as any
const ChildA = {
methods: {
foo() {}
a: () => null
},
render() {}
}
inject: ['a'],
render() {
return this.a
}
} as any

const root = nodeOps.createElement('div')
render(h(Comp), root)
expect(
`Methods property "foo" is already defined in Props.`
`Methods property "a" is already defined in Inject.`
).toHaveBeenWarned()
})

test('methods property is already declared in computed', () => {
test('data property is already declared in props', () => {
const Comp = {
computed: {
foo: {
get() {},
set() {}
}
},
methods: {
foo() {}
},
props: { foo: Number },
data: () => ({
foo: 1
}),
render() {}
}

const root = nodeOps.createElement('div')
render(h(Comp), root)
expect(
`Methods property "foo" is already defined in Computed.`
`Data property "foo" is already defined in Props.`
).toHaveBeenWarned()
})

test('inject property is already declared in data', () => {
test('data property is already declared in inject', () => {
const Comp = {
data() {
return {
Expand Down Expand Up @@ -785,42 +821,45 @@ describe('api: options', () => {
const root = nodeOps.createElement('div')
render(h(Comp), root)
expect(
`Inject property "a" is already defined in Data.`
`Data property "a" is already defined in Inject.`
).toHaveBeenWarned()
})

test('inject property is already declared in props', () => {
test('data property is already declared in methods', () => {
const Comp = {
data() {
return {
a: 1
}
data: () => ({
foo: 1
}),
methods: {
foo() {}
},
provide() {
return {
a: this.a
}
render() {}
}

const root = nodeOps.createElement('div')
render(h(Comp), root)
expect(
`Data property "foo" is already defined in Methods.`
).toHaveBeenWarned()
})

test('computed property is already declared in props', () => {
const Comp = {
props: { foo: Number },
computed: {
foo() {}
},
render() {
return [h(ChildA)]
}
} as any
const ChildA = {
props: { a: Number },
inject: ['a'],
render() {
return this.a
}
} as any
render() {}
}

const root = nodeOps.createElement('div')
render(h(Comp), root)
expect(
`Inject property "a" is already defined in Props.`
`Computed property "foo" is already defined in Props.`
).toHaveBeenWarned()
})

test('inject property is already declared in computed', () => {
test('computed property is already declared in inject', () => {
const Comp = {
data() {
return {
Expand Down Expand Up @@ -852,40 +891,43 @@ describe('api: options', () => {
const root = nodeOps.createElement('div')
render(h(Comp), root)
expect(
`Inject property "a" is already defined in Computed.`
`Computed property "a" is already defined in Inject.`
).toHaveBeenWarned()
})

test('inject property is already declared in methods', () => {
test('computed property is already declared in methods', () => {
const Comp = {
data() {
return {
a: 1
}
},
provide() {
return {
a: this.a
}
computed: {
foo() {}
},
render() {
return [h(ChildA)]
}
} as any
const ChildA = {
methods: {
a: () => null
foo() {}
},
inject: ['a'],
render() {
return this.a
}
} as any
render() {}
}

const root = nodeOps.createElement('div')
render(h(Comp), root)
expect(
`Inject property "a" is already defined in Methods.`
`Computed property "foo" is already defined in Methods.`
).toHaveBeenWarned()
})

test('computed property is already declared in data', () => {
const Comp = {
data: () => ({
foo: 1
}),
computed: {
foo() {}
},
render() {}
}

const root = nodeOps.createElement('div')
render(h(Comp), root)
expect(
`Computed property "foo" is already defined in Data.`
).toHaveBeenWarned()
})
})
Expand Down
Loading

0 comments on commit ff4d1fc

Please sign in to comment.