Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unit test component examples? #183

Open
frankandrobot opened this issue Dec 28, 2017 · 3 comments
Open

Unit test component examples? #183

frankandrobot opened this issue Dec 28, 2017 · 3 comments

Comments

@frankandrobot
Copy link

frankandrobot commented Dec 28, 2017

Have you guys had any luck unit testing components? (See for example, https://puigcerber.com/2016/02/07/how-to-test-angular-1-5-components/)

I've currently configured angular 1.5, ngtemplate-loader, and webpack to load the HTML partials correctly in karma but tests are erring out with the following ngRedux error:

	_iterator is undefined
	ngReduxProvider/this.$get@webpack:///~/ng-redux/lib/components/ngRedux.js:57:0 <- test.webpack.js:148525:85
	invoke@webpack:///~/angular/angular.js:4771:0 <- test.webpack.js:81782:16

Update: oh wait, I probably have to configure ngRedux in tests as well (doh)

@frankandrobot frankandrobot changed the title Unit test examples? Unit test component examples? Dec 28, 2017
@AntJanus
Copy link
Collaborator

AntJanus commented Dec 28, 2017

Let us know how that works out!

If you're testing redux, I'd make sure to do unit tests on the reducers themselves. It's easier but it's also way more robust.

@frankandrobot
Copy link
Author

frankandrobot commented Dec 28, 2017

Yea i got this working. Unfortunately, there's no code to share because it's closed source :( but here's an overview of what needs to happen:

  1. First do you really need to unit test the template? In our case, the template (in particular, the underlying angular form) had a lot of state that needed to be tested. This is difficult to test in controller/reducer tests because we mainly let Angular forms do their own thing (even though we use redux and one-way data binding---the culprits here are validators).
  2. Use ngtemplate-loader and html-loader to make webpack load the templates. The ngtemplate-loader instructions worked.
  3. Setup ngRedux by creating a throwaway module in the tests
  4. Load ngRedux into the tests by using angular mock to load the throwaway module from step 3
  5. Load the component-under-test by using angular mock
  6. Proceed to test the template by following https://puigcerber.com/2016/02/07/how-to-test-angular-1-5-components/)

Here's a minimal test example that uses karma and mocha:

import 'angularMocks';
import angular from 'angular';
import 'ng-redux';

import appReducers from '../../reducers';
import './user-completion.component';
import '../../app';

// Setup angular. Note that we need a working ngRedux for the template tests
angular.module('testConnect', ['ngRedux']).config([
  '$ngReduxProvider',
  function($ngReduxProvider) {
    $ngReduxProvider.createStoreWith(appReducers, []);
  },
]);
describe.only('component', function() {
  let ngRedux;

  beforeEach(angular.mock.module('testConnect'));
  beforeEach(angular.mock.module('componentUnderTest'));
  beforeEach(angular.mock.inject(function($ngRedux) {
    ngRedux = $ngRedux;
  }));

  describe('with $compile', function() {
    let element;
    let scope;

    beforeEach(
      angular.mock.inject(function($rootScope, $compile) {
        scope = $rootScope.$new();
        element = angular.element('<component-under-test></component-under-test>');
        element = $compile(element)(scope);
        scope.$apply();
      })
    );

    it('should show missing username', function() {
      ngRedux.dispatch(updateState({
        missing: {
          username: true,
          email: false,
        },
      }));
      scope.$apply();
      const result = element.html().toString();
      expect(result).to.match(/Username/);
    });
  });
});

@frankandrobot
Copy link
Author

frankandrobot commented Dec 28, 2017

One of the things that I noticed, however, is that it's not obvious how to do fuller integration tests i.e., a test where everything is real except for AJAX requests. In our code base we are already doing this when testing sagas. Unfortunately, for this to work we use redux-mock-store-middleware which allows a fully working store with getActions and resetActions functionality (needed for testing).

So... to make these types of integration tests work with templates, we need the ngRedux magic of reduxifying angular components and the redux-mock-store-middleware functionality. Hmm.... since it is middleware, I could probably still use it. However, our tests recreate the store on each test (that means we get a fresh copy of the redux state each test)... I don't see an obvious way of doing that (meaning tests won't be independent).

Update: I suppose there's this: https://stackoverflow.com/questions/35622588/how-to-reset-the-state-of-a-redux-store/35641992#35641992 The downside is that tests start to get a lot of boilerplate

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants