solved: css modules support in wallaby #924

Closed
cellog opened this Issue Dec 29, 2016 · 3 comments

Projects

None yet

2 participants

@cellog
cellog commented Dec 29, 2016 edited

Issue description or question

This is not a bug report, it is reporting a quick and clever way to solve a problem I had, encouraging you to share it with other users in the docs.

You might remember I have been struggling with CSS modules support, because one of my testing dependencies just plain doesn't work in the web environment. I just figured out a clever way to make it work, with this simple preprocessor:

  const next = require('postcss-cssnext')
  const modules = require('postcss-modules')
  const postcss = require('postcss')

  const processCss = function(file, done) {
    postcss([
      next,
      modules({
        getJSON: function(filename, json) {
          file.rename(file.path + '.json')
          done(JSON.stringify(json))
        }
      })
    ]).process(file.content, {
      from: file.path,
      to: file.path
    }).catch(function(err) {
      throw err
    })
  }

and then preprocessors like so:

    preprocessors: {
      'src/**/*.css': processCss,
    },

This then allows referencing styles in the tests, like so:

import styles from '../../../src/modules/main/components/App.css'
...
  describe("month chooser", () => {
    it('displays selected month 1', () => {
      component = renderComponent(App, {
        ...genericApp,
        currentYear: 2014,
        years: [2013, 2014, 2015],
        startMonth: 5
      })
      expect(component.find('#june-button').props('className')).eqls(`selected-month ${styles.selectedButton}`)
      expect(component.find('#july-button').props('className')).eqls(styles.button)
    })
  })

Wallaby.js configuration file

module.exports = function(wallaby) {
  const next = require('postcss-cssnext')
  const modules = require('postcss-modules')
  const postcss = require('postcss')

  const processCss = function(file, done) {
    postcss([
      next,
      modules({
        getJSON: function(filename, json) {
          file.rename(file.path + '.json')
          done(JSON.stringify(json))
        }
      })
    ]).process(file.content, {
      from: file.path,
      to: file.path
    }).catch(function(err) {
      throw err
    })
  }

  return {
    files: [
      'test/test_helper.js',
      { pattern: 'test/**/*.test.js', ignore: true },
      { pattern: 'test/karma/*', ignore: true, instrument: false },
      'src/**/*.js*',
      'src/**/*.css',
      'style/**/*.css',
      { pattern: 'src/.stories/**/*.*', ignore: true, instrument: false },
      { pattern: 'src/index.js', ignore: true, instrument: false },
      { pattern: 'config.js'},
      { pattern: 'config/coaches.js'},
    ],
    filesWithNoCoverageCalculated: ['test/test_helper.js', '*.css'],
    tests: [
      { pattern: 'node_modules/*', ignore: true, instrument: false },
      { pattern: 'test/karma/*', ignore: true, instrument: false },
      'test/**/*.test.js*'
    ],
    preprocessors: {
      'src/**/*.css': processCss,
      'style/**/*.css': processCss
    },
    compilers: {
      '**/*.js?(x)': wallaby.compilers.babel({
        babel: require('babel-core'),
        presets: ['es2015', 'stage-0', 'react']
      }),
    },
    env: {
      type: 'node'
    },
    testFramework: 'mocha',
    setup: function() {
      const jsdom = require('jsdom').jsdom
      const sinon = require('sinon')
      const chai = require('chai')
      const expect = chai.expect
      const $ = require('jquery')
      const chaiJquery = require('chai-jquery')
      require('babel-polyfill')

// from mocha-jsdom https://github.com/rstacruz/mocha-jsdom/blob/master/index.js#L80
      const propagateToGlobal = (window) => {
        for (var key in window) {
          if (!window.hasOwnProperty(key)) continue
          if (key in global) continue

          global[key] = window[key]
        }
      }

// setup the simplest document possible
      const doc = jsdom('')
      const win = doc.defaultView
      global.document = doc
      global.window = win
      global.sinon = sinon
      global.expect = expect
      global.chai = chai
      global.$ = $(win)

      propagateToGlobal(win)
      global.window.____isjsdom = true
    },
    debug: true
  };
};

Code editor or IDE name and version

n/a

OS name and version

n/a

@cellog
cellog commented Dec 29, 2016

one caveat: it leaves the .json files hanging around. Is there a simple way to remove them? A post-processor?

@cellog
cellog commented Dec 29, 2016

final note: the .css.json files were generated by postcss-modules. I solved it with this corrected preprocessor (will edit the original bug report with it)

  const processCss = function(file, done) {
    postcss([
      next,
      modules({
        getJSON: function(filename, json) {
          file.rename(file.path + '.json')
          done(JSON.stringify(json))
        }
      })
    ]).process(file.content, {
      from: file.path,
      to: file.path
    }).catch(function(err) {
      throw err
    })
  }
@ArtemGovorov
Member

Great, thanks heaps for sharing it! Have added the recipe to our docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment