Skip to content

Commit becaffd

Browse files
committed
Temporarily feature flag numeric fallback for symbols
1 parent d63cd97 commit becaffd

15 files changed

+328
-27
lines changed

packages/react/src/__tests__/ReactElement-test.js

+112
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,26 @@
99

1010
'use strict';
1111

12+
import {enableSymbolFallbackForWWW} from 'shared/ReactFeatureFlags';
13+
1214
let React;
1315
let ReactDOM;
1416
let ReactTestUtils;
1517

1618
describe('ReactElement', () => {
1719
let ComponentClass;
20+
let originalSymbol;
1821

1922
beforeEach(() => {
2023
jest.resetModules();
2124

25+
if (enableSymbolFallbackForWWW) {
26+
// Delete the native Symbol if we have one to ensure we test the
27+
// unpolyfilled environment.
28+
originalSymbol = global.Symbol;
29+
global.Symbol = undefined;
30+
}
31+
2232
React = require('react');
2333
ReactDOM = require('react-dom');
2434
ReactTestUtils = require('react-dom/test-utils');
@@ -31,6 +41,17 @@ describe('ReactElement', () => {
3141
};
3242
});
3343

44+
afterEach(() => {
45+
if (enableSymbolFallbackForWWW) {
46+
global.Symbol = originalSymbol;
47+
}
48+
});
49+
50+
// @gate enableSymbolFallbackForWWW
51+
it('uses the fallback value when in an environment without Symbol', () => {
52+
expect((<div />).$$typeof).toBe(0xeac7);
53+
});
54+
3455
it('returns a complete element according to spec', () => {
3556
const element = React.createElement(ComponentClass);
3657
expect(element.type).toBe(ComponentClass);
@@ -280,6 +301,42 @@ describe('ReactElement', () => {
280301
expect(element.type.someStaticMethod()).toBe('someReturnValue');
281302
});
282303

304+
// NOTE: We're explicitly not using JSX here. This is intended to test
305+
// classic JS without JSX.
306+
// @gate enableSymbolFallbackForWWW
307+
it('identifies valid elements', () => {
308+
class Component extends React.Component {
309+
render() {
310+
return React.createElement('div');
311+
}
312+
}
313+
314+
expect(React.isValidElement(React.createElement('div'))).toEqual(true);
315+
expect(React.isValidElement(React.createElement(Component))).toEqual(true);
316+
317+
expect(React.isValidElement(null)).toEqual(false);
318+
expect(React.isValidElement(true)).toEqual(false);
319+
expect(React.isValidElement({})).toEqual(false);
320+
expect(React.isValidElement('string')).toEqual(false);
321+
if (!__EXPERIMENTAL__) {
322+
let factory;
323+
expect(() => {
324+
factory = React.createFactory('div');
325+
}).toWarnDev(
326+
'Warning: React.createFactory() is deprecated and will be removed in a ' +
327+
'future major release. Consider using JSX or use React.createElement() ' +
328+
'directly instead.',
329+
{withoutStack: true},
330+
);
331+
expect(React.isValidElement(factory)).toEqual(false);
332+
}
333+
expect(React.isValidElement(Component)).toEqual(false);
334+
expect(React.isValidElement({type: 'div', props: {}})).toEqual(false);
335+
336+
const jsonElement = JSON.stringify(React.createElement('div'));
337+
expect(React.isValidElement(JSON.parse(jsonElement))).toBe(true);
338+
});
339+
283340
// NOTE: We're explicitly not using JSX here. This is intended to test
284341
// classic JS without JSX.
285342
it('is indistinguishable from a plain object', () => {
@@ -397,6 +454,7 @@ describe('ReactElement', () => {
397454

398455
// NOTE: We're explicitly not using JSX here. This is intended to test
399456
// classic JS without JSX.
457+
// @gate !enableSymbolFallbackForWWW
400458
it('identifies elements, but not JSON, if Symbols are supported', () => {
401459
class Component extends React.Component {
402460
render() {
@@ -429,4 +487,58 @@ describe('ReactElement', () => {
429487
const jsonElement = JSON.stringify(React.createElement('div'));
430488
expect(React.isValidElement(JSON.parse(jsonElement))).toBe(false);
431489
});
490+
491+
// NOTE: We're explicitly not using JSX here. This is intended to test
492+
// classic JS without JSX.
493+
it('identifies elements, but not JSON, if Symbols are supported (with polyfill)', () => {
494+
// Rudimentary polyfill
495+
// Once all jest engines support Symbols natively we can swap this to test
496+
// WITH native Symbols by default.
497+
const REACT_ELEMENT_TYPE = function() {}; // fake Symbol
498+
const OTHER_SYMBOL = function() {}; // another fake Symbol
499+
global.Symbol = function(name) {
500+
return OTHER_SYMBOL;
501+
};
502+
global.Symbol.for = function(key) {
503+
if (key === 'react.element') {
504+
return REACT_ELEMENT_TYPE;
505+
}
506+
return OTHER_SYMBOL;
507+
};
508+
509+
jest.resetModules();
510+
511+
React = require('react');
512+
513+
class Component extends React.Component {
514+
render() {
515+
return React.createElement('div');
516+
}
517+
}
518+
519+
expect(React.isValidElement(React.createElement('div'))).toEqual(true);
520+
expect(React.isValidElement(React.createElement(Component))).toEqual(true);
521+
522+
expect(React.isValidElement(null)).toEqual(false);
523+
expect(React.isValidElement(true)).toEqual(false);
524+
expect(React.isValidElement({})).toEqual(false);
525+
expect(React.isValidElement('string')).toEqual(false);
526+
if (!__EXPERIMENTAL__) {
527+
let factory;
528+
expect(() => {
529+
factory = React.createFactory('div');
530+
}).toWarnDev(
531+
'Warning: React.createFactory() is deprecated and will be removed in a ' +
532+
'future major release. Consider using JSX or use React.createElement() ' +
533+
'directly instead.',
534+
{withoutStack: true},
535+
);
536+
expect(React.isValidElement(factory)).toEqual(false);
537+
}
538+
expect(React.isValidElement(Component)).toEqual(false);
539+
expect(React.isValidElement({type: 'div', props: {}})).toEqual(false);
540+
541+
const jsonElement = JSON.stringify(React.createElement('div'));
542+
expect(React.isValidElement(JSON.parse(jsonElement))).toBe(false);
543+
});
432544
});

packages/react/src/__tests__/ReactElementJSX-test.js

+113
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
'use strict';
1111

12+
import {enableSymbolFallbackForWWW} from 'shared/ReactFeatureFlags';
13+
1214
let React;
1315
let ReactDOM;
1416
let ReactTestUtils;
@@ -20,16 +22,31 @@ let JSXDEVRuntime;
2022
// A lot of these tests are pulled from ReactElement-test because
2123
// this api is meant to be backwards compatible.
2224
describe('ReactElement.jsx', () => {
25+
let originalSymbol;
26+
2327
beforeEach(() => {
2428
jest.resetModules();
2529

30+
if (enableSymbolFallbackForWWW) {
31+
// Delete the native Symbol if we have one to ensure we test the
32+
// unpolyfilled environment.
33+
originalSymbol = global.Symbol;
34+
global.Symbol = undefined;
35+
}
36+
2637
React = require('react');
2738
JSXRuntime = require('react/jsx-runtime');
2839
JSXDEVRuntime = require('react/jsx-dev-runtime');
2940
ReactDOM = require('react-dom');
3041
ReactTestUtils = require('react-dom/test-utils');
3142
});
3243

44+
afterEach(() => {
45+
if (enableSymbolFallbackForWWW) {
46+
global.Symbol = originalSymbol;
47+
}
48+
});
49+
3350
it('allows static methods to be called using the type property', () => {
3451
class StaticMethodComponentClass extends React.Component {
3552
render() {
@@ -42,6 +59,48 @@ describe('ReactElement.jsx', () => {
4259
expect(element.type.someStaticMethod()).toBe('someReturnValue');
4360
});
4461

62+
// @gate enableSymbolFallbackForWWW
63+
it('identifies valid elements', () => {
64+
class Component extends React.Component {
65+
render() {
66+
return JSXRuntime.jsx('div', {});
67+
}
68+
}
69+
70+
expect(React.isValidElement(JSXRuntime.jsx('div', {}))).toEqual(true);
71+
expect(React.isValidElement(JSXRuntime.jsx(Component, {}))).toEqual(true);
72+
expect(
73+
React.isValidElement(JSXRuntime.jsx(JSXRuntime.Fragment, {})),
74+
).toEqual(true);
75+
if (__DEV__) {
76+
expect(React.isValidElement(JSXDEVRuntime.jsxDEV('div', {}))).toEqual(
77+
true,
78+
);
79+
}
80+
81+
expect(React.isValidElement(null)).toEqual(false);
82+
expect(React.isValidElement(true)).toEqual(false);
83+
expect(React.isValidElement({})).toEqual(false);
84+
expect(React.isValidElement('string')).toEqual(false);
85+
if (!__EXPERIMENTAL__) {
86+
let factory;
87+
expect(() => {
88+
factory = React.createFactory('div');
89+
}).toWarnDev(
90+
'Warning: React.createFactory() is deprecated and will be removed in a ' +
91+
'future major release. Consider using JSX or use React.createElement() ' +
92+
'directly instead.',
93+
{withoutStack: true},
94+
);
95+
expect(React.isValidElement(factory)).toEqual(false);
96+
}
97+
expect(React.isValidElement(Component)).toEqual(false);
98+
expect(React.isValidElement({type: 'div', props: {}})).toEqual(false);
99+
100+
const jsonElement = JSON.stringify(JSXRuntime.jsx('div', {}));
101+
expect(React.isValidElement(JSON.parse(jsonElement))).toBe(true);
102+
});
103+
45104
it('is indistinguishable from a plain object', () => {
46105
const element = JSXRuntime.jsx('div', {className: 'foo'});
47106
const object = {};
@@ -235,6 +294,7 @@ describe('ReactElement.jsx', () => {
235294
);
236295
});
237296

297+
// @gate !enableSymbolFallbackForWWW
238298
it('identifies elements, but not JSON, if Symbols are supported', () => {
239299
class Component extends React.Component {
240300
render() {
@@ -276,6 +336,59 @@ describe('ReactElement.jsx', () => {
276336
expect(React.isValidElement(JSON.parse(jsonElement))).toBe(false);
277337
});
278338

339+
it('identifies elements, but not JSON, if Symbols are polyfilled', () => {
340+
// Rudimentary polyfill
341+
// Once all jest engines support Symbols natively we can swap this to test
342+
// WITH native Symbols by default.
343+
const REACT_ELEMENT_TYPE = function() {}; // fake Symbol
344+
const OTHER_SYMBOL = function() {}; // another fake Symbol
345+
global.Symbol = function(name) {
346+
return OTHER_SYMBOL;
347+
};
348+
global.Symbol.for = function(key) {
349+
if (key === 'react.element') {
350+
return REACT_ELEMENT_TYPE;
351+
}
352+
return OTHER_SYMBOL;
353+
};
354+
355+
jest.resetModules();
356+
357+
React = require('react');
358+
JSXRuntime = require('react/jsx-runtime');
359+
360+
class Component extends React.Component {
361+
render() {
362+
return JSXRuntime.jsx('div');
363+
}
364+
}
365+
366+
expect(React.isValidElement(JSXRuntime.jsx('div', {}))).toEqual(true);
367+
expect(React.isValidElement(JSXRuntime.jsx(Component, {}))).toEqual(true);
368+
369+
expect(React.isValidElement(null)).toEqual(false);
370+
expect(React.isValidElement(true)).toEqual(false);
371+
expect(React.isValidElement({})).toEqual(false);
372+
expect(React.isValidElement('string')).toEqual(false);
373+
if (!__EXPERIMENTAL__) {
374+
let factory;
375+
expect(() => {
376+
factory = React.createFactory('div');
377+
}).toWarnDev(
378+
'Warning: React.createFactory() is deprecated and will be removed in a ' +
379+
'future major release. Consider using JSX or use React.createElement() ' +
380+
'directly instead.',
381+
{withoutStack: true},
382+
);
383+
expect(React.isValidElement(factory)).toEqual(false);
384+
}
385+
expect(React.isValidElement(Component)).toEqual(false);
386+
expect(React.isValidElement({type: 'div', props: {}})).toEqual(false);
387+
388+
const jsonElement = JSON.stringify(JSXRuntime.jsx('div', {}));
389+
expect(React.isValidElement(JSON.parse(jsonElement))).toBe(false);
390+
});
391+
279392
it('should warn when unkeyed children are passed to jsx', () => {
280393
const container = document.createElement('div');
281394

packages/shared/ReactFeatureFlags.js

+3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ export const enablePersistentOffscreenHostContainer = false;
2828
// like migrating internal callers or performance testing.
2929
// -----------------------------------------------------------------------------
3030

31+
// This is blocked on adding a symbol polyfill to www.
32+
export const enableSymbolFallbackForWWW = false;
33+
3134
// This rolled out to 10% public in www, so we should be able to land, but some
3235
// internal tests need to be updated. The open source behavior is correct.
3336
export const skipUnmountedBoundaries = true;

0 commit comments

Comments
 (0)