Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d9393ee
Add Fragment fiber type
sebmarkbage Sep 13, 2016
e8c1cb4
Add Text node types
sebmarkbage Sep 14, 2016
d7322d8
Silence Fiber warning when the feature flag is on
sebmarkbage Sep 13, 2016
e05ab67
Fix MultiChild tests so they work with Fiber
sebmarkbage Sep 13, 2016
8c7409b
Add comment about bug in yields
sebmarkbage Sep 15, 2016
4ed67f1
Enable text updates in ReactNoop
sebmarkbage Sep 19, 2016
dff0faf
Fiber child reconciliation
sebmarkbage Sep 20, 2016
51f2bf9
Add index field to each fiber
sebmarkbage Sep 21, 2016
bcbceae
Don't track side-effects unless needed
sebmarkbage Sep 21, 2016
c49a91c
Fast path for create child
sebmarkbage Oct 4, 2016
be0acf8
Deletion tracking
sebmarkbage Oct 4, 2016
76725fe
Tag the fiber with the kind of side-effect that was applied to it
sebmarkbage Oct 4, 2016
86e854e
Append deletions to the effect list
sebmarkbage Oct 4, 2016
eabed69
Move child updates to use the reconciled effects
sebmarkbage Oct 5, 2016
31ca1e7
Remove beginWork shortcut
sebmarkbage Oct 6, 2016
0262e70
Reset effect list when we recompute children
sebmarkbage Oct 7, 2016
f3d7116
Always override priority level when visiting children
sebmarkbage Oct 7, 2016
40989f8
Call componentWillUnmount during deletion phase
sebmarkbage Oct 7, 2016
8360088
Fire componentDidMount/componentDidUpdate life-cycles
sebmarkbage Oct 7, 2016
48cf81c
Resolve ref callbacks
sebmarkbage Oct 7, 2016
8721ec1
Invoke all null ref calls before any new ref calls
sebmarkbage Oct 7, 2016
d9efde7
Fix resuming bug
sebmarkbage Oct 10, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Fix MultiChild tests so they work with Fiber
Dropped the unnecessary use of findDOMNode.
Dropped unnecessary arrow functions.
Math.random() -> id counter, since this used to be
non-deterministic which is not ideal for unit tests.

getOriginalKeys() used to rely on implementation details
to scan that the internal data structure maintained its
structure, however, since that is unobservable we don't
need to test the internal data structure itself. We're
already testing refs and dom structure which is the only
observable effect of the reorder.
  • Loading branch information
sebmarkbage committed Oct 17, 2016
commit e05ab67db284ccab5c3fc0a3a6078be7fef39cdc
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,10 @@

var React = require('React');
var ReactDOM = require('ReactDOM');
var ReactDOMComponentTree = require('ReactDOMComponentTree');
var ReactInstanceMap = require('ReactInstanceMap');

var stripEmptyValues = function(obj) {
var ret = {};
var name;
for (name in obj) {
for (var name in obj) {
if (!obj.hasOwnProperty(name)) {
continue;
}
Expand All @@ -30,31 +27,23 @@ var stripEmptyValues = function(obj) {
return ret;
};

/**
* Child key names are wrapped like '.$key:0'. We strip the extra chars out
* here. This relies on an implementation detail of the rendering system.
*/
var getOriginalKey = function(childName) {
var match = childName.match(/^\.\$([^.]+)$/);
expect(match).not.toBeNull();
return match[1];
};
var idCounter = 123;

/**
* Contains internal static internal state in order to test that updates to
* existing children won't reinitialize components, when moving children -
* reusing existing DOM/memory resources.
*/
class StatusDisplay extends React.Component {
state = {internalState: Math.random()};
state = {internalState: idCounter++};

getStatus = () => {
getStatus() {
return this.props.status;
};
}

getInternalState = () => {
getInternalState() {
return this.state.internalState;
};
}

componentDidMount() {
this.props.onFlush();
Expand All @@ -67,7 +56,7 @@ class StatusDisplay extends React.Component {
render() {
return (
<div>
{this.state.internalState}
{this.props.contentKey}
</div>
);
}
Expand All @@ -82,39 +71,29 @@ class FriendsStatusDisplay extends React.Component {
* Refs are not maintained in the rendered order, and neither is
* `this._renderedChildren` (surprisingly).
*/
getOriginalKeys = () => {
getOriginalKeys() {
var originalKeys = [];
// TODO: Update this to a better test that doesn't rely so much on internal
// implementation details.
var statusDisplays =
ReactInstanceMap.get(this)
._renderedComponent
._renderedChildren;
var name;
for (name in statusDisplays) {
var child = statusDisplays[name];
var isPresent = !!child;
if (isPresent) {
originalKeys[child._mountIndex] = getOriginalKey(name);
for (var key in this.props.usernameToStatus) {
if (this.props.usernameToStatus[key]) {
originalKeys.push(key);
}
}
return originalKeys;
};
}

/**
* Retrieves the rendered children in a nice format for comparing to the input
* `this.props.usernameToStatus`.
*/
getStatusDisplays = () => {
getStatusDisplays() {
var res = {};
var i;
var originalKeys = this.getOriginalKeys();
for (i = 0; i < originalKeys.length; i++) {
for (var i = 0; i < originalKeys.length; i++) {
var key = originalKeys[i];
res[key] = this.refs[key];
}
return res;
};
}

/**
* Verifies that by the time a child is flushed, the refs that appeared
Expand All @@ -123,29 +102,28 @@ class FriendsStatusDisplay extends React.Component {
* but our internal layer API depends on this assumption. We need to change
* it to be more declarative before making ref resolution indeterministic.
*/
verifyPreviousRefsResolved = (flushedKey) => {
var i;
verifyPreviousRefsResolved(flushedKey) {
var originalKeys = this.getOriginalKeys();
for (i = 0; i < originalKeys.length; i++) {
for (var i = 0; i < originalKeys.length; i++) {
var key = originalKeys[i];
if (key === flushedKey) {
// We are only interested in children up to the current key.
return;
}
expect(this.refs[key]).toBeTruthy();
}
};
}

render() {
var children = [];
var key;
for (key in this.props.usernameToStatus) {
for (var key in this.props.usernameToStatus) {
var status = this.props.usernameToStatus[key];
children.push(
!status ? null :
<StatusDisplay
key={key}
ref={key}
contentKey={key}
onFlush={this.verifyPreviousRefsResolved.bind(this, key)}
status={status}
/>
Expand Down Expand Up @@ -223,35 +201,33 @@ function verifyStatesPreserved(lastInternalStates, statusDisplays) {
* Verifies that the internal representation of a set of `renderedChildren`
* accurately reflects what is in the DOM.
*/
function verifyDomOrderingAccurate(parentInstance, statusDisplays) {
var containerNode = ReactDOM.findDOMNode(parentInstance);
function verifyDomOrderingAccurate(outerContainer, statusDisplays) {
var containerNode = outerContainer.firstChild;
var statusDisplayNodes = containerNode.childNodes;
var i;
var orderedDomIDs = [];
for (i = 0; i < statusDisplayNodes.length; i++) {
var inst = ReactDOMComponentTree.getInstanceFromNode(statusDisplayNodes[i]);
orderedDomIDs.push(inst._rootNodeID);
var orderedDomKeys = [];
for (var i = 0; i < statusDisplayNodes.length; i++) {
var contentKey = statusDisplayNodes[i].textContent;
orderedDomKeys.push(contentKey);
}

var orderedLogicalIDs = [];
var orderedLogicalKeys = [];
var username;
for (username in statusDisplays) {
if (!statusDisplays.hasOwnProperty(username)) {
continue;
}
var statusDisplay = statusDisplays[username];
orderedLogicalIDs.push(
ReactInstanceMap.get(statusDisplay)._renderedComponent._rootNodeID
orderedLogicalKeys.push(
statusDisplay.props.contentKey
);
}
expect(orderedDomIDs).toEqual(orderedLogicalIDs);
expect(orderedDomKeys).toEqual(orderedLogicalKeys);
}

/**
* Todo: Check that internal state is preserved across transitions
*/
function testPropsSequence(sequence) {
var i;
var container = document.createElement('div');
var parentInstance = ReactDOM.render(
<FriendsStatusDisplay {...sequence[0]} />,
Expand All @@ -261,15 +237,15 @@ function testPropsSequence(sequence) {
var lastInternalStates = getInternalStateByUserName(statusDisplays);
verifyStatuses(statusDisplays, sequence[0]);

for (i = 1; i < sequence.length; i++) {
for (var i = 1; i < sequence.length; i++) {
ReactDOM.render(
<FriendsStatusDisplay {...sequence[i]} />,
container
);
statusDisplays = parentInstance.getStatusDisplays();
verifyStatuses(statusDisplays, sequence[i]);
verifyStatesPreserved(lastInternalStates, statusDisplays);
verifyDomOrderingAccurate(parentInstance, statusDisplays);
verifyDomOrderingAccurate(container, statusDisplays);

lastInternalStates = getInternalStateByUserName(statusDisplays);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,17 @@ var testAllPermutations = function(testCases) {
var expectedResultAfterUpdate = testCases[j + 1];

var container = document.createElement('div');
var d = ReactDOM.render(<div>{renderWithChildren}</div>, container);
expectChildren(d, expectedResultAfterRender);
ReactDOM.render(<div>{renderWithChildren}</div>, container);
expectChildren(container, expectedResultAfterRender);

d = ReactDOM.render(<div>{updateWithChildren}</div>, container);
expectChildren(d, expectedResultAfterUpdate);
ReactDOM.render(<div>{updateWithChildren}</div>, container);
expectChildren(container, expectedResultAfterUpdate);
}
}
};

var expectChildren = function(d, children) {
var outerNode = ReactDOM.findDOMNode(d);
var expectChildren = function(container, children) {
var outerNode = container.firstChild;
var textNode;
if (typeof children === 'string') {
textNode = outerNode.firstChild;
Expand Down