Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS design guide

Previously when I was writing angular apps, I used to do

angular.module('ngApp', ['all', 'required', 'ng*', 'dependencies'])

in my app.js and then inside services/ and controllers, I could simply do:

angular.module('ngApp')

I have a repo to demonstrate that.

But then I saw the angular-seed/, the way implemented was,

in controllers/

angular.module('appControllers', ['dependencies'])...

in services/

angular.module('appServices', ['dependencies'])..

in app.js

angular.module('ngApp', ['ng*', 'appControllers', 'appSrvices'])..

I had no issue with design, infact I thought it was good, since evrything was dependency injected as well as modular.

I have a situation where I have a services/movie.js that has

angular.module('myAppServices', ['ngResource']).factory(..)

and services/config.js

angular.module('myAppServices').factory(..)

But while writing tests with karma and jasmine. In the karma.conf.js,

I had files: ['usual', 'bower_components/angular-*.js', 'app/services/**/*.js', '..']

but the problem was config.js got loaded before movie.js and there were errors, myAppServices is not loaded or mis-spelt.

The way I fixed it was I did:

files: ['..', 'app/services/movie.js', 'app/services/config.js']

I have set up a github repo for this too. Here is the controller test file and here is the karma.conf.

I want to know what can be the possible approaches to take such modular approach, without having to specify the order in which the files are to be loaded for my tests.

And this is my first unit test, and its failing:

Error: Unexpected request: GET https://api.themoviedb.org/3/configuration?api_key=2e329c92227ed8be07944ae447c9426f
Expected GET https://api.themoviedb.org/3/movie/top_rated?api_key=2e329c92227ed8be07944ae447c9426f

It would be helpful if I could get some help in fixing that too.

The test

describe('Controllers', function() {

  beforeEach(module('myApp'));
  beforeEach(module('myAppServices'));

  describe("MoviesCtrl", function() {
    var scope, ctrl, httpBackend;

    beforeEach(inject(function($httpBackend, $rootScope, _$controller_, Movie, Config) {
      httpBackend = $httpBackend;
      ctrl = _$controller_;
      scope = $rootScope.$new();
    }));

    it("should return a list of movies", function() {
      var data = {results: [{name: "Abc"}, {name: "Def"}]};

      httpBackend.
        expectGET("https://api.themoviedb.org/3/movie/top_rated?api_key=2e329c92227ed8be07944ae447c9426f").
        respond(data);
      ctrl('MoviesCtrl', { $scope: scope });
      httpBackend.flush()
      expect(scope.image).toEqual("https://api.themoviedb.org/3/");
    });
  });

});

conf. file

module.exports = function(config) {
  config.set({
    basePath: './',

    frameworks: ['jasmine'],

    files: [
      'app/bower_components/angular/angular.js',
      'app/bower_components/angular-mocks/angular-mocks.js',
      'app/bower_components/angular-resource/angular-resource.js',
      'app/bower_components/angular-route/angular-route.js',
      'app/services/movie.js',
      'app/services/config.js',
      'app/controllers/*.js',
      'app/app.js',
      'unit-tests/**/*.js'
    ],

    exclude: [
      'app/**/*.min.js'
    ],

    preprocessors: {
    },

    reporters: ['progress'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['Chrome'],
    singleRun: false
  });
};

UPDATE

I have figured out the error in test, I had to mock the other http request for the configuration. thanks to @Phil.

This is my test now:

describe('Controllers', function() {
  beforeEach(module('myApp'));
  beforeEach(module('myAppServices'));

  describe("MoviesCtrl", function() {
    var scope, httpBackend;
    var config_data = { images: { base_url: "http://tmdb.com/t/p", backdrop_sizes: ["w300", "w500"]}},
        movie_data = {results: [{name: "Abc"}, {name: "Def"}]};

    beforeEach(inject(function($httpBackend, $rootScope, $controller) {
      httpBackend = $httpBackend;
      scope = $rootScope.$new();
       httpBackend.
        expectGET("https://api.themoviedb.org/3/configuration?api_key=2e329c92227ed8be07944ae447c9426f").
        respond(config_data);
      httpBackend.
        expectGET("https://api.themoviedb.org/3/movie/top_rated?api_key=2e329c92227ed8be07944ae447c9426f").
        respond(movie_data);
      $controller('MoviesCtrl', { $scope: scope });
    }));

    it("should return a list of movies", function() {
      expect(scope.image).toEqual({})

      httpBackend.flush();

      expect(scope.image.backdrop_size).toEqual("w300");
    });
  });

});

Although I am not sure if this is the right test to do :P . Something like a VCR would be helpful.

like image 481
argentum47 Avatar asked Apr 10 '15 06:04

argentum47


1 Answers

Why use two separate files for 10 lines each? The purpose of writing code in separate files is to keep it understandable and maintainable. It would make sense to keep your module 'myAppServices' in one file.

If you really need to break down your code in multiple files, you should make use of dependency injection and make them each a separate module (see my patch against your repo). Then the order of loading stops being an issue.

like image 173
Nowhere man Avatar answered Nov 22 '22 17:11

Nowhere man