Back home

AngularJs: Warsztaty - stopień 3

Środowisko

Start

Podpinanie js do html

Directive blokujący zaznaczanie i klikanie na element

<quote ws-unselectable>Copyright protected piece of thought</quote>
return {
  restrict: 'A',
  link: function postLink(scope, element, attrs) {
    element.bind('mousedown', function(e) {
      e.preventDefault();
    }); 
    element.bind('selectstart', function(e) {
      e.preventDefault();
    }); 
  }

Kontrolka w directive

<div ws-shortcut-input ws-label="Special key + 1"></div>
<div ws-shortcut-input ws-label="Special key + 2"></div>

Nieizolowane scopy

return {
  template: ': <input ng-model="number" />',
  restrict: 'A',
  link: function (scope, element, attrs)  {
    scope.label = attrs.wsLabel;
  }

Izolowane scopy

return {
  template: ': <input ng-model="number" />',
  restrict: 'A',
  scope: {
    label: '@wsLabel',
    number: '=ngModel'
  }

Zadanie 1: kontrolka dla filtru przedziału

<fieldset ws-interval min="20" max="40" ng-model="interval">
</fieldset>

Rozwiązanie 1

return {
  template: 'Min: <input type="range" max="" min="" ng-model="model.min"> ' +
      ' <br> Max: <input type="range" max="" min="" ng-model="model.max"> ',
    scope: {
    min: '@',
    max: '@',
    model: '=ngModel'
  },
  restrict: 'A',
  link: function (scope, element, attrs) {
    scope.model = {
      min: scope.min,
      max: scope.max
    };
  }

Hack

template: 'Min: <input type="range" max="" min="" ng-model="model.min"> ' +
          ' <br> Max: <input type="range" max="" min="" ng-model="model.max"> '

Testy

Piramida testów

Unit testy - idea

Mocks & stubs

Dependecy injection

// Dependecy injection
function ContactEditCtrl ($scope, $routeParams, contacts) {
  $scope.contact = contacts.get($routeParams.id);
  $scope.id = $routeParams.id;
}
// Dependecy 'calling'
function ContactEditCtrl () {
  var $scope = ScopeFactory.getNewScope(),
    $routeParams = RouteParams.getSingleton(),
    contacts = new Contacts();

  $scope.contact = contacts.get($routeParams.id);
  $scope.id = $routeParams.id;
}

Jasmine

Jasmine - składnia

describe("Jasmine", function() {
  it("is aware that true === true", function() {
    expect(true).toBe(true);
  });

  it("is aware that false !== true", function() {
    expect(false).not.toBe(true);
  });
});

Jasmine - matchery (asercje)

// Defaults
expect(a.foo).toBeDefined();
expect(message).toMatch(/bar/);
expect(a).toBe(true);
expect(a).toEqual(12);
expect(pi).toBeGreaterThan(e);

// Jasmine matchers
expect(function).toBeFunction();
expect(string).toBeString();
expect(array).toBeArray();

Jasmine - mokowanie

spyOn(foo, 'setBar').andCallThrough();
foo.setBar(42);
expect(foo.setBar).toHaveBeenCalled();
expect(foo.setBar).toHaveBeenCalledWith(42);

var standAloneSpy = jasmine.createSpy('standAloneSpy').andReturn(11);

Unit testy - Angular

Angular - testowanie controlera

$controller('GlobalCtrl', {
  $scope: scope});

Zadanie 2 - unit testy controlera

Rozwiązanie 2a

beforeEach(inject(function ($controller, $rootScope) {
  scope = $rootScope.$new();
  cookies = {};
  wsUuidGenerator = {
    createUuid: jasmine.createSpy('createUuid').andReturn('341')
  };

  GlobalCtrl = $controller('GlobalCtrl', {
    $scope: scope,
    $cookies: cookies,
    wsUuidGenerator: wsUuidGenerator
  });
}));

it('should setup cookies', function () {
  expect(cookies.trackingId).toEqual('341');
});

Zadanie 2b - naiwna implementacja

Rozwiązanie 2b

$cookies.trackingId = '341';

Refaktoring testu

init = function () {
  GlobalCtrl = $controller('GlobalCtrl', {
    $scope: scope,
    $cookies: cookies,
    wsUuidGenerator: wsUuidGenerator
  });
};

Zadanie 2c

Rozwiązanie 2c

expect(wsUuidGenerator.createUuid).toHaveBeenCalled();

Naiwna implementacja

wsUuidGenerator.createUuid();
$cookies.trackingId = '341';

Zadanie 2d

Rozwiązanie 2d

// check for some other value   
wsUuidGenerator.createUuid.andReturn('111');
init();
expect(cookies.trackingId).toEqual('111');

Pokryty testami kod

$cookies.trackingId = wsUuidGenerator.createUuid();

Zadanie 2e

Rozwiązanie 2e

// should not override existing cookie value
wsUuidGenerator.createUuid.andReturn('111');
init();
expect(cookies.trackingId).toEqual('341');

Pokryty testami kod

if (!angular.isString($cookies.trackingId)) {
  $cookies.trackingId = wsUuidGenerator.createUuid();
}

Angular - testowanie serwisu

module(function($provide) {
  $provide.value('ServiceA', ServiceAMock);
  $provide.value('ServiceB', ServiceBMock);
});

inject(function(_ServiceInTest_) {
  ServiceInTest = _ServiceInTest_;
});

Przykład testów service

beforeEach(function () {
  module(function($provide) {
    $provide.value('$resource', _resource);
  });

  inject(function(_contacts_) {
    contacts = _contacts_;
  });
});

it('should implement getAll', function () {
  expect(ContactsResource.query).not.toHaveBeenCalled();
  var returned = contacts.getAll();
  expect(ContactsResource.query).toHaveBeenCalled();
  expect(returned).toEqual('queryTest');
});

Podsumowanie

Stay tuned