Add test selectors to experimental build (#22760)

This change adds a new "react-dom/unstable_testing" entry point but I believe its contents will exactly match "react-dom/index" for the stable build. (The experimental build will have the added new selector APIs.)
This commit is contained in:
Brian Vaughn 2021-11-16 16:27:10 -05:00 committed by GitHub
parent 520ffc77a3
commit aa19d569b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 66 additions and 47 deletions

View File

@ -109,7 +109,7 @@
"scripts": { "scripts": {
"build": "node ./scripts/rollup/build.js", "build": "node ./scripts/rollup/build.js",
"build-combined": "node ./scripts/rollup/build-all-release-channels.js", "build-combined": "node ./scripts/rollup/build-all-release-channels.js",
"build-for-devtools": "cross-env RELEASE_CHANNEL=experimental yarn build react/index,react/jsx,react-dom,react-is,react-debug-tools,scheduler,react-test-renderer,react-refresh --type=NODE && cp -r ./build/node_modules build/oss-experimental/", "build-for-devtools": "cross-env RELEASE_CHANNEL=experimental yarn build react/index,react/jsx,react-dom/index,react-dom/test,react-is,react-debug-tools,scheduler,react-test-renderer,react-refresh --type=NODE && cp -r ./build/node_modules build/oss-experimental/",
"build-for-devtools-dev": "yarn build-for-devtools --type=NODE_DEV", "build-for-devtools-dev": "yarn build-for-devtools --type=NODE_DEV",
"build-for-devtools-prod": "yarn build-for-devtools --type=NODE_PROD", "build-for-devtools-prod": "yarn build-for-devtools --type=NODE_PROD",
"linc": "node ./scripts/tasks/linc.js", "linc": "node ./scripts/tasks/linc.js",

View File

@ -33,6 +33,14 @@ const babelOptions = {
), ),
}; };
const builtModulesDir = resolve(
__dirname,
'..',
'..',
'build',
'oss-experimental',
);
module.exports = { module.exports = {
mode: __DEV__ ? 'development' : 'production', mode: __DEV__ ? 'development' : 'production',
devtool: __DEV__ ? 'eval-cheap-source-map' : 'source-map', devtool: __DEV__ ? 'eval-cheap-source-map' : 'source-map',
@ -49,12 +57,10 @@ module.exports = {
libraryTarget: 'commonjs2', libraryTarget: 'commonjs2',
}, },
externals: { externals: {
react: 'react', react: resolve(builtModulesDir, 'react'),
// TODO: Once this package is published, remove the external 'react-dom': resolve(builtModulesDir, 'react-dom/unstable_testing'),
// 'react-debug-tools': 'react-debug-tools', 'react-is': resolve(builtModulesDir, 'react-is'),
'react-dom': 'react-dom', scheduler: resolve(builtModulesDir, 'scheduler'),
'react-is': 'react-is',
scheduler: 'scheduler',
}, },
node: { node: {
// source-maps package has a dependency on 'fs' // source-maps package has a dependency on 'fs'

View File

@ -55,7 +55,7 @@ const config = {
react: resolve(builtModulesDir, 'react'), react: resolve(builtModulesDir, 'react'),
'react-debug-tools': resolve(builtModulesDir, 'react-debug-tools'), 'react-debug-tools': resolve(builtModulesDir, 'react-debug-tools'),
'react-devtools-feature-flags': resolveFeatureFlags('shell'), 'react-devtools-feature-flags': resolveFeatureFlags('shell'),
'react-dom': resolve(builtModulesDir, 'react-dom'), 'react-dom': resolve(builtModulesDir, 'react-dom/unstable_testing'),
'react-is': resolve(builtModulesDir, 'react-is'), 'react-is': resolve(builtModulesDir, 'react-is'),
scheduler: resolve(builtModulesDir, 'scheduler'), scheduler: resolve(builtModulesDir, 'scheduler'),
}, },

View File

@ -34,6 +34,7 @@
"server.browser.js", "server.browser.js",
"server.node.js", "server.node.js",
"test-utils.js", "test-utils.js",
"unstable_testing.js",
"cjs/", "cjs/",
"umd/" "umd/"
], ],

View File

@ -56,7 +56,7 @@ describe('ReactDOMTestSelectors', () => {
}); });
describe('findAllNodes', () => { describe('findAllNodes', () => {
// @gate www // @gate www || experimental
it('should support searching from the document root', () => { it('should support searching from the document root', () => {
function Example() { function Example() {
return ( return (
@ -76,7 +76,7 @@ describe('ReactDOMTestSelectors', () => {
expect(matches[0].id).toBe('match'); expect(matches[0].id).toBe('match');
}); });
// @gate www // @gate www || experimental
it('should support searching from the container', () => { it('should support searching from the container', () => {
function Example() { function Example() {
return ( return (
@ -96,7 +96,7 @@ describe('ReactDOMTestSelectors', () => {
expect(matches[0].id).toBe('match'); expect(matches[0].id).toBe('match');
}); });
// @gate www // @gate www || experimental
it('should support searching from a previous match if the match had a data-testname', () => { it('should support searching from a previous match if the match had a data-testname', () => {
function Outer() { function Outer() {
return ( return (
@ -127,7 +127,7 @@ describe('ReactDOMTestSelectors', () => {
expect(matches[0].id).toBe('inner'); expect(matches[0].id).toBe('inner');
}); });
// @gate www // @gate www || experimental
it('should not support searching from a previous match if the match did not have a data-testname', () => { it('should not support searching from a previous match if the match did not have a data-testname', () => {
function Outer() { function Outer() {
return ( return (
@ -157,7 +157,7 @@ describe('ReactDOMTestSelectors', () => {
); );
}); });
// @gate www // @gate www || experimental
it('should support an multiple component types in the selector array', () => { it('should support an multiple component types in the selector array', () => {
function Outer() { function Outer() {
return ( return (
@ -211,7 +211,7 @@ describe('ReactDOMTestSelectors', () => {
expect(matches[0].id).toBe('match3'); expect(matches[0].id).toBe('match3');
}); });
// @gate www // @gate www || experimental
it('should find multiple matches', () => { it('should find multiple matches', () => {
function Example1() { function Example1() {
return ( return (
@ -249,7 +249,7 @@ describe('ReactDOMTestSelectors', () => {
]); ]);
}); });
// @gate www // @gate www || experimental
it('should ignore nested matches', () => { it('should ignore nested matches', () => {
function Example() { function Example() {
return ( return (
@ -269,7 +269,7 @@ describe('ReactDOMTestSelectors', () => {
expect(matches[0].id).toEqual('match1'); expect(matches[0].id).toEqual('match1');
}); });
// @gate www // @gate www || experimental
it('should enforce the specific order of selectors', () => { it('should enforce the specific order of selectors', () => {
function Outer() { function Outer() {
return ( return (
@ -294,7 +294,7 @@ describe('ReactDOMTestSelectors', () => {
).toHaveLength(0); ).toHaveLength(0);
}); });
// @gate www // @gate www || experimental
it('should not search within hidden subtrees', () => { it('should not search within hidden subtrees', () => {
const ref1 = React.createRef(null); const ref1 = React.createRef(null);
const ref2 = React.createRef(null); const ref2 = React.createRef(null);
@ -324,7 +324,7 @@ describe('ReactDOMTestSelectors', () => {
expect(matches[0]).toBe(ref2.current); expect(matches[0]).toBe(ref2.current);
}); });
// @gate www // @gate www || experimental
it('should support filtering by display text', () => { it('should support filtering by display text', () => {
function Example() { function Example() {
return ( return (
@ -347,7 +347,7 @@ describe('ReactDOMTestSelectors', () => {
expect(matches[0].id).toBe('match'); expect(matches[0].id).toBe('match');
}); });
// @gate www // @gate www || experimental
it('should support filtering by explicit accessibiliy role', () => { it('should support filtering by explicit accessibiliy role', () => {
function Example() { function Example() {
return ( return (
@ -372,7 +372,7 @@ describe('ReactDOMTestSelectors', () => {
expect(matches[0].id).toBe('match'); expect(matches[0].id).toBe('match');
}); });
// @gate www // @gate www || experimental
it('should support filtering by explicit secondary accessibiliy role', () => { it('should support filtering by explicit secondary accessibiliy role', () => {
const ref = React.createRef(); const ref = React.createRef();
@ -397,7 +397,7 @@ describe('ReactDOMTestSelectors', () => {
expect(matches[0]).toBe(ref.current); expect(matches[0]).toBe(ref.current);
}); });
// @gate www // @gate www || experimental
it('should support filtering by implicit accessibiliy role', () => { it('should support filtering by implicit accessibiliy role', () => {
function Example() { function Example() {
return ( return (
@ -420,7 +420,7 @@ describe('ReactDOMTestSelectors', () => {
expect(matches[0].id).toBe('match'); expect(matches[0].id).toBe('match');
}); });
// @gate www // @gate www || experimental
it('should support filtering by implicit accessibiliy role with attributes qualifications', () => { it('should support filtering by implicit accessibiliy role with attributes qualifications', () => {
function Example() { function Example() {
return ( return (
@ -443,7 +443,7 @@ describe('ReactDOMTestSelectors', () => {
expect(matches[0].id).toBe('match'); expect(matches[0].id).toBe('match');
}); });
// @gate www // @gate www || experimental
it('should support searching ahead with the has() selector', () => { it('should support searching ahead with the has() selector', () => {
function Example() { function Example() {
return ( return (
@ -479,14 +479,14 @@ describe('ReactDOMTestSelectors', () => {
expect(matches[0].id).toBe('match'); expect(matches[0].id).toBe('match');
}); });
// @gate www // @gate www || experimental
it('should throw if no container can be found', () => { it('should throw if no container can be found', () => {
expect(() => findAllNodes(document.body, [])).toThrow( expect(() => findAllNodes(document.body, [])).toThrow(
'Could not find React container within specified host subtree.', 'Could not find React container within specified host subtree.',
); );
}); });
// @gate www // @gate www || experimental
it('should throw if an invalid host root is specified', () => { it('should throw if an invalid host root is specified', () => {
const ref = React.createRef(); const ref = React.createRef();
function Example() { function Example() {
@ -502,7 +502,7 @@ describe('ReactDOMTestSelectors', () => {
}); });
describe('getFindAllNodesFailureDescription', () => { describe('getFindAllNodesFailureDescription', () => {
// @gate www // @gate www || experimental
it('should describe findAllNodes failures caused by the component type selector', () => { it('should describe findAllNodes failures caused by the component type selector', () => {
function Outer() { function Outer() {
return <Middle />; return <Middle />;
@ -532,7 +532,7 @@ No matching component was found for:
); );
}); });
// @gate www // @gate www || experimental
it('should return null if findAllNodes was able to find a match', () => { it('should return null if findAllNodes was able to find a match', () => {
function Example() { function Example() {
return ( return (
@ -568,7 +568,7 @@ No matching component was found for:
}; };
} }
// @gate www // @gate www || experimental
it('should return a single rect for a component that returns a single root host element', () => { it('should return a single rect for a component that returns a single root host element', () => {
const ref = React.createRef(); const ref = React.createRef();
@ -602,7 +602,7 @@ No matching component was found for:
}); });
}); });
// @gate www // @gate www || experimental
it('should return a multiple rects for multiple matches', () => { it('should return a multiple rects for multiple matches', () => {
const outerRef = React.createRef(); const outerRef = React.createRef();
const innerRef = React.createRef(); const innerRef = React.createRef();
@ -652,7 +652,7 @@ No matching component was found for:
}); });
}); });
// @gate www // @gate www || experimental
it('should return a multiple rects for single match that returns a fragment', () => { it('should return a multiple rects for single match that returns a fragment', () => {
const refA = React.createRef(); const refA = React.createRef();
const refB = React.createRef(); const refB = React.createRef();
@ -702,7 +702,7 @@ No matching component was found for:
}); });
}); });
// @gate www // @gate www || experimental
it('should merge overlapping rects', () => { it('should merge overlapping rects', () => {
const refA = React.createRef(); const refA = React.createRef();
const refB = React.createRef(); const refB = React.createRef();
@ -757,7 +757,7 @@ No matching component was found for:
}); });
}); });
// @gate www // @gate www || experimental
it('should merge some types of adjacent rects (if they are the same in one dimension)', () => { it('should merge some types of adjacent rects (if they are the same in one dimension)', () => {
const refA = React.createRef(); const refA = React.createRef();
const refB = React.createRef(); const refB = React.createRef();
@ -857,7 +857,7 @@ No matching component was found for:
}); });
}); });
// @gate www // @gate www || experimental
it('should not search within hidden subtrees', () => { it('should not search within hidden subtrees', () => {
const refA = React.createRef(); const refA = React.createRef();
const refB = React.createRef(); const refB = React.createRef();
@ -914,7 +914,7 @@ No matching component was found for:
}); });
describe('focusWithin', () => { describe('focusWithin', () => {
// @gate www // @gate www || experimental
it('should return false if the specified component path has no matches', () => { it('should return false if the specified component path has no matches', () => {
function Example() { function Example() {
return <Child />; return <Child />;
@ -935,7 +935,7 @@ No matching component was found for:
expect(didFocus).toBe(false); expect(didFocus).toBe(false);
}); });
// @gate www // @gate www || experimental
it('should return false if there are no focusable elements within the matched subtree', () => { it('should return false if there are no focusable elements within the matched subtree', () => {
function Example() { function Example() {
return <Child />; return <Child />;
@ -953,7 +953,7 @@ No matching component was found for:
expect(didFocus).toBe(false); expect(didFocus).toBe(false);
}); });
// @gate www // @gate www || experimental
it('should return false if the only focusable elements are disabled', () => { it('should return false if the only focusable elements are disabled', () => {
function Example() { function Example() {
return ( return (
@ -971,7 +971,7 @@ No matching component was found for:
expect(didFocus).toBe(false); expect(didFocus).toBe(false);
}); });
// @gate www // @gate www || experimental
it('should return false if the only focusable elements are hidden', () => { it('should return false if the only focusable elements are hidden', () => {
function Example() { function Example() {
return <button hidden={true}>not clickable</button>; return <button hidden={true}>not clickable</button>;
@ -985,7 +985,7 @@ No matching component was found for:
expect(didFocus).toBe(false); expect(didFocus).toBe(false);
}); });
// @gate www // @gate www || experimental
it('should successfully focus the first focusable element within the tree', () => { it('should successfully focus the first focusable element within the tree', () => {
const secondRef = React.createRef(null); const secondRef = React.createRef(null);
@ -1040,7 +1040,7 @@ No matching component was found for:
expect(handleThirdFocus).not.toHaveBeenCalled(); expect(handleThirdFocus).not.toHaveBeenCalled();
}); });
// @gate www // @gate www || experimental
it('should successfully focus the first focusable element even if application logic interferes', () => { it('should successfully focus the first focusable element even if application logic interferes', () => {
const ref = React.createRef(null); const ref = React.createRef(null);
@ -1070,7 +1070,7 @@ No matching component was found for:
expect(handleFocus).toHaveBeenCalledTimes(1); expect(handleFocus).toHaveBeenCalledTimes(1);
}); });
// @gate www // @gate www || experimental
it('should not focus within hidden subtrees', () => { it('should not focus within hidden subtrees', () => {
const secondRef = React.createRef(null); const secondRef = React.createRef(null);
@ -1194,7 +1194,7 @@ No matching component was found for:
window.IntersectionObserver = IntersectionObserver; window.IntersectionObserver = IntersectionObserver;
}); });
// @gate www // @gate www || experimental
it('should notify a listener when the underlying instance intersection changes', () => { it('should notify a listener when the underlying instance intersection changes', () => {
const ref = React.createRef(null); const ref = React.createRef(null);
@ -1231,7 +1231,7 @@ No matching component was found for:
expect(handleVisibilityChange).toHaveBeenCalledWith([{rect, ratio: 0.5}]); expect(handleVisibilityChange).toHaveBeenCalledWith([{rect, ratio: 0.5}]);
}); });
// @gate www // @gate www || experimental
it('should notify a listener of multiple targets when the underlying instance intersection changes', () => { it('should notify a listener of multiple targets when the underlying instance intersection changes', () => {
const ref1 = React.createRef(null); const ref1 = React.createRef(null);
const ref2 = React.createRef(null); const ref2 = React.createRef(null);
@ -1308,7 +1308,7 @@ No matching component was found for:
]); ]);
}); });
// @gate www // @gate www || experimental
it('should stop listening when its disconnected', () => { it('should stop listening when its disconnected', () => {
const ref = React.createRef(null); const ref = React.createRef(null);
@ -1343,7 +1343,7 @@ No matching component was found for:
}); });
// This test reuires gating because it relies on the __DEV__ only commit hook to work. // This test reuires gating because it relies on the __DEV__ only commit hook to work.
// @gate www && __DEV__ // @gate www || experimental && __DEV__
it('should update which targets its listening to after a commit', () => { it('should update which targets its listening to after a commit', () => {
const ref1 = React.createRef(null); const ref1 = React.createRef(null);
const ref2 = React.createRef(null); const ref2 = React.createRef(null);
@ -1422,7 +1422,7 @@ No matching component was found for:
]); ]);
}); });
// @gate www // @gate www || experimental
it('should not observe components within hidden subtrees', () => { it('should not observe components within hidden subtrees', () => {
const ref1 = React.createRef(null); const ref1 = React.createRef(null);
const ref2 = React.createRef(null); const ref2 = React.createRef(null);

View File

@ -8,3 +8,15 @@
*/ */
export * from './index.experimental.js'; export * from './index.experimental.js';
export {
createComponentSelector,
createHasPseudoClassSelector,
createRoleSelector,
createTestNameSelector,
createTextSelector,
getFindAllNodesFailureDescription,
findAllNodes,
findBoundingRects,
focusWithin,
observeVisibleRects,
} from 'react-reconciler/src/ReactFiberReconciler';

View File

@ -23,7 +23,7 @@ export const enableUpdaterTracking = false;
export const enableSuspenseServerRenderer = false; export const enableSuspenseServerRenderer = false;
export const enableSelectiveHydration = false; export const enableSelectiveHydration = false;
export const enableLazyElements = false; export const enableLazyElements = false;
export const enableCache = false; export const enableCache = __EXPERIMENTAL__;
export const disableJavaScriptURLs = false; export const disableJavaScriptURLs = false;
export const disableInputAttributeSyncing = false; export const disableInputAttributeSyncing = false;
export const enableSchedulerDebugging = false; export const enableSchedulerDebugging = false;

View File

@ -249,7 +249,7 @@ const bundles = [
/******* React DOM - www - Testing *******/ /******* React DOM - www - Testing *******/
{ {
moduleType: RENDERER, moduleType: RENDERER,
bundleTypes: [FB_WWW_DEV, FB_WWW_PROD], bundleTypes: [FB_WWW_DEV, FB_WWW_PROD, NODE_DEV, NODE_PROD],
entry: 'react-dom/testing', entry: 'react-dom/testing',
global: 'ReactDOMTesting', global: 'ReactDOMTesting',
minifyWithProdErrorCodes: true, minifyWithProdErrorCodes: true,