diff --git a/src/runtime/validation.ts b/src/runtime/validation.ts index 7d069c56..3c499de4 100644 --- a/src/runtime/validation.ts +++ b/src/runtime/validation.ts @@ -1,4 +1,5 @@ import { OwlError } from "./error_handling"; +import { toRaw } from "./reactivity"; type BaseType = | typeof String @@ -84,6 +85,7 @@ export function validateSchema(obj: { [key: string]: any }, schema: Schema): str if (Array.isArray(schema)) { schema = toSchema(schema); } + obj = toRaw(obj); let errors = []; // check if each value in obj has correct shape for (let key in obj) { diff --git a/tests/components/__snapshots__/props_validation.test.ts.snap b/tests/components/__snapshots__/props_validation.test.ts.snap index 9b50aec0..7b167f60 100644 --- a/tests/components/__snapshots__/props_validation.test.ts.snap +++ b/tests/components/__snapshots__/props_validation.test.ts.snap @@ -841,6 +841,33 @@ exports[`props validation props are validated whenever component is updated 2`] }" `; +exports[`props validation props validation does not cause additional subscription 1`] = ` +"function anonymous(app, bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, comment } = bdom; + const comp1 = app.createComponent(\`Child\`, true, false, false, false); + + return function template(ctx, node, key = \\"\\") { + const props1 = {obj: ctx['obj']}; + helpers.validateProps(\`Child\`, props1, this); + const b2 = comp1(props1, key + \`__1\`, node, this, null); + const b3 = text(ctx['obj'].otherValue); + return multi([b2, b3]); + } +}" +`; + +exports[`props validation props validation does not cause additional subscription 2`] = ` +"function anonymous(app, bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, comment } = bdom; + + return function template(ctx, node, key = \\"\\") { + return text(ctx['props'].obj.value); + } +}" +`; + exports[`props validation props: list of strings 1`] = ` "function anonymous(app, bdom, helpers ) { diff --git a/tests/components/props_validation.test.ts b/tests/components/props_validation.test.ts index 55327611..2ce4b244 100644 --- a/tests/components/props_validation.test.ts +++ b/tests/components/props_validation.test.ts @@ -1,5 +1,5 @@ import { makeTestFixture, nextAppError, nextTick, snapshotEverything } from "../helpers"; -import { Component, onError, xml, mount, OwlError } from "../../src"; +import { Component, onError, xml, mount, OwlError, useState } from "../../src"; import { App, DEV_MSG } from "../../src/runtime/app"; import { validateProps } from "../../src/runtime/template_helpers"; import { Schema } from "../../src/runtime/validation"; @@ -682,6 +682,29 @@ describe("props validation", () => { expect(error!.message).toBe("Invalid props for component 'SubComp': 'p' is missing"); }); + test("props validation does not cause additional subscription", async () => { + let obj = { + value: 1, + otherValue: 2, + }; + class Child extends Component { + static props = { + obj: { type: Object, shape: { value: Number, otherValue: Number } }, + }; + static template = xml``; + } + class Parent extends Component { + static template = xml``; + static components = { Child }; + + obj = useState(obj); + } + const app = new App(Parent, { test: true }); + await app.mount(fixture); + expect(fixture.innerHTML).toBe("12"); + expect(app.root!.subscriptions).toEqual([{ keys: ["otherValue"], target: obj }]); + }); + test("props are validated whenever component is updated", async () => { let error: Error; class SubComp extends Component {