diff --git a/packages/runtime-core/__tests__/componentProps.spec.ts b/packages/runtime-core/__tests__/componentProps.spec.ts
index ca30dd8232c..fbe274d2c60 100644
--- a/packages/runtime-core/__tests__/componentProps.spec.ts
+++ b/packages/runtime-core/__tests__/componentProps.spec.ts
@@ -278,26 +278,54 @@ describe('component props', () => {
expect(root.innerHTML).toBe('
2
')
})
- test('validator arguments', async () => {
- const mockFn = jest.fn((...args: any[]) => true)
- const Comp = defineComponent({
- props: {
- foo: {
- type: Number,
- validator: (value, props) => mockFn(value, props)
+ describe('validator', () => {
+ test('validator should be called with two arguments', async () => {
+ const mockFn = jest.fn((...args: any[]) => true)
+ const Comp = defineComponent({
+ props: {
+ foo: {
+ type: Number,
+ validator: (value, props) => mockFn(value, props)
+ },
+ bar: {
+ type: Number
+ }
},
- bar: {
- type: Number
- }
- },
- template: ``
+ template: ``
+ })
+
+ // Note this one is using the main Vue render so it can compile template
+ // on the fly
+ const root = document.createElement('div')
+ domRender(h(Comp, { foo: 1, bar: 2 }), root)
+ expect(mockFn).toHaveBeenCalledWith(1, { foo: 1, bar: 2 })
})
- // Note this one is using the main Vue render so it can compile template
- // on the fly
- const root = document.createElement('div')
- domRender(h(Comp, { foo: 1, bar: 2 }), root)
- expect(mockFn).toHaveBeenCalledWith(1, { foo: 1, bar: 2 })
+ test('validator should not be able to mutate other props', async () => {
+ const mockFn = jest.fn((...args: any[]) => true)
+ const Comp = defineComponent({
+ props: {
+ foo: {
+ type: Number,
+ validator: (value, props) => !!(props.bar = 1)
+ },
+ bar: {
+ type: Number,
+ validator: value => mockFn(value)
+ }
+ },
+ template: ``
+ })
+
+ // Note this one is using the main Vue render so it can compile template
+ // on the fly
+ const root = document.createElement('div')
+ domRender(h(Comp, { foo: 1, bar: 2 }), root)
+ expect(
+ `Set operation on key "bar" failed: target is readonly.`
+ ).toHaveBeenWarnedLast()
+ expect(mockFn).toHaveBeenCalledWith(2)
+ })
})
test('warn props mutation', () => {
diff --git a/packages/runtime-core/src/componentProps.ts b/packages/runtime-core/src/componentProps.ts
index e634314af76..c7568227ae3 100644
--- a/packages/runtime-core/src/componentProps.ts
+++ b/packages/runtime-core/src/componentProps.ts
@@ -2,7 +2,8 @@ import {
toRaw,
shallowReactive,
trigger,
- TriggerOpTypes
+ TriggerOpTypes,
+ shallowReadonly
} from '@vue/reactivity'
import {
EMPTY_OBJ,
@@ -575,7 +576,7 @@ function validateProps(
key,
resolvedValues[key],
opt,
- resolvedValues
+ shallowReadonly(resolvedValues),
!hasOwn(rawProps, key) && !hasOwn(rawProps, hyphenate(key))
)
}