Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run persistent mode tests in CI #15029

Merged
merged 9 commits into from
Mar 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
"postinstall": "node node_modules/fbjs-scripts/node/check-dev-engines.js package.json && node ./scripts/flow/createFlowConfigs.js",
"debug-test": "cross-env NODE_ENV=development node --inspect-brk node_modules/.bin/jest --config ./scripts/jest/config.source.js --runInBand",
"test": "cross-env NODE_ENV=development jest --config ./scripts/jest/config.source.js",
"test-persistent": "cross-env NODE_ENV=development jest --config ./scripts/jest/config.source-persistent.js",
"test-fire": "cross-env NODE_ENV=development jest --config ./scripts/jest/config.source-fire.js",
"test-prod": "cross-env NODE_ENV=production jest --config ./scripts/jest/config.source.js",
"test-fire-prod": "cross-env NODE_ENV=production jest --config ./scripts/jest/config.source-fire.js",
Expand Down
27 changes: 0 additions & 27 deletions packages/react-native-renderer/src/ReactFabricHostConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -387,25 +387,6 @@ export function cloneHiddenInstance(
};
}

export function cloneUnhiddenInstance(
instance: Instance,
type: string,
props: Props,
internalInstanceHandle: Object,
): Instance {
const viewConfig = instance.canonical.viewConfig;
const node = instance.node;
const updatePayload = diff(
{...props, style: [props.style, {display: 'none'}]},
props,
viewConfig.validAttributes,
);
return {
node: cloneNodeWithNewProps(node, updatePayload),
canonical: instance.canonical,
};
}

export function cloneHiddenTextInstance(
instance: Instance,
text: string,
Expand All @@ -414,14 +395,6 @@ export function cloneHiddenTextInstance(
throw new Error('Not yet implemented.');
}

export function cloneUnhiddenTextInstance(
instance: Instance,
text: string,
internalInstanceHandle: Object,
): TextInstance {
throw new Error('Not yet implemented.');
}

export function createContainerChildSet(container: Container): ChildSet {
return createChildNodeSet(container);
}
Expand Down
43 changes: 0 additions & 43 deletions packages/react-noop-renderer/src/createReactNoop.js
Original file line number Diff line number Diff line change
Expand Up @@ -486,26 +486,6 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
return clone;
},

cloneUnhiddenInstance(
instance: Instance,
type: string,
props: Props,
internalInstanceHandle: Object,
): Instance {
const clone = cloneInstance(
instance,
null,
type,
props,
props,
internalInstanceHandle,
true,
null,
);
clone.hidden = props.hidden === true;
return clone;
},

cloneHiddenTextInstance(
instance: TextInstance,
text: string,
Expand All @@ -528,29 +508,6 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
});
return clone;
},

cloneUnhiddenTextInstance(
instance: TextInstance,
text: string,
internalInstanceHandle: Object,
): TextInstance {
const clone = {
text: instance.text,
id: instanceCounter++,
hidden: false,
context: instance.context,
};
// Hide from unit tests
Object.defineProperty(clone, 'id', {
value: clone.id,
enumerable: false,
});
Object.defineProperty(clone, 'context', {
value: clone.context,
enumerable: false,
});
return clone;
},
};

const NoopRenderer = reconciler(hostConfig);
Expand Down
128 changes: 59 additions & 69 deletions packages/react-reconciler/src/ReactFiberCompleteWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,7 @@ import {
supportsPersistence,
cloneInstance,
cloneHiddenInstance,
cloneUnhiddenInstance,
cloneHiddenTextInstance,
cloneUnhiddenTextInstance,
createContainerChildSet,
appendChildToContainerChildSet,
finalizeContainerChildren,
Expand Down Expand Up @@ -209,31 +207,19 @@ if (supportsMutation) {
// eslint-disable-next-line no-labels
branches: if (node.tag === HostComponent) {
let instance = node.stateNode;
if (needsVisibilityToggle) {
if (needsVisibilityToggle && isHidden) {
// This child is inside a timed out tree. Hide it.
const props = node.memoizedProps;
const type = node.type;
if (isHidden) {
// This child is inside a timed out tree. Hide it.
instance = cloneHiddenInstance(instance, type, props, node);
} else {
// This child was previously inside a timed out tree. If it was not
// updated during this render, it may need to be unhidden. Clone
// again to be sure.
instance = cloneUnhiddenInstance(instance, type, props, node);
}
node.stateNode = instance;
instance = cloneHiddenInstance(instance, type, props, node);
}
appendInitialChild(parent, instance);
} else if (node.tag === HostText) {
let instance = node.stateNode;
if (needsVisibilityToggle) {
if (needsVisibilityToggle && isHidden) {
// This child is inside a timed out tree. Hide it.
const text = node.memoizedProps;
if (isHidden) {
instance = cloneHiddenTextInstance(instance, text, node);
} else {
instance = cloneUnhiddenTextInstance(instance, text, node);
}
node.stateNode = instance;
instance = cloneHiddenTextInstance(instance, text, node);
}
appendInitialChild(parent, instance);
} else if (node.tag === HostPortal) {
Expand All @@ -247,15 +233,22 @@ if (supportsMutation) {
if (newIsHidden) {
const primaryChildParent = node.child;
if (primaryChildParent !== null) {
appendAllChildren(parent, primaryChildParent, true, newIsHidden);
node = primaryChildParent.sibling;
continue;
if (primaryChildParent.child !== null) {
primaryChildParent.child.return = primaryChildParent;
appendAllChildren(
parent,
primaryChildParent,
true,
newIsHidden,
);
}
const fallbackChildParent = primaryChildParent.sibling;
if (fallbackChildParent !== null) {
fallbackChildParent.return = node;
node = fallbackChildParent;
continue;
}
}
} else {
const primaryChildParent = node;
appendAllChildren(parent, primaryChildParent, true, newIsHidden);
// eslint-disable-next-line no-labels
break branches;
}
}
if (node.child !== null) {
Expand Down Expand Up @@ -299,31 +292,19 @@ if (supportsMutation) {
// eslint-disable-next-line no-labels
branches: if (node.tag === HostComponent) {
let instance = node.stateNode;
if (needsVisibilityToggle) {
if (needsVisibilityToggle && isHidden) {
// This child is inside a timed out tree. Hide it.
const props = node.memoizedProps;
const type = node.type;
if (isHidden) {
// This child is inside a timed out tree. Hide it.
instance = cloneHiddenInstance(instance, type, props, node);
} else {
// This child was previously inside a timed out tree. If it was not
// updated during this render, it may need to be unhidden. Clone
// again to be sure.
instance = cloneUnhiddenInstance(instance, type, props, node);
}
node.stateNode = instance;
instance = cloneHiddenInstance(instance, type, props, node);
}
appendChildToContainerChildSet(containerChildSet, instance);
} else if (node.tag === HostText) {
let instance = node.stateNode;
if (needsVisibilityToggle) {
if (needsVisibilityToggle && isHidden) {
// This child is inside a timed out tree. Hide it.
const text = node.memoizedProps;
if (isHidden) {
instance = cloneHiddenTextInstance(instance, text, node);
} else {
instance = cloneUnhiddenTextInstance(instance, text, node);
}
node.stateNode = instance;
instance = cloneHiddenTextInstance(instance, text, node);
}
appendChildToContainerChildSet(containerChildSet, instance);
} else if (node.tag === HostPortal) {
Expand All @@ -337,25 +318,22 @@ if (supportsMutation) {
if (newIsHidden) {
const primaryChildParent = node.child;
if (primaryChildParent !== null) {
appendAllChildrenToContainer(
containerChildSet,
primaryChildParent,
true,
newIsHidden,
);
node = primaryChildParent.sibling;
continue;
if (primaryChildParent.child !== null) {
primaryChildParent.child.return = primaryChildParent;
appendAllChildrenToContainer(
containerChildSet,
primaryChildParent,
true,
newIsHidden,
);
}
const fallbackChildParent = primaryChildParent.sibling;
if (fallbackChildParent !== null) {
fallbackChildParent.return = node;
node = fallbackChildParent;
continue;
}
}
} else {
const primaryChildParent = node;
appendAllChildrenToContainer(
containerChildSet,
primaryChildParent,
true,
newIsHidden,
);
// eslint-disable-next-line no-labels
break branches;
}
}
if (node.child !== null) {
Expand Down Expand Up @@ -714,11 +692,23 @@ function completeWork(
}
}

if (nextDidTimeout || prevDidTimeout) {
// If the children are hidden, or if they were previous hidden, schedule
// an effect to toggle their visibility. This is also used to attach a
// retry listener to the promise.
workInProgress.effectTag |= Update;
if (supportsPersistence) {
if (nextDidTimeout) {
// If this boundary just timed out, schedule an effect to attach a
// retry listener to the proimse. This flag is also used to hide the
// primary children.
workInProgress.effectTag |= Update;
}
}
if (supportsMutation) {
if (nextDidTimeout || prevDidTimeout) {
// If this boundary just timed out, schedule an effect to attach a
// retry listener to the proimse. This flag is also used to hide the
// primary children. In mutation mode, we also need the flag to
// *unhide* children that were previously hidden, so check if the
// is currently timed out, too.
workInProgress.effectTag |= Update;
}
}
break;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
let React;
let Suspense;
let ReactTestRenderer;
let ReactNoop;
let Scheduler;
let ReactFeatureFlags;
let Random;
Expand All @@ -26,7 +26,7 @@ describe('ReactSuspenseFuzz', () => {
ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
React = require('react');
Suspense = React.Suspense;
ReactTestRenderer = require('react-test-renderer');
ReactNoop = require('react-noop-renderer');
Scheduler = require('scheduler');
Random = require('random-seed');
});
Expand Down Expand Up @@ -143,54 +143,49 @@ describe('ReactSuspenseFuzz', () => {
return resolvedText;
}

function renderToRoot(
root,
children,
{shouldSuspend} = {shouldSuspend: true},
) {
root.update(
<ShouldSuspendContext.Provider value={shouldSuspend}>
{children}
</ShouldSuspendContext.Provider>,
);
function resolveAllTasks() {
Scheduler.unstable_flushWithoutYielding();

let elapsedTime = 0;
while (pendingTasks && pendingTasks.size > 0) {
if ((elapsedTime += 1000) > 1000000) {
throw new Error('Something did not resolve properly.');
}
ReactTestRenderer.act(() => jest.advanceTimersByTime(1000));
ReactNoop.act(() => jest.advanceTimersByTime(1000));
Scheduler.unstable_flushWithoutYielding();
}

return root.toJSON();
}

function testResolvedOutput(unwrappedChildren) {
const children = (
<Suspense fallback="Loading...">{unwrappedChildren}</Suspense>
);

const expectedRoot = ReactTestRenderer.create(null);
const expectedOutput = renderToRoot(expectedRoot, children, {
shouldSuspend: false,
});
expectedRoot.unmount();
resetCache();
ReactNoop.renderToRootWithID(
<ShouldSuspendContext.Provider value={false}>
{children}
</ShouldSuspendContext.Provider>,
'expected',
);
resolveAllTasks();
const expectedOutput = ReactNoop.getChildrenAsJSX('expected');
ReactNoop.renderToRootWithID(null, 'expected');
Scheduler.unstable_flushWithoutYielding();

resetCache();
const syncRoot = ReactTestRenderer.create(null);
const syncOutput = renderToRoot(syncRoot, children);
ReactNoop.renderLegacySyncRoot(children);
resolveAllTasks();
const syncOutput = ReactNoop.getChildrenAsJSX();
expect(syncOutput).toEqual(expectedOutput);
syncRoot.unmount();
ReactNoop.renderLegacySyncRoot(null);

resetCache();
const concurrentRoot = ReactTestRenderer.create(null, {
unstable_isConcurrent: true,
});
const concurrentOutput = renderToRoot(concurrentRoot, children);
ReactNoop.renderToRootWithID(children, 'concurrent');
Scheduler.unstable_flushWithoutYielding();
resolveAllTasks();
const concurrentOutput = ReactNoop.getChildrenAsJSX('concurrent');
expect(concurrentOutput).toEqual(expectedOutput);
concurrentRoot.unmount();
ReactNoop.renderToRootWithID(null, 'concurrent');
Scheduler.unstable_flushWithoutYielding();
}

Expand Down
Loading