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
…15030)

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 authored Mar 11, 2019
1 parent bc8bd24 commit 6a4a261
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 6a4a261

Please sign in to comment.