Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add connectAdvanced() tests #1079

Merged
merged 2 commits into from Nov 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 1 addition & 5 deletions src/components/connectAdvanced.js
Expand Up @@ -203,11 +203,7 @@ export default function connectAdvanced(
store
)

if (pure) {
return this.selectChildElement(derivedProps, forwardedRef)
}

return <FinalWrappedComponent {...derivedProps} ref={forwardedRef} />
return this.selectChildElement(derivedProps, forwardedRef)
}

render() {
Expand Down
183 changes: 183 additions & 0 deletions test/components/connectAdvanced.spec.js
@@ -0,0 +1,183 @@
import React, { Component } from 'react'
import * as rtl from 'react-testing-library'
import { Provider as ProviderMock, connectAdvanced } from '../../src/index.js'
import { createStore } from 'redux'
import 'jest-dom/extend-expect'

describe('React', () => {
describe('connectAdvanced', () => {
it('should map state and render once on mount', () => {
const initialState = {
foo: 'bar'
}

let mapCount = 0
let renderCount = 0

const store = createStore(() => initialState)

function Inner(props) {
renderCount++
return <div data-testid="foo">{JSON.stringify(props)}</div>
}

const Container = connectAdvanced(() => {
return state => {
mapCount++
return state
}
})(Inner)

const tester = rtl.render(
<ProviderMock store={store}>
<Container />
</ProviderMock>
)

expect(tester.getByTestId('foo')).toHaveTextContent('bar')

expect(mapCount).toEqual(1)
expect(renderCount).toEqual(1)
})

it('should render on reference change', () => {
let mapCount = 0
let renderCount = 0

// force new reference on each dispatch
const store = createStore(() => ({
foo: 'bar'
}))

function Inner(props) {
renderCount++
return <div data-testid="foo">{JSON.stringify(props)}</div>
}

const Container = connectAdvanced(() => {
return state => {
mapCount++
return state
}
})(Inner)

rtl.render(
<ProviderMock store={store}>
<Container />
</ProviderMock>
)

store.dispatch({ type: 'NEW_REFERENCE' })

// Should have mapped the state on mount and on the dispatch
expect(mapCount).toEqual(2)

// Should have rendered on mount and after the dispatch bacause the map
// state returned new reference
expect(renderCount).toEqual(2)
})

it('should not render when the returned reference does not change', () => {
const staticReference = {
foo: 'bar'
}

let mapCount = 0
let renderCount = 0

// force new reference on each dispatch
const store = createStore(() => ({
foo: 'bar'
}))

function Inner(props) {
renderCount++
return <div data-testid="foo">{JSON.stringify(props)}</div>
}

const Container = connectAdvanced(() => {
return () => {
mapCount++
// but return static reference
return staticReference
}
})(Inner)

const tester = rtl.render(
<ProviderMock store={store}>
<Container />
</ProviderMock>
)

store.dispatch({ type: 'NEW_REFERENCE' })

expect(tester.getByTestId('foo')).toHaveTextContent('bar')

// The state should have been mapped twice: on mount and on the dispatch
expect(mapCount).toEqual(2)

// But the render should have been called only on mount since the map state
// did not return a new reference
expect(renderCount).toEqual(1)
})

it('should map state on own props change but not render when the reference does not change', () => {
const staticReference = {
foo: 'bar'
}

let mapCount = 0
let renderCount = 0

const store = createStore(() => staticReference)

function Inner(props) {
renderCount++
return <div data-testid="foo">{JSON.stringify(props)}</div>
}

const Container = connectAdvanced(() => {
return () => {
mapCount++
// return the static reference
return staticReference
}
})(Inner)

class OuterComponent extends Component {
constructor() {
super()
this.state = { foo: 'FOO' }
}

setFoo(foo) {
this.setState({ foo })
}

render() {
return (
<div>
<Container {...this.state} />
</div>
)
}
}

let outerComponent
rtl.render(
<ProviderMock store={store}>
<OuterComponent ref={c => (outerComponent = c)} />
</ProviderMock>
)

outerComponent.setFoo('BAR')

// map on mount and on prop change
expect(mapCount).toEqual(2)

// render only on mount but skip on prop change because no new
// reference was returned
expect(renderCount).toEqual(1)
})
})
})