Skip to content

Commit 154c1d0

Browse files
committed
test(react-debug): cover source detection boundaries
1 parent 2459556 commit 154c1d0

2 files changed

Lines changed: 209 additions & 45 deletions

File tree

plugins/eslint-plugin-react-debug/src/rules/is-from-react/is-from-react.spec.ts

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ import { ruleTester } from "#/testing/helpers";
44
import { stringify } from "@/utils/stringify";
55
import rule, { RULE_NAME } from "./is-from-react";
66

7+
function reactError(name: string, importSource = "react") {
8+
return {
9+
data: {
10+
json: stringify({ name, importSource }),
11+
},
12+
messageId: "default" as const,
13+
};
14+
}
15+
716
ruleTester.run(RULE_NAME, rule, {
817
invalid: [
918
{
@@ -633,6 +642,95 @@ ruleTester.run(RULE_NAME, rule, {
633642
},
634643
},
635644
},
645+
{
646+
code: tsx`
647+
import ReactDOM from "react-dom";
648+
`,
649+
errors: [reactError("ReactDOM")],
650+
},
651+
{
652+
code: tsx`
653+
import type { ReactNode } from "react";
654+
655+
type Props = { children: ReactNode };
656+
`,
657+
errors: [
658+
reactError("ReactNode"),
659+
reactError("ReactNode"),
660+
],
661+
},
662+
{
663+
code: tsx`
664+
import * as React from "react";
665+
666+
const { Children: ReactChildren } = React;
667+
`,
668+
errors: [
669+
reactError("React"),
670+
reactError("ReactChildren"),
671+
reactError("React"),
672+
],
673+
},
674+
{
675+
code: tsx`
676+
import React from "react";
677+
678+
const Children = React["Children"];
679+
`,
680+
errors: [
681+
reactError("React"),
682+
reactError("Children"),
683+
reactError("React"),
684+
],
685+
},
686+
{
687+
code: tsx`
688+
import React from "react";
689+
690+
const only = React.Children.only;
691+
`,
692+
errors: [
693+
reactError("React"),
694+
reactError("React"),
695+
reactError("Children"),
696+
],
697+
},
698+
{
699+
code: tsx`
700+
import { Component } from "react";
701+
702+
let Alias;
703+
Alias = Component;
704+
const Copy = Alias;
705+
`,
706+
errors: [
707+
reactError("Component"),
708+
reactError("Component"),
709+
],
710+
},
711+
{
712+
code: tsx`
713+
const React = {};
714+
React.Children;
715+
`,
716+
errors: [
717+
reactError("React"),
718+
reactError("React"),
719+
reactError("Children"),
720+
],
721+
},
722+
{
723+
code: tsx`
724+
import { memo } from "react";
725+
726+
const wrapped = memo as unknown;
727+
`,
728+
errors: [
729+
reactError("memo"),
730+
reactError("wrapped"),
731+
reactError("memo"),
732+
],
733+
},
636734
],
637735
valid: [
638736
{
@@ -707,5 +805,16 @@ ruleTester.run(RULE_NAME, rule, {
707805
},
708806
},
709807
},
808+
tsx`
809+
export { memo } from "react";
810+
`,
811+
tsx`
812+
const library = require(source);
813+
const Children = library.Children;
814+
`,
815+
tsx`
816+
const Reactish = {};
817+
const value = Reactish.Children;
818+
`,
710819
],
711820
});

plugins/eslint-plugin-react-debug/src/rules/is-from-ref/is-from-ref.spec.ts

Lines changed: 100 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ import { ruleTester } from "#/testing/helpers";
44
import { stringify } from "@/utils/stringify";
55
import rule, { RULE_NAME } from "./is-from-ref";
66

7+
function refError(name: string, init: string) {
8+
return {
9+
data: {
10+
json: stringify({ name, init }),
11+
},
12+
messageId: "default" as const,
13+
};
14+
}
15+
716
ruleTester.run(RULE_NAME, rule, {
817
invalid: [
918
{
@@ -17,51 +26,72 @@ ruleTester.run(RULE_NAME, rule, {
1726
}
1827
`,
1928
errors: [
20-
{
21-
data: {
22-
json: stringify({
23-
name: "myRef",
24-
init: "React.useRef(42)",
25-
}),
26-
},
27-
messageId: "default",
28-
},
29-
{
30-
data: {
31-
json: stringify({
32-
name: "value",
33-
init: "myRef.current",
34-
}),
35-
},
36-
messageId: "default",
37-
},
38-
{
39-
data: {
40-
json: stringify({
41-
name: "myRef",
42-
init: "React.useRef(42)",
43-
}),
44-
},
45-
messageId: "default",
46-
},
47-
{
48-
data: {
49-
json: stringify({
50-
name: "current",
51-
init: "React.useRef(42)",
52-
}),
53-
},
54-
messageId: "default",
55-
},
56-
{
57-
data: {
58-
json: stringify({
59-
name: "value",
60-
init: "myRef.current",
61-
}),
62-
},
63-
messageId: "default",
64-
},
29+
refError("myRef", "React.useRef(42)"),
30+
refError("value", "myRef.current"),
31+
refError("myRef", "React.useRef(42)"),
32+
refError("current", "React.useRef(42)"),
33+
refError("value", "myRef.current"),
34+
],
35+
},
36+
{
37+
code: tsx`
38+
import { useRef } from "react";
39+
40+
const ref = useRef(null);
41+
`,
42+
errors: [refError("ref", "useRef(null)")],
43+
},
44+
{
45+
code: tsx`
46+
const ref = hooks.useRef(null);
47+
`,
48+
errors: [refError("ref", "hooks.useRef(null)")],
49+
},
50+
{
51+
code: tsx`
52+
function read(ref, inputRef) {
53+
const first = ref.value;
54+
const second = inputRef.value;
55+
}
56+
`,
57+
errors: [
58+
refError("first", "ref.value"),
59+
refError("second", "inputRef.value"),
60+
],
61+
},
62+
{
63+
code: tsx`
64+
const sourceRef = useRef(null);
65+
const alias = sourceRef;
66+
const value = alias.current;
67+
`,
68+
errors: [
69+
refError("sourceRef", "useRef(null)"),
70+
refError("sourceRef", "useRef(null)"),
71+
],
72+
},
73+
{
74+
code: tsx`
75+
const myRef = useRef(null);
76+
77+
function read() {
78+
const myRef = { current: 0 };
79+
return myRef.current;
80+
}
81+
`,
82+
errors: [refError("myRef", "useRef(null)")],
83+
},
84+
{
85+
code: tsx`
86+
import React from "react";
87+
88+
const ComponentRef = React.useRef(() => null);
89+
const element = <ComponentRef.current />;
90+
`,
91+
errors: [
92+
refError("ComponentRef", "React.useRef(() => null)"),
93+
refError("ComponentRef", "React.useRef(() => null)"),
94+
refError("current", "React.useRef(() => null)"),
6595
],
6696
},
6797
],
@@ -75,5 +105,30 @@ ruleTester.run(RULE_NAME, rule, {
75105
return <div>{value}</div>;
76106
}
77107
`,
108+
tsx`
109+
import React from "react";
110+
111+
const createdRef = React.createRef();
112+
const factory = React.useRef;
113+
const similar = React.useRefValue();
114+
`,
115+
tsx`
116+
function read(reference, myref, holder, inputRef) {
117+
const fromReference = reference.current;
118+
const fromLowercase = myref.current;
119+
const fromNested = holder.inputRef.current;
120+
const fromOptional = inputRef?.current;
121+
}
122+
`,
123+
tsx`
124+
function read(sourceRef) {
125+
const alias = sourceRef;
126+
const value = alias.current;
127+
}
128+
`,
129+
tsx`
130+
let ref;
131+
ref = useRef(null);
132+
`,
78133
],
79134
});

0 commit comments

Comments
 (0)