Assert that unmounted instances are in the tree until purged

This commit is contained in:
Dan Abramov
2016-04-24 01:53:53 +01:00
parent 829558b8b0
commit 9f16003e69
2 changed files with 106 additions and 17 deletions
@@ -119,7 +119,7 @@ var ReactComponentTreeDevtool = {
unmountedContainerIDs.push(nativeContainerID);
},
purgeComponentsFromUnmountedContainers() {
purgeUnmountedComponents() {
var unmountedIDs = Object.keys(tree).filter(id =>
unmountedContainerIDs.indexOf(tree[id].nativeContainerID) !== -1
);
@@ -42,34 +42,43 @@ describe('ReactComponentTreeDevtool', () => {
.map(ReactComponentTreeDevtool.getDisplayName);
}
function getTree(rootID, includeOwner = false, expectedParentID = null) {
function getTree(rootID, options = {}) {
var {
includeOwnerDisplayName = false,
includeParentDisplayName = false,
expectedParentID = null,
} = options;
var result = {
isComposite: ReactComponentTreeDevtool.isComposite(rootID),
displayName: ReactComponentTreeDevtool.getDisplayName(rootID),
};
var ownerID = ReactComponentTreeDevtool.getOwnerID(rootID);
var parentID = ReactComponentTreeDevtool.getParentID(rootID);
expect(parentID).toBe(expectedParentID);
if (includeParentDisplayName && parentID) {
result.parentDisplayName = ReactComponentTreeDevtool.getDisplayName(parentID);
}
if (includeOwnerDisplayName && ownerID) {
result.ownerDisplayName = ReactComponentTreeDevtool.getDisplayName(ownerID);
}
var childIDs = ReactComponentTreeDevtool.getChildIDs(rootID);
var text = ReactComponentTreeDevtool.getText(rootID);
if (text != null) {
result.text = text;
} else {
result.children = childIDs.map(childID =>
getTree(childID, includeOwner, rootID)
getTree(childID, {...options, expectedParentID: rootID })
);
}
var ownerID = ReactComponentTreeDevtool.getOwnerID(rootID);
if (includeOwner && ownerID) {
result.ownerDisplayName = ReactComponentTreeDevtool.getDisplayName(ownerID);
}
return result;
}
function assertTreeMatches(pairs, includeOwner) {
function assertTreeMatches(pairs, options) {
if (!Array.isArray(pairs[0])) {
pairs = [pairs];
}
@@ -85,23 +94,31 @@ describe('ReactComponentTreeDevtool', () => {
}
}
function getActualTree() {
return getTree(rootInstance._debugID, options).children[0];
}
pairs.forEach(([element, expectedTree]) => {
currentElement = element;
ReactDOM.render(<Wrapper />, node);
expect(
getTree(rootInstance._debugID, includeOwner).children[0]
).toEqual(expectedTree);
expect(getActualTree()).toEqual(expectedTree);
});
ReactDOM.unmountComponentAtNode(node);
var lastExpectedTree = pairs[pairs.length - 1][1];
expect(getActualTree()).toEqual(lastExpectedTree);
ReactComponentTreeDevtool.purgeUnmountedComponents();
expect(getActualTree()).toBe(undefined);
expect(getRegisteredDisplayNames()).toEqual([]);
pairs.forEach(([element, expectedTree]) => {
currentElement = element;
ReactDOMServer.renderToString(<Wrapper />);
expect(
getTree(rootInstance._debugID, includeOwner).children[0]
).toEqual(expectedTree);
ReactComponentTreeDevtool.purgeComponentsFromUnmountedContainers();
expect(getActualTree()).toEqual(expectedTree);
ReactComponentTreeDevtool.purgeUnmountedComponents();
expect(getActualTree()).toBe(undefined);
expect(getRegisteredDisplayNames()).toEqual([]);
});
}
@@ -1820,7 +1837,77 @@ describe('ReactComponentTreeDevtool', () => {
}],
}],
};
assertTreeMatches([element, tree], true);
assertTreeMatches([element, tree], {includeOwnerDisplayName: true});
});
it.only('preserves unmounted components until purge', () => {
var node = document.createElement('div');
var renderBar = true;
var fooInstance;
var barInstance;
class Foo extends React.Component {
render() {
fooInstance = ReactInstanceMap.get(this);
return renderBar ? <Bar /> : null;
}
}
class Bar extends React.Component {
render() {
barInstance = ReactInstanceMap.get(this);
return null;
}
}
ReactDOM.render(<Foo />, node);
expect(
getTree(barInstance._debugID, {
includeParentDisplayName: true,
expectedParentID: fooInstance._debugID
})
).toEqual({
isComposite: true,
displayName: 'Bar',
parentDisplayName: 'Foo',
children: [],
});
renderBar = false;
ReactDOM.render(<Foo />, node);
expect(
getTree(barInstance._debugID, {
includeParentDisplayName: true,
expectedParentID: fooInstance._debugID
})
).toEqual({
isComposite: true,
displayName: 'Bar',
parentDisplayName: 'Foo',
children: [],
});
ReactDOM.unmountComponentAtNode(node);
expect(
getTree(barInstance._debugID, {
includeParentDisplayName: true,
expectedParentID: fooInstance._debugID,
})
).toEqual({
isComposite: true,
displayName: 'Bar',
parentDisplayName: 'Foo',
children: [],
});
ReactComponentTreeDevtool.purgeUnmountedComponents();
expect(
getTree(barInstance._debugID, {includeParentDisplayName: true})
).toEqual({
isComposite: false,
displayName: 'Unknown',
children: [],
});
});
it('ignores top-level wrapper', () => {
@@ -1830,6 +1917,8 @@ describe('ReactComponentTreeDevtool', () => {
ReactDOM.render(<div className="b" />, node);
expect(getRegisteredDisplayNames()).toEqual(['div']);
ReactDOM.unmountComponentAtNode(node);
expect(getRegisteredDisplayNames()).toEqual(['div']);
ReactComponentTreeDevtool.purgeUnmountedComponents();
expect(getRegisteredDisplayNames()).toEqual([]);
});
});