UNPKG

styled-components

Version:

**This is a work in progress** based off of [this demo](https://github.com/geelen/css-components-demo).

254 lines (211 loc) 7.23 kB
/* eslint-disable no-unused-expressions */ /** * This is our end-to-end test suite, which essentially makes sure our public API works the way we * promise/want */ import React from 'react' import expect from 'expect' import proxyquire from 'proxyquire' import { shallow } from 'enzyme' /** * Setup */ let styleSheet let styled class StubStylesheet { constructor() { // TODO: there must be a better way to get a handle on the instance each time // For the tests so far, the first stylesheet to be created is the good one // TODO: fix GlobalStyle.js if (!styleSheet) styleSheet = this this.injected = false this.rules = [] } inject() { this.injected = true } insert(string) { const rule = string ? [string] : [] this.rules.push(rule) return { appendRule: css => rule.push(css) } } toCSS() { return this.rules.map(r => r.join('\n')).join('\n') } } const stubbedSheet = { StyleSheet: StubStylesheet, '@global': true, } /* Ignore hashing, just return class names sequentially as .a .b .c etc */ let index = 0 const classNames = code => { const lastLetter = String.fromCodePoint(97 + code) return code > 26 ? `${classNames(Math.floor(code / 26))}${lastLetter}` : lastLetter } const stubbedEmoji = () => classNames(index++) // eslint-disable-line no-plusplus stubbedEmoji['@global'] = true describe('e2e', () => { /** * Make sure the setup is the same for every test */ beforeEach(() => { styleSheet = null index = 0 styled = proxyquire('../index', { '../vendor/glamor/sheet': stubbedSheet, '../utils/toEmoji': stubbedEmoji, }).default }) /** * Tests */ describe('basic', () => { it('should not throw an error when called', () => { styled.div`` }) it('should inject a stylesheet when a component is created', () => { const Comp = styled.div`` shallow(<Comp />) expect(styleSheet.injected).toBe(true) }) it('should not generate any styles by default', () => { styled.div`` expect(styleSheet.toCSS()).toEqual('') }) it('should generate an empty tag once rendered', () => { const Comp = styled.div`` shallow(<Comp />) expect(styleSheet.toCSS()).toEqual('.a { }') }) /* TODO: we should probably pretty-format the output so this test might have to change */ it('should pass through all whitespace', () => { const Comp = styled.div` \n ` shallow(<Comp />) expect(styleSheet.toCSS()).toEqual('.a { \n }') }) it('should inject only once for a styled component, no matter how often it\'s mounted', () => { const Comp = styled.div`` shallow(<Comp />) shallow(<Comp />) expect(styleSheet.toCSS()).toEqual('.a { }') }) }) describe('with styles', () => { it('should append a style', () => { const rule = 'color: blue;' const Comp = styled.div` ${rule} ` shallow(<Comp />) expect(styleSheet.toCSS().replace(/\s+/g, ' ')).toEqual('.a { color: blue; }') }) it('should append multiple styles', () => { const rule1 = 'color: blue;' const rule2 = 'background: red;' const Comp = styled.div` ${rule1} ${rule2} ` shallow(<Comp />) expect(styleSheet.toCSS().replace(/\s+/g, ' ')).toEqual('.a { color: blue; background: red; }') }) it('should inject styles of multiple components', () => { const firstRule = 'background: blue;' const secondRule = 'background: red;' const FirstComp = styled.div` ${firstRule} ` const SecondComp = styled.div` ${secondRule} ` shallow(<FirstComp />) shallow(<SecondComp />) expect(styleSheet.toCSS().replace(/\s+/g, ' ')).toEqual('.a { background: blue; } .b { background: red; }') }) it('should inject styles of multiple components based on creation, not rendering order', () => { const firstRule = 'content: "first rule";' const secondRule = 'content: "second rule";' const FirstComp = styled.div` ${firstRule} ` const SecondComp = styled.div` ${secondRule} ` // Switch rendering order, shouldn't change injection order shallow(<SecondComp />) shallow(<FirstComp />) // Classes _do_ get generated in the order of rendering but that's ok expect(styleSheet.toCSS().replace(/\s+/g, ' ')).toEqual(` .b { content: "first rule"; } .a { content: "second rule"; } `.trim().replace(/\s+/g, ' ')) }) it('should ignore a JS-style (invalid) comment in the styles', () => { const comment = '// This is an invalid comment' const rule = 'color: blue;' const Comp = styled.div` ${comment} ${rule} ` shallow(<Comp />) expect(styleSheet.toCSS().replace(/\s+/g, ' ')).toEqual(` .a { // This is an invalid comment ${''/* TODO: this probably should be stripped */} color: blue; } `.trim().replace(/\s+/g, ' ')) }) }) describe('extending', () => { it('should generate a single class with no styles', () => { const Parent = styled.div`` const Child = styled(Parent)`` shallow(<Parent />) shallow(<Child />) expect(styleSheet.toCSS().trim().replace(/\s+/g, ' ')).toEqual('.a { }') }) it('should generate a single class if only parent has styles', () => { const Parent = styled.div`color: blue;` const Child = styled(Parent)`` shallow(<Parent />) shallow(<Child />) expect(styleSheet.toCSS().trim().replace(/\s+/g, ' ')).toEqual('.a { color: blue; }') }) it('should generate a single class if only child has styles', () => { const Parent = styled.div`color: blue;` const Child = styled(Parent)`` shallow(<Parent />) shallow(<Child />) expect(styleSheet.toCSS().trim().replace(/\s+/g, ' ')).toEqual('.a { color: blue; }') }) it('should generate a class for the child with the rules of the parent', () => { const Parent = styled.div`color: blue;` const Child = styled(Parent)`color: red;` shallow(<Child />) expect(styleSheet.toCSS().trim().replace(/\s+/g, ' ')).toEqual('.a { color: blue;color: red; }') }) it('should generate different classes for both parent and child', () => { const Parent = styled.div`color: blue;` const Child = styled(Parent)`color: red;` shallow(<Parent />) shallow(<Child />) expect(styleSheet.toCSS().trim().replace(/\s+/g, ' ')).toEqual('.a { color: blue; } .b { color: blue;color: red; }') }) it('should copy nested rules to the child', () => { const Parent = styled.div` color: blue; > h1 { font-size: 4rem; } ` const Child = styled(Parent)`color: red;` shallow(<Parent />) shallow(<Child />) expect(styleSheet.toCSS().trim().replace(/\s+/g, ' ')).toEqual(` .a { color: blue; } .a > h1 { font-size: 4rem; } .b { color: blue; color: red; } .b > h1 { font-size: 4rem; } `.trim().replace(/\s+/g, ' ')) }) }) })