Skip to content
This repository was archived by the owner on Jun 2, 2024. It is now read-only.

Commit 5304937

Browse files
authored
test(showasync): increase test coverage in ShowAsync component (#35)
1 parent 46e5119 commit 5304937

File tree

2 files changed

+123
-135
lines changed

2 files changed

+123
-135
lines changed

src/components/ShowAsync/ShowAsync.tsx

Lines changed: 32 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -47,25 +47,9 @@ export class ShowAsync extends React.Component<IShowAsyncProps, IShowAsyncState>
4747
// Initialize state
4848
public readonly state: IShowAsyncState = initialState;
4949

50-
// Create escape hatch to stop handling of promise if unmounted
51-
public unmounted = false;
52-
53-
public componentDidMount() {
50+
public async componentDidMount() {
5451
// Start handling the promise, must happen after mount as setState is called when promise is handled
55-
this.handlePromise(this.props.when);
56-
}
57-
58-
public componentDidUpdate(prevProps: IShowAsyncProps) {
59-
if (this.props.when !== prevProps.when) {
60-
this.setState({
61-
status: statusTypes.none,
62-
});
63-
this.handlePromise(this.props.when);
64-
}
65-
}
66-
67-
public componentWillUnmount() {
68-
this.unmounted = true;
52+
await this.handlePromise(this.props.when);
6953
}
7054

7155
public render() {
@@ -74,7 +58,10 @@ export class ShowAsync extends React.Component<IShowAsyncProps, IShowAsyncState>
7458

7559
switch (status) {
7660
case statusTypes.pending:
77-
return pending ? pending() : null;
61+
if (pending) {
62+
return pending();
63+
}
64+
break;
7865

7966
case statusTypes.resolved:
8067
if (children && typeof children === 'function') {
@@ -83,46 +70,42 @@ export class ShowAsync extends React.Component<IShowAsyncProps, IShowAsyncState>
8370
if (render) {
8471
return render(value);
8572
}
86-
return null;
73+
break;
8774

8875
case statusTypes.rejected:
89-
return rejected ? rejected(value) : null;
76+
if (rejected) {
77+
return rejected(value);
78+
}
79+
break;
80+
9081
default:
91-
return null;
82+
break;
9283
}
84+
85+
return null;
9386
}
9487

95-
// Promise resolver function
96-
private handlePromise(promise: Promise<any>) {
97-
// Store the current promise to fast exit if promise is change during handling
98-
const currentPromise = promise;
99-
this.setState({
100-
status: statusTypes.pending,
88+
private setStateAsync(state: any) {
89+
return new Promise(resolve => {
90+
this.setState(state, resolve);
10191
});
102-
promise
92+
}
93+
94+
// Promise resolver function
95+
private async handlePromise(promise: Promise<any>) {
96+
await this.setStateAsync({ status: statusTypes.pending });
97+
await promise
10398
.then(success => {
104-
// Escape early as promise is changed
105-
if (currentPromise !== promise) {
106-
return;
107-
}
108-
if (!this.unmounted) {
109-
this.setState({
110-
status: statusTypes.resolved,
111-
value: success,
112-
});
113-
}
99+
this.setStateAsync({
100+
status: statusTypes.resolved,
101+
value: success,
102+
});
114103
})
115104
.catch(reason => {
116-
// Escape early as promise is changed
117-
if (currentPromise !== promise) {
118-
return;
119-
}
120-
if (!this.unmounted) {
121-
this.setState({
122-
status: statusTypes.rejected,
123-
value: reason,
124-
});
125-
}
105+
this.setStateAsync({
106+
status: statusTypes.rejected,
107+
value: reason,
108+
});
126109
});
127110
}
128111
}

src/components/ShowAsync/index.test.tsx

Lines changed: 91 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -3,125 +3,130 @@ import * as React from 'react';
33

44
import ShowAsync from './';
55

6-
const timeout = 100;
7-
8-
const resolvable = resolved =>
6+
const resolve = () =>
97
new Promise(resolve => {
108
setTimeout(() => {
11-
resolve(resolved);
12-
}, timeout);
9+
resolve('resolve');
10+
}, 10);
1311
});
14-
15-
const rejectable = rejected =>
12+
const reject = () =>
1613
new Promise((_, reject) => {
1714
setTimeout(() => {
18-
reject(rejected);
19-
}, timeout);
15+
reject('reject');
16+
}, 10);
2017
});
21-
22-
const getPromiseStatus = wrapper => wrapper.state('status');
23-
24-
describe('resolve', () => {
25-
test('no pending, resolve, reject', () => {
26-
const wrapper = mount(<ShowAsync when={resolvable('resolved')} />);
27-
expect(wrapper.html()).toEqual(null);
18+
const waitForResult = () =>
19+
new Promise(resolve => {
20+
setTimeout(resolve, 11);
2821
});
22+
const getPromise = wrapper => wrapper.prop('when');
23+
const pendingResult = '<div>pending</div>';
24+
const resolveResult = '<div>resolve</div>';
25+
const rejectResult = '<div>reject</div>';
26+
27+
describe('render tests', () => {
28+
test('resolve with nothing', async () => {
29+
const element = <ShowAsync when={resolve()} />;
30+
const wrapper = mount(element);
2931

30-
test('pending', () => {
31-
const pending = () => <p>horse</p>;
32-
const result = '<p>horse</p>';
33-
const wrapper = mount(<ShowAsync when={resolvable('resolved')} pending={pending} />);
34-
expect(wrapper.html()).toEqual(result);
32+
await expect(wrapper.html()).toEqual(null);
33+
await waitForResult();
34+
await expect(wrapper.html()).toEqual(null);
3535
});
3636

37-
test('resolve with render', done => {
38-
const resolved = value => <p>{value}</p>;
39-
const result = '<p>resolved</p>';
40-
const wrapper = mount(<ShowAsync when={resolvable('resolved')} render={resolved} />);
41-
setTimeout(() => {
42-
expect(wrapper.html()).toEqual(result);
43-
done();
44-
}, timeout + 50);
37+
test('reject with nothing', async () => {
38+
const element = <ShowAsync when={reject()} />;
39+
const wrapper = mount(element);
40+
41+
await expect(wrapper.html()).toEqual(null);
42+
await waitForResult();
43+
await expect(wrapper.html()).toEqual(null);
4544
});
4645

47-
test('resolve with children', done => {
48-
const result = '<p>resolved</p>';
49-
const wrapper = mount(
50-
<ShowAsync when={resolvable('resolved')}>{value => <p>{value}</p>}</ShowAsync>,
46+
test('pending then resolve', async () => {
47+
const element = (
48+
<ShowAsync when={resolve()} pending={() => <div>pending</div>}>
49+
{value => <div>{value}</div>}
50+
</ShowAsync>
5151
);
52-
setTimeout(() => {
53-
expect(wrapper.html()).toEqual(result);
54-
done();
55-
}, timeout + 50);
52+
const wrapper = mount(element);
53+
54+
await expect(wrapper.html()).toEqual(pendingResult);
55+
await waitForResult();
56+
await expect(wrapper.html()).toEqual(resolveResult);
5657
});
5758

58-
test('resolve', done => {
59-
const rejected = value => <p>{value}</p>;
60-
const result = '<p>rejected</p>';
61-
const wrapper = mount(
62-
<ShowAsync when={rejectable('rejected')} rejected={rejected} />,
59+
test('no pending then resolve', async () => {
60+
const element = (
61+
<ShowAsync when={resolve()}>{value => <div>{value}</div>}</ShowAsync>
6362
);
64-
setTimeout(() => {
65-
expect(wrapper.html()).toEqual(result);
66-
done();
67-
}, timeout + 50);
63+
const wrapper = mount(element);
64+
65+
await expect(wrapper.html()).toEqual(null);
66+
await waitForResult();
67+
await expect(wrapper.html()).toEqual(resolveResult);
6868
});
6969

70-
test('lifecycle', () => {
70+
test('pending then reject', async () => {
7171
const element = (
7272
<ShowAsync
73-
when={resolvable('result')}
73+
when={reject()}
7474
pending={() => <div>pending</div>}
75-
rejected={() => <div>rejected</div>}
76-
>
77-
{value => <div>{value}</div>}
78-
</ShowAsync>
75+
rejected={() => <div>reject</div>}
76+
/>
7977
);
8078
const wrapper = mount(element);
8179

82-
if (getPromiseStatus(wrapper) === 'pending') {
83-
expect(wrapper.html()).toEqual('<div>pending</div>');
84-
}
80+
await expect(wrapper.html()).toEqual(pendingResult);
81+
await waitForResult();
82+
await expect(wrapper.html()).toEqual(rejectResult);
83+
});
8584

86-
if (getPromiseStatus(wrapper) === 'resolved') {
87-
expect(wrapper.html()).toEqual('<div>result</div>');
88-
}
85+
test('no pending then reject', async () => {
86+
const element = <ShowAsync when={reject()} rejected={() => <div>reject</div>} />;
87+
const wrapper = mount(element);
8988

90-
wrapper.setProps({ when: rejectable('rejected') });
89+
await expect(wrapper.html()).toEqual(null);
90+
await waitForResult();
91+
await expect(wrapper.html()).toEqual(rejectResult);
92+
});
93+
});
9194

92-
if (getPromiseStatus(wrapper) === 'pending') {
93-
expect(wrapper.html()).toEqual('<div>pending</div>');
94-
}
95+
describe('promise tests', () => {
96+
test('reject without rejected', async () => {
97+
const element = <ShowAsync when={reject()} />;
98+
const wrapper = mount(element);
9599

96-
if (getPromiseStatus(wrapper) === 'rejected') {
97-
expect(wrapper.html()).toEqual('<div>rejected</div>');
98-
}
100+
await expect(getPromise(wrapper)).rejects.toEqual('reject');
101+
});
99102

100-
wrapper.unmount();
103+
test('reject with rejected', async () => {
104+
const element = <ShowAsync when={reject()} rejected={error => <div>{error}</div>} />;
105+
const wrapper = mount(element);
101106

102-
expect(wrapper.html()).toEqual(null);
107+
await expect(getPromise(wrapper)).rejects.toEqual('reject');
108+
});
103109

104-
wrapper.mount();
110+
test('resolve without children/render', async () => {
111+
const element = <ShowAsync when={resolve()} />;
112+
const wrapper = mount(element);
105113

106-
wrapper.setProps({ when: rejectable('rejected'), rejected: undefined });
107-
if (getPromiseStatus(wrapper) === 'rejected') {
108-
expect(wrapper.html()).toEqual(null);
109-
}
114+
await expect(getPromise(wrapper)).resolves.toEqual('resolve');
115+
});
110116

111-
wrapper.setProps({
112-
when: resolvable('result'),
113-
render: undefined,
114-
children: undefined,
115-
});
116-
if (getPromiseStatus(wrapper) === 'resolved') {
117-
expect(wrapper.html()).toEqual(null);
118-
}
117+
test('resolve with children', async () => {
118+
const element = (
119+
<ShowAsync when={resolve()}>{value => <div>{value}</div>}</ShowAsync>
120+
);
121+
const wrapper = mount(element);
122+
123+
await expect(getPromise(wrapper)).resolves.toEqual('resolve');
124+
});
125+
126+
test('resolve with render', async () => {
127+
const element = <ShowAsync when={resolve()} render={value => <div>{value}</div>} />;
128+
const wrapper = mount(element);
119129

120-
wrapper.unmount();
121-
wrapper.mount();
122-
wrapper.setProps({ pending: undefined });
123-
if (getPromiseStatus(wrapper) === 'pending') {
124-
expect(wrapper.html()).toEqual(null);
125-
}
130+
await expect(getPromise(wrapper)).resolves.toEqual('resolve');
126131
});
127132
});

0 commit comments

Comments
 (0)