rofrischmann/fela

View on GitHub
packages/fela/src/__tests__/createRenderer-test.js

Summary

Maintainability
A
0 mins
Test Coverage
import createRenderer from '../createRenderer'
import cssifyKeyframeRule from '../cssifyKeyframeRule'

describe('Renderer', () => {
  describe('Instantiating a new renderer', () => {
    it('should initialize all values', () => {
      const renderer = createRenderer()

      expect(renderer.cache).toEqual({})
      expect(renderer.uniqueRuleIdentifier).toEqual(0)
      expect(renderer.uniqueKeyframeIdentifier).toEqual(0)
    })

    it('should apply enhancers directly', () => {
      const enhancer = (renderer) => {
        renderer.foo = 'bar'
        return renderer
      }
      const renderer = createRenderer({
        enhancers: [enhancer],
      })

      expect(renderer.foo).toEqual('bar')
    })
  })

  describe('Clearing a Renderer', () => {
    it('should reset all values', () => {
      const renderer = createRenderer()
      const rule = () => ({
        color: 'red',
      })

      renderer.renderRule(rule)
      renderer.clear()

      expect(renderer.cache).toEqual({})
      expect(renderer.uniqueRuleIdentifier).toEqual(0)
      expect(renderer.uniqueKeyframeIdentifier).toEqual(0)
    })
  })

  describe('Rendering rules', () => {
    it('should add a cache entry', () => {
      const rule = () => ({
        color: 'red',
      })
      const renderer = createRenderer()

      renderer.renderRule(rule)

      expect(renderer.cache.hasOwnProperty('colorred')).toEqual(true)
    })

    it('should reuse cached classNames', () => {
      const rule = (props) => ({
        color: props.color,
        fontSize: '23px',
      })
      const renderer = createRenderer()

      const className1 = renderer.renderRule(rule, {
        color: 'red',
      })
      const className2 = renderer.renderRule(rule, {
        color: 'red',
      })
      const className3 = renderer.renderRule(rule, {
        color: 'blue',
      })

      expect(className1).toEqual(className2)
      expect(className1).toMatchSnapshot()
      expect(className3).toMatchSnapshot()
    })

    it('should return an empty string if the style is empty', () => {
      const rule = () => ({})
      const renderer = createRenderer()

      const className = renderer.renderRule(rule)

      expect(className).toEqual('')
    })

    it('should allow nested props', () => {
      const rule = (props) => ({
        color: props.theme.color,
        fontSize: 15,
      })
      const renderer = createRenderer()

      const className = renderer.renderRule(rule, {
        theme: {
          color: 'red',
        },
      })

      expect(className).toMatchSnapshot()
    })

    it('should add use the propertyPriority config', () => {
      const rule = () => ({
        color: 'red',
      })

      const renderer = createRenderer({
        propertyPriority: {
          color: 2,
        },
      })

      renderer.renderRule(rule)

      expect(renderer.cache.colorred.selector).toEqual('.a.a')
    })

    it('should render css custom properties', () => {
      const rule = () => ({
        '--custom-property': '12px',
      })

      const renderer = createRenderer()
      renderer.renderRule(rule)

      expect(renderer.cache).toMatchSnapshot()
    })
  })

  describe('Rendering keyframes', () => {
    it('should add a cache entry', () => {
      const keyframe = () => ({
        from: {
          color: 'red',
        },
        to: {
          color: 'blue',
        },
      })

      const renderer = createRenderer()

      renderer.renderKeyframe(keyframe)

      expect(
        renderer.cache.hasOwnProperty(cssifyKeyframeRule(keyframe()))
      ).toEqual(true)
    })

    it('should return a valid animation name', () => {
      const keyframe = () => ({
        from: {
          color: 'red',
        },
        to: {
          color: 'blue',
        },
      })

      const renderer = createRenderer()
      const animationName = renderer.renderKeyframe(keyframe)

      expect(animationName).toMatchSnapshot()
    })
  })

  describe('Rendering Fonts', () => {
    it('should cache the font-face', () => {
      const renderer = createRenderer()
      const family = 'Arial'
      const properties = {
        fontWeight: 300,
      }

      renderer.renderFont(
        family,
        ['../fonts/Arial.ttf', '../fonts/Arial.woff'],
        properties
      )

      const key = family + JSON.stringify(properties)
      expect(renderer.cache.hasOwnProperty(key)).toEqual(true)
    })

    it('should return the font family', () => {
      const renderer = createRenderer()

      const family = renderer.renderFont(
        'Arial',
        ['../fonts/Arial.ttf', '../fonts/Arial.woff'],
        {
          fontWeight: 300,
        }
      )

      expect(family).toEqual('"Arial"')
    })
    it('should return the font family when localAlias is provided as string', () => {
      const renderer = createRenderer()

      const family = renderer.renderFont(
        'Arial',
        ['../fonts/Arial.ttf', '../fonts/Arial.woff'],
        {
          localAlias: 'Arial',
          fontWeight: 300,
        }
      )

      expect(family).toEqual('"Arial"')
    })
    it('should return the font family when localAlias provided as array', () => {
      const renderer = createRenderer()

      const family = renderer.renderFont(
        'Arial',
        ['../fonts/Arial.ttf', '../fonts/Arial.woff'],
        {
          localAlias: ['Arial', 'Arial-Regular'],
          fontWeight: 300,
        }
      )

      expect(family).toEqual('"Arial"')
    })
    it('should create a valid src list', () => {
      const renderer = createRenderer()
      const family = 'Arial'
      const properties = {}

      renderer.renderFont(
        family,
        ['../fonts/Arial.ttf', '../fonts/Arial.woff'],
        properties
      )

      const key = family + JSON.stringify(properties)
      const src = renderer.cache[key].fontFace.match(/.*(src:.*);.*$/)[1]
      expect(src).toEqual(
        "src:url('../fonts/Arial.ttf') format('truetype'),url('../fonts/Arial.woff') format('woff')"
      )
    })
  })

  describe('Subscribing to the Renderer', () => {
    it('should call the callback each time it emits changes', () => {
      const rule = () => ({
        color: 'red',
        '@media (min-height: 300px)': {
          color: 'blue',
        },
      })

      const renderer = createRenderer()
      const subscriber = jest.fn()
      renderer.subscribe(subscriber)
      renderer.renderRule(rule)

      expect(subscriber).toHaveBeenCalledTimes(2)
    })

    it('should call the callback with a change object', () => {
      const rule = () => ({
        color: 'red',
        '@media (min-height: 300px)': {
          color: 'blue',
        },
      })

      const renderer = createRenderer()

      const changes = []
      const subscriber = (change) => changes.push(change)

      renderer.subscribe(subscriber)
      renderer.renderRule(rule)

      expect(changes).toMatchSnapshot()
    })

    it('should return a unsubscribe method', () => {
      const renderer = createRenderer()
      const subscriber = () => {}

      const unsubscriber = renderer.subscribe(subscriber)
      unsubscriber.unsubscribe()

      expect(unsubscriber.unsubscribe).toBeInstanceOf(Function)
      expect(renderer.listeners.length).toEqual(0)
    })
  })
})