<!DOCTYPE html>
<html>

<head>
  <link data-require="jasmine@*" data-semver="2.0.0" rel="stylesheet" href="//cdn.jsdelivr.net/jasmine/2.0.0/jasmine.css" />
  <script data-require="jasmine@*" data-semver="2.0.0" src="//cdn.jsdelivr.net/jasmine/2.0.0/jasmine.js"></script>
  <script data-require="jasmine@*" data-semver="2.0.0" src="//cdn.jsdelivr.net/jasmine/2.0.0/jasmine-html.js"></script>
  <script data-require="jasmine@*" data-semver="2.0.0" src="//cdn.jsdelivr.net/jasmine/2.0.0/boot.js"></script>
  <script data-require="angular.js@*" data-semver="1.5.3" src="https://code.angularjs.org/1.5.3/angular.js"></script>
  <script data-require="angular-mocks@*" data-semver="1.5.3" src="https://code.angularjs.org/1.5.3/angular-mocks.js"></script>
  <script src="components.js"></script>
  <script src="mainControllerTest.js"></script>
</head>

<body>
  <h1>Angular controller test with Jasmine</h1>
</body>

</html>
angular.module('myComponentModule', [])
  .component('myComponent', {
    bindings: {
      myBinding: '@',
      myTextForCallFromChild: '@'
    },
    controller: function($q) {
      this.myTitle = 'Unit Testing AngularJS';
      this.myChildParameter = 'Child parameter';
      this.callFromChild = function(param) {
        // console.log('callFromChild', param);
        return 'returnCallFromChild(' + param + ')';
      };

      function promise1() {
        return Promise.resolve('ciao!');
      }
    },
    template: '<h1>{{ $ctrl.myTitle }} - {{ $ctrl.myBinding }}</h1>{{$ctrl.myTextForCallFromChild}}<my-child-component my-child-binding="{{$ctrl.myChildParameter}}" my-text-for-call-from-child="{{$ctrl.myTextForCallFromChild}}"></my-child-component>'
  })
  .component('myChildComponent', {
    bindings: {
      myChildBinding: '@',
      myTextForCallFromChild: '@'
    },
    controller: function($timeout) {
      let self = this;
      $timeout(function() {
        self.myChildTitle = 'Subtitle';
      });
    },
    require: {
      myComponent: '^myComponent'
    },
    template: '<h2>{{ $ctrl.myChildTitle }} - {{ $ctrl.myChildBinding }}</h2><h3>{{ $ctrl.myComponent.callFromChild($ctrl.myTextForCallFromChild) }}</h3>'
  });

describe('Component: myComponent', function() {
  beforeEach(angular.mock.module('myComponentModule'));

  let element;
  let childElement;
  let scope;
  beforeEach(inject(function($rootScope, $compile) {
    scope = $rootScope.$new();
    element = angular.element('<my-component my-binding="{{param1}}" my-text-for-call-from-child="{{param2}}"></my-component>');
    element = $compile(element)(scope);
    scope.param1 = '1.5';
    scope.param2 = 'Primo test';
    scope.$apply();
  }));

  let controller;
  let childController;
  beforeEach(function() {
    controller = element.controller('myComponent');
    spyOn(controller, 'callFromChild');
    childElement = element.find('my-child-component');
    childController = childElement.controller('myChildComponent');
  });

  beforeEach(inject(function($timeout) {
    $timeout.flush();
  }));

  describe('main component', function() {
    it('should render the text', function() {
      let h1 = element.find('h1');
      expect(h1.text()).toBe('Unit Testing AngularJS - 1.5');
    });

    it('should expose my title', function() {
      expect(controller.myTitle).toBeDefined();
      expect(controller.myTitle).toBe('Unit Testing AngularJS');
    });

    it('should have my binding bound', function() {
      expect(controller.myBinding).toBeDefined();
      expect(controller.myBinding).toBe('1.5');
    });
  });

  describe('child component', function() {
    it('should have child controller', function() {
      expect(childController.myChildBinding).toBeDefined();
      expect(childController.myChildBinding).toBe('Child parameter');
    });

    it('should have child controller', function() {
      expect(childController.myTextForCallFromChild).toBeDefined();
      expect(childController.myTextForCallFromChild).toBe('Primo test');
    });

    it('should have parent controller', function() {
      expect(childController.myComponent).toBeDefined();
      expect(childController.myComponent).toBe(controller);
    });

    it('should have called parent function', function() {
      expect(controller.callFromChild).toHaveBeenCalled();
      expect(controller.callFromChild).toHaveBeenCalledWith('Primo test');
    });
  });

});