dvdzkwsk / react-redux-starter-kit

Get started with React, Redux, and React-Router.
MIT License
10.29k stars 2.21k forks source link

proxyquire in tests erroring #563

Closed Exegetech closed 8 years ago

Exegetech commented 8 years ago

I tried to add proxyquire in one of the spec file but it gives this error

PhantomJS 2.1.1 (Mac OS X 0.0.0) ERROR
  Error: Cannot find module "module"
  at /Users/christiansakai/Desktop/fullstack-react-redux-starter-kit/tests/test-bundler.js:45586 <- webpack:///~/proxyquire/lib/proxyquire.js:5:0

any idea why?

kevinchiu commented 8 years ago

Can you post the spec file?

Exegetech commented 8 years ago

This is using the counter.spec.js, I just added import proxquire on top and the test fails

import proxyquire from 'proxyquire';
import {
  COUNTER_INCREMENT,
  increment,
  doubleAsync,
  default as counterReducer
} from 'redux/modules/counter'

describe('(Redux Module) Counter', function () {
  it('Should export a constant COUNTER_INCREMENT.', function () {
    expect(COUNTER_INCREMENT).to.equal('COUNTER_INCREMENT')
  })

  describe('(Reducer)', function () {
    it('Should be a function.', function () {
      expect(counterReducer).to.be.a('function')
    })

    it('Should initialize with a state of 0 (Number).', function () {
      expect(counterReducer(undefined, {})).to.equal(0)
    })

    it('Should return the previous state if an action was not matched.', function () {
      let state = counterReducer(undefined, {})
      expect(state).to.equal(0)
      state = counterReducer(state, {type: '@@@@@@@'})
      expect(state).to.equal(0)
      state = counterReducer(state, increment(5))
      expect(state).to.equal(5)
      state = counterReducer(state, {type: '@@@@@@@'})
      expect(state).to.equal(5)
    })
  })

  describe('(Action Creator) increment', function () {
    it('Should be exported as a function.', function () {
      expect(increment).to.be.a('function')
    })

    it('Should return an action with type "COUNTER_INCREMENT".', function () {
      expect(increment()).to.have.property('type', COUNTER_INCREMENT)
    })

    it('Should assign the first argument to the "payload" property.', function () {
      expect(increment(5)).to.have.property('payload', 5)
    })

    it('Should default the "payload" property to 1 if not provided.', function () {
      expect(increment()).to.have.property('payload', 1)
    })
  })

  describe('(Action Creator) doubleAsync', function () {
    let _globalState
    let _dispatchSpy
    let _getStateSpy

    beforeEach(function () {
      _globalState = {
        counter: counterReducer(undefined, {})
      }
      _dispatchSpy = sinon.spy((action) => {
        _globalState = {
          ..._globalState,
          counter: counterReducer(_globalState.counter, action)
        }
      })
      _getStateSpy = sinon.spy(() => {
        return _globalState
      })
    })

    it('Should be exported as a function.', function () {
      expect(doubleAsync).to.be.a('function')
    })

    it('Should return a function (is a thunk).', function () {
      expect(doubleAsync()).to.be.a('function')
    })

    it('Should return a promise from that thunk that gets fulfilled.', function () {
      return doubleAsync()(_dispatchSpy, _getStateSpy).should.eventually.be.fulfilled
    })

    it('Should call dispatch and getState exactly once.', function () {
      return doubleAsync()(_dispatchSpy, _getStateSpy)
        .then(() => {
          _dispatchSpy.should.have.been.calledOnce
          _getStateSpy.should.have.been.calledOnce
        })
    })

    it('Should produce a state that is double the previous state.', function () {
      _globalState = { counter: 2 }

      return doubleAsync()(_dispatchSpy, _getStateSpy)
        .then(() => {
          _dispatchSpy.should.have.been.calledOnce
          _getStateSpy.should.have.been.calledOnce
          expect(_globalState.counter).to.equal(4)
          return doubleAsync()(_dispatchSpy, _getStateSpy)
        })
        .then(() => {
          _dispatchSpy.should.have.been.calledTwice
          _getStateSpy.should.have.been.calledTwice
          expect(_globalState.counter).to.equal(8)
        })
    })
  })

  // NOTE: if you have a more complex state, you will probably want to verify
  // that you did not mutate the state. In this case our state is just a number
  // (which cannot be mutated).
  describe('(Action Handler) COUNTER_INCREMENT', function () {
    it('Should increment the state by the action payload\'s "value" property.', function () {
      let state = counterReducer(undefined, {})
      expect(state).to.equal(0)
      state = counterReducer(state, increment(1))
      expect(state).to.equal(1)
      state = counterReducer(state, increment(2))
      expect(state).to.equal(3)
      state = counterReducer(state, increment(-3))
      expect(state).to.equal(0)
    })
  })
})
dvdzkwsk commented 8 years ago

I've never used proxyquire, but looking at the repo on Github it looks like it's for NodeJS. Your tests are being run in a headless browser (PhantomJS) and not a Node environment, so my first instinct is that it's related to that. See: https://github.com/thlorenz/proxyquire/blob/master/lib/proxyquire.js#L5

Exegetech commented 8 years ago

@davezuko makes sense! thanks, I'll close the issue

Exegetech commented 8 years ago

@davezuko I have a question. I want to implement the server's API with testings. What are the best approach in doing so? I will be using stuffs like supertest and proxyquire sometimes to mock the dependencies.

Looking at your tests structure, you are using PhantomJS. What is the role of PhantomJs here? It seems without PhantomJs, the regular redux/react/enzyme tests will run just fine

I do will use all of testing framework that this repo have been using (chai, mocha, sinon, chai-as-promised) so I want to use the test-bundler.

dvdzkwsk commented 8 years ago

PhantomJS is there to simulate a real browser environment, so you know whether your application works as expected in that environment.

The application is currently not setup for server tests, but it's far less work to setup tests for code that only needs Node. You'd want to run mocha directly against the server tests (maybe put them in tests/server, and then update the test-bundler to exclude that directory, or similarly nest client tests in something like tests/client).

Exegetech commented 8 years ago

Thanks @davezuko. Ok so I'll run mocha directly against server test. Thanks!