[be][tests] Run todo fixtures

--- 

Snap should compile all fixtures to record changes in results, even `todo` 
prefixed ones. Previously, they were skipped as we noted the correlation of `// 
@skip` pragmas and file naming. 

Now, no fixture should be skipped as our compiler pipeline should be able to 
handle every kind of error.
This commit is contained in:
Mofei Zhang
2023-11-14 13:04:28 -05:00
parent 2efd85f145
commit 00abc5acf5
70 changed files with 1622 additions and 23 deletions
@@ -0,0 +1,29 @@
## Input
```javascript
// @skip
// Unsupported input
// Valid -- this is a regression test.
jest.useFakeTimers();
beforeEach(() => {
jest.useRealTimers();
});
```
## Code
```javascript
// @skip
// Unsupported input
// Valid -- this is a regression test.
jest.useFakeTimers();
beforeEach(() => {
jest.useRealTimers();
});
```
@@ -0,0 +1,40 @@
## Input
```javascript
// @skip
// Unsupported input
// Valid because hooks can be used in anonymous function arguments to
// React.memo.
const MemoizedFunction = React.memo((props) => {
useHook();
return <button {...props} />;
});
```
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
// Unsupported input
// Valid because hooks can be used in anonymous function arguments to
// React.memo.
const MemoizedFunction = React.memo((props) => {
const $ = useMemoCache(2);
useHook();
let t0;
if ($[0] !== props) {
t0 = <button {...props} />;
$[0] = props;
$[1] = t0;
} else {
t0 = $[1];
}
return t0;
});
```
@@ -0,0 +1,52 @@
## Input
```javascript
// @skip
// Unsupported input
// Invalid because it's a common misunderstanding.
// We *could* make it valid but the runtime error could be confusing.
const ComponentWithHookInsideCallback = React.forwardRef((props, ref) => {
useEffect(() => {
useHookInsideCallback();
});
return <button {...props} ref={ref} />;
});
```
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
// Unsupported input
// Invalid because it's a common misunderstanding.
// We *could* make it valid but the runtime error could be confusing.
const ComponentWithHookInsideCallback = React.forwardRef((props, ref) => {
const $ = useMemoCache(4);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = () => {
useHookInsideCallback();
};
$[0] = t0;
} else {
t0 = $[0];
}
useEffect(t0);
let t1;
if ($[1] !== props || $[2] !== ref) {
t1 = <button {...props} ref={ref} />;
$[1] = props;
$[2] = ref;
$[3] = t1;
} else {
t1 = $[3];
}
return t1;
});
```
@@ -0,0 +1,159 @@
## Input
```javascript
// @skip
// Unsupported input
// Valid because the neither the conditions before or after the hook affect the hook call
// Failed prior to implementing BigInt because pathsFromStartToEnd and allPathsFromStartToEnd were too big and had rounding errors
const useSomeHook = () => {};
const SomeName = () => {
const filler = FILLER ?? FILLER ?? FILLER;
const filler2 = FILLER ?? FILLER ?? FILLER;
const filler3 = FILLER ?? FILLER ?? FILLER;
const filler4 = FILLER ?? FILLER ?? FILLER;
const filler5 = FILLER ?? FILLER ?? FILLER;
const filler6 = FILLER ?? FILLER ?? FILLER;
const filler7 = FILLER ?? FILLER ?? FILLER;
const filler8 = FILLER ?? FILLER ?? FILLER;
useSomeHook();
if (anyConditionCanEvenBeFalse) {
return null;
}
return (
<React.Fragment>
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
</React.Fragment>
);
};
```
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
// Unsupported input
// Valid because the neither the conditions before or after the hook affect the hook call
// Failed prior to implementing BigInt because pathsFromStartToEnd and allPathsFromStartToEnd were too big and had rounding errors
const useSomeHook = () => {};
const SomeName = () => {
const $ = useMemoCache(1);
(FILLER ?? FILLER, FILLER) ?? FILLER;
(FILLER ?? FILLER, FILLER) ?? FILLER;
(FILLER ?? FILLER, FILLER) ?? FILLER;
(FILLER ?? FILLER, FILLER) ?? FILLER;
(FILLER ?? FILLER, FILLER) ?? FILLER;
(FILLER ?? FILLER, FILLER) ?? FILLER;
(FILLER ?? FILLER, FILLER) ?? FILLER;
(FILLER ?? FILLER, FILLER) ?? FILLER;
useSomeHook();
if (anyConditionCanEvenBeFalse) {
return null;
}
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = (
<React.Fragment>
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
</React.Fragment>
);
$[0] = t0;
} else {
t0 = $[0];
}
return t0;
};
```
@@ -0,0 +1,51 @@
## Input
```javascript
// @skip
// Unsupported input
// Invalid because it's a common misunderstanding.
// We *could* make it valid but the runtime error could be confusing.
const ComponentWithHookInsideCallback = React.memo((props) => {
useEffect(() => {
useHookInsideCallback();
});
return <button {...props} />;
});
```
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
// Unsupported input
// Invalid because it's a common misunderstanding.
// We *could* make it valid but the runtime error could be confusing.
const ComponentWithHookInsideCallback = React.memo((props) => {
const $ = useMemoCache(3);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = () => {
useHookInsideCallback();
};
$[0] = t0;
} else {
t0 = $[0];
}
useEffect(t0);
let t1;
if ($[1] !== props) {
t1 = <button {...props} />;
$[1] = props;
$[2] = t1;
} else {
t1 = $[2];
}
return t1;
});
```
@@ -0,0 +1,99 @@
## Input
```javascript
// @skip
// Unsupported input
// Valid because hooks can call hooks.
function useHook() {
useState();
}
const whatever = function useHook() {
useState();
};
const useHook1 = () => {
useState();
};
let useHook2 = () => useState();
useHook2 = () => {
useState();
};
({
useHook: () => {
useState();
},
});
({
useHook() {
useState();
},
});
const {
useHook3 = () => {
useState();
},
} = {};
({
useHook = () => {
useState();
},
} = {});
Namespace.useHook = () => {
useState();
};
```
## Code
```javascript
// @skip
// Unsupported input
// Valid because hooks can call hooks.
function useHook() {
useState();
}
const whatever = function useHook() {
useState();
};
const useHook1 = () => {
useState();
};
let useHook2 = () => {
return useState();
};
useHook2 = () => {
useState();
};
({
useHook: () => {
useState();
},
});
({
useHook() {
useState();
},
});
const {
useHook3 = () => {
useState();
},
} = {};
({
useHook = () => {
useState();
},
} = {});
Namespace.useHook = () => {
useState();
};
```
@@ -0,0 +1,41 @@
## Input
```javascript
// @skip
// Unsupported input
// Valid because hooks can be used in anonymous arrow-function arguments
// to forwardRef.
const FancyButton = React.forwardRef((props, ref) => {
useHook();
return <button {...props} ref={ref} />;
});
```
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
// Unsupported input
// Valid because hooks can be used in anonymous arrow-function arguments
// to forwardRef.
const FancyButton = React.forwardRef((props, ref) => {
const $ = useMemoCache(3);
useHook();
let t0;
if ($[0] !== props || $[1] !== ref) {
t0 = <button {...props} ref={ref} />;
$[0] = props;
$[1] = ref;
$[2] = t0;
} else {
t0 = $[2];
}
return t0;
});
```
@@ -0,0 +1,101 @@
## Input
```javascript
// @skip
// Unsupported input
// Currently invalid.
// These are variations capturing the current heuristic--
// we only allow hooks in PascalCase or useFoo functions.
// We *could* make some of these valid. But before doing it,
// consider specific cases documented above that contain reasoning.
function a() {
useState();
}
const whatever = function b() {
useState();
};
const c = () => {
useState();
};
let d = () => useState();
e = () => {
useState();
};
({
f: () => {
useState();
},
});
({
g() {
useState();
},
});
const {
j = () => {
useState();
},
} = {};
({
k = () => {
useState();
},
} = {});
```
## Code
```javascript
// @skip
// Unsupported input
// Currently invalid.
// These are variations capturing the current heuristic--
// we only allow hooks in PascalCase or useFoo functions.
// We *could* make some of these valid. But before doing it,
// consider specific cases documented above that contain reasoning.
function a() {
useState();
}
const whatever = function b() {
useState();
};
const c = () => {
useState();
};
let d = () => {
return useState();
};
e = () => {
useState();
};
({
f: () => {
useState();
},
});
({
g() {
useState();
},
});
const {
j = () => {
useState();
},
} = {};
({
k = () => {
useState();
},
} = {});
```
@@ -0,0 +1,26 @@
## Input
```javascript
// @skip
// Passed but should have failed
// Invalid because it's dangerous and might not warn otherwise.
// This *must* be invalid.
const FancyButton = forwardRef(function (props, ref) {
if (props.fancy) {
useCustomHook();
}
return <button ref={ref}>{props.children}</button>;
});
```
## Error
```
[ReactForget] InvalidReact: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning) (8:8)
```
@@ -0,0 +1,26 @@
## Input
```javascript
// @skip
// Passed but should have failed
// Invalid because it's dangerous and might not warn otherwise.
// This *must* be invalid.
const MemoizedButton = memo(function (props) {
if (props.fancy) {
useCustomHook();
}
return <button>{props.children}</button>;
});
```
## Error
```
[ReactForget] InvalidReact: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning) (8:8)
```
@@ -0,0 +1,25 @@
## Input
```javascript
// @skip
// Passed but should have failed
// Invalid because it's dangerous and might not warn otherwise.
// This *must* be invalid.
function ComponentWithConditionalHook() {
if (cond) {
Namespace.useConditionalHook();
}
}
```
## Error
```
[ReactForget] InvalidReact: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning) (8:8)
```
@@ -0,0 +1,26 @@
## Input
```javascript
// @skip
// Unsupported input
// Invalid because it's dangerous and might not warn otherwise.
// This *must* be invalid.
const FancyButton = React.forwardRef((props, ref) => {
if (props.fancy) {
useCustomHook();
}
return <button ref={ref}>{props.children}</button>;
});
```
## Error
```
[ReactForget] InvalidReact: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning) (8:8)
```
@@ -0,0 +1,28 @@
## Input
```javascript
// @skip
// Unsupported input
// Valid because the neither the condition nor the loop affect the hook call.
function App(props) {
const someObject = { propA: true };
for (const propName in someObject) {
if (propName === true) {
} else {
}
}
const [myState, setMyState] = useState(null);
}
```
## Error
```
[ReactForget] InvalidReact: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning) (12:12)
```
@@ -0,0 +1,27 @@
## Input
```javascript
// @skip
// Unsupported input
// Valid because the loop doesn't change the order of hooks calls.
function RegressionTest() {
const res = [];
const additionalCond = true;
for (let i = 0; i !== 10 && additionalCond; ++i) {
res.push(i);
}
React.useLayoutEffect(() => {});
}
```
## Error
```
[ReactForget] InvalidReact: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning) (11:11)
```
@@ -0,0 +1,25 @@
## Input
```javascript
// @skip
// Unsupported input
// This is valid because "use"-prefixed functions called in
// unnamed function arguments are not assumed to be hooks.
React.unknownFunction((foo, bar) => {
if (foo) {
useNotAHook(bar);
}
});
```
## Error
```
[ReactForget] InvalidReact: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning) (8:8)
```
@@ -0,0 +1,26 @@
## Input
```javascript
// @skip
// Unsupported input
// Invalid because it's dangerous and might not warn otherwise.
// This *must* be invalid.
function useHook() {
try {
f();
useState();
} catch {}
}
```
## Error
```
[ReactForget] InvalidReact: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning) (9:9)
```
@@ -0,0 +1,45 @@
## Input
```javascript
// @skip
// Passed but should have failed
// Invalid because it's dangerous and might not warn otherwise.
// This *must* be invalid.
function createHook() {
return function useHookWithConditionalHook() {
if (cond) {
useConditionalHook();
}
};
}
```
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
// Passed but should have failed
// Invalid because it's dangerous and might not warn otherwise.
// This *must* be invalid.
function createHook() {
const $ = useMemoCache(1);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = function useHookWithConditionalHook() {
if (cond) {
useConditionalHook();
}
};
$[0] = t0;
} else {
t0 = $[0];
}
return t0;
}
```
@@ -0,0 +1,45 @@
## Input
```javascript
// @skip
// Passed but should have failed
// Invalid because it's a common misunderstanding.
// We *could* make it valid but the runtime error could be confusing.
function createComponent() {
return function ComponentWithHookInsideCallback() {
useEffect(() => {
useHookInsideCallback();
});
};
}
```
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
// Passed but should have failed
// Invalid because it's a common misunderstanding.
// We *could* make it valid but the runtime error could be confusing.
function createComponent() {
const $ = useMemoCache(1);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = function ComponentWithHookInsideCallback() {
useEffect(() => {
useHookInsideCallback();
});
};
$[0] = t0;
} else {
t0 = $[0];
}
return t0;
}
```
@@ -0,0 +1,41 @@
## Input
```javascript
// @skip
// Passed but should have failed
// Invalid because it's dangerous.
// Normally, this would crash, but not if you use inline requires.
// This *must* be invalid.
// It's expected to have some false positives, but arguably
// they are confusing anyway due to the use*() convention
// already being associated with Hooks.
useState();
if (foo) {
const foo = React.useCallback(() => {});
}
useCustomHook();
```
## Code
```javascript
// @skip
// Passed but should have failed
// Invalid because it's dangerous.
// Normally, this would crash, but not if you use inline requires.
// This *must* be invalid.
// It's expected to have some false positives, but arguably
// they are confusing anyway due to the use*() convention
// already being associated with Hooks.
useState();
if (foo) {
const foo = React.useCallback(() => {});
}
useCustomHook();
```
@@ -0,0 +1,37 @@
## Input
```javascript
// @skip
// Passed but should have failed
// This is a false positive (it's valid) that unfortunately
// we cannot avoid. Prefer to rename it to not start with "use"
class Foo extends Component {
render() {
if (cond) {
FooStore.useFeatureFlag();
}
}
}
```
## Code
```javascript
// @skip
// Passed but should have failed
// This is a false positive (it's valid) that unfortunately
// we cannot avoid. Prefer to rename it to not start with "use"
class Foo extends Component {
render() {
if (cond) {
FooStore.useFeatureFlag();
}
}
}
```
@@ -0,0 +1,43 @@
## Input
```javascript
// @skip
// Passed but should have failed
// Technically this is a false positive.
// We *could* make it valid (and it used to be).
//
// However, top-level Hook-like calls can be very dangerous
// in environments with inline requires because they can mask
// the runtime error by accident.
// So we prefer to disallow it despite the false positive.
const { createHistory, useBasename } = require("history-2.1.2");
const browserHistory = useBasename(createHistory)({
basename: "/",
});
```
## Code
```javascript
// @skip
// Passed but should have failed
// Technically this is a false positive.
// We *could* make it valid (and it used to be).
//
// However, top-level Hook-like calls can be very dangerous
// in environments with inline requires because they can mask
// the runtime error by accident.
// So we prefer to disallow it despite the false positive.
const { createHistory, useBasename } = require("history-2.1.2");
const browserHistory = useBasename(createHistory)({
basename: "/",
});
```
@@ -0,0 +1,29 @@
## Input
```javascript
// @skip
// Passed but should have failed
(class {
useHook() {
useState();
}
});
```
## Code
```javascript
// @skip
// Passed but should have failed
(class {
useHook() {
useState();
}
});
```
@@ -0,0 +1,41 @@
## Input
```javascript
// @skip
// Passed but should have failed
// Invalid because it's a common misunderstanding.
// We *could* make it valid but the runtime error could be confusing.
function createComponent() {
return function ComponentWithHookInsideCallback() {
function handleClick() {
useState();
}
};
}
```
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
// Passed but should have failed
// Invalid because it's a common misunderstanding.
// We *could* make it valid but the runtime error could be confusing.
function createComponent() {
const $ = useMemoCache(1);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = function ComponentWithHookInsideCallback() {};
$[0] = t0;
} else {
t0 = $[0];
}
return t0;
}
```
@@ -0,0 +1,34 @@
## Input
```javascript
// @skip
// Passed but should have failed
// These are neither functions nor hooks.
function _normalFunctionWithHook() {
useHookInsideNormalFunction();
}
function _useNotAHook() {
useHookInsideNormalFunction();
}
```
## Code
```javascript
// @skip
// Passed but should have failed
// These are neither functions nor hooks.
function _normalFunctionWithHook() {
useHookInsideNormalFunction();
}
function _useNotAHook() {
useHookInsideNormalFunction();
}
```
@@ -0,0 +1,29 @@
## Input
```javascript
// @skip
// Passed but should have failed
// Invalid because it's a common misunderstanding.
// We *could* make it valid but the runtime error could be confusing.
function ComponentWithHookInsideCallback() {
function handleClick() {
useState();
}
}
```
## Code
```javascript
// @skip
// Passed but should have failed
// Invalid because it's a common misunderstanding.
// We *could* make it valid but the runtime error could be confusing.
function ComponentWithHookInsideCallback() {}
```
@@ -0,0 +1,29 @@
## Input
```javascript
// @skip
// Passed but should have failed
class ClassComponentWithHook extends React.Component {
render() {
React.useState();
}
}
```
## Code
```javascript
// @skip
// Passed but should have failed
class ClassComponentWithHook extends React.Component {
render() {
React.useState();
}
}
```
@@ -0,0 +1,33 @@
## Input
```javascript
// @skip
// Passed but should have failed
class ClassComponentWithFeatureFlag extends React.Component {
render() {
if (foo) {
useFeatureFlag();
}
}
}
```
## Code
```javascript
// @skip
// Passed but should have failed
class ClassComponentWithFeatureFlag extends React.Component {
render() {
if (foo) {
useFeatureFlag();
}
}
}
```
@@ -0,0 +1,29 @@
## Input
```javascript
// @skip
// Passed but should have failed
(class {
h = () => {
useState();
};
});
```
## Code
```javascript
// @skip
// Passed but should have failed
(class {
h = () => {
useState();
};
});
```
@@ -0,0 +1,29 @@
## Input
```javascript
// @skip
// Passed but should have failed
// This is invalid because "use"-prefixed functions used in named
// functions are assumed to be hooks.
React.unknownFunction(function notAComponent(foo, bar) {
useProbablyAHook(bar);
});
```
## Code
```javascript
// @skip
// Passed but should have failed
// This is invalid because "use"-prefixed functions used in named
// functions are assumed to be hooks.
React.unknownFunction(function notAComponent(foo, bar) {
useProbablyAHook(bar);
});
```
@@ -0,0 +1,31 @@
## Input
```javascript
// @skip
// Passed but should have failed
class C {
m() {
This.useHook();
Super.useHook();
}
}
```
## Code
```javascript
// @skip
// Passed but should have failed
class C {
m() {
This.useHook();
Super.useHook();
}
}
```
@@ -0,0 +1,33 @@
## Input
```javascript
// @skip
// Passed but should have failed
// Currently invalid because it violates the convention and removes the "taint"
// from a hook. We *could* make it valid to avoid some false positives but let's
// ensure that we don't break the "renderItem" and "normalFunctionWithConditionalHook"
// cases which must remain invalid.
function normalFunctionWithHook() {
useHookInsideNormalFunction();
}
```
## Code
```javascript
// @skip
// Passed but should have failed
// Currently invalid because it violates the convention and removes the "taint"
// from a hook. We *could* make it valid to avoid some false positives but let's
// ensure that we don't break the "renderItem" and "normalFunctionWithConditionalHook"
// cases which must remain invalid.
function normalFunctionWithHook() {
useHookInsideNormalFunction();
}
```
@@ -0,0 +1,45 @@
## Input
```javascript
// @skip
// Passed but should have failed
// Invalid because it's dangerous and might not warn otherwise.
// This *must* be invalid.
function createComponent() {
return function ComponentWithConditionalHook() {
if (cond) {
useConditionalHook();
}
};
}
```
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
// Passed but should have failed
// Invalid because it's dangerous and might not warn otherwise.
// This *must* be invalid.
function createComponent() {
const $ = useMemoCache(1);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = function ComponentWithConditionalHook() {
if (cond) {
useConditionalHook();
}
};
$[0] = t0;
} else {
t0 = $[0];
}
return t0;
}
```
@@ -0,0 +1,41 @@
## Input
```javascript
// @skip
// Passed but should have failed
// Invalid because it's a common misunderstanding.
// We *could* make it valid but the runtime error could be confusing.
function ComponentWithHookInsideCallback() {
useEffect(() => {
useHookInsideCallback();
});
}
```
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
// Passed but should have failed
// Invalid because it's a common misunderstanding.
// We *could* make it valid but the runtime error could be confusing.
function ComponentWithHookInsideCallback() {
const $ = useMemoCache(1);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = () => {
useHookInsideCallback();
};
$[0] = t0;
} else {
t0 = $[0];
}
useEffect(t0);
}
```
@@ -0,0 +1,29 @@
## Input
```javascript
// @skip
// Passed but should have failed
(class {
i() {
useState();
}
});
```
## Code
```javascript
// @skip
// Passed but should have failed
(class {
i() {
useState();
}
});
```
@@ -0,0 +1,46 @@
## Input
```javascript
// @skip
// Passed but should have failed
// Invalid because it's dangerous and might not warn otherwise.
// This *must* be invalid.
function renderItem() {
useState();
}
function List(props) {
return props.items.map(renderItem);
}
```
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
// Passed but should have failed
// Invalid because it's dangerous and might not warn otherwise.
// This *must* be invalid.
function renderItem() {
useState();
}
function List(props) {
const $ = useMemoCache(2);
let t0;
if ($[0] !== props.items) {
t0 = props.items.map(renderItem);
$[0] = props.items;
$[1] = t0;
} else {
t0 = $[1];
}
return t0;
}
```
@@ -0,0 +1,29 @@
## Input
```javascript
// @skip
// Passed but should have failed
(class {
useHook = () => {
useState();
};
});
```
## Code
```javascript
// @skip
// Passed but should have failed
(class {
useHook = () => {
useState();
};
});
```
@@ -0,0 +1,27 @@
## Input
```javascript
import { identity } from "shared-runtime";
const SCALE = 2;
function Component(props) {
const { [props.name]: value } = props;
return value;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{ name: "Sathya" }],
};
```
## Error
```
[ReactForget] Todo: (BuildHIR::lowerAssignment) Handle computed properties in ObjectPattern (5:5)
```
@@ -26,9 +26,8 @@ import { unstable_useMemoCache as useMemoCache } from "react";
function Component(props) {
const $ = useMemoCache(5);
const data = useFreeze();
const c_0 = $[0] !== data.items;
let t1;
if (c_0) {
if ($[0] !== data.items) {
let t0;
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
t0 = (item) => <Item item={item} />;
@@ -43,9 +42,8 @@ function Component(props) {
t1 = $[1];
}
const items = t1;
const c_3 = $[3] !== items;
let t2;
if (c_3) {
if ($[3] !== items) {
t2 = <div>{items}</div>;
$[3] = items;
$[4] = t2;
@@ -0,0 +1,46 @@
## Input
```javascript
function Component(props) {
const FooContext = useContext(Foo);
// This function should be memoized, but its mutable range is entangled
// with the useContext call. We can't memoize hooks, therefore the
// reactive scope around the hook + callback is pruned and we're left
// w no memoization of the callback.
//
// Ideally we'd determine that this isn't called during render and can
// therefore be considered "immutable" or otherwise safe to memoize
// independently
const onClick = () => {
FooContext.current = true;
};
return <div onClick={onClick} />;
}
```
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react";
function Component(props) {
const $ = useMemoCache(2);
const FooContext = useContext(Foo);
const onClick = () => {
FooContext.current = true;
};
let t0;
if ($[0] !== onClick) {
t0 = <div onClick={onClick} />;
$[0] = onClick;
$[1] = t0;
} else {
t0 = $[1];
}
return t0;
}
```
@@ -42,11 +42,7 @@ function stripExtension(filename: string, extensions: Array<string>): string {
return filename;
}
function shouldSkip(
filter: TestFilter | null,
filterId: string,
filename: string
) {
function shouldSkip(filter: TestFilter | null, filterId: string) {
if (filter) {
if (filter.kind === "only" && filter.paths.indexOf(filterId) === -1) {
return true;
@@ -56,8 +52,6 @@ function shouldSkip(
) {
return true;
}
} else if (filename.startsWith("todo.")) {
return true;
}
return false;
}
@@ -117,10 +111,9 @@ export function getFixtures(
});
const fixtures: Map<string, TestFixture> = new Map();
for (const filePath of inputFiles) {
const filename = path.basename(filePath);
// Do not include extensions in unique identifier for fixture
const partialPath = stripExtension(filePath, INPUT_EXTENSIONS);
if (shouldSkip(filter, partialPath, filename)) {
if (shouldSkip(filter, partialPath)) {
continue;
}
@@ -145,10 +138,9 @@ export function getFixtures(
cwd: FIXTURES_PATH,
});
for (const filePath of outputFiles) {
const filename = path.basename(filePath);
// Do not include extensions in unique identifier for fixture
const partialPath = stripExtension(filePath, [OUTPUT_EXTENSION]);
if (shouldSkip(filter, partialPath, filename)) {
if (shouldSkip(filter, partialPath)) {
continue;
}
@@ -53,8 +53,7 @@ export async function compile(
clearRequireCache();
}
version = compilerVersion;
const { inputPath, outputPath, outputExists, basename } =
fixture;
const { inputPath, outputPath, outputExists, basename } = fixture;
const input = inputPath != null ? await fs.readFile(inputPath, "utf8") : null;
const expected = outputExists ? await fs.readFile(outputPath, "utf8") : null;
@@ -109,7 +108,8 @@ export async function compile(
}
const output = writeOutputToString(input, code, error);
const expectError = basename.startsWith("error.");
const expectError =
basename.startsWith("error.") || basename.startsWith("todo.error");
let unexpectedError: string | null = null;
if (expectError) {
if (error === null) {
@@ -477,6 +477,37 @@ const skipFilter = new Set([
// nothing to compile/run
"repro-no-gating-import-without-compiled-functions",
// TODOs
"rules-of-hooks/todo.bail.rules-of-hooks-279ac76f53af",
"rules-of-hooks/todo.bail.rules-of-hooks-28a78701970c",
"rules-of-hooks/todo.bail.rules-of-hooks-3d692676194b",
"rules-of-hooks/todo.bail.rules-of-hooks-6949b255e7eb",
"rules-of-hooks/todo.bail.rules-of-hooks-8503ca76d6f8",
"rules-of-hooks/todo.bail.rules-of-hooks-e0a5db3ae21e",
"rules-of-hooks/todo.bail.rules-of-hooks-e9f9bac89f8f",
"rules-of-hooks/todo.bail.rules-of-hooks-fadd52c1e460",
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-0a1dbff27ba0",
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-0de1224ce64b",
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-191029ac48c8",
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-206e2811c87c",
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-28a7111f56a7",
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-2c51251df67a",
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-449a37146a83",
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-5a7ac9a6e8fa",
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-76a74b4666e9",
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-8303403b8e4c",
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-99b5c750d1d1",
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-9c79feec4b9b",
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-a63fd4f9dcc0",
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-acb56658fe7e",
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-c59788ef5676",
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-d842d36db450",
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-d952b82c2597",
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-ddeca9708b63",
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-e675f0a672d8",
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-e69ffce323c3",
"todo.unnecessary-lambda-memoization",
]);
export default skipFilter;
+11 -5
View File
@@ -6,16 +6,19 @@
*/
import chalk from "chalk";
import { TestFixture } from "fixture-test-utils";
import { getFixtures, readTestFilter } from "fixture-test-utils";
import {
FILTER_FILENAME,
TestFixture,
getFixtures,
readTestFilter,
} from "fixture-test-utils";
import { Worker } from "jest-worker";
import process from "process";
import * as readline from "readline";
import * as RunnerWorker from "./runner-worker";
import yargs from "yargs";
import { hideBin } from "yargs/helpers";
import SproutTodoFilter from "./SproutTodoFilter";
import { FILTER_FILENAME } from "fixture-test-utils";
import * as RunnerWorker from "./runner-worker";
const WORKER_PATH = require.resolve("./runner-worker");
readline.emitKeypressEvents(process.stdin);
@@ -186,7 +189,10 @@ export async function main(opts: RunnerOptions): Promise<void> {
const validFixtures = new Map();
for (const [name, fixture] of allFixtures) {
if (fixture.basename.startsWith("error.")) {
if (
fixture.basename.startsWith("error.") ||
fixture.basename.startsWith("todo.error.")
) {
// skip
continue;
}