'use strict';
let React;
let Scheduler;
let ReactNoop;
let act;
let assertLog;
describe('ReactFiberRefs', () => {
beforeEach(() => {
jest.resetModules();
React = require('react');
Scheduler = require('scheduler');
ReactNoop = require('react-noop-renderer');
act = require('internal-test-utils').act;
assertLog = require('internal-test-utils').assertLog;
});
test('ref is attached even if there are no other updates (class)', async () => {
let component;
class Component extends React.Component {
shouldComponentUpdate() {
return false;
}
render() {
Scheduler.log('Render');
component = this;
return 'Hi';
}
}
const ref1 = React.createRef();
const ref2 = React.createRef();
const root = ReactNoop.createRoot();
await act(() => root.render(<Component ref={ref1} />));
assertLog(['Render']);
expect(root).toMatchRenderedOutput('Hi');
expect(ref1.current).toBe(component);
expect(ref2.current).toBe(null);
await act(() => root.render(<Component ref={ref2} />));
assertLog([]);
expect(root).toMatchRenderedOutput('Hi');
expect(ref1.current).toBe(null);
expect(ref2.current).toBe(component);
});
test('ref is attached even if there are no other updates (host component)', async () => {
const ref1 = React.createRef();
const ref2 = React.createRef();
const root = ReactNoop.createRoot();
await act(() => root.render(<div ref={ref1}>Hi</div>));
expect(root).toMatchRenderedOutput(<div>Hi</div>);
expect(ref1.current).not.toBe(null);
expect(ref2.current).toBe(null);
await act(() => root.render(<div ref={ref2}>Hi</div>));
expect(root).toMatchRenderedOutput(<div>Hi</div>);
expect(ref1.current).toBe(null);
expect(ref2.current).not.toBe(null);
});
test('string ref props are converted to function refs', async () => {
let refProp;
function Child({ref}) {
refProp = ref;
return <div ref={ref} />;
}
let owner;
class Owner extends React.Component {
render() {
owner = this;
return <Child ref="child" />;
}
}
const root = ReactNoop.createRoot();
await act(() => root.render(<Owner />));
expect(typeof refProp === 'function').toBe(true);
expect(owner.refs.child.type).toBe('div');
});
test('throw if a string ref is passed to a ref-receiving component', async () => {
let refProp;
function Child({ref}) {
refProp = ref;
return <div ref={ref} />;
}
class Owner extends React.Component {
render() {
return <Child ref="child" />;
}
}
const root = ReactNoop.createRoot();
await expect(act(() => root.render(<Owner />))).rejects.toThrow(
'Expected ref to be a function',
);
expect(refProp).toBe('child');
});
});