// @flow
/* eslint-disable react/no-multi-comp */
import React from 'react'
import { shallow, render, mount } from 'enzyme'
import ThemeProvider, { CHANNEL_NEXT, CONTEXT_CHANNEL_SHAPE } from '../ThemeProvider'
describe('ThemeProvider', () => {
it('should not throw an error when no children are passed', () => {
const result = shallow()
expect(result.html()).toEqual(null)
})
it('should accept a theme prop that\'s a plain object', () => {
shallow()
})
it('should render its child', () => {
const child = (
Child!
)
const renderedComp = shallow(
{ child }
)
expect(renderedComp.contains(child)).toEqual(true)
})
it('should merge its theme with an outer theme', (done) => {
const outerTheme = { main: 'black' }
const innerTheme = { secondary: 'black' }
// Setup Child
class Child extends React.Component {
componentWillMount() {
this.context[CHANNEL_NEXT].subscribe(theme => {
expect(theme).toEqual({ ...outerTheme, ...innerTheme })
done()
})
}
render() { return null }
}
Child.contextTypes = {
[CHANNEL_NEXT]: CONTEXT_CHANNEL_SHAPE,
}
render(
)
})
it('should merge its theme with multiple outer themes', (done) => {
const outerestTheme = { main: 'black' }
const outerTheme = { main: 'blue' }
const innerTheme = { secondary: 'black' }
// Setup Child
class Child extends React.Component {
componentWillMount() {
this.context[CHANNEL_NEXT].subscribe(theme => {
expect(theme).toEqual({ ...outerestTheme, ...outerTheme, ...innerTheme })
done()
})
}
render() { return null }
}
Child.contextTypes = {
[CHANNEL_NEXT]: CONTEXT_CHANNEL_SHAPE,
}
render(
)
})
it('should be able to render two independent themes', (done) => {
const themes = {
one: { main: 'black', secondary: 'red' },
two: { main: 'blue', other: 'green' },
}
let childRendered = 0
// Setup Child
class Child extends React.Component {
componentWillMount() {
this.context[CHANNEL_NEXT].subscribe(theme => {
// eslint-disable-next-line react/prop-types
expect(theme).toEqual(themes[this.props.shouldHaveTheme])
childRendered++ // eslint-disable-line no-plusplus
if (childRendered === Object.keys(themes).length) {
done()
}
})
}
render() { return null }
}
Child.contextTypes = {
[CHANNEL_NEXT]: CONTEXT_CHANNEL_SHAPE,
}
render(
)
})
it('ThemeProvider propagates theme updates through nested ThemeProviders', () => {
const theme = { themed: true }
const augment = outerTheme =>
Object.assign({}, outerTheme, { augmented: true })
const update = { updated: true }
let actual
const expected = { themed: true, augmented: true, updated: true }
// Setup Child
class Child extends React.Component {
componentWillMount() {
this.context[CHANNEL_NEXT].subscribe(receivedTheme => {
actual = receivedTheme
})
}
render() {
return null
}
}
Child.contextTypes = {
[CHANNEL_NEXT]: CONTEXT_CHANNEL_SHAPE,
}
const wrapper = mount(
,
)
wrapper.setProps({ theme: Object.assign({}, theme, update) })
expect(actual).toEqual(expected)
})
})