react / react-0.13.3 / examples / basic-commonjs / node_modules / reactify / node_modules / react-tools / src / browser / server / __tests__ / ReactServerRendering-test.js
81162 views/**1* Copyright 2013-2014, Facebook, Inc.2* All rights reserved.3*4* This source code is licensed under the BSD-style license found in the5* LICENSE file in the root directory of this source tree. An additional grant6* of patent rights can be found in the PATENTS file in the same directory.7*8* @emails react-core9*/1011/*jslint evil: true */1213"use strict";1415require('mock-modules')16.dontMock('ExecutionEnvironment')17.dontMock('React')18.dontMock('ReactMount')19.dontMock('ReactServerRendering')20.dontMock('ReactTestUtils')21.dontMock('ReactMarkupChecksum');2223var mocks = require('mocks');2425var ExecutionEnvironment;26var React;27var ReactMarkupChecksum;28var ReactMount;29var ReactReconcileTransaction;30var ReactTestUtils;31var ReactServerRendering;3233var ID_ATTRIBUTE_NAME;3435describe('ReactServerRendering', function() {36beforeEach(function() {37require('mock-modules').dumpCache();38React = require('React');39ReactMarkupChecksum = require('ReactMarkupChecksum');40ReactMount = require('ReactMount');41ReactTestUtils = require('ReactTestUtils');42ReactReconcileTransaction = require('ReactReconcileTransaction');4344ExecutionEnvironment = require('ExecutionEnvironment');45ExecutionEnvironment.canUseDOM = false;46ReactServerRendering = require('ReactServerRendering');4748var DOMProperty = require('DOMProperty');49ID_ATTRIBUTE_NAME = DOMProperty.ID_ATTRIBUTE_NAME;50});5152describe('renderComponentToString', function() {53it('should generate simple markup', function() {54var response = ReactServerRendering.renderToString(55<span>hello world</span>56);57expect(response).toMatch(58'<span ' + ID_ATTRIBUTE_NAME + '="[^"]+" ' +59ReactMarkupChecksum.CHECKSUM_ATTR_NAME + '="[^"]+">hello world</span>'60);61});6263it('should not register event listeners', function() {64var EventPluginHub = require('EventPluginHub');65var cb = mocks.getMockFunction();6667ReactServerRendering.renderToString(68<span onClick={cb}>hello world</span>69);70expect(EventPluginHub.__getListenerBank()).toEqual({});71});7273it('should render composite components', function() {74var Parent = React.createClass({75render: function() {76return <div><Child name="child" /></div>;77}78});79var Child = React.createClass({80render: function() {81return <span>My name is {this.props.name}</span>;82}83});84var response = ReactServerRendering.renderToString(85<Parent />86);87expect(response).toMatch(88'<div ' + ID_ATTRIBUTE_NAME + '="[^"]+" ' +89ReactMarkupChecksum.CHECKSUM_ATTR_NAME + '="[^"]+">' +90'<span ' + ID_ATTRIBUTE_NAME + '="[^"]+">' +91'<span ' + ID_ATTRIBUTE_NAME + '="[^"]+">My name is </span>' +92'<span ' + ID_ATTRIBUTE_NAME + '="[^"]+">child</span>' +93'</span>' +94'</div>'95);96});9798it('should only execute certain lifecycle methods', function() {99function runTest() {100var lifecycle = [];101var TestComponent = React.createClass({102componentWillMount: function() {103lifecycle.push('componentWillMount');104},105componentDidMount: function() {106lifecycle.push('componentDidMount');107},108getInitialState: function() {109lifecycle.push('getInitialState');110return {name: 'TestComponent'};111},112render: function() {113lifecycle.push('render');114return <span>Component name: {this.state.name}</span>;115},116componentWillUpdate: function() {117lifecycle.push('componentWillUpdate');118},119componentDidUpdate: function() {120lifecycle.push('componentDidUpdate');121},122shouldComponentUpdate: function() {123lifecycle.push('shouldComponentUpdate');124},125componentWillReceiveProps: function() {126lifecycle.push('componentWillReceiveProps');127},128componentWillUnmount: function() {129lifecycle.push('componentWillUnmount');130}131});132133var response = ReactServerRendering.renderToString(134<TestComponent />135);136137expect(response).toMatch(138'<span ' + ID_ATTRIBUTE_NAME + '="[^"]+" ' +139ReactMarkupChecksum.CHECKSUM_ATTR_NAME + '="[^"]+">' +140'<span ' + ID_ATTRIBUTE_NAME + '="[^"]+">Component name: </span>' +141'<span ' + ID_ATTRIBUTE_NAME + '="[^"]+">TestComponent</span>' +142'</span>'143);144expect(lifecycle).toEqual(145['getInitialState', 'componentWillMount', 'render']146);147}148149runTest();150151// This should work the same regardless of whether you can use DOM or not.152ExecutionEnvironment.canUseDOM = true;153runTest();154});155156it('should have the correct mounting behavior', function() {157// This test is testing client-side behavior.158ExecutionEnvironment.canUseDOM = true;159160var mountCount = 0;161var numClicks = 0;162163var TestComponent = React.createClass({164componentDidMount: function() {165mountCount++;166},167click: function() {168numClicks++;169},170render: function() {171return (172<span ref="span" onClick={this.click}>Name: {this.props.name}</span>173);174}175});176177var element = document.createElement('div');178React.render(<TestComponent />, element);179180var lastMarkup = element.innerHTML;181182// Exercise the update path. Markup should not change,183// but some lifecycle methods should be run again.184React.render(<TestComponent name="x" />, element);185expect(mountCount).toEqual(1);186187// Unmount and remount. We should get another mount event and188// we should get different markup, as the IDs are unique each time.189React.unmountComponentAtNode(element);190expect(element.innerHTML).toEqual('');191React.render(<TestComponent name="x" />, element);192expect(mountCount).toEqual(2);193expect(element.innerHTML).not.toEqual(lastMarkup);194195// Now kill the node and render it on top of server-rendered markup, as if196// we used server rendering. We should mount again, but the markup should197// be unchanged. We will append a sentinel at the end of innerHTML to be198// sure that innerHTML was not changed.199React.unmountComponentAtNode(element);200expect(element.innerHTML).toEqual('');201202ExecutionEnvironment.canUseDOM = false;203lastMarkup = ReactServerRendering.renderToString(204<TestComponent name="x" />205);206ExecutionEnvironment.canUseDOM = true;207element.innerHTML = lastMarkup + ' __sentinel__';208209React.render(<TestComponent name="x" />, element);210expect(mountCount).toEqual(3);211expect(element.innerHTML.indexOf('__sentinel__') > -1).toBe(true);212React.unmountComponentAtNode(element);213expect(element.innerHTML).toEqual('');214215// Now simulate a situation where the app is not idempotent. React should216// warn but do the right thing.217var _warn = console.warn;218console.warn = mocks.getMockFunction();219element.innerHTML = lastMarkup;220var instance = React.render(<TestComponent name="y" />, element);221expect(mountCount).toEqual(4);222expect(console.warn.mock.calls.length).toBe(1);223expect(element.innerHTML.length > 0).toBe(true);224expect(element.innerHTML).not.toEqual(lastMarkup);225console.warn = _warn;226227// Ensure the events system works228expect(numClicks).toEqual(0);229ReactTestUtils.Simulate.click(instance.refs.span.getDOMNode());230expect(numClicks).toEqual(1);231});232233it('should throw with silly args', function() {234expect(235ReactServerRendering.renderToString.bind(236ReactServerRendering,237'not a component'238)239).toThrow(240'Invariant Violation: renderToString(): You must pass ' +241'a valid ReactElement.'242);243});244});245246describe('renderComponentToStaticMarkup', function() {247it('should not put checksum and React ID on components', function() {248var lifecycle = [];249var NestedComponent = React.createClass({250render: function() {251return <div>inner text</div>;252}253});254255var TestComponent = React.createClass({256render: function() {257lifecycle.push('render');258return <span><NestedComponent /></span>;259}260});261262var response = ReactServerRendering.renderToStaticMarkup(263<TestComponent />264);265266expect(response).toBe('<span><div>inner text</div></span>');267});268269it('should not put checksum and React ID on text components', function() {270var TestComponent = React.createClass({271render: function() {272return <span>{'hello'} {'world'}</span>;273}274});275276var response = ReactServerRendering.renderToStaticMarkup(277<TestComponent />278);279280expect(response).toBe('<span>hello world</span>');281});282283it('should not register event listeners', function() {284var EventPluginHub = require('EventPluginHub');285var cb = mocks.getMockFunction();286287ReactServerRendering.renderToString(288<span onClick={cb}>hello world</span>289);290expect(EventPluginHub.__getListenerBank()).toEqual({});291});292293it('should only execute certain lifecycle methods', function() {294function runTest() {295var lifecycle = [];296var TestComponent = React.createClass({297componentWillMount: function() {298lifecycle.push('componentWillMount');299},300componentDidMount: function() {301lifecycle.push('componentDidMount');302},303getInitialState: function() {304lifecycle.push('getInitialState');305return {name: 'TestComponent'};306},307render: function() {308lifecycle.push('render');309return <span>Component name: {this.state.name}</span>;310},311componentWillUpdate: function() {312lifecycle.push('componentWillUpdate');313},314componentDidUpdate: function() {315lifecycle.push('componentDidUpdate');316},317shouldComponentUpdate: function() {318lifecycle.push('shouldComponentUpdate');319},320componentWillReceiveProps: function() {321lifecycle.push('componentWillReceiveProps');322},323componentWillUnmount: function() {324lifecycle.push('componentWillUnmount');325}326});327328var response = ReactServerRendering.renderToStaticMarkup(329<TestComponent />330);331332expect(response).toBe('<span>Component name: TestComponent</span>');333expect(lifecycle).toEqual(334['getInitialState', 'componentWillMount', 'render']335);336}337338runTest();339340// This should work the same regardless of whether you can use DOM or not.341ExecutionEnvironment.canUseDOM = true;342runTest();343});344345it('should throw with silly args', function() {346expect(347ReactServerRendering.renderToStaticMarkup.bind(348ReactServerRendering,349'not a component'350)351).toThrow(352'Invariant Violation: renderToStaticMarkup(): You must pass ' +353'a valid ReactElement.'354);355});356357it('allows setState in componentWillMount without using DOM', function() {358var Component = React.createClass({359componentWillMount: function() {360this.setState({text: 'hello, world'});361},362render: function() {363return <div>{this.state.text}</div>;364}365});366367ReactReconcileTransaction.prototype.perform = function() {368// We shouldn't ever be calling this on the server369throw new Error('Browser reconcile transaction should not be used');370};371var markup = ReactServerRendering.renderToString(372<Component />373);374expect(markup.indexOf('hello, world') >= 0).toBe(true);375});376});377});378379380