Skip to content

Commit 0641700

Browse files
committed
Add tests for getTypeFromReactComponent and remove unnecessary resolveToValue call
1 parent f0c32ab commit 0641700

File tree

4 files changed

+205
-2
lines changed

4 files changed

+205
-2
lines changed

.changeset/lazy-walls-swim.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'react-docgen': patch
3+
---
4+
5+
Remove unnecessary call to `resolveToValue` when trying to find props type from
6+
react components.
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2+
3+
exports[`getTypeFromReactComponent > Flow > classes > finds props type in new params 1`] = `
4+
Node {
5+
"id": Node {
6+
"name": "Props",
7+
"type": "Identifier",
8+
},
9+
"type": "GenericTypeAnnotation",
10+
"typeParameters": null,
11+
}
12+
`;
13+
14+
exports[`getTypeFromReactComponent > Flow > classes > finds props type in old params 1`] = `
15+
Node {
16+
"id": Node {
17+
"name": "Props",
18+
"type": "Identifier",
19+
},
20+
"type": "GenericTypeAnnotation",
21+
"typeParameters": null,
22+
}
23+
`;
24+
25+
exports[`getTypeFromReactComponent > Flow > classes > finds props type in properties 1`] = `
26+
Node {
27+
"id": Node {
28+
"name": "Props",
29+
"type": "Identifier",
30+
},
31+
"type": "GenericTypeAnnotation",
32+
"typeParameters": null,
33+
}
34+
`;
35+
36+
exports[`getTypeFromReactComponent > Flow > stateless > finds param type annotation 1`] = `
37+
Node {
38+
"id": Node {
39+
"name": "Props",
40+
"type": "Identifier",
41+
},
42+
"type": "GenericTypeAnnotation",
43+
"typeParameters": null,
44+
}
45+
`;
46+
47+
exports[`getTypeFromReactComponent > TypeScript > classes > finds props type in params 1`] = `
48+
Node {
49+
"type": "TSTypeReference",
50+
"typeName": Node {
51+
"name": "Props",
52+
"type": "Identifier",
53+
},
54+
}
55+
`;
56+
57+
exports[`getTypeFromReactComponent > TypeScript > classes > finds props type in properties 1`] = `
58+
Node {
59+
"type": "TSTypeReference",
60+
"typeName": Node {
61+
"name": "Props",
62+
"type": "Identifier",
63+
},
64+
}
65+
`;
66+
67+
exports[`getTypeFromReactComponent > TypeScript > stateless > finds param type annotation 1`] = `
68+
Node {
69+
"type": "TSTypeReference",
70+
"typeName": Node {
71+
"name": "Props",
72+
"type": "Identifier",
73+
},
74+
}
75+
`;
76+
77+
exports[`getTypeFromReactComponent > handles no class props 1`] = `null`;
78+
79+
exports[`getTypeFromReactComponent > handles no stateless props 1`] = `null`;
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import type {
2+
ArrowFunctionExpression,
3+
ClassDeclaration,
4+
VariableDeclaration,
5+
} from '@babel/types';
6+
import { parse, parseTypescript } from '../../../tests/utils';
7+
import getTypeFromReactComponent from '../getTypeFromReactComponent.js';
8+
import { describe, expect, test } from 'vitest';
9+
import type { NodePath } from '@babel/traverse';
10+
11+
describe('getTypeFromReactComponent', () => {
12+
test('handles no stateless props', () => {
13+
const path = parseTypescript
14+
.statementLast<VariableDeclaration>(`const x = () => {}`)
15+
.get('declarations')[0]
16+
.get('init') as NodePath<ArrowFunctionExpression>;
17+
18+
expect(getTypeFromReactComponent(path)).toMatchSnapshot();
19+
});
20+
21+
test('handles no class props', () => {
22+
const path = parseTypescript.statementLast<ClassDeclaration>(
23+
`import React from 'react';
24+
class X extends React.Component {
25+
render() {}
26+
}`,
27+
);
28+
29+
expect(getTypeFromReactComponent(path)).toMatchSnapshot();
30+
});
31+
32+
describe('TypeScript', () => {
33+
describe('stateless', () => {
34+
test('finds param type annotation', () => {
35+
const path = parseTypescript
36+
.statementLast<VariableDeclaration>(`const x = (props: Props) => {}`)
37+
.get('declarations')[0]
38+
.get('init') as NodePath<ArrowFunctionExpression>;
39+
40+
expect(getTypeFromReactComponent(path)).toMatchSnapshot();
41+
});
42+
});
43+
44+
describe('classes', () => {
45+
test('finds props type in params', () => {
46+
const path = parseTypescript.statementLast<ClassDeclaration>(
47+
`import React from 'react';
48+
class X extends React.Component<Props, State> {
49+
render() {}
50+
}`,
51+
);
52+
53+
expect(getTypeFromReactComponent(path)).toMatchSnapshot();
54+
});
55+
56+
test('finds props type in properties', () => {
57+
const path = parseTypescript.statementLast<ClassDeclaration>(
58+
`import React from 'react';
59+
class X extends React.Component {
60+
props: Props;
61+
render() {}
62+
}`,
63+
);
64+
65+
expect(getTypeFromReactComponent(path)).toMatchSnapshot();
66+
});
67+
});
68+
});
69+
70+
describe('Flow', () => {
71+
describe('stateless', () => {
72+
test('finds param type annotation', () => {
73+
const path = parse
74+
.statementLast<VariableDeclaration>(`const x = (props: Props) => {}`)
75+
.get('declarations')[0]
76+
.get('init') as NodePath<ArrowFunctionExpression>;
77+
78+
expect(getTypeFromReactComponent(path)).toMatchSnapshot();
79+
});
80+
});
81+
82+
describe('classes', () => {
83+
test('finds props type in new params', () => {
84+
const path = parse.statementLast<ClassDeclaration>(
85+
`import React from 'react';
86+
class X extends React.Component<Props, State> {
87+
render() {}
88+
}`,
89+
);
90+
91+
expect(getTypeFromReactComponent(path)).toMatchSnapshot();
92+
});
93+
94+
test('finds props type in old params', () => {
95+
const path = parse.statementLast<ClassDeclaration>(
96+
`import React from 'react';
97+
class X extends React.Component<DefaultProps, Props, State> {
98+
render() {}
99+
}`,
100+
);
101+
102+
expect(getTypeFromReactComponent(path)).toMatchSnapshot();
103+
});
104+
105+
test('finds props type in properties', () => {
106+
const path = parse.statementLast<ClassDeclaration>(
107+
`import React from 'react';
108+
class X extends React.Component {
109+
props: Props;
110+
render() {}
111+
}`,
112+
);
113+
114+
expect(getTypeFromReactComponent(path)).toMatchSnapshot();
115+
});
116+
});
117+
});
118+
});

packages/react-docgen/src/utils/getTypeFromReactComponent.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import getTypeIdentifier from './getTypeIdentifier.js';
2727
function getStatelessPropsPath(
2828
componentDefinition: NodePath,
2929
): NodePath | undefined {
30-
let value = resolveToValue(componentDefinition);
30+
let value = componentDefinition;
3131

3232
if (isReactForwardRefCall(value)) {
3333
value = resolveToValue(value.get('arguments')[0]!);
@@ -40,7 +40,7 @@ function getStatelessPropsPath(
4040

4141
/**
4242
* Given an React component (stateless or class) tries to find the
43-
* flow type for the props. If not found or not one of the supported
43+
* flow or TS type for the props. If not found or not one of the supported
4444
* component types returns null.
4545
*/
4646
export default (path: NodePath): NodePath | null => {

0 commit comments

Comments
 (0)