import 'react-native'
import { View } from 'react-native'
import React from 'react'
import styled from '../index'
import { shallow, mount } from 'enzyme'
// NOTE: These tests are like the ones for Web but a "light-version" of them
// This is mostly due to the similar logic
describe('native', () => {
it('should not throw an error when called with a valid element', () => {
expect(() => styled.View``).not.toThrowError()
const FunctionalComponent = () =>
class ClassComponent extends React.Component {
render() {
return
}
}
const validComps = ['View', FunctionalComponent, ClassComponent]
validComps.forEach(comp => {
expect(() => {
const Comp = styled(comp)
shallow()
}).not.toThrowError()
})
})
it('should throw a meaningful error when called with an invalid element', () => {
const FunctionalComponent = () =>
class ClassComponent extends React.Component {
render() {
return
}
}
const invalidComps = [
undefined,
null,
123,
[],
,
,
,
]
invalidComps.forEach(comp => {
expect(() => {
// $FlowInvalidInputTest
const Comp = styled(comp)
shallow()
// $FlowInvalidInputTest
}).toThrow(`Cannot create styled-component for component: ${comp}`)
})
})
it('should generate inline styles', () => {
const Comp = styled.View``
const wrapper = shallow()
const view = wrapper.find('View').first()
expect(view.prop('style')).toEqual([{}, undefined])
})
it('should combine inline styles and the style prop', () => {
const Comp = styled.View`
padding-top: 10;
`
const style = { opacity: 0.9 }
const wrapper = shallow()
const view = wrapper.find('View').first()
expect(view.prop('style')).toEqual([{ paddingTop: 10 }, style])
})
it('should not console.warn if a comment is seen', () => {
const oldConsoleWarn = console.warn
console.warn = jest.fn()
try {
styled.View`
/* this is a comment */
`
expect(console.warn).not.toHaveBeenCalled()
} finally {
console.warn = oldConsoleWarn
}
})
// https://github.com/styled-components/styled-components/issues/1266
it('should update when props change', () => {
const Comp = styled.View`
padding-top: 5px;
opacity: ${p => p.opacity || 0};
`
const comp = shallow()
expect(comp.find('View').prop('style')).toEqual([
{ paddingTop: 5, opacity: 0.5 },
undefined,
])
comp.setProps({ opacity: 0.9 })
expect(comp.find('View').prop('style')).toEqual([
{ paddingTop: 5, opacity: 0.9 },
undefined,
])
})
describe('extending', () => {
it('should combine styles of extending components', () => {
const Parent = styled.View`
opacity: 0.9;
`
const Child = Parent.extend`
padding: 10px;
`
const parent = shallow()
const child = shallow()
expect(parent.find('View').prop('style')).toEqual([
{ opacity: 0.9 },
undefined,
])
expect(child.find('View').prop('style')).toEqual([
{
opacity: 0.9,
paddingTop: 10,
paddingRight: 10,
paddingBottom: 10,
paddingLeft: 10,
},
undefined,
])
})
it('should combine styles of extending components in >= 3 inheritances', () => {
const GrandGrandParent = styled.View`
background-color: red;
`
const GrandParent = GrandGrandParent.extend`
border-width: 10;
`
const Parent = GrandParent.extend`
opacity: 0.9;
`
const Child = Parent.extend`
padding: 10px;
`
const grandGrandParent = shallow()
const grandParent = shallow()
const parent = shallow()
const child = shallow()
expect(grandGrandParent.find('View').prop('style')).toEqual([
{
backgroundColor: 'red',
},
undefined,
])
expect(grandParent.find('View').prop('style')).toEqual([
{
backgroundColor: 'red',
borderWidth: 10,
},
undefined,
])
expect(parent.find('View').prop('style')).toEqual([
{
backgroundColor: 'red',
borderWidth: 10,
opacity: 0.9,
},
undefined,
])
expect(child.find('View').prop('style')).toEqual([
{
backgroundColor: 'red',
borderWidth: 10,
opacity: 0.9,
paddingTop: 10,
paddingRight: 10,
paddingBottom: 10,
paddingLeft: 10,
},
undefined,
])
})
})
describe('attrs', () => {
it('works fine with an empty object', () => {
const Comp = styled.View.attrs({})``
const wrapper = shallow()
const view = wrapper.find('View').first()
expect(view.props()).toEqual({
style: [{}, undefined],
})
})
it('passes simple props on', () => {
const Comp = styled.View.attrs({
test: true,
})``
const wrapper = shallow()
const view = wrapper.find('View').first()
expect(view.props()).toEqual({
style: [{}, undefined],
test: true,
})
})
it('calls an attr-function with context', () => {
const Comp = styled.View.attrs({
copy: props => props.test,
})``
const test = 'Put that cookie down!'
const wrapper = shallow()
const view = wrapper.find('View').first()
expect(view.props()).toEqual({
style: [{}, undefined],
copy: test,
test,
})
})
it('merges multiple calls', () => {
const Comp = styled.View.attrs({
first: 'first',
test: '_',
}).attrs({
second: 'second',
test: 'test',
})``
const wrapper = shallow()
const view = wrapper.find('View').first()
expect(view.props()).toEqual({
style: [{}, undefined],
first: 'first',
second: 'second',
test: 'test',
})
})
it('merges attrs when inheriting SC', () => {
const Parent = styled.View.attrs({
first: 'first',
})``
const Child = Parent.extend.attrs({
second: 'second',
})``
const wrapper = shallow()
const view = wrapper.find('View').first()
expect(view.props()).toEqual({
style: [{}, undefined],
first: 'first',
second: 'second',
})
})
})
describe('expanded API', () => {
it('should attach a displayName', () => {
const Comp = styled.View``
expect(Comp.displayName).toBe('Styled(View)')
const CompTwo = styled.View.withConfig({ displayName: 'Test' })``
expect(CompTwo.displayName).toBe('Test')
})
it('should allow multiple calls to be chained', () => {
const Comp = styled.View.withConfig({ displayName: 'Test1' }).withConfig({
displayName: 'Test2',
})``
expect(Comp.displayName).toBe('Test2')
})
})
describe('innerRef', () => {
it('should pass a callback ref to the component', () => {
const Comp = styled.View``
const ref = jest.fn()
const wrapper = mount()
const view = wrapper.find('View').first()
const comp = wrapper.find(Comp).first()
expect(ref).toHaveBeenCalledWith(view.instance())
expect(view.prop('innerRef')).toBeFalsy()
expect(comp.instance().root).toBeTruthy()
})
it('should pass an object ref to the component', () => {
const Comp = styled.View``
const ref = React.createRef()
const wrapper = mount()
const view = wrapper.find('View').first()
const comp = wrapper.find(Comp).first()
expect(ref.current).toBe(view.instance())
expect(view.prop('innerRef')).toBeFalsy()
expect(comp.instance().root).toBeTruthy()
})
it('should not leak the innerRef prop to the wrapped child', () => {
class InnerComponent extends React.Component {
render() {
return null
}
}
const OuterComponent = styled(InnerComponent)``
const ref = jest.fn()
const wrapper = mount()
const innerComponent = wrapper.find(InnerComponent).first()
const outerComponent = wrapper.find(OuterComponent).first()
expect(ref).toHaveBeenCalledWith(innerComponent.instance())
expect(innerComponent.prop('innerRef')).toBeFalsy()
expect(outerComponent.instance().root).toBeTruthy()
})
it('should pass the innerRef to the wrapped styled component', () => {
const InnerComponent = styled.View``
const OuterComponent = styled(InnerComponent)``
const ref = jest.fn()
const wrapper = mount()
const view = wrapper.find('View').first()
const outerComponent = wrapper.find(OuterComponent).first()
expect(ref).toHaveBeenCalledWith(view.instance())
expect(outerComponent.instance().root).toBeTruthy()
})
it('should pass innerRef instead of ref to a wrapped stateless functional component', () => {
const InnerComponent = () => null
const OuterComponent = styled(InnerComponent)``
// NOTE: A ref should always be passed, so we don't need to (setNativeProps feature)
const wrapper = mount()
const outerComponent = wrapper.find(OuterComponent).first()
const innerComponent = wrapper.find(InnerComponent).first()
expect(innerComponent.prop('ref')).toBeFalsy()
expect(innerComponent.prop('innerRef')).toBeTruthy()
expect(outerComponent.instance().root).toBeFalsy()
})
it('should hoist non-react static properties', () => {
const InnerComponent = styled.View``
InnerComponent.foo = 'bar'
const OuterComponent = styled(InnerComponent)``
expect(OuterComponent).toHaveProperty('foo', 'bar')
})
it('should not hoist styled component statics', () => {
const InnerComponent = styled.View`
color: red;
`
const OuterComponent = styled(InnerComponent)`
color: blue;
`
expect(OuterComponent.inlineStyle).not.toEqual(InnerComponent.inlineStyle)
})
})
})