Skip to content

Commit

Permalink
Spy on collection changes
Browse files Browse the repository at this point in the history
  • Loading branch information
knicklabs committed Sep 24, 2018
1 parent 19220a3 commit 8b4ab79
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 3 deletions.
16 changes: 13 additions & 3 deletions src/components/EnhancedComponent/EnhancedComponent.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import React, {Component} from 'react'
import {getModels, transformDataToProps} from './util'
import {getCollections, getModels, transformDataToProps} from './util'

const COLLECTION_EVENTS = 'add change remove reset'
const MODEL_EVENTS = 'change'

class EnhancedComponent extends Component {
constructor(props) {
super(props)
this.state = this.getPropsForState()
this.collections = getCollections(props.data)
this.models = getModels(props.data)
}

Expand Down Expand Up @@ -35,14 +39,20 @@ class EnhancedComponent extends Component {
}

unwatch() {
this.collections.forEach(collection => {
collection.off(COLLECTION_EVENTS, this.updatePropsInState, this)
})
this.models.forEach(model => {
model.off('change', this.updatePropsInState, this)
model.off(MODEL_EVENTS, this.updatePropsInState, this)
})
}

watch() {
this.collections.forEach(collection => {
collection.on(COLLECTION_EVENTS, this.updatePropsInState, this)
})
this.models.forEach(model => {
model.on('change', this.updatePropsInState, this)
model.on(MODEL_EVENTS, this.updatePropsInState, this)
})
}
}
Expand Down
121 changes: 121 additions & 0 deletions src/components/EnhancedComponent/__tests__/EnhancedComponent.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ import {mount} from 'enzyme'
describe('EnhancedComponent', () => {
const Button = ({label}) => <button>{label}</button>

test('should listen for changes on collections when the component mounts', () => {
const component = <Button label="Click Me" />
const data = {
collection: new Backbone.Collection([]),
}
data.collection.on = jest.fn()
mount(<EnhancedComponent component={component} data={data} />)
expect(data.collection.on).toHaveBeenCalled()
})

test('should listen for changes on models when the component mounts', () => {
const component = <Button label="Click Me" />
const data = {
Expand All @@ -16,6 +26,17 @@ describe('EnhancedComponent', () => {
expect(data.model.on).toHaveBeenCalled()
})

test('should stop listening for changes on collections when the component unmounts', () => {
const component = <Button label="Click Me" />
const data = {
collection: new Backbone.Collection([]),
}
data.collection.off = jest.fn()
const c = mount(<EnhancedComponent component={component} data={data} />)
c.unmount()
expect(data.collection.off).toHaveBeenCalled()
})

test('should stop listening for changes on models when the component unmounts', () => {
const component = <Button label="Click Me" />
const data = {
Expand All @@ -27,6 +48,106 @@ describe('EnhancedComponent', () => {
expect(data.model.off).toHaveBeenCalled()
})

test('should update the state when the collection is added to', () => {
const component = <Button />
const data = {
collection: new Backbone.Collection([]),
}
const selector = ({collection}) => {
return {
label: collection.map(m => m.name).join(' '),
}
}
const c = mount(
<EnhancedComponent
component={component}
data={data}
selector={selector}
/>,
)
expect(c.state('label')).toEqual('')
data.collection.add(new Backbone.Model({name: 'hello'}))
expect(c.state('label')).toEqual('hello')
data.collection.add(new Backbone.Model({name: 'world'}))
expect(c.state('label')).toEqual('hello world')
})

test('should update the state when models are changed in the collection', () => {
const component = <Button />
const model1 = new Backbone.Model({id: 1, name: 'hello'})
const model2 = new Backbone.Model({id: 2, name: 'world'})
const data = {
collection: new Backbone.Collection([model1, model2]),
}
const selector = ({collection}) => {
return {
label: collection.map(m => m.name).join(' '),
}
}
const c = mount(
<EnhancedComponent
component={component}
data={data}
selector={selector}
/>,
)
expect(c.state('label')).toEqual('hello world')
model1.set('name', 'hey')
expect(c.state('label')).toEqual('hey world')
model2.set('name', 'you')
expect(c.state('label')).toEqual('hey you')
})

test('should update the state when models are removed from the collection', () => {
const component = <Button />
const model1 = new Backbone.Model({id: 1, name: 'hello'})
const model2 = new Backbone.Model({id: 2, name: 'world'})
const data = {
collection: new Backbone.Collection([model1, model2]),
}
const selector = ({collection}) => {
return {
label: collection.map(m => m.name).join(' '),
}
}
const c = mount(
<EnhancedComponent
component={component}
data={data}
selector={selector}
/>,
)
expect(c.state('label')).toEqual('hello world')
data.collection.remove(model2)
expect(c.state('label')).toEqual('hello')
data.collection.remove(model1)
expect(c.state('label')).toEqual('')
})

test('should update the state when the collection is reset', () => {
const component = <Button />
const data = {
collection: new Backbone.Collection([
new Backbone.Model({name: 'Click Me'}),
]),
}
const selector = ({collection}) => {
return {
label: collection.map(m => m.name).join(' '),
}
}
const c = mount(
<EnhancedComponent
component={component}
data={data}
selector={selector}
/>,
)
expect(c.state('label')).toEqual('Click Me')
data.collection.reset([])
expect(c.state('label')).toEqual('')
})

test('should update the state when the model changes', () => {
const component = <Button />
const data = {
Expand Down

0 comments on commit 8b4ab79

Please sign in to comment.