Skip to content

Commit 19ccf75

Browse files
authored
refactor: transform test/components/Provider => ts (#1772)
1 parent 1f4d970 commit 19ccf75

File tree

4 files changed

+109
-54
lines changed

4 files changed

+109
-54
lines changed

src/exports.ts

+2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { useSelector, createSelectorHook } from './hooks/useSelector'
2727
import { useStore, createStoreHook } from './hooks/useStore'
2828

2929
import shallowEqual from './utils/shallowEqual'
30+
import type { Subscription } from '../src/utils/Subscription'
3031

3132
export * from './types'
3233
export type {
@@ -46,6 +47,7 @@ export type {
4647
MapDispatchToPropsNonObject,
4748
MergeProps,
4849
ReactReduxContextValue,
50+
Subscription,
4951
}
5052
export {
5153
Provider,

test/components/Provider.spec.js test/components/Provider.spec.tsx

+100-49
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
/*eslint-disable react/prop-types*/
22

3-
import React, { Component } from 'react'
3+
import React, { Component, Dispatch } from 'react'
44
import ReactDOM from 'react-dom'
55
import { createStore } from 'redux'
66
import { Provider, connect, ReactReduxContext } from '../../src/index'
77
import * as rtl from '@testing-library/react'
8+
import type { ReactReduxContextValue } from '../../src'
9+
import type { Store } from 'redux'
10+
811
import '@testing-library/jest-dom/extend-expect'
912

1013
const createExampleTextReducer =
@@ -21,7 +24,8 @@ describe('React', () => {
2124
render() {
2225
return (
2326
<ReactReduxContext.Consumer>
24-
{({ store }) => {
27+
{(props) => {
28+
let { store } = props as ReactReduxContextValue
2529
let text = ''
2630

2731
if (store) {
@@ -46,10 +50,6 @@ describe('React', () => {
4650
it('should not enforce a single child', () => {
4751
const store = createStore(() => ({}))
4852

49-
// Ignore propTypes warnings
50-
const propTypes = Provider.propTypes
51-
Provider.propTypes = {}
52-
5353
const spy = jest.spyOn(console, 'error').mockImplementation(() => {})
5454

5555
expect(() =>
@@ -59,7 +59,7 @@ describe('React', () => {
5959
</Provider>
6060
)
6161
).not.toThrow()
62-
62+
//@ts-expect-error
6363
expect(() => rtl.render(<Provider store={store} />)).not.toThrow(
6464
/children with exactly one child/
6565
)
@@ -73,7 +73,6 @@ describe('React', () => {
7373
)
7474
).not.toThrow(/a single React element child/)
7575
spy.mockRestore()
76-
Provider.propTypes = propTypes
7776
})
7877

7978
it('should add the store to context', () => {
@@ -94,14 +93,18 @@ describe('React', () => {
9493
})
9594

9695
it('accepts new store in props', () => {
97-
const store1 = createStore((state = 10) => state + 1)
98-
const store2 = createStore((state = 10) => state * 2)
99-
const store3 = createStore((state = 10) => state * state + 1)
100-
101-
let externalSetState
102-
class ProviderContainer extends Component {
103-
constructor() {
104-
super()
96+
const store1 = createStore((state: number = 10) => state + 1)
97+
const store2 = createStore((state: number = 10) => state * 2)
98+
const store3 = createStore((state: number = 10) => state * state + 1)
99+
100+
interface StateType {
101+
store: Store
102+
}
103+
104+
let externalSetState: Dispatch<StateType>
105+
class ProviderContainer extends Component<unknown, StateType> {
106+
constructor(props: {}) {
107+
super(props)
105108
this.state = { store: store1 }
106109
externalSetState = this.setState.bind(this)
107110
}
@@ -156,33 +159,47 @@ describe('React', () => {
156159
})
157160

158161
it('should handle subscriptions correctly when there is nested Providers', () => {
159-
const reducer = (state = 0, action) =>
162+
interface ActionType {
163+
type: string
164+
}
165+
interface TStateProps {
166+
count: number
167+
}
168+
const reducer = (state = 0, action: ActionType) =>
160169
action.type === 'INC' ? state + 1 : state
161170

162171
const innerStore = createStore(reducer)
163-
const innerMapStateToProps = jest.fn((state) => ({ count: state }))
164-
@connect(innerMapStateToProps)
165-
class Inner extends Component {
166-
render() {
172+
const innerMapStateToProps = jest.fn<TStateProps, [number]>((state) => ({
173+
count: state,
174+
}))
175+
class Inner extends Component<TStateProps> {
176+
render(): JSX.Element {
167177
return <div>{this.props.count}</div>
168178
}
169179
}
170180

181+
const WrapperInner = connect<TStateProps, unknown, unknown, number>(
182+
innerMapStateToProps
183+
)(Inner)
184+
171185
const outerStore = createStore(reducer)
172-
@connect((state) => ({ count: state }))
173186
class Outer extends Component {
174187
render() {
175188
return (
176189
<Provider store={innerStore}>
177-
<Inner />
190+
<WrapperInner />
178191
</Provider>
179192
)
180193
}
181194
}
182195

196+
const WrapperOuter = connect<TStateProps, unknown, unknown, number>(
197+
(state) => ({ count: state })
198+
)(Outer)
199+
183200
rtl.render(
184201
<Provider store={outerStore}>
185-
<Outer />
202+
<WrapperOuter />
186203
</Provider>
187204
)
188205
expect(innerMapStateToProps).toHaveBeenCalledTimes(1)
@@ -195,50 +212,69 @@ describe('React', () => {
195212
})
196213

197214
it('should pass state consistently to mapState', () => {
198-
function stringBuilder(prev = '', action) {
215+
interface ActionType {
216+
type: string
217+
body: string
218+
}
219+
function stringBuilder(prev = '', action: ActionType) {
199220
return action.type === 'APPEND' ? prev + action.body : prev
200221
}
201222

202-
const store = createStore(stringBuilder)
223+
const store: Store = createStore(stringBuilder)
203224

204225
rtl.act(() => {
205226
store.dispatch({ type: 'APPEND', body: 'a' })
206227
})
207228

208229
let childMapStateInvokes = 0
209230

210-
@connect((state) => ({ state }))
211-
class Container extends Component {
212-
emitChange() {
213-
store.dispatch({ type: 'APPEND', body: 'b' })
214-
}
231+
const childCalls: Array<Array<string>> = []
215232

233+
interface ChildContainerProps {
234+
parentState: string
235+
}
236+
class ChildContainer extends Component<ChildContainerProps> {
216237
render() {
217-
return (
218-
<div>
219-
<button onClick={this.emitChange.bind(this)}>change</button>
220-
<ChildContainer parentState={this.props.state} />
221-
</div>
222-
)
238+
return <div />
223239
}
224240
}
225241

226-
const childCalls = []
227-
@connect((state, parentProps) => {
242+
const WrapperChildrenContainer = connect<
243+
{},
244+
unknown,
245+
ChildContainerProps,
246+
string
247+
>((state, parentProps) => {
228248
childMapStateInvokes++
229249
childCalls.push([state, parentProps.parentState])
230250
// The state from parent props should always be consistent with the current state
231251
return {}
232-
})
233-
class ChildContainer extends Component {
252+
})(ChildContainer)
253+
254+
interface TStateProps {
255+
state: string
256+
}
257+
class Container extends Component<TStateProps> {
258+
emitChange() {
259+
store.dispatch({ type: 'APPEND', body: 'b' })
260+
}
261+
234262
render() {
235-
return <div />
263+
return (
264+
<div>
265+
<button onClick={this.emitChange.bind(this)}>change</button>
266+
<WrapperChildrenContainer parentState={this.props.state} />
267+
</div>
268+
)
236269
}
237270
}
271+
const WrapperContainer = connect<TStateProps, unknown, unknown, string>(
272+
(state) => ({ state })
273+
)(Container)
238274

239275
const tester = rtl.render(
240276
<Provider store={store}>
241-
<Container />
277+
<WrapperContainer />
242278
</Provider>
243279
)
244280

@@ -320,37 +356,52 @@ describe('React', () => {
320356
})
321357

322358
it('should handle store and children change in a the same render', () => {
359+
interface PropsType {
360+
value: string
361+
}
362+
interface StateType {
363+
nestedA: PropsType
364+
nestedB: PropsType
365+
}
323366
const reducerA = (state = { nestedA: { value: 'expectedA' } }) => state
324367
const reducerB = (state = { nestedB: { value: 'expectedB' } }) => state
325368

326369
const storeA = createStore(reducerA)
327370
const storeB = createStore(reducerB)
328371

329-
@connect((state) => ({ value: state.nestedA.value }))
330-
class ComponentA extends Component {
372+
class ComponentA extends Component<PropsType> {
331373
render() {
332374
return <div data-testid="value">{this.props.value}</div>
333375
}
334376
}
335377

336-
@connect((state) => ({ value: state.nestedB.value }))
337-
class ComponentB extends Component {
378+
const WrapperComponentA = connect<PropsType, unknown, unknown, StateType>(
379+
(state) => ({
380+
value: state.nestedA.value,
381+
})
382+
)(ComponentA)
383+
384+
class ComponentB extends Component<PropsType> {
338385
render() {
339386
return <div data-testid="value">{this.props.value}</div>
340387
}
341388
}
342389

390+
const WrapperComponentB = connect<PropsType, unknown, unknown, StateType>(
391+
(state) => ({ value: state.nestedB.value })
392+
)(ComponentB)
393+
343394
const { getByTestId, rerender } = rtl.render(
344395
<Provider store={storeA}>
345-
<ComponentA />
396+
<WrapperComponentA />
346397
</Provider>
347398
)
348399

349400
expect(getByTestId('value')).toHaveTextContent('expectedA')
350401

351402
rerender(
352403
<Provider store={storeB}>
353-
<ComponentB />
404+
<WrapperComponentB />
354405
</Provider>
355406
)
356407

test/hooks/useDispatch.spec.tsx

+1-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ import {
66
useDispatch,
77
createDispatchHook,
88
} from '../../src/index'
9-
import type { ProviderProps } from '../../src/'
10-
import type { ReactReduxContextValue } from '../../src/components/Context'
9+
import type { ProviderProps, ReactReduxContextValue } from '../../src/'
1110

1211
const store = createStore((c: number = 1): number => c + 1)
1312
const store2 = createStore((c: number = 1): number => c + 2)

test/hooks/useSelector.spec.tsx

+6-3
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,12 @@ import {
1414
import { useReduxContext } from '../../src/hooks/useReduxContext'
1515
import type { FunctionComponent, DispatchWithoutAction, ReactNode } from 'react'
1616
import type { Store, AnyAction } from 'redux'
17-
import type { ProviderProps, TypedUseSelectorHook } from '../../src/'
18-
import type { Subscription } from '../../src/utils/Subscription'
19-
import type { ReactReduxContextValue } from '../../src/components/Context'
17+
import type {
18+
ProviderProps,
19+
TypedUseSelectorHook,
20+
ReactReduxContextValue,
21+
Subscription,
22+
} from '../../src/'
2023

2124
describe('React', () => {
2225
describe('hooks', () => {

0 commit comments

Comments
 (0)