Skip to content

Commit 249f33c

Browse files
committed
test(linter): Add tests for is_es5_component and is_es6_component react utils (#19656)
Source code parsing logic in these tests was generated by Claude Code. Test React components/code snippets mainly by me.
1 parent b3b2d30 commit 249f33c

File tree

1 file changed

+89
-0
lines changed

1 file changed

+89
-0
lines changed

crates/oxc_linter/src/utils/react.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,4 +789,93 @@ mod test {
789789
assert!(!is_react_hook_name("user"));
790790
assert!(!is_react_hook_name("use_state"));
791791
}
792+
793+
#[test]
794+
fn test_is_es5_component() {
795+
use oxc_parser::Parser;
796+
use oxc_semantic::SemanticBuilder;
797+
use oxc_span::SourceType;
798+
799+
// Returns true if any of the nodes in the code snippets are an es5 component.
800+
let cases: Vec<(&str, bool)> = vec![
801+
("createReactClass({})", true),
802+
("React.createReactClass({})", true),
803+
("createReactClass({ render() {} })", true),
804+
("/* createReactClass({ render() {} }) */", false),
805+
("// createReactClass({ render() {} })", false),
806+
("somethingElse({})", false),
807+
("React.somethingElse({})", false),
808+
("let x = 1;", false),
809+
];
810+
811+
for (source, expected) in cases {
812+
let allocator = Allocator::default();
813+
let source_type = SourceType::jsx();
814+
let parser_ret = Parser::new(&allocator, source, source_type).parse();
815+
assert!(parser_ret.errors.is_empty(), "Parse error in: {source}");
816+
let semantic =
817+
SemanticBuilder::new().build(allocator.alloc(parser_ret.program)).semantic;
818+
819+
let found = semantic.nodes().iter().any(|node| is_es5_component(node));
820+
assert_eq!(found, expected, "Failed for: {source}");
821+
}
822+
}
823+
824+
#[test]
825+
fn test_is_es6_component() {
826+
use oxc_parser::Parser;
827+
use oxc_semantic::SemanticBuilder;
828+
use oxc_span::SourceType;
829+
830+
// Returns true if any of the nodes in the code snippets are an es6 component.
831+
let cases: Vec<(&str, bool)> = vec![
832+
("class Foo extends React.Component {}", true),
833+
("class Foo extends React.PureComponent {}", true),
834+
("class Foo extends Component {}", true),
835+
("class Foo extends PureComponent {}", true),
836+
("class Foo extends Bar {}", false),
837+
("/* class Foo extends PureComponent {} */", false),
838+
("// class Foo extends PureComponent {}", false),
839+
("class Foo {}", false),
840+
("function Foo() {}", false),
841+
("const Foo = () => {}", false),
842+
("const Component = () => {}", false),
843+
("let Component = () => {}", false),
844+
// Not an es6 component, this is a function component.
845+
(
846+
"
847+
export function Foo({ to, children }: { to: string; children: React.ReactNode }) {
848+
return (
849+
<Link className={linkClass} to={to}>
850+
{children}
851+
</Link>
852+
)
853+
}",
854+
false,
855+
),
856+
(
857+
r#"
858+
export const Bar = ({ ...props }: React.ComponentProps<'button'>) => {
859+
return (
860+
<button type="button" className={linkClass} {...props}>
861+
<Foo />
862+
</button>
863+
)
864+
}"#,
865+
false,
866+
),
867+
];
868+
869+
for (source, expected) in cases {
870+
let allocator = Allocator::default();
871+
let source_type = SourceType::tsx();
872+
let parser_ret = Parser::new(&allocator, source, source_type).parse();
873+
assert!(parser_ret.errors.is_empty(), "Parse error in: {source}");
874+
let semantic =
875+
SemanticBuilder::new().build(allocator.alloc(parser_ret.program)).semantic;
876+
877+
let found = semantic.nodes().iter().any(|node| is_es6_component(node));
878+
assert_eq!(found, expected, "Failed for: {source}");
879+
}
880+
}
792881
}

0 commit comments

Comments
 (0)