Skip to content

Commit

Permalink
Test suspended children are hidden before layout in persistent mode
Browse files Browse the repository at this point in the history
Refs behave differently in persistent mode, so instead of a ref, the
persistent mode version of this test asserts on the output of the
host tree.
  • Loading branch information
acdlite committed Mar 11, 2019
1 parent bc8bd24 commit 71fcff1
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 6 deletions.
37 changes: 34 additions & 3 deletions packages/react-noop-renderer/src/createReactNoop.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type Thenable = {
type Container = {
rootID: string,
children: Array<Instance | TextInstance>,
pendingChildren: Array<Instance | TextInstance>,
};
type Props = {prop: any, hidden: boolean, children?: mixed};
type Instance = {|
Expand Down Expand Up @@ -457,7 +458,9 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
finalizeContainerChildren(
container: Container,
newChildren: Array<Instance | TextInstance>,
): void {},
): void {
container.pendingChildren = newChildren;
},

replaceContainerChildren(
container: Container,
Expand Down Expand Up @@ -581,13 +584,22 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
}
},

getPendingChildren(rootID: string = DEFAULT_ROOT_ID) {
const container = rootContainers.get(rootID);
if (container) {
return container.pendingChildren;
} else {
return null;
}
},

getOrCreateRootContainer(
rootID: string = DEFAULT_ROOT_ID,
isConcurrent: boolean = false,
) {
let root = roots.get(rootID);
if (!root) {
const container = {rootID: rootID, children: []};
const container = {rootID: rootID, pendingChildren: [], children: []};
rootContainers.set(rootID, container);
root = NoopRenderer.createContainer(container, isConcurrent, false);
roots.set(rootID, root);
Expand All @@ -614,6 +626,25 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
return children;
},

getPendingChildrenAsJSX(rootID: string = DEFAULT_ROOT_ID) {
const children = childToJSX(ReactNoop.getPendingChildren(rootID), null);
if (children === null) {
return null;
}
if (Array.isArray(children)) {
return {
$$typeof: REACT_ELEMENT_TYPE,
type: REACT_FRAGMENT_TYPE,
key: null,
ref: null,
props: {children},
_owner: null,
_store: __DEV__ ? {} : undefined,
};
}
return children;
},

createPortal(
children: ReactNodeList,
container: Container,
Expand Down Expand Up @@ -778,7 +809,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
// Trick to flush passive effects without exposing an internal API:
// Create a throwaway root and schedule a dummy update on it.
const rootID = 'bloopandthenmoreletterstoavoidaconflict';
const container = {rootID: rootID, children: []};
const container = {rootID: rootID, pendingChildren: [], children: []};
rootContainers.set(rootID, container);
const root = NoopRenderer.createContainer(container, true, false);
NoopRenderer.updateContainer(null, root, null, null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1387,9 +1387,50 @@ describe('ReactSuspenseWithNoopRenderer', () => {
expect(ReactNoop.getChildren()).toEqual([span('Hi')]);
});

if (!global.__PERSISTENT__) {
// TODO: Write persistent version of this test
it('toggles visibility during the mutation phase', async () => {
if (global.__PERSISTENT__) {
it('hides/unhides suspended children before layout effects fire (persistent)', async () => {
const {useRef, useLayoutEffect} = React;

function Parent() {
const child = useRef(null);

useLayoutEffect(() => {
Scheduler.yieldValue(ReactNoop.getPendingChildrenAsJSX());
});

return (
<span ref={child} hidden={false}>
<AsyncText ms={1000} text="Hi" />
</span>
);
}

function App(props) {
return (
<Suspense fallback={<Text text="Loading..." />}>
<Parent />
</Suspense>
);
}

ReactNoop.renderLegacySyncRoot(<App middleText="B" />);

expect(Scheduler).toHaveYielded([
'Suspend! [Hi]',
'Loading...',
// The child should have already been hidden
<React.Fragment>
<span hidden={true} />
<span prop="Loading..." />
</React.Fragment>,
]);

await advanceTimers(1000);

expect(Scheduler).toHaveYielded(['Promise resolved [Hi]', 'Hi']);
});
} else {
it('hides/unhides suspended children before layout effects fire (mutation)', async () => {
const {useRef, useLayoutEffect} = React;

function Parent() {
Expand Down

0 comments on commit 71fcff1

Please sign in to comment.