mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[IMP] component: use reactivity to allow shallow renderings
With this commit, component only render child components if they have different props (shallow equality). Otherwise, we trust the reactivity system to make sure that all impacted components are updated
This commit is contained in:
committed by
Samuel Degueldre
parent
592d9a458e
commit
1ae9d514b9
+6
-2
@@ -29,7 +29,7 @@ See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration
|
|||||||
|
|
||||||
export class App<
|
export class App<
|
||||||
T extends abstract new (...args: any) => any = any,
|
T extends abstract new (...args: any) => any = any,
|
||||||
P = any,
|
P extends object = any,
|
||||||
E = any
|
E = any
|
||||||
> extends TemplateSet {
|
> extends TemplateSet {
|
||||||
static validateTarget = validateTarget;
|
static validateTarget = validateTarget;
|
||||||
@@ -102,7 +102,11 @@ export class App<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function mount<T extends abstract new (...args: any) => any = any, P = any, E = any>(
|
export async function mount<
|
||||||
|
T extends abstract new (...args: any) => any = any,
|
||||||
|
P extends object = any,
|
||||||
|
E = any
|
||||||
|
>(
|
||||||
C: T & ComponentConstructor<P, E>,
|
C: T & ComponentConstructor<P, E>,
|
||||||
target: HTMLElement,
|
target: HTMLElement,
|
||||||
config: AppConfig<P, E> & MountOptions = {}
|
config: AppConfig<P, E> & MountOptions = {}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { BDom, multi, text, toggler } from "../blockdom";
|
|||||||
import { validateProps } from "../component/props_validation";
|
import { validateProps } from "../component/props_validation";
|
||||||
import { Markup } from "../utils";
|
import { Markup } from "../utils";
|
||||||
import { html } from "../blockdom/index";
|
import { html } from "../blockdom/index";
|
||||||
|
import { TARGET } from "../reactivity";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file contains utility functions that will be injected in each template,
|
* This file contains utility functions that will be injected in each template,
|
||||||
* to perform various useful tasks in the compiled code.
|
* to perform various useful tasks in the compiled code.
|
||||||
@@ -21,7 +23,7 @@ function callSlot(
|
|||||||
defaultContent?: (ctx: any, node: any, key: string) => BDom
|
defaultContent?: (ctx: any, node: any, key: string) => BDom
|
||||||
): BDom {
|
): BDom {
|
||||||
key = key + "__slot_" + name;
|
key = key + "__slot_" + name;
|
||||||
const slots = (ctx.props && ctx.props.slots) || {};
|
const slots = ctx.props[TARGET].slots || {};
|
||||||
const { __render, __ctx, __scope } = slots[name] || {};
|
const { __render, __ctx, __scope } = slots[name] || {};
|
||||||
const slotScope = Object.create(__ctx || {});
|
const slotScope = Object.create(__ctx || {});
|
||||||
if (__scope) {
|
if (__scope) {
|
||||||
|
|||||||
@@ -1125,18 +1125,17 @@ export class CodeGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (slotDef && !(ast.dynamicProps || hasSlotsProp)) {
|
if (slotDef && !(ast.dynamicProps || hasSlotsProp)) {
|
||||||
props.push(`slots: ${slotDef}`);
|
this.helpers.add("markRaw");
|
||||||
|
props.push(`slots: markRaw(${slotDef})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const propStr = `{${props.join(",")}}`;
|
const propStr = `{${props.join(",")}}`;
|
||||||
|
|
||||||
let propString = propStr;
|
let propString = propStr;
|
||||||
if (ast.dynamicProps) {
|
if (ast.dynamicProps) {
|
||||||
if (!props.length) {
|
propString = `Object.assign({}, ${compileExpr(ast.dynamicProps)}${
|
||||||
propString = `Object.assign({}, ${compileExpr(ast.dynamicProps)})`;
|
props.length ? ", " + propStr : ""
|
||||||
} else {
|
})`;
|
||||||
propString = `Object.assign({}, ${compileExpr(ast.dynamicProps)}, ${propStr})`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let propVar: string;
|
let propVar: string;
|
||||||
@@ -1147,7 +1146,8 @@ export class CodeGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (slotDef && (ast.dynamicProps || hasSlotsProp)) {
|
if (slotDef && (ast.dynamicProps || hasSlotsProp)) {
|
||||||
this.addLine(`${propVar!}.slots = Object.assign(${slotDef}, ${propVar!}.slots)`);
|
this.helpers.add("markRaw");
|
||||||
|
this.addLine(`${propVar!}.slots = markRaw(Object.assign(${slotDef}, ${propVar!}.slots))`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// cmap key
|
// cmap key
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export class Component<Props = any, Env = any> {
|
|||||||
|
|
||||||
setup() {}
|
setup() {}
|
||||||
|
|
||||||
render() {
|
render(deep: boolean = false) {
|
||||||
this.__owl__.render();
|
this.__owl__.render(deep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { App, Env } from "../app/app";
|
import type { App, Env } from "../app/app";
|
||||||
import { BDom, VNode } from "../blockdom";
|
import { BDom, VNode } from "../blockdom";
|
||||||
import { clearReactivesForCallback, NonReactive, Reactive, reactive } from "../reactivity";
|
import { clearReactivesForCallback, Reactive, reactive, TARGET, NonReactive } from "../reactivity";
|
||||||
import { batched, Callback } from "../utils";
|
import { batched, Callback } from "../utils";
|
||||||
import { Component, ComponentConstructor } from "./component";
|
import { Component, ComponentConstructor } from "./component";
|
||||||
import { fibersInError, handleError } from "./error_handling";
|
import { fibersInError, handleError } from "./error_handling";
|
||||||
@@ -58,14 +58,24 @@ export function useState<T extends object>(state: T): Reactive<T> | NonReactive<
|
|||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// component function (used in compiled template code)
|
// component function (used in compiled template code)
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
type Props = { [key: string]: any };
|
||||||
|
|
||||||
export function component(
|
function arePropsDifferent(props1: Props, props2: Props): boolean {
|
||||||
name: string | typeof Component,
|
for (let k in props1) {
|
||||||
props: any,
|
if (props1[k] !== props2[k]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Object.keys(props1).length !== Object.keys(props2).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function component<P extends object>(
|
||||||
|
name: string | ComponentConstructor<P>,
|
||||||
|
props: P,
|
||||||
key: string,
|
key: string,
|
||||||
ctx: ComponentNode,
|
ctx: ComponentNode,
|
||||||
parent: any
|
parent: any
|
||||||
): ComponentNode {
|
): ComponentNode<P> {
|
||||||
let node: any = ctx.children[key];
|
let node: any = ctx.children[key];
|
||||||
let isDynamic = typeof name !== "string";
|
let isDynamic = typeof name !== "string";
|
||||||
|
|
||||||
@@ -83,7 +93,10 @@ export function component(
|
|||||||
|
|
||||||
const parentFiber = ctx.fiber!;
|
const parentFiber = ctx.fiber!;
|
||||||
if (node) {
|
if (node) {
|
||||||
node.updateAndRender(props, parentFiber);
|
const currentProps = node.component.props[TARGET];
|
||||||
|
if (parentFiber.deep || arePropsDifferent(currentProps, props)) {
|
||||||
|
node.updateAndRender(props, parentFiber);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// new component
|
// new component
|
||||||
let C;
|
let C;
|
||||||
@@ -98,8 +111,7 @@ export function component(
|
|||||||
node = new ComponentNode(C, props, ctx.app, ctx);
|
node = new ComponentNode(C, props, ctx.app, ctx);
|
||||||
ctx.children[key] = node;
|
ctx.children[key] = node;
|
||||||
|
|
||||||
const fiber = makeChildFiber(node, parentFiber);
|
node.initiateRender(new Fiber(node, parentFiber));
|
||||||
node.initiateRender(fiber);
|
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@@ -110,7 +122,7 @@ export function component(
|
|||||||
|
|
||||||
type LifecycleHook = Function;
|
type LifecycleHook = Function;
|
||||||
|
|
||||||
export class ComponentNode<P = any, E = any> implements VNode<ComponentNode<P, E>> {
|
export class ComponentNode<P extends object = any, E = any> implements VNode<ComponentNode<P, E>> {
|
||||||
el?: HTMLElement | Text | undefined;
|
el?: HTMLElement | Text | undefined;
|
||||||
app: App;
|
app: App;
|
||||||
fiber: Fiber | null = null;
|
fiber: Fiber | null = null;
|
||||||
@@ -141,6 +153,7 @@ export class ComponentNode<P = any, E = any> implements VNode<ComponentNode<P, E
|
|||||||
applyDefaultProps(props, C);
|
applyDefaultProps(props, C);
|
||||||
const env = (parent && parent.childEnv) || app.env;
|
const env = (parent && parent.childEnv) || app.env;
|
||||||
this.childEnv = env;
|
this.childEnv = env;
|
||||||
|
props = useState(props);
|
||||||
this.component = new C(props, env, this) as any;
|
this.component = new C(props, env, this) as any;
|
||||||
this.renderFn = app.getTemplate(C.template).bind(this.component, this.component, this);
|
this.renderFn = app.getTemplate(C.template).bind(this.component, this.component, this);
|
||||||
this.component.setup();
|
this.component.setup();
|
||||||
@@ -170,21 +183,29 @@ export class ComponentNode<P = any, E = any> implements VNode<ComponentNode<P, E
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async render() {
|
async render(deep: boolean = false) {
|
||||||
let current = this.fiber;
|
let current = this.fiber;
|
||||||
if (current && current.root!.locked) {
|
if (current && current.root!.locked) {
|
||||||
await Promise.resolve();
|
await Promise.resolve();
|
||||||
// situation may have changed after the microtask tick
|
// situation may have changed after the microtask tick
|
||||||
current = this.fiber;
|
current = this.fiber;
|
||||||
}
|
}
|
||||||
if (current && !current.bdom && !fibersInError.has(current)) {
|
if (current) {
|
||||||
return;
|
if (!current.bdom && !fibersInError.has(current)) {
|
||||||
}
|
if (deep) {
|
||||||
if (!this.bdom && !current) {
|
// we want the render from this point on to be with deep=true
|
||||||
|
current.deep = deep;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// if current rendering was with deep=true, we want this one to be the same
|
||||||
|
deep = deep || current.deep;
|
||||||
|
} else if (!this.bdom) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fiber = makeRootFiber(this);
|
const fiber = makeRootFiber(this);
|
||||||
|
fiber.deep = deep;
|
||||||
this.fiber = fiber;
|
this.fiber = fiber;
|
||||||
this.app.scheduler.addFiber(fiber);
|
this.app.scheduler.addFiber(fiber);
|
||||||
await Promise.resolve();
|
await Promise.resolve();
|
||||||
@@ -246,6 +267,10 @@ export class ComponentNode<P = any, E = any> implements VNode<ComponentNode<P, E
|
|||||||
this.fiber = fiber;
|
this.fiber = fiber;
|
||||||
const component = this.component;
|
const component = this.component;
|
||||||
applyDefaultProps(props, component.constructor as any);
|
applyDefaultProps(props, component.constructor as any);
|
||||||
|
|
||||||
|
currentNode = this;
|
||||||
|
props = useState(props);
|
||||||
|
currentNode = null;
|
||||||
const prom = Promise.all(this.willUpdateProps.map((f) => f.call(component, props)));
|
const prom = Promise.all(this.willUpdateProps.map((f) => f.call(component, props)));
|
||||||
await prom;
|
await prom;
|
||||||
if (fiber !== this.fiber) {
|
if (fiber !== this.fiber) {
|
||||||
@@ -310,6 +335,14 @@ export class ComponentNode<P = any, E = any> implements VNode<ComponentNode<P, E
|
|||||||
}
|
}
|
||||||
|
|
||||||
patch() {
|
patch() {
|
||||||
|
if (this.fiber && this.fiber.parent) {
|
||||||
|
// we only patch here renderings coming from above. renderings initiated
|
||||||
|
// by the component will be patched independently in the appropriate
|
||||||
|
// fiber.complete
|
||||||
|
this._patch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_patch() {
|
||||||
const hasChildren = Object.keys(this.children).length > 0;
|
const hasChildren = Object.keys(this.children).length > 0;
|
||||||
this.bdom!.patch(this!.fiber!.bdom!, hasChildren);
|
this.bdom!.patch(this!.fiber!.bdom!, hasChildren);
|
||||||
if (hasChildren) {
|
if (hasChildren) {
|
||||||
|
|||||||
@@ -16,9 +16,8 @@ export function makeRootFiber(node: ComponentNode): Fiber {
|
|||||||
let current = node.fiber;
|
let current = node.fiber;
|
||||||
if (current) {
|
if (current) {
|
||||||
let root = current.root!;
|
let root = current.root!;
|
||||||
root.counter -= cancelFibers(current.children);
|
root.counter = root.counter + 1 - cancelFibers(current.children);
|
||||||
current.children = [];
|
current.children = [];
|
||||||
root.counter++;
|
|
||||||
current.bdom = null;
|
current.bdom = null;
|
||||||
if (fibersInError.has(current)) {
|
if (fibersInError.has(current)) {
|
||||||
fibersInError.delete(current);
|
fibersInError.delete(current);
|
||||||
@@ -34,7 +33,6 @@ export function makeRootFiber(node: ComponentNode): Fiber {
|
|||||||
if (node.patched.length) {
|
if (node.patched.length) {
|
||||||
fiber.patched.push(fiber);
|
fiber.patched.push(fiber);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fiber;
|
return fiber;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,11 +58,13 @@ export class Fiber {
|
|||||||
parent: Fiber | null;
|
parent: Fiber | null;
|
||||||
children: Fiber[] = [];
|
children: Fiber[] = [];
|
||||||
appliedToDom = false;
|
appliedToDom = false;
|
||||||
|
deep: boolean = false;
|
||||||
|
|
||||||
constructor(node: ComponentNode, parent: Fiber | null) {
|
constructor(node: ComponentNode, parent: Fiber | null) {
|
||||||
this.node = node;
|
this.node = node;
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
if (parent) {
|
if (parent) {
|
||||||
|
this.deep = parent.deep;
|
||||||
const root = parent.root!;
|
const root = parent.root!;
|
||||||
root.counter++;
|
root.counter++;
|
||||||
this.root = root;
|
this.root = root;
|
||||||
@@ -107,7 +107,7 @@ export class RootFiber extends Fiber {
|
|||||||
current = undefined;
|
current = undefined;
|
||||||
|
|
||||||
// Step 2: patching the dom
|
// Step 2: patching the dom
|
||||||
node.patch();
|
node._patch();
|
||||||
this.locked = false;
|
this.locked = false;
|
||||||
|
|
||||||
// Step 4: calling all mounted lifecycle hooks
|
// Step 4: calling all mounted lifecycle hooks
|
||||||
|
|||||||
@@ -14,11 +14,13 @@ import {
|
|||||||
} from "./blockdom";
|
} from "./blockdom";
|
||||||
import { mainEventHandler } from "./component/handler";
|
import { mainEventHandler } from "./component/handler";
|
||||||
import { Portal } from "./portal";
|
import { Portal } from "./portal";
|
||||||
|
import { markRaw } from "./reactivity";
|
||||||
export type { Reactive } from "./reactivity";
|
export type { Reactive } from "./reactivity";
|
||||||
|
|
||||||
config.shouldNormalizeDom = false;
|
config.shouldNormalizeDom = false;
|
||||||
config.mainEventHandler = mainEventHandler;
|
config.mainEventHandler = mainEventHandler;
|
||||||
(UTILS as any).Portal = Portal;
|
(UTILS as any).Portal = Portal;
|
||||||
|
(UTILS as any).markRaw = markRaw;
|
||||||
|
|
||||||
export const blockDom = {
|
export const blockDom = {
|
||||||
config,
|
config,
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
import { Callback } from "./utils";
|
import { Callback } from "./utils";
|
||||||
|
|
||||||
// Allows to get the target of a Reactive (used for making a new Reactive from the underlying object)
|
// Allows to get the target of a Reactive (used for making a new Reactive from the underlying object)
|
||||||
const TARGET = Symbol("Target");
|
export const TARGET = Symbol("Target");
|
||||||
// Escape hatch to prevent reactivity system to turn something into a reactive
|
// Escape hatch to prevent reactivity system to turn something into a reactive
|
||||||
const SKIP = Symbol("Skip");
|
const SKIP = Symbol("Skip");
|
||||||
// Special key to subscribe to, to be notified of key creation/deletion
|
// Special key to subscribe to, to be notified of key creation/deletion
|
||||||
|
|||||||
@@ -1067,6 +1067,33 @@ exports[`delay willUpdateProps with rendering grandchild 4`] = `
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`destroying/recreating a subcomponent, other scenario 1`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
let b2,b3;
|
||||||
|
b2 = text(\`parent\`);
|
||||||
|
if (ctx['state'].hasChild) {
|
||||||
|
b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
|
||||||
|
}
|
||||||
|
return multi([b2, b3]);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`destroying/recreating a subcomponent, other scenario 2`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
return text(\`child\`);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`destroying/recreating a subwidget with different props (if start is not over) 1`] = `
|
exports[`destroying/recreating a subwidget with different props (if start is not over) 1`] = `
|
||||||
"function anonymous(bdom, helpers
|
"function anonymous(bdom, helpers
|
||||||
) {
|
) {
|
||||||
@@ -1145,7 +1172,7 @@ exports[`properly behave when destroyed/unmounted while rendering 2`] = `
|
|||||||
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
let b2 = component(\`SubChild\`, {}, key + \`__1\`, node, ctx);
|
let b2 = component(\`SubChild\`, {val: ctx['props'].val}, key + \`__1\`, node, ctx);
|
||||||
return block1([], [b2]);
|
return block1([], [b2]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ exports[`can catch errors can catch an error in a component render function 1`]
|
|||||||
"function anonymous(bdom, helpers
|
"function anonymous(bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
let { markRaw } = helpers;
|
||||||
|
|
||||||
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||||
|
|
||||||
@@ -108,7 +109,7 @@ exports[`can catch errors can catch an error in a component render function 1`]
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
let b3 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
|
let b3 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__2\`, node, ctx);
|
||||||
return block1([], [b3]);
|
return block1([], [b3]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -152,6 +153,7 @@ exports[`can catch errors can catch an error in the constructor call of a compon
|
|||||||
"function anonymous(bdom, helpers
|
"function anonymous(bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
let { markRaw } = helpers;
|
||||||
|
|
||||||
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||||
|
|
||||||
@@ -160,7 +162,7 @@ exports[`can catch errors can catch an error in the constructor call of a compon
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
let b3 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
|
let b3 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__2\`, node, ctx);
|
||||||
return block1([], [b3]);
|
return block1([], [b3]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -190,6 +192,7 @@ exports[`can catch errors can catch an error in the constructor call of a compon
|
|||||||
"function anonymous(bdom, helpers
|
"function anonymous(bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
let { markRaw } = helpers;
|
||||||
|
|
||||||
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||||
|
|
||||||
@@ -200,7 +203,7 @@ exports[`can catch errors can catch an error in the constructor call of a compon
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
let b5 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__3\`, node, ctx);
|
let b5 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__3\`, node, ctx);
|
||||||
return block1([], [b5]);
|
return block1([], [b5]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -269,6 +272,7 @@ exports[`can catch errors can catch an error in the initial call of a component
|
|||||||
"function anonymous(bdom, helpers
|
"function anonymous(bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
let { markRaw } = helpers;
|
||||||
|
|
||||||
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||||
|
|
||||||
@@ -277,7 +281,7 @@ exports[`can catch errors can catch an error in the initial call of a component
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
let b3 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
|
let b3 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__2\`, node, ctx);
|
||||||
return block1([], [b3]);
|
return block1([], [b3]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -321,6 +325,7 @@ exports[`can catch errors can catch an error in the initial call of a component
|
|||||||
"function anonymous(bdom, helpers
|
"function anonymous(bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
let { markRaw } = helpers;
|
||||||
|
|
||||||
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||||
|
|
||||||
@@ -331,7 +336,7 @@ exports[`can catch errors can catch an error in the initial call of a component
|
|||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
let b3;
|
let b3;
|
||||||
if (ctx['state'].flag) {
|
if (ctx['state'].flag) {
|
||||||
b3 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
|
b3 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__2\`, node, ctx);
|
||||||
}
|
}
|
||||||
return block1([], [b3]);
|
return block1([], [b3]);
|
||||||
}
|
}
|
||||||
@@ -465,6 +470,7 @@ exports[`can catch errors can catch an error in the mounted call 1`] = `
|
|||||||
"function anonymous(bdom, helpers
|
"function anonymous(bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
let { markRaw } = helpers;
|
||||||
|
|
||||||
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||||
|
|
||||||
@@ -473,7 +479,7 @@ exports[`can catch errors can catch an error in the mounted call 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
let b3 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
|
let b3 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__2\`, node, ctx);
|
||||||
return block1([], [b3]);
|
return block1([], [b3]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -516,6 +522,7 @@ exports[`can catch errors can catch an error in the willPatch call 1`] = `
|
|||||||
"function anonymous(bdom, helpers
|
"function anonymous(bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
let { markRaw } = helpers;
|
||||||
|
|
||||||
let block1 = createBlock(\`<div><span><block-text-0/></span><block-child-0/></div>\`);
|
let block1 = createBlock(\`<div><span><block-text-0/></span><block-child-0/></div>\`);
|
||||||
|
|
||||||
@@ -525,7 +532,7 @@ exports[`can catch errors can catch an error in the willPatch call 1`] = `
|
|||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
let txt1 = ctx['state'].message;
|
let txt1 = ctx['state'].message;
|
||||||
let b3 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
|
let b3 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__2\`, node, ctx);
|
||||||
return block1([txt1], [b3]);
|
return block1([txt1], [b3]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -569,6 +576,7 @@ exports[`can catch errors can catch an error in the willStart call 1`] = `
|
|||||||
"function anonymous(bdom, helpers
|
"function anonymous(bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
let { markRaw } = helpers;
|
||||||
|
|
||||||
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||||
|
|
||||||
@@ -577,7 +585,7 @@ exports[`can catch errors can catch an error in the willStart call 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
let b3 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
|
let b3 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__2\`, node, ctx);
|
||||||
return block1([], [b3]);
|
return block1([], [b3]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -620,6 +628,7 @@ exports[`can catch errors can catch an error origination from a child's willStar
|
|||||||
"function anonymous(bdom, helpers
|
"function anonymous(bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
let { markRaw } = helpers;
|
||||||
|
|
||||||
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||||
|
|
||||||
@@ -630,7 +639,7 @@ exports[`can catch errors can catch an error origination from a child's willStar
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
let b5 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__3\`, node, ctx);
|
let b5 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__3\`, node, ctx);
|
||||||
return block1([], [b5]);
|
return block1([], [b5]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -733,7 +742,7 @@ exports[`can catch errors catching error, rethrow, render parent -- a main comp
|
|||||||
"function anonymous(bdom, helpers
|
"function anonymous(bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
let { prepareList, capture, withKey } = helpers;
|
let { prepareList, capture, markRaw, withKey } = helpers;
|
||||||
|
|
||||||
function slot1(ctx, node, key = \\"\\") {
|
function slot1(ctx, node, key = \\"\\") {
|
||||||
let Comp1 = ctx['cp'].Comp;
|
let Comp1 = ctx['cp'].Comp;
|
||||||
@@ -748,7 +757,7 @@ exports[`can catch errors catching error, rethrow, render parent -- a main comp
|
|||||||
let key1 = ctx['cp'].id;
|
let key1 = ctx['cp'].id;
|
||||||
const v1 = ctx['cp'];
|
const v1 = ctx['cp'];
|
||||||
const ctx1 = capture(ctx);
|
const ctx1 = capture(ctx);
|
||||||
c_block1[i1] = withKey(component(\`ErrorHandler\`, {onError: ()=>this.cleanUp(v1.id),slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__2__\${key1}\`, node, ctx), key1);
|
c_block1[i1] = withKey(component(\`ErrorHandler\`, {onError: ()=>this.cleanUp(v1.id),slots: markRaw({'default': {__render: slot1, __ctx: ctx1}})}, key + \`__2__\${key1}\`, node, ctx), key1);
|
||||||
}
|
}
|
||||||
return list(c_block1);
|
return list(c_block1);
|
||||||
}
|
}
|
||||||
@@ -808,7 +817,7 @@ exports[`can catch errors catching in child makes parent render 1`] = `
|
|||||||
"function anonymous(bdom, helpers
|
"function anonymous(bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
let { prepareList, capture, withKey } = helpers;
|
let { prepareList, capture, markRaw, withKey } = helpers;
|
||||||
|
|
||||||
function slot1(ctx, node, key = \\"\\") {
|
function slot1(ctx, node, key = \\"\\") {
|
||||||
let Comp1 = ctx['elem'][1];
|
let Comp1 = ctx['elem'][1];
|
||||||
@@ -823,7 +832,7 @@ exports[`can catch errors catching in child makes parent render 1`] = `
|
|||||||
let key1 = ctx['elem'][0];
|
let key1 = ctx['elem'][0];
|
||||||
const v1 = ctx['elem'];
|
const v1 = ctx['elem'];
|
||||||
const ctx1 = capture(ctx);
|
const ctx1 = capture(ctx);
|
||||||
c_block1[i1] = withKey(component(\`Catch\`, {onError: (_error)=>this.onError(v1[0],_error),slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__2__\${key1}\`, node, ctx), key1);
|
c_block1[i1] = withKey(component(\`Catch\`, {onError: (_error)=>this.onError(v1[0],_error),slots: markRaw({'default': {__render: slot1, __ctx: ctx1}})}, key + \`__2__\${key1}\`, node, ctx), key1);
|
||||||
}
|
}
|
||||||
return list(c_block1);
|
return list(c_block1);
|
||||||
}
|
}
|
||||||
@@ -873,6 +882,7 @@ exports[`can catch errors error in mounted on a component with a sibling (proper
|
|||||||
"function anonymous(bdom, helpers
|
"function anonymous(bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
let { markRaw } = helpers;
|
||||||
|
|
||||||
let block1 = createBlock(\`<div><block-child-0/><block-child-1/></div>\`);
|
let block1 = createBlock(\`<div><block-child-0/><block-child-1/></div>\`);
|
||||||
|
|
||||||
@@ -882,7 +892,7 @@ exports[`can catch errors error in mounted on a component with a sibling (proper
|
|||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
let b2 = component(\`OK\`, {}, key + \`__1\`, node, ctx);
|
let b2 = component(\`OK\`, {}, key + \`__1\`, node, ctx);
|
||||||
let b4 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__3\`, node, ctx);
|
let b4 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__3\`, node, ctx);
|
||||||
return block1([], [b2, b4]);
|
return block1([], [b2, b4]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
|
|||||||
@@ -527,7 +527,7 @@ exports[`lifecycle hooks onWillRender 1`] = `
|
|||||||
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
return component(\`Child\`, {}, key + \`__1\`, node, ctx);
|
return component(\`Child\`, {someValue: ctx['state'].value}, key + \`__1\`, node, ctx);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ exports[`refs refs are properly bound in slots 1`] = `
|
|||||||
"function anonymous(bdom, helpers
|
"function anonymous(bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
let { capture } = helpers;
|
let { capture, markRaw } = helpers;
|
||||||
|
|
||||||
let block1 = createBlock(\`<div><span class=\\"counter\\"><block-text-0/></span><block-child-0/></div>\`);
|
let block1 = createBlock(\`<div><span class=\\"counter\\"><block-text-0/></span><block-child-0/></div>\`);
|
||||||
let block2 = createBlock(\`<button block-handler-0=\\"click\\" block-ref=\\"1\\">do something</button>\`);
|
let block2 = createBlock(\`<button block-handler-0=\\"click\\" block-ref=\\"1\\">do something</button>\`);
|
||||||
@@ -77,7 +77,7 @@ exports[`refs refs are properly bound in slots 1`] = `
|
|||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
let txt1 = ctx['state'].val;
|
let txt1 = ctx['state'].val;
|
||||||
const ctx1 = capture(ctx);
|
const ctx1 = capture(ctx);
|
||||||
let b3 = component(\`Dialog\`, {slots: {'footer': {__render: slot1, __ctx: ctx1}}}, key + \`__1\`, node, ctx);
|
let b3 = component(\`Dialog\`, {slots: markRaw({'footer': {__render: slot1, __ctx: ctx1}})}, key + \`__1\`, node, ctx);
|
||||||
return block1([txt1], [b3]);
|
return block1([txt1], [b3]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
|
|||||||
@@ -0,0 +1,212 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`force render in case of existing render 1`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
return component(\`B\`, {val: ctx['state'].val}, key + \`__1\`, node, ctx);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`force render in case of existing render 2`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
let b2 = component(\`C\`, {}, key + \`__1\`, node, ctx);
|
||||||
|
let b3 = text(ctx['props'].val);
|
||||||
|
return multi([b2, b3]);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`force render in case of existing render 3`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
return text(\`C\`);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`rendering semantics can force a render to update sub tree 1`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
let b2 = text(ctx['state'].value);
|
||||||
|
let b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
|
||||||
|
return multi([b2, b3]);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`rendering semantics can force a render to update sub tree 2`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
return text(\`child\`);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`rendering semantics can render a parent without rendering child 1`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
let b2 = text(ctx['state'].value);
|
||||||
|
let b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
|
||||||
|
return multi([b2, b3]);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`rendering semantics can render a parent without rendering child 2`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
return text(\`child\`);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`rendering semantics props are reactive (nested prop) 1`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
return component(\`Child\`, {a: ctx['state']}, key + \`__1\`, node, ctx);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`rendering semantics props are reactive (nested prop) 2`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
return text(ctx['props'].a.b.c);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`rendering semantics props are reactive 1`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
return component(\`Child\`, {a: ctx['state']}, key + \`__1\`, node, ctx);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`rendering semantics props are reactive 2`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
return text(ctx['props'].a.b);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`rendering semantics render with deep=true followed by render with deep=false work as expected 1`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
let b2 = text(\`parent\`);
|
||||||
|
let b3 = text(ctx['state'].value);
|
||||||
|
let b4 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
|
||||||
|
return multi([b2, b3, b4]);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`rendering semantics render with deep=true followed by render with deep=false work as expected 2`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
let b2 = text(\`child\`);
|
||||||
|
let b3 = text(ctx['env'].getValue());
|
||||||
|
return multi([b2, b3]);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`rendering semantics rendering is atomic (for one subtree) 1`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
let b2 = text(ctx['state'].obj.val);
|
||||||
|
let b3 = component(\`B\`, {obj: ctx['state'].obj}, key + \`__1\`, node, ctx);
|
||||||
|
return multi([b2, b3]);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`rendering semantics rendering is atomic (for one subtree) 2`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
return component(\`C\`, {obj: ctx['props'].obj}, key + \`__1\`, node, ctx);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`rendering semantics rendering is atomic (for one subtree) 3`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
return text(ctx['props'].obj.val);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`rendering semantics works as expected for dynamic number of props 1`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
return component(\`Child\`, Object.assign({}, ctx['state']), key + \`__1\`, node, ctx);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`rendering semantics works as expected for dynamic number of props 2`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
return text(Object.keys(ctx['props']).length);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@ exports[`t-set slot setted value (with t-set) not accessible with t-esc 1`] = `
|
|||||||
"function anonymous(bdom, helpers
|
"function anonymous(bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
let { isBoundary, withDefault, setContextValue, capture } = helpers;
|
let { isBoundary, withDefault, setContextValue, capture, markRaw } = helpers;
|
||||||
|
|
||||||
let block1 = createBlock(\`<div><p><block-text-0/></p><block-child-0/><p><block-text-1/></p></div>\`);
|
let block1 = createBlock(\`<div><p><block-text-0/></p><block-child-0/><p><block-text-1/></p></div>\`);
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ exports[`t-set slot setted value (with t-set) not accessible with t-esc 1`] = `
|
|||||||
setContextValue(ctx, \\"iter\\", 'source');
|
setContextValue(ctx, \\"iter\\", 'source');
|
||||||
let txt1 = ctx['iter'];
|
let txt1 = ctx['iter'];
|
||||||
const ctx1 = capture(ctx);
|
const ctx1 = capture(ctx);
|
||||||
let b2 = component(\`Childcomp\`, {slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__1\`, node, ctx);
|
let b2 = component(\`Childcomp\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx1}})}, key + \`__1\`, node, ctx);
|
||||||
let txt2 = ctx['iter'];
|
let txt2 = ctx['iter'];
|
||||||
return block1([txt1, txt2], [b2]);
|
return block1([txt1, txt2], [b2]);
|
||||||
}
|
}
|
||||||
@@ -51,7 +51,7 @@ exports[`t-set slots with a t-set with a component in body 1`] = `
|
|||||||
"function anonymous(bdom, helpers
|
"function anonymous(bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
let { capture, isBoundary, withDefault, LazyValue, safeOutput } = helpers;
|
let { capture, isBoundary, withDefault, LazyValue, safeOutput, markRaw } = helpers;
|
||||||
|
|
||||||
function slot1(ctx, node, key = \\"\\") {
|
function slot1(ctx, node, key = \\"\\") {
|
||||||
ctx = Object.create(ctx);
|
ctx = Object.create(ctx);
|
||||||
@@ -68,7 +68,7 @@ exports[`t-set slots with a t-set with a component in body 1`] = `
|
|||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
const ctx1 = capture(ctx);
|
const ctx1 = capture(ctx);
|
||||||
return component(\`Child\`, {slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__2\`, node, ctx);
|
return component(\`Child\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx1}})}, key + \`__2\`, node, ctx);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
@@ -102,7 +102,7 @@ exports[`t-set slots with an t-set with a component in body 1`] = `
|
|||||||
"function anonymous(bdom, helpers
|
"function anonymous(bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
let { capture, isBoundary, withDefault, LazyValue, safeOutput } = helpers;
|
let { capture, isBoundary, withDefault, LazyValue, safeOutput, markRaw } = helpers;
|
||||||
|
|
||||||
let block4 = createBlock(\`<div>coffee</div>\`);
|
let block4 = createBlock(\`<div>coffee</div>\`);
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ exports[`t-set slots with an t-set with a component in body 1`] = `
|
|||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
const ctx1 = capture(ctx);
|
const ctx1 = capture(ctx);
|
||||||
return component(\`Blorg\`, {slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__2\`, node, ctx);
|
return component(\`Blorg\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx1}})}, key + \`__2\`, node, ctx);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
@@ -157,7 +157,7 @@ exports[`t-set slots with an unused t-set with a component in body 1`] = `
|
|||||||
"function anonymous(bdom, helpers
|
"function anonymous(bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
let { capture, isBoundary, withDefault, LazyValue } = helpers;
|
let { capture, isBoundary, withDefault, LazyValue, markRaw } = helpers;
|
||||||
|
|
||||||
function slot1(ctx, node, key = \\"\\") {
|
function slot1(ctx, node, key = \\"\\") {
|
||||||
ctx = Object.create(ctx);
|
ctx = Object.create(ctx);
|
||||||
@@ -172,7 +172,7 @@ exports[`t-set slots with an unused t-set with a component in body 1`] = `
|
|||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
const ctx1 = capture(ctx);
|
const ctx1 = capture(ctx);
|
||||||
return component(\`Child\`, {slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__2\`, node, ctx);
|
return component(\`Child\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx1}})}, key + \`__2\`, node, ctx);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { App, Component, mount, status, useState, xml } from "../../src";
|
import { App, Component, mount, status, toRaw, useState, xml } from "../../src";
|
||||||
import { elem, makeTestFixture, nextTick, snapshotEverything, useLogLifecycle } from "../helpers";
|
import { elem, makeTestFixture, nextTick, snapshotEverything, useLogLifecycle } from "../helpers";
|
||||||
import { markup } from "../../src/utils";
|
import { markup } from "../../src/utils";
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ describe("basics", () => {
|
|||||||
class Test extends Component {
|
class Test extends Component {
|
||||||
static template = xml`<span>simple vnode</span>`;
|
static template = xml`<span>simple vnode</span>`;
|
||||||
setup() {
|
setup() {
|
||||||
expect(this.props).toBe(p);
|
expect(toRaw(this.props)).toBe(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ Scheduler.prototype.addFiber = function (fiber: Fiber) {
|
|||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
if (lastScheduler && lastScheduler.tasks.size > 0) {
|
if (lastScheduler && lastScheduler.tasks.size > 0) {
|
||||||
|
// we still clear the scheduler to prevent additional noise
|
||||||
|
lastScheduler.tasks.clear();
|
||||||
throw new Error("we got a memory leak...");
|
throw new Error("we got a memory leak...");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -131,6 +133,58 @@ test("destroying/recreating a subwidget with different props (if start is not ov
|
|||||||
]).toBeLogged();
|
]).toBeLogged();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("destroying/recreating a subcomponent, other scenario", async () => {
|
||||||
|
let flag = false;
|
||||||
|
|
||||||
|
class Child extends Component {
|
||||||
|
static template = xml`child`;
|
||||||
|
setup() {
|
||||||
|
if (!flag) {
|
||||||
|
flag = true;
|
||||||
|
parent.render(true);
|
||||||
|
}
|
||||||
|
useLogLifecycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Parent extends Component {
|
||||||
|
static template = xml`parent<Child t-if="state.hasChild"/>`;
|
||||||
|
static components = { Child };
|
||||||
|
state = useState({ hasChild: false });
|
||||||
|
setup() {
|
||||||
|
useLogLifecycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const parent = await mount(Parent, fixture);
|
||||||
|
|
||||||
|
expect([
|
||||||
|
"Parent:setup",
|
||||||
|
"Parent:willStart",
|
||||||
|
"Parent:willRender",
|
||||||
|
"Parent:rendered",
|
||||||
|
"Parent:mounted",
|
||||||
|
]).toBeLogged();
|
||||||
|
expect(fixture.innerHTML).toBe("parent");
|
||||||
|
|
||||||
|
parent.state.hasChild = true;
|
||||||
|
|
||||||
|
await nextTick();
|
||||||
|
expect([
|
||||||
|
"Parent:willRender",
|
||||||
|
"Child:setup",
|
||||||
|
"Child:willStart",
|
||||||
|
"Parent:rendered",
|
||||||
|
"Child:willRender",
|
||||||
|
"Child:rendered",
|
||||||
|
"Parent:willPatch",
|
||||||
|
"Child:mounted",
|
||||||
|
"Parent:patched",
|
||||||
|
]).toBeLogged();
|
||||||
|
|
||||||
|
expect(fixture.innerHTML).toBe("parentchild");
|
||||||
|
});
|
||||||
|
|
||||||
test("creating two async components, scenario 1", async () => {
|
test("creating two async components, scenario 1", async () => {
|
||||||
let defA = makeDeferred();
|
let defA = makeDeferred();
|
||||||
let defB = makeDeferred();
|
let defB = makeDeferred();
|
||||||
@@ -521,7 +575,7 @@ test("properly behave when destroyed/unmounted while rendering ", async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Child extends Component {
|
class Child extends Component {
|
||||||
static template = xml`<div><SubChild /></div>`;
|
static template = xml`<div><SubChild val="props.val"/></div>`;
|
||||||
static components = { SubChild };
|
static components = { SubChild };
|
||||||
setup() {
|
setup() {
|
||||||
useLogLifecycle();
|
useLogLifecycle();
|
||||||
@@ -1907,18 +1961,13 @@ test("concurrent renderings scenario 13", async () => {
|
|||||||
await nextTick(); // wait for this change to be applied
|
await nextTick(); // wait for this change to be applied
|
||||||
expect([
|
expect([
|
||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:willUpdateProps",
|
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
"Parent:rendered",
|
"Parent:rendered",
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
"Child:willRender",
|
|
||||||
"Child:rendered",
|
|
||||||
"Parent:willPatch",
|
"Parent:willPatch",
|
||||||
"Child:willPatch",
|
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Child:patched",
|
|
||||||
"Parent:patched",
|
"Parent:patched",
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
@@ -2472,9 +2521,9 @@ test("two renderings initiated between willPatch and patched", async () => {
|
|||||||
useLogLifecycle();
|
useLogLifecycle();
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
this.mounted = "Mounted";
|
this.mounted = "Mounted";
|
||||||
parent.render();
|
parent.render(true);
|
||||||
});
|
});
|
||||||
onWillUnmount(() => parent.render());
|
onWillUnmount(() => parent.render(true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2507,15 +2556,11 @@ test("two renderings initiated between willPatch and patched", async () => {
|
|||||||
"Parent:rendered",
|
"Parent:rendered",
|
||||||
]).toBeLogged();
|
]).toBeLogged();
|
||||||
|
|
||||||
|
await nextMicroTick();
|
||||||
|
expect(["Panel:willRender", "Panel:rendered"]).toBeLogged();
|
||||||
|
|
||||||
await nextTick();
|
await nextTick();
|
||||||
expect([
|
expect(["Parent:willPatch", "Panel:willPatch", "Panel:patched", "Parent:patched"]).toBeLogged();
|
||||||
"Panel:willRender",
|
|
||||||
"Panel:rendered",
|
|
||||||
"Parent:willPatch",
|
|
||||||
"Panel:willPatch",
|
|
||||||
"Panel:patched",
|
|
||||||
"Parent:patched",
|
|
||||||
]).toBeLogged();
|
|
||||||
expect(fixture.innerHTML).toBe("<div><abc>Panel1Mounted</abc></div>");
|
expect(fixture.innerHTML).toBe("<div><abc>Panel1Mounted</abc></div>");
|
||||||
|
|
||||||
parent.state.panel = "Panel2";
|
parent.state.panel = "Panel2";
|
||||||
@@ -2753,12 +2798,20 @@ test("delay willUpdateProps with rendering grandchild", async () => {
|
|||||||
static template = xml`<Parent state="state"/>`;
|
static template = xml`<Parent state="state"/>`;
|
||||||
static components = { Parent };
|
static components = { Parent };
|
||||||
state = { value: 0 };
|
state = { value: 0 };
|
||||||
|
setup() {
|
||||||
|
useLogLifecycle();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const parent = await mount(GrandParent, fixture);
|
const parent = await mount(GrandParent, fixture);
|
||||||
expect(fixture.innerHTML).toBe("0_0<div></div>");
|
expect(fixture.innerHTML).toBe("0_0<div></div>");
|
||||||
expect([
|
expect([
|
||||||
|
"GrandParent:setup",
|
||||||
|
"GrandParent:willStart",
|
||||||
|
"GrandParent:willRender",
|
||||||
"Parent:setup",
|
"Parent:setup",
|
||||||
"Parent:willStart",
|
"Parent:willStart",
|
||||||
|
"GrandParent:rendered",
|
||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"DelayedChild:setup",
|
"DelayedChild:setup",
|
||||||
"DelayedChild:willStart",
|
"DelayedChild:willStart",
|
||||||
@@ -2772,20 +2825,23 @@ test("delay willUpdateProps with rendering grandchild", async () => {
|
|||||||
"ReactiveChild:mounted",
|
"ReactiveChild:mounted",
|
||||||
"DelayedChild:mounted",
|
"DelayedChild:mounted",
|
||||||
"Parent:mounted",
|
"Parent:mounted",
|
||||||
|
"GrandParent:mounted",
|
||||||
]).toBeLogged();
|
]).toBeLogged();
|
||||||
|
|
||||||
promise = makeDeferred();
|
promise = makeDeferred();
|
||||||
const prom1 = promise;
|
const prom1 = promise;
|
||||||
parent.state.value = 1;
|
parent.state.value = 1;
|
||||||
child.render(); // trigger a root rendering first
|
child.render(); // trigger a root rendering first
|
||||||
parent.render();
|
parent.render(true);
|
||||||
reactiveChild.render();
|
reactiveChild.render();
|
||||||
await nextTick();
|
await nextTick();
|
||||||
expect(fixture.innerHTML).toBe("0_0<div></div>");
|
expect(fixture.innerHTML).toBe("0_0<div></div>");
|
||||||
expect([
|
expect([
|
||||||
"DelayedChild:willRender",
|
"DelayedChild:willRender",
|
||||||
"DelayedChild:rendered",
|
"DelayedChild:rendered",
|
||||||
|
"GrandParent:willRender",
|
||||||
"Parent:willUpdateProps",
|
"Parent:willUpdateProps",
|
||||||
|
"GrandParent:rendered",
|
||||||
"ReactiveChild:willRender",
|
"ReactiveChild:willRender",
|
||||||
"ReactiveChild:rendered",
|
"ReactiveChild:rendered",
|
||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
@@ -2800,12 +2856,14 @@ test("delay willUpdateProps with rendering grandchild", async () => {
|
|||||||
const prom2 = promise;
|
const prom2 = promise;
|
||||||
child.render(); // trigger a root rendering first
|
child.render(); // trigger a root rendering first
|
||||||
parent.state.value = 2;
|
parent.state.value = 2;
|
||||||
parent.render();
|
parent.render(true);
|
||||||
reactiveChild.render();
|
reactiveChild.render();
|
||||||
await nextTick();
|
await nextTick();
|
||||||
expect(fixture.innerHTML).toBe("0_0<div></div>");
|
expect(fixture.innerHTML).toBe("0_0<div></div>");
|
||||||
expect([
|
expect([
|
||||||
|
"GrandParent:willRender",
|
||||||
"Parent:willUpdateProps",
|
"Parent:willUpdateProps",
|
||||||
|
"GrandParent:rendered",
|
||||||
"ReactiveChild:willRender",
|
"ReactiveChild:willRender",
|
||||||
"ReactiveChild:rendered",
|
"ReactiveChild:rendered",
|
||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
@@ -2822,12 +2880,14 @@ test("delay willUpdateProps with rendering grandchild", async () => {
|
|||||||
expect([
|
expect([
|
||||||
"DelayedChild:willRender",
|
"DelayedChild:willRender",
|
||||||
"DelayedChild:rendered",
|
"DelayedChild:rendered",
|
||||||
|
"GrandParent:willPatch",
|
||||||
"Parent:willPatch",
|
"Parent:willPatch",
|
||||||
"ReactiveChild:willPatch",
|
"ReactiveChild:willPatch",
|
||||||
"DelayedChild:willPatch",
|
"DelayedChild:willPatch",
|
||||||
"DelayedChild:patched",
|
"DelayedChild:patched",
|
||||||
"ReactiveChild:patched",
|
"ReactiveChild:patched",
|
||||||
"Parent:patched",
|
"Parent:patched",
|
||||||
|
"GrandParent:patched",
|
||||||
]).toBeLogged();
|
]).toBeLogged();
|
||||||
|
|
||||||
prom1.resolve();
|
prom1.resolve();
|
||||||
|
|||||||
@@ -238,7 +238,7 @@ describe("hooks", () => {
|
|||||||
expect(fixture.innerHTML).toBe("<div>maggot brain</div>");
|
expect(fixture.innerHTML).toBe("<div>maggot brain</div>");
|
||||||
someVal = "brain";
|
someVal = "brain";
|
||||||
someVal2 = "maggot";
|
someVal2 = "maggot";
|
||||||
component.render();
|
component.render(true);
|
||||||
await nextTick();
|
await nextTick();
|
||||||
expect(fixture.innerHTML).toBe("<div>brain maggot</div>");
|
expect(fixture.innerHTML).toBe("<div>brain maggot</div>");
|
||||||
});
|
});
|
||||||
@@ -272,7 +272,7 @@ describe("hooks", () => {
|
|||||||
expect(fixture.innerHTML).toBe("<div>maggot brain</div>");
|
expect(fixture.innerHTML).toBe("<div>maggot brain</div>");
|
||||||
someVal = "brain";
|
someVal = "brain";
|
||||||
someVal2 = "maggot";
|
someVal2 = "maggot";
|
||||||
component.render();
|
component.render(true);
|
||||||
await nextTick();
|
await nextTick();
|
||||||
expect(fixture.innerHTML).toBe("<div>brain maggot</div>");
|
expect(fixture.innerHTML).toBe("<div>brain maggot</div>");
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -849,8 +849,9 @@ describe("lifecycle hooks", () => {
|
|||||||
|
|
||||||
class Parent extends Component {
|
class Parent extends Component {
|
||||||
static template = xml`
|
static template = xml`
|
||||||
<Child />`;
|
<Child someValue="state.value" />`;
|
||||||
static components = { Child };
|
static components = { Child };
|
||||||
|
state = useState({ value: 1 });
|
||||||
setup() {
|
setup() {
|
||||||
useLogLifecycle();
|
useLogLifecycle();
|
||||||
}
|
}
|
||||||
@@ -871,7 +872,7 @@ describe("lifecycle hooks", () => {
|
|||||||
"Parent:mounted",
|
"Parent:mounted",
|
||||||
]).toBeLogged();
|
]).toBeLogged();
|
||||||
|
|
||||||
parent.render(); // to block child render
|
parent.state.value++; // to block child render
|
||||||
await nextTick();
|
await nextTick();
|
||||||
expect(["Parent:willRender", "Child:willUpdateProps", "Parent:rendered"]).toBeLogged();
|
expect(["Parent:willRender", "Child:willUpdateProps", "Parent:rendered"]).toBeLogged();
|
||||||
|
|
||||||
@@ -1008,20 +1009,15 @@ describe("lifecycle hooks", () => {
|
|||||||
await nextTick();
|
await nextTick();
|
||||||
expect([
|
expect([
|
||||||
"C:willRender",
|
"C:willRender",
|
||||||
"D:willUpdateProps",
|
|
||||||
"F:setup",
|
"F:setup",
|
||||||
"F:willStart",
|
"F:willStart",
|
||||||
"C:rendered",
|
"C:rendered",
|
||||||
"D:willRender",
|
|
||||||
"D:rendered",
|
|
||||||
"F:willRender",
|
"F:willRender",
|
||||||
"F:rendered",
|
"F:rendered",
|
||||||
"C:willPatch",
|
"C:willPatch",
|
||||||
"D:willPatch",
|
|
||||||
"E:willUnmount",
|
"E:willUnmount",
|
||||||
"E:willDestroy",
|
"E:willDestroy",
|
||||||
"F:mounted",
|
"F:mounted",
|
||||||
"D:patched",
|
|
||||||
"C:patched",
|
"C:patched",
|
||||||
]).toBeLogged();
|
]).toBeLogged();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,442 @@
|
|||||||
|
import { Component, mount, onRendered, onWillUpdateProps, useState, xml } from "../../src";
|
||||||
|
import {
|
||||||
|
makeTestFixture,
|
||||||
|
snapshotEverything,
|
||||||
|
nextTick,
|
||||||
|
useLogLifecycle,
|
||||||
|
makeDeferred,
|
||||||
|
nextMicroTick,
|
||||||
|
} from "../helpers";
|
||||||
|
|
||||||
|
let fixture: HTMLElement;
|
||||||
|
|
||||||
|
snapshotEverything();
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = makeTestFixture();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("rendering semantics", () => {
|
||||||
|
test("can render a parent without rendering child", async () => {
|
||||||
|
class Child extends Component {
|
||||||
|
static template = xml`child`;
|
||||||
|
setup() {
|
||||||
|
useLogLifecycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Parent extends Component {
|
||||||
|
static template = xml`
|
||||||
|
<t t-esc="state.value"/>
|
||||||
|
<Child/>
|
||||||
|
`;
|
||||||
|
static components = { Child };
|
||||||
|
|
||||||
|
state = useState({ value: "A" });
|
||||||
|
setup() {
|
||||||
|
useLogLifecycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const parent = await mount(Parent, fixture);
|
||||||
|
|
||||||
|
expect(fixture.innerHTML).toBe("Achild");
|
||||||
|
expect([
|
||||||
|
"Parent:setup",
|
||||||
|
"Parent:willStart",
|
||||||
|
"Parent:willRender",
|
||||||
|
"Child:setup",
|
||||||
|
"Child:willStart",
|
||||||
|
"Parent:rendered",
|
||||||
|
"Child:willRender",
|
||||||
|
"Child:rendered",
|
||||||
|
"Child:mounted",
|
||||||
|
"Parent:mounted",
|
||||||
|
]).toBeLogged();
|
||||||
|
|
||||||
|
parent.state.value = "B";
|
||||||
|
await nextTick();
|
||||||
|
expect(fixture.innerHTML).toBe("Bchild");
|
||||||
|
expect([
|
||||||
|
"Parent:willRender",
|
||||||
|
"Parent:rendered",
|
||||||
|
"Parent:willPatch",
|
||||||
|
"Parent:patched",
|
||||||
|
]).toBeLogged();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("can force a render to update sub tree", async () => {
|
||||||
|
let childN = 0;
|
||||||
|
let parentN = 0;
|
||||||
|
class Child extends Component {
|
||||||
|
static template = xml`child`;
|
||||||
|
setup() {
|
||||||
|
onRendered(() => childN++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Parent extends Component {
|
||||||
|
static template = xml`
|
||||||
|
<t t-esc="state.value"/>
|
||||||
|
<Child/>
|
||||||
|
`;
|
||||||
|
static components = { Child };
|
||||||
|
|
||||||
|
state = { value: "A" };
|
||||||
|
setup() {
|
||||||
|
onRendered(() => parentN++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const parent = await mount(Parent, fixture);
|
||||||
|
|
||||||
|
expect(fixture.innerHTML).toBe("Achild");
|
||||||
|
expect(parentN).toBe(1);
|
||||||
|
expect(childN).toBe(1);
|
||||||
|
|
||||||
|
parent.state.value = "B";
|
||||||
|
parent.render(true);
|
||||||
|
await nextTick();
|
||||||
|
expect(fixture.innerHTML).toBe("Bchild");
|
||||||
|
expect(parentN).toBe(2);
|
||||||
|
expect(childN).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("render with deep=true followed by render with deep=false work as expected", async () => {
|
||||||
|
class Child extends Component {
|
||||||
|
static template = xml`child<t t-esc="env.getValue()"/>`;
|
||||||
|
setup() {
|
||||||
|
useLogLifecycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Parent extends Component {
|
||||||
|
static template = xml`parent<t t-esc="state.value"/><Child/>`;
|
||||||
|
static components = { Child };
|
||||||
|
|
||||||
|
state = useState({ value: "A" });
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
useLogLifecycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let value = 3;
|
||||||
|
const env = {
|
||||||
|
getValue() {
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const parent = await mount(Parent, fixture, { env });
|
||||||
|
|
||||||
|
expect(fixture.innerHTML).toBe("parentAchild3");
|
||||||
|
expect([
|
||||||
|
"Parent:setup",
|
||||||
|
"Parent:willStart",
|
||||||
|
"Parent:willRender",
|
||||||
|
"Child:setup",
|
||||||
|
"Child:willStart",
|
||||||
|
"Parent:rendered",
|
||||||
|
"Child:willRender",
|
||||||
|
"Child:rendered",
|
||||||
|
"Child:mounted",
|
||||||
|
"Parent:mounted",
|
||||||
|
]).toBeLogged();
|
||||||
|
|
||||||
|
value = 4;
|
||||||
|
parent.render(true);
|
||||||
|
|
||||||
|
// wait for child to be rendered, but dom not yet patched
|
||||||
|
await nextMicroTick();
|
||||||
|
await nextMicroTick();
|
||||||
|
await nextMicroTick();
|
||||||
|
expect([
|
||||||
|
"Parent:willRender",
|
||||||
|
"Child:willUpdateProps",
|
||||||
|
"Parent:rendered",
|
||||||
|
"Child:willRender",
|
||||||
|
"Child:rendered",
|
||||||
|
]).toBeLogged();
|
||||||
|
|
||||||
|
parent.state.value = "B";
|
||||||
|
|
||||||
|
await nextTick();
|
||||||
|
|
||||||
|
expect(fixture.innerHTML).toBe("parentBchild4");
|
||||||
|
expect([
|
||||||
|
"Parent:willRender",
|
||||||
|
"Child:willUpdateProps",
|
||||||
|
"Parent:rendered",
|
||||||
|
"Child:willRender",
|
||||||
|
"Child:rendered",
|
||||||
|
"Parent:willPatch",
|
||||||
|
"Child:willPatch",
|
||||||
|
"Child:patched",
|
||||||
|
"Parent:patched",
|
||||||
|
]).toBeLogged();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("props are reactive", async () => {
|
||||||
|
class Child extends Component {
|
||||||
|
static template = xml`<t t-esc="props.a.b"/>`;
|
||||||
|
setup() {
|
||||||
|
useLogLifecycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Parent extends Component {
|
||||||
|
static template = xml`
|
||||||
|
<Child a="state"/>
|
||||||
|
`;
|
||||||
|
static components = { Child };
|
||||||
|
|
||||||
|
state = useState({ b: 1 });
|
||||||
|
setup() {
|
||||||
|
useLogLifecycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const parent = await mount(Parent, fixture);
|
||||||
|
expect(fixture.innerHTML).toBe("1");
|
||||||
|
expect([
|
||||||
|
"Parent:setup",
|
||||||
|
"Parent:willStart",
|
||||||
|
"Parent:willRender",
|
||||||
|
"Child:setup",
|
||||||
|
"Child:willStart",
|
||||||
|
"Parent:rendered",
|
||||||
|
"Child:willRender",
|
||||||
|
"Child:rendered",
|
||||||
|
"Child:mounted",
|
||||||
|
"Parent:mounted",
|
||||||
|
]).toBeLogged();
|
||||||
|
|
||||||
|
parent.state.b = 3;
|
||||||
|
await nextTick();
|
||||||
|
expect(fixture.innerHTML).toBe("3");
|
||||||
|
expect(["Child:willRender", "Child:rendered", "Child:willPatch", "Child:patched"]).toBeLogged();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("props are reactive (nested prop)", async () => {
|
||||||
|
class Child extends Component {
|
||||||
|
static template = xml`<t t-esc="props.a.b.c"/>`;
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
useLogLifecycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Parent extends Component {
|
||||||
|
static template = xml`
|
||||||
|
<Child a="state"/>
|
||||||
|
`;
|
||||||
|
static components = { Child };
|
||||||
|
|
||||||
|
state = useState({ b: { c: 1 } });
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
useLogLifecycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const parent = await mount(Parent, fixture);
|
||||||
|
expect(fixture.innerHTML).toBe("1");
|
||||||
|
expect([
|
||||||
|
"Parent:setup",
|
||||||
|
"Parent:willStart",
|
||||||
|
"Parent:willRender",
|
||||||
|
"Child:setup",
|
||||||
|
"Child:willStart",
|
||||||
|
"Parent:rendered",
|
||||||
|
"Child:willRender",
|
||||||
|
"Child:rendered",
|
||||||
|
"Child:mounted",
|
||||||
|
"Parent:mounted",
|
||||||
|
]).toBeLogged();
|
||||||
|
|
||||||
|
parent.state.b.c = 3; // parent is now subscribed to 'b' key
|
||||||
|
await nextTick();
|
||||||
|
expect(fixture.innerHTML).toBe("3");
|
||||||
|
expect(["Child:willRender", "Child:rendered", "Child:willPatch", "Child:patched"]).toBeLogged();
|
||||||
|
|
||||||
|
parent.state.b = { c: 444 }; // triggers a parent and a child render
|
||||||
|
await nextTick();
|
||||||
|
expect(fixture.innerHTML).toBe("444");
|
||||||
|
expect([
|
||||||
|
"Parent:willRender",
|
||||||
|
"Parent:rendered",
|
||||||
|
"Child:willRender",
|
||||||
|
"Child:rendered",
|
||||||
|
"Parent:willPatch",
|
||||||
|
"Parent:patched",
|
||||||
|
"Child:willPatch",
|
||||||
|
"Child:patched",
|
||||||
|
]).toBeLogged();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("works as expected for dynamic number of props", async () => {
|
||||||
|
class Child extends Component {
|
||||||
|
static template = xml`<t t-esc="Object.keys(props).length"/>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Parent extends Component {
|
||||||
|
static template = xml`
|
||||||
|
<Child t-props="state"/>
|
||||||
|
`;
|
||||||
|
static components = { Child };
|
||||||
|
|
||||||
|
state: any = useState({ b: 1 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const parent = await mount(Parent, fixture);
|
||||||
|
expect(fixture.innerHTML).toBe("1");
|
||||||
|
parent.state.newkey = 3;
|
||||||
|
await nextTick();
|
||||||
|
expect(fixture.innerHTML).toBe("2");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("rendering is atomic (for one subtree)", async () => {
|
||||||
|
const def = makeDeferred();
|
||||||
|
|
||||||
|
class C extends Component {
|
||||||
|
static template = xml`<t t-esc="props.obj.val"/>`;
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
useLogLifecycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B extends Component {
|
||||||
|
static template = xml`<C obj="props.obj"/>`;
|
||||||
|
static components = { C };
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
useLogLifecycle();
|
||||||
|
onWillUpdateProps(() => def);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class A extends Component {
|
||||||
|
static template = xml`<t t-esc="state.obj.val"/><B obj="state.obj"/>`;
|
||||||
|
static components = { B };
|
||||||
|
|
||||||
|
state = useState({ obj: { val: 1 } });
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
useLogLifecycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const parent = await mount(A, fixture);
|
||||||
|
expect(fixture.innerHTML).toBe("11");
|
||||||
|
expect([
|
||||||
|
"A:setup",
|
||||||
|
"A:willStart",
|
||||||
|
"A:willRender",
|
||||||
|
"B:setup",
|
||||||
|
"B:willStart",
|
||||||
|
"A:rendered",
|
||||||
|
"B:willRender",
|
||||||
|
"C:setup",
|
||||||
|
"C:willStart",
|
||||||
|
"B:rendered",
|
||||||
|
"C:willRender",
|
||||||
|
"C:rendered",
|
||||||
|
"C:mounted",
|
||||||
|
"B:mounted",
|
||||||
|
"A:mounted",
|
||||||
|
]).toBeLogged();
|
||||||
|
|
||||||
|
parent.state.obj.val = 3;
|
||||||
|
await nextTick();
|
||||||
|
expect(fixture.innerHTML).toBe("33");
|
||||||
|
expect([
|
||||||
|
"A:willRender",
|
||||||
|
"A:rendered",
|
||||||
|
"C:willRender",
|
||||||
|
"C:rendered",
|
||||||
|
"A:willPatch",
|
||||||
|
"A:patched",
|
||||||
|
"C:willPatch",
|
||||||
|
"C:patched",
|
||||||
|
]).toBeLogged();
|
||||||
|
|
||||||
|
def.resolve();
|
||||||
|
await nextTick();
|
||||||
|
expect([]).toBeLogged();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("force render in case of existing render", async () => {
|
||||||
|
const def = makeDeferred();
|
||||||
|
|
||||||
|
class C extends Component {
|
||||||
|
static template = xml`C`;
|
||||||
|
setup() {
|
||||||
|
useLogLifecycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class B extends Component {
|
||||||
|
static template = xml`<C/><t t-esc="props.val"/>`;
|
||||||
|
static components = { C };
|
||||||
|
setup() {
|
||||||
|
useLogLifecycle();
|
||||||
|
onWillUpdateProps(() => def);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class A extends Component {
|
||||||
|
static template = xml`<B val="state.val"/>`;
|
||||||
|
static components = { B };
|
||||||
|
state = useState({ val: 1 });
|
||||||
|
setup() {
|
||||||
|
useLogLifecycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const parent = await mount(A, fixture);
|
||||||
|
expect(fixture.innerHTML).toBe("C1");
|
||||||
|
expect([
|
||||||
|
"A:setup",
|
||||||
|
"A:willStart",
|
||||||
|
"A:willRender",
|
||||||
|
"B:setup",
|
||||||
|
"B:willStart",
|
||||||
|
"A:rendered",
|
||||||
|
"B:willRender",
|
||||||
|
"C:setup",
|
||||||
|
"C:willStart",
|
||||||
|
"B:rendered",
|
||||||
|
"C:willRender",
|
||||||
|
"C:rendered",
|
||||||
|
"C:mounted",
|
||||||
|
"B:mounted",
|
||||||
|
"A:mounted",
|
||||||
|
]).toBeLogged();
|
||||||
|
|
||||||
|
// trigger a new rendering, blocked in B
|
||||||
|
parent.state.val = 2;
|
||||||
|
await nextTick();
|
||||||
|
expect(["A:willRender", "B:willUpdateProps", "A:rendered"]).toBeLogged();
|
||||||
|
|
||||||
|
// initiate a new render with deep=true. it should cancel the current render
|
||||||
|
// and also be blocked in B
|
||||||
|
parent.render(true);
|
||||||
|
await nextTick();
|
||||||
|
expect(["A:willRender", "B:willUpdateProps", "A:rendered"]).toBeLogged();
|
||||||
|
|
||||||
|
def.resolve();
|
||||||
|
await nextTick();
|
||||||
|
// we check here that the render reaches C (so, that it was properly forced)
|
||||||
|
expect([
|
||||||
|
"B:willRender",
|
||||||
|
"C:willUpdateProps",
|
||||||
|
"B:rendered",
|
||||||
|
"C:willRender",
|
||||||
|
"C:rendered",
|
||||||
|
"A:willPatch",
|
||||||
|
"B:willPatch",
|
||||||
|
"C:willPatch",
|
||||||
|
"C:patched",
|
||||||
|
"B:patched",
|
||||||
|
"A:patched",
|
||||||
|
]).toBeLogged();
|
||||||
|
});
|
||||||
@@ -1675,4 +1675,60 @@ describe("slots", () => {
|
|||||||
await mount(Parent, fixture);
|
await mount(Parent, fixture);
|
||||||
expect(fixture.innerHTML).toBe("<div>SlotDisplay</div><div>Parent</div>");
|
expect(fixture.innerHTML).toBe("<div>SlotDisplay</div><div>Parent</div>");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("mix of slots, t-call, t-call with body, and giving own props child", async () => {
|
||||||
|
expect.assertions(11);
|
||||||
|
|
||||||
|
class C extends Component {
|
||||||
|
static template = xml`[C]<t t-slot="default" />`;
|
||||||
|
}
|
||||||
|
class B extends Component {
|
||||||
|
static template = xml`[B]<C slots="props.slots" />`;
|
||||||
|
static components = { C };
|
||||||
|
}
|
||||||
|
|
||||||
|
const subTemplate2 = xml`[sub2<t t-esc="v"/>]`;
|
||||||
|
const subTemplate1 = xml`[sub1]
|
||||||
|
<t t-set="dummy" t-value="validate"/>
|
||||||
|
<t t-call="${subTemplate2}">
|
||||||
|
<t t-set="v" t-value="props.number"/>
|
||||||
|
</t>`;
|
||||||
|
|
||||||
|
let a: any;
|
||||||
|
class A extends Component {
|
||||||
|
static components = { B };
|
||||||
|
static template = xml`<B>[A]<t t-call="${subTemplate1}"/></B>`;
|
||||||
|
setup() {
|
||||||
|
a = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
get validate() {
|
||||||
|
// we check here that the actual component was not lost somehow
|
||||||
|
expect(this.__owl__.component === a).toBe(true);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class P extends Component {
|
||||||
|
static components = { A };
|
||||||
|
static template = xml`<button t-on-click="inc">inc</button><A number="state.number"/>`;
|
||||||
|
|
||||||
|
state = useState({ number: 333 });
|
||||||
|
inc() {
|
||||||
|
this.state.number++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Parent extends Component {
|
||||||
|
static template = xml`<P/>`;
|
||||||
|
static components = { P };
|
||||||
|
}
|
||||||
|
|
||||||
|
await mount(Parent, fixture);
|
||||||
|
expect(fixture.innerHTML).toBe("<button>inc</button>[B][C][A][sub1] [sub2333]");
|
||||||
|
|
||||||
|
fixture.querySelector("button")!.click();
|
||||||
|
await nextTick();
|
||||||
|
expect(fixture.innerHTML).toBe("<button>inc</button>[B][C][A][sub1] [sub2334]");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ describe("t-props", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("basic use", async () => {
|
test("basic use", async () => {
|
||||||
expect.assertions(4);
|
expect.assertions(5);
|
||||||
|
|
||||||
let props = { a: 1, b: 2 };
|
let props = { a: 1, b: 2 };
|
||||||
|
|
||||||
@@ -65,6 +65,7 @@ describe("t-props", () => {
|
|||||||
`;
|
`;
|
||||||
setup() {
|
setup() {
|
||||||
expect(this.props).toEqual({ a: 1, b: 2 });
|
expect(this.props).toEqual({ a: 1, b: 2 });
|
||||||
|
expect(this.props).not.toBe(props);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class Parent extends Component {
|
class Parent extends Component {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ exports[`Memo if no prop change, prevent renderings from above 1`] = `
|
|||||||
"function anonymous(bdom, helpers
|
"function anonymous(bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
let { markRaw } = helpers;
|
||||||
|
|
||||||
function slot1(ctx, node, key = \\"\\") {
|
function slot1(ctx, node, key = \\"\\") {
|
||||||
let b6 = text(ctx['state'].a);
|
let b6 = text(ctx['state'].a);
|
||||||
@@ -16,7 +17,7 @@ exports[`Memo if no prop change, prevent renderings from above 1`] = `
|
|||||||
let b2 = text(ctx['state'].a);
|
let b2 = text(ctx['state'].a);
|
||||||
let b3 = text(ctx['state'].b);
|
let b3 = text(ctx['state'].b);
|
||||||
let b4 = text(ctx['state'].c);
|
let b4 = text(ctx['state'].c);
|
||||||
let b9 = component(\`Memo\`, {a: ctx['state'].a, b: ctx['state'].b,slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
|
let b9 = component(\`Memo\`, {a: ctx['state'].a, b: ctx['state'].b,slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__1\`, node, ctx);
|
||||||
return multi([b2, b3, b4, b9]);
|
return multi([b2, b3, b4, b9]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -26,6 +27,7 @@ exports[`Memo if no props, prevent renderings from above 1`] = `
|
|||||||
"function anonymous(bdom, helpers
|
"function anonymous(bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
let { markRaw } = helpers;
|
||||||
|
|
||||||
function slot1(ctx, node, key = \\"\\") {
|
function slot1(ctx, node, key = \\"\\") {
|
||||||
return component(\`Child\`, {value: ctx['state'].value}, key + \`__2\`, node, ctx);
|
return component(\`Child\`, {value: ctx['state'].value}, key + \`__2\`, node, ctx);
|
||||||
@@ -33,7 +35,7 @@ exports[`Memo if no props, prevent renderings from above 1`] = `
|
|||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
let b2 = component(\`Child\`, {value: ctx['state'].value}, key + \`__1\`, node, ctx);
|
let b2 = component(\`Child\`, {value: ctx['state'].value}, key + \`__1\`, node, ctx);
|
||||||
let b4 = component(\`Memo\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__3\`, node, ctx);
|
let b4 = component(\`Memo\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__3\`, node, ctx);
|
||||||
return multi([b2, b4]);
|
return multi([b2, b4]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -54,6 +56,7 @@ exports[`Memo if no props, prevent renderings from above (work with simple html)
|
|||||||
"function anonymous(bdom, helpers
|
"function anonymous(bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
let { markRaw } = helpers;
|
||||||
|
|
||||||
function slot1(ctx, node, key = \\"\\") {
|
function slot1(ctx, node, key = \\"\\") {
|
||||||
return text(ctx['state'].value);
|
return text(ctx['state'].value);
|
||||||
@@ -61,7 +64,7 @@ exports[`Memo if no props, prevent renderings from above (work with simple html)
|
|||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
let b2 = text(ctx['state'].value);
|
let b2 = text(ctx['state'].value);
|
||||||
let b4 = component(\`Memo\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
|
let b4 = component(\`Memo\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__1\`, node, ctx);
|
||||||
return multi([b2, b4]);
|
return multi([b2, b4]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
|
|||||||
@@ -149,6 +149,7 @@ exports[`Portal Portal composed with t-slot 1`] = `
|
|||||||
"function anonymous(bdom, helpers
|
"function anonymous(bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
let { markRaw } = helpers;
|
||||||
|
|
||||||
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||||
|
|
||||||
@@ -157,7 +158,7 @@ exports[`Portal Portal composed with t-slot 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
let b3 = component(\`Child\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
|
let b3 = component(\`Child\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__2\`, node, ctx);
|
||||||
return block1([], [b3]);
|
return block1([], [b3]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
|
|||||||
@@ -421,6 +421,7 @@ describe("Portal", () => {
|
|||||||
addOutsideDiv(fixture);
|
addOutsideDiv(fixture);
|
||||||
const parent = await mount(Parent, fixture);
|
const parent = await mount(Parent, fixture);
|
||||||
expect(steps).toEqual(["parent:mounted"]);
|
expect(steps).toEqual(["parent:mounted"]);
|
||||||
|
expect(fixture.innerHTML).toBe('<div id="outside"></div><div></div>');
|
||||||
|
|
||||||
parent.state.hasChild = true;
|
parent.state.hasChild = true;
|
||||||
await nextTick();
|
await nextTick();
|
||||||
@@ -430,6 +431,7 @@ describe("Portal", () => {
|
|||||||
"child:mounted",
|
"child:mounted",
|
||||||
"parent:patched",
|
"parent:patched",
|
||||||
]);
|
]);
|
||||||
|
expect(fixture.innerHTML).toBe('<div id="outside"><span>1</span></div><div></div>');
|
||||||
|
|
||||||
parent.state.val = 2;
|
parent.state.val = 2;
|
||||||
await nextTick();
|
await nextTick();
|
||||||
@@ -443,6 +445,7 @@ describe("Portal", () => {
|
|||||||
"child:patched",
|
"child:patched",
|
||||||
"parent:patched",
|
"parent:patched",
|
||||||
]);
|
]);
|
||||||
|
expect(fixture.innerHTML).toBe('<div id="outside"><span>2</span></div><div></div>');
|
||||||
|
|
||||||
parent.state.hasChild = false;
|
parent.state.hasChild = false;
|
||||||
await nextTick();
|
await nextTick();
|
||||||
@@ -459,6 +462,7 @@ describe("Portal", () => {
|
|||||||
"child:willUnmount",
|
"child:willUnmount",
|
||||||
"parent:patched",
|
"parent:patched",
|
||||||
]);
|
]);
|
||||||
|
expect(fixture.innerHTML).toBe('<div id="outside"></div><div></div>');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("portal destroys on crash", async () => {
|
test("portal destroys on crash", async () => {
|
||||||
|
|||||||
@@ -1657,7 +1657,7 @@ describe("Reactivity: useState", () => {
|
|||||||
expect([...steps]).toEqual(["list"]);
|
expect([...steps]).toEqual(["list"]);
|
||||||
await nextTick();
|
await nextTick();
|
||||||
expect(fixture.innerHTML).toBe("<div><div>3</div> Total: 3 Count: 1</div>");
|
expect(fixture.innerHTML).toBe("<div><div>3</div> Total: 3 Count: 1</div>");
|
||||||
expect([...steps]).toEqual(["list", "quantity1"]);
|
expect([...steps]).toEqual(["list"]);
|
||||||
steps.clear();
|
steps.clear();
|
||||||
|
|
||||||
secondQuantity.quantity = 2;
|
secondQuantity.quantity = 2;
|
||||||
|
|||||||
Reference in New Issue
Block a user