Repository: tkh44/emotion
Pull request #43 (2017-06-28 16:51:12)

Add innerRef functionality
<!--
Thanks for your interest in the project. I appreciate bugs filed and PRs submitted!

Please make sure that you are familiar with and follow the Code of Conduct for
this project (found in the CODE_OF_CONDUCT.md file).

Also, please make sure you're familiar with and follow the instructions in the
contributing guidelines (found in the CONTRIBUTING.md file).

If you're new to contributing to open source projects, you might find this free
video course helpful: http://kcd.im/pull-request

Please fill out the information below to expedite the review and (hopefully)
merge of your pull request!
-->

<!-- What changes are being made? (What feature/bug is being fixed here?) -->
**What**: Support for `innerRef` being passed down as `ref`.

<!-- Why are these changes necessary? -->
**Why**: To add `ref` functionality to emotioned(?) components. 

<!-- How were these changes implemented? -->
**How**: By adding `innerRef` as prop for child component

<!-- Have you done all of these things?  -->
**Checklist**:
<!-- add "N/A" to the end of each line that's irrelevant to your changes -->
<!-- to check an item, place an "x" in the box like so: "- [x] Documentation" -->
- [x] Documentation
- [x] Tests
- [x] Code complete

<!-- feel free to add additional comments -->



Patch:
diff --git a/README.md b/README.md
index 47c36303..129ba862 100644
--- a/README.md
+++ b/README.md
@@ -141,6 +141,17 @@ const H3 = styled.h3`
 function Greeting ({ name }) {
   return <H3>Hello {name}</H3> // red, 16px text
 }
+
+// You can also pass refs down using innerRef
+const H1 = styled('h1')`
+  color: 'red';
+`
+
+function Greeting ({ name }) {
+  // will turn into to <h1 className="generated-className" ref={() => console.log('hello!')}>Hello {name}</h1>
+  return <H1 innerRef={() => console.log('hello!')}>Hello {name}</H1> 
+}
+
 ```
 
 #### attr
diff --git a/src/babel.js b/src/babel.js
index e8e6e7d8..f5592b25 100644
--- a/src/babel.js
+++ b/src/babel.js
@@ -1,7 +1,7 @@
 import fs from 'fs'
 import { basename } from 'path'
 import { touchSync } from 'touch'
-import { inline, keyframes, fontFace, injectGlobal } from './inline'
+import { inline, keyframes, fontFace } from './inline'
 import findAndReplaceAttrs from './attrs'
 
 function parseDynamicValues (rules, t) {
@@ -112,8 +112,9 @@ export default function (babel) {
         // });
 
         const parent = path.findParent(p => p.isVariableDeclarator())
-        const identifierName =
-          parent && t.isIdentifier(parent.node.id) ? parent.node.id.name : ''
+        const identifierName = parent && t.isIdentifier(parent.node.id)
+          ? parent.node.id.name
+          : ''
 
         function buildCallExpression (identifier, tag, path) {
           const built = findAndReplaceAttrs(path, t)
@@ -242,101 +243,56 @@ export default function (babel) {
           t.isIdentifier(path.node.tag) &&
           path.node.tag.name === 'keyframes'
         ) {
-          const { hash, name, rules, isStatic } = keyframes(
+          const { hash, name, rules } = keyframes(
             path.node.quasi,
             identifierName,
-            'animation',
-            state.inline
+            'animation'
           )
-          const animationName = `${name}-${hash}`
-          if (isStatic) {
-            state.insertStaticRules([
-              `@keyframes ${animationName} ${rules.join('')}`
+
+          path.replaceWith(
+            t.callExpression(t.identifier('keyframes'), [
+              t.stringLiteral(`${name}-${hash}`),
+              t.arrayExpression(path.node.quasi.expressions),
+              t.functionExpression(
+                t.identifier('createEmotionKeyframe'),
+                path.node.quasi.expressions.map((x, i) =>
+                  t.identifier(`x${i}`)
+                ),
+                t.blockStatement([
+                  t.returnStatement(
+                    t.arrayExpression(rules.map(r => t.stringLiteral(r)))
+                  )
+                ])
+              )
             ])
-            path.replaceWith(t.stringLiteral(animationName))
-          } else {
-            path.replaceWith(
-              t.callExpression(t.identifier('keyframes'), [
-                t.stringLiteral(animationName),
-                t.arrayExpression(path.node.quasi.expressions),
-                t.functionExpression(
-                  t.identifier('createEmotionKeyframes'),
-                  path.node.quasi.expressions.map((x, i) =>
-                    t.identifier(`x${i}`)
-                  ),
-                  t.blockStatement([
-                    t.returnStatement(
-                      t.arrayExpression(parseDynamicValues(rules, t))
-                    )
-                  ])
-                )
-              ])
-            )
-          }
+          )
         } else if (
           t.isIdentifier(path.node.tag) &&
           path.node.tag.name === 'fontFace'
         ) {
-          const { rules, isStatic } = fontFace(path.node.quasi, state.inline)
-          if (isStatic) {
-            state.insertStaticRules(rules)
-            if (t.isExpressionStatement(path.parent)) {
-              path.parentPath.remove()
-            } else {
-              path.replaceWith(t.identifier('undefined'))
-            }
-          } else {
-            path.replaceWith(
-              t.callExpression(t.identifier('fontFace'), [
-                t.arrayExpression(path.node.quasi.expressions),
-                t.functionExpression(
-                  t.identifier('createEmotionFontFace'),
-                  path.node.quasi.expressions.map((x, i) =>
-                    t.identifier(`x${i}`)
-                  ),
-                  t.blockStatement([
-                    t.returnStatement(
-                      t.arrayExpression(parseDynamicValues(rules, t))
-                    )
-                  ])
-                )
-              ])
-            )
-          }
-        } else if (
-          t.isIdentifier(path.node.tag) &&
-          path.node.tag.name === 'injectGlobal' &&
-          t.isTemplateLiteral(path.node.quasi)
-        ) {
-          const { isStatic, rules } = injectGlobal(
+          const { hash, name, rules } = fontFace(
             path.node.quasi,
-            state.inline
+            identifierName,
+            'font-face'
+          )
+
+          path.replaceWith(
+            t.callExpression(t.identifier('fontFace'), [
+              t.stringLiteral(`${name}-${hash}`),
+              t.arrayExpression(path.node.quasi.expressions),
+              t.functionExpression(
+                t.identifier('createEmotionFontFace'),
+                path.node.quasi.expressions.map((x, i) =>
+                  t.identifier(`x${i}`)
+                ),
+                t.blockStatement([
+                  t.returnStatement(
+                    t.arrayExpression(rules.map(r => t.stringLiteral(r)))
+                  )
+                ])
+              )
+            ])
           )
-          if (isStatic) {
-            state.insertStaticRules(rules)
-            if (t.isExpressionStatement(path.parent)) {
-              path.parentPath.remove()
-            } else {
-              path.replaceWith(t.identifier('undefined'))
-            }
-          } else {
-            path.replaceWith(
-              t.callExpression(t.identifier('injectGlobal'), [
-                t.arrayExpression(path.node.quasi.expressions),
-                t.functionExpression(
-                  t.identifier('createEmotionGlobal'),
-                  path.node.quasi.expressions.map((x, i) =>
-                    t.identifier(`x${i}`)
-                  ),
-                  t.blockStatement([
-                    t.returnStatement(
-                      t.arrayExpression(parseDynamicValues(rules, t))
-                    )
-                  ])
-                )
-              ])
-            )
-          }
         }
       }
     }
diff --git a/src/index.js b/src/index.js
index fbf6ddcf..40611c1f 100644
--- a/src/index.js
+++ b/src/index.js
@@ -49,32 +49,36 @@ export function css (cls: string, vars: vars, content: () => string[]) {
   return cls + (vars && vars.length > 0 ? ' ' + values(cls, vars) : '')
 }
 
-export function fragment (vars: vars, content: () => string) {
+export function fragment (vars: vars, content: () => string[]) {
   return content(...vars)
 }
 
-export function injectGlobal (vars: vars, content: () => string[]) {
-  const src = content(...vars)
-  const hash = hashArray(src)
+export function keyframes (kfm: string, vars: vars, content: () => string[]) {
+  let src = content(...vars)
+  let hash = hashArray(src)
   if (!inserted[hash]) {
     inserted[hash] = true
-    sheet.insert(src)
+    src.forEach(r => {
+      return sheet.insert(`@keyframes ${kfm}-${hash} {${r}}`)
+    })
   }
+  return `${kfm}-${hash}`
 }
 
-export const fontFace = injectGlobal
-
-export function keyframes (kfm: string, vars: vars, content: () => string[]) {
-  const src = content(...vars)
-  const hash = hashArray(src)
-  const animationName = `${kfm}-${hash}`
+export function fontFace (
+  fontRules: string,
+  vars: vars,
+  content: () => string[]
+) {
+  let src = content(...vars)
+  let hash = hashArray(src)
   if (!inserted[hash]) {
     inserted[hash] = true
     src.forEach(r => {
-      sheet.insert(`@keyframes ${animationName} ${r}`)
+      return sheet.insert(r)
     })
   }
-  return animationName
+  return `${fontRules}-${hash}`
 }
 
 export function hydrate (ids: string[]) {
diff --git a/src/inline.js b/src/inline.js
index cfb01511..637968e7 100644
--- a/src/inline.js
+++ b/src/inline.js
@@ -25,24 +25,6 @@ function getName (
   return parts.join('-')
 }
 
-function replaceVarsWithPlaceholders (rules: string[]): string[] {
-  return rules.map(rule =>
-    rule.replace(
-      /var\(--[A-Za-z0-9-_]+-([0-9]+)\)/gm,
-      (match, p1) => `xxx${p1}xxx`
-    )
-  )
-}
-
-function replaceApplyWithPlaceholders (rules: string[]): string[] {
-  return rules.map(rule =>
-    rule.replace(
-      /@apply\s+--[A-Za-z0-9-_]+-([0-9]+)/gm,
-      (match, p1) => `xxx${p1}xxx`
-    )
-  )
-}
-
 export function inline (
   quasi: any,
   identifierName?: string,
@@ -74,101 +56,67 @@ export function inline (
     .trim()
 
   let rules = parseCSS(`.${name}-${hash} { ${src} }`)
-  if (inlineVars || hasApply) {
-    rules = replaceVarsWithPlaceholders(rules)
-  }
   if (hasApply) {
-    rules = replaceApplyWithPlaceholders(rules)
+    rules = rules.map(rule =>
+      rule.replace(
+        /@apply\s+--[A-Za-z0-9-_]+-([0-9]+)/gm,
+        (match, p1) => `xxx${p1}xxx`
+      )
+    )
+  }
+  if (inlineVars || hasApply) {
+    rules = rules.map(rule =>
+      rule.replace(
+        /var\(--[A-Za-z0-9-_]+-([0-9]+)\)/gm,
+        (match, p1) => `xxx${p1}xxx`
+      )
+    )
   }
+
   return { hash, name, rules, isStatic: !hasApply && !inlineVars }
 }
 
 export function keyframes (
   quasi: any,
   identifierName?: string,
-  prefix: string,
-  inlineVars: boolean
+  prefix: string
 ): { hash: string, name: string, rules: string[] } {
-  const strs = quasi.quasis.map(x => x.value.cooked)
-  const hash = hashArray([...strs])
-  const name = getName(
+  let strs = quasi.quasis.map(x => x.value.cooked)
+  let hash = hashArray([...strs])
+  let name = getName(
     extractNameFromProperty(strs.join('xxx')),
     identifierName,
     prefix
   )
-  let hasApplyOrVar = false
-  const src = strs
-    .reduce((arr, str, i) => {
-      arr.push(str)
-      if (i !== quasi.expressions.length) {
-        hasApplyOrVar = true
-        // todo - test for preceding @apply
-        let applyMatch = /@apply\s*$/gm.exec(str)
-        if (applyMatch) {
-          arr.push(`--name-hash-${i}`)
-        } else arr.push(`var(--name-hash-${i})`)
-      }
-      return arr
-    }, [])
-    .join('')
-    .trim()
-  let rules = parseCSS(`{ ${src} }`, { nested: false })
-  if (hasApplyOrVar) {
-    rules = replaceVarsWithPlaceholders(rules)
-    rules = replaceApplyWithPlaceholders(rules)
-  }
-  return { hash, name, rules, isStatic: !hasApplyOrVar && !inlineVars }
-}
 
-export function fontFace (
-  quasi: any,
-  inlineVars: boolean
-): { rules: string[], isStatic: boolean } {
-  let strs = quasi.quasis.map(x => x.value.cooked)
-  let hasVar
-  let src = strs
-    .reduce((arr, str, i) => {
-      arr.push(str)
-      if (i !== quasi.expressions.length) {
-        hasVar = true
-        arr.push(`var(--name-hash-${i})`)
-      }
-      return arr
-    }, [])
-    .join('')
-    .trim()
-  let rules = parseCSS(`@font-face {${src}}`)
-  if (hasVar) {
-    rules = replaceVarsWithPlaceholders(rules)
+  return {
+    hash,
+    name,
+    rules: [parseCSS(`{ ${strs.join('').trim()} }`).join('').trim()]
   }
-  return { rules, isStatic: !inlineVars && !hasVar }
 }
 
-export function injectGlobal (
+export function fontFace (
   quasi: any,
-  inlineVars: boolean
-): { rules: string[], isStatic: boolean } {
+  identifierName?: string,
+  prefix: string
+): { hash: string, name: string, rules: string[] } {
   let strs = quasi.quasis.map(x => x.value.cooked)
-  let hasApplyOrVar = false
-  let src = strs
-    .reduce((arr, str, i) => {
-      arr.push(str)
-      if (i !== quasi.expressions.length) {
-        hasApplyOrVar = true
-        // todo - test for preceding @apply
-        let applyMatch = /@apply\s*$/gm.exec(str)
-        if (applyMatch) {
-          arr.push(`--name-hash-${i}`)
-        } else arr.push(`var(--name-hash-${i})`)
-      }
-      return arr
-    }, [])
-    .join('')
-    .trim()
-  let rules = parseCSS(src)
-  if (hasApplyOrVar) {
-    rules = replaceVarsWithPlaceholders(rules)
-    rules = replaceApplyWithPlaceholders(rules)
+  let hash = hashArray([...strs])
+  let name = getName(
+    extractNameFromProperty(strs.join('xxx')),
+    identifierName,
+    prefix
+  )
+  return {
+    hash,
+    name,
+    rules: [
+      parseCSS(`@font-face {${strs.join('').trim()}}`, {
+        nested: false
+      })
+        .join('')
+        .trim()
+    ]
   }
-  return { rules, isStatic: !inlineVars && !hasApplyOrVar }
 }
diff --git a/src/styled.js b/src/styled.js
index 26f874cf..2d38a804 100644
--- a/src/styled.js
+++ b/src/styled.js
@@ -18,6 +18,7 @@ export default function (tag, cls, vars = [], content) {
     return React.createElement(
       tag,
       Object.assign({}, props, {
+        ref: props.innerRef,
         className: props.className
           ? className + ' ' + props.className
           : className


Test patch:
diff --git a/test/babel/__snapshots__/fs.test.js.snap b/test/__snapshots__/babel-fs.test.js.snap
similarity index 90%
rename from test/babel/__snapshots__/fs.test.js.snap
rename to test/__snapshots__/babel-fs.test.js.snap
index f7817782..53f45a60 100644
--- a/test/babel/__snapshots__/fs.test.js.snap
+++ b/test/__snapshots__/babel-fs.test.js.snap
@@ -16,13 +16,13 @@ exports[`babel plugin fs creates and writes to the css file when it does not exi
 `;
 
 exports[`babel plugin fs creates and writes to the css file when it does not exist 2`] = `
-"import \\"./fs.test.emotion.css\\";
+"import \\"./babel-fs.test.emotion.css\\";
 
 css(\\"css-class-lk4ur6\\", [widthVar]);"
 `;
 
 exports[`babel plugin fs does not write to the css file when it is the same as is already written 1`] = `
-"import \\"./fs.test.emotion.css\\";
+"import \\"./babel-fs.test.emotion.css\\";
 
 css(\\"css-class-lk4ur6\\", [widthVar]);"
 `;
@@ -43,7 +43,7 @@ exports[`babel plugin fs writes to the css file when it does exist  1`] = `
 `;
 
 exports[`babel plugin fs writes to the css file when it does exist  2`] = `
-"import \\"./fs.test.emotion.css\\";
+"import \\"./babel-fs.test.emotion.css\\";
 
 css(\\"css-class-lk4ur6\\", [widthVar]);"
 `;
diff --git a/test/__snapshots__/babel.test.js.snap b/test/__snapshots__/babel.test.js.snap
new file mode 100644
index 00000000..8e431786
--- /dev/null
+++ b/test/__snapshots__/babel.test.js.snap
@@ -0,0 +1,260 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`emotion/babel babel css css basic 1`] = `
+"
+css(\\"css-cu78iu\\", [widthVar], function createEmotionRules(x0) {
+        return [\`.css-cu78iu { margin: 12px 48px;
+        color: #ffffff;
+        display: -webkit-box;
+        display: -moz-box;
+        display: -ms-flexbox;
+        display: -webkit-flex;
+        display: flex;
+        -webkit-flex: 1 0 auto;
+        -ms-flex: 1 0 auto;
+        flex: 1 0 auto;
+        color: blue;
+        width: \${x0}; }\`];
+});"
+`;
+
+exports[`emotion/babel babel css css kitchen sink 1`] = `
+"
+const cls = css(\\"css-cls-h5t3cu\\", [margin], function createEmotionRules(x0) {
+        return [\`.css-cls-h5t3cu { font-size: 58pt;margin: \${x0}; }\`];
+});
+const frag = fragment([], function createEmotionFragment() {
+        return \` padding: 8px; \`;
+});
+const fragB = fragment([heightVar, frag], function createEmotionFragment(x0, x1) {
+        return \` height: \${x0};\${x1}; \`;
+});
+const cls2 = css(\\"css-cls2-1b4c3x0\\", [frag, fragB], function createEmotionRules(x0, x1) {
+        return [\`.css-cls2-1b4c3x0 { \${x0};
+        \${x1};
+        margin: 12px 48px;
+        color: #ffffff; }\`];
+});"
+`;
+
+exports[`emotion/babel babel css extract css basic 1`] = `
+"import \\"./babel.test.emotion.css\\";
+
+css(\\"css-cu78iu\\", [widthVar]);"
+`;
+
+exports[`emotion/babel babel css extract css basic 2`] = `
+".css-cu78iu { margin: 12px 48px;
+        color: #ffffff;
+        display: -webkit-box;
+        display: -moz-box;
+        display: -ms-flexbox;
+        display: -webkit-flex;
+        display: flex;
+        -webkit-flex: 1 0 auto;
+        -ms-flex: 1 0 auto;
+        flex: 1 0 auto;
+        color: blue;
+        width: var(--css-cu78iu-0); }"
+`;
+
+exports[`emotion/babel babel css extract css kitchen sink 1`] = `
+"import \\"./babel.test.emotion.css\\";
+
+const cls = css(\\"css-cls-h5t3cu\\", [margin]);
+const frag = fragment([], function createEmotionFragment() {
+        return \` padding: 8px; \`;
+});
+const fragB = fragment([heightVar, frag], function createEmotionFragment(x0, x1) {
+        return \` height: \${x0};\${x1}; \`;
+});
+const cls2 = css(\\"css-cls2-1b4c3x0\\", [frag, fragB], function createEmotionRules(x0, x1) {
+        return [\`.css-cls2-1b4c3x0 { \${x0};
+        \${x1};
+        margin: 12px 48px;
+        color: #ffffff; }\`];
+});"
+`;
+
+exports[`emotion/babel babel css extract css kitchen sink 2`] = `".css-cls-h5t3cu { font-size: 58pt;margin: var(--css-cls-h5t3cu-0); }"`;
+
+exports[`emotion/babel babel font-face font-face basic 1`] = `
+"
+fontFace(\\"font-face-1o0czbr\\", [], function createEmotionFontFace() {
+     return [\\"@font-face {font-family: MyHelvetica;\\\\n          src: local(\\\\\\"Helvetica Neue Bold\\\\\\"),\\\\n               local(\\\\\\"HelveticaNeue-Bold\\\\\\"),\\\\n               url(MgOpenModernaBold.ttf);\\\\n          font-weight: bold;}\\"];
+});"
+`;
+
+exports[`emotion/babel babel fragment basic fragment 1`] = `
+"
+const frag = fragment([], function createEmotionFragment() {
+        return \` color: green \`;
+});
+styled(\\"h1\\", \\"css-u3lc8x\\", [frag], function createEmotionStyledRules(x0) {
+        return [\`.css-u3lc8x { font-size: 20px; \${x0}; }\`];
+});"
+`;
+
+exports[`emotion/babel babel fragment fragment kitchen sink 1`] = `
+"
+const frag = fragment([backgroundColor], function createEmotionFragment(x0) {
+        return \` color: green; background-color: \${x0} \`;
+});
+const frag1 = fragment([], function createEmotionFragment() {
+        return \` width: 20px; \`;
+});
+const frag2 = fragment([frag1], function createEmotionFragment(x0) {
+        return \` height: 20px; \${x0}; \`;
+});
+styled('h1', 'css-some-name-9k8moo', [fontSize + 'px', frag, frag2], function createEmotionStyledRules(x0, x1, x2) {
+        return [\`.css-some-name-9k8moo { font-size: \${x0}; \${x1}; \${x2} }\`];
+});"
+`;
+
+exports[`emotion/babel babel fragment fragment with multiple selectors that should throw 1`] = `"unknown: Fragments cannot have multiple selectors."`;
+
+exports[`emotion/babel babel keyframes keyframe basic 1`] = `
+"
+const rotate360 = keyframes(\\"animation-rotate360-f35ahc\\", [], function createEmotionKeyframe() {
+  return [\\"from {\\\\n    -webkit-transform: rotate(0deg);\\\\n    -ms-transform: rotate(0deg);\\\\n    transform: rotate(0deg);\\\\n} to {\\\\n    -webkit-transform: rotate(360deg);\\\\n    -ms-transform: rotate(360deg);\\\\n    transform: rotate(360deg);\\\\n}\\"];
+});"
+`;
+
+exports[`emotion/babel babel styled component attr 1`] = `
+"styled('input', 'css-14vghnb', [function getMargin(props) {
+       return props.margin;
+}, props => props.height * props.scale, function getWidth(props) {
+       return props.width;
+}, flex], function createEmotionStyledRules(x0, x1, x2, x3) {
+       return [\`.css-14vghnb { margin: \${x0};
+       color: #ffffff;
+       height: \${x1};
+       width: \${x2};
+       color: blue;
+       display: \${x3}; }\`];
+});"
+`;
+
+exports[`emotion/babel babel styled component attr kitchen sink 1`] = `
+"styled('input', 'css-1lqib20', [function getMargin(props) {
+        return props.margin ? props.margin : ('16' + 'px');
+}, function getPadding(props) {
+        return props.padding ? props.padding : ('16' + 'em');
+}, function getWidth(props) {
+        return props.width ? props.width : ('95' + '%');
+}, function getHeight(props) {
+        return props.height ? props.height : ('90' + 'vw');
+}, function getDisplay(props) {
+        return props.display ? props.display : ('flex' + '');
+}], function createEmotionStyledRules(x0, x1, x2, x3, x4) {
+        return [\`.css-1lqib20 { margin: \${x0};
+        padding: \${x1};
+        font-size: attr(fontSize ch, 8);
+        width: \${x2};
+        height: \${x3};
+        display: \${x4}; }\`];
+});"
+`;
+
+exports[`emotion/babel babel styled component attr with default value 1`] = `
+"styled('input', 'css-1luxokk', [function getMargin(props) {
+        return props.margin ? props.margin : ('16' + '');
+}], function createEmotionStyledRules(x0) {
+        return [\`.css-1luxokk { margin: \${x0}; }\`];
+});"
+`;
+
+exports[`emotion/babel babel styled component attr with value type 1`] = `
+"styled('input', 'css-1luxokk', [function getMargin(props) {
+        return props.margin + 'px';
+}], function createEmotionStyledRules(x0) {
+        return [\`.css-1luxokk { margin: \${x0}; }\`];
+});"
+`;
+
+exports[`emotion/babel babel styled component attr with value type and default value 1`] = `
+"styled('input', 'css-1luxokk', [function getMargin(props) {
+        return props.margin ? props.margin : ('16' + 'px');
+}], function createEmotionStyledRules(x0) {
+        return [\`.css-1luxokk { margin: \${x0}; }\`];
+});"
+`;
+
+exports[`emotion/babel babel styled component basic 1`] = `
+"const H1 = styled('h1', 'css-H1-1t8i2zo', [fontSize + 'px'], function createEmotionStyledRules(x0) {
+  return [\`.css-H1-1t8i2zo { font-size: \${x0}; }\`];
+});"
+`;
+
+exports[`emotion/babel babel styled component extract based on props 1`] = `
+"import './babel.test.emotion.css';
+const H1 = styled('h1', 'css-H1-q3ohdq', [fontSize + 'px', props => props.translateX]);"
+`;
+
+exports[`emotion/babel babel styled component extract based on props 2`] = `".css-H1-q3ohdq { font-size: var(--css-H1-q3ohdq-0); height: 20px; -webkit-transform: translateX(var(--css-H1-q3ohdq-1)); -ms-transform: translateX(var(--css-H1-q3ohdq-1)); transform: translateX(var(--css-H1-q3ohdq-1)) }"`;
+
+exports[`emotion/babel babel styled component extract basic 1`] = `
+"import './babel.test.emotion.css';
+const H1 = styled('h1', 'css-H1-1mh2el5', [fontSize + 'px']);"
+`;
+
+exports[`emotion/babel babel styled component extract basic 2`] = `".css-H1-1mh2el5 { font-size: var(--css-H1-1mh2el5-0); height: 20px }"`;
+
+exports[`emotion/babel babel styled component extract no dynamic 1`] = `
+"import \\"./babel.test.emotion.css\\";
+styled(\\"h1\\", \\"css-14ksm7b\\", []);"
+`;
+
+exports[`emotion/babel babel styled component extract no dynamic 2`] = `".css-14ksm7b { color: blue; }"`;
+
+exports[`emotion/babel babel styled component extract no use 1`] = `"\\"h1\\";"`;
+
+exports[`emotion/babel babel styled component extract with fragment 1`] = `
+"const frag1 = fragment([], function createEmotionFragment() {
+  return \` width: 20px; \`;
+});
+const H1 = styled('h1', 'css-H1-osx1au', [fontSize + 'px', props => props.translateX, frag1], function createEmotionStyledRules(x0, x1, x2) {
+  return [\`.css-H1-osx1au { font-size: \${x0};
+        height: 20px;
+        -webkit-transform: translateX(\${x1});
+        -ms-transform: translateX(\${x1});
+        transform: translateX(\${x1});
+        \${x2} }\`];
+});"
+`;
+
+exports[`emotion/babel babel styled component extract with fragment 2`] = `".css-H1-q3ohdq { font-size: var(--css-H1-q3ohdq-0); height: 20px; -webkit-transform: translateX(var(--css-H1-q3ohdq-1)); -ms-transform: translateX(var(--css-H1-q3ohdq-1)); transform: translateX(var(--css-H1-q3ohdq-1)) }"`;
+
+exports[`emotion/babel babel styled component function call 1`] = `
+"styled(MyComponent, 'css-1t8i2zo', [fontSize + 'px'], function createEmotionStyledRules(x0) {
+  return [\`.css-1t8i2zo { font-size: \${x0}; }\`];
+});"
+`;
+
+exports[`emotion/babel babel styled component match works on multiple 1`] = `
+"styled('input', 'css-1j6h68f', [function getMargin(props) {
+        return props.margin ? props.margin : ('16' + 'px');
+}, function getPadding(props) {
+        return props.padding ? props.padding : ('16' + 'em');
+}], function createEmotionStyledRules(x0, x1) {
+        return [\`.css-1j6h68f { margin: \${x0};
+        color: blue;
+        padding: \${x1}; }\`];
+});"
+`;
+
+exports[`emotion/babel babel styled component name is correct with no identifier 1`] = `
+"
+css(\\"css-1cppx8p\\", [], function createEmotionRules() {
+        return [\`.css-1cppx8p { margin: 12px 48px;
+        color: #ffffff; }\`];
+});"
+`;
+
+exports[`emotion/babel babel styled component no dynamic 1`] = `
+"styled(\\"h1\\", \\"css-14ksm7b\\", [], function createEmotionStyledRules() {
+  return [\`.css-14ksm7b { color: blue; }\`];
+});"
+`;
+
+exports[`emotion/babel babel styled component no use 1`] = `"\\"h1\\";"`;
diff --git a/test/__snapshots__/font-face.test.js.snap b/test/__snapshots__/font-face.test.js.snap
index 5dc1c850..b34e6aa7 100644
--- a/test/__snapshots__/font-face.test.js.snap
+++ b/test/__snapshots__/font-face.test.js.snap
@@ -1,21 +1,3 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`font-face adds font-face to sheet 1`] = `
-"@font-face {font-family: 'Patrick Hand SC';
-      font-style: normal;
-      font-weight: 400;
-      src: local('Patrick Hand SC'), local('PatrickHandSC-Regular'), url(https://fonts.gstatic.com/s/patrickhandsc/v4/OYFWCgfCR-7uHIovjUZXsZ71Uis0Qeb9Gqo8IZV7ckE.woff2) format('woff2');
-      unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;}"
-`
-
-exports[`font-face adds font-face to sheet with interpolation 1`] = `
-"@font-face {font-family: 'Patrick Hand SC';
-      font-style: normal;
-      font-weight: 400;
-      src: local('Patrick Hand SC'), local('PatrickHandSC-Regular'), url(https://fonts.gstatic.com/s/patrickhandsc/v4/OYFWCgfCR-7uHIovjUZXsZ71Uis0Qeb9Gqo8IZV7ckE.woff2) format('woff2');
-      unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: MyHelvetica;
-      src: local(\\"Helvetica Neue Bold\\"),
-          local(\\"HelveticaNeue-Bold\\"),
-          url(MgOpenModernaBold.ttf);
-      font-weight: bold;}"
-`
+exports[`font-face adds font-face to sheet 1`] = `Array []`;
diff --git a/test/__snapshots__/inject-global.test.js.snap b/test/__snapshots__/inject-global.test.js.snap
deleted file mode 100644
index 09c0a7f8..00000000
--- a/test/__snapshots__/inject-global.test.js.snap
+++ /dev/null
@@ -1,11 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`injectGlobal 1`] = `
-"html {
-      background: pink;
-    }body {
-      color: yellow
-       margin: 0;
-    padding: 0; 
-    }"
-`;
diff --git a/test/__snapshots__/keyframes.test.js.snap b/test/__snapshots__/keyframes.test.js.snap
index 6eaf4c91..bdd25434 100644
--- a/test/__snapshots__/keyframes.test.js.snap
+++ b/test/__snapshots__/keyframes.test.js.snap
@@ -1,58 +1,14 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`keyframes keyframes with interpolation 1`] = `
-"@keyframes animation-bounce-10a3qiv-cmo0tx { from, 20%, 53%, 80%, to {
-        -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
-        animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
-        -webkit-transform: translate3d(0,0,0);
-        -ms-transform: translate3d(0,0,0);
-        transform: translate3d(0,0,0);
-      }
-    
-      40%, 43% {
-        -webkit-animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
-        animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
-        -webkit-transform: translate3d(0, -30px, 0);
-        -ms-transform: translate3d(0, -30px, 0);
-        transform: translate3d(0, -30px, 0);
-      }
-    
-      70% {
-        -webkit-animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
-        animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
-        -webkit-transform: translate3d(0, -15px, 0);
-        -ms-transform: translate3d(0, -15px, 0);
-        transform: translate3d(0, -15px, 0);
-      }
-    
-      90% {
-        -webkit-transform: translate3d(0,-4px,0);
-        -ms-transform: translate3d(0,-4px,0);
-        transform: translate3d(0,-4px,0);
-      } }.css-H1-o0kcx2-fy8ana { font-size: 20px;
-      -webkit-animation: animation-bounce-10a3qiv-cmo0tx 2s linear infinite;
-      animation: animation-bounce-10a3qiv-cmo0tx 2s linear infinite; }@keyframes animation-1fpnjxj-1mmv2re { from {
-        -webkit-transform: rotate(0deg);
-        -ms-transform: rotate(0deg);
-        transform: rotate(0deg);
-      }
-    
-      to {
-        -webkit-transform: rotate(360deg);
-        -ms-transform: rotate(360deg);
-        transform: rotate(360deg);
-      } }"
-`;
-
 exports[`keyframes renders 1`] = `
-.css-H1-o0kcx2-fy8ana {
+.css-H1-o0kcx2-5hrnwy {
   font-size: 20px;
-  -webkit-animation: animation-bounce-10a3qiv-cmo0tx 2s linear infinite;
-  animation: animation-bounce-10a3qiv-cmo0tx 2s linear infinite;
+  -webkit-animation: animation-bounce-10a3qiv-c1ph90 2s linear infinite;
+  animation: animation-bounce-10a3qiv-c1ph90 2s linear infinite;
 }
 
 <h1
-  className="css-H1-o0kcx2-fy8ana"
+  className="css-H1-o0kcx2-5hrnwy"
 >
   hello world
 </h1>
diff --git a/test/__snapshots__/parser.test.js.snap b/test/__snapshots__/parser.test.js.snap
index 9dc968e8..953e275b 100644
--- a/test/__snapshots__/parser.test.js.snap
+++ b/test/__snapshots__/parser.test.js.snap
@@ -15,7 +15,7 @@ Array [
   width: var(--css-hash-0);
 }",
 ]
-`
+`;
 
 exports[`parser fancy 1`] = `
 Array [
@@ -52,7 +52,7 @@ Array [
   content: 'pseudo'
 }",
 ]
-`
+`;
 
 exports[`parser static 1`] = `
 Array [
@@ -62,4 +62,4 @@ Array [
   width: 30px
 }",
 ]
-`
+`;
diff --git a/test/__snapshots__/styled.test.js.snap b/test/__snapshots__/styled.test.js.snap
index b6eccad7..896fca1e 100644
--- a/test/__snapshots__/styled.test.js.snap
+++ b/test/__snapshots__/styled.test.js.snap
@@ -13,12 +13,12 @@ exports[`styled attr 1`] = `
 `;
 
 exports[`styled basic render 1`] = `
-.css-H1-8xpzga-1e133rd {
+.css-H1-13wdnau-xy96vj {
   font-size: 20px;
 }
 
 <h1
-  className="css-H1-8xpzga-1e133rd"
+  className="css-H1-13wdnau-xy96vj"
 >
   hello world
 </h1>
@@ -108,6 +108,19 @@ exports[`styled higher order component 1`] = `
 />
 `;
 
+exports[`styled innerRef 1`] = `
+.css-H1-dae0kw-kdrkuq {
+  font-size: 12px;
+}
+
+<h1
+  className="css-H1-dae0kw-kdrkuq"
+  innerRef={[Function]}
+>
+  hello world
+</h1>
+`;
+
 exports[`styled name 1`] = `
 .css-FancyH1-1azfbv1-1fzd8kz {
   font-size: 20px;
@@ -121,18 +134,13 @@ exports[`styled name 1`] = `
 `;
 
 exports[`styled no dynamic 1`] = `
-.css-H1-ijh7uz-10q50rl {
+.css-H1-dae0kw-kdrkuq {
   font-size: 12px;
 }
 
 <h1
-  className="css-H1-ijh7uz-10q50rl"
+  className="css-H1-dae0kw-kdrkuq"
 >
   hello world
 </h1>
 `;
-
-exports[`styled throws if undefined is passed as the component 1`] = `
-"You are trying to create a styled element with an undefined component.
-You may have forgotten to import it."
-`;
diff --git a/test/babel/fs.test.js b/test/babel-fs.test.js
similarity index 98%
rename from test/babel/fs.test.js
rename to test/babel-fs.test.js
index 6e22fcff..a01e58c4 100644
--- a/test/babel/fs.test.js
+++ b/test/babel-fs.test.js
@@ -2,7 +2,7 @@
 import { transform } from 'babel-core'
 import fs from 'fs'
 import touch from 'touch'
-import emotionPlugin from '../../src/babel'
+import emotionPlugin from '../src/babel'
 
 jest.mock('fs').mock('touch')
 
diff --git a/test/babel/styled.test.js b/test/babel.test.js
similarity index 51%
rename from test/babel/styled.test.js
rename to test/babel.test.js
index 92488e75..4da31233 100644
--- a/test/babel/styled.test.js
+++ b/test/babel.test.js
@@ -1,14 +1,15 @@
-/* eslint-disable no-template-curly-in-string */
+/* eslint-disable jsx-quotes,no-useless-escape,no-template-curly-in-string */
 /* eslint-env jest */
-import * as babel from 'babel-core'
-import plugin from '../../src/babel'
-import * as fs from 'fs'
+const babel = require('babel-core')
+const plugin = require('../src/babel')
+const fs = require('fs')
+
 jest.mock('fs')
 
 fs.existsSync.mockReturnValue(true)
 
-describe('babel styled component', () => {
-  describe('inline', () => {
+describe('emotion/babel', () => {
+  describe('babel styled component', () => {
     test('no use', () => {
       const basic = 'styled.h1``'
       const { code } = babel.transform(basic, {
@@ -58,10 +59,10 @@ describe('babel styled component', () => {
       const basic = `styled('input')\`
        margin: attr(margin);
        color: #ffffff;
-       height: \${props => props.height * props.scale};
+       height: \$\{props => props.height * props.scale\};
        width: attr(width);
        color: blue;
-       display: \${flex};
+       display: \$\{flex\};
       \``
       const { code } = babel.transform(basic, {
         plugins: [plugin]
@@ -126,7 +127,42 @@ describe('babel styled component', () => {
       expect(code).toMatchSnapshot()
     })
   })
-  describe('extract', () => {
+  describe('babel css', () => {
+    test('css basic', () => {
+      const basic = `
+        css\`
+        margin: 12px 48px;
+        color: #ffffff;
+        display: flex;
+        flex: 1 0 auto;
+        color: blue;
+        width: \$\{widthVar\};
+      \``
+      const { code } = babel.transform(basic, {
+        plugins: [[plugin]]
+      })
+      expect(code).toMatchSnapshot()
+    })
+
+    test('css kitchen sink', () => {
+      const basic = `
+        const cls = css\`font-size: 58pt;margin: $\{margin};\`
+        const frag = fragment\`padding: 8px;\`
+        const fragB = fragment\`height: $\{heightVar};@apply \$\{frag};\`
+        const cls2 = css\`
+        @apply $\{frag};
+        @apply $\{fragB};
+        margin: 12px 48px;
+        color: #ffffff;
+        \`
+      `
+      const { code } = babel.transform(basic, {
+        plugins: [[plugin]]
+      })
+      expect(code).toMatchSnapshot()
+    })
+  })
+  describe('babel styled component extract', () => {
     test('no use', () => {
       const basic = 'styled.h1``'
       const { code } = babel.transform(basic, {
@@ -190,6 +226,128 @@ describe('babel styled component', () => {
       })
       expect(code).toMatchSnapshot()
       expect(fs.writeFileSync).toHaveBeenCalledTimes(3)
+      expect(fs.writeFileSync.mock.calls[2][1]).toMatchSnapshot()
+    })
+  })
+  describe('babel css extract', () => {
+    test('css basic', () => {
+      const basic = `
+        css\`
+        margin: 12px 48px;
+        color: #ffffff;
+        display: flex;
+        flex: 1 0 auto;
+        color: blue;
+        width: \$\{widthVar\};
+      \``
+      const { code } = babel.transform(basic, {
+        plugins: [[plugin]],
+        filename: __filename,
+        babelrc: false
+      })
+      expect(code).toMatchSnapshot()
+      expect(fs.writeFileSync).toHaveBeenCalledTimes(4)
+      expect(fs.writeFileSync.mock.calls[3][1]).toMatchSnapshot()
+    })
+
+    test('css kitchen sink', () => {
+      const basic = `
+        const cls = css\`font-size: 58pt;margin: $\{margin};\`
+        const frag = fragment\`padding: 8px;\`
+        const fragB = fragment\`height: $\{heightVar};@apply \$\{frag};\`
+        const cls2 = css\`
+        @apply $\{frag};
+        @apply $\{fragB};
+        margin: 12px 48px;
+        color: #ffffff;
+        \`
+      `
+      const { code } = babel.transform(basic, {
+        plugins: [[plugin]],
+        filename: __filename,
+        babelrc: false
+      })
+      expect(code).toMatchSnapshot()
+      expect(fs.writeFileSync).toHaveBeenCalledTimes(5)
+      expect(fs.writeFileSync.mock.calls[4][1]).toMatchSnapshot()
+    })
+  })
+  describe('babel fragment', () => {
+    test('basic fragment', () => {
+      const basic = `
+        const frag = fragment\`color: green\`;
+        styled.h1\`font-size: 20px; @apply \${frag};\``
+      const { code } = babel.transform(basic, {
+        plugins: [plugin]
+      })
+      expect(code).toMatchSnapshot()
+    })
+
+    test('fragment kitchen sink', () => {
+      const basic = `
+        const frag = fragment\`color: green; background-color: \${backgroundColor}\`;
+        const frag1 = fragment\` width: 20px; name: some-frag-name; \`
+        const frag2 = fragment\` height: 20px; @apply \${frag1}; \`
+        styled.h1\`font-size: \${fontSize + 'px'}; name: some-name; @apply \${frag}; @apply \${frag2}\``
+      const { code } = babel.transform(basic, {
+        plugins: [plugin]
+      })
+      expect(code).toMatchSnapshot()
+    })
+
+    test('fragment with multiple selectors that should throw', () => {
+      expect(() => {
+        const basic = `
+          const frag = fragment\`
+            color: green;
+            display: none;
+            &:hover {
+              color: yellow;
+            }
+            & .wow {
+              color: purple;
+            }
+          \`;
+        `
+        babel.transform(basic, {
+          plugins: [plugin]
+        })
+      }).toThrowErrorMatchingSnapshot()
+    })
+  })
+
+  describe('babel keyframes', () => {
+    test('keyframe basic', () => {
+      const basic = `
+        const rotate360 = keyframes\`
+          from {
+            transform: rotate(0deg);
+          }
+        
+          to {
+            transform: rotate(360deg);
+          }
+      \`;`
+      const { code } = babel.transform(basic, {
+        plugins: [[plugin]]
+      })
+      expect(code).toMatchSnapshot()
+    })
+  })
+  describe('babel font-face', () => {
+    test('font-face basic', () => {
+      const basic = `
+        fontFace\`
+          font-family: MyHelvetica;
+          src: local("Helvetica Neue Bold"),
+               local("HelveticaNeue-Bold"),
+               url(MgOpenModernaBold.ttf);
+          font-weight: bold;
+      \`;`
+      const { code } = babel.transform(basic, {
+        plugins: [[plugin]]
+      })
+      expect(code).toMatchSnapshot()
     })
   })
 })
diff --git a/test/babel/__snapshots__/css.test.js.snap b/test/babel/__snapshots__/css.test.js.snap
deleted file mode 100644
index 22a3d37b..00000000
--- a/test/babel/__snapshots__/css.test.js.snap
+++ /dev/null
@@ -1,75 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`babel css extract css basic 1`] = `
-"import \\"./css.test.emotion.css\\";
-
-css(\\"css-cu78iu\\", [widthVar]);"
-`;
-
-exports[`babel css extract css basic 2`] = `
-".css-cu78iu { margin: 12px 48px;
-        color: #ffffff;
-        display: -webkit-box;
-        display: -moz-box;
-        display: -ms-flexbox;
-        display: -webkit-flex;
-        display: flex;
-        -webkit-flex: 1 0 auto;
-        -ms-flex: 1 0 auto;
-        flex: 1 0 auto;
-        color: blue;
-        width: var(--css-cu78iu-0); }"
-`;
-
-exports[`babel css extract css kitchen sink 1`] = `
-"
-const frag = fragment([], function createEmotionFragment() {
-        return \` padding: 8px; \`;
-});
-const fragB = fragment([heightVar, frag], function createEmotionFragment(x0, x1) {
-        return \` height: \${x0};\${x1}; \`;
-});
-const cls2 = css(\\"css-cls2-1b4c3x0\\", [frag, fragB], function createEmotionRules(x0, x1) {
-        return [\`.css-cls2-1b4c3x0 { \${x0};
-        \${x1};
-        margin: 12px 48px;
-        color: #ffffff; }\`];
-});"
-`;
-
-exports[`babel css inline css basic 1`] = `
-"
-css(\\"css-cu78iu\\", [widthVar], function createEmotionRules(x0) {
-        return [\`.css-cu78iu { margin: 12px 48px;
-        color: #ffffff;
-        display: -webkit-box;
-        display: -moz-box;
-        display: -ms-flexbox;
-        display: -webkit-flex;
-        display: flex;
-        -webkit-flex: 1 0 auto;
-        -ms-flex: 1 0 auto;
-        flex: 1 0 auto;
-        color: blue;
-        width: \${x0}; }\`];
-});"
-`;
-
-exports[`babel css inline css kitchen sink 1`] = `
-"
-const cls = css(\\"css-cls-h5t3cu\\", [margin], function createEmotionRules(x0) {
-        return [\`.css-cls-h5t3cu { font-size: 58pt;margin: \${x0}; }\`];
-});
-const frag = fragment([], function createEmotionFragment() {
-        return \` padding: 8px; \`;
-});
-const fragB = fragment([heightVar, frag], function createEmotionFragment(x0, x1) {
-        return \` height: \${x0};\${x1}; \`;
-});
-const cls2 = css(\\"css-cls2-1b4c3x0\\", [frag, fragB], function createEmotionRules(x0, x1) {
-        return [\`.css-cls2-1b4c3x0 { \${x0};
-        \${x1};
-        margin: 12px 48px;
-        color: #ffffff; }\`];
-});"
-`;
diff --git a/test/babel/__snapshots__/font-face.test.js.snap b/test/babel/__snapshots__/font-face.test.js.snap
deleted file mode 100644
index 75c2cd9e..00000000
--- a/test/babel/__snapshots__/font-face.test.js.snap
+++ /dev/null
@@ -1,58 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`fontFace babel extract basic 1`] = `"import \\"./font-face.test.emotion.css\\";"`;
-
-exports[`fontFace babel extract basic 2`] = `
-"@font-face {font-family: MyHelvetica;
-          src: local(\\"Helvetica Neue Bold\\"),
-               local(\\"HelveticaNeue-Bold\\"),
-               url(MgOpenModernaBold.ttf);
-          font-weight: bold;}"
-`;
-
-exports[`fontFace babel extract basic assign to variable 1`] = `
-"import \\"./font-face.test.emotion.css\\";
-
-const thisWillBeUndefined = undefined;"
-`;
-
-exports[`fontFace babel extract basic assign to variable 2`] = `
-"@font-face {font-family: MyHelvetica;
-          src: local(\\"Helvetica Neue Bold\\"),
-               local(\\"HelveticaNeue-Bold\\"),
-               url(MgOpenModernaBold.ttf);
-          font-weight: bold;}"
-`;
-
-exports[`fontFace babel extract interpolation 1`] = `
-"
-fontFace([fontFamilyName], function createEmotionFontFace(x0) {
-     return [\`@font-face {font-family: \${x0};
-          src: local(\\"Helvetica Neue Bold\\"),
-               local(\\"HelveticaNeue-Bold\\"),
-               url(MgOpenModernaBold.ttf);
-          font-weight: bold;}\`];
-});"
-`;
-
-exports[`fontFace babel inline basic 1`] = `
-"
-fontFace([], function createEmotionFontFace() {
-     return [\`@font-face {font-family: MyHelvetica;
-          src: local(\\"Helvetica Neue Bold\\"),
-               local(\\"HelveticaNeue-Bold\\"),
-               url(MgOpenModernaBold.ttf);
-          font-weight: bold;}\`];
-});"
-`;
-
-exports[`fontFace babel inline interpolation 1`] = `
-"
-fontFace([fontFamilyName], function createEmotionFontFace(x0) {
-     return [\`@font-face {font-family: \${x0};
-          src: local(\\"Helvetica Neue Bold\\"),
-               local(\\"HelveticaNeue-Bold\\"),
-               url(MgOpenModernaBold.ttf);
-          font-weight: bold;}\`];
-});"
-`;
diff --git a/test/babel/__snapshots__/fragment.test.js.snap b/test/babel/__snapshots__/fragment.test.js.snap
deleted file mode 100644
index 43205560..00000000
--- a/test/babel/__snapshots__/fragment.test.js.snap
+++ /dev/null
@@ -1,29 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`babel fragment basic fragment 1`] = `
-"
-const frag = fragment([], function createEmotionFragment() {
-      return \` color: green \`;
-});
-styled(\\"h1\\", \\"css-u3lc8x\\", [frag], function createEmotionStyledRules(x0) {
-      return [\`.css-u3lc8x { font-size: 20px; \${x0}; }\`];
-});"
-`;
-
-exports[`babel fragment fragment kitchen sink 1`] = `
-"
-const frag = fragment([backgroundColor], function createEmotionFragment(x0) {
-      return \` color: green; background-color: \${x0} \`;
-});
-const frag1 = fragment([], function createEmotionFragment() {
-      return \` width: 20px; \`;
-});
-const frag2 = fragment([frag1], function createEmotionFragment(x0) {
-      return \` height: 20px; \${x0}; \`;
-});
-styled('h1', 'css-some-name-9k8moo', [fontSize + 'px', frag, frag2], function createEmotionStyledRules(x0, x1, x2) {
-      return [\`.css-some-name-9k8moo { font-size: \${x0}; \${x1}; \${x2} }\`];
-});"
-`;
-
-exports[`babel fragment fragment with multiple selectors that should throw 1`] = `"unknown: Fragments cannot have multiple selectors."`;
diff --git a/test/babel/__snapshots__/inject-global.test.js.snap b/test/babel/__snapshots__/inject-global.test.js.snap
deleted file mode 100644
index 745652b5..00000000
--- a/test/babel/__snapshots__/inject-global.test.js.snap
+++ /dev/null
@@ -1,94 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`babel injectGlobal extract injectGlobal assign to variable 1`] = `
-"import \\"./inject-global.test.emotion.css\\";
-
-const thisWillBeUndefined = undefined;"
-`;
-
-exports[`babel injectGlobal extract injectGlobal assign to variable 2`] = `
-"body {
-            margin: 0;
-            padding: 0;
-          }
-body > div {
-            display: none;
-}
-html {
-            background: green;
-          }"
-`;
-
-exports[`babel injectGlobal extract injectGlobal basic 1`] = `"import \\"./inject-global.test.emotion.css\\";"`;
-
-exports[`babel injectGlobal extract injectGlobal basic 2`] = `
-"body {
-            margin: 0;
-            padding: 0;
-          }
-body > div {
-            display: none;
-}
-html {
-            background: green;
-          }"
-`;
-
-exports[`babel injectGlobal extract injectGlobal with interpolation 1`] = `
-"
-injectGlobal([display], function createEmotionGlobal(x0) {
-  return [\`body {
-            margin: 0;
-            padding: 0;
-            display: \${x0};
-          }\`, \`body > div {
-            display: none;
-}\`, \`html {
-            background: green;
-          }\`];
-});"
-`;
-
-exports[`babel injectGlobal inline injectGlobal basic 1`] = `
-"
-injectGlobal([], function createEmotionGlobal() {
-  return [\`body {
-            margin: 0;
-            padding: 0;
-          }\`, \`body > div {
-            display: none;
-}\`, \`html {
-            background: green;
-          }\`];
-});"
-`;
-
-exports[`babel injectGlobal inline injectGlobal with fragment 1`] = `
-"
-injectGlobal([display, htmlStyled], function createEmotionGlobal(x0, x1) {
-  return [\`body {
-            margin: 0;
-            padding: 0;
-            display: \${x0};
-          }\`, \`body > div {
-            display: none;
-}\`, \`html {
-            \${x1}
-          }\`];
-});"
-`;
-
-exports[`babel injectGlobal inline injectGlobal with interpolation 1`] = `
-"
-injectGlobal([display], function createEmotionGlobal(x0) {
-  return [\`body {
-            margin: 0;
-            padding: 0;
-            display: \${x0};
-          }\`, \`body > div {
-            display: none;
-}\`, \`html {
-            background: green;
-          }\`];
-});"
-`;
diff --git a/test/babel/__snapshots__/keyframes.test.js.snap b/test/babel/__snapshots__/keyframes.test.js.snap
deleted file mode 100644
index a03e7673..00000000
--- a/test/babel/__snapshots__/keyframes.test.js.snap
+++ /dev/null
@@ -1,87 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`babel keyframes extract keyframes basic 1`] = `
-"import \\"./keyframes.test.emotion.css\\";
-
-const rotate360 = \\"animation-rotate360-f35ahc\\";"
-`;
-
-exports[`babel keyframes extract keyframes basic 2`] = `
-"@keyframes animation-rotate360-f35ahc { from {
-            -webkit-transform: rotate(0deg);
-            -ms-transform: rotate(0deg);
-            transform: rotate(0deg);
-          }
-        
-          to {
-            -webkit-transform: rotate(360deg);
-            -ms-transform: rotate(360deg);
-            transform: rotate(360deg);
-          } }"
-`;
-
-exports[`babel keyframes extract keyframes with interpolation 1`] = `
-"
-const rotate360 = keyframes(\\"animation-rotate360-9bsj7q\\", [endingRotation], function createEmotionKeyframes(x0) {
-  return [\`{ from {
-            -webkit-transform: rotate(0deg);
-            -ms-transform: rotate(0deg);
-            transform: rotate(0deg);
-          }
-        
-          to {
-            -webkit-transform: rotate(\${x0});
-            -ms-transform: rotate(\${x0});
-            transform: rotate(\${x0});
-          } }\`];
-});"
-`;
-
-exports[`babel keyframes inline keyframes basic 1`] = `
-"
-const rotate360 = keyframes(\\"animation-rotate360-10gy9ar\\", [], function createEmotionKeyframes() {
-  return [\`{ from {
-            -webkit-transform: rotate(0deg);
-            -ms-transform: rotate(0deg);
-            transform: rotate(0deg);
-          }
-          to {
-            -webkit-transform: rotate(360deg);
-            -ms-transform: rotate(360deg);
-            transform: rotate(360deg);
-          } }\`];
-});"
-`;
-
-exports[`babel keyframes inline keyframes with fragment 1`] = `
-"
-const rotate360 = keyframes(\\"animation-rotate360-b0ufjw\\", [endingRotation, frag1], function createEmotionKeyframes(x0, x1) {
-  return [\`{ from {
-            -webkit-transform: rotate(0deg);
-            -ms-transform: rotate(0deg);
-            transform: rotate(0deg);
-          }
-          to {
-            -webkit-transform: rotate(\${x0});
-            -ms-transform: rotate(\${x0});
-            transform: rotate(\${x0});
-            \${x1}
-          } }\`];
-});"
-`;
-
-exports[`babel keyframes inline keyframes with interpolation 1`] = `
-"
-const rotate360 = keyframes(\\"animation-rotate360-r2494l\\", [endingRotation], function createEmotionKeyframes(x0) {
-  return [\`{ from {
-            -webkit-transform: rotate(0deg);
-            -ms-transform: rotate(0deg);
-            transform: rotate(0deg);
-          }
-          to {
-            -webkit-transform: rotate(\${x0});
-            -ms-transform: rotate(\${x0});
-            transform: rotate(\${x0});
-          } }\`];
-});"
-`;
diff --git a/test/babel/__snapshots__/styled.test.js.snap b/test/babel/__snapshots__/styled.test.js.snap
deleted file mode 100644
index 4c275c2d..00000000
--- a/test/babel/__snapshots__/styled.test.js.snap
+++ /dev/null
@@ -1,138 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`babel styled component extract based on props 1`] = `
-"import './styled.test.emotion.css';
-const H1 = styled('h1', 'css-H1-q3ohdq', [fontSize + 'px', props => props.translateX]);"
-`;
-
-exports[`babel styled component extract based on props 2`] = `".css-H1-q3ohdq { font-size: var(--css-H1-q3ohdq-0); height: 20px; -webkit-transform: translateX(var(--css-H1-q3ohdq-1)); -ms-transform: translateX(var(--css-H1-q3ohdq-1)); transform: translateX(var(--css-H1-q3ohdq-1)) }"`;
-
-exports[`babel styled component extract basic 1`] = `
-"import './styled.test.emotion.css';
-const H1 = styled('h1', 'css-H1-1mh2el5', [fontSize + 'px']);"
-`;
-
-exports[`babel styled component extract basic 2`] = `".css-H1-1mh2el5 { font-size: var(--css-H1-1mh2el5-0); height: 20px }"`;
-
-exports[`babel styled component extract no dynamic 1`] = `
-"import \\"./styled.test.emotion.css\\";
-styled(\\"h1\\", \\"css-14ksm7b\\", []);"
-`;
-
-exports[`babel styled component extract no dynamic 2`] = `".css-14ksm7b { color: blue; }"`;
-
-exports[`babel styled component extract no use 1`] = `"\\"h1\\";"`;
-
-exports[`babel styled component extract with fragment 1`] = `
-"const frag1 = fragment([], function createEmotionFragment() {
-  return \` width: 20px; \`;
-});
-const H1 = styled('h1', 'css-H1-osx1au', [fontSize + 'px', props => props.translateX, frag1], function createEmotionStyledRules(x0, x1, x2) {
-  return [\`.css-H1-osx1au { font-size: \${x0};
-        height: 20px;
-        -webkit-transform: translateX(\${x1});
-        -ms-transform: translateX(\${x1});
-        transform: translateX(\${x1});
-        \${x2} }\`];
-});"
-`;
-
-exports[`babel styled component inline attr 1`] = `
-"styled('input', 'css-14vghnb', [function getMargin(props) {
-       return props.margin;
-}, props => props.height * props.scale, function getWidth(props) {
-       return props.width;
-}, flex], function createEmotionStyledRules(x0, x1, x2, x3) {
-       return [\`.css-14vghnb { margin: \${x0};
-       color: #ffffff;
-       height: \${x1};
-       width: \${x2};
-       color: blue;
-       display: \${x3}; }\`];
-});"
-`;
-
-exports[`babel styled component inline attr kitchen sink 1`] = `
-"styled('input', 'css-1lqib20', [function getMargin(props) {
-        return props.margin ? props.margin : ('16' + 'px');
-}, function getPadding(props) {
-        return props.padding ? props.padding : ('16' + 'em');
-}, function getWidth(props) {
-        return props.width ? props.width : ('95' + '%');
-}, function getHeight(props) {
-        return props.height ? props.height : ('90' + 'vw');
-}, function getDisplay(props) {
-        return props.display ? props.display : ('flex' + '');
-}], function createEmotionStyledRules(x0, x1, x2, x3, x4) {
-        return [\`.css-1lqib20 { margin: \${x0};
-        padding: \${x1};
-        font-size: attr(fontSize ch, 8);
-        width: \${x2};
-        height: \${x3};
-        display: \${x4}; }\`];
-});"
-`;
-
-exports[`babel styled component inline attr with default value 1`] = `
-"styled('input', 'css-1luxokk', [function getMargin(props) {
-        return props.margin ? props.margin : ('16' + '');
-}], function createEmotionStyledRules(x0) {
-        return [\`.css-1luxokk { margin: \${x0}; }\`];
-});"
-`;
-
-exports[`babel styled component inline attr with value type 1`] = `
-"styled('input', 'css-1luxokk', [function getMargin(props) {
-        return props.margin + 'px';
-}], function createEmotionStyledRules(x0) {
-        return [\`.css-1luxokk { margin: \${x0}; }\`];
-});"
-`;
-
-exports[`babel styled component inline attr with value type and default value 1`] = `
-"styled('input', 'css-1luxokk', [function getMargin(props) {
-        return props.margin ? props.margin : ('16' + 'px');
-}], function createEmotionStyledRules(x0) {
-        return [\`.css-1luxokk { margin: \${x0}; }\`];
-});"
-`;
-
-exports[`babel styled component inline basic 1`] = `
-"const H1 = styled('h1', 'css-H1-1t8i2zo', [fontSize + 'px'], function createEmotionStyledRules(x0) {
-  return [\`.css-H1-1t8i2zo { font-size: \${x0}; }\`];
-});"
-`;
-
-exports[`babel styled component inline function call 1`] = `
-"styled(MyComponent, 'css-1t8i2zo', [fontSize + 'px'], function createEmotionStyledRules(x0) {
-  return [\`.css-1t8i2zo { font-size: \${x0}; }\`];
-});"
-`;
-
-exports[`babel styled component inline match works on multiple 1`] = `
-"styled('input', 'css-1j6h68f', [function getMargin(props) {
-        return props.margin ? props.margin : ('16' + 'px');
-}, function getPadding(props) {
-        return props.padding ? props.padding : ('16' + 'em');
-}], function createEmotionStyledRules(x0, x1) {
-        return [\`.css-1j6h68f { margin: \${x0};
-        color: blue;
-        padding: \${x1}; }\`];
-});"
-`;
-
-exports[`babel styled component inline name is correct with no identifier 1`] = `
-"
-css(\\"css-1cppx8p\\", [], function createEmotionRules() {
-        return [\`.css-1cppx8p { margin: 12px 48px;
-        color: #ffffff; }\`];
-});"
-`;
-
-exports[`babel styled component inline no dynamic 1`] = `
-"styled(\\"h1\\", \\"css-14ksm7b\\", [], function createEmotionStyledRules() {
-  return [\`.css-14ksm7b { color: blue; }\`];
-});"
-`;
-
-exports[`babel styled component inline no use 1`] = `"\\"h1\\";"`;
diff --git a/test/babel/css.test.js b/test/babel/css.test.js
deleted file mode 100644
index e57d7955..00000000
--- a/test/babel/css.test.js
+++ /dev/null
@@ -1,86 +0,0 @@
-/* eslint-env jest */
-import * as babel from 'babel-core'
-import plugin from '../../src/babel'
-import * as fs from 'fs'
-jest.mock('fs')
-
-fs.existsSync.mockReturnValue(true)
-
-describe('babel css', () => {
-  describe('inline', () => {
-    test('css basic', () => {
-      const basic = `
-        css\`
-        margin: 12px 48px;
-        color: #ffffff;
-        display: flex;
-        flex: 1 0 auto;
-        color: blue;
-        width: \${widthVar};
-      \``
-      const { code } = babel.transform(basic, {
-        plugins: [[plugin]]
-      })
-      expect(code).toMatchSnapshot()
-    })
-
-    test('css kitchen sink', () => {
-      const basic = `
-        const cls = css\`font-size: 58pt;margin: \${margin};\`
-        const frag = fragment\`padding: 8px;\`
-        const fragB = fragment\`height: \${heightVar};@apply \${frag};\`
-        const cls2 = css\`
-        @apply $\{frag};
-        @apply $\{fragB};
-        margin: 12px 48px;
-        color: #ffffff;
-        \`
-      `
-      const { code } = babel.transform(basic, {
-        plugins: [[plugin]]
-      })
-      expect(code).toMatchSnapshot()
-    })
-  })
-  describe('extract', () => {
-    test('css basic', () => {
-      const basic = `
-        css\`
-        margin: 12px 48px;
-        color: #ffffff;
-        display: flex;
-        flex: 1 0 auto;
-        color: blue;
-        width: \${widthVar};
-      \``
-      const { code } = babel.transform(basic, {
-        plugins: [[plugin]],
-        filename: __filename,
-        babelrc: false
-      })
-      expect(code).toMatchSnapshot()
-      expect(fs.writeFileSync).toHaveBeenCalledTimes(1)
-      expect(fs.writeFileSync.mock.calls[0][1]).toMatchSnapshot()
-    })
-
-    test('css kitchen sink', () => {
-      const basic = `
-        const frag = fragment\`padding: 8px;\`
-        const fragB = fragment\`height: \${heightVar};@apply \${frag};\`
-        const cls2 = css\`
-        @apply \${frag};
-        @apply \${fragB};
-        margin: 12px 48px;
-        color: #ffffff;
-        \`
-      `
-      const { code } = babel.transform(basic, {
-        plugins: [[plugin]],
-        filename: __filename,
-        babelrc: false
-      })
-      expect(code).toMatchSnapshot()
-      expect(fs.writeFileSync).toHaveBeenCalledTimes(1)
-    })
-  })
-})
diff --git a/test/babel/font-face.test.js b/test/babel/font-face.test.js
deleted file mode 100644
index 79cd3d88..00000000
--- a/test/babel/font-face.test.js
+++ /dev/null
@@ -1,95 +0,0 @@
-/* eslint-env jest */
-import * as babel from 'babel-core'
-import plugin from '../../src/babel'
-import * as fs from 'fs'
-jest.mock('fs')
-
-fs.existsSync.mockReturnValue(true)
-
-describe('fontFace babel', () => {
-  describe('inline', () => {
-    test('basic', () => {
-      const basic = `
-        fontFace\`
-          font-family: MyHelvetica;
-          src: local("Helvetica Neue Bold"),
-               local("HelveticaNeue-Bold"),
-               url(MgOpenModernaBold.ttf);
-          font-weight: bold;
-      \`;`
-      const { code } = babel.transform(basic, {
-        plugins: [[plugin]]
-      })
-      expect(code).toMatchSnapshot()
-    })
-    test('interpolation', () => {
-      const basic = `
-        fontFace\`
-          font-family: \${fontFamilyName};
-          src: local("Helvetica Neue Bold"),
-               local("HelveticaNeue-Bold"),
-               url(MgOpenModernaBold.ttf);
-          font-weight: bold;
-      \`;`
-      const { code } = babel.transform(basic, {
-        plugins: [[plugin]]
-      })
-      expect(code).toMatchSnapshot()
-    })
-  })
-  describe('extract', () => {
-    test('basic', () => {
-      const basic = `
-        fontFace\`
-          font-family: MyHelvetica;
-          src: local("Helvetica Neue Bold"),
-               local("HelveticaNeue-Bold"),
-               url(MgOpenModernaBold.ttf);
-          font-weight: bold;
-      \`;`
-      const { code } = babel.transform(basic, {
-        plugins: [[plugin]],
-        filename: __filename,
-        babelrc: false
-      })
-      expect(code).toMatchSnapshot()
-      expect(fs.writeFileSync).toHaveBeenCalledTimes(1)
-      expect(fs.writeFileSync.mock.calls[0][1]).toMatchSnapshot()
-    })
-    test('basic assign to variable', () => {
-      const basic = `
-        const thisWillBeUndefined = fontFace\`
-          font-family: MyHelvetica;
-          src: local("Helvetica Neue Bold"),
-               local("HelveticaNeue-Bold"),
-               url(MgOpenModernaBold.ttf);
-          font-weight: bold;
-      \`;`
-      const { code } = babel.transform(basic, {
-        plugins: [[plugin]],
-        filename: __filename,
-        babelrc: false
-      })
-      expect(code).toMatchSnapshot()
-      expect(fs.writeFileSync).toHaveBeenCalledTimes(2)
-      expect(fs.writeFileSync.mock.calls[1][1]).toMatchSnapshot()
-    })
-    test('interpolation', () => {
-      const basic = `
-        fontFace\`
-          font-family: \${fontFamilyName};
-          src: local("Helvetica Neue Bold"),
-               local("HelveticaNeue-Bold"),
-               url(MgOpenModernaBold.ttf);
-          font-weight: bold;
-      \`;`
-      const { code } = babel.transform(basic, {
-        plugins: [[plugin]],
-        babelrc: false,
-        filename: __filename
-      })
-      expect(code).toMatchSnapshot()
-      expect(fs.writeFileSync).toHaveBeenCalledTimes(2)
-    })
-  })
-})
diff --git a/test/babel/fragment.test.js b/test/babel/fragment.test.js
deleted file mode 100644
index 1f8db817..00000000
--- a/test/babel/fragment.test.js
+++ /dev/null
@@ -1,51 +0,0 @@
-/* eslint-env jest */
-import * as babel from 'babel-core'
-import plugin from '../../src/babel'
-import * as fs from 'fs'
-jest.mock('fs')
-
-fs.existsSync.mockReturnValue(true)
-
-describe('babel fragment', () => {
-  test('basic fragment', () => {
-    const basic = `
-      const frag = fragment\`color: green\`;
-      styled.h1\`font-size: 20px; @apply \${frag};\``
-    const { code } = babel.transform(basic, {
-      plugins: [plugin]
-    })
-    expect(code).toMatchSnapshot()
-  })
-
-  test('fragment kitchen sink', () => {
-    const basic = `
-      const frag = fragment\`color: green; background-color: \${backgroundColor}\`;
-      const frag1 = fragment\` width: 20px; name: some-frag-name; \`
-      const frag2 = fragment\` height: 20px; @apply \${frag1}; \`
-      styled.h1\`font-size: \${fontSize + 'px'}; name: some-name; @apply \${frag}; @apply \${frag2}\``
-    const { code } = babel.transform(basic, {
-      plugins: [plugin]
-    })
-    expect(code).toMatchSnapshot()
-  })
-
-  test('fragment with multiple selectors that should throw', () => {
-    expect(() => {
-      const basic = `
-        const frag = fragment\`
-          color: green;
-          display: none;
-          &:hover {
-            color: yellow;
-          }
-          & .wow {
-            color: purple;
-          }
-        \`;
-      `
-      babel.transform(basic, {
-        plugins: [plugin]
-      })
-    }).toThrowErrorMatchingSnapshot()
-  })
-})
diff --git a/test/babel/inject-global.test.js b/test/babel/inject-global.test.js
deleted file mode 100644
index 61aa901b..00000000
--- a/test/babel/inject-global.test.js
+++ /dev/null
@@ -1,140 +0,0 @@
-/* eslint-env jest */
-import * as babel from 'babel-core'
-import plugin from '../../src/babel'
-import * as fs from 'fs'
-jest.mock('fs')
-
-fs.existsSync.mockReturnValue(true)
-
-describe('babel injectGlobal', () => {
-  describe('inline', () => {
-    test('injectGlobal basic', () => {
-      const basic = `
-        injectGlobal\`
-          body {
-            margin: 0;
-            padding: 0;
-            & > div {
-              display: none;
-            }
-          }
-          html {
-            background: green;
-          }
-      \`;`
-      const { code } = babel.transform(basic, {
-        plugins: [[plugin]]
-      })
-      expect(code).toMatchSnapshot()
-    })
-    test('injectGlobal with interpolation', () => {
-      const basic = `
-        injectGlobal\`
-          body {
-            margin: 0;
-            padding: 0;
-            display: \${display};
-            & > div {
-              display: none;
-            }
-          }
-          html {
-            background: green;
-          }
-      \`;`
-      const { code } = babel.transform(basic, {
-        plugins: [[plugin]]
-      })
-      expect(code).toMatchSnapshot()
-    })
-    test('injectGlobal with fragment', () => {
-      const basic = `
-        injectGlobal\`
-          body {
-            margin: 0;
-            padding: 0;
-            display: \${display};
-            & > div {
-              display: none;
-            }
-          }
-          html {
-            @apply \${htmlStyled}
-          }
-      \`;`
-      const { code } = babel.transform(basic, {
-        plugins: [[plugin]]
-      })
-      expect(code).toMatchSnapshot()
-    })
-  })
-  describe('extract', () => {
-    test('injectGlobal basic', () => {
-      const basic = `
-        injectGlobal\`
-          body {
-            margin: 0;
-            padding: 0;
-            & > div {
-              display: none;
-            }
-          }
-          html {
-            background: green;
-          }
-      \`;`
-      const { code } = babel.transform(basic, {
-        plugins: [[plugin]],
-        filename: __filename,
-        babelrc: false
-      })
-      expect(code).toMatchSnapshot()
-      expect(fs.writeFileSync).toHaveBeenCalledTimes(1)
-      expect(fs.writeFileSync.mock.calls[0][1]).toMatchSnapshot()
-    })
-    test('injectGlobal assign to variable', () => {
-      const basic = `
-        const thisWillBeUndefined = injectGlobal\`
-          body {
-            margin: 0;
-            padding: 0;
-            & > div {
-              display: none;
-            }
-          }
-          html {
-            background: green;
-          }
-      \`;`
-      const { code } = babel.transform(basic, {
-        plugins: [[plugin]],
-        filename: __filename,
-        babelrc: false
-      })
-      expect(code).toMatchSnapshot()
-      expect(fs.writeFileSync).toHaveBeenCalledTimes(2)
-      expect(fs.writeFileSync.mock.calls[1][1]).toMatchSnapshot()
-    })
-    test('injectGlobal with interpolation', () => {
-      const basic = `
-        injectGlobal\`
-          body {
-            margin: 0;
-            padding: 0;
-            display: \${display};
-            & > div {
-              display: none;
-            }
-          }
-          html {
-            background: green;
-          }
-      \`;`
-      const { code } = babel.transform(basic, {
-        plugins: [[plugin]]
-      })
-      expect(code).toMatchSnapshot()
-      expect(fs.writeFileSync).toHaveBeenCalledTimes(2)
-    })
-  })
-})
diff --git a/test/babel/keyframes.test.js b/test/babel/keyframes.test.js
deleted file mode 100644
index dd5dc576..00000000
--- a/test/babel/keyframes.test.js
+++ /dev/null
@@ -1,99 +0,0 @@
-/* eslint-env jest */
-import * as babel from 'babel-core'
-import plugin from '../../src/babel'
-import * as fs from 'fs'
-jest.mock('fs')
-
-fs.existsSync.mockReturnValue(true)
-
-describe('babel keyframes', () => {
-  describe('inline', () => {
-    test('keyframes basic', () => {
-      const basic = `
-        const rotate360 = keyframes\`
-          from {
-            transform: rotate(0deg);
-          }
-          to {
-            transform: rotate(360deg);
-          }
-      \`;`
-      const { code } = babel.transform(basic, {
-        plugins: [[plugin]]
-      })
-      expect(code).toMatchSnapshot()
-    })
-    test('keyframes with interpolation', () => {
-      const basic = `
-        const rotate360 = keyframes\`
-          from {
-            transform: rotate(0deg);
-          }
-          to {
-            transform: rotate(\${endingRotation});
-          }
-      \`;`
-      const { code } = babel.transform(basic, {
-        plugins: [[plugin]]
-      })
-      expect(code).toMatchSnapshot()
-    })
-    test('keyframes with fragment', () => {
-      const basic = `
-        const rotate360 = keyframes\`
-          from {
-            transform: rotate(0deg);
-          }
-          to {
-            transform: rotate(\${endingRotation});
-            @apply \${frag1}
-          }
-      \`;`
-      const { code } = babel.transform(basic, {
-        plugins: [[plugin]]
-      })
-      expect(code).toMatchSnapshot()
-    })
-  })
-  describe('extract', () => {
-    test('keyframes basic', () => {
-      const basic = `
-        const rotate360 = keyframes\`
-          from {
-            transform: rotate(0deg);
-          }
-        
-          to {
-            transform: rotate(360deg);
-          }
-      \`;`
-      const { code } = babel.transform(basic, {
-        plugins: [[plugin]],
-        babelrc: false,
-        filename: __filename
-      })
-      expect(code).toMatchSnapshot()
-      expect(fs.writeFileSync).toHaveBeenCalledTimes(1)
-      expect(fs.writeFileSync.mock.calls[0][1]).toMatchSnapshot()
-    })
-    test('keyframes with interpolation', () => {
-      const basic = `
-        const rotate360 = keyframes\`
-          from {
-            transform: rotate(0deg);
-          }
-        
-          to {
-            transform: rotate(\${endingRotation});
-          }
-      \`;`
-      const { code } = babel.transform(basic, {
-        plugins: [[plugin]],
-        babelrc: false,
-        filename: __filename
-      })
-      expect(code).toMatchSnapshot()
-      expect(fs.writeFileSync).toHaveBeenCalledTimes(1)
-    })
-  })
-})
diff --git a/test/extract/__snapshots__/extract.test.js.snap b/test/extract/__snapshots__/extract.test.js.snap
index 4c675095..8b05ad3a 100644
--- a/test/extract/__snapshots__/extract.test.js.snap
+++ b/test/extract/__snapshots__/extract.test.js.snap
@@ -13,12 +13,12 @@ exports[`styled attr 1`] = `
 `;
 
 exports[`styled basic render 1`] = `
-.vars-v8l2zy {
-  --css-H1-8xpzga-0: 20;
+.vars-fnvbv0 {
+  --css-H1-13wdnau-0: 20;
 }
 
 <h1
-  className="css-H1-8xpzga vars-v8l2zy"
+  className="css-H1-13wdnau vars-fnvbv0"
 >
   hello world
 </h1>
@@ -118,15 +118,15 @@ exports[`styled name 1`] = `
 
 exports[`styled no dynamic 1`] = `
 <h1
-  className="css-H1-ijh7uz"
+  className="css-H1-dae0kw"
 >
   hello world
 </h1>
 `;
 
 exports[`styled writes the correct css 1`] = `
-".css-H1-ijh7uz { font-size: 12px; }
-.css-H1-8xpzga { font-size: var(--css-H1-8xpzga-0)px; }
+".css-H1-dae0kw { font-size: 12px; }
+.css-H1-13wdnau { font-size: var(--css-H1-13wdnau-0)px; }
 .css-FancyH1-1azfbv1 {
       font-size: var(--css-FancyH1-1azfbv1-0)px; }
 .css-H1-15vt02v { font-size: var(--css-H1-15vt02v-0);
@@ -137,8 +137,5 @@ exports[`styled writes the correct css 1`] = `
 .css-H1-13wdnau { font-size: var(--css-H1-13wdnau-0)px; }
 .css-H2-vxb7tq { font-size: var(--css-H2-vxb7tq-0) }
 .css-H2-idm3bz { font-size: 32px; }
-.css-Content-13wdnau { font-size: var(--css-Content-13wdnau-0)px; }
-html {
-        background: pink;
-      }"
+.css-Content-13wdnau { font-size: var(--css-Content-13wdnau-0)px; }"
 `;
diff --git a/test/extract/extract.test.emotion.css b/test/extract/extract.test.emotion.css
index 90ce6709..c5edd5bb 100644
--- a/test/extract/extract.test.emotion.css
+++ b/test/extract/extract.test.emotion.css
@@ -1,5 +1,5 @@
-.css-H1-ijh7uz { font-size: 12px; }
-.css-H1-8xpzga { font-size: var(--css-H1-8xpzga-0)px; }
+.css-H1-dae0kw { font-size: 12px; }
+.css-H1-13wdnau { font-size: var(--css-H1-13wdnau-0)px; }
 .css-FancyH1-1azfbv1 {
       font-size: var(--css-FancyH1-1azfbv1-0)px; }
 .css-H1-15vt02v { font-size: var(--css-H1-15vt02v-0);
@@ -10,7 +10,4 @@
 .css-H1-13wdnau { font-size: var(--css-H1-13wdnau-0)px; }
 .css-H2-vxb7tq { font-size: var(--css-H2-vxb7tq-0) }
 .css-H2-idm3bz { font-size: 32px; }
-.css-Content-13wdnau { font-size: var(--css-Content-13wdnau-0)px; }
-html {
-        background: pink;
-      }
\ No newline at end of file
+.css-Content-13wdnau { font-size: var(--css-Content-13wdnau-0)px; }
\ No newline at end of file
diff --git a/test/extract/extract.test.js b/test/extract/extract.test.js
index e9270bfe..b30ef176 100644
--- a/test/extract/extract.test.js
+++ b/test/extract/extract.test.js
@@ -4,7 +4,9 @@ import React from 'react'
 import renderer from 'react-test-renderer'
 import { basename } from 'path'
 import { matcher, serializer } from '../../jest-utils'
-import { fragment, injectGlobal } from '../../src/index'
+
+// eslint-disable-next-line no-unused-vars
+import css, { fragment } from '../../src/index'
 import styled from '../../src/styled'
 
 expect.addSnapshotSerializer(serializer)
@@ -12,18 +14,34 @@ expect.extend(matcher)
 
 describe('styled', () => {
   test('no dynamic', () => {
-    const H1 = styled.h1`font-size: 12px;`
+    const H1 = styled.h1`
+      font-size: 12px;
+    `
 
-    const tree = renderer.create(<H1>hello world</H1>).toJSON()
+    const tree = renderer
+      .create(
+        <H1>
+          hello world
+        </H1>
+      )
+      .toJSON()
 
     expect(tree).toMatchSnapshotWithEmotion()
   })
 
   test('basic render', () => {
     const fontSize = 20
-    const H1 = styled.h1`font-size: ${fontSize}px;`
+    const H1 = styled.h1`
+      font-size: ${fontSize}px;
+    `
 
-    const tree = renderer.create(<H1>hello world</H1>).toJSON()
+    const tree = renderer
+      .create(
+        <H1>
+          hello world
+        </H1>
+      )
+      .toJSON()
 
     expect(tree).toMatchSnapshotWithEmotion()
   })
@@ -35,7 +53,13 @@ describe('styled', () => {
       font-size: ${fontSize}px;
     `
 
-    const tree = renderer.create(<H1>hello world</H1>).toJSON()
+    const tree = renderer
+      .create(
+        <H1>
+          hello world
+        </H1>
+      )
+      .toJSON()
 
     expect(tree).toMatchSnapshotWithEmotion()
   })
@@ -66,7 +90,11 @@ describe('styled', () => {
     `
 
     const tree = renderer
-      .create(<H1 className={'legacy__class'}>hello world</H1>)
+      .create(
+        <H1 className={'legacy__class'}>
+          hello world
+        </H1>
+      )
       .toJSON()
 
     expect(tree).toMatchSnapshotWithEmotion()
@@ -81,7 +109,11 @@ describe('styled', () => {
     const H2 = styled(H1)`font-size: ${fontSize * 2 / 3}`
 
     const tree = renderer
-      .create(<H2 className={'legacy__class'}>hello world</H2>)
+      .create(
+        <H2 className={'legacy__class'}>
+          hello world
+        </H2>
+      )
       .toJSON()
 
     expect(tree).toMatchSnapshotWithEmotion()
@@ -166,13 +198,6 @@ describe('styled', () => {
 
     expect(tree).toMatchSnapshotWithEmotion()
   })
-  test('injectGlobal', () => {
-    injectGlobal`
-      html {
-        background: pink;
-      }
-    `
-  })
   test('writes the correct css', () => {
     const filenameArr = basename(__filename).split('.')
     filenameArr.pop()
diff --git a/test/font-face.test.js b/test/font-face.test.js
index e6ad8ea5..134a2dac 100644
--- a/test/font-face.test.js
+++ b/test/font-face.test.js
@@ -1,8 +1,18 @@
+/* eslint-disable jsx-quotes,no-useless-escape,no-template-curly-in-string */
 /* eslint-env jest */
-import { sheet, fontFace } from '../src/index'
+import React from 'react'
+import renderer from 'react-test-renderer'
+import { matcher, serializer } from '../jest-utils'
 
-describe('font-face', () => {
-  test('adds font-face to sheet', () => {
+// eslint-disable-next-line no-unused-vars
+import css, { sheet, fragment, fontFace } from '../src/index'
+
+expect.addSnapshotSerializer(serializer)
+expect.extend(matcher)
+
+// This does nothing
+describe.skip('font-face', () => {
+  test('adds font-face to sheet', done => {
     fontFace`
       font-family: 'Patrick Hand SC';
       font-style: normal;
@@ -10,21 +20,7 @@ describe('font-face', () => {
       src: local('Patrick Hand SC'), local('PatrickHandSC-Regular'), url(https://fonts.gstatic.com/s/patrickhandsc/v4/OYFWCgfCR-7uHIovjUZXsZ71Uis0Qeb9Gqo8IZV7ckE.woff2) format('woff2');
       unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
     `
-    expect(
-      sheet.tags.map(tag => tag.textContent || '').join('')
-    ).toMatchSnapshot()
-  })
-  test('adds font-face to sheet with interpolation', () => {
-    const fontFamilyName = 'MyHelvetica'
-    fontFace`
-      font-family: ${fontFamilyName};
-      src: local("Helvetica Neue Bold"),
-          local("HelveticaNeue-Bold"),
-          url(MgOpenModernaBold.ttf);
-      font-weight: bold;
-    `
-    expect(
-      sheet.tags.map(tag => tag.textContent || '').join('')
-    ).toMatchSnapshot()
+    // console.log(sheet.rules())
+    expect(sheet).toMatchSnapshot()
   })
 })
diff --git a/test/inject-global.test.js b/test/inject-global.test.js
deleted file mode 100644
index 3aa459f6..00000000
--- a/test/inject-global.test.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/* eslint-env jest */
-import { injectGlobal, sheet, fragment } from '../src/index'
-
-test('injectGlobal', () => {
-  injectGlobal`
-    html {
-      background: pink;
-    }
-  `
-  const bodyStyles = fragment`
-    margin: 0;
-    padding: 0;
-  `
-  const color = 'yellow'
-  injectGlobal`
-    body {
-      color: ${color}
-      @apply ${bodyStyles}
-    }
-  `
-  expect(
-    sheet.tags.map(tag => tag.textContent || '').join('')
-  ).toMatchSnapshot()
-})
diff --git a/test/keyframes.test.js b/test/keyframes.test.js
index 547fb81c..bbfa41bb 100644
--- a/test/keyframes.test.js
+++ b/test/keyframes.test.js
@@ -1,8 +1,11 @@
+/* eslint-disable jsx-quotes,no-useless-escape,no-template-curly-in-string */
 /* eslint-env jest */
 import React from 'react'
 import renderer from 'react-test-renderer'
 import { matcher, serializer } from '../jest-utils'
-import { keyframes, sheet } from '../src/index'
+
+// eslint-disable-next-line no-unused-vars
+import css, { fragment, keyframes } from '../src/index'
 import styled from '../src/styled'
 
 expect.addSnapshotSerializer(serializer)
@@ -37,23 +40,14 @@ describe('keyframes', () => {
       animation: ${bounce} 2s linear infinite;
     `
 
-    const tree = renderer.create(<H1>hello world</H1>).toJSON()
+    const tree = renderer
+      .create(
+        <H1>
+          hello world
+        </H1>
+      )
+      .toJSON()
 
     expect(tree).toMatchSnapshotWithEmotion()
   })
-  test('keyframes with interpolation', () => {
-    const endingRotation = '360deg'
-    keyframes`
-      from {
-        transform: rotate(0deg);
-      }
-    
-      to {
-        transform: rotate(${endingRotation});
-      }
-    `
-    expect(
-      sheet.tags.map(tag => tag.textContent || '').join('')
-    ).toMatchSnapshot()
-  })
 })
diff --git a/test/styled.test.js b/test/styled.test.js
index fce76e52..278ddc01 100644
--- a/test/styled.test.js
+++ b/test/styled.test.js
@@ -13,18 +13,34 @@ expect.extend(matcher)
 
 describe('styled', () => {
   test('no dynamic', () => {
-    const H1 = styled.h1`font-size: 12px;`
+    const H1 = styled.h1`
+      font-size: 12px;
+    `
 
-    const tree = renderer.create(<H1>hello world</H1>).toJSON()
+    const tree = renderer
+      .create(
+        <H1>
+          hello world
+        </H1>
+      )
+      .toJSON()
 
     expect(tree).toMatchSnapshotWithEmotion()
   })
 
   test('basic render', () => {
     const fontSize = 20
-    const H1 = styled.h1`font-size: ${fontSize}px;`
+    const H1 = styled.h1`
+      font-size: ${fontSize}px;
+    `
 
-    const tree = renderer.create(<H1>hello world</H1>).toJSON()
+    const tree = renderer
+      .create(
+        <H1>
+          hello world
+        </H1>
+      )
+      .toJSON()
 
     expect(tree).toMatchSnapshotWithEmotion()
   })
@@ -36,7 +52,13 @@ describe('styled', () => {
       font-size: ${fontSize}px;
     `
 
-    const tree = renderer.create(<H1>hello world</H1>).toJSON()
+    const tree = renderer
+      .create(
+        <H1>
+          hello world
+        </H1>
+      )
+      .toJSON()
 
     expect(tree).toMatchSnapshotWithEmotion()
   })
@@ -67,7 +89,11 @@ describe('styled', () => {
     `
 
     const tree = renderer
-      .create(<H1 className={'legacy__class'}>hello world</H1>)
+      .create(
+        <H1 className={'legacy__class'}>
+          hello world
+        </H1>
+      )
       .toJSON()
 
     expect(tree).toMatchSnapshotWithEmotion()
@@ -82,7 +108,11 @@ describe('styled', () => {
     const H2 = styled(H1)`font-size: ${fontSize * 2 / 3}`
 
     const tree = renderer
-      .create(<H2 className={'legacy__class'}>hello world</H2>)
+      .create(
+        <H2 className={'legacy__class'}>
+          hello world
+        </H2>
+      )
       .toJSON()
 
     expect(tree).toMatchSnapshotWithEmotion()
@@ -137,6 +167,25 @@ describe('styled', () => {
     expect(tree).toMatchSnapshotWithEmotion()
   })
 
+  test('innerRef', () => {
+    const H1 = styled.h1`
+      font-size: 12px;
+    `
+
+    const refFunction = jest.fn()
+
+    const tree = renderer
+      .create(
+        <H1 innerRef={refFunction}>
+          hello world
+        </H1>
+      )
+      .toJSON()
+
+    expect(tree).toMatchSnapshotWithEmotion()
+    expect(refFunction).toBeCalled()
+  })
+
   test('higher order component', () => {
     const fontSize = 20
     const Content = styled('div')`
@@ -167,9 +216,4 @@ describe('styled', () => {
 
     expect(tree).toMatchSnapshotWithEmotion()
   })
-  test('throws if undefined is passed as the component', () => {
-    expect(
-      () => styled(undefined)`display: flex;`
-    ).toThrowErrorMatchingSnapshot()
-  })
 })