mirror of
https://github.com/facebookarchive/prepack.git
synced 2024-10-26 23:32:02 +03:00
Reduce React bloat on equivalent objects with similar temporal alias trees (#2193)
Summary: Release notes: none In an attempt to pull out some of the work from https://github.com/facebook/prepack/pull/2148 to make things easier to consume and review. This PR is one part, where we check the temporal alias values (if an object value has it) and see if we can dedupe the trees. Example below: Closes https://github.com/facebook/prepack/pull/2193 Differential Revision: D8732542 Pulled By: trueadm fbshipit-source-id: 352d0048acfef69b5a257c0fe280435fa7baaa7f
This commit is contained in:
parent
ef7e1873fa
commit
3cd3dd8431
@ -11,6 +11,7 @@
|
||||
|
||||
import { Realm } from "../realm.js";
|
||||
import {
|
||||
AbstractObjectValue,
|
||||
AbstractValue,
|
||||
ArrayValue,
|
||||
FunctionValue,
|
||||
@ -54,12 +55,14 @@ export class ReactEquivalenceSet {
|
||||
this.arrayRoot = new Map();
|
||||
this.reactElementRoot = new Map();
|
||||
this.reactPropsRoot = new Map();
|
||||
this.temporalAliasRoot = new Map();
|
||||
}
|
||||
realm: Realm;
|
||||
objectRoot: ReactSetKeyMap;
|
||||
arrayRoot: ReactSetKeyMap;
|
||||
reactElementRoot: ReactSetKeyMap;
|
||||
reactPropsRoot: ReactSetKeyMap;
|
||||
temporalAliasRoot: ReactSetKeyMap;
|
||||
residualReactElementVisitor: ResidualReactElementVisitor;
|
||||
|
||||
_createNode(): ReactSetNode {
|
||||
@ -118,10 +121,8 @@ export class ReactEquivalenceSet {
|
||||
let temporalAlias = object.temporalAlias;
|
||||
|
||||
if (temporalAlias !== undefined) {
|
||||
// Snapshotting uses temporalAlias to on ObjectValues, so if
|
||||
// they have a temporalAlias then we need to treat it as a field
|
||||
currentMap = this.getKey(temporalAliasSymbol, currentMap, visitedValues);
|
||||
result = this.getValue(temporalAlias, currentMap, visitedValues);
|
||||
result = this.getTemporalAliasValue(temporalAlias, currentMap, visitedValues);
|
||||
}
|
||||
|
||||
if (result === undefined) {
|
||||
@ -137,6 +138,85 @@ export class ReactEquivalenceSet {
|
||||
return result.value;
|
||||
}
|
||||
|
||||
_getTemporalValue(temporalAlias: AbstractObjectValue, visitedValues: Set<Value>): AbstractObjectValue {
|
||||
// Check to ensure the temporal alias is definitely declared in the current scope
|
||||
if (!this.residualReactElementVisitor.wasTemporalAliasDeclaredInCurrentScope(temporalAlias)) {
|
||||
return temporalAlias;
|
||||
}
|
||||
let temporalBuildNodeEntryArgs = this.realm.getTemporalBuildNodeEntryArgsFromDerivedValue(temporalAlias);
|
||||
|
||||
if (temporalBuildNodeEntryArgs === undefined) {
|
||||
return temporalAlias;
|
||||
}
|
||||
let temporalArgs = temporalBuildNodeEntryArgs.args;
|
||||
if (temporalArgs.length === 0) {
|
||||
return temporalAlias;
|
||||
}
|
||||
let currentMap = this.temporalAliasRoot;
|
||||
let result;
|
||||
|
||||
for (let i = 0; i < temporalArgs.length; i++) {
|
||||
let arg = temporalArgs[i];
|
||||
let equivalenceArg;
|
||||
if (arg instanceof ObjectValue && arg.temporalAlias === temporalAlias) {
|
||||
continue;
|
||||
}
|
||||
if (arg instanceof ObjectValue && isReactElement(arg)) {
|
||||
equivalenceArg = this.residualReactElementVisitor.reactElementEquivalenceSet.add(arg);
|
||||
|
||||
if (arg !== equivalenceArg) {
|
||||
temporalArgs[i] = equivalenceArg;
|
||||
}
|
||||
} else if (arg instanceof AbstractObjectValue && !arg.values.isTop() && arg.kind !== "conditional") {
|
||||
// Might be a temporal, so let's check
|
||||
let childTemporalBuildNodeEntryArgs = this.realm.getTemporalBuildNodeEntryArgsFromDerivedValue(arg);
|
||||
|
||||
if (childTemporalBuildNodeEntryArgs !== undefined) {
|
||||
equivalenceArg = this._getTemporalValue(arg, visitedValues);
|
||||
invariant(equivalenceArg instanceof AbstractObjectValue);
|
||||
|
||||
if (equivalenceArg !== arg) {
|
||||
temporalArgs[i] = equivalenceArg;
|
||||
}
|
||||
}
|
||||
} else if (arg instanceof AbstractValue) {
|
||||
equivalenceArg = this.residualReactElementVisitor.residualHeapVisitor.equivalenceSet.add(arg);
|
||||
|
||||
if (arg !== equivalenceArg) {
|
||||
temporalArgs[i] = equivalenceArg;
|
||||
}
|
||||
}
|
||||
currentMap = this.getKey(i, (currentMap: any), visitedValues);
|
||||
invariant(arg instanceof Value && (equivalenceArg instanceof Value || equivalenceArg === undefined));
|
||||
result = this.getValue(equivalenceArg || arg, currentMap, visitedValues);
|
||||
currentMap = result.map;
|
||||
}
|
||||
invariant(result !== undefined);
|
||||
if (result.value === null) {
|
||||
result.value = temporalAlias;
|
||||
}
|
||||
// Check to ensure the equivalent temporal alias is definitely declared in the current scope
|
||||
if (!this.residualReactElementVisitor.wasTemporalAliasDeclaredInCurrentScope(result.value)) {
|
||||
result.value = temporalAlias;
|
||||
return temporalAlias;
|
||||
}
|
||||
return result.value;
|
||||
}
|
||||
|
||||
getTemporalAliasValue(
|
||||
temporalAlias: AbstractObjectValue,
|
||||
map: ReactSetValueMap,
|
||||
visitedValues: Set<Value>
|
||||
): ReactSetNode {
|
||||
let result = this._getTemporalValue(temporalAlias, visitedValues);
|
||||
|
||||
invariant(result instanceof AbstractObjectValue);
|
||||
if (!map.has(result)) {
|
||||
map.set(result, this._createNode());
|
||||
}
|
||||
return ((map.get(result): any): ReactSetNode);
|
||||
}
|
||||
|
||||
// for arrays: [0] -> [1] -> [2]... as nodes
|
||||
_getArrayValue(array: ArrayValue, visitedValues: Set<Value>): ArrayValue {
|
||||
if (visitedValues.has(array)) return array;
|
||||
|
@ -37,10 +37,9 @@ export class ReactPropsSet {
|
||||
let temporalAlias = props.temporalAlias;
|
||||
|
||||
if (temporalAlias !== undefined) {
|
||||
// Snapshotting uses temporalAlias to on ObjectValues, so if
|
||||
// they have a temporalAlias then we need to treat it as a field
|
||||
currentMap = reactEquivalenceSet.getKey(temporalAliasSymbol, currentMap, visitedValues);
|
||||
result = reactEquivalenceSet.getValue(temporalAlias, currentMap, visitedValues);
|
||||
result = reactEquivalenceSet.getTemporalAliasValue(temporalAlias, currentMap, visitedValues);
|
||||
currentMap = result.map;
|
||||
}
|
||||
|
||||
if (result === undefined) {
|
||||
|
@ -41,6 +41,9 @@ function createPropsObject(
|
||||
config: ObjectValue | AbstractObjectValue,
|
||||
children: void | Value
|
||||
): { key: Value, ref: Value, props: ObjectValue } {
|
||||
// If we're in "rendering" a React component tree, we should have an active reconciler
|
||||
let activeReconciler = realm.react.activeReconciler;
|
||||
let firstRenderOnly = activeReconciler !== undefined ? activeReconciler.componentTreeConfig.firstRenderOnly : false;
|
||||
let defaultProps =
|
||||
type instanceof ObjectValue || type instanceof AbstractObjectValue
|
||||
? Get(realm, type, "defaultProps")
|
||||
@ -82,7 +85,7 @@ function createPropsObject(
|
||||
}
|
||||
|
||||
let possibleRef = Get(realm, config, "ref");
|
||||
if (possibleRef !== realm.intrinsics.null && possibleRef !== realm.intrinsics.undefined) {
|
||||
if (possibleRef !== realm.intrinsics.null && possibleRef !== realm.intrinsics.undefined && !firstRenderOnly) {
|
||||
// if the config has been marked as having no partial key or ref and the possible ref
|
||||
// is abstract, yet the config doesn't have a ref property, then the ref can remain null
|
||||
let refNotNeeded =
|
||||
@ -117,13 +120,11 @@ function createPropsObject(
|
||||
(config instanceof AbstractObjectValue && config.isPartialObject()) ||
|
||||
(config instanceof ObjectValue && config.isPartialObject() && config.isSimpleObject())
|
||||
) {
|
||||
let args = [];
|
||||
args.push(config);
|
||||
// create a new props object that will be the target of the Object.assign
|
||||
props = Create.ObjectCreate(realm, realm.intrinsics.ObjectPrototype);
|
||||
realm.react.reactProps.add(props);
|
||||
|
||||
applyObjectAssignConfigsForReactElement(realm, props, args);
|
||||
applyObjectAssignConfigsForReactElement(realm, props, [config]);
|
||||
props.makeFinal();
|
||||
|
||||
if (children !== undefined) {
|
||||
|
@ -10,7 +10,15 @@
|
||||
/* @flow strict-local */
|
||||
|
||||
import { Realm } from "../realm.js";
|
||||
import { AbstractValue, ObjectValue, StringValue, SymbolValue, Value } from "../values/index.js";
|
||||
import {
|
||||
AbstractObjectValue,
|
||||
AbstractValue,
|
||||
FunctionValue,
|
||||
ObjectValue,
|
||||
StringValue,
|
||||
SymbolValue,
|
||||
Value,
|
||||
} from "../values/index.js";
|
||||
import { ResidualHeapVisitor } from "./ResidualHeapVisitor.js";
|
||||
import { determineIfReactElementCanBeHoisted } from "../react/hoisting.js";
|
||||
import { traverseReactElement } from "../react/elements.js";
|
||||
@ -21,6 +29,7 @@ import {
|
||||
hardModifyReactObjectPropertyBinding,
|
||||
} from "../react/utils.js";
|
||||
import invariant from "../invariant.js";
|
||||
import { TemporalBuildNodeEntry } from "../utils/generator.js";
|
||||
import { ReactEquivalenceSet } from "../react/ReactEquivalenceSet.js";
|
||||
import { ReactElementSet } from "../react/ReactElementSet.js";
|
||||
import { ReactPropsSet } from "../react/ReactPropsSet.js";
|
||||
@ -122,4 +131,27 @@ export class ResidualReactElementVisitor {
|
||||
this.reactElementEquivalenceSet = reactElementEquivalenceSet;
|
||||
this.reactPropsEquivalenceSet = reactPropsEquivalenceSet;
|
||||
}
|
||||
|
||||
wasTemporalAliasDeclaredInCurrentScope(temporalAlias: AbstractObjectValue): boolean {
|
||||
let scope = this.residualHeapVisitor.scope;
|
||||
if (scope instanceof FunctionValue) {
|
||||
return false;
|
||||
}
|
||||
// If the temporal has already been visited, then we know the temporal
|
||||
// value was used and thus declared in another scope
|
||||
if (this.residualHeapVisitor.values.has(temporalAlias)) {
|
||||
return false;
|
||||
}
|
||||
// Otherwise, we check the current scope and see if the
|
||||
// temporal value was declared in one of the entries
|
||||
for (let i = 0; i < scope._entries.length; i++) {
|
||||
let entry = scope._entries[i];
|
||||
if (entry instanceof TemporalBuildNodeEntry) {
|
||||
if (entry.declared === temporalAlias) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ export type TemporalBuildNodeEntryArgs = {
|
||||
mutatesOnly?: Array<Value>,
|
||||
};
|
||||
|
||||
class TemporalBuildNodeEntry extends GeneratorEntry {
|
||||
export class TemporalBuildNodeEntry extends GeneratorEntry {
|
||||
constructor(args: TemporalBuildNodeEntryArgs) {
|
||||
super();
|
||||
Object.assign(this, args);
|
||||
|
@ -94,3 +94,23 @@ it("Replace this in callbacks 2", () => {
|
||||
it("Replace this in callbacks 3", () => {
|
||||
runTest(__dirname + "/FirstRenderOnly/replace-this-in-callbacks3.js", { firstRenderOnly: true });
|
||||
});
|
||||
|
||||
it("Equivalence of snapshotted node", () => {
|
||||
runTest(__dirname + "/FirstRenderOnly/equivalence.js", { firstRenderOnly: true });
|
||||
});
|
||||
|
||||
it("Equivalence of snapshotted node 2", () => {
|
||||
runTest(__dirname + "/FirstRenderOnly/equivalence2.js", { firstRenderOnly: true });
|
||||
});
|
||||
|
||||
it("Equivalence of snapshotted node 3", () => {
|
||||
runTest(__dirname + "/FirstRenderOnly/equivalence3.js", { firstRenderOnly: true });
|
||||
});
|
||||
|
||||
it("Equivalence of snapshotted node 4", () => {
|
||||
runTest(__dirname + "/FirstRenderOnly/equivalence4.js", { firstRenderOnly: true });
|
||||
});
|
||||
|
||||
it("Equivalence of snapshotted node 5", () => {
|
||||
runTest(__dirname + "/FirstRenderOnly/equivalence5.js", { firstRenderOnly: true });
|
||||
});
|
||||
|
27
test/react/FirstRenderOnly/equivalence.js
Normal file
27
test/react/FirstRenderOnly/equivalence.js
Normal file
@ -0,0 +1,27 @@
|
||||
var React = require("react");
|
||||
|
||||
function App(props) {
|
||||
var foo = Object.assign({}, props);
|
||||
var a = <span {...foo} key={null} />;
|
||||
var b = <span {...foo} key={null} />;
|
||||
return [a, b];
|
||||
}
|
||||
|
||||
App.getTrials = function(renderer, Root, data, isCompiled) {
|
||||
if (isCompiled) {
|
||||
const [a, b] = Root({});
|
||||
if (a !== b) {
|
||||
throw new Error("Equivalence check failed");
|
||||
}
|
||||
}
|
||||
renderer.update(<Root />);
|
||||
return [["equivalence render", renderer.toJSON()]];
|
||||
};
|
||||
|
||||
if (this.__optimizeReactComponentTree) {
|
||||
__optimizeReactComponentTree(App, {
|
||||
firstRenderOnly: true,
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = App;
|
28
test/react/FirstRenderOnly/equivalence2.js
Normal file
28
test/react/FirstRenderOnly/equivalence2.js
Normal file
@ -0,0 +1,28 @@
|
||||
var React = require("react");
|
||||
|
||||
function App(props) {
|
||||
var foo = { children: <div /> };
|
||||
var foo2 = Object.assign({}, props, foo);
|
||||
var a = <span {...foo2} key={null} />;
|
||||
var b = <span {...foo2} key={null} />;
|
||||
return [a, b];
|
||||
}
|
||||
|
||||
App.getTrials = function(renderer, Root, data, isCompiled) {
|
||||
if (isCompiled) {
|
||||
const [a, b] = Root({});
|
||||
if (a !== b) {
|
||||
throw new Error("Equivalence check failed");
|
||||
}
|
||||
}
|
||||
renderer.update(<Root />);
|
||||
return [["equivalence render", renderer.toJSON()]];
|
||||
};
|
||||
|
||||
if (this.__optimizeReactComponentTree) {
|
||||
__optimizeReactComponentTree(App, {
|
||||
firstRenderOnly: true,
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = App;
|
34
test/react/FirstRenderOnly/equivalence3.js
Normal file
34
test/react/FirstRenderOnly/equivalence3.js
Normal file
@ -0,0 +1,34 @@
|
||||
var React = require("react");
|
||||
|
||||
function App(props) {
|
||||
var foo = props.foo;
|
||||
var x = {
|
||||
val: 1,
|
||||
};
|
||||
var y = {
|
||||
val: 1,
|
||||
};
|
||||
var foo = Object.assign({}, props, foo ? x : y);
|
||||
var a = <span {...foo} key={null} />;
|
||||
var b = <span {...foo} key={null} />;
|
||||
return [a, b];
|
||||
}
|
||||
|
||||
App.getTrials = function(renderer, Root, data, isCompiled) {
|
||||
if (isCompiled) {
|
||||
const [a, b] = Root({ foo: false });
|
||||
if (a !== b) {
|
||||
throw new Error("Equivalence check failed");
|
||||
}
|
||||
}
|
||||
renderer.update(<Root foo={false} />);
|
||||
return [["equivalence render", renderer.toJSON()]];
|
||||
};
|
||||
|
||||
if (this.__optimizeReactComponentTree) {
|
||||
__optimizeReactComponentTree(App, {
|
||||
firstRenderOnly: true,
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = App;
|
24
test/react/FirstRenderOnly/equivalence4.js
Normal file
24
test/react/FirstRenderOnly/equivalence4.js
Normal file
@ -0,0 +1,24 @@
|
||||
var React = require("react");
|
||||
|
||||
function App(props) {
|
||||
var foo = Object.assign({}, props);
|
||||
|
||||
if (props.x) {
|
||||
return <span {...foo} key={null} />;
|
||||
} else {
|
||||
return <span {...foo} key={null} />;
|
||||
}
|
||||
}
|
||||
|
||||
App.getTrials = function(renderer, Root, data, isCompiled) {
|
||||
renderer.update(<Root x={false} className={"test"} />);
|
||||
return [["equivalence render", renderer.toJSON()]];
|
||||
};
|
||||
|
||||
if (this.__optimizeReactComponentTree) {
|
||||
__optimizeReactComponentTree(App, {
|
||||
firstRenderOnly: true,
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = App;
|
30
test/react/FirstRenderOnly/equivalence5.js
Normal file
30
test/react/FirstRenderOnly/equivalence5.js
Normal file
@ -0,0 +1,30 @@
|
||||
var React = require("react");
|
||||
|
||||
function App(props) {
|
||||
var foo = Object.assign({}, props);
|
||||
|
||||
if (props.x) {
|
||||
return [<span {...foo} key={null} />, <span {...foo} key={null} />];
|
||||
} else {
|
||||
return [<span {...foo} key={null} />, <span {...foo} key={null} />];
|
||||
}
|
||||
}
|
||||
|
||||
App.getTrials = function(renderer, Root, data, isCompiled) {
|
||||
if (isCompiled) {
|
||||
const [a, b] = Root({ x: false });
|
||||
if (a !== b) {
|
||||
throw new Error("Equivalence check failed");
|
||||
}
|
||||
}
|
||||
renderer.update(<Root x={false} className={"test"} />);
|
||||
return [["equivalence render", renderer.toJSON()]];
|
||||
};
|
||||
|
||||
if (this.__optimizeReactComponentTree) {
|
||||
__optimizeReactComponentTree(App, {
|
||||
firstRenderOnly: true,
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = App;
|
@ -1,5 +1,345 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Equivalence of snapshotted node 2: (JSX => JSX) 1`] = `
|
||||
ReactStatistics {
|
||||
"componentsEvaluated": 1,
|
||||
"evaluatedRootNodes": Array [
|
||||
Object {
|
||||
"children": Array [],
|
||||
"message": "",
|
||||
"name": "App",
|
||||
"status": "ROOT",
|
||||
},
|
||||
],
|
||||
"inlinedComponents": 0,
|
||||
"optimizedNestedClosures": 0,
|
||||
"optimizedTrees": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Equivalence of snapshotted node 2: (JSX => createElement) 1`] = `
|
||||
ReactStatistics {
|
||||
"componentsEvaluated": 1,
|
||||
"evaluatedRootNodes": Array [
|
||||
Object {
|
||||
"children": Array [],
|
||||
"message": "",
|
||||
"name": "App",
|
||||
"status": "ROOT",
|
||||
},
|
||||
],
|
||||
"inlinedComponents": 0,
|
||||
"optimizedNestedClosures": 0,
|
||||
"optimizedTrees": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Equivalence of snapshotted node 2: (createElement => JSX) 1`] = `
|
||||
ReactStatistics {
|
||||
"componentsEvaluated": 1,
|
||||
"evaluatedRootNodes": Array [
|
||||
Object {
|
||||
"children": Array [],
|
||||
"message": "",
|
||||
"name": "App",
|
||||
"status": "ROOT",
|
||||
},
|
||||
],
|
||||
"inlinedComponents": 0,
|
||||
"optimizedNestedClosures": 0,
|
||||
"optimizedTrees": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Equivalence of snapshotted node 2: (createElement => createElement) 1`] = `
|
||||
ReactStatistics {
|
||||
"componentsEvaluated": 1,
|
||||
"evaluatedRootNodes": Array [
|
||||
Object {
|
||||
"children": Array [],
|
||||
"message": "",
|
||||
"name": "App",
|
||||
"status": "ROOT",
|
||||
},
|
||||
],
|
||||
"inlinedComponents": 0,
|
||||
"optimizedNestedClosures": 0,
|
||||
"optimizedTrees": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Equivalence of snapshotted node 3: (JSX => JSX) 1`] = `
|
||||
ReactStatistics {
|
||||
"componentsEvaluated": 1,
|
||||
"evaluatedRootNodes": Array [
|
||||
Object {
|
||||
"children": Array [],
|
||||
"message": "",
|
||||
"name": "App",
|
||||
"status": "ROOT",
|
||||
},
|
||||
],
|
||||
"inlinedComponents": 0,
|
||||
"optimizedNestedClosures": 0,
|
||||
"optimizedTrees": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Equivalence of snapshotted node 3: (JSX => createElement) 1`] = `
|
||||
ReactStatistics {
|
||||
"componentsEvaluated": 1,
|
||||
"evaluatedRootNodes": Array [
|
||||
Object {
|
||||
"children": Array [],
|
||||
"message": "",
|
||||
"name": "App",
|
||||
"status": "ROOT",
|
||||
},
|
||||
],
|
||||
"inlinedComponents": 0,
|
||||
"optimizedNestedClosures": 0,
|
||||
"optimizedTrees": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Equivalence of snapshotted node 3: (createElement => JSX) 1`] = `
|
||||
ReactStatistics {
|
||||
"componentsEvaluated": 1,
|
||||
"evaluatedRootNodes": Array [
|
||||
Object {
|
||||
"children": Array [],
|
||||
"message": "",
|
||||
"name": "App",
|
||||
"status": "ROOT",
|
||||
},
|
||||
],
|
||||
"inlinedComponents": 0,
|
||||
"optimizedNestedClosures": 0,
|
||||
"optimizedTrees": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Equivalence of snapshotted node 3: (createElement => createElement) 1`] = `
|
||||
ReactStatistics {
|
||||
"componentsEvaluated": 1,
|
||||
"evaluatedRootNodes": Array [
|
||||
Object {
|
||||
"children": Array [],
|
||||
"message": "",
|
||||
"name": "App",
|
||||
"status": "ROOT",
|
||||
},
|
||||
],
|
||||
"inlinedComponents": 0,
|
||||
"optimizedNestedClosures": 0,
|
||||
"optimizedTrees": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Equivalence of snapshotted node 4: (JSX => JSX) 1`] = `
|
||||
ReactStatistics {
|
||||
"componentsEvaluated": 1,
|
||||
"evaluatedRootNodes": Array [
|
||||
Object {
|
||||
"children": Array [],
|
||||
"message": "",
|
||||
"name": "App",
|
||||
"status": "ROOT",
|
||||
},
|
||||
],
|
||||
"inlinedComponents": 0,
|
||||
"optimizedNestedClosures": 0,
|
||||
"optimizedTrees": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Equivalence of snapshotted node 4: (JSX => createElement) 1`] = `
|
||||
ReactStatistics {
|
||||
"componentsEvaluated": 1,
|
||||
"evaluatedRootNodes": Array [
|
||||
Object {
|
||||
"children": Array [],
|
||||
"message": "",
|
||||
"name": "App",
|
||||
"status": "ROOT",
|
||||
},
|
||||
],
|
||||
"inlinedComponents": 0,
|
||||
"optimizedNestedClosures": 0,
|
||||
"optimizedTrees": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Equivalence of snapshotted node 4: (createElement => JSX) 1`] = `
|
||||
ReactStatistics {
|
||||
"componentsEvaluated": 1,
|
||||
"evaluatedRootNodes": Array [
|
||||
Object {
|
||||
"children": Array [],
|
||||
"message": "",
|
||||
"name": "App",
|
||||
"status": "ROOT",
|
||||
},
|
||||
],
|
||||
"inlinedComponents": 0,
|
||||
"optimizedNestedClosures": 0,
|
||||
"optimizedTrees": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Equivalence of snapshotted node 4: (createElement => createElement) 1`] = `
|
||||
ReactStatistics {
|
||||
"componentsEvaluated": 1,
|
||||
"evaluatedRootNodes": Array [
|
||||
Object {
|
||||
"children": Array [],
|
||||
"message": "",
|
||||
"name": "App",
|
||||
"status": "ROOT",
|
||||
},
|
||||
],
|
||||
"inlinedComponents": 0,
|
||||
"optimizedNestedClosures": 0,
|
||||
"optimizedTrees": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Equivalence of snapshotted node 5: (JSX => JSX) 1`] = `
|
||||
ReactStatistics {
|
||||
"componentsEvaluated": 1,
|
||||
"evaluatedRootNodes": Array [
|
||||
Object {
|
||||
"children": Array [],
|
||||
"message": "",
|
||||
"name": "App",
|
||||
"status": "ROOT",
|
||||
},
|
||||
],
|
||||
"inlinedComponents": 0,
|
||||
"optimizedNestedClosures": 0,
|
||||
"optimizedTrees": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Equivalence of snapshotted node 5: (JSX => createElement) 1`] = `
|
||||
ReactStatistics {
|
||||
"componentsEvaluated": 1,
|
||||
"evaluatedRootNodes": Array [
|
||||
Object {
|
||||
"children": Array [],
|
||||
"message": "",
|
||||
"name": "App",
|
||||
"status": "ROOT",
|
||||
},
|
||||
],
|
||||
"inlinedComponents": 0,
|
||||
"optimizedNestedClosures": 0,
|
||||
"optimizedTrees": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Equivalence of snapshotted node 5: (createElement => JSX) 1`] = `
|
||||
ReactStatistics {
|
||||
"componentsEvaluated": 1,
|
||||
"evaluatedRootNodes": Array [
|
||||
Object {
|
||||
"children": Array [],
|
||||
"message": "",
|
||||
"name": "App",
|
||||
"status": "ROOT",
|
||||
},
|
||||
],
|
||||
"inlinedComponents": 0,
|
||||
"optimizedNestedClosures": 0,
|
||||
"optimizedTrees": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Equivalence of snapshotted node 5: (createElement => createElement) 1`] = `
|
||||
ReactStatistics {
|
||||
"componentsEvaluated": 1,
|
||||
"evaluatedRootNodes": Array [
|
||||
Object {
|
||||
"children": Array [],
|
||||
"message": "",
|
||||
"name": "App",
|
||||
"status": "ROOT",
|
||||
},
|
||||
],
|
||||
"inlinedComponents": 0,
|
||||
"optimizedNestedClosures": 0,
|
||||
"optimizedTrees": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Equivalence of snapshotted node: (JSX => JSX) 1`] = `
|
||||
ReactStatistics {
|
||||
"componentsEvaluated": 1,
|
||||
"evaluatedRootNodes": Array [
|
||||
Object {
|
||||
"children": Array [],
|
||||
"message": "",
|
||||
"name": "App",
|
||||
"status": "ROOT",
|
||||
},
|
||||
],
|
||||
"inlinedComponents": 0,
|
||||
"optimizedNestedClosures": 0,
|
||||
"optimizedTrees": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Equivalence of snapshotted node: (JSX => createElement) 1`] = `
|
||||
ReactStatistics {
|
||||
"componentsEvaluated": 1,
|
||||
"evaluatedRootNodes": Array [
|
||||
Object {
|
||||
"children": Array [],
|
||||
"message": "",
|
||||
"name": "App",
|
||||
"status": "ROOT",
|
||||
},
|
||||
],
|
||||
"inlinedComponents": 0,
|
||||
"optimizedNestedClosures": 0,
|
||||
"optimizedTrees": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Equivalence of snapshotted node: (createElement => JSX) 1`] = `
|
||||
ReactStatistics {
|
||||
"componentsEvaluated": 1,
|
||||
"evaluatedRootNodes": Array [
|
||||
Object {
|
||||
"children": Array [],
|
||||
"message": "",
|
||||
"name": "App",
|
||||
"status": "ROOT",
|
||||
},
|
||||
],
|
||||
"inlinedComponents": 0,
|
||||
"optimizedNestedClosures": 0,
|
||||
"optimizedTrees": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Equivalence of snapshotted node: (createElement => createElement) 1`] = `
|
||||
ReactStatistics {
|
||||
"componentsEvaluated": 1,
|
||||
"evaluatedRootNodes": Array [
|
||||
Object {
|
||||
"children": Array [],
|
||||
"message": "",
|
||||
"name": "App",
|
||||
"status": "ROOT",
|
||||
},
|
||||
],
|
||||
"inlinedComponents": 0,
|
||||
"optimizedNestedClosures": 0,
|
||||
"optimizedTrees": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`React Context 2: (JSX => JSX) 1`] = `
|
||||
ReactStatistics {
|
||||
"componentsEvaluated": 4,
|
||||
|
@ -289,8 +289,8 @@ function setupReactTests() {
|
||||
let { getTrials: getTrialsA, independent } = A;
|
||||
let { getTrials: getTrialsB } = B;
|
||||
// Run tests that assert the rendered output matches.
|
||||
let resultA = getTrialsA(rendererA, A, data);
|
||||
let resultB = independent ? getTrialsB(rendererB, B, data) : getTrialsA(rendererB, B, data);
|
||||
let resultA = getTrialsA(rendererA, A, data, false);
|
||||
let resultB = independent ? getTrialsB(rendererB, B, data, true) : getTrialsA(rendererB, B, data, false);
|
||||
|
||||
// The test has returned many values for us to check
|
||||
for (let i = 0; i < resultA.length; i++) {
|
||||
|
Loading…
Reference in New Issue
Block a user