Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add fragment validation function #12092

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/react/src/React.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
createFactory,
cloneElement,
isValidElement,
isValidFragmentElement,
} from './ReactElement';
import {
createElementWithValidation,
Expand Down Expand Up @@ -44,6 +45,7 @@ const React = {
cloneElement: __DEV__ ? cloneElementWithValidation : cloneElement,
createFactory: __DEV__ ? createFactoryWithValidation : createFactory,
isValidElement: isValidElement,
isValidFragmentElement: isValidFragmentElement,

version: ReactVersion,

Expand Down
12 changes: 11 additions & 1 deletion packages/react/src/ReactElement.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import warning from 'fbjs/lib/warning';
import {REACT_ELEMENT_TYPE} from 'shared/ReactSymbols';
import {REACT_ELEMENT_TYPE, REACT_FRAGMENT_TYPE} from 'shared/ReactSymbols';

import ReactCurrentOwner from './ReactCurrentOwner';

Expand Down Expand Up @@ -368,3 +368,13 @@ export function isValidElement(object) {
object.$$typeof === REACT_ELEMENT_TYPE
);
}

/**
* Verifies the object is a ReactFragmentElement.
* @param {?object} object
* @return {boolean} True if `object` is a valid fragment component.
* @final
*/
export function isValidFragmentElement(object) {
return isValidElement(object) && object.type === REACT_FRAGMENT_TYPE;
}
1 change: 0 additions & 1 deletion packages/react/src/ReactElementValidator.js
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,6 @@ function validateFragmentProps(fragment) {
getStackAddendum(),
);
}

currentlyValidatingElement = null;
}

Expand Down
46 changes: 46 additions & 0 deletions packages/react/src/__tests__/ReactElement-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,52 @@ describe('ReactElement', () => {
expect(React.isValidElement(JSON.parse(jsonElement))).toBe(true);
});

// NOTE: We're explicitly not using JSX here. This is intended to test
// classic JS without JSX.
it('identifies valid fragment elements', () => {
// because we set global.Symbol = undefined in the beforeEach of some tests
// so we can't use `Object.keys` together with `for of` syntax
// in the 'validateFragmentProps' function of ReactElementValidator.js
// it will throw TypeError: can not read property 'interator' of undefined
// so we have to set it to orgin value
global.Symbol = originalSymbol;

class Component extends React.Component {
render() {
return React.createElement(
React.Fragment,
null,
React.createElement('div'),
);
}
}

expect(
React.isValidFragmentElement(
React.createElement(React.Fragment, null, React.createElement('div')),
),
).toEqual(true);

expect(
React.isValidFragmentElement(React.createElement(Component)),
).toEqual(false);
expect(React.isValidFragmentElement(null)).toEqual(false);
expect(React.isValidFragmentElement(true)).toEqual(false);
expect(React.isValidFragmentElement({})).toEqual(false);
expect(React.isValidFragmentElement('string')).toEqual(false);
expect(React.isValidFragmentElement(React.createFactory('div'))).toEqual(
false,
);
expect(React.isValidFragmentElement(Component)).toEqual(false);
expect(
React.isValidFragmentElement({type: React.Fragment, props: {}}),
).toEqual(false);

const jsonElement = JSON.stringify(React.createElement(React.Fragment));
expect(jsonElement).not.toHaveProperty('type');
expect(React.isValidFragmentElement(JSON.parse(jsonElement))).toBe(true);
});

// NOTE: We're explicitly not using JSX here. This is intended to test
// classic JS without JSX.
it('is indistinguishable from a plain object', () => {
Expand Down
15 changes: 15 additions & 0 deletions packages/react/src/__tests__/ReactJSXElement-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,21 @@ describe('ReactJSXElement', () => {
expect(React.isValidElement({type: 'div', props: {}})).toEqual(false);
});

it('identifies valid fragment elements', () => {
expect(React.isValidFragmentElement(<React.Fragment />)).toEqual(true);

expect(React.isValidFragmentElement(<div />)).toEqual(false);
expect(React.isValidFragmentElement(<Component />)).toEqual(false);
expect(React.isValidFragmentElement(null)).toEqual(false);
expect(React.isValidFragmentElement(true)).toEqual(false);
expect(React.isValidFragmentElement({})).toEqual(false);
expect(React.isValidFragmentElement('string')).toEqual(false);
expect(React.isValidFragmentElement(Component)).toEqual(false);
expect(React.isValidFragmentElement({type: 'div', props: {}})).toEqual(
false,
);
});

it('is indistinguishable from a plain object', () => {
const element = <div className="foo" />;
const object = {};
Expand Down