mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Merge branch 'master' into rollup
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
<html>
|
||||
<body>
|
||||
<script src="../../build/react.js"></script>
|
||||
<script src="../../build/react-dom.js"></script>
|
||||
<script src="https://unpkg.com/babel-standalone@6/babel.js"></script>
|
||||
<div id="container"></div>
|
||||
<script type="text/babel">
|
||||
ReactDOM.render(
|
||||
<h1>Hello World!</h1>,
|
||||
document.getElementById('container')
|
||||
);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -102,6 +102,42 @@ src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js
|
||||
* renders >,<, and & as single child with client render on top of good server markup
|
||||
* renders >,<, and & as multiple children with server string render
|
||||
* renders >,<, and & as multiple children with client render on top of good server markup
|
||||
* renders an input with a value and an onChange with client render on top of good server markup
|
||||
* renders an input with a value and readOnly with client render on top of good server markup
|
||||
* renders an input with a value and no onChange/readOnly with client render on top of good server markup
|
||||
* renders an input with a defaultValue with client render on top of good server markup
|
||||
* renders an input value overriding defaultValue with client render on top of good server markup
|
||||
* renders an input value overriding defaultValue no matter the prop order with client render on top of good server markup
|
||||
* renders a checkbox that is checked with an onChange with client render on top of good server markup
|
||||
* renders a checkbox that is checked with readOnly with client render on top of good server markup
|
||||
* renders a checkbox that is checked and no onChange/readOnly with client render on top of good server markup
|
||||
* renders a checkbox with defaultChecked with client render on top of good server markup
|
||||
* renders a checkbox checked overriding defaultChecked with client render on top of good server markup
|
||||
* renders a checkbox checked overriding defaultChecked no matter the prop order with client render on top of good server markup
|
||||
* renders a textarea with a value and an onChange with client render on top of good server markup
|
||||
* renders a textarea with a value and readOnly with client render on top of good server markup
|
||||
* renders a textarea with a value and no onChange/readOnly with client render on top of good server markup
|
||||
* renders a textarea with a defaultValue with client render on top of good server markup
|
||||
* renders a textarea value overriding defaultValue with client render on top of good server markup
|
||||
* renders a textarea value overriding defaultValue no matter the prop order with client render on top of good server markup
|
||||
* renders a select with a value and an onChange with client render on top of good server markup
|
||||
* renders a select with a value and readOnly with client render on top of good server markup
|
||||
* renders a select with a multiple values and an onChange with client render on top of good server markup
|
||||
* renders a select with a multiple values and readOnly with client render on top of good server markup
|
||||
* renders a select with a value and no onChange/readOnly with client render on top of good server markup
|
||||
* renders a select with a defaultValue with client render on top of good server markup
|
||||
* renders a select value overriding defaultValue with client render on top of good server markup
|
||||
* renders a select value overriding defaultValue no matter the prop order with client render on top of good server markup
|
||||
* renders a controlled text input with client render on top of good server markup
|
||||
* renders a controlled textarea with client render on top of good server markup
|
||||
* renders a controlled checkbox with client render on top of good server markup
|
||||
* renders a controlled select with client render on top of good server markup
|
||||
* should not blow away user-entered text on successful reconnect to an uncontrolled input
|
||||
* should not blow away user-entered text on successful reconnect to a controlled input
|
||||
* should not blow away user-entered text on successful reconnect to an uncontrolled checkbox
|
||||
* should not blow away user-entered text on successful reconnect to a controlled checkbox
|
||||
* should not blow away user-selected value on successful reconnect to an uncontrolled select
|
||||
* should not blow away user-selected value on successful reconnect to an controlled select
|
||||
* renders class child with context with client render on top of good server markup
|
||||
* renders stateless child with context with client render on top of good server markup
|
||||
* renders class child without context with client render on top of good server markup
|
||||
|
||||
@@ -94,6 +94,36 @@ src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js
|
||||
* throws when rendering an undefined component with client render on top of bad server markup
|
||||
* throws when rendering a number component with clean client render
|
||||
* throws when rendering a number component with client render on top of bad server markup
|
||||
* renders an input with a value and an onChange with client render on top of bad server markup
|
||||
* renders an input with a value and readOnly with client render on top of bad server markup
|
||||
* renders an input with a value and no onChange/readOnly with client render on top of bad server markup
|
||||
* renders an input with a defaultValue with client render on top of bad server markup
|
||||
* renders an input value overriding defaultValue with client render on top of bad server markup
|
||||
* renders an input value overriding defaultValue no matter the prop order with client render on top of bad server markup
|
||||
* renders a checkbox that is checked with an onChange with client render on top of bad server markup
|
||||
* renders a checkbox that is checked with readOnly with client render on top of bad server markup
|
||||
* renders a checkbox that is checked and no onChange/readOnly with client render on top of bad server markup
|
||||
* renders a checkbox with defaultChecked with client render on top of bad server markup
|
||||
* renders a checkbox checked overriding defaultChecked with client render on top of bad server markup
|
||||
* renders a checkbox checked overriding defaultChecked no matter the prop order with client render on top of bad server markup
|
||||
* renders a textarea with a value and an onChange with client render on top of bad server markup
|
||||
* renders a textarea with a value and readOnly with client render on top of bad server markup
|
||||
* renders a textarea with a value and no onChange/readOnly with client render on top of bad server markup
|
||||
* renders a textarea with a defaultValue with client render on top of bad server markup
|
||||
* renders a textarea value overriding defaultValue with client render on top of bad server markup
|
||||
* renders a textarea value overriding defaultValue no matter the prop order with client render on top of bad server markup
|
||||
* renders a select with a value and an onChange with client render on top of bad server markup
|
||||
* renders a select with a value and readOnly with client render on top of bad server markup
|
||||
* renders a select with a multiple values and an onChange with client render on top of bad server markup
|
||||
* renders a select with a multiple values and readOnly with client render on top of bad server markup
|
||||
* renders a select with a value and no onChange/readOnly with client render on top of bad server markup
|
||||
* renders a select with a defaultValue with client render on top of bad server markup
|
||||
* renders a select value overriding defaultValue with client render on top of bad server markup
|
||||
* renders a select value overriding defaultValue no matter the prop order with client render on top of bad server markup
|
||||
* renders a controlled text input with client render on top of bad server markup
|
||||
* renders a controlled textarea with client render on top of bad server markup
|
||||
* renders a controlled checkbox with client render on top of bad server markup
|
||||
* renders a controlled select with client render on top of bad server markup
|
||||
* renders class child with context with client render on top of bad server markup
|
||||
* renders stateless child with context with client render on top of bad server markup
|
||||
* renders class child without context with client render on top of bad server markup
|
||||
|
||||
@@ -1154,6 +1154,62 @@ src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js
|
||||
* throws when rendering string with server string render
|
||||
* throws when rendering string with clean client render
|
||||
* throws when rendering string with client render on top of bad server markup
|
||||
* renders an input with a value and an onChange with server string render
|
||||
* renders an input with a value and an onChange with clean client render
|
||||
* renders an input with a value and readOnly with server string render
|
||||
* renders an input with a value and readOnly with clean client render
|
||||
* renders an input with a value and no onChange/readOnly with server string render
|
||||
* renders an input with a value and no onChange/readOnly with clean client render
|
||||
* renders an input with a defaultValue with server string render
|
||||
* renders an input with a defaultValue with clean client render
|
||||
* renders an input value overriding defaultValue with server string render
|
||||
* renders an input value overriding defaultValue with clean client render
|
||||
* renders an input value overriding defaultValue no matter the prop order with server string render
|
||||
* renders an input value overriding defaultValue no matter the prop order with clean client render
|
||||
* renders a checkbox that is checked with an onChange with server string render
|
||||
* renders a checkbox that is checked with an onChange with clean client render
|
||||
* renders a checkbox that is checked with readOnly with server string render
|
||||
* renders a checkbox that is checked with readOnly with clean client render
|
||||
* renders a checkbox that is checked and no onChange/readOnly with server string render
|
||||
* renders a checkbox that is checked and no onChange/readOnly with clean client render
|
||||
* renders a checkbox with defaultChecked with server string render
|
||||
* renders a checkbox with defaultChecked with clean client render
|
||||
* renders a checkbox checked overriding defaultChecked with server string render
|
||||
* renders a checkbox checked overriding defaultChecked with clean client render
|
||||
* renders a checkbox checked overriding defaultChecked no matter the prop order with server string render
|
||||
* renders a checkbox checked overriding defaultChecked no matter the prop order with clean client render
|
||||
* renders a textarea with a value and an onChange with server string render
|
||||
* renders a textarea with a value and an onChange with clean client render
|
||||
* renders a textarea with a value and readOnly with server string render
|
||||
* renders a textarea with a value and readOnly with clean client render
|
||||
* renders a textarea with a value and no onChange/readOnly with server string render
|
||||
* renders a textarea with a value and no onChange/readOnly with clean client render
|
||||
* renders a textarea with a defaultValue with server string render
|
||||
* renders a textarea with a defaultValue with clean client render
|
||||
* renders a textarea value overriding defaultValue with server string render
|
||||
* renders a textarea value overriding defaultValue with clean client render
|
||||
* renders a textarea value overriding defaultValue no matter the prop order with server string render
|
||||
* renders a textarea value overriding defaultValue no matter the prop order with clean client render
|
||||
* renders a select with a value and an onChange with server string render
|
||||
* renders a select with a value and an onChange with clean client render
|
||||
* renders a select with a value and readOnly with server string render
|
||||
* renders a select with a value and readOnly with clean client render
|
||||
* renders a select with a multiple values and an onChange with server string render
|
||||
* renders a select with a multiple values and an onChange with clean client render
|
||||
* renders a select with a multiple values and readOnly with server string render
|
||||
* renders a select with a multiple values and readOnly with clean client render
|
||||
* renders a select with a value and no onChange/readOnly with server string render
|
||||
* renders a select with a value and no onChange/readOnly with clean client render
|
||||
* renders a select with a defaultValue with server string render
|
||||
* renders a select with a defaultValue with clean client render
|
||||
* renders a select value overriding defaultValue with server string render
|
||||
* renders a select value overriding defaultValue with clean client render
|
||||
* renders a select value overriding defaultValue no matter the prop order with server string render
|
||||
* renders a select value overriding defaultValue no matter the prop order with clean client render
|
||||
* renders a controlled text input with clean client render
|
||||
* renders a controlled textarea with clean client render
|
||||
* renders a controlled checkbox with clean client render
|
||||
* renders a controlled select with clean client render
|
||||
* renders class child with context with server string render
|
||||
* renders class child with context with clean client render
|
||||
* renders stateless child with context with server string render
|
||||
@@ -1193,7 +1249,6 @@ src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js
|
||||
* should reconnect Pure Component to Bare Element
|
||||
* should reconnect Bare Element to Bare Element
|
||||
* should reconnect a div with a number and string version of number
|
||||
* should reconnect if component trees differ but resulting markup is the same
|
||||
|
||||
src/renderers/dom/shared/__tests__/ReactDOMTextComponent-test.js
|
||||
* updates a mounted text component in place
|
||||
|
||||
@@ -30,7 +30,6 @@ var processStyleName = memoizeStringOnly(function(styleName) {
|
||||
});
|
||||
|
||||
var hasShorthandPropertyBug = false;
|
||||
var styleFloatAccessor = 'cssFloat';
|
||||
if (ExecutionEnvironment.canUseDOM) {
|
||||
var tempStyle = document.createElement('div').style;
|
||||
try {
|
||||
@@ -39,10 +38,6 @@ if (ExecutionEnvironment.canUseDOM) {
|
||||
} catch (e) {
|
||||
hasShorthandPropertyBug = true;
|
||||
}
|
||||
// IE8 only supports accessing cssFloat (standard) as styleFloat
|
||||
if (document.documentElement.style.cssFloat === undefined) {
|
||||
styleFloatAccessor = 'styleFloat';
|
||||
}
|
||||
}
|
||||
|
||||
if (__DEV__) {
|
||||
@@ -215,8 +210,8 @@ var CSSPropertyOperations = {
|
||||
styles[styleName],
|
||||
component,
|
||||
);
|
||||
if (styleName === 'float' || styleName === 'cssFloat') {
|
||||
styleName = styleFloatAccessor;
|
||||
if (styleName === 'float') {
|
||||
styleName = 'cssFloat';
|
||||
}
|
||||
if (styleValue) {
|
||||
style[styleName] = styleValue;
|
||||
|
||||
@@ -16,6 +16,7 @@ let React;
|
||||
let ReactDOM;
|
||||
let ReactDOMServer;
|
||||
let ReactDOMFeatureFlags;
|
||||
let ReactTestUtils;
|
||||
|
||||
// Helper functions for rendering tests
|
||||
// ====================================
|
||||
@@ -209,6 +210,7 @@ function resetModules() {
|
||||
ReactDOM = require('ReactDOM');
|
||||
ReactDOMServer = require('ReactDOMServer');
|
||||
ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
|
||||
ReactTestUtils = require('ReactTestUtils');
|
||||
ExecutionEnvironment = require('ExecutionEnvironment');
|
||||
}
|
||||
|
||||
@@ -1022,6 +1024,556 @@ describe('ReactDOMServerIntegration', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('form controls', function() {
|
||||
describe('inputs', function() {
|
||||
itRenders('an input with a value and an onChange', async render => {
|
||||
const e = await render(<input value="foo" onChange={() => {}} />);
|
||||
expect(e.value).toBe('foo');
|
||||
});
|
||||
|
||||
itRenders('an input with a value and readOnly', async render => {
|
||||
const e = await render(<input value="foo" readOnly={true} />);
|
||||
expect(e.value).toBe('foo');
|
||||
});
|
||||
|
||||
itRenders(
|
||||
'an input with a value and no onChange/readOnly',
|
||||
async render => {
|
||||
// this configuration should raise a dev warning that value without
|
||||
// onChange or readOnly is a mistake.
|
||||
const e = await render(<input value="foo" />, 1);
|
||||
expect(e.value).toBe('foo');
|
||||
expect(e.getAttribute('value')).toBe('foo');
|
||||
},
|
||||
);
|
||||
|
||||
itRenders('an input with a defaultValue', async render => {
|
||||
const e = await render(<input defaultValue="foo" />);
|
||||
expect(e.value).toBe('foo');
|
||||
expect(e.getAttribute('value')).toBe('foo');
|
||||
expect(e.getAttribute('defaultValue')).toBe(null);
|
||||
});
|
||||
|
||||
itRenders('an input value overriding defaultValue', async render => {
|
||||
const e = await render(
|
||||
<input value="foo" defaultValue="bar" readOnly={true} />,
|
||||
1,
|
||||
);
|
||||
expect(e.value).toBe('foo');
|
||||
expect(e.getAttribute('value')).toBe('foo');
|
||||
expect(e.getAttribute('defaultValue')).toBe(null);
|
||||
});
|
||||
|
||||
itRenders(
|
||||
'an input value overriding defaultValue no matter the prop order',
|
||||
async render => {
|
||||
const e = await render(
|
||||
<input defaultValue="bar" value="foo" readOnly={true} />,
|
||||
1,
|
||||
);
|
||||
expect(e.value).toBe('foo');
|
||||
expect(e.getAttribute('value')).toBe('foo');
|
||||
expect(e.getAttribute('defaultValue')).toBe(null);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe('checkboxes', function() {
|
||||
itRenders('a checkbox that is checked with an onChange', async render => {
|
||||
const e = await render(
|
||||
<input type="checkbox" checked={true} onChange={() => {}} />,
|
||||
);
|
||||
expect(e.checked).toBe(true);
|
||||
});
|
||||
|
||||
itRenders('a checkbox that is checked with readOnly', async render => {
|
||||
const e = await render(
|
||||
<input type="checkbox" checked={true} readOnly={true} />,
|
||||
);
|
||||
expect(e.checked).toBe(true);
|
||||
});
|
||||
|
||||
itRenders(
|
||||
'a checkbox that is checked and no onChange/readOnly',
|
||||
async render => {
|
||||
// this configuration should raise a dev warning that checked without
|
||||
// onChange or readOnly is a mistake.
|
||||
const e = await render(<input type="checkbox" checked={true} />, 1);
|
||||
expect(e.checked).toBe(true);
|
||||
},
|
||||
);
|
||||
|
||||
itRenders('a checkbox with defaultChecked', async render => {
|
||||
const e = await render(<input type="checkbox" defaultChecked={true} />);
|
||||
expect(e.checked).toBe(true);
|
||||
expect(e.getAttribute('defaultChecked')).toBe(null);
|
||||
});
|
||||
|
||||
itRenders(
|
||||
'a checkbox checked overriding defaultChecked',
|
||||
async render => {
|
||||
const e = await render(
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={true}
|
||||
defaultChecked={false}
|
||||
readOnly={true}
|
||||
/>,
|
||||
1,
|
||||
);
|
||||
expect(e.checked).toBe(true);
|
||||
expect(e.getAttribute('defaultChecked')).toBe(null);
|
||||
},
|
||||
);
|
||||
|
||||
itRenders(
|
||||
'a checkbox checked overriding defaultChecked no matter the prop order',
|
||||
async render => {
|
||||
const e = await render(
|
||||
<input
|
||||
type="checkbox"
|
||||
defaultChecked={false}
|
||||
checked={true}
|
||||
readOnly={true}
|
||||
/>,
|
||||
1,
|
||||
);
|
||||
expect(e.checked).toBe(true);
|
||||
expect(e.getAttribute('defaultChecked')).toBe(null);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe('textareas', function() {
|
||||
// textareas
|
||||
// ---------
|
||||
itRenders('a textarea with a value and an onChange', async render => {
|
||||
const e = await render(<textarea value="foo" onChange={() => {}} />);
|
||||
// textarea DOM elements don't have a value **attribute**, the text is
|
||||
// a child of the element and accessible via the .value **property**.
|
||||
expect(e.getAttribute('value')).toBe(null);
|
||||
expect(e.value).toBe('foo');
|
||||
});
|
||||
|
||||
itRenders('a textarea with a value and readOnly', async render => {
|
||||
const e = await render(<textarea value="foo" readOnly={true} />);
|
||||
// textarea DOM elements don't have a value **attribute**, the text is
|
||||
// a child of the element and accessible via the .value **property**.
|
||||
expect(e.getAttribute('value')).toBe(null);
|
||||
expect(e.value).toBe('foo');
|
||||
});
|
||||
|
||||
itRenders(
|
||||
'a textarea with a value and no onChange/readOnly',
|
||||
async render => {
|
||||
// this configuration should raise a dev warning that value without
|
||||
// onChange or readOnly is a mistake.
|
||||
const e = await render(<textarea value="foo" />, 1);
|
||||
expect(e.getAttribute('value')).toBe(null);
|
||||
expect(e.value).toBe('foo');
|
||||
},
|
||||
);
|
||||
|
||||
itRenders('a textarea with a defaultValue', async render => {
|
||||
const e = await render(<textarea defaultValue="foo" />);
|
||||
expect(e.getAttribute('value')).toBe(null);
|
||||
expect(e.getAttribute('defaultValue')).toBe(null);
|
||||
expect(e.value).toBe('foo');
|
||||
});
|
||||
|
||||
itRenders('a textarea value overriding defaultValue', async render => {
|
||||
const e = await render(
|
||||
<textarea value="foo" defaultValue="bar" readOnly={true} />,
|
||||
1,
|
||||
);
|
||||
expect(e.getAttribute('value')).toBe(null);
|
||||
expect(e.getAttribute('defaultValue')).toBe(null);
|
||||
expect(e.value).toBe('foo');
|
||||
});
|
||||
|
||||
itRenders(
|
||||
'a textarea value overriding defaultValue no matter the prop order',
|
||||
async render => {
|
||||
const e = await render(
|
||||
<textarea defaultValue="bar" value="foo" readOnly={true} />,
|
||||
1,
|
||||
);
|
||||
expect(e.getAttribute('value')).toBe(null);
|
||||
expect(e.getAttribute('defaultValue')).toBe(null);
|
||||
expect(e.value).toBe('foo');
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe('selects', function() {
|
||||
var options;
|
||||
beforeEach(function() {
|
||||
options = [
|
||||
<option key={1} value="foo" id="foo">Foo</option>,
|
||||
<option key={2} value="bar" id="bar">Bar</option>,
|
||||
<option key={3} value="baz" id="baz">Baz</option>,
|
||||
];
|
||||
});
|
||||
|
||||
// a helper function to test the selected value of a <select> element.
|
||||
// takes in a <select> DOM element (element) and a value or array of
|
||||
// values that should be selected (selected).
|
||||
const expectSelectValue = (element, selected) => {
|
||||
if (!Array.isArray(selected)) {
|
||||
selected = [selected];
|
||||
}
|
||||
// the select DOM element shouldn't ever have a value or defaultValue
|
||||
// attribute; that is not how select values are expressed in the DOM.
|
||||
expect(element.getAttribute('value')).toBe(null);
|
||||
expect(element.getAttribute('defaultValue')).toBe(null);
|
||||
|
||||
['foo', 'bar', 'baz'].forEach(value => {
|
||||
const expectedValue = selected.indexOf(value) !== -1;
|
||||
var option = element.querySelector(`#${value}`);
|
||||
expect(option.selected).toBe(expectedValue);
|
||||
});
|
||||
};
|
||||
|
||||
itRenders('a select with a value and an onChange', async render => {
|
||||
const e = await render(
|
||||
<select value="bar" onChange={() => {}}>{options}</select>,
|
||||
);
|
||||
expectSelectValue(e, 'bar');
|
||||
});
|
||||
|
||||
itRenders('a select with a value and readOnly', async render => {
|
||||
const e = await render(
|
||||
<select value="bar" readOnly={true}>{options}</select>,
|
||||
);
|
||||
expectSelectValue(e, 'bar');
|
||||
});
|
||||
|
||||
itRenders(
|
||||
'a select with a multiple values and an onChange',
|
||||
async render => {
|
||||
const e = await render(
|
||||
<select value={['bar', 'baz']} multiple={true} onChange={() => {}}>
|
||||
{options}
|
||||
</select>,
|
||||
);
|
||||
expectSelectValue(e, ['bar', 'baz']);
|
||||
},
|
||||
);
|
||||
|
||||
itRenders(
|
||||
'a select with a multiple values and readOnly',
|
||||
async render => {
|
||||
const e = await render(
|
||||
<select value={['bar', 'baz']} multiple={true} readOnly={true}>
|
||||
{options}
|
||||
</select>,
|
||||
);
|
||||
expectSelectValue(e, ['bar', 'baz']);
|
||||
},
|
||||
);
|
||||
|
||||
itRenders(
|
||||
'a select with a value and no onChange/readOnly',
|
||||
async render => {
|
||||
// this configuration should raise a dev warning that value without
|
||||
// onChange or readOnly is a mistake.
|
||||
const e = await render(<select value="bar">{options}</select>, 1);
|
||||
expectSelectValue(e, 'bar');
|
||||
},
|
||||
);
|
||||
|
||||
itRenders('a select with a defaultValue', async render => {
|
||||
const e = await render(<select defaultValue="bar">{options}</select>);
|
||||
expectSelectValue(e, 'bar');
|
||||
});
|
||||
|
||||
itRenders('a select value overriding defaultValue', async render => {
|
||||
const e = await render(
|
||||
<select value="bar" defaultValue="baz" readOnly={true}>
|
||||
{options}
|
||||
</select>,
|
||||
1,
|
||||
);
|
||||
expectSelectValue(e, 'bar');
|
||||
});
|
||||
|
||||
itRenders(
|
||||
'a select value overriding defaultValue no matter the prop order',
|
||||
async render => {
|
||||
const e = await render(
|
||||
<select defaultValue="baz" value="bar" readOnly={true}>
|
||||
{options}
|
||||
</select>,
|
||||
1,
|
||||
);
|
||||
expectSelectValue(e, 'bar');
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe('user interaction', function() {
|
||||
let ControlledInput,
|
||||
ControlledTextArea,
|
||||
ControlledCheckbox,
|
||||
ControlledSelect;
|
||||
beforeEach(() => {
|
||||
ControlledInput = class extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {value: 'Hello'};
|
||||
}
|
||||
handleChange(event) {
|
||||
if (this.props.onChange) {
|
||||
this.props.onChange(event);
|
||||
}
|
||||
this.setState({value: event.target.value});
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<input
|
||||
value={this.state.value}
|
||||
onChange={this.handleChange.bind(this)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
ControlledTextArea = class extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {value: 'Hello'};
|
||||
}
|
||||
handleChange(event) {
|
||||
if (this.props.onChange) {
|
||||
this.props.onChange(event);
|
||||
}
|
||||
this.setState({value: event.target.value});
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<textarea
|
||||
value={this.state.value}
|
||||
onChange={this.handleChange.bind(this)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
ControlledCheckbox = class extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {value: true};
|
||||
}
|
||||
handleChange(event) {
|
||||
if (this.props.onChange) {
|
||||
this.props.onChange(event);
|
||||
}
|
||||
this.setState({value: event.target.checked});
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={this.state.value}
|
||||
onChange={this.handleChange.bind(this)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
ControlledSelect = class extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {value: 'Hello'};
|
||||
}
|
||||
handleChange(event) {
|
||||
if (this.props.onChange) {
|
||||
this.props.onChange(event);
|
||||
}
|
||||
this.setState({value: event.target.value});
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<select
|
||||
value={this.state.value}
|
||||
onChange={this.handleChange.bind(this)}>
|
||||
<option key="1" value="Hello">Hello</option>
|
||||
<option key="2" value="Goodbye">Goodbye</option>
|
||||
</select>
|
||||
);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
describe('user interaction with controlled inputs', function() {
|
||||
itClientRenders('a controlled text input', async render => {
|
||||
let changeCount = 0;
|
||||
const e = await render(
|
||||
<ControlledInput onChange={() => changeCount++} />,
|
||||
);
|
||||
expect(changeCount).toBe(0);
|
||||
expect(e.value).toBe('Hello');
|
||||
|
||||
// simulate a user typing.
|
||||
e.value = 'Goodbye';
|
||||
ReactTestUtils.Simulate.change(e);
|
||||
|
||||
expect(changeCount).toBe(1);
|
||||
expect(e.value).toBe('Goodbye');
|
||||
});
|
||||
|
||||
itClientRenders('a controlled textarea', async render => {
|
||||
let changeCount = 0;
|
||||
const e = await render(
|
||||
<ControlledTextArea onChange={() => changeCount++} />,
|
||||
);
|
||||
expect(changeCount).toBe(0);
|
||||
expect(e.value).toBe('Hello');
|
||||
|
||||
// simulate a user typing.
|
||||
e.value = 'Goodbye';
|
||||
ReactTestUtils.Simulate.change(e);
|
||||
|
||||
expect(changeCount).toBe(1);
|
||||
expect(e.value).toBe('Goodbye');
|
||||
});
|
||||
|
||||
itClientRenders('a controlled checkbox', async render => {
|
||||
let changeCount = 0;
|
||||
const e = await render(
|
||||
<ControlledCheckbox onChange={() => changeCount++} />,
|
||||
);
|
||||
expect(changeCount).toBe(0);
|
||||
expect(e.checked).toBe(true);
|
||||
|
||||
// simulate a user typing.
|
||||
e.checked = false;
|
||||
ReactTestUtils.Simulate.change(e);
|
||||
|
||||
expect(changeCount).toBe(1);
|
||||
expect(e.checked).toBe(false);
|
||||
});
|
||||
|
||||
itClientRenders('a controlled select', async render => {
|
||||
let changeCount = 0;
|
||||
const e = await render(
|
||||
<ControlledSelect onChange={() => changeCount++} />,
|
||||
);
|
||||
expect(changeCount).toBe(0);
|
||||
expect(e.value).toBe('Hello');
|
||||
|
||||
// simulate a user typing.
|
||||
e.value = 'Goodbye';
|
||||
ReactTestUtils.Simulate.change(e);
|
||||
|
||||
expect(changeCount).toBe(1);
|
||||
expect(e.value).toBe('Goodbye');
|
||||
});
|
||||
});
|
||||
|
||||
describe('user interaction with inputs before client render', function() {
|
||||
// renders the element and changes the value **before** the client
|
||||
// code has a chance to render; this simulates what happens when a
|
||||
// user starts to interact with a server-rendered form before
|
||||
// ReactDOM.render is called. the client render should NOT blow away
|
||||
// the changes the user has made.
|
||||
const testUserInteractionBeforeClientRender = async (
|
||||
element,
|
||||
initialValue = 'Hello',
|
||||
changedValue = 'Goodbye',
|
||||
valueKey = 'value',
|
||||
) => {
|
||||
const field = await serverRender(element);
|
||||
expect(field[valueKey]).toBe(initialValue);
|
||||
|
||||
// simulate a user typing in the field **before** client-side reconnect happens.
|
||||
field[valueKey] = changedValue;
|
||||
|
||||
resetModules();
|
||||
// client render on top of the server markup.
|
||||
const clientField = await renderIntoDom(element, field.parentNode);
|
||||
// verify that the input field was not replaced.
|
||||
// Note that we cannot use expect(clientField).toBe(field) because
|
||||
// of jest bug #1772
|
||||
expect(clientField === field).toBe(true);
|
||||
// confirm that the client render has not changed what the user typed.
|
||||
expect(clientField[valueKey]).toBe(changedValue);
|
||||
};
|
||||
|
||||
it('should not blow away user-entered text on successful reconnect to an uncontrolled input', () =>
|
||||
testUserInteractionBeforeClientRender(
|
||||
<input defaultValue="Hello" />,
|
||||
));
|
||||
|
||||
it('should not blow away user-entered text on successful reconnect to a controlled input', async () => {
|
||||
let changeCount = 0;
|
||||
await testUserInteractionBeforeClientRender(
|
||||
<ControlledInput onChange={() => changeCount++} />,
|
||||
);
|
||||
// note that there's a strong argument to be made that the DOM revival
|
||||
// algorithm should notice that the user has changed the value and fire
|
||||
// an onChange. however, it does not now, so that's what this tests.
|
||||
expect(changeCount).toBe(0);
|
||||
});
|
||||
|
||||
it('should not blow away user-entered text on successful reconnect to an uncontrolled checkbox', () =>
|
||||
testUserInteractionBeforeClientRender(
|
||||
<input type="checkbox" defaultChecked={true} />,
|
||||
true,
|
||||
false,
|
||||
'checked',
|
||||
));
|
||||
|
||||
it('should not blow away user-entered text on successful reconnect to a controlled checkbox', async () => {
|
||||
let changeCount = 0;
|
||||
await testUserInteractionBeforeClientRender(
|
||||
<ControlledCheckbox onChange={() => changeCount++} />,
|
||||
true,
|
||||
false,
|
||||
'checked',
|
||||
);
|
||||
expect(changeCount).toBe(0);
|
||||
});
|
||||
|
||||
// skipping this test because React 15 does the wrong thing. it blows
|
||||
// away the user's typing in the textarea.
|
||||
xit(
|
||||
'should not blow away user-entered text on successful reconnect to an uncontrolled textarea',
|
||||
() =>
|
||||
testUserInteractionBeforeClientRender(
|
||||
<textarea defaultValue="Hello" />,
|
||||
),
|
||||
);
|
||||
|
||||
// skipping this test because React 15 does the wrong thing. it blows
|
||||
// away the user's typing in the textarea.
|
||||
xit(
|
||||
'should not blow away user-entered text on successful reconnect to a controlled textarea',
|
||||
async () => {
|
||||
let changeCount = 0;
|
||||
await testUserInteractionBeforeClientRender(
|
||||
<ControlledTextArea onChange={() => changeCount++} />,
|
||||
);
|
||||
expect(changeCount).toBe(0);
|
||||
},
|
||||
);
|
||||
|
||||
it('should not blow away user-selected value on successful reconnect to an uncontrolled select', () =>
|
||||
testUserInteractionBeforeClientRender(
|
||||
<select defaultValue="Hello">
|
||||
<option key="1" value="Hello">Hello</option>
|
||||
<option key="2" value="Goodbye">Goodbye</option>
|
||||
</select>,
|
||||
));
|
||||
|
||||
it('should not blow away user-selected value on successful reconnect to an controlled select', async () => {
|
||||
let changeCount = 0;
|
||||
await testUserInteractionBeforeClientRender(
|
||||
<ControlledSelect onChange={() => changeCount++} />,
|
||||
);
|
||||
expect(changeCount).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('context', function() {
|
||||
let PurpleContext, RedContext;
|
||||
beforeEach(() => {
|
||||
@@ -1442,20 +1994,6 @@ describe('ReactDOMServerIntegration', () => {
|
||||
|
||||
it('can distinguish an empty component from an empty text component', () =>
|
||||
expectMarkupMismatch(<div><EmptyComponent /></div>, <div>{''}</div>));
|
||||
|
||||
it('should reconnect if component trees differ but resulting markup is the same', () => {
|
||||
class Component1 extends React.Component {
|
||||
render() {
|
||||
return <span id="foobar" />;
|
||||
}
|
||||
}
|
||||
class Component2 extends React.Component {
|
||||
render() {
|
||||
return <span id="foobar" />;
|
||||
}
|
||||
}
|
||||
return expectMarkupMatch(<Component1 />, <Component2 />);
|
||||
});
|
||||
});
|
||||
|
||||
// Markup Mismatches: misc
|
||||
|
||||
Reference in New Issue
Block a user