2016-11-14 06:00:07 +08:00
|
|
|
'use strict';
|
|
|
|
|
2018-11-09 01:56:35 +08:00
|
|
|
const {
|
|
|
|
es5Paths,
|
|
|
|
esNextPaths,
|
|
|
|
} = require('./scripts/shared/pathsByLanguageVersion');
|
|
|
|
|
2020-02-20 01:14:53 +08:00
|
|
|
const restrictedGlobals = require('confusing-browser-globals');
|
|
|
|
|
2016-03-02 07:40:52 +08:00
|
|
|
const OFF = 0;
|
|
|
|
const ERROR = 2;
|
|
|
|
|
|
|
|
module.exports = {
|
Add test run that uses www feature flags (#18234)
In CI, we run our test suite against multiple build configurations. For
example, we run our tests in both dev and prod, and in both the
experimental and stable release channels. This is to prevent accidental
deviations in behavior between the different builds. If there's an
intentional deviation in behavior, the test author must account
for them.
However, we currently don't run tests against the www builds. That's
a problem, because it's common for features to land in www before they
land anywhere else, including the experimental release channel.
Typically we do this so we can gradually roll out the feature behind
a flag before deciding to enable it.
The way we test those features today is by mutating the
`shared/ReactFeatureFlags` module. There are a few downsides to this
approach, though. The flag is only overridden for the specific tests or
test suites where you apply the override. But usually what you want is
to run *all* tests with the flag enabled, to protect against unexpected
regressions.
Also, mutating the feature flags module only works when running the
tests against source, not against the final build artifacts, because the
ReactFeatureFlags module is inlined by the build script.
Instead, we should run the test suite against the www configuration,
just like we do for prod, experimental, and so on. I've added a new
command, `yarn test-www`. It automatically runs in CI.
Some of the www feature flags are dynamic; that is, they depend on
a runtime condition (i.e. a GK). These flags are imported from an
external module that lives in www. Those flags will be enabled for some
clients and disabled for others, so we should run the tests against
*both* modes.
So I've added a new global `__VARIANT__`, and a new test command `yarn
test-www-variant`. `__VARIANT__` is set to false by default; when
running `test-www-variant`, it's set to true.
If we were going for *really* comprehensive coverage, we would run the
tests against every possible configuration of feature flags: 2 ^
numberOfFlags total combinations. That's not practical, though, so
instead we only run against two combinations: once with `__VARIANT__`
set to `true`, and once with it set to `false`. We generally assume that
flags can be toggled independently, so in practice this should
be enough.
You can also refer to `__VARIANT__` in tests to detect which mode you're
running in. Or, you can import `shared/ReactFeatureFlags` and read the
specific flag you can about. However, we should stop mutating that
module going forward. Treat it as read-only.
In this commit, I have only setup the www tests to run against source.
I'll leave running against build for a follow up.
Many of our tests currently assume they run only in the default
configuration, and break when certain flags are toggled. Rather than fix
these all up front, I've hard-coded the relevant flags to the default
values. We can incrementally migrate those tests later.
2020-03-07 01:29:05 +08:00
|
|
|
extends: ['fbjs', 'prettier'],
|
2016-03-02 07:40:52 +08:00
|
|
|
|
2017-11-29 06:56:29 +08:00
|
|
|
// Stop ESLint from looking for a configuration file in parent folders
|
2019-08-10 03:59:02 +08:00
|
|
|
root: true,
|
2017-11-29 06:56:29 +08:00
|
|
|
|
2020-09-01 20:55:10 +08:00
|
|
|
plugins: [
|
|
|
|
'jest',
|
|
|
|
'no-for-of-loops',
|
|
|
|
'no-function-declare-after-return',
|
|
|
|
'react',
|
|
|
|
'react-internal',
|
|
|
|
],
|
2016-03-02 07:40:52 +08:00
|
|
|
|
2019-08-10 03:59:02 +08:00
|
|
|
parser: 'babel-eslint',
|
2018-11-09 01:56:35 +08:00
|
|
|
parserOptions: {
|
2019-08-10 03:59:02 +08:00
|
|
|
ecmaVersion: 8,
|
2018-11-09 01:56:35 +08:00
|
|
|
sourceType: 'script',
|
|
|
|
ecmaFeatures: {
|
|
|
|
experimentalObjectRestSpread: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
2016-03-02 07:40:52 +08:00
|
|
|
// We're stricter than the default config, mostly. We'll override a few rules
|
|
|
|
// and then enable some React specific ones.
|
|
|
|
rules: {
|
|
|
|
'accessor-pairs': OFF,
|
|
|
|
'brace-style': [ERROR, '1tbs'],
|
2016-11-18 06:16:44 +08:00
|
|
|
'consistent-return': OFF,
|
2016-03-02 07:40:52 +08:00
|
|
|
'dot-location': [ERROR, 'property'],
|
2019-12-15 02:09:25 +08:00
|
|
|
// We use console['error']() as a signal to not transform it:
|
|
|
|
'dot-notation': [ERROR, {allowPattern: '^(error|warn)$'}],
|
2016-03-02 07:40:52 +08:00
|
|
|
'eol-last': ERROR,
|
2019-08-10 03:59:02 +08:00
|
|
|
eqeqeq: [ERROR, 'allow-null'],
|
|
|
|
indent: OFF,
|
2016-03-02 07:40:52 +08:00
|
|
|
'jsx-quotes': [ERROR, 'prefer-double'],
|
2016-11-18 06:16:44 +08:00
|
|
|
'keyword-spacing': [ERROR, {after: true, before: true}],
|
2016-03-02 07:40:52 +08:00
|
|
|
'no-bitwise': OFF,
|
2020-10-16 23:06:08 +08:00
|
|
|
'no-console': OFF,
|
2016-06-05 04:37:57 +08:00
|
|
|
'no-inner-declarations': [ERROR, 'functions'],
|
2016-03-02 07:40:52 +08:00
|
|
|
'no-multi-spaces': ERROR,
|
2020-02-20 01:14:53 +08:00
|
|
|
'no-restricted-globals': [ERROR].concat(restrictedGlobals),
|
2016-03-02 07:40:52 +08:00
|
|
|
'no-restricted-syntax': [ERROR, 'WithStatement'],
|
|
|
|
'no-shadow': ERROR,
|
|
|
|
'no-unused-expressions': ERROR,
|
|
|
|
'no-unused-vars': [ERROR, {args: 'none'}],
|
2019-08-10 03:59:02 +08:00
|
|
|
'no-use-before-define': OFF,
|
2017-03-15 05:12:35 +08:00
|
|
|
'no-useless-concat': OFF,
|
2019-08-10 03:59:02 +08:00
|
|
|
quotes: [ERROR, 'single', {avoidEscape: true, allowTemplateLiterals: true}],
|
2016-03-02 07:40:52 +08:00
|
|
|
'space-before-blocks': ERROR,
|
2017-03-15 05:12:35 +08:00
|
|
|
'space-before-function-paren': OFF,
|
2018-08-21 00:28:04 +08:00
|
|
|
'valid-typeof': [ERROR, {requireStringLiterals: true}],
|
2020-10-16 23:06:08 +08:00
|
|
|
// Flow fails with with non-string literal keys
|
|
|
|
'no-useless-computed-key': OFF,
|
2016-03-02 07:40:52 +08:00
|
|
|
|
2018-11-09 01:56:35 +08:00
|
|
|
// We apply these settings to files that should run on Node.
|
|
|
|
// They can't use JSX or ES6 modules, and must be in strict mode.
|
|
|
|
// They can, however, use other ES6 features.
|
|
|
|
// (Note these rules are overridden later for source files.)
|
|
|
|
'no-var': ERROR,
|
|
|
|
strict: ERROR,
|
|
|
|
|
2019-08-10 03:59:02 +08:00
|
|
|
// Enforced by Prettier
|
|
|
|
// TODO: Prettier doesn't handle long strings or long comments. Not a big
|
|
|
|
// deal. But I turned it off because loading the plugin causes some obscure
|
|
|
|
// syntax error and it didn't seem worth investigating.
|
|
|
|
'max-len': OFF,
|
2020-10-16 23:06:08 +08:00
|
|
|
// Prettier forces semicolons in a few places
|
|
|
|
'flowtype/object-type-delimiter': OFF,
|
2019-08-10 03:59:02 +08:00
|
|
|
|
2016-03-02 07:40:52 +08:00
|
|
|
// React & JSX
|
|
|
|
// Our transforms set this automatically
|
|
|
|
'react/jsx-boolean-value': [ERROR, 'always'],
|
|
|
|
'react/jsx-no-undef': ERROR,
|
|
|
|
// We don't care to do this
|
|
|
|
'react/jsx-sort-prop-types': OFF,
|
2017-03-01 01:03:08 +08:00
|
|
|
'react/jsx-space-before-closing': ERROR,
|
2016-03-02 07:40:52 +08:00
|
|
|
'react/jsx-uses-react': ERROR,
|
2016-11-18 06:16:44 +08:00
|
|
|
'react/no-is-mounted': OFF,
|
2016-03-02 07:40:52 +08:00
|
|
|
// This isn't useful in our test code
|
|
|
|
'react/react-in-jsx-scope': ERROR,
|
|
|
|
'react/self-closing-comp': ERROR,
|
|
|
|
// We don't care to do this
|
2019-08-10 03:59:02 +08:00
|
|
|
'react/jsx-wrap-multilines': [
|
|
|
|
ERROR,
|
|
|
|
{declaration: false, assignment: false},
|
|
|
|
],
|
2016-03-02 07:40:52 +08:00
|
|
|
|
2018-02-10 00:11:22 +08:00
|
|
|
// Prevent for...of loops because they require a Symbol polyfill.
|
|
|
|
// You can disable this rule for code that isn't shipped (e.g. build scripts and tests).
|
|
|
|
'no-for-of-loops/no-for-of-loops': ERROR,
|
|
|
|
|
2020-09-01 20:55:10 +08:00
|
|
|
// Prevent function declarations after return statements
|
|
|
|
'no-function-declare-after-return/no-function-declare-after-return': ERROR,
|
|
|
|
|
2016-03-02 07:40:52 +08:00
|
|
|
// CUSTOM RULES
|
|
|
|
// the second argument of warning/invariant should be a literal string
|
2017-03-01 07:59:45 +08:00
|
|
|
'react-internal/no-primitive-constructors': ERROR,
|
Improve DEV errors if string coercion throws (Temporal.*, Symbol, etc.) (#22064)
* Revise ESLint rules for string coercion
Currently, react uses `'' + value` to coerce mixed values to strings.
This code will throw for Temporal objects or symbols.
To make string-coercion safer and to improve user-facing error messages,
This commit adds a new ESLint rule called `safe-string-coercion`.
This rule has two modes: a production mode and a non-production mode.
* If the `isProductionUserAppCode` option is true, then `'' + value`
coercions are allowed (because they're faster, although they may
throw) and `String(value)` coercions are disallowed. Exception:
when building error messages or running DEV-only code in prod
files, `String()` should be used because it won't throw.
* If the `isProductionUserAppCode` option is false, then `'' + value`
coercions are disallowed (because they may throw, and in non-prod
code it's not worth the risk) and `String(value)` are allowed.
Production mode is used for all files which will be bundled with
developers' userland apps. Non-prod mode is used for all other React
code: tests, DEV blocks, devtools extension, etc.
In production mode, in addiiton to flagging `String(value)` calls,
the rule will also flag `'' + value` or `value + ''` coercions that may
throw. The rule is smart enough to silence itself in the following
"will never throw" cases:
* When the coercion is wrapped in a `typeof` test that restricts to safe
(non-symbol, non-object) types. Example:
if (typeof value === 'string' || typeof value === 'number') {
thisWontReport('' + value);
}
* When what's being coerced is a unary function result, because unary
functions never return an object or a symbol.
* When the coerced value is a commonly-used numeric identifier:
`i`, `idx`, or `lineNumber`.
* When the statement immeidately before the coercion is a DEV-only
call to a function from shared/CheckStringCoercion.js. This call is a
no-op in production, but in DEV it will show a console error
explaining the problem, then will throw right after a long explanatory
code comment so that debugger users will have an idea what's going on.
The check function call must be in the following format:
if (__DEV__) {
checkXxxxxStringCoercion(value);
};
Manually disabling the rule is usually not necessary because almost all
prod use of the `'' + value` pattern falls into one of the categories
above. But in the rare cases where the rule isn't smart enough to detect
safe usage (e.g. when a coercion is inside a nested ternary operator),
manually disabling the rule will be needed.
The rule should also be manually disabled in prod error handling code
where `String(value)` should be used for coercions, because it'd be
bad to throw while building an error message or stack trace!
The prod and non-prod modes have differentiated error messages to
explain how to do a proper coercion in that mode.
If a production check call is needed but is missing or incorrect
(e.g. not in a DEV block or not immediately before the coercion), then
a context-sensitive error message will be reported so that developers
can figure out what's wrong and how to fix the problem.
Because string coercions are now handled by the `safe-string-coercion`
rule, the `no-primitive-constructor` rule no longer flags `String()`
usage. It still flags `new String(value)` because that usage is almost
always a bug.
* Add DEV-only string coercion check functions
This commit adds DEV-only functions to check whether coercing
values to strings using the `'' + value` pattern will throw. If it will
throw, these functions will:
1. Display a console error with a friendly error message describing
the problem and the developer can fix it.
2. Perform the coercion, which will throw. Right before the line where
the throwing happens, there's a long code comment that will help
debugger users (or others looking at the exception call stack) figure
out what happened and how to fix the problem.
One of these check functions should be called before all string coercion
of user-provided values, except when the the coercion is guaranteed not
to throw, e.g.
* if inside a typeof check like `if (typeof value === 'string')`
* if coercing the result of a unary function like `+value` or `value++`
* if coercing a variable named in a whitelist of numeric identifiers:
`i`, `idx`, or `lineNumber`.
The new `safe-string-coercion` internal ESLint rule enforces that
these check functions are called when they are required.
Only use these check functions in production code that will be bundled
with user apps. For non-prod code (and for production error-handling
code), use `String(value)` instead which may be a little slower but will
never throw.
* Add failing tests for string coercion
Added failing tests to verify:
* That input, select, and textarea elements with value and defaultValue
set to Temporal-like objects which will throw when coerced to string
using the `'' + value` pattern.
* That text elements will throw for Temporal-like objects
* That dangerouslySetInnerHTML will *not* throw for Temporal-like
objects because this value is not cast to a string before passing to
the DOM.
* That keys that are Temporal-like objects will throw
All tests above validate the friendly error messages thrown.
* Use `String(value)` for coercion in non-prod files
This commit switches non-production code from `'' + value` (which
throws for Temporal objects and symbols) to instead use `String(value)`
which won't throw for these or other future plus-phobic types.
"Non-produciton code" includes anything not bundled into user apps:
* Tests and test utilities. Note that I didn't change legacy React
test fixtures because I assumed it was good for those files to
act just like old React, including coercion behavior.
* Build scripts
* Dev tools package - In addition to switching to `String`, I also
removed special-case code for coercing symbols which is now
unnecessary.
* Add DEV-only string coercion checks to prod files
This commit adds DEV-only function calls to to check if string coercion
using `'' + value` will throw, which it will if the value is a Temporal
object or a symbol because those types can't be added with `+`.
If it will throw, then in DEV these checks will show a console error
to help the user undertsand what went wrong and how to fix the
problem. After emitting the console error, the check functions will
retry the coercion which will throw with a call stack that's easy (or
at least easier!) to troubleshoot because the exception happens right
after a long comment explaining the issue. So whether the user is in
a debugger, looking at the browser console, or viewing the in-browser
DEV call stack, it should be easy to understand and fix the problem.
In most cases, the safe-string-coercion ESLint rule is smart enough to
detect when a coercion is safe. But in rare cases (e.g. when a coercion
is inside a ternary) this rule will have to be manually disabled.
This commit also switches error-handling code to use `String(value)`
for coercion, because it's bad to crash when you're trying to build
an error message or a call stack! Because `String()` is usually
disallowed by the `safe-string-coercion` ESLint rule in production
code, the rule must be disabled when `String()` is used.
2021-09-28 01:05:07 +08:00
|
|
|
'react-internal/safe-string-coercion': [
|
|
|
|
ERROR,
|
|
|
|
{isProductionUserAppCode: true},
|
|
|
|
],
|
2018-08-21 22:43:02 +08:00
|
|
|
'react-internal/no-to-warn-dev-within-to-throw': ERROR,
|
2019-12-11 11:28:14 +08:00
|
|
|
'react-internal/invariant-args': ERROR,
|
|
|
|
'react-internal/warning-args': ERROR,
|
2019-12-07 02:25:54 +08:00
|
|
|
'react-internal/no-production-logging': ERROR,
|
2020-04-10 09:11:34 +08:00
|
|
|
'react-internal/no-cross-fork-imports': ERROR,
|
2020-08-25 01:07:11 +08:00
|
|
|
'react-internal/no-cross-fork-types': [
|
|
|
|
ERROR,
|
|
|
|
{
|
2021-01-23 03:49:33 +08:00
|
|
|
old: [],
|
2020-11-14 00:09:48 +08:00
|
|
|
new: [],
|
2020-08-25 01:07:11 +08:00
|
|
|
},
|
|
|
|
],
|
2016-11-14 06:00:07 +08:00
|
|
|
},
|
|
|
|
|
2018-01-10 02:55:51 +08:00
|
|
|
overrides: [
|
2018-11-09 01:56:35 +08:00
|
|
|
{
|
[RFC] Codemod invariant -> throw new Error (#22435)
* Hoist error codes import to module scope
When this code was written, the error codes map (`codes.json`) was
created on-the-fly, so we had to lazily require from inside the visitor.
Because `codes.json` is now checked into source, we can import it a
single time in module scope.
* Minify error constructors in production
We use a script to minify our error messages in production. Each message
is assigned an error code, defined in `scripts/error-codes/codes.json`.
Then our build script replaces the messages with a link to our
error decoder page, e.g. https://reactjs.org/docs/error-decoder.html/?invariant=92
This enables us to write helpful error messages without increasing the
bundle size.
Right now, the script only works for `invariant` calls. It does not work
if you throw an Error object. This is an old Facebookism that we don't
really need, other than the fact that our error minification script
relies on it.
So, I've updated the script to minify error constructors, too:
Input:
Error(`A ${adj} message that contains ${noun}`);
Output:
Error(formatProdErrorMessage(ERR_CODE, adj, noun));
It only works for constructors that are literally named Error, though we
could add support for other names, too.
As a next step, I will add a lint rule to enforce that errors written
this way must have a corresponding error code.
* Minify "no fallback UI specified" error in prod
This error message wasn't being minified because it doesn't use
invariant. The reason it didn't use invariant is because this particular
error is created without begin thrown — it doesn't need to be thrown
because it's located inside the error handling part of the runtime.
Now that the error minification script supports Error constructors, we
can minify it by assigning it a production error code in
`scripts/error-codes/codes.json`.
To support the use of Error constructors more generally, I will add a
lint rule that enforces each message has a corresponding error code.
* Lint rule to detect unminified errors
Adds a lint rule that detects when an Error constructor is used without
a corresponding production error code.
We already have this for `invariant`, but not for regular errors, i.e.
`throw new Error(msg)`. There's also nothing that enforces the use of
`invariant` besides convention.
There are some packages where we don't care to minify errors. These are
packages that run in environments where bundle size is not a concern,
like react-pg. I added an override in the ESLint config to ignore these.
* Temporarily add invariant codemod script
I'm adding this codemod to the repo temporarily, but I'll revert it
in the same PR. That way we don't have to check it in but it's still
accessible (via the PR) if we need it later.
* [Automated] Codemod invariant -> Error
This commit contains only automated changes:
npx jscodeshift -t scripts/codemod-invariant.js packages --ignore-pattern="node_modules/**/*"
yarn linc --fix
yarn prettier
I will do any manual touch ups in separate commits so they're easier
to review.
* Remove temporary codemod script
This reverts the codemod script and ESLint config I added temporarily
in order to perform the invariant codemod.
* Manual touch ups
A few manual changes I made after the codemod ran.
* Enable error code transform per package
Currently we're not consistent about which packages should have their
errors minified in production and which ones should.
This adds a field to the bundle configuration to control whether to
apply the transform. We should decide what the criteria is going
forward. I think it's probably a good idea to minify any package that
gets sent over the network. So yes to modules that run in the browser,
and no to modules that run on the server and during development only.
2021-10-01 03:01:28 +08:00
|
|
|
// By default, anything error message that appears the packages directory
|
|
|
|
// must have a corresponding error code. The exceptions are defined
|
|
|
|
// in the next override entry.
|
|
|
|
files: ['packages/**/*.js'],
|
|
|
|
rules: {
|
|
|
|
'react-internal/prod-error-codes': ERROR,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// These are files where it's OK to have unminified error messages. These
|
|
|
|
// are environments where bundle size isn't a concern, like tests
|
|
|
|
// or Node.
|
|
|
|
files: [
|
|
|
|
'packages/react-dom/src/test-utils/**/*.js',
|
|
|
|
'packages/react-devtools-shared/**/*.js',
|
|
|
|
'packages/react-noop-renderer/**/*.js',
|
|
|
|
'packages/react-pg/**/*.js',
|
|
|
|
'packages/react-fs/**/*.js',
|
|
|
|
'packages/react-refresh/**/*.js',
|
|
|
|
'packages/react-server-dom-webpack/**/*.js',
|
|
|
|
'packages/react-test-renderer/**/*.js',
|
|
|
|
'packages/react-debug-tools/**/*.js',
|
|
|
|
'packages/react-devtools-extensions/**/*.js',
|
|
|
|
'packages/react-devtools-scheduling-profiler/**/*.js',
|
|
|
|
'packages/react-native-renderer/**/*.js',
|
|
|
|
'packages/eslint-plugin-react-hooks/**/*.js',
|
|
|
|
'packages/jest-react/**/*.js',
|
|
|
|
'packages/**/__tests__/*.js',
|
|
|
|
'packages/**/npm/*.js',
|
|
|
|
],
|
|
|
|
rules: {
|
|
|
|
'react-internal/prod-error-codes': OFF,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
2018-11-09 01:56:35 +08:00
|
|
|
// We apply these settings to files that we ship through npm.
|
|
|
|
// They must be ES5.
|
|
|
|
files: es5Paths,
|
|
|
|
parser: 'espree',
|
|
|
|
parserOptions: {
|
|
|
|
ecmaVersion: 5,
|
|
|
|
sourceType: 'script',
|
|
|
|
},
|
|
|
|
rules: {
|
|
|
|
'no-var': OFF,
|
|
|
|
strict: ERROR,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// We apply these settings to the source files that get compiled.
|
|
|
|
// They can use all features including JSX (but shouldn't use `var`).
|
|
|
|
files: esNextPaths,
|
|
|
|
parser: 'babel-eslint',
|
|
|
|
parserOptions: {
|
2019-08-10 03:59:02 +08:00
|
|
|
ecmaVersion: 8,
|
2018-11-09 01:56:35 +08:00
|
|
|
sourceType: 'module',
|
|
|
|
},
|
|
|
|
rules: {
|
|
|
|
'no-var': ERROR,
|
2020-04-02 03:35:52 +08:00
|
|
|
'prefer-const': ERROR,
|
2018-11-09 01:56:35 +08:00
|
|
|
strict: OFF,
|
|
|
|
},
|
|
|
|
},
|
2018-01-10 02:55:51 +08:00
|
|
|
{
|
|
|
|
files: ['**/__tests__/*.js'],
|
|
|
|
rules: {
|
|
|
|
// https://github.com/jest-community/eslint-plugin-jest
|
|
|
|
'jest/no-focused-tests': ERROR,
|
2019-08-14 18:51:01 +08:00
|
|
|
'jest/valid-expect': ERROR,
|
|
|
|
'jest/valid-expect-in-promise': ERROR,
|
2019-08-10 03:59:02 +08:00
|
|
|
},
|
2019-04-30 05:31:16 +08:00
|
|
|
},
|
2019-12-15 02:09:25 +08:00
|
|
|
{
|
|
|
|
files: [
|
|
|
|
'**/__tests__/**/*.js',
|
|
|
|
'scripts/**/*.js',
|
|
|
|
'packages/*/npm/**/*.js',
|
2019-12-20 00:51:25 +08:00
|
|
|
'packages/dom-event-testing-library/**/*.js',
|
Add test run that uses www feature flags (#18234)
In CI, we run our test suite against multiple build configurations. For
example, we run our tests in both dev and prod, and in both the
experimental and stable release channels. This is to prevent accidental
deviations in behavior between the different builds. If there's an
intentional deviation in behavior, the test author must account
for them.
However, we currently don't run tests against the www builds. That's
a problem, because it's common for features to land in www before they
land anywhere else, including the experimental release channel.
Typically we do this so we can gradually roll out the feature behind
a flag before deciding to enable it.
The way we test those features today is by mutating the
`shared/ReactFeatureFlags` module. There are a few downsides to this
approach, though. The flag is only overridden for the specific tests or
test suites where you apply the override. But usually what you want is
to run *all* tests with the flag enabled, to protect against unexpected
regressions.
Also, mutating the feature flags module only works when running the
tests against source, not against the final build artifacts, because the
ReactFeatureFlags module is inlined by the build script.
Instead, we should run the test suite against the www configuration,
just like we do for prod, experimental, and so on. I've added a new
command, `yarn test-www`. It automatically runs in CI.
Some of the www feature flags are dynamic; that is, they depend on
a runtime condition (i.e. a GK). These flags are imported from an
external module that lives in www. Those flags will be enabled for some
clients and disabled for others, so we should run the tests against
*both* modes.
So I've added a new global `__VARIANT__`, and a new test command `yarn
test-www-variant`. `__VARIANT__` is set to false by default; when
running `test-www-variant`, it's set to true.
If we were going for *really* comprehensive coverage, we would run the
tests against every possible configuration of feature flags: 2 ^
numberOfFlags total combinations. That's not practical, though, so
instead we only run against two combinations: once with `__VARIANT__`
set to `true`, and once with it set to `false`. We generally assume that
flags can be toggled independently, so in practice this should
be enough.
You can also refer to `__VARIANT__` in tests to detect which mode you're
running in. Or, you can import `shared/ReactFeatureFlags` and read the
specific flag you can about. However, we should stop mutating that
module going forward. Treat it as read-only.
In this commit, I have only setup the www tests to run against source.
I'll leave running against build for a follow up.
Many of our tests currently assume they run only in the default
configuration, and break when certain flags are toggled. Rather than fix
these all up front, I've hard-coded the relevant flags to the default
values. We can incrementally migrate those tests later.
2020-03-07 01:29:05 +08:00
|
|
|
'packages/react-devtools*/**/*.js',
|
Improve DEV errors if string coercion throws (Temporal.*, Symbol, etc.) (#22064)
* Revise ESLint rules for string coercion
Currently, react uses `'' + value` to coerce mixed values to strings.
This code will throw for Temporal objects or symbols.
To make string-coercion safer and to improve user-facing error messages,
This commit adds a new ESLint rule called `safe-string-coercion`.
This rule has two modes: a production mode and a non-production mode.
* If the `isProductionUserAppCode` option is true, then `'' + value`
coercions are allowed (because they're faster, although they may
throw) and `String(value)` coercions are disallowed. Exception:
when building error messages or running DEV-only code in prod
files, `String()` should be used because it won't throw.
* If the `isProductionUserAppCode` option is false, then `'' + value`
coercions are disallowed (because they may throw, and in non-prod
code it's not worth the risk) and `String(value)` are allowed.
Production mode is used for all files which will be bundled with
developers' userland apps. Non-prod mode is used for all other React
code: tests, DEV blocks, devtools extension, etc.
In production mode, in addiiton to flagging `String(value)` calls,
the rule will also flag `'' + value` or `value + ''` coercions that may
throw. The rule is smart enough to silence itself in the following
"will never throw" cases:
* When the coercion is wrapped in a `typeof` test that restricts to safe
(non-symbol, non-object) types. Example:
if (typeof value === 'string' || typeof value === 'number') {
thisWontReport('' + value);
}
* When what's being coerced is a unary function result, because unary
functions never return an object or a symbol.
* When the coerced value is a commonly-used numeric identifier:
`i`, `idx`, or `lineNumber`.
* When the statement immeidately before the coercion is a DEV-only
call to a function from shared/CheckStringCoercion.js. This call is a
no-op in production, but in DEV it will show a console error
explaining the problem, then will throw right after a long explanatory
code comment so that debugger users will have an idea what's going on.
The check function call must be in the following format:
if (__DEV__) {
checkXxxxxStringCoercion(value);
};
Manually disabling the rule is usually not necessary because almost all
prod use of the `'' + value` pattern falls into one of the categories
above. But in the rare cases where the rule isn't smart enough to detect
safe usage (e.g. when a coercion is inside a nested ternary operator),
manually disabling the rule will be needed.
The rule should also be manually disabled in prod error handling code
where `String(value)` should be used for coercions, because it'd be
bad to throw while building an error message or stack trace!
The prod and non-prod modes have differentiated error messages to
explain how to do a proper coercion in that mode.
If a production check call is needed but is missing or incorrect
(e.g. not in a DEV block or not immediately before the coercion), then
a context-sensitive error message will be reported so that developers
can figure out what's wrong and how to fix the problem.
Because string coercions are now handled by the `safe-string-coercion`
rule, the `no-primitive-constructor` rule no longer flags `String()`
usage. It still flags `new String(value)` because that usage is almost
always a bug.
* Add DEV-only string coercion check functions
This commit adds DEV-only functions to check whether coercing
values to strings using the `'' + value` pattern will throw. If it will
throw, these functions will:
1. Display a console error with a friendly error message describing
the problem and the developer can fix it.
2. Perform the coercion, which will throw. Right before the line where
the throwing happens, there's a long code comment that will help
debugger users (or others looking at the exception call stack) figure
out what happened and how to fix the problem.
One of these check functions should be called before all string coercion
of user-provided values, except when the the coercion is guaranteed not
to throw, e.g.
* if inside a typeof check like `if (typeof value === 'string')`
* if coercing the result of a unary function like `+value` or `value++`
* if coercing a variable named in a whitelist of numeric identifiers:
`i`, `idx`, or `lineNumber`.
The new `safe-string-coercion` internal ESLint rule enforces that
these check functions are called when they are required.
Only use these check functions in production code that will be bundled
with user apps. For non-prod code (and for production error-handling
code), use `String(value)` instead which may be a little slower but will
never throw.
* Add failing tests for string coercion
Added failing tests to verify:
* That input, select, and textarea elements with value and defaultValue
set to Temporal-like objects which will throw when coerced to string
using the `'' + value` pattern.
* That text elements will throw for Temporal-like objects
* That dangerouslySetInnerHTML will *not* throw for Temporal-like
objects because this value is not cast to a string before passing to
the DOM.
* That keys that are Temporal-like objects will throw
All tests above validate the friendly error messages thrown.
* Use `String(value)` for coercion in non-prod files
This commit switches non-production code from `'' + value` (which
throws for Temporal objects and symbols) to instead use `String(value)`
which won't throw for these or other future plus-phobic types.
"Non-produciton code" includes anything not bundled into user apps:
* Tests and test utilities. Note that I didn't change legacy React
test fixtures because I assumed it was good for those files to
act just like old React, including coercion behavior.
* Build scripts
* Dev tools package - In addition to switching to `String`, I also
removed special-case code for coercing symbols which is now
unnecessary.
* Add DEV-only string coercion checks to prod files
This commit adds DEV-only function calls to to check if string coercion
using `'' + value` will throw, which it will if the value is a Temporal
object or a symbol because those types can't be added with `+`.
If it will throw, then in DEV these checks will show a console error
to help the user undertsand what went wrong and how to fix the
problem. After emitting the console error, the check functions will
retry the coercion which will throw with a call stack that's easy (or
at least easier!) to troubleshoot because the exception happens right
after a long comment explaining the issue. So whether the user is in
a debugger, looking at the browser console, or viewing the in-browser
DEV call stack, it should be easy to understand and fix the problem.
In most cases, the safe-string-coercion ESLint rule is smart enough to
detect when a coercion is safe. But in rare cases (e.g. when a coercion
is inside a ternary) this rule will have to be manually disabled.
This commit also switches error-handling code to use `String(value)`
for coercion, because it's bad to crash when you're trying to build
an error message or a call stack! Because `String()` is usually
disallowed by the `safe-string-coercion` ESLint rule in production
code, the rule must be disabled when `String()` is used.
2021-09-28 01:05:07 +08:00
|
|
|
'dangerfile.js',
|
|
|
|
'fixtures',
|
|
|
|
'packages/react-dom/src/test-utils/*.js',
|
2019-12-15 02:09:25 +08:00
|
|
|
],
|
|
|
|
rules: {
|
|
|
|
'react-internal/no-production-logging': OFF,
|
|
|
|
'react-internal/warning-args': OFF,
|
Improve DEV errors if string coercion throws (Temporal.*, Symbol, etc.) (#22064)
* Revise ESLint rules for string coercion
Currently, react uses `'' + value` to coerce mixed values to strings.
This code will throw for Temporal objects or symbols.
To make string-coercion safer and to improve user-facing error messages,
This commit adds a new ESLint rule called `safe-string-coercion`.
This rule has two modes: a production mode and a non-production mode.
* If the `isProductionUserAppCode` option is true, then `'' + value`
coercions are allowed (because they're faster, although they may
throw) and `String(value)` coercions are disallowed. Exception:
when building error messages or running DEV-only code in prod
files, `String()` should be used because it won't throw.
* If the `isProductionUserAppCode` option is false, then `'' + value`
coercions are disallowed (because they may throw, and in non-prod
code it's not worth the risk) and `String(value)` are allowed.
Production mode is used for all files which will be bundled with
developers' userland apps. Non-prod mode is used for all other React
code: tests, DEV blocks, devtools extension, etc.
In production mode, in addiiton to flagging `String(value)` calls,
the rule will also flag `'' + value` or `value + ''` coercions that may
throw. The rule is smart enough to silence itself in the following
"will never throw" cases:
* When the coercion is wrapped in a `typeof` test that restricts to safe
(non-symbol, non-object) types. Example:
if (typeof value === 'string' || typeof value === 'number') {
thisWontReport('' + value);
}
* When what's being coerced is a unary function result, because unary
functions never return an object or a symbol.
* When the coerced value is a commonly-used numeric identifier:
`i`, `idx`, or `lineNumber`.
* When the statement immeidately before the coercion is a DEV-only
call to a function from shared/CheckStringCoercion.js. This call is a
no-op in production, but in DEV it will show a console error
explaining the problem, then will throw right after a long explanatory
code comment so that debugger users will have an idea what's going on.
The check function call must be in the following format:
if (__DEV__) {
checkXxxxxStringCoercion(value);
};
Manually disabling the rule is usually not necessary because almost all
prod use of the `'' + value` pattern falls into one of the categories
above. But in the rare cases where the rule isn't smart enough to detect
safe usage (e.g. when a coercion is inside a nested ternary operator),
manually disabling the rule will be needed.
The rule should also be manually disabled in prod error handling code
where `String(value)` should be used for coercions, because it'd be
bad to throw while building an error message or stack trace!
The prod and non-prod modes have differentiated error messages to
explain how to do a proper coercion in that mode.
If a production check call is needed but is missing or incorrect
(e.g. not in a DEV block or not immediately before the coercion), then
a context-sensitive error message will be reported so that developers
can figure out what's wrong and how to fix the problem.
Because string coercions are now handled by the `safe-string-coercion`
rule, the `no-primitive-constructor` rule no longer flags `String()`
usage. It still flags `new String(value)` because that usage is almost
always a bug.
* Add DEV-only string coercion check functions
This commit adds DEV-only functions to check whether coercing
values to strings using the `'' + value` pattern will throw. If it will
throw, these functions will:
1. Display a console error with a friendly error message describing
the problem and the developer can fix it.
2. Perform the coercion, which will throw. Right before the line where
the throwing happens, there's a long code comment that will help
debugger users (or others looking at the exception call stack) figure
out what happened and how to fix the problem.
One of these check functions should be called before all string coercion
of user-provided values, except when the the coercion is guaranteed not
to throw, e.g.
* if inside a typeof check like `if (typeof value === 'string')`
* if coercing the result of a unary function like `+value` or `value++`
* if coercing a variable named in a whitelist of numeric identifiers:
`i`, `idx`, or `lineNumber`.
The new `safe-string-coercion` internal ESLint rule enforces that
these check functions are called when they are required.
Only use these check functions in production code that will be bundled
with user apps. For non-prod code (and for production error-handling
code), use `String(value)` instead which may be a little slower but will
never throw.
* Add failing tests for string coercion
Added failing tests to verify:
* That input, select, and textarea elements with value and defaultValue
set to Temporal-like objects which will throw when coerced to string
using the `'' + value` pattern.
* That text elements will throw for Temporal-like objects
* That dangerouslySetInnerHTML will *not* throw for Temporal-like
objects because this value is not cast to a string before passing to
the DOM.
* That keys that are Temporal-like objects will throw
All tests above validate the friendly error messages thrown.
* Use `String(value)` for coercion in non-prod files
This commit switches non-production code from `'' + value` (which
throws for Temporal objects and symbols) to instead use `String(value)`
which won't throw for these or other future plus-phobic types.
"Non-produciton code" includes anything not bundled into user apps:
* Tests and test utilities. Note that I didn't change legacy React
test fixtures because I assumed it was good for those files to
act just like old React, including coercion behavior.
* Build scripts
* Dev tools package - In addition to switching to `String`, I also
removed special-case code for coercing symbols which is now
unnecessary.
* Add DEV-only string coercion checks to prod files
This commit adds DEV-only function calls to to check if string coercion
using `'' + value` will throw, which it will if the value is a Temporal
object or a symbol because those types can't be added with `+`.
If it will throw, then in DEV these checks will show a console error
to help the user undertsand what went wrong and how to fix the
problem. After emitting the console error, the check functions will
retry the coercion which will throw with a call stack that's easy (or
at least easier!) to troubleshoot because the exception happens right
after a long comment explaining the issue. So whether the user is in
a debugger, looking at the browser console, or viewing the in-browser
DEV call stack, it should be easy to understand and fix the problem.
In most cases, the safe-string-coercion ESLint rule is smart enough to
detect when a coercion is safe. But in rare cases (e.g. when a coercion
is inside a ternary) this rule will have to be manually disabled.
This commit also switches error-handling code to use `String(value)`
for coercion, because it's bad to crash when you're trying to build
an error message or a call stack! Because `String()` is usually
disallowed by the `safe-string-coercion` ESLint rule in production
code, the rule must be disabled when `String()` is used.
2021-09-28 01:05:07 +08:00
|
|
|
'react-internal/safe-string-coercion': [
|
|
|
|
ERROR,
|
|
|
|
{isProductionUserAppCode: false},
|
|
|
|
],
|
2020-10-16 23:06:08 +08:00
|
|
|
|
|
|
|
// Disable accessibility checks
|
|
|
|
'jsx-a11y/aria-role': OFF,
|
|
|
|
'jsx-a11y/no-noninteractive-element-interactions': OFF,
|
|
|
|
'jsx-a11y/no-static-element-interactions': OFF,
|
|
|
|
'jsx-a11y/role-has-required-aria-props': OFF,
|
|
|
|
'jsx-a11y/no-noninteractive-tabindex': OFF,
|
|
|
|
'jsx-a11y/tabindex-no-positive': OFF,
|
2019-12-15 02:09:25 +08:00
|
|
|
},
|
|
|
|
},
|
2021-09-07 03:17:51 +08:00
|
|
|
{
|
2021-09-07 03:42:40 +08:00
|
|
|
files: [
|
|
|
|
'scripts/eslint-rules/*.js',
|
Improve DEV errors if string coercion throws (Temporal.*, Symbol, etc.) (#22064)
* Revise ESLint rules for string coercion
Currently, react uses `'' + value` to coerce mixed values to strings.
This code will throw for Temporal objects or symbols.
To make string-coercion safer and to improve user-facing error messages,
This commit adds a new ESLint rule called `safe-string-coercion`.
This rule has two modes: a production mode and a non-production mode.
* If the `isProductionUserAppCode` option is true, then `'' + value`
coercions are allowed (because they're faster, although they may
throw) and `String(value)` coercions are disallowed. Exception:
when building error messages or running DEV-only code in prod
files, `String()` should be used because it won't throw.
* If the `isProductionUserAppCode` option is false, then `'' + value`
coercions are disallowed (because they may throw, and in non-prod
code it's not worth the risk) and `String(value)` are allowed.
Production mode is used for all files which will be bundled with
developers' userland apps. Non-prod mode is used for all other React
code: tests, DEV blocks, devtools extension, etc.
In production mode, in addiiton to flagging `String(value)` calls,
the rule will also flag `'' + value` or `value + ''` coercions that may
throw. The rule is smart enough to silence itself in the following
"will never throw" cases:
* When the coercion is wrapped in a `typeof` test that restricts to safe
(non-symbol, non-object) types. Example:
if (typeof value === 'string' || typeof value === 'number') {
thisWontReport('' + value);
}
* When what's being coerced is a unary function result, because unary
functions never return an object or a symbol.
* When the coerced value is a commonly-used numeric identifier:
`i`, `idx`, or `lineNumber`.
* When the statement immeidately before the coercion is a DEV-only
call to a function from shared/CheckStringCoercion.js. This call is a
no-op in production, but in DEV it will show a console error
explaining the problem, then will throw right after a long explanatory
code comment so that debugger users will have an idea what's going on.
The check function call must be in the following format:
if (__DEV__) {
checkXxxxxStringCoercion(value);
};
Manually disabling the rule is usually not necessary because almost all
prod use of the `'' + value` pattern falls into one of the categories
above. But in the rare cases where the rule isn't smart enough to detect
safe usage (e.g. when a coercion is inside a nested ternary operator),
manually disabling the rule will be needed.
The rule should also be manually disabled in prod error handling code
where `String(value)` should be used for coercions, because it'd be
bad to throw while building an error message or stack trace!
The prod and non-prod modes have differentiated error messages to
explain how to do a proper coercion in that mode.
If a production check call is needed but is missing or incorrect
(e.g. not in a DEV block or not immediately before the coercion), then
a context-sensitive error message will be reported so that developers
can figure out what's wrong and how to fix the problem.
Because string coercions are now handled by the `safe-string-coercion`
rule, the `no-primitive-constructor` rule no longer flags `String()`
usage. It still flags `new String(value)` because that usage is almost
always a bug.
* Add DEV-only string coercion check functions
This commit adds DEV-only functions to check whether coercing
values to strings using the `'' + value` pattern will throw. If it will
throw, these functions will:
1. Display a console error with a friendly error message describing
the problem and the developer can fix it.
2. Perform the coercion, which will throw. Right before the line where
the throwing happens, there's a long code comment that will help
debugger users (or others looking at the exception call stack) figure
out what happened and how to fix the problem.
One of these check functions should be called before all string coercion
of user-provided values, except when the the coercion is guaranteed not
to throw, e.g.
* if inside a typeof check like `if (typeof value === 'string')`
* if coercing the result of a unary function like `+value` or `value++`
* if coercing a variable named in a whitelist of numeric identifiers:
`i`, `idx`, or `lineNumber`.
The new `safe-string-coercion` internal ESLint rule enforces that
these check functions are called when they are required.
Only use these check functions in production code that will be bundled
with user apps. For non-prod code (and for production error-handling
code), use `String(value)` instead which may be a little slower but will
never throw.
* Add failing tests for string coercion
Added failing tests to verify:
* That input, select, and textarea elements with value and defaultValue
set to Temporal-like objects which will throw when coerced to string
using the `'' + value` pattern.
* That text elements will throw for Temporal-like objects
* That dangerouslySetInnerHTML will *not* throw for Temporal-like
objects because this value is not cast to a string before passing to
the DOM.
* That keys that are Temporal-like objects will throw
All tests above validate the friendly error messages thrown.
* Use `String(value)` for coercion in non-prod files
This commit switches non-production code from `'' + value` (which
throws for Temporal objects and symbols) to instead use `String(value)`
which won't throw for these or other future plus-phobic types.
"Non-produciton code" includes anything not bundled into user apps:
* Tests and test utilities. Note that I didn't change legacy React
test fixtures because I assumed it was good for those files to
act just like old React, including coercion behavior.
* Build scripts
* Dev tools package - In addition to switching to `String`, I also
removed special-case code for coercing symbols which is now
unnecessary.
* Add DEV-only string coercion checks to prod files
This commit adds DEV-only function calls to to check if string coercion
using `'' + value` will throw, which it will if the value is a Temporal
object or a symbol because those types can't be added with `+`.
If it will throw, then in DEV these checks will show a console error
to help the user undertsand what went wrong and how to fix the
problem. After emitting the console error, the check functions will
retry the coercion which will throw with a call stack that's easy (or
at least easier!) to troubleshoot because the exception happens right
after a long comment explaining the issue. So whether the user is in
a debugger, looking at the browser console, or viewing the in-browser
DEV call stack, it should be easy to understand and fix the problem.
In most cases, the safe-string-coercion ESLint rule is smart enough to
detect when a coercion is safe. But in rare cases (e.g. when a coercion
is inside a ternary) this rule will have to be manually disabled.
This commit also switches error-handling code to use `String(value)`
for coercion, because it's bad to crash when you're trying to build
an error message or a call stack! Because `String()` is usually
disallowed by the `safe-string-coercion` ESLint rule in production
code, the rule must be disabled when `String()` is used.
2021-09-28 01:05:07 +08:00
|
|
|
'packages/eslint-plugin-react-hooks/src/*.js',
|
2021-09-07 03:42:40 +08:00
|
|
|
],
|
2021-09-07 03:17:51 +08:00
|
|
|
plugins: ['eslint-plugin'],
|
|
|
|
rules: {
|
|
|
|
'eslint-plugin/prefer-object-rule': ERROR,
|
|
|
|
'eslint-plugin/require-meta-fixable': [
|
|
|
|
ERROR,
|
|
|
|
{catchNoFixerButFixableProperty: true},
|
|
|
|
],
|
|
|
|
'eslint-plugin/require-meta-has-suggestions': ERROR,
|
|
|
|
},
|
|
|
|
},
|
2019-04-30 05:31:16 +08:00
|
|
|
{
|
2020-11-03 10:49:48 +08:00
|
|
|
files: [
|
|
|
|
'packages/react-native-renderer/**/*.js',
|
2020-12-08 21:08:57 +08:00
|
|
|
'packages/react-server-native-relay/**/*.js',
|
2020-11-03 10:49:48 +08:00
|
|
|
],
|
2019-04-30 05:31:16 +08:00
|
|
|
globals: {
|
|
|
|
nativeFabricUIManager: true,
|
2019-08-10 03:59:02 +08:00
|
|
|
},
|
|
|
|
},
|
2020-03-19 03:18:34 +08:00
|
|
|
{
|
2020-12-08 21:08:57 +08:00
|
|
|
files: ['packages/react-server-dom-webpack/**/*.js'],
|
2020-03-19 03:18:34 +08:00
|
|
|
globals: {
|
2020-04-10 09:11:34 +08:00
|
|
|
__webpack_chunk_load__: true,
|
|
|
|
__webpack_require__: true,
|
2020-03-19 03:18:34 +08:00
|
|
|
},
|
|
|
|
},
|
2020-08-12 21:39:47 +08:00
|
|
|
{
|
|
|
|
files: ['packages/scheduler/**/*.js'],
|
|
|
|
globals: {
|
|
|
|
TaskController: true,
|
|
|
|
},
|
|
|
|
},
|
2018-01-10 02:55:51 +08:00
|
|
|
],
|
|
|
|
|
2016-11-14 06:00:07 +08:00
|
|
|
globals: {
|
Run Jest in production mode (#11616)
* Move Jest setup files to /dev/ subdirectory
* Clone Jest /dev/ files into /prod/
* Move shared code into scripts/jest
* Move Jest config into the scripts folder
* Fix the equivalence test
It fails because the config is now passed to Jest explicitly.
But the test doesn't know about the config.
To fix this, we just run it via `yarn test` (which includes the config).
We already depend on Yarn for development anyway.
* Add yarn test-prod to run Jest with production environment
* Actually flip the production tests to run in prod environment
This produces a bunch of errors:
Test Suites: 64 failed, 58 passed, 122 total
Tests: 740 failed, 26 skipped, 1809 passed, 2575 total
Snapshots: 16 failed, 4 passed, 20 total
* Ignore expectDev() calls in production
Down from 740 to 175 failed.
Test Suites: 44 failed, 78 passed, 122 total
Tests: 175 failed, 26 skipped, 2374 passed, 2575 total
Snapshots: 16 failed, 4 passed, 20 total
* Decode errors so tests can assert on their messages
Down from 175 to 129.
Test Suites: 33 failed, 89 passed, 122 total
Tests: 129 failed, 1029 skipped, 1417 passed, 2575 total
Snapshots: 16 failed, 4 passed, 20 total
* Remove ReactDOMProduction-test
There is no need for it now. The only test that was special is moved into ReactDOM-test.
* Remove production switches from ReactErrorUtils
The tests now run in production in a separate pass.
* Add and use spyOnDev() for warnings
This ensures that by default we expect no warnings in production bundles.
If the warning *is* expected, use the regular spyOn() method.
This currently breaks all expectDev() assertions without __DEV__ blocks so we go back to:
Test Suites: 56 failed, 65 passed, 121 total
Tests: 379 failed, 1029 skipped, 1148 passed, 2556 total
Snapshots: 16 failed, 4 passed, 20 total
* Replace expectDev() with expect() in __DEV__ blocks
We started using spyOnDev() for console warnings to ensure we don't *expect* them to occur in production. As a consequence, expectDev() assertions on console.error.calls fail because console.error.calls doesn't exist. This is actually good because it would help catch accidental warnings in production.
To solve this, we are getting rid of expectDev() altogether, and instead introduce explicit expectation branches. We'd need them anyway for testing intentional behavior differences.
This commit replaces all expectDev() calls with expect() calls in __DEV__ blocks. It also removes a few unnecessary expect() checks that no warnings were produced (by also removing the corresponding spyOnDev() calls).
Some DEV-only assertions used plain expect(). Those were also moved into __DEV__ blocks.
ReactFiberErrorLogger was special because it console.error()'s in production too. So in that case I intentionally used spyOn() instead of spyOnDev(), and added extra assertions.
This gets us down to:
Test Suites: 21 failed, 100 passed, 121 total
Tests: 72 failed, 26 skipped, 2458 passed, 2556 total
Snapshots: 16 failed, 4 passed, 20 total
* Enable User Timing API for production testing
We could've disabled it, but seems like a good idea to test since we use it at FB.
* Test for explicit Object.freeze() differences between PROD and DEV
This is one of the few places where DEV and PROD behavior differs for performance reasons.
Now we explicitly test both branches.
* Run Jest via "yarn test" on CI
* Remove unused variable
* Assert different error messages
* Fix error handling tests
This logic is really complicated because of the global ReactFiberErrorLogger mock.
I understand it now, so I added TODOs for later.
It can be much simpler if we change the rest of the tests that assert uncaught errors to also assert they are logged as warnings.
Which mirrors what happens in practice anyway.
* Fix more assertions
* Change tests to document the DEV/PROD difference for state invariant
It is very likely unintentional but I don't want to change behavior in this PR.
Filed a follow up as https://github.com/facebook/react/issues/11618.
* Remove unnecessary split between DEV/PROD ref tests
* Fix more test message assertions
* Make validateDOMNesting tests DEV-only
* Fix error message assertions
* Document existing DEV/PROD message difference (possible bug)
* Change mocking assertions to be DEV-only
* Fix the error code test
* Fix more error message assertions
* Fix the last failing test due to known issue
* Run production tests on CI
* Unify configuration
* Fix coverage script
* Remove expectDev from eslintrc
* Run everything in band
We used to before, too. I just forgot to add the arguments after deleting the script.
2017-11-22 21:02:26 +08:00
|
|
|
spyOnDev: true,
|
2017-11-29 06:06:26 +08:00
|
|
|
spyOnDevAndProd: true,
|
|
|
|
spyOnProd: true,
|
2020-10-13 01:07:10 +08:00
|
|
|
__EXPERIMENTAL__: true,
|
|
|
|
__EXTENSION__: true,
|
2018-06-12 04:16:27 +08:00
|
|
|
__PROFILE__: true,
|
2020-10-13 01:07:10 +08:00
|
|
|
__TEST__: true,
|
2018-09-02 03:00:00 +08:00
|
|
|
__UMD__: true,
|
Add test run that uses www feature flags (#18234)
In CI, we run our test suite against multiple build configurations. For
example, we run our tests in both dev and prod, and in both the
experimental and stable release channels. This is to prevent accidental
deviations in behavior between the different builds. If there's an
intentional deviation in behavior, the test author must account
for them.
However, we currently don't run tests against the www builds. That's
a problem, because it's common for features to land in www before they
land anywhere else, including the experimental release channel.
Typically we do this so we can gradually roll out the feature behind
a flag before deciding to enable it.
The way we test those features today is by mutating the
`shared/ReactFeatureFlags` module. There are a few downsides to this
approach, though. The flag is only overridden for the specific tests or
test suites where you apply the override. But usually what you want is
to run *all* tests with the flag enabled, to protect against unexpected
regressions.
Also, mutating the feature flags module only works when running the
tests against source, not against the final build artifacts, because the
ReactFeatureFlags module is inlined by the build script.
Instead, we should run the test suite against the www configuration,
just like we do for prod, experimental, and so on. I've added a new
command, `yarn test-www`. It automatically runs in CI.
Some of the www feature flags are dynamic; that is, they depend on
a runtime condition (i.e. a GK). These flags are imported from an
external module that lives in www. Those flags will be enabled for some
clients and disabled for others, so we should run the tests against
*both* modes.
So I've added a new global `__VARIANT__`, and a new test command `yarn
test-www-variant`. `__VARIANT__` is set to false by default; when
running `test-www-variant`, it's set to true.
If we were going for *really* comprehensive coverage, we would run the
tests against every possible configuration of feature flags: 2 ^
numberOfFlags total combinations. That's not practical, though, so
instead we only run against two combinations: once with `__VARIANT__`
set to `true`, and once with it set to `false`. We generally assume that
flags can be toggled independently, so in practice this should
be enough.
You can also refer to `__VARIANT__` in tests to detect which mode you're
running in. Or, you can import `shared/ReactFeatureFlags` and read the
specific flag you can about. However, we should stop mutating that
module going forward. Treat it as read-only.
In this commit, I have only setup the www tests to run against source.
I'll leave running against build for a follow up.
Many of our tests currently assume they run only in the default
configuration, and break when certain flags are toggled. Rather than fix
these all up front, I've hard-coded the relevant flags to the default
values. We can incrementally migrate those tests later.
2020-03-07 01:29:05 +08:00
|
|
|
__VARIANT__: true,
|
Add pragma for feature testing: @gate (#18581)
* Add pragma for feature testing: @gate
The `@gate` pragma declares under which conditions a test is expected to
pass.
If the gate condition passes, then the test runs normally (same as if
there were no pragma).
If the conditional fails, then the test runs and is *expected to fail*.
An alternative to `it.experimental` and similar proposals.
Examples
--------
Basic:
```js
// @gate enableBlocksAPI
test('passes only if Blocks API is available', () => {/*...*/})
```
Negation:
```js
// @gate !disableLegacyContext
test('depends on a deprecated feature', () => {/*...*/})
```
Multiple flags:
```js
// @gate enableNewReconciler
// @gate experimental
test('needs both useEvent and Blocks', () => {/*...*/})
```
Logical operators (yes, I'm sorry):
```js
// @gate experimental && (enableNewReconciler || disableSchedulerTimeoutBasedOnReactExpirationTime)
test('concurrent mode, doesn\'t work in old fork unless Scheduler timeout flag is disabled', () => {/*...*/})
```
Strings, and comparion operators
No use case yet but I figure eventually we'd use this to gate on
different release channels:
```js
// @gate channel === "experimental" || channel === "modern"
test('works in OSS experimental or www modern', () => {/*...*/})
```
How does it work?
I'm guessing those last two examples might be controversial. Supporting
those cases did require implementing a mini-parser.
The output of the transform is very straightforward, though.
Input:
```js
// @gate a && (b || c)
test('some test', () => {/*...*/})
```
Output:
```js
_test_gate(ctx => ctx.a && (ctx.b || ctx.c, 'some test'), () => {/*...*/});
```
It also works with `it`, `it.only`, and `fit`. It leaves `it.skip` and
`xit` alone because those tests are disabled anyway.
`_test_gate` is a global method that I set up in our Jest config. It
works about the same as the existing `it.experimental` helper.
The context (`ctx`) argument is whatever we want it to be. I set it up
so that it throws if you try to access a flag that doesn't exist. I also
added some shortcuts for common gating conditions, like `old`
and `new`:
```js
// @gate experimental
test('experimental feature', () => {/*...*/})
// @gate new
test('only passes in new reconciler', () => {/*...*/})
```
Why implement this as a pragma instead of a runtime API?
- Doesn't require monkey patching built-in Jest methods. Instead it
compiles to a runtime function that composes Jest's API.
- Will be easy to upgrade if Jest ever overhauls their API or we switch
to a different testing framework (unlikely but who knows).
- It feels lightweight so hopefully people won't feel gross using it.
For example, adding or removing a gate pragma will never affect the
indentation of the test, unlike if you wrapped the test in a
conditional block.
* Compatibility with console error/warning tracking
We patch console.error and console.warning to track unexpected calls
in our tests. If there's an unexpected call, we usually throw inside
an `afterEach` hook. However, that's too late for tests that we
expect to fail, because our `_test_gate` runtime can't capture the
error. So I also check for unexpected calls inside `_test_gate`.
* Move test flags to dedicated file
Added some instructions for how the flags are set up and how to
use them.
* Add dynamic version of gate API
Receives same flags as the pragma.
If we ever decide to revert the pragma, we can codemod them to use
this instead.
2020-04-14 01:14:34 +08:00
|
|
|
gate: true,
|
2019-09-16 20:43:22 +08:00
|
|
|
trustedTypes: true,
|
2021-10-18 23:27:26 +08:00
|
|
|
IS_REACT_ACT_ENVIRONMENT: true,
|
2016-11-14 06:00:07 +08:00
|
|
|
},
|
2016-03-02 07:40:52 +08:00
|
|
|
};
|