Skip to content

Commit d856a6c

Browse files
authored
Convert class components to functional components with hooks in test fixtures (vadimdemedes#914)
1 parent 0dc4dfa commit d856a6c

11 files changed

Lines changed: 194 additions & 315 deletions

examples/jest/jest.tsx

Lines changed: 49 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react';
1+
import React, {useState, useEffect, useCallback} from 'react';
22
import PQueue from 'p-queue';
33
import delay from 'delay';
44
import ms from 'ms';
@@ -19,88 +19,67 @@ const paths = [
1919
'tests/comments.js',
2020
];
2121

22-
type State = {
23-
startTime: number;
24-
completedTests: Array<{
25-
path: string;
26-
status: string;
27-
}>;
28-
runningTests: Array<{
29-
path: string;
30-
status: string;
31-
}>;
22+
type TestResult = {
23+
path: string;
24+
status: string;
3225
};
3326

34-
class Jest extends React.Component<Record<string, unknown>, State> {
35-
state: State = {
36-
startTime: Date.now(),
37-
completedTests: [],
38-
runningTests: [],
39-
};
27+
function Jest() {
28+
const [startTime, setStartTime] = useState(Date.now);
29+
const [completedTests, setCompletedTests] = useState<TestResult[]>([]);
30+
const [runningTests, setRunningTests] = useState<TestResult[]>([]);
4031

41-
render() {
42-
const {startTime, completedTests, runningTests} = this.state;
32+
const runTest = useCallback(async (path: string) => {
33+
setRunningTests(previous => [
34+
...previous,
35+
{
36+
status: 'runs',
37+
path,
38+
},
39+
]);
4340

44-
return (
45-
<Box flexDirection="column">
46-
<Static items={completedTests}>
47-
{test => (
48-
<Test key={test.path} status={test.status} path={test.path} />
49-
)}
50-
</Static>
51-
52-
{runningTests.length > 0 && (
53-
<Box flexDirection="column" marginTop={1}>
54-
{runningTests.map(test => (
55-
<Test key={test.path} status={test.status} path={test.path} />
56-
))}
57-
</Box>
58-
)}
41+
await delay(1000 * Math.random());
5942

60-
<Summary
61-
isFinished={runningTests.length === 0}
62-
passed={completedTests.filter(test => test.status === 'pass').length}
63-
failed={completedTests.filter(test => test.status === 'fail').length}
64-
time={ms(Date.now() - startTime)}
65-
/>
66-
</Box>
67-
);
68-
}
43+
setRunningTests(previous => previous.filter(test => test.path !== path));
44+
setCompletedTests(previous => [
45+
...previous,
46+
{
47+
status: Math.random() < 0.5 ? 'pass' : 'fail',
48+
path,
49+
},
50+
]);
51+
}, []);
6952

70-
componentDidMount() {
53+
useEffect(() => {
7154
const queue = new PQueue({concurrency: 4});
7255

7356
for (const path of paths) {
74-
void queue.add(this.runTest.bind(this, path));
57+
void queue.add(async () => runTest(path));
7558
}
76-
}
59+
}, [runTest]);
7760

78-
async runTest(path: string) {
79-
this.setState(previousState => ({
80-
runningTests: [
81-
...previousState.runningTests,
82-
{
83-
status: 'runs',
84-
path,
85-
},
86-
],
87-
}));
61+
return (
62+
<Box flexDirection="column">
63+
<Static items={completedTests}>
64+
{test => <Test key={test.path} status={test.status} path={test.path} />}
65+
</Static>
8866

89-
await delay(1000 * Math.random());
67+
{runningTests.length > 0 && (
68+
<Box flexDirection="column" marginTop={1}>
69+
{runningTests.map(test => (
70+
<Test key={test.path} status={test.status} path={test.path} />
71+
))}
72+
</Box>
73+
)}
9074

91-
this.setState(previousState => ({
92-
runningTests: previousState.runningTests.filter(
93-
test => test.path !== path,
94-
),
95-
completedTests: [
96-
...previousState.completedTests,
97-
{
98-
status: Math.random() < 0.5 ? 'pass' : 'fail',
99-
path,
100-
},
101-
],
102-
}));
103-
}
75+
<Summary
76+
isFinished={runningTests.length === 0}
77+
passed={completedTests.filter(test => test.status === 'pass').length}
78+
failed={completedTests.filter(test => test.status === 'fail').length}
79+
time={ms(Date.now() - startTime)}
80+
/>
81+
</Box>
82+
);
10483
}
10584

10685
render(<Jest />);

test/components.tsx

Lines changed: 37 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -583,18 +583,16 @@ test('disable raw mode when all input components are unmounted', t => {
583583
debug: true,
584584
};
585585

586-
class Input extends React.Component<{setRawMode: (mode: boolean) => void}> {
587-
override render() {
588-
return <Text>Test</Text>;
589-
}
586+
function Input({setRawMode}: {readonly setRawMode: (mode: boolean) => void}) {
587+
useEffect(() => {
588+
setRawMode(true);
590589

591-
override componentDidMount() {
592-
this.props.setRawMode(true);
593-
}
590+
return () => {
591+
setRawMode(false);
592+
};
593+
}, [setRawMode]);
594594

595-
override componentWillUnmount() {
596-
this.props.setRawMode(false);
597-
}
595+
return <Text>Test</Text>;
598596
}
599597

600598
function Test({
@@ -653,18 +651,16 @@ test('re-ref stdin when input is used after previous unmount', t => {
653651
debug: true,
654652
};
655653

656-
class Input extends React.Component<{setRawMode: (mode: boolean) => void}> {
657-
override render() {
658-
return <Text>Test</Text>;
659-
}
654+
function Input({setRawMode}: {readonly setRawMode: (mode: boolean) => void}) {
655+
useEffect(() => {
656+
setRawMode(true);
660657

661-
override componentDidMount() {
662-
this.props.setRawMode(true);
663-
}
658+
return () => {
659+
setRawMode(false);
660+
};
661+
}, [setRawMode]);
664662

665-
override componentWillUnmount() {
666-
this.props.setRawMode(false);
667-
}
663+
return <Text>Test</Text>;
668664
}
669665

670666
function Test({onInput}: {readonly onInput: (input: string) => void}) {
@@ -740,26 +736,24 @@ test('setRawMode() should throw if raw mode is not supported', t => {
740736
debug: true,
741737
};
742738

743-
class Input extends React.Component<{setRawMode: (mode: boolean) => void}> {
744-
override render() {
745-
return <Text>Test</Text>;
746-
}
747-
748-
override componentDidMount() {
739+
function Input({setRawMode}: {readonly setRawMode: (mode: boolean) => void}) {
740+
useEffect(() => {
749741
try {
750-
this.props.setRawMode(true);
742+
setRawMode(true);
751743
} catch (error: unknown) {
752744
didCatchInMount(error);
753745
}
754-
}
755746

756-
override componentWillUnmount() {
757-
try {
758-
this.props.setRawMode(false);
759-
} catch (error: unknown) {
760-
didCatchInUnmount(error);
761-
}
762-
}
747+
return () => {
748+
try {
749+
setRawMode(false);
750+
} catch (error: unknown) {
751+
didCatchInUnmount(error);
752+
}
753+
};
754+
}, [setRawMode]);
755+
756+
return <Text>Test</Text>;
763757
}
764758

765759
function Test() {
@@ -789,18 +783,16 @@ test('render different component based on whether stdin is a TTY or not', t => {
789783
debug: true,
790784
};
791785

792-
class Input extends React.Component<{setRawMode: (mode: boolean) => void}> {
793-
override render() {
794-
return <Text>Test</Text>;
795-
}
786+
function Input({setRawMode}: {readonly setRawMode: (mode: boolean) => void}) {
787+
useEffect(() => {
788+
setRawMode(true);
796789

797-
override componentDidMount() {
798-
this.props.setRawMode(true);
799-
}
790+
return () => {
791+
setRawMode(false);
792+
};
793+
}, [setRawMode]);
800794

801-
override componentWillUnmount() {
802-
this.props.setRawMode(false);
803-
}
795+
return <Text>Test</Text>;
804796
}
805797

806798
function Test({

test/fixtures/ci.tsx

Lines changed: 24 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,38 @@
1-
import React from 'react';
1+
import React, {useState, useEffect, useRef} from 'react';
22
import {render, Static, Text} from '../../src/index.js';
33

4-
type TestState = {
5-
counter: number;
6-
items: string[];
7-
};
4+
function Test() {
5+
const [items, setItems] = useState<string[]>([]);
6+
const [counter, setCounter] = useState(0);
7+
const counterRef = useRef(0);
8+
const timerRef = useRef<NodeJS.Timeout>(undefined);
89

9-
class Test extends React.Component<Record<string, unknown>, TestState> {
10-
timer?: NodeJS.Timeout;
11-
12-
override state: TestState = {
13-
items: [],
14-
counter: 0,
15-
};
16-
17-
override render() {
18-
return (
19-
<>
20-
<Static items={this.state.items}>
21-
{item => <Text key={item}>{item}</Text>}
22-
</Static>
23-
24-
<Text>Counter: {this.state.counter}</Text>
25-
</>
26-
);
27-
}
28-
29-
override componentDidMount() {
10+
useEffect(() => {
3011
const onTimeout = () => {
31-
if (this.state.counter > 4) {
12+
if (counterRef.current > 4) {
3213
return;
3314
}
3415

35-
this.setState(prevState => ({
36-
counter: prevState.counter + 1,
37-
items: [...prevState.items, `#${prevState.counter + 1}`],
38-
}));
16+
counterRef.current += 1;
17+
setCounter(counterRef.current);
18+
setItems(prevItems => [...prevItems, `#${counterRef.current}`]);
19+
timerRef.current = setTimeout(onTimeout, 20);
20+
};
21+
22+
timerRef.current = setTimeout(onTimeout, 20);
3923

40-
this.timer = setTimeout(onTimeout, 20);
24+
return () => {
25+
clearTimeout(timerRef.current);
4126
};
27+
}, []);
4228

43-
this.timer = setTimeout(onTimeout, 20);
44-
}
29+
return (
30+
<>
31+
<Static items={items}>{item => <Text key={item}>{item}</Text>}</Static>
4532

46-
override componentWillUnmount() {
47-
clearTimeout(this.timer);
48-
}
33+
<Text>Counter: {counter}</Text>
34+
</>
35+
);
4936
}
5037

5138
render(<Test />);

test/fixtures/exit-double-raw-mode.tsx

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
11
import process from 'node:process';
2-
import React from 'react';
2+
import React, {useEffect} from 'react';
33
import {Text, render, useStdin} from '../../src/index.js';
44

5-
class ExitDoubleRawMode extends React.Component<{
6-
setRawMode: (value: boolean) => void;
7-
}> {
8-
override render() {
9-
return <Text>Hello World</Text>;
10-
}
11-
12-
override componentDidMount() {
13-
const {setRawMode} = this.props;
5+
function Test() {
6+
const {setRawMode} = useStdin();
147

8+
useEffect(() => {
159
setRawMode(true);
1610

1711
setTimeout(() => {
@@ -21,13 +15,9 @@ class ExitDoubleRawMode extends React.Component<{
2115
// Start the test
2216
process.stdout.write('s');
2317
}, 500);
24-
}
25-
}
26-
27-
function Test() {
28-
const {setRawMode} = useStdin();
18+
}, [setRawMode]);
2919

30-
return <ExitDoubleRawMode setRawMode={setRawMode} />;
20+
return <Text>Hello World</Text>;
3121
}
3222

3323
const {unmount, waitUntilExit} = render(<Test />);

0 commit comments

Comments
 (0)