it('must reject update if selection is not on an edge', () => { var helloBlock = getHelloBlock(); var props = getProps(helloBlock); var container = document.createElement('div'); ReactDOM.render( <DraftEditorBlock {...props} />, container ); expect(mockLeafRender.mock.calls.length).toBe(1); // Move selection state to some other block. var nonEdgeSelection = props.selection.merge({ anchorKey: 'z', focusKey: 'z', }); var newProps = {...props, selection: nonEdgeSelection}; // Render again with selection now moved elsewhere and the contents // unchanged. ReactDOM.render( <DraftEditorBlock {...newProps} />, container ); // No new leaf renders. expect(mockLeafRender.mock.calls.length).toBe(1); });
it('must allow update when `block` has changed', () => { var helloBlock = getHelloBlock(); var props = getProps(helloBlock); var container = document.createElement('div'); ReactDOM.render( <DraftEditorBlock {...props} />, container ); expect(mockLeafRender.mock.calls.length).toBe(1); var updatedHelloBlock = helloBlock.set('text', 'hxllo'); var nextProps = getProps(updatedHelloBlock); expect(updatedHelloBlock).not.toBe(helloBlock); expect(props.block).not.toBe(nextProps.block); ReactDOM.render( <DraftEditorBlock {...nextProps} />, container ); expect(mockLeafRender.mock.calls.length).toBe(2); });
it('should reorder keyed text nodes', function() { spyOn(console, 'error'); var container = document.createElement('div'); ReactDOM.render( <div>{new Map([['a', 'alpha'], ['b', 'beta']])}</div>, container ); var childNodes = container.firstChild.childNodes; var alpha1 = childNodes[0]; var alpha2 = childNodes[1]; var alpha3 = childNodes[2]; var beta1 = childNodes[3]; var beta2 = childNodes[4]; var beta3 = childNodes[5]; ReactDOM.render( <div>{new Map([['b', 'beta'], ['a', 'alpha']])}</div>, container ); childNodes = container.firstChild.childNodes; expect(childNodes[0]).toBe(beta1); expect(childNodes[1]).toBe(beta2); expect(childNodes[2]).toBe(beta3); expect(childNodes[3]).toBe(alpha1); expect(childNodes[4]).toBe(alpha2); expect(childNodes[5]).toBe(alpha3); // Using Maps as children gives a single warning expect(console.error.calls.count()).toBe(1); });
it('should destroy a react root upon request', function() { var mainContainerDiv = document.createElement('div'); document.body.appendChild(mainContainerDiv); var instanceOne = ( <div className="firstReactDiv"> </div> ); var firstRootDiv = document.createElement('div'); mainContainerDiv.appendChild(firstRootDiv); ReactDOM.render(instanceOne, firstRootDiv); var instanceTwo = ( <div className="secondReactDiv"> </div> ); var secondRootDiv = document.createElement('div'); mainContainerDiv.appendChild(secondRootDiv); ReactDOM.render(instanceTwo, secondRootDiv); // Test that two react roots are rendered in isolation expect(firstRootDiv.firstChild.className).toBe('firstReactDiv'); expect(secondRootDiv.firstChild.className).toBe('secondReactDiv'); // Test that after unmounting each, they are no longer in the document. ReactDOM.unmountComponentAtNode(firstRootDiv); expect(firstRootDiv.firstChild).toBeNull(); ReactDOM.unmountComponentAtNode(secondRootDiv); expect(secondRootDiv.firstChild).toBeNull(); });
it('should not crash in node cache when unmounting', function() { var Component = React.createClass({ render: function() { // Add refs to some nodes so that they get traversed and cached return ( <div ref="a"> <div ref="b">b</div> {this.props.showC && <div>c</div>} </div> ); }, }); var container = document.createElement('container'); ReactDOM.render(<div><Component showC={false} /></div>, container); // Right now, A and B are in the cache. When we add C, it won't get added to // the cache (assuming markup-string mode). ReactDOM.render(<div><Component showC={true} /></div>, container); // Remove A, B, and C. Unmounting C shouldn't cause B to get recached. ReactDOM.render(<div></div>, container); // Add them back -- this shouldn't cause a cached node collision. ReactDOM.render(<div><Component showC={true} /></div>, container); ReactDOM.unmountComponentAtNode(container); });
it('findDOMNode should find dom element after an update from null', () => { function Bar({ flag }) { if (flag) { return <span>A</span>; } return null; } class MyNode extends React.Component { render() { return <Bar flag={this.props.flag} />; } } var container = document.createElement('div'); var myNodeA = ReactDOM.render(<MyNode />, container); var a = ReactDOM.findDOMNode(myNodeA); expect(a).toBe(null); var myNodeB = ReactDOM.render(<MyNode flag={true} />, container); expect(myNodeA === myNodeB).toBe(true); var b = ReactDOM.findDOMNode(myNodeB); expect(b.tagName).toBe('SPAN'); });
it('should reuse markup if rendering to the same target twice', function() { var container = document.createElement('container'); var instance1 = ReactDOM.render(<div />, container); var instance2 = ReactDOM.render(<div />, container); expect(instance1 === instance2).toBe(true); });
it('should reset internal state if removed then readded', function() { // Test basics. var props = { usernameToStatus: { jcw: 'jcwStatus', }, }; var container = document.createElement('div'); var parentInstance = ReactDOM.render( <FriendsStatusDisplay {...props} />, container ); var statusDisplays = parentInstance.getStatusDisplays(); var startingInternalState = statusDisplays.jcw.getInternalState(); // Now remove the child. ReactDOM.render( <FriendsStatusDisplay />, container ); statusDisplays = parentInstance.getStatusDisplays(); expect(statusDisplays.jcw).toBeFalsy(); // Now reset the props that cause there to be a child ReactDOM.render( <FriendsStatusDisplay {...props} />, container ); statusDisplays = parentInstance.getStatusDisplays(); expect(statusDisplays.jcw).toBeTruthy(); expect(statusDisplays.jcw.getInternalState()) .toNotBe(startingInternalState); });
value: function() { shadowRoot = this.createShadowRoot(); ReactDOM.render(<div>Hi, from within a WC!</div>, shadowRoot); expect(shadowRoot.firstChild.tagName).toBe('DIV'); ReactDOM.render(<span>Hi, from within a WC!</span>, shadowRoot); expect(shadowRoot.firstChild.tagName).toBe('SPAN'); },
function testPropsSequenceWithPreparedChildren(sequence, prepareChildren) { var container = document.createElement('div'); var parentInstance = ReactDOM.render( <FriendsStatusDisplay {...sequence[0]} prepareChildren={prepareChildren} />, container ); var statusDisplays = parentInstance.getStatusDisplays(); var lastInternalStates = getInternalStateByUserName(statusDisplays); verifyStatuses(statusDisplays, sequence[0]); for (var i = 1; i < sequence.length; i++) { ReactDOM.render( <FriendsStatusDisplay {...sequence[i]} prepareChildren={prepareChildren} />, container ); statusDisplays = parentInstance.getStatusDisplays(); verifyStatuses(statusDisplays, sequence[i]); verifyStatesPreserved(lastInternalStates, statusDisplays); verifyDomOrderingAccurate(container, statusDisplays); lastInternalStates = getInternalStateByUserName(statusDisplays); } }
test('must allow update when `tree` has changed', () => { const helloBlock = getHelloBlock(); const props = getProps(helloBlock); const container = document.createElement('div'); ReactDOM.render(<DraftEditorBlock {...props} />, container); expect(mockLeafRender.mock.calls.length).toMatchSnapshot(); mockGetDecorations.mockReturnValue( Immutable.List.of('x', 'x', null, null, null), ); const decorator = new Decorator(); const newTree = BlockTree.generate( ContentState.createFromText(helloBlock.getText()), helloBlock, decorator, ); const nextProps = {...props, tree: newTree, decorator}; expect(props.tree !== nextProps.tree).toMatchSnapshot(); ReactDOM.render(<DraftEditorBlock {...nextProps} />, container); expect(mockLeafRender.mock.calls.length).toMatchSnapshot(); });
it('must allow update when `tree` has changed', () => { var helloBlock = getHelloBlock(); var props = getProps(helloBlock); var container = document.createElement('div'); ReactDOM.render( <DraftEditorBlock {...props} />, container ); expect(mockLeafRender.mock.calls.length).toBe(1); mockGetDecorations.mockReturnValue( Immutable.List.of('x', 'x', null, null, null) ); var decorator = new Decorator(); var newTree = BlockTree.generate(helloBlock, decorator); var nextProps = {...props, tree: newTree, decorator}; expect(props.tree).not.toBe(nextProps.tree); ReactDOM.render( <DraftEditorBlock {...nextProps} />, container ); expect(mockLeafRender.mock.calls.length).toBe(3); });
it('must allow update when forcing selection', () => { var helloBlock = getHelloBlock(); var props = getProps(helloBlock); var container = document.createElement('div'); ReactDOM.render( <DraftEditorBlock {...props} />, container ); expect(mockLeafRender.mock.calls.length).toBe(1); // The default selection state in this test is on a selection edge. var nextProps = { ...props, forceSelection: true, }; ReactDOM.render( <DraftEditorBlock {...nextProps} />, container ); expect(mockLeafRender.mock.calls.length).toBe(2); });
it('does not update static content', () => { var mockRender = jest.genMockFunction().mockReturnValue(<div />); var MyComponent = React.createClass({render: mockRender}); ReactDOM.render(<StaticContainer><MyComponent /></StaticContainer>, container); expect(mockRender.mock.calls.length).toBe(1); ReactDOM.render(<StaticContainer><MyComponent /></StaticContainer>, container); expect(mockRender.mock.calls.length).toBe(1); });
test('must reject update if conditions are not met', () => { const helloBlock = getHelloBlock(); const props = getProps(helloBlock); const container = document.createElement('div'); ReactDOM.render(<DraftEditorBlock {...props} />, container); expect(mockLeafRender.mock.calls.length).toMatchSnapshot(); // Render again with the exact same props as before. ReactDOM.render(<DraftEditorBlock {...props} />, container); // No new leaf renders. expect(mockLeafRender.mock.calls.length).toMatchSnapshot(); });
it('is `stale` if force fetching when data is fulfillable', () => { ReactDOM.render( <RelayRenderer Container={MockContainer} queryConfig={queryConfig} forceFetch={true} render={render} />, container ); expect(request => request.resolve({stale: true})).toRenderWithArgs({ done: false, error: null, props: {}, stale: true, }); expect(request => request.resolve({stale: false})).toRenderWithArgs({ done: false, error: null, props: {}, stale: false, }); expect(request => request.succeed()).toRenderWithArgs({ done: true, error: null, props: {}, stale: false, }); });
test('must allow update when `direction` has changed', () => { const helloBlock = getHelloBlock(); const props = getProps(helloBlock); const container = document.createElement('div'); ReactDOM.render(<DraftEditorBlock {...props} />, container); expect(mockLeafRender.mock.calls.length).toMatchSnapshot(); const nextProps = {...props, direction: UnicodeBidiDirection.RTL}; expect(props.direction !== nextProps.direction).toMatchSnapshot(); ReactDOM.render(<DraftEditorBlock {...nextProps} />, container); expect(mockLeafRender.mock.calls.length).toMatchSnapshot(); });
it('should call a callback argument when the same element is re-rendered', () => { class Foo extends React.Component { render() { return <div>Foo</div>; } } const element = <Foo />; // mounting phase let called = false; ReactDOM.render( element, container, () => called = true ); expect(called).toEqual(true); // updating phase called = false; ReactDOM.unstable_batchedUpdates(() => { ReactDOM.render( element, container, () => called = true ); }); expect(called).toEqual(true); });
it('throws in render() if the update callback is not a function', function() { function Foo() { this.a = 1; this.b = 2; } class A extends React.Component { state = {}; render() { return <div />; } } var myDiv = document.createElement('div'); ReactDOM.render(<A />, myDiv); expect(() => ReactDOM.render(<A />, myDiv, 'no')).toThrowError( 'ReactDOM.render(...): Expected the last optional `callback` argument ' + 'to be a function. Instead received: string.' ); expect(() => ReactDOM.render(<A />, myDiv, {})).toThrowError( 'ReactDOM.render(...): Expected the last optional `callback` argument ' + 'to be a function. Instead received: Object.' ); expect(() => ReactDOM.render(<A />, myDiv, new Foo())).toThrowError( 'ReactDOM.render(...): Expected the last optional `callback` argument ' + 'to be a function. Instead received: Foo (keys: a, b).' ); });
toRenderWithArgs: () => ({ compare(elementOrReadyState, expected) { const render = jest.fn(() => <div />); const element = ReactTestUtils.isElement(elementOrReadyState) ? React.cloneElement(elementOrReadyState, {render}) : <RelayReadyStateRenderer {...defaultProps} readyState={elementOrReadyState} render={render} />; ReactDOM.render(element, container); const actual = render.mock.calls[0][0]; const pass = jasmine.matchersUtil.equals( actual, jasmine.objectContaining(expected) ); return { get message() { const not = pass ? ' not' : ''; return ( `Expected ${ppReactElement(elementOrReadyState)}${not} ` + `to render with arguments ${jasmine.pp(expected)}. ` + `Instead, it rendered with arguments ${jasmine.pp(actual)}.` ); }, pass, }; }, }),
it('sets environment and query config on the React context', () => { class TestComponent extends React.Component { static contextTypes = { relay: Relay.PropTypes.Environment, route: Relay.PropTypes.QueryConfig.isRequired, }; render() { this.props.onRenderContext(this.context); return null; } } const onRenderContext = jest.fn(); const container = document.createElement('div'); ReactDOM.render( <RelayReadyStateRenderer {...defaultProps} readyState={defaultReadyState} render={() => <TestComponent onRenderContext={onRenderContext} />} />, container ); expect(onRenderContext).toBeCalledWith({ relay: defaultProps.environment, route: defaultProps.queryConfig, }); });
export function build(id, url, page = 1) { component = ReactDOM.render( <FeedItemList url={url} page={page}/>, document.getElementById(id) ); component.loadFeedItem(page) }
ReactDOM.unstable_batchedUpdates(() => { ReactDOM.render( element, container, () => called = true ); });
it('finds the first child even when first child renders null', () => { class NullComponent extends React.Component { render() { return null; } } class Fragment extends React.Component { render() { return [ <NullComponent />, <div />, <span />, ]; } } let instance = null; ReactDOM.render( <Fragment ref={ref => instance = ref} />, container ); expect(container.childNodes.length).toBe(2); const firstNode = ReactDOM.findDOMNode(instance); expect(firstNode).toBe(container.firstChild); expect(firstNode.tagName).toBe('DIV'); });
it('finds the first child even when fragment is nested', () => { class Wrapper extends React.Component { render() { return this.props.children; } } class Fragment extends React.Component { render() { return [ <Wrapper><div /></Wrapper>, <span />, ]; } } let instance = null; ReactDOM.render( <Fragment ref={ref => instance = ref} />, container ); expect(container.childNodes.length).toBe(2); const firstNode = ReactDOM.findDOMNode(instance); expect(firstNode).toBe(container.firstChild); expect(firstNode.tagName).toBe('DIV'); });
it('must split apart styled spans', () => { var helloBlock = getHelloBlock(); var characters = helloBlock.getCharacterList(); var newChars = characters.slice(0, 2).map(ch => { return CharacterMetadata.applyStyle(ch, 'BOLD'); }).concat(characters.slice(2)); helloBlock = helloBlock.set('characterList', Immutable.List(newChars)); var props = getProps(helloBlock); var container = document.createElement('div'); var block = ReactDOM.render( <DraftEditorBlock {...props} />, container ); expect(mockLeafRender.mock.calls.length).toBe(2); var rendered = reactComponentExpect(block) .expectRenderedChild() .toBeComponentOfType('div'); let child = rendered.expectRenderedChildAt(0); child.toBeComponentOfType(DraftEditorLeaf); arePropsEqual(child, {offsetKey: 'a-0-0', styleSet: BOLD}); child = rendered.expectRenderedChildAt(1); child.toBeComponentOfType(DraftEditorLeaf); arePropsEqual(child, {offsetKey: 'a-0-1', styleSet: NONE}); });
it('must split apart two decorators', () => { var helloBlock = getHelloBlock(); mockGetDecorations.mockReturnValue( Immutable.List.of('x', 'x', 'y', 'y', 'y') ); var decorator = new Decorator(); var props = getProps(helloBlock, decorator); var container = document.createElement('div'); var block = ReactDOM.render( <DraftEditorBlock {...props} />, container ); expect(mockLeafRender.mock.calls.length).toBe(2); var rendered = reactComponentExpect(block) .expectRenderedChild() .toBeComponentOfType('div'); rendered .expectRenderedChildAt(0) .scalarPropsEqual({offsetKey: 'a-0-0'}) .toBeComponentOfType(DecoratorSpan); rendered .expectRenderedChildAt(1) .scalarPropsEqual({offsetKey: 'a-1-0'}) .toBeComponentOfType(DecoratorSpan); });
it('should render nested portals', () => { var portalContainer1 = document.createElement('div'); var portalContainer2 = document.createElement('div'); var portalContainer3 = document.createElement('div'); ReactDOM.render([ <div>normal[0]</div>, ReactDOM.unstable_createPortal([ <div>portal1[0]</div>, ReactDOM.unstable_createPortal( <div>portal2[0]</div>, portalContainer2 ), ReactDOM.unstable_createPortal( <div>portal3[0]</div>, portalContainer3 ), <div>portal1[1]</div>, ], portalContainer1), <div>normal[1]</div>, ], container); expect(portalContainer1.innerHTML).toBe('<div>portal1[0]</div><div>portal1[1]</div>'); expect(portalContainer2.innerHTML).toBe('<div>portal2[0]</div>'); expect(portalContainer3.innerHTML).toBe('<div>portal3[0]</div>'); expect(container.innerHTML).toBe('<div>normal[0]</div><div>normal[1]</div>'); ReactDOM.unmountComponentAtNode(container); expect(portalContainer1.innerHTML).toBe(''); expect(portalContainer2.innerHTML).toBe(''); expect(portalContainer3.innerHTML).toBe(''); expect(container.innerHTML).toBe(''); });
beforeEach(() => { onReadyStateChange = jest.fn(); ReactDOM.render( <RelayRenderer Container={MockContainer} queryConfig={queryConfig} environment={environment} onReadyStateChange={onReadyStateChange} />, container, ); const defaultState = { aborted: false, done: false, error: null, mounted: true, ready: false, stale: false, }; expect.extend({ toTriggerReadyStateChanges(requestCallback, expected) { const request = environment.primeCache.mock.requests[0]; requestCallback(request); jest.runAllTimers(); expect(onReadyStateChange.mock.calls.map(args => args[0])).toEqual( expected.map(deltaState => ({...defaultState, ...deltaState})), ); return { pass: true, }; }, }); });
it('should bubble events from the portal to the parent', () => { var portalContainer = document.createElement('div'); var ops = []; var portal = null; ReactDOM.render( <div onClick={() => ops.push('parent clicked')}> {ReactDOM.unstable_createPortal( <div onClick={() => ops.push('portal clicked')} ref={n => portal = n}> portal </div>, portalContainer )} </div>, container ); expect(portal.tagName).toBe('DIV'); var fakeNativeEvent = {}; ReactTestUtils.simulateNativeEventOnNode( 'topClick', portal, fakeNativeEvent ); expect(ops).toEqual([ 'portal clicked', 'parent clicked', ]); });