diff --git a/.circleci/config.yml b/.circleci/config.yml index ea8f6458f96bb..d5d0e4f8f488b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -115,6 +115,106 @@ jobs: RELEASE_CHANNEL: experimental command: yarn test --maxWorkers=2 + test_source_www: + docker: *docker + environment: *environment + steps: + - checkout + - *restore_yarn_cache + - *run_yarn + - run: + environment: + RELEASE_CHANNEL: stable + command: yarn test-www --maxWorkers=2 + + test_source_www_variant: + docker: *docker + environment: *environment + steps: + - checkout + - *restore_yarn_cache + - *run_yarn + - run: + environment: + RELEASE_CHANNEL: stable + command: yarn test-www-variant --maxWorkers=2 + + test_source_www_prod: + docker: *docker + environment: *environment + steps: + - checkout + - *restore_yarn_cache + - *run_yarn + - run: + environment: + NODE_ENV: production + RELEASE_CHANNEL: stable + command: yarn test-www --maxWorkers=2 + + test_source_www_variant_prod: + docker: *docker + environment: *environment + steps: + - checkout + - *restore_yarn_cache + - *run_yarn + - run: + environment: + NODE_ENV: production + RELEASE_CHANNEL: stable + command: yarn test-www-variant --maxWorkers=2 + + test_source_www_experimental: + docker: *docker + environment: *environment + steps: + - checkout + - *restore_yarn_cache + - *run_yarn + - run: + environment: + RELEASE_CHANNEL: experimental + command: yarn test-www --maxWorkers=2 + + test_source_www_variant_experimental: + docker: *docker + environment: *environment + steps: + - checkout + - *restore_yarn_cache + - *run_yarn + - run: + environment: + RELEASE_CHANNEL: experimental + command: yarn test-www-variant --maxWorkers=2 + + test_source_www_prod_experimental: + docker: *docker + environment: *environment + steps: + - checkout + - *restore_yarn_cache + - *run_yarn + - run: + environment: + NODE_ENV: production + RELEASE_CHANNEL: experimental + command: yarn test-www --maxWorkers=2 + + test_source_www_variant_prod_experimental: + docker: *docker + environment: *environment + steps: + - checkout + - *restore_yarn_cache + - *run_yarn + - run: + environment: + NODE_ENV: production + RELEASE_CHANNEL: experimental + command: yarn test-www-variant --maxWorkers=2 + test_source_persistent: docker: *docker environment: *environment @@ -384,6 +484,18 @@ workflows: - test_source_persistent: requires: - setup + - test_source_www: + requires: + - setup + - test_source_www_variant: + requires: + - setup + - test_source_www_prod: + requires: + - setup + - test_source_www_variant_prod: + requires: + - setup - build: requires: - setup @@ -415,6 +527,18 @@ workflows: - test_source_prod_experimental: requires: - setup + - test_source_www_experimental: + requires: + - setup + - test_source_www_variant_experimental: + requires: + - setup + - test_source_www_prod_experimental: + requires: + - setup + - test_source_www_variant_prod_experimental: + requires: + - setup - build_experimental: requires: - setup diff --git a/.eslintrc.js b/.eslintrc.js index b10d30525c198..112b17120f065 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -11,10 +11,7 @@ const OFF = 0; const ERROR = 2; module.exports = { - extends: [ - 'fbjs', - 'prettier' - ], + extends: ['fbjs', 'prettier'], // Stop ESLint from looking for a configuration file in parent folders root: true, @@ -147,7 +144,7 @@ module.exports = { 'scripts/**/*.js', 'packages/*/npm/**/*.js', 'packages/dom-event-testing-library/**/*.js', - 'packages/react-devtools*/**/*.js' + 'packages/react-devtools*/**/*.js', ], rules: { 'react-internal/no-production-logging': OFF, @@ -171,6 +168,7 @@ module.exports = { __PROFILE__: true, __UMD__: true, __EXPERIMENTAL__: true, + __VARIANT__: true, trustedTypes: true, }, }; diff --git a/package.json b/package.json index 42fa148eb0714..bc48ac2fc5719 100644 --- a/package.json +++ b/package.json @@ -108,6 +108,8 @@ "postinstall": "node node_modules/fbjs-scripts/node/check-dev-engines.js package.json && node ./scripts/flow/createFlowConfigs.js && node ./scripts/yarn/downloadReactIsForPrettyFormat.js", "debug-test": "cross-env NODE_ENV=development node --inspect-brk node_modules/jest/bin/jest.js --config ./scripts/jest/config.source.js --runInBand", "test": "cross-env NODE_ENV=development jest --config ./scripts/jest/config.source.js", + "test-www": "cross-env NODE_ENV=development jest --config ./scripts/jest/config.source-www.js", + "test-www-variant": "cross-env NODE_ENV=development VARIANT=true jest --config ./scripts/jest/config.source-www.js", "test-persistent": "cross-env NODE_ENV=development jest --config ./scripts/jest/config.source-persistent.js", "debug-test-persistent": "cross-env NODE_ENV=development node --inspect-brk node_modules/jest/bin/jest.js --config ./scripts/jest/config.source-persistent.js --runInBand", "test-prod": "cross-env NODE_ENV=production jest --config ./scripts/jest/config.source.js", diff --git a/packages/react-dom/src/__tests__/ReactServerRendering-test.js b/packages/react-dom/src/__tests__/ReactServerRendering-test.js index bcefcdb652468..b920a025eae85 100644 --- a/packages/react-dom/src/__tests__/ReactServerRendering-test.js +++ b/packages/react-dom/src/__tests__/ReactServerRendering-test.js @@ -14,6 +14,8 @@ let React; let ReactDOMServer; let PropTypes; let ReactCurrentDispatcher; +let enableSuspenseServerRenderer = require('shared/ReactFeatureFlags') + .enableSuspenseServerRenderer; function normalizeCodeLocInfo(str) { return str && str.replace(/\(at .+?:\d+\)/g, '(at **)'); @@ -686,7 +688,7 @@ describe('ReactDOMServer', () => { expect(markup).toBe('
'); }); - if (!__EXPERIMENTAL__) { + if (!enableSuspenseServerRenderer) { it('throws for unsupported types on the server', () => { expect(() => { ReactDOMServer.renderToString(); diff --git a/packages/react-reconciler/src/ReactFiber.js b/packages/react-reconciler/src/ReactFiber.js index 719544533b39b..4ff3aa45d27af 100644 --- a/packages/react-reconciler/src/ReactFiber.js +++ b/packages/react-reconciler/src/ReactFiber.js @@ -973,10 +973,10 @@ export function assignFiberPropertiesInDEV( } if (enableUserTimingAPI) { target._debugID = source._debugID; + target._debugIsCurrentlyTiming = source._debugIsCurrentlyTiming; } target._debugSource = source._debugSource; target._debugOwner = source._debugOwner; - target._debugIsCurrentlyTiming = source._debugIsCurrentlyTiming; target._debugNeedsRemount = source._debugNeedsRemount; target._debugHookTypes = source._debugHookTypes; return target; diff --git a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js new file mode 100644 index 0000000000000..007577a1f4bc7 --- /dev/null +++ b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js @@ -0,0 +1,32 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict + */ + +// In www, these flags are controlled by GKs. Because most GKs have some +// population running in either mode, we should run our tests that way, too, +// +// Use __VARIANT__ to simulate a GK. The tests will be run twice: once +// with the __VARIANT__ set to `true`, and once set to `false`. + +export const deferPassiveEffectCleanupDuringUnmount = __VARIANT__; +export const runAllPassiveEffectDestroysBeforeCreates = __VARIANT__; +export const warnAboutSpreadingKeyToJSX = __VARIANT__; + +// These are already tested in both modes using the build type dimension, +// so we don't need to use __VARIANT__ to get extra coverage. +export const debugRenderPhaseSideEffectsForStrictMode = __DEV__; +export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__; + +// TODO: These flags are hard-coded to the default values used in open source. +// Update the tests so that they pass in either mode, then set these +// to __VARIANT__. +export const enableTrustedTypesIntegration = false; +export const warnAboutShorthandPropertyCollision = true; +export const disableInputAttributeSyncing = false; +export const disableSchedulerTimeoutBasedOnReactExpirationTime = false; +export const enableModernEventSystem = false; diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index 1f6840be998d7..e9919256bc12b 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -9,8 +9,11 @@ import typeof * as FeatureFlagsType from 'shared/ReactFeatureFlags'; import typeof * as ExportsType from './ReactFeatureFlags.www'; +import typeof * as DynamicFeatureFlags from './ReactFeatureFlags.www-dynamic'; // Re-export dynamic flags from the www version. +const dynamicFeatureFlags: DynamicFeatureFlags = require('ReactFeatureFlags'); + export const { debugRenderPhaseSideEffectsForStrictMode, deferPassiveEffectCleanupDuringUnmount, @@ -20,8 +23,9 @@ export const { warnAboutShorthandPropertyCollision, disableSchedulerTimeoutBasedOnReactExpirationTime, warnAboutSpreadingKeyToJSX, + replayFailedUnitOfWorkWithInvokeGuardedCallback, enableModernEventSystem, -} = require('ReactFeatureFlags'); +} = dynamicFeatureFlags; // On WWW, __EXPERIMENTAL__ is used for a new modern build. // It's not used anywhere in production yet. @@ -39,7 +43,6 @@ export const enableProfilerCommitHooks = false; export const enableSchedulerTracing = __PROFILE__; export const enableSchedulerDebugging = true; -export const replayFailedUnitOfWorkWithInvokeGuardedCallback = false; export const warnAboutDeprecatedLifecycles = true; export const disableLegacyContext = __EXPERIMENTAL__; export const warnAboutStringRefs = false; diff --git a/scripts/flow/environment.js b/scripts/flow/environment.js index 524cae905bc2e..270f1c4c9451d 100644 --- a/scripts/flow/environment.js +++ b/scripts/flow/environment.js @@ -12,6 +12,7 @@ declare var __PROFILE__: boolean; declare var __UMD__: boolean; declare var __EXPERIMENTAL__: boolean; +declare var __VARIANT__: boolean; declare var __REACT_DEVTOOLS_GLOBAL_HOOK__: any; /*?{ inject: ?((stuff: Object) => void) diff --git a/scripts/jest/config.source-www.js b/scripts/jest/config.source-www.js new file mode 100644 index 0000000000000..0d79c83bbebb0 --- /dev/null +++ b/scripts/jest/config.source-www.js @@ -0,0 +1,36 @@ +'use strict'; + +const baseConfig = require('./config.base'); + +const RELEASE_CHANNEL = process.env.RELEASE_CHANNEL; + +// Default to building in experimental mode. If the release channel is set via +// an environment variable, then check if it's "experimental". +const __EXPERIMENTAL__ = + typeof RELEASE_CHANNEL === 'string' + ? RELEASE_CHANNEL === 'experimental' + : true; + +const preferredExtension = __EXPERIMENTAL__ ? '.js' : '.stable.js'; + +const moduleNameMapper = {}; +moduleNameMapper[ + '^react$' +] = `/packages/react/index${preferredExtension}`; +moduleNameMapper[ + '^react-dom$' +] = `/packages/react-dom/index${preferredExtension}`; + +module.exports = Object.assign({}, baseConfig, { + // Prefer the stable forks for tests. + moduleNameMapper, + modulePathIgnorePatterns: [ + ...baseConfig.modulePathIgnorePatterns, + 'packages/react-devtools-shared', + ], + setupFiles: [ + ...baseConfig.setupFiles, + require.resolve('./setupHostConfigs.js'), + require.resolve('./setupTests.www.js'), + ], +}); diff --git a/scripts/jest/setupEnvironment.js b/scripts/jest/setupEnvironment.js index 7eef6432e73cf..456645cddaba9 100644 --- a/scripts/jest/setupEnvironment.js +++ b/scripts/jest/setupEnvironment.js @@ -17,6 +17,8 @@ global.__EXPERIMENTAL__ = ? RELEASE_CHANNEL === 'experimental' : true; +global.__VARIANT__ = !!process.env.VARIANT; + if (typeof window !== 'undefined') { global.requestIdleCallback = function(callback) { return setTimeout(() => { diff --git a/scripts/jest/setupTests.www.js b/scripts/jest/setupTests.www.js new file mode 100644 index 0000000000000..82cebc15bd247 --- /dev/null +++ b/scripts/jest/setupTests.www.js @@ -0,0 +1,23 @@ +'use strict'; + +jest.mock('shared/ReactFeatureFlags', () => { + jest.mock( + 'ReactFeatureFlags', + () => jest.requireActual('shared/forks/ReactFeatureFlags.www-dynamic'), + {virtual: true} + ); + + const wwwFlags = jest.requireActual('shared/forks/ReactFeatureFlags.www'); + const defaultFlags = jest.requireActual('shared/ReactFeatureFlags'); + + // TODO: Many tests were written before we started running them against the + // www configuration. Update those tests so that they work against the www + // configuration, too. Then remove these overrides. + wwwFlags.disableLegacyContext = defaultFlags.disableLegacyContext; + wwwFlags.warnAboutUnmockedScheduler = defaultFlags.warnAboutUnmockedScheduler; + wwwFlags.enableUserTimingAPI = defaultFlags.enableUserTimingAPI; + wwwFlags.disableJavaScriptURLs = defaultFlags.disableJavaScriptURLs; + wwwFlags.enableDeprecatedFlareAPI = defaultFlags.enableDeprecatedFlareAPI; + + return wwwFlags; +}); diff --git a/scripts/rollup/build.js b/scripts/rollup/build.js index c3e7d8c7c73a8..cfc967249bf07 100644 --- a/scripts/rollup/build.js +++ b/scripts/rollup/build.js @@ -391,6 +391,7 @@ function getPlugins( __UMD__: isUMDBundle ? 'true' : 'false', 'process.env.NODE_ENV': isProduction ? "'production'" : "'development'", __EXPERIMENTAL__, + __VARIANT__: false, }), // The CommonJS plugin *only* exists to pull "art" into "react-art". // I'm going to port "art" to ES modules to avoid this problem.