Skip to content

Commit ff4d1fc

Browse files
committed
fix(runtime-core): mixin options that rely on this context should be deferred
Also ensure consistent option apply order with Vue 2, close #1016, close #1029
1 parent b0d4df9 commit ff4d1fc

File tree

2 files changed

+267
-187
lines changed

2 files changed

+267
-187
lines changed

packages/runtime-core/__tests__/apiOptions.spec.ts

Lines changed: 152 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,51 @@ describe('api: options', () => {
562562
expect(serializeInner(root)).toBe(`<div>1,1,3</div>`)
563563
})
564564

565+
// #1016
566+
test('watcher initialization should be deferred in mixins', async () => {
567+
const mixin1 = {
568+
data() {
569+
return {
570+
mixin1Data: 'mixin1'
571+
}
572+
},
573+
methods: {}
574+
}
575+
576+
const watchSpy = jest.fn()
577+
const mixin2 = {
578+
watch: {
579+
mixin3Data: watchSpy
580+
}
581+
}
582+
583+
const mixin3 = {
584+
data() {
585+
return {
586+
mixin3Data: 'mixin3'
587+
}
588+
},
589+
methods: {}
590+
}
591+
592+
let vm: any
593+
const Comp = {
594+
mixins: [mixin1, mixin2, mixin3],
595+
render() {},
596+
created() {
597+
vm = this
598+
}
599+
}
600+
601+
const root = nodeOps.createElement('div')
602+
render(h(Comp), root)
603+
604+
// should have no warnings
605+
vm.mixin3Data = 'hello'
606+
await nextTick()
607+
expect(watchSpy.mock.calls[0].slice(0, 2)).toEqual(['hello', 'mixin3'])
608+
})
609+
565610
describe('warnings', () => {
566611
mockWarn()
567612

@@ -631,53 +676,34 @@ describe('api: options', () => {
631676
).toHaveBeenWarned()
632677
})
633678

634-
test('data property is already declared in props', () => {
635-
const Comp = {
636-
props: { foo: Number },
637-
data: () => ({
638-
foo: 1
639-
}),
640-
render() {}
641-
}
642-
643-
const root = nodeOps.createElement('div')
644-
render(h(Comp), root)
645-
expect(
646-
`Data property "foo" is already defined in Props.`
647-
).toHaveBeenWarned()
648-
})
649-
650-
test('computed property is already declared in data', () => {
679+
test('inject property is already declared in props', () => {
651680
const Comp = {
652-
data: () => ({
653-
foo: 1
654-
}),
655-
computed: {
656-
foo() {}
681+
data() {
682+
return {
683+
a: 1
684+
}
657685
},
658-
render() {}
659-
}
660-
661-
const root = nodeOps.createElement('div')
662-
render(h(Comp), root)
663-
expect(
664-
`Computed property "foo" is already defined in Data.`
665-
).toHaveBeenWarned()
666-
})
667-
668-
test('computed property is already declared in props', () => {
669-
const Comp = {
670-
props: { foo: Number },
671-
computed: {
672-
foo() {}
686+
provide() {
687+
return {
688+
a: this.a
689+
}
673690
},
674-
render() {}
675-
}
691+
render() {
692+
return [h(ChildA)]
693+
}
694+
} as any
695+
const ChildA = {
696+
props: { a: Number },
697+
inject: ['a'],
698+
render() {
699+
return this.a
700+
}
701+
} as any
676702

677703
const root = nodeOps.createElement('div')
678704
render(h(Comp), root)
679705
expect(
680-
`Computed property "foo" is already defined in Props.`
706+
`Inject property "a" is already defined in Props.`
681707
).toHaveBeenWarned()
682708
})
683709

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

700-
test('methods property is already declared in data', () => {
726+
test('methods property is already declared in props', () => {
701727
const Comp = {
702-
data: () => ({
703-
foo: 2
704-
}),
728+
props: {
729+
foo: Number
730+
},
705731
methods: {
706732
foo() {}
707733
},
@@ -711,50 +737,60 @@ describe('api: options', () => {
711737
const root = nodeOps.createElement('div')
712738
render(h(Comp), root)
713739
expect(
714-
`Methods property "foo" is already defined in Data.`
740+
`Methods property "foo" is already defined in Props.`
715741
).toHaveBeenWarned()
716742
})
717743

718-
test('methods property is already declared in props', () => {
744+
test('methods property is already declared in inject', () => {
719745
const Comp = {
720-
props: {
721-
foo: Number
746+
data() {
747+
return {
748+
a: 1
749+
}
750+
},
751+
provide() {
752+
return {
753+
a: this.a
754+
}
722755
},
756+
render() {
757+
return [h(ChildA)]
758+
}
759+
} as any
760+
const ChildA = {
723761
methods: {
724-
foo() {}
762+
a: () => null
725763
},
726-
render() {}
727-
}
764+
inject: ['a'],
765+
render() {
766+
return this.a
767+
}
768+
} as any
728769

729770
const root = nodeOps.createElement('div')
730771
render(h(Comp), root)
731772
expect(
732-
`Methods property "foo" is already defined in Props.`
773+
`Methods property "a" is already defined in Inject.`
733774
).toHaveBeenWarned()
734775
})
735776

736-
test('methods property is already declared in computed', () => {
777+
test('data property is already declared in props', () => {
737778
const Comp = {
738-
computed: {
739-
foo: {
740-
get() {},
741-
set() {}
742-
}
743-
},
744-
methods: {
745-
foo() {}
746-
},
779+
props: { foo: Number },
780+
data: () => ({
781+
foo: 1
782+
}),
747783
render() {}
748784
}
749785

750786
const root = nodeOps.createElement('div')
751787
render(h(Comp), root)
752788
expect(
753-
`Methods property "foo" is already defined in Computed.`
789+
`Data property "foo" is already defined in Props.`
754790
).toHaveBeenWarned()
755791
})
756792

757-
test('inject property is already declared in data', () => {
793+
test('data property is already declared in inject', () => {
758794
const Comp = {
759795
data() {
760796
return {
@@ -785,42 +821,45 @@ describe('api: options', () => {
785821
const root = nodeOps.createElement('div')
786822
render(h(Comp), root)
787823
expect(
788-
`Inject property "a" is already defined in Data.`
824+
`Data property "a" is already defined in Inject.`
789825
).toHaveBeenWarned()
790826
})
791827

792-
test('inject property is already declared in props', () => {
828+
test('data property is already declared in methods', () => {
793829
const Comp = {
794-
data() {
795-
return {
796-
a: 1
797-
}
830+
data: () => ({
831+
foo: 1
832+
}),
833+
methods: {
834+
foo() {}
798835
},
799-
provide() {
800-
return {
801-
a: this.a
802-
}
836+
render() {}
837+
}
838+
839+
const root = nodeOps.createElement('div')
840+
render(h(Comp), root)
841+
expect(
842+
`Data property "foo" is already defined in Methods.`
843+
).toHaveBeenWarned()
844+
})
845+
846+
test('computed property is already declared in props', () => {
847+
const Comp = {
848+
props: { foo: Number },
849+
computed: {
850+
foo() {}
803851
},
804-
render() {
805-
return [h(ChildA)]
806-
}
807-
} as any
808-
const ChildA = {
809-
props: { a: Number },
810-
inject: ['a'],
811-
render() {
812-
return this.a
813-
}
814-
} as any
852+
render() {}
853+
}
815854

816855
const root = nodeOps.createElement('div')
817856
render(h(Comp), root)
818857
expect(
819-
`Inject property "a" is already defined in Props.`
858+
`Computed property "foo" is already defined in Props.`
820859
).toHaveBeenWarned()
821860
})
822861

823-
test('inject property is already declared in computed', () => {
862+
test('computed property is already declared in inject', () => {
824863
const Comp = {
825864
data() {
826865
return {
@@ -852,40 +891,43 @@ describe('api: options', () => {
852891
const root = nodeOps.createElement('div')
853892
render(h(Comp), root)
854893
expect(
855-
`Inject property "a" is already defined in Computed.`
894+
`Computed property "a" is already defined in Inject.`
856895
).toHaveBeenWarned()
857896
})
858897

859-
test('inject property is already declared in methods', () => {
898+
test('computed property is already declared in methods', () => {
860899
const Comp = {
861-
data() {
862-
return {
863-
a: 1
864-
}
865-
},
866-
provide() {
867-
return {
868-
a: this.a
869-
}
900+
computed: {
901+
foo() {}
870902
},
871-
render() {
872-
return [h(ChildA)]
873-
}
874-
} as any
875-
const ChildA = {
876903
methods: {
877-
a: () => null
904+
foo() {}
878905
},
879-
inject: ['a'],
880-
render() {
881-
return this.a
882-
}
883-
} as any
906+
render() {}
907+
}
884908

885909
const root = nodeOps.createElement('div')
886910
render(h(Comp), root)
887911
expect(
888-
`Inject property "a" is already defined in Methods.`
912+
`Computed property "foo" is already defined in Methods.`
913+
).toHaveBeenWarned()
914+
})
915+
916+
test('computed property is already declared in data', () => {
917+
const Comp = {
918+
data: () => ({
919+
foo: 1
920+
}),
921+
computed: {
922+
foo() {}
923+
},
924+
render() {}
925+
}
926+
927+
const root = nodeOps.createElement('div')
928+
render(h(Comp), root)
929+
expect(
930+
`Computed property "foo" is already defined in Data.`
889931
).toHaveBeenWarned()
890932
})
891933
})

0 commit comments

Comments
 (0)