DinisCruz / Book_Practical_AngularJS

Content for 'Practical AngularJS' book published at LeanPub
Apache License 2.0
18 stars 6 forks source link

Add section with answers to the question 'how to test an AngularJS view' #28

Open DinisCruz opened 8 years ago

DinisCruz commented 8 years ago

https://twitter.com/DinisCruz/status/747391516344205313

DinisCruz commented 8 years ago

$compile("<div ng-view></div>")($rootScope); is key to trigger compilation when testing Angular routes and views

image

Here is the complete loop

image

DinisCruz commented 8 years ago

Here is an example of a full test

describe 'views | radar.page', ->

  html          = null
  project       = null
  team          = null
  test_Data     = null
  ngView        = null
  url           = null
  url_Data      = null
  url_Path      = null
  url_Template  = null

  beforeEach ()->
    module('MM_Graph')
    project      = 'bsimm'
    team         = 'team-A'
    test_Data    = { metadata: 42 }
    url          = "/view/#{project}/#{team}/table"
    url_Data     = "/api/v1/table/#{project}/#{team}"
    url_Path     = '/view/:project/:team/table'
    url_Template = '/ui/html/pages/table.page.html'

    inject ($templateCache)->      
      $templateCache.get_Keys().assert_Contains 'pages/table.page.html'
      html = $templateCache.get 'pages/table.page.html'

  it '$templateCache value',->
    using $(html), ->
      $(html).find('h1').html().assert_Is 'table will go here'

  it 'check view content', ->
    inject ($route, $location, $rootScope, $httpBackend, $compile)->

      ngView = $compile("<div ng-view></div>")($rootScope)

      using $httpBackend, ->
        @.expectGET(url_Template).respond(html)
        @.expectGET(url_Data    ).respond test_Data

      $location.path(url)
      $httpBackend.flush()

      element = ngView[0].nextSibling
      $scope = angular.element(element).scope()
      $scope.team.assert_Is 'team-A'
      $scope.table.assert_Is metadata: 42

  it 'check routes /view/:project/:team/table', ()->

    inject ($route, $location, $rootScope, $httpBackend)->
      $httpBackend.expectGET(url_Template).respond(html)
      $location.path(url)
      $rootScope.$digest()

      $location.path().assert_Is url

      using $route.current, ->
        @.controller          .assert_Is 'TableController'
        @.params              .assert_Is { project: 'bsimm', team: 'team-A' }
        @.templateUrl         .assert_Is url_Template
        @.$$route.originalPath.assert_Is url_Path

      #$route.current.assert_Is expected_Route
      $httpBackend.flush()
      $rootScope.$digest()

  it 'checking values set by angular routes', ->
    inject ($route, $location, $rootScope, $httpBackend)->
      $httpBackend.expectGET('/ui/html/pages/table.page.html').respond(html)
      $location.path url
      $rootScope.$digest()

      $location.path().assert_Is url

      expected_Route =
        params    : { project: 'bsimm', team: 'team-A' }
        pathParams: { project: 'bsimm', team: 'team-A' },        
        $$route   :          
          templateUrl         : '/ui/html/pages/table.page.html',
          controller          : 'TableController'
          reloadOnSearch      : true,
          caseInsensitiveMatch: false,
          originalPath        : '/view/:project/:team/table',
          regexp              : /^\/view\/(?:([^\/]+))\/(?:([^\/]+))\/table$/,
          keys                : [ { name: 'project', optional: false }, { name: 'team', optional: false } ]
        loadedTemplateUrl     : '/ui/html/pages/table.page.html'
      console.log $route.current
      JSON.stringify($route.current).assert_Is JSON.stringify(expected_Route)
DinisCruz commented 8 years ago

better version of the test above

test:

describe 'views | table.page', ->
  $scope        = null
  element       = null
  html          = null
  route         = 

  project       = 'bsimm'
  team          = 'team-A'
  test_Data     = { metadata: 42 }
  url           = "/view/#{project}/#{team}/table"
  url_Data      = "/api/v1/table/#{project}/#{team}"
  template_Key  = 'pages/table.page.html'
  url_Template  = '/ui/html/' + template_Key

  beforeEach ()->
    module('MM_Graph')
    inject ($route, $compile, $httpBackend, $location, $rootScope, $templateCache)->
      $templateCache.get_Keys().assert_Contains template_Key

      ngView = $compile("<div ng-view></div>")($rootScope)

      using $httpBackend, ->
        @.expectGET(url_Template).respond $templateCache.get(template_Key)
        @.expectGET(url_Data    ).respond test_Data

      $location.path(url)
      $httpBackend.flush()

      element = ngView[0].nextSibling
      $scope  = angular.element(element).scope()
      html    = element.outerHTML
      route   = $route.current

  it 'rendered view', ->
    using route, ->
      @.params.assert_Is { project: 'bsimm', team: 'team-A' }
      @.$$route.templateUrl.assert_Is url_Template
      @.$$route.controller.assert_Is 'TableController'

    $(html).find('h1').html('table will go here')
    $(html).find('pre').html().assert_Is '{"metadata":42}' 

table.pug:

h1 table will go here
pre {{table}}

controller:

angular.module('MM_Graph')
  .controller 'TableController', ($scope, $routeParams, MM_Graph_API)->
    project = $routeParams.project
    team    = $routeParams.team

    if project and team
      $scope.project = project
      $scope.team    = team
      MM_Graph_API.view_Table project, team, (data)->
        $scope.table = data
DinisCruz commented 8 years ago

Here is a service that allows the easy testing of Angular Views

class Render_View
  constructor: (options, route, compile, httpBackend, location, rootScope, templateCache)->
    @.options          = options || {}
    @.$route           = route
    @.$compile         = compile
    @.$httpBackend     = httpBackend
    @.$location        = location
    @.$rootScope       = rootScope
    @.$templateCache   = templateCache
    @.project          = @.options.project || 'bsimm'
    @.team             = @.options.team    || 'team-A'
    @.$                = null
    @.element          = null
    @.html             = null
    @.route            = null
    @.ng_View          = null
    @.Url_Template_Key = null
    @.url_Data         = null
    @.url_Location     = null
    @.url_Template     = null

    @.set_Url_Location     @.options.url_Location
    @.set_Url_Template_Key @.options.url_Template_Key
    @.set_Url_Data         @.options.url_Data

  run: =>    
    @.ng_View = @.$compile("<div ng-view></div>")(@.$rootScope)
    @.$location.path @.url_Location
    @.$httpBackend.flush()

    @.route   = @.$route.current
    @.element = @.ng_View[0].nextSibling
    @.html    = @.element.outerHTML
    @.$       = (selector)->$(@.html).find(selector)

    @

  set_Url_Data: (url_Data)=>
    if url_Data and url_Data.path and url_Data.value
      @.url_Data = url_Data
      @.$httpBackend.expectGET(@.url_Data.path).respond @.url_Data.value
    @

  set_Url_Location: (location)=>
    if location
      @.url_Location = location
    @

  set_Url_Template_Key: (template_Key)=>
    if template_Key
      @.url_Template_Key = template_Key
      @.url_Template = "/ui/html/#{@.url_Template_Key}"
      @.$httpBackend.expectGET(@.url_Template).respond @.$templateCache.get(@.url_Template_Key)
    @      

angular.module('MM_Graph')
       .service 'Render_View', ($route, $compile, $httpBackend, $location, $rootScope, $templateCache)->
          (options)->
            new Render_View(options, $route, $compile, $httpBackend, $location, $rootScope, $templateCache)
describe 'services | Render-View', ->

  render_View = null

  beforeEach ()->
    module('MM_Graph')

    inject ($injector)->      
      render_View = $injector.get('Render_View')()

  it 'constructor', ->
    using render_View, ->
      (typeof(@.$route        )).assert_Is 'object'
      (typeof(@.$compile      )).assert_Is 'function'
      (typeof(@.$httpBackend  )).assert_Is 'function'
      (typeof(@.$location     )).assert_Is 'object'
      (typeof(@.$rootScope    )).assert_Is 'object'
      (typeof(@.$templateCache)).assert_Is 'object'

      @.project .assert_Is 'bsimm'
      @.team    .assert_Is 'team-A'

      (@.element          is null).assert_Is_True()
      (@.html             is null).assert_Is_True()
      (@.ng_View          is null).assert_Is_True()
      (@.Url_Template_Key is null).assert_Is_True()
      (@.url_Data         is null).assert_Is_True()
      (@.url_Location     is null).assert_Is_True()
      (@.url_Template     is null).assert_Is_True()

  it 'constructor (with custom options)', ->
    options = 
      project: 'aaaaas'
      team   : 'bbbbbb'
    inject ($injector)->
      using $injector.get('Render_View')(options), ->
        @.options.assert_Is options
        @.project.assert_Is options.project
        @.team   .assert_Is options.team

  it 'run (with values set on constructor)', ->
    project = 'abc'
    team    =  '123'
    options =
      project         : project
      team            : team
      url_Data        : path :"/api/v1/team/#{project}/get/#{team}?pretty" , value: { metadata: 42}
      url_Location    : "/view/#{project}/#{team}/raw"
      url_Template_Key: 'pages/raw.page.html'

    inject ($injector)->
      using $injector.get('Render_View')(options), ->    
        @.run()

        @.element.outerHTML.assert_Is @.html
        @.html.assert_Contains('ng-controller')
        @.html.assert_Contains '"metadata": 42'
        @.route.params.assert_Is { project: 'abc', team: '123' }
        @.route.$$route.templateUrl.assert_Is @.url_Template
        @.$('div').length.assert_Is 4

  it 'run (with values manually set)', ->
    using render_View, ->
      @.set_Url_Location     "/view/#{@.project}/#{@.team}/raw"
       .set_Url_Template_Key 'pages/raw.page.html'
       .set_Url_Data         path: "/api/v1/team/#{@.project}/get/#{@.team}?pretty", value: metadata: 42
       .run()

      @.element.outerHTML.assert_Is @.html
      @.html.assert_Contains('ng-controller')
      @.html.assert_Contains '"metadata": 42'
      @.route.params.assert_Is { project: 'bsimm', team: 'team-A' }
      @.route.$$route.templateUrl.assert_Is @.url_Template
      @.$('div').length.assert_Is 4

  it 'set_Url_Data', -> 
    using render_View, ->
      @.set_Url_Data path: "/api/v1/table/#{@.project}/#{@.team}", value: {a : 42}
      @.url_Data.path .assert_Is '/api/v1/table/bsimm/team-A'
      @.url_Data.value.assert_Is a: 42

  it 'set_Url_Location', ->
    using render_View, ->
      @.set_Url_Location "/view/#{@.project}/#{@.team}/table"
      @.url_Location.assert_Is '/view/bsimm/team-A/table'

  it 'set_Url_Template_Key', ->
    using render_View, ->
      @.set_Url_Template_Key 'pages/table.page.html'
      @.url_Template_Key.assert_Is 'pages/table.page.html'
      @.url_Template    .assert_Is "/ui/html/#{@.url_Template_Key}"

which can be used like this

describe 'views | view.page', ->

  project       = 'bsimm'
  team          = 'team-A'
  options =
    project         : project
    team            : team
    url_Data        : path :"/api/v1/table/#{project}/#{team}" , value: { metadata: 42}
    url_Location    : "/view/#{project}/#{team}"
    url_Template_Key: 'pages/view.page.html'

  view = null

  beforeEach ()->
    module('MM_Graph')
    inject ($injector)->
      using $injector.get('Render_View')(options), ->
        view = @
        @.$httpBackend.expectGET("/api/v1/team/#{project}/get/#{team}?pretty").respond {}
        @.run()

  it 'pages/view.page.html', ->
    $(view.html).eq(0).attr('ng-controller').assert_Is 'TableController'

or like this

describe 'views | table.page', ->

  project       = 'bsimm'
  team          = 'team-A'
  options =
    project         : project
    team            : team
    url_Data        : path: "/api/v1/table/#{project}/#{team}" , value: { metadata: 42}
    url_Location    : "/view/#{project}/#{team}/table"
    url_Template_Key: 'pages/table.page.html'

  view = null

  beforeEach ()->
    module('MM_Graph')
    inject ($injector)->
      view = $injector.get('Render_View')(options).run()

  it 'pages/view.page.html', -> 
    view.$('h1').html().assert_Is 'table will go here'
    view.$('pre').html().assert_Is '{"metadata":42}'
    view.route.$$route.controller.assert_Is 'TableController'