@samitouri / QOS-React-2 / commits / de5102c4cd

Ignore symbols and functions in select tag (#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

Rauno Freiberg committed Aug 14, 2018 at 20:31 UTC de5102c4cd9a0ece37872c5a1c6b1e1345b8afef
3 files changed +178 -3
packages/react-dom/src/__tests__/ReactDOMSelect-test.js
+172
@@ -808,4 +808,176 @@ describe('ReactDOMSelect', () => {
808 expect(node.options[1].selected).toBe(false); // b
809 expect(node.options[2].selected).toBe(false); // c
810 });
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 + });
983 });
packages/react-dom/src/client/ReactDOMFiberOption.js
+2 -1
@@ -10,6 +10,7 @@
10 import React from 'react';
11 import warning from 'shared/warning';
12 import {validateDOMNesting, updatedAncestorInfo} from './validateDOMNesting';
13 +import {getToStringValue, toString} from './ToStringValue';
14
15 let didWarnSelectedSetOnOption = false;
16
@@ -73,7 +74,7 @@ export function validateProps(element: Element, props: Object) {
74 export function postMountWrapper(element: Element, props: Object) {
75 // value="" should make a value attribute (#6219)
76 if (props.value != null) {
76 - element.setAttribute('value', props.value);
77 + element.setAttribute('value', toString(getToStringValue(props.value)));
78 }
79 }
80
packages/react-dom/src/client/ReactDOMFiberSelect.js
+4 -2
@@ -12,6 +12,8 @@ import {getCurrentFiberOwnerNameInDevOrNull} from 'react-reconciler/src/ReactCur
12 import warning from 'shared/warning';
13
14 import ReactControlledValuePropTypes from '../shared/ReactControlledValuePropTypes';
15 +import {getToStringValue, toString} from './ToStringValue';
16 +import type {ToStringValue} from './ToStringValue';
17
18 let didWarnValueDefaultValue;
19
@@ -21,7 +23,7 @@ if (__DEV__) {
23
24 type SelectWithWrapperState = HTMLSelectElement & {
25 _wrapperState: {
24 - initialValue: ?string,
26 + initialValue: ?ToStringValue,
27 wasMultiple: boolean,
28 },
29 };
@@ -98,7 +100,7 @@ function updateOptions(
100 } else {
101 // Do not set `select.value` as exact behavior isn't consistent across all
102 // browsers for all cases.
101 - let selectedValue = '' + (propValue: string);
103 + let selectedValue = toString(getToStringValue((propValue: any)));
104 let defaultSelected = null;
105 for (let i = 0; i < options.length; i++) {
106 if (options[i].value === selectedValue) {