Skip to content

Commit de5102c

Browse files
raunofreibergnhunzaker
authored andcommitted
Ignore symbols and functions in select tag (facebook#13389)
* 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
1 parent e3d5b5e commit de5102c

File tree

3 files changed

+178
-3
lines changed

3 files changed

+178
-3
lines changed

packages/react-dom/src/__tests__/ReactDOMSelect-test.js

+172
Original file line numberDiff line numberDiff line change
@@ -808,4 +808,176 @@ describe('ReactDOMSelect', () => {
808808
expect(node.options[1].selected).toBe(false); // b
809809
expect(node.options[2].selected).toBe(false); // c
810810
});
811+
812+
describe('When given a Symbol value', () => {
813+
it('treats initial Symbol value as an empty string', () => {
814+
let node;
815+
816+
expect(() => {
817+
node = ReactTestUtils.renderIntoDocument(
818+
<select onChange={noop} value={Symbol('foobar')}>
819+
<option value={Symbol('foobar')}>A Symbol!</option>
820+
<option value="monkey">A monkey!</option>
821+
<option value="giraffe">A giraffe!</option>
822+
</select>,
823+
);
824+
}).toWarnDev('Invalid value for prop `value`');
825+
826+
expect(node.value).toBe('');
827+
});
828+
829+
it('treats updated Symbol value as an empty string', () => {
830+
let node;
831+
832+
expect(() => {
833+
node = ReactTestUtils.renderIntoDocument(
834+
<select onChange={noop} value="monkey">
835+
<option value={Symbol('foobar')}>A Symbol!</option>
836+
<option value="monkey">A monkey!</option>
837+
<option value="giraffe">A giraffe!</option>
838+
</select>,
839+
);
840+
}).toWarnDev('Invalid value for prop `value`');
841+
842+
expect(node.value).toBe('monkey');
843+
844+
node = ReactTestUtils.renderIntoDocument(
845+
<select onChange={noop} value={Symbol('foobar')}>
846+
<option value={Symbol('foobar')}>A Symbol!</option>
847+
<option value="monkey">A monkey!</option>
848+
<option value="giraffe">A giraffe!</option>
849+
</select>,
850+
);
851+
852+
expect(node.value).toBe('');
853+
});
854+
855+
it('treats initial Symbol defaultValue as an empty string', () => {
856+
let node;
857+
858+
expect(() => {
859+
node = ReactTestUtils.renderIntoDocument(
860+
<select defaultValue={Symbol('foobar')}>
861+
<option value={Symbol('foobar')}>A Symbol!</option>
862+
<option value="monkey">A monkey!</option>
863+
<option value="giraffe">A giraffe!</option>
864+
</select>,
865+
);
866+
}).toWarnDev('Invalid value for prop `value`');
867+
868+
expect(node.value).toBe('');
869+
});
870+
871+
it('treats updated Symbol defaultValue as an empty string', () => {
872+
let node;
873+
874+
expect(() => {
875+
node = ReactTestUtils.renderIntoDocument(
876+
<select defaultValue="monkey">
877+
<option value={Symbol('foobar')}>A Symbol!</option>
878+
<option value="monkey">A monkey!</option>
879+
<option value="giraffe">A giraffe!</option>
880+
</select>,
881+
);
882+
}).toWarnDev('Invalid value for prop `value`');
883+
884+
expect(node.value).toBe('monkey');
885+
886+
node = ReactTestUtils.renderIntoDocument(
887+
<select defaultValue={Symbol('foobar')}>
888+
<option value={Symbol('foobar')}>A Symbol!</option>
889+
<option value="monkey">A monkey!</option>
890+
<option value="giraffe">A giraffe!</option>
891+
</select>,
892+
);
893+
894+
expect(node.value).toBe('');
895+
});
896+
});
897+
898+
describe('When given a function value', () => {
899+
it('treats initial function value as an empty string', () => {
900+
let node;
901+
902+
expect(() => {
903+
node = ReactTestUtils.renderIntoDocument(
904+
<select onChange={noop} value={() => {}}>
905+
<option value={() => {}}>A function!</option>
906+
<option value="monkey">A monkey!</option>
907+
<option value="giraffe">A giraffe!</option>
908+
</select>,
909+
);
910+
}).toWarnDev('Invalid value for prop `value`');
911+
912+
expect(node.value).toBe('');
913+
});
914+
915+
it('treats initial function defaultValue as an empty string', () => {
916+
let node;
917+
918+
expect(() => {
919+
node = ReactTestUtils.renderIntoDocument(
920+
<select defaultValue={() => {}}>
921+
<option value={() => {}}>A function!</option>
922+
<option value="monkey">A monkey!</option>
923+
<option value="giraffe">A giraffe!</option>
924+
</select>,
925+
);
926+
}).toWarnDev('Invalid value for prop `value`');
927+
928+
expect(node.value).toBe('');
929+
});
930+
931+
it('treats updated function value as an empty string', () => {
932+
let node;
933+
934+
expect(() => {
935+
node = ReactTestUtils.renderIntoDocument(
936+
<select onChange={noop} value="monkey">
937+
<option value={() => {}}>A function!</option>
938+
<option value="monkey">A monkey!</option>
939+
<option value="giraffe">A giraffe!</option>
940+
</select>,
941+
);
942+
}).toWarnDev('Invalid value for prop `value`');
943+
944+
expect(node.value).toBe('monkey');
945+
946+
node = ReactTestUtils.renderIntoDocument(
947+
<select onChange={noop} value={() => {}}>
948+
<option value={() => {}}>A function!</option>
949+
<option value="monkey">A monkey!</option>
950+
<option value="giraffe">A giraffe!</option>
951+
</select>,
952+
);
953+
954+
expect(node.value).toBe('');
955+
});
956+
957+
it('treats updated function defaultValue as an empty string', () => {
958+
let node;
959+
960+
expect(() => {
961+
node = ReactTestUtils.renderIntoDocument(
962+
<select defaultValue="monkey">
963+
<option value={() => {}}>A function!</option>
964+
<option value="monkey">A monkey!</option>
965+
<option value="giraffe">A giraffe!</option>
966+
</select>,
967+
);
968+
}).toWarnDev('Invalid value for prop `value`');
969+
970+
expect(node.value).toBe('monkey');
971+
972+
node = ReactTestUtils.renderIntoDocument(
973+
<select defaultValue={() => {}}>
974+
<option value={() => {}}>A function!</option>
975+
<option value="monkey">A monkey!</option>
976+
<option value="giraffe">A giraffe!</option>
977+
</select>,
978+
);
979+
980+
expect(node.value).toBe('');
981+
});
982+
});
811983
});

packages/react-dom/src/client/ReactDOMFiberOption.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import React from 'react';
1111
import warning from 'shared/warning';
1212
import {validateDOMNesting, updatedAncestorInfo} from './validateDOMNesting';
13+
import {getToStringValue, toString} from './ToStringValue';
1314

1415
let didWarnSelectedSetOnOption = false;
1516

@@ -73,7 +74,7 @@ export function validateProps(element: Element, props: Object) {
7374
export function postMountWrapper(element: Element, props: Object) {
7475
// value="" should make a value attribute (#6219)
7576
if (props.value != null) {
76-
element.setAttribute('value', props.value);
77+
element.setAttribute('value', toString(getToStringValue(props.value)));
7778
}
7879
}
7980

packages/react-dom/src/client/ReactDOMFiberSelect.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {getCurrentFiberOwnerNameInDevOrNull} from 'react-reconciler/src/ReactCur
1212
import warning from 'shared/warning';
1313

1414
import ReactControlledValuePropTypes from '../shared/ReactControlledValuePropTypes';
15+
import {getToStringValue, toString} from './ToStringValue';
16+
import type {ToStringValue} from './ToStringValue';
1517

1618
let didWarnValueDefaultValue;
1719

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

2224
type SelectWithWrapperState = HTMLSelectElement & {
2325
_wrapperState: {
24-
initialValue: ?string,
26+
initialValue: ?ToStringValue,
2527
wasMultiple: boolean,
2628
},
2729
};
@@ -98,7 +100,7 @@ function updateOptions(
98100
} else {
99101
// Do not set `select.value` as exact behavior isn't consistent across all
100102
// browsers for all cases.
101-
let selectedValue = '' + (propValue: string);
103+
let selectedValue = toString(getToStringValue((propValue: any)));
102104
let defaultSelected = null;
103105
for (let i = 0; i < options.length; i++) {
104106
if (options[i].value === selectedValue) {

0 commit comments

Comments
 (0)