// @flow import React from 'react' import { shallow } from 'enzyme' import * as nonce from '../utils/nonce'; import { resetStyled, expectCSSMatches } from './utils' import StyleSheet from '../models/StyleSheet' import _injectGlobal from '../constructors/injectGlobal' import stringifyRules from '../utils/stringifyRules' import css from '../constructors/css' const injectGlobal = _injectGlobal(stringifyRules, css) jest.mock('../utils/nonce') jest.spyOn(nonce, 'default').mockImplementation(() => 'foo') let styled describe('with styles', () => { /** * Make sure the setup is the same for every test */ beforeEach(() => { // $FlowFixMe document.head.innerHTML = '' styled = resetStyled() }) it('should append a style', () => { const rule = 'color: blue;' const Comp = styled.div` ${rule} ` shallow() expectCSSMatches('.sc-a {} .b { color:blue; }') }) it('should append multiple styles', () => { const rule1 = 'color: blue;' const rule2 = 'background: red;' const Comp = styled.div` ${rule1} ${rule2} ` shallow() expectCSSMatches('.sc-a {} .b { color:blue; background:red; }') }) it('should handle inline style objects', () => { const rule1 = { backgroundColor: 'blue', } const Comp = styled.div` ${rule1} ` shallow() expectCSSMatches('.sc-a {} .b { background-color:blue; }') }) it('should throw a meaningful error if a non styled component with react element is interpolated', () => { const NestedComp = () =>
const Comp = styled.div` ${ NestedComp} { color: purple; } ` expect(() => shallow()).toThrowErrorMatchingSnapshot(); }) it('should handle inline style objects with media queries', () => { const rule1 = { backgroundColor: 'blue', '@media screen and (min-width: 250px)': { backgroundColor: 'red', }, } const Comp = styled.div` ${rule1} ` shallow() expectCSSMatches('.sc-a {} .b { background-color:blue; } @media screen and (min-width:250px) { .b { background-color:red; } }') }) it('should handle inline style objects with pseudo selectors', () => { const rule1 = { backgroundColor: 'blue', '&:hover': { color: 'green', }, } const Comp = styled.div` ${rule1} ` shallow() expectCSSMatches('.sc-a {} .b { background-color:blue; } .b:hover { color:green; }') }) it('should handle inline style objects with pseudo selectors', () => { const rule1 = { backgroundColor: 'blue', '&:hover': { color: 'green', }, } const Comp = styled.div` ${rule1} ` shallow() expectCSSMatches('.sc-a {} .b { background-color:blue; } .b:hover { color:green; }') }) it('should handle inline style objects with nesting', () => { const rule1 = { backgroundColor: 'blue', '> h1': { color: 'white', }, } const Comp = styled.div` ${rule1} ` shallow() expectCSSMatches('.sc-a {} .b { background-color:blue; } .b > h1 { color:white; }') }) it('should handle inline style objects with contextual selectors', () => { const rule1 = { backgroundColor: 'blue', 'html.something &': { color: 'white', }, } const Comp = styled.div` ${rule1} ` shallow() expectCSSMatches('.sc-a {} .b { background-color:blue; } html.something .b { color:white; }') }) 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() shallow() expectCSSMatches('.sc-a {} .c { background:blue; } .sc-b {} .d { 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() shallow() // Classes _do_ get generated in the order of rendering but that's ok expectCSSMatches(` .sc-a {} .d { content:"first rule"; } .sc-b {} .c { content:"second rule"; } `) }) it('should strip 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() expectCSSMatches(` .sc-a {} .b { color:blue; } `) }) it('should respect removed rules', () => { const Heading = styled.h1` color: red; ` const Text = styled.span` color: green; ` shallow() StyleSheet.master.remove(Text.styledComponentId) expectCSSMatches(` .sc-a {} .c { color:red; } `) }) it('should add a webpack nonce to the style tags if one is available in the global scope', () => { const rule = 'color: blue;' const Comp = styled.div` ${rule} ` shallow() expectCSSMatches(` .sc-a {} .b { color:blue; } `) Array.from(document.querySelectorAll('style')).forEach(el => { expect(el.getAttribute('nonce')).toBe('foo') }) }) it('should handle deferredInject and inject correctly', () => { const cloneA = StyleSheet.master.clone() const cloneB = StyleSheet.master.clone() const rules = ['.testA {}'] StyleSheet.master.deferredInject('test', rules) expect(StyleSheet.master.deferred.test).toBe(rules) expect(cloneA.deferred.test).toBe(rules) expect(cloneB.deferred.test).toBe(rules) StyleSheet.master.inject('test', ['.testB {}']) const inspectTag = sheet => { const tag = sheet.getTagForId('test') return tag.css() } const masterCss = inspectTag(StyleSheet.master) expect(masterCss).toEqual(inspectTag(cloneA)) expect(masterCss).toEqual(inspectTag(cloneB)) }) })