77

I'm new to Mocha and I am trying to use it to test a simple React component. The test would pass if the react component doesn't have any CSS styling but throws a syntax error if the tag within the React component contains any className:

Testing.react.js

import React from 'react';

export default class Testing extends React.Component {
  render() {
    return (
      <section>
        <form>
          <input type="text" />
        </form>
      </section>
    );
  }
}

testing.jsx

import {
  React,
  sinon,
  assert,
  expect,
  TestUtils
} from '../../test_helper';

import TestingSample from '../../../app/components/Testing.react.js';

describe('TestingSample component', function(){
    before('render and locate element', function(){
        var renderedComponent = TestUtils.renderIntoDocument(
            <TestingSample />
        );

        var inputComponent = TestUtils.findRenderedDOMComponentWithTag(
            renderedComponent, 'input'
        );

        this.inputElement = inputComponent.getDOMNode();
    });

    it('<input> should be of type "text"', function () {
        assert(this.inputElement.getAttribute('type') === 'text');
    });
})

The test would pass:

> mocha --opts ./test/javascripts/mocha.opts --compilers js:babel/register --recursive test/javascripts/**/*.jsx


  TestSample component
    ✓ <input> should be of type "text"


  1 passing (44ms)

after I added the className inside of the input tag an error shows up:

import React from 'react';
import testingStyle from '../../scss/components/landing/testing.scss';

export default class Testing extends React.Component {
  render() {
    return (
      <section>
        <form>
          <input type="text" className="testingStyle.color" placeholder="Where would you like to dine" />     
        </form>
      </section>
    );
  }
}

Test result:

SyntaxError: /Users/../../../Documents/project/app/scss/components/landing/testing.scss: Unexpected token (1:0)
> 1 | .color {
    | ^
  2 |   color: red;
  3 | }

I've searched online but no luck so far. Am I missing something? Please help me out or point me to the right direction would be greatly appreciated. I'm currently using:
Node Express Server
React
React-router
Webpack
Babel
Mocha
Chai
Sinon
Sinon-Chai

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
Yi Ren
  • 841
  • 1
  • 8
  • 17

9 Answers9

155

There is a babel/register style hook to ignore style imports:

https://www.npmjs.com/package/ignore-styles

Install it:

npm install --save-dev ignore-styles

Run tests without styles:

mocha --require ignore-styles

rzueger
  • 1,707
  • 1
  • 13
  • 13
12

you can use a css compilers run mocha, the compiler js as follow:

css-dnt-compiler.js

function donothing() {
  return null;
}

require.extensions['.css'] = donothing;
require.extensions['.less'] = donothing;
require.extensions['.scss'] = donothing;
// ..etc

and run the mocha command like this:

mocha --compilers js:babel-core/register,css:css-dnt-compiler.js --recursive
zzm
  • 645
  • 1
  • 5
  • 19
  • 1
    This solution worked for me, the only thing you gotta make sure is that you include the correct path to the `css-dnt-compiler` file, so on my case I've stored it inside of the `test` folder, so the command becomes: `mocha --compilers js:babel-core/register,css:test/css-dnt-compiler.js --recursive` – Marcos Abreu Apr 19 '16 at 14:41
  • slightly more simple `require.extensions['.scss'] = ()=>null; require.extensions['.css'] = ()=>null;` but this answer was perfect – Kevin Danikowski Apr 20 '18 at 20:04
8

My same answer as here, this is what I used to get working on Babel 6

package.json

"scripts": {
  "test": "mocha --compilers js:babel-core/register 
          --require ./tools/testHelper.js 'src/**/*-spec.@(js|jsx)'",

tools/testHelper.js

// Prevent mocha from interpreting CSS @import files
function noop() {
  return null;
}

require.extensions['.css'] = noop;

This enables you to have your tests inside your src folder alongside your components. You can add as many extensions as you would like with require.extensions.

Community
  • 1
  • 1
mummybot
  • 2,668
  • 2
  • 28
  • 31
  • 1
    if `noop()` returns `{}` instead, you can also use it to mock classnames. So for example, if you used `import styles from 'my.css'`, you can set `styles.myClassName` in your test suite, and your react component that references the same CSS module will see those values. This is super useful when using class selectors in test frameworks like Enzyme – killthrush Jul 19 '16 at 13:53
  • Works good. I've moved all mocha options to mocha.opts to make scripts clean. – evgeny.myasishchev Sep 02 '16 at 06:42
4

Since you're using webpack, use null-loader to load null when webpack encounters a required CSS/LESS/SASS/etc file in your components. Install via npm and then update your webpack config to include the loader:

{
    test: /(\.css|\.less|.\scss)$/,
    loader: 'null-loader'
}

Obviously this will prevent you from loading CSS in your actual application, so you'll want to have a separate webpack config for your test bundle that uses this loader.

Jim Skerritt
  • 4,348
  • 2
  • 28
  • 25
  • I tried it, it doesn't seem to work. In addition, I noticed the error is not caused by adding className to the components. It's cause by importing css file: `import testingStyle from '../../scss/components/landing/testing.scss';` – Yi Ren Sep 06 '15 at 22:54
2

For those looking how to handle this in jest - you just add a handler for style files:

// package.json
{
  "jest": {
    "moduleNameMapper": {
      "\\.(css|less|scss|sass)$": "<rootDir>/__mocks__/styleMock.js"
    }
  }
}

// __mocks__/styleMock.js
module.exports = {};

More here.

Piotr Jaworski
  • 584
  • 1
  • 5
  • 20
1

None of these solutions worked for me, as I'm using mocha-webpack, and it doesn't accept the "--compilers" switch. I implemented the ignore-styles package, as described in the most popular answer, but it seemed inert, with no difference in my Istanbul coverage report (.less files still being tested).

The problem is the .less loader that I was using in my webpack.config.test.js file. Simply swapping less-loader for null-loader fixed my problem.

module: {
    rules: [
        {
            test: /\.less$/,
            use: ['null-loader']
        }
    ]
}

For me, this is by far the simplest solution, and targets my testing configuration directly, rather than having to alter/add to the package.json scripts, or worse, add new .js files.

Artif3x
  • 4,391
  • 1
  • 28
  • 24
  • Seems to me this is the same solution as the one posted two years ago by [Jim Skerritt](https://stackoverflow.com/a/32236924/1906307): replace your loader with `null-loader`. – Louis Jul 13 '17 at 20:00
0

One simple way is to import 'ignore-styles'; in your test classes..

0

The code below works without any dependencies. Just add it to the top of the tests.

var Module = require('module');
var originalRequire = Module.prototype.require;
Module.prototype.require = function () {
    if (arguments[0] && arguments[0].endsWith(".css"))
        return;
    return originalRequire.apply(this, arguments);
};
bert
  • 1,556
  • 13
  • 15
0

Although very old, this question is still relevant, so let me throw in another solution.

Use pirates, a package to add hooks to require() - if you use Babel, you already have it.

Example code:

// .test-init.js
const { addHook } = require('pirates');

const IGNORE_EXTENSIONS = ['.scss', '.svg', '.css'];

addHook((code, filename) => '', { exts: IGNORE_EXTENSIONS });

This way you can call mocha like so: mocha --require .test-init.js [whatever other parameters you use]

This is straightforward, elegant and unlike ignore-styles it doesn't imply you are ignoring styles only. Also, this is easily extendable if you need to apply some more trickery to your tests like mocking entire modules.

moongoal
  • 2,847
  • 22
  • 23