Skip to content

Commit

Permalink
Ignore symbols and functions in select tag (facebook#13389)
Browse files Browse the repository at this point in the history
* wip: ignore symbols and functions in select tag

* fix: Use ToStringValue as a maybe type

* refactor: remove unnecessary test

* refactor: remove implicit return from tests
  • Loading branch information
raunofreiberg authored and nhunzaker committed Aug 14, 2018
1 parent e3d5b5e commit de5102c
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 3 deletions.
172 changes: 172 additions & 0 deletions packages/react-dom/src/__tests__/ReactDOMSelect-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -808,4 +808,176 @@ describe('ReactDOMSelect', () => {
expect(node.options[1].selected).toBe(false); // b
expect(node.options[2].selected).toBe(false); // c
});

describe('When given a Symbol value', () => {
it('treats initial Symbol value as an empty string', () => {
let node;

expect(() => {
node = ReactTestUtils.renderIntoDocument(
<select onChange={noop} value={Symbol('foobar')}>
<option value={Symbol('foobar')}>A Symbol!</option>
<option value="monkey">A monkey!</option>
<option value="giraffe">A giraffe!</option>
</select>,
);
}).toWarnDev('Invalid value for prop `value`');

expect(node.value).toBe('');
});

it('treats updated Symbol value as an empty string', () => {
let node;

expect(() => {
node = ReactTestUtils.renderIntoDocument(
<select onChange={noop} value="monkey">
<option value={Symbol('foobar')}>A Symbol!</option>
<option value="monkey">A monkey!</option>
<option value="giraffe">A giraffe!</option>
</select>,
);
}).toWarnDev('Invalid value for prop `value`');

expect(node.value).toBe('monkey');

node = ReactTestUtils.renderIntoDocument(
<select onChange={noop} value={Symbol('foobar')}>
<option value={Symbol('foobar')}>A Symbol!</option>
<option value="monkey">A monkey!</option>
<option value="giraffe">A giraffe!</option>
</select>,
);

expect(node.value).toBe('');
});

it('treats initial Symbol defaultValue as an empty string', () => {
let node;

expect(() => {
node = ReactTestUtils.renderIntoDocument(
<select defaultValue={Symbol('foobar')}>
<option value={Symbol('foobar')}>A Symbol!</option>
<option value="monkey">A monkey!</option>
<option value="giraffe">A giraffe!</option>
</select>,
);
}).toWarnDev('Invalid value for prop `value`');

expect(node.value).toBe('');
});

it('treats updated Symbol defaultValue as an empty string', () => {
let node;

expect(() => {
node = ReactTestUtils.renderIntoDocument(
<select defaultValue="monkey">
<option value={Symbol('foobar')}>A Symbol!</option>
<option value="monkey">A monkey!</option>
<option value="giraffe">A giraffe!</option>
</select>,
);
}).toWarnDev('Invalid value for prop `value`');

expect(node.value).toBe('monkey');

node = ReactTestUtils.renderIntoDocument(
<select defaultValue={Symbol('foobar')}>
<option value={Symbol('foobar')}>A Symbol!</option>
<option value="monkey">A monkey!</option>
<option value="giraffe">A giraffe!</option>
</select>,
);

expect(node.value).toBe('');
});
});

describe('When given a function value', () => {
it('treats initial function value as an empty string', () => {
let node;

expect(() => {
node = ReactTestUtils.renderIntoDocument(
<select onChange={noop} value={() => {}}>
<option value={() => {}}>A function!</option>
<option value="monkey">A monkey!</option>
<option value="giraffe">A giraffe!</option>
</select>,
);
}).toWarnDev('Invalid value for prop `value`');

expect(node.value).toBe('');
});

it('treats initial function defaultValue as an empty string', () => {
let node;

expect(() => {
node = ReactTestUtils.renderIntoDocument(
<select defaultValue={() => {}}>
<option value={() => {}}>A function!</option>
<option value="monkey">A monkey!</option>
<option value="giraffe">A giraffe!</option>
</select>,
);
}).toWarnDev('Invalid value for prop `value`');

expect(node.value).toBe('');
});

it('treats updated function value as an empty string', () => {
let node;

expect(() => {
node = ReactTestUtils.renderIntoDocument(
<select onChange={noop} value="monkey">
<option value={() => {}}>A function!</option>
<option value="monkey">A monkey!</option>
<option value="giraffe">A giraffe!</option>
</select>,
);
}).toWarnDev('Invalid value for prop `value`');

expect(node.value).toBe('monkey');

node = ReactTestUtils.renderIntoDocument(
<select onChange={noop} value={() => {}}>
<option value={() => {}}>A function!</option>
<option value="monkey">A monkey!</option>
<option value="giraffe">A giraffe!</option>
</select>,
);

expect(node.value).toBe('');
});

it('treats updated function defaultValue as an empty string', () => {
let node;

expect(() => {
node = ReactTestUtils.renderIntoDocument(
<select defaultValue="monkey">
<option value={() => {}}>A function!</option>
<option value="monkey">A monkey!</option>
<option value="giraffe">A giraffe!</option>
</select>,
);
}).toWarnDev('Invalid value for prop `value`');

expect(node.value).toBe('monkey');

node = ReactTestUtils.renderIntoDocument(
<select defaultValue={() => {}}>
<option value={() => {}}>A function!</option>
<option value="monkey">A monkey!</option>
<option value="giraffe">A giraffe!</option>
</select>,
);

expect(node.value).toBe('');
});
});
});
3 changes: 2 additions & 1 deletion packages/react-dom/src/client/ReactDOMFiberOption.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import React from 'react';
import warning from 'shared/warning';
import {validateDOMNesting, updatedAncestorInfo} from './validateDOMNesting';
import {getToStringValue, toString} from './ToStringValue';

let didWarnSelectedSetOnOption = false;

Expand Down Expand Up @@ -73,7 +74,7 @@ export function validateProps(element: Element, props: Object) {
export function postMountWrapper(element: Element, props: Object) {
// value="" should make a value attribute (#6219)
if (props.value != null) {
element.setAttribute('value', props.value);
element.setAttribute('value', toString(getToStringValue(props.value)));
}
}

Expand Down
6 changes: 4 additions & 2 deletions packages/react-dom/src/client/ReactDOMFiberSelect.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {getCurrentFiberOwnerNameInDevOrNull} from 'react-reconciler/src/ReactCur
import warning from 'shared/warning';

import ReactControlledValuePropTypes from '../shared/ReactControlledValuePropTypes';
import {getToStringValue, toString} from './ToStringValue';
import type {ToStringValue} from './ToStringValue';

let didWarnValueDefaultValue;

Expand All @@ -21,7 +23,7 @@ if (__DEV__) {

type SelectWithWrapperState = HTMLSelectElement & {
_wrapperState: {
initialValue: ?string,
initialValue: ?ToStringValue,
wasMultiple: boolean,
},
};
Expand Down Expand Up @@ -98,7 +100,7 @@ function updateOptions(
} else {
// Do not set `select.value` as exact behavior isn't consistent across all
// browsers for all cases.
let selectedValue = '' + (propValue: string);
let selectedValue = toString(getToStringValue((propValue: any)));
let defaultSelected = null;
for (let i = 0; i < options.length; i++) {
if (options[i].value === selectedValue) {
Expand Down

0 comments on commit de5102c

Please sign in to comment.