'use strict';

(function () {
  // InfrastructureRequests Controller Spec
  describe('InfrastructureRequests Controller Tests', function () {
    // Initialize global variables
    var InfrastructureRequestsController,
      scope,
      $httpBackend,
      $stateParams,
      $location,
      Authentication,
      InfrastructureRequests,
      mockInfrastructureRequest;

    // The $resource service augments the response object with methods for updating and deleting the resource.
    // If we were to use the standard toEqual matcher, our tests would fail because the test values would not match
    // the responses exactly. To solve the problem, we define a new toEqualData Jasmine matcher.
    // When the toEqualData matcher compares two objects, it takes only object properties into
    // account and ignores methods.
    beforeEach(function () {
      jasmine.addMatchers({
        toEqualData: function (util, customEqualityTesters) {
          return {
            compare: function (actual, expected) {
              return {
                pass: angular.equals(actual, expected)
              };
            }
          };
        }
      });
    });

    // Then we can start by loading the main application module
    beforeEach(module(ApplicationConfiguration.applicationModuleName));

    // The injector ignores leading and trailing underscores here (i.e. _$httpBackend_).
    // This allows us to inject a service but then attach it to a variable
    // with the same name as the service.
    beforeEach(inject(function ($controller, $rootScope, _$location_, _$stateParams_, _$httpBackend_, _Authentication_, _InfrastructureRequests_) {
      // Set a new global scope
      scope = $rootScope.$new();

      // Point global variables to injected services
      $stateParams = _$stateParams_;
      $httpBackend = _$httpBackend_;
      $location = _$location_;
      Authentication = _Authentication_;
      InfrastructureRequests = _InfrastructureRequests_;

      // create mock infrastructureRequest
      mockInfrastructureRequest = new InfrastructureRequests({
        _id: '525a8422f6d0f87f0e407a33',
        title: 'An InfrastructureRequest about MEAN',
        content: 'MEAN rocks!'
      });

      // Mock logged in user
      Authentication.user = {
        roles: ['user']
      };

      // Initialize the InfrastructureRequests controller.
      InfrastructureRequestsController = $controller('InfrastructureRequestsController', {
        $scope: scope
      });
    }));

    it('$scope.find() should create an array with at least one infrastructureRequest object fetched from XHR', inject(function (InfrastructureRequests) {
      // Create a sample infrastructureRequests array that includes the new infrastructureRequest
      var sampleInfrastructureRequests = [mockInfrastructureRequest];

      // Set GET response
      $httpBackend.expectGET('api/infrastructureRequests').respond(sampleInfrastructureRequests);

      // Run controller functionality
      scope.find();
      $httpBackend.flush();

      // Test scope value
      expect(scope.infrastructureRequests).toEqualData(sampleInfrastructureRequests);
    }));

    it('$scope.findOne() should create an array with one infrastructureRequest object fetched from XHR using a infrastructureRequestId URL parameter', inject(function (infrastructureRequests) {
      // Set the URL parameter
      $stateParams.infrastructureRequestId = mockInfrastructureRequest._id;

      // Set GET response
      $httpBackend.expectGET(/api\/infrastructureRequests\/([0-9a-fA-F]{24})$/).respond(mockInfrastructureRequest);

      // Run controller functionality
      scope.findOne();
      $httpBackend.flush();

      // Test scope value
      expect(scope.infrastructureRequest).toEqualData(mockInfrastructureRequest);
    }));

    describe('$scope.create()', function () {
      var sampleInfrastructureRequestPostData;

      beforeEach(function () {
        // Create a sample infrastructureRequest object
        sampleInfrastructureRequestPostData = new InfrastructureRequests({
          title: 'An infrastructureRequest about MEAN',
          content: 'MEAN rocks!'
        });

        // Fixture mock form input values
        scope.title = 'An InfrastructureRequest about MEAN';
        scope.content = 'MEAN rocks!';

        spyOn($location, 'path');
      });

      it('should send a POST request with the form input values and then locate to new object URL', inject(function (infrastructureRequests) {
        // Set POST response
        $httpBackend.expectPOST('api/infrastructureRequests', sampleInfrastructureRequestPostData).respond(mockInfrastructureRequest);

        // Run controller functionality
        scope.create(true);
        $httpBackend.flush();

        // Test form inputs are reset
        expect(scope.title).toEqual('');
        expect(scope.content).toEqual('');

        // Test URL redirection after the infrastructureRequest was created
        expect($location.path.calls.mostRecent().args[0]).toBe('infrastructureRequests/' + mockInfrastructureRequest._id);
      }));

      it('should set scope.error if save error', function () {
        var errorMessage = 'this is an error message';
        $httpBackend.expectPOST('api/infrastructureRequests', sampleInfrastructureRequestPostData).respond(400, {
          message: errorMessage
        });

        scope.create(true);
        $httpBackend.flush();

        expect(scope.error).toBe(errorMessage);
      });
    });

    describe('$scope.update()', function () {
      beforeEach(function () {
        // Mock infrastructureRequest in scope
        scope.infrastructureRequest = mockInfrastructureRequest;
      });

      it('should update a valid infrastructureRequest', inject(function (InfrastructureRequests) {
        // Set PUT response
        $httpBackend.expectPUT(/api\/infrastructureRequests\/([0-9a-fA-F]{24})$/).respond();

        // Run controller functionality
        scope.update(true);
        $httpBackend.flush();

        // Test URL location to new object
        expect($location.path()).toBe('/infrastructureRequests/' + mockInfrastructureRequest._id);
      }));

      it('should set scope.error to error response message', inject(function (InfrastructureRequests) {
        var errorMessage = 'error';
        $httpBackend.expectPUT(/api\/infrastructureRequests\/([0-9a-fA-F]{24})$/).respond(400, {
          message: errorMessage
        });

        scope.update(true);
        $httpBackend.flush();

        expect(scope.error).toBe(errorMessage);
      }));
    });

    describe('$scope.remove(infrastructureRequest)', function () {
      beforeEach(function () {
        // Create new infrastructureRequests array and include the infrastructureRequest
        scope.infrastructureRequests = [mockInfrastructureRequest, {}];

        // Set expected DELETE response
        $httpBackend.expectDELETE(/api\/infrastructureRequests\/([0-9a-fA-F]{24})$/).respond(204);

        // Run controller functionality
        scope.remove(mockInfrastructureRequest);
      });

      it('should send a DELETE request with a valid infrastructureRequestId and remove the infrastructureRequest from the scope', inject(function (infrastructureRequests) {
        expect(scope.infrastructureRequests.length).toBe(1);
      }));
    });

    describe('scope.remove()', function () {
      beforeEach(function () {
        spyOn($location, 'path');
        scope.infrastructureRequest = mockInfrastructureRequest;

        $httpBackend.expectDELETE(/api\/infrastructureRequests\/([0-9a-fA-F]{24})$/).respond(204);

        scope.remove();
        $httpBackend.flush();
      });

      it('should redirect to infrastructureRequests', function () {
        expect($location.path).toHaveBeenCalledWith('infrastructureRequests');
      });
    });
  });
}());
