Upgrade to Pro — share decks privately, control downloads, hide ads and more …

TDD with AngularJS

Mike Tierney
November 08, 2014

TDD with AngularJS

Talk given at NationJS 2014.

In this talk we will build a simple AngularJS application using the principles of Test Driven Development (TDD). While we will primarily focus on using Karma and Jasmine to create unit tests, we will also look at creating end-to-end (commonly referred to as E2E) integration tests using Protractor.

Mike Tierney

November 08, 2014
Tweet

More Decks by Mike Tierney

Other Decks in Programming

Transcript

  1. TDD with AngularJS
    Michael Tierney
    NationJS
    November
    8, 2014

    View Slide

  2. About me
    Director of UI Engineering at
    ( )
    Co
    -
    organizer of Refresh Seattle
    Find me on both and as
    @
    miketierney
    Intridea
    http
    ://
    intridea
    .com
    GitHub Twitter

    View Slide

  3. Resources for Today’s talk:
    Code Samples
    :
    Slides
    :
    https
    ://
    github
    .com
    /
    miketierney
    /
    tdd
    -
    with
    -
    angular
    https
    ://
    speakerdeck
    .com
    /
    miketierney
    /
    tdd
    -
    with
    -
    angularjs

    View Slide

  4. Why TDD?
    Added stability
    Improves inter
    -
    developer communication
    Makes maintenance easier

    View Slide

  5. Added Stability
    Can make changes with relative confidence that
    they won

    t break something without you knowing
    Encourages you to consider how you are
    implementing your code
    Encourages loosely coupled modules

    View Slide

  6. Improved Communication
    Tests function as both documentation and API
    definition
    Impacts of changes can be more readily spotted in
    git di
    ffs
    , code review
    , etc
    .

    View Slide

  7. Maintenance
    Because behavior is defined in the tests
    ,
    understanding what the code does is easier for
    other contributors

    View Slide

  8. Today’s Tools
    Angular
    Karma
    (
    unit tests
    )
    Protractor
    (
    E
    2E
    , or

    end to end
    ”)
    Jasmine
    PhantomJS
    Gulp
    (
    not required
    , but helpful
    )

    View Slide

  9. Today’s project
    Build a ToDo app using TDD
    .

    View Slide

  10. Foundation
    Bootstrap the NPM and Bower files
    $ c
    d ~
    /
    P
    r
    o
    j
    e
    c
    t
    s
    /
    t
    d
    d
    -
    w
    i
    t
    h
    -
    a
    n
    g
    u
    l
    a
    r
    j
    s
    $ e
    c
    h
    o "
    {
    }
    " >
    > p
    a
    c
    k
    a
    g
    e
    .
    j
    s
    o
    n
    $ e
    c
    h
    o '
    {
    "
    n
    a
    m
    e
    "
    : "
    T
    D
    D w
    i
    t
    h A
    n
    g
    u
    l
    a
    r
    "
    }
    ' >
    > b
    o
    w
    e
    r
    .
    j
    s
    o
    n

    View Slide

  11. Install Packages
    $ n
    p
    m i
    n
    s
    t
    a
    l
    l -
    -
    s
    a
    v
    e
    -
    d
    e
    v k
    a
    r
    m
    a g
    u
    l
    p
    $ b
    o
    w
    e
    r i
    n
    s
    t
    a
    l
    l -
    -
    s
    a
    v
    e a
    n
    g
    u
    l
    a
    r a
    n
    g
    u
    l
    a
    r
    -
    m
    o
    c
    k
    s a
    n
    g
    u
    l
    a
    r
    -
    r
    e
    s
    o
    u
    r
    c
    e

    View Slide

  12. Con gure Karma
    $ n
    o
    d
    e
    _
    m
    o
    d
    u
    l
    e
    s
    /
    k
    a
    r
    m
    a
    /
    b
    i
    n
    /
    k
    a
    r
    m
    a i
    n
    i
    t k
    a
    r
    m
    a
    .
    c
    o
    n
    f
    .
    j
    s

    and just follow the on
    -
    screen instructions
    .
    Accept all of the defaults
    , and add both Chrome
    and PhantomJS as the browsers
    .

    View Slide

  13. Con gure Karma (cont’d)

    View Slide

  14. Con gure Karma (cont’d)
    Add the bower components to Karma
    :
    /
    / k
    a
    r
    m
    a
    .
    c
    o
    n
    f
    .
    j
    s
    /
    / l
    i
    s
    t o
    f f
    i
    l
    e
    s / p
    a
    t
    t
    e
    r
    n
    s t
    o l
    o
    a
    d i
    n t
    h
    e b
    r
    o
    w
    s
    e
    r
    f
    i
    l
    e
    s
    : [
    '
    b
    o
    w
    e
    r
    _
    c
    o
    m
    p
    o
    n
    e
    n
    t
    s
    /
    a
    n
    g
    u
    l
    a
    r
    /
    a
    n
    g
    u
    l
    a
    r
    .
    m
    i
    n
    .
    j
    s
    '
    ,
    '
    b
    o
    w
    e
    r
    _
    c
    o
    m
    p
    o
    n
    e
    n
    t
    s
    /
    a
    n
    g
    u
    l
    a
    r
    -
    m
    o
    c
    k
    s
    /
    a
    n
    g
    u
    l
    a
    r
    -
    m
    o
    c
    k
    s
    .
    j
    s
    '
    ,
    '
    b
    o
    w
    e
    r
    _
    c
    o
    m
    p
    o
    n
    e
    n
    t
    s
    /
    a
    n
    g
    u
    l
    a
    r
    -
    r
    e
    s
    o
    u
    r
    c
    e
    /
    a
    n
    g
    u
    l
    a
    r
    -
    r
    e
    s
    o
    u
    r
    c
    e
    .
    j
    s
    '
    ,
    '
    j
    s
    /
    *
    .
    j
    s
    '
    ,
    '
    t
    e
    s
    t
    /
    *
    *
    /
    *
    _
    s
    p
    e
    c
    .
    j
    s
    '
    ]
    ,

    View Slide

  15. Con gure Gulp
    /
    / g
    u
    l
    p
    f
    i
    l
    e
    .
    j
    s
    v
    a
    r g
    u
    l
    p = r
    e
    q
    u
    i
    r
    e
    (
    '
    g
    u
    l
    p
    '
    )
    ,
    k
    a
    r
    m
    a = r
    e
    q
    u
    i
    r
    e
    (
    '
    k
    a
    r
    m
    a
    '
    )
    .
    s
    e
    r
    v
    e
    r
    ;
    /
    *
    *
    * R
    u
    n t
    e
    s
    t o
    n
    c
    e a
    n
    d e
    x
    i
    t
    *
    /
    g
    u
    l
    p
    .
    t
    a
    s
    k
    (
    '
    t
    e
    s
    t
    '
    , f
    u
    n
    c
    t
    i
    o
    n (
    d
    o
    n
    e
    ) {
    k
    a
    r
    m
    a
    .
    s
    t
    a
    r
    t
    (
    {
    c
    o
    n
    f
    i
    g
    F
    i
    l
    e
    : _
    _
    d
    i
    r
    n
    a
    m
    e + '
    /
    k
    a
    r
    m
    a
    .
    c
    o
    n
    f
    .
    j
    s
    '
    ,
    s
    i
    n
    g
    l
    e
    R
    u
    n
    : t
    r
    u
    e
    }
    , d
    o
    n
    e
    )
    ;
    }
    )
    ;

    View Slide

  16. Create the directories
    $ m
    k
    d
    i
    r j
    s t
    e
    s
    t

    View Slide

  17. index.html
    <
    !
    D
    O
    C
    T
    Y
    P
    E h
    t
    m
    l
    >
    <
    h
    t
    m
    l l
    a
    n
    g
    =
    "
    e
    n
    "
    >
    <
    h
    e
    a
    d
    >
    <
    m
    e
    t
    a c
    h
    a
    r
    s
    e
    t
    =
    "
    U
    T
    F
    -
    8
    " /
    >
    <
    t
    i
    t
    l
    e
    >
    T
    o
    D
    o T
    D
    D
    <
    /
    t
    i
    t
    l
    e
    >
    <
    /
    h
    e
    a
    d
    >
    <
    b
    o
    d
    y n
    g
    -
    a
    p
    p
    =
    "
    t
    o
    d
    o
    A
    p
    p
    "
    >
    <
    s
    c
    r
    i
    p
    t s
    r
    c
    =
    "
    /
    b
    o
    w
    e
    r
    _
    c
    o
    m
    p
    o
    n
    e
    n
    t
    s
    /
    a
    n
    g
    u
    l
    a
    r
    /
    a
    n
    g
    u
    l
    a
    r
    .
    m
    i
    n
    .
    j
    s
    "
    >
    <
    /
    s
    c
    r
    i
    p
    t
    >
    <
    s
    c
    r
    i
    p
    t s
    r
    c
    =
    "
    /
    b
    o
    w
    e
    r
    _
    c
    o
    m
    p
    o
    n
    e
    n
    t
    s
    /
    a
    n
    g
    u
    l
    a
    r
    -
    r
    e
    s
    o
    u
    r
    c
    e
    /
    a
    n
    g
    u
    l
    a
    r
    -
    r
    e
    s
    o
    u
    r
    c
    e
    .
    m
    i
    <
    s
    c
    r
    i
    p
    t s
    r
    c
    =
    "
    /
    j
    s
    /
    a
    p
    p
    .
    j
    s
    "
    >
    <
    /
    s
    c
    r
    i
    p
    t
    >
    <
    /
    b
    o
    d
    y
    >
    <
    /
    h
    t
    m
    l
    >

    View Slide

  18. js/app.js
    '
    u
    s
    e s
    t
    r
    i
    c
    t
    '
    ;
    a
    n
    g
    u
    l
    a
    r
    .
    m
    o
    d
    u
    l
    e
    (
    '
    t
    o
    d
    o
    A
    p
    p
    '
    , [
    ]
    )
    ;
    Nothin

    fancy yet
    ; just a bare minimum app
    .

    View Slide

  19. Application specs
    It should display a list of to do items
    It should allow a user to add new to do items
    It should allow a user to toggle the item state
    It should allow a user to delete an item
    It should store the To Do items on a remote server

    View Slide

  20. Let’s get going!
    Set up the rst test.
    /
    / t
    e
    s
    t
    /
    c
    o
    n
    t
    r
    o
    l
    l
    e
    r
    .
    j
    s
    '
    u
    s
    e s
    t
    r
    i
    c
    t
    '
    ;
    d
    e
    s
    c
    r
    i
    b
    e
    (
    '
    T
    o
    D
    o
    C
    o
    n
    t
    r
    o
    l
    l
    e
    r
    '
    , f
    u
    n
    c
    t
    i
    o
    n (
    ) {
    b
    e
    f
    o
    r
    e
    E
    a
    c
    h
    (
    f
    u
    n
    c
    t
    i
    o
    n (
    ) {
    v
    a
    r c
    o
    n
    t
    r
    o
    l
    l
    e
    r
    ,
    s
    c
    o
    p
    e
    ;
    m
    o
    d
    u
    l
    e
    (
    '
    t
    o
    d
    o
    A
    p
    p
    .
    c
    o
    n
    t
    r
    o
    l
    l
    e
    r
    s
    '
    )
    ;

    View Slide

  21. …a little more setup…
    i
    n
    j
    e
    c
    t
    (
    f
    u
    n
    c
    t
    i
    o
    n (
    $
    c
    o
    n
    t
    r
    o
    l
    l
    e
    r
    , $
    r
    o
    o
    t
    S
    c
    o
    p
    e
    ) {
    c
    o
    n
    t
    r
    o
    l
    l
    e
    r = $
    c
    o
    n
    t
    r
    o
    l
    l
    e
    r
    ;
    s
    c
    o
    p
    e = $
    r
    o
    o
    t
    S
    c
    o
    p
    e
    .
    $
    n
    e
    w
    (
    )
    ;
    }
    )
    ;
    t
    h
    i
    s
    .
    c
    r
    e
    a
    t
    e
    C
    o
    n
    t
    r
    o
    l
    l
    e
    r = f
    u
    n
    c
    t
    i
    o
    n (
    ) {
    r
    e
    t
    u
    r
    n c
    o
    n
    t
    r
    o
    l
    l
    e
    r
    (
    '
    T
    o
    D
    o
    A
    p
    p
    C
    o
    n
    t
    r
    o
    l
    l
    e
    r
    '
    , {
    $
    s
    c
    o
    p
    e
    : s
    c
    o
    p
    e
    }
    )
    ;
    }
    ;
    t
    h
    i
    s
    .
    c
    t
    r
    l = t
    h
    i
    s
    .
    c
    r
    e
    a
    t
    e
    C
    o
    n
    t
    r
    o
    l
    l
    e
    r
    (
    )
    ;
    }
    )
    ; /
    / e
    n
    d o
    f b
    e
    f
    o
    r
    e
    E
    a
    c
    h
    (
    )

    View Slide

  22. Finally
    , a test!
    i
    t
    (
    '
    s
    h
    o
    u
    l
    d h
    a
    v
    e a t
    o
    d
    o
    s a
    r
    r
    a
    y
    '
    , f
    u
    n
    c
    t
    i
    o
    n (
    ) {
    e
    x
    p
    e
    c
    t
    (
    t
    h
    i
    s
    .
    c
    t
    r
    l
    .
    t
    o
    d
    o
    I
    t
    e
    m
    s
    )
    .
    t
    o
    E
    q
    u
    a
    l
    (
    [
    ]
    )
    ;
    }
    )
    ;
    }
    )
    ; /
    / e
    n
    d o
    f D
    e
    s
    c
    r
    i
    b
    e
    (
    '
    T
    o
    D
    o
    C
    o
    n
    t
    r
    o
    l
    l
    e
    r
    '
    )

    View Slide

  23. Jasmine Matchers
    e
    x
    p
    e
    c
    t
    (
    a
    )
    .
    t
    o
    B
    e
    (
    b
    )
    ;
    e
    x
    p
    e
    c
    t
    (
    a
    )
    .
    n
    o
    t
    .
    t
    o
    B
    e
    (
    n
    u
    l
    l
    )
    ;
    e
    x
    p
    e
    c
    t
    (
    m
    e
    s
    s
    a
    g
    e
    )
    .
    t
    o
    M
    a
    t
    c
    h
    (
    /
    b
    a
    r
    /
    )
    ;
    e
    x
    p
    e
    c
    t
    (
    n
    u
    l
    l
    )
    .
    t
    o
    B
    e
    N
    u
    l
    l
    (
    )
    ;
    e
    x
    p
    e
    c
    t
    (
    a
    .
    f
    o
    o
    )
    .
    t
    o
    b
    e
    D
    e
    f
    i
    n
    e
    d
    (
    )
    ;
    e
    x
    p
    e
    c
    t
    (
    a
    .
    b
    a
    r
    )
    .
    t
    o
    B
    e
    U
    n
    d
    e
    f
    i
    n
    e
    d
    (
    )
    ;
    e
    x
    p
    e
    c
    t
    (
    f
    o
    o
    )
    .
    t
    o
    B
    e
    T
    r
    u
    t
    h
    y
    (
    )
    ;
    e
    x
    p
    e
    c
    t
    (
    a
    )
    .
    t
    o
    B
    e
    F
    a
    l
    s
    y
    (
    )
    ;
    e
    x
    p
    e
    c
    t
    (
    [
    '
    f
    o
    o
    '
    , '
    b
    a
    r
    '
    , '
    b
    a
    z
    '
    ]
    )
    .
    t
    o
    C
    o
    n
    t
    a
    i
    n
    (
    '
    b
    a
    r
    '
    )
    ;
    e
    x
    p
    e
    c
    t
    (
    b
    a
    r
    )
    .
    t
    o
    T
    h
    r
    o
    w
    (
    )
    ;

    View Slide

  24. Run the test
    $ g
    u
    l
    p t
    e
    s
    t

    View Slide

  25. Aaaaaand fail

    View Slide

  26. Create the controller
    /
    / j
    s
    /
    a
    p
    p
    .
    j
    s
    '
    u
    s
    e s
    t
    r
    i
    c
    t
    '
    ;
    a
    n
    g
    u
    l
    a
    r
    .
    m
    o
    d
    u
    l
    e
    (
    '
    t
    o
    d
    o
    A
    p
    p
    .
    c
    o
    n
    t
    r
    o
    l
    l
    e
    r
    s
    '
    , [
    ]
    )
    .
    c
    o
    n
    t
    r
    o
    l
    l
    e
    r
    (
    '
    T
    o
    D
    o
    A
    p
    p
    C
    o
    n
    t
    r
    o
    l
    l
    e
    r
    '
    , f
    u
    n
    c
    t
    i
    o
    n (
    $
    s
    c
    o
    p
    e
    ) {
    }
    )
    ;
    a
    n
    g
    u
    l
    a
    r
    .
    m
    o
    d
    u
    l
    e
    (
    '
    t
    o
    d
    o
    A
    p
    p
    '
    , [
    '
    t
    o
    d
    o
    A
    p
    p
    .
    c
    o
    n
    t
    r
    o
    l
    l
    e
    r
    s
    '
    ]
    )
    ;

    View Slide

  27. Still failing
    But failing di
    fferently
    !

    View Slide

  28. One more adjustment…
    a
    n
    g
    u
    l
    a
    r
    .
    m
    o
    d
    u
    l
    e
    (
    '
    t
    o
    d
    o
    A
    p
    p
    .
    c
    o
    n
    t
    r
    o
    l
    l
    e
    r
    s
    '
    , [
    ]
    )
    .
    c
    o
    n
    t
    r
    o
    l
    l
    e
    r
    (
    '
    T
    o
    D
    o
    A
    p
    p
    C
    o
    n
    t
    r
    o
    l
    l
    e
    r
    '
    , f
    u
    n
    c
    t
    i
    o
    n (
    $
    s
    c
    o
    p
    e
    ) {
    t
    h
    i
    s
    .
    t
    o
    d
    o
    I
    t
    e
    m
    s = [
    ]
    ;
    }
    )
    ;

    View Slide

  29. Look ma, all green!

    View Slide

  30. Add some functionality
    We need add and edit abilities
    . Let

    s start with add
    .

    View Slide

  31. Create the test…
    The basic requirement of
    a
    d
    d
    I
    t
    e
    m is that it add a
    new
    i
    t
    e
    m to the
    t
    o
    d
    o
    I
    t
    e
    m
    s Array
    .
    /
    / i
    n t
    e
    s
    t
    /
    c
    o
    n
    t
    r
    o
    l
    l
    e
    r
    .
    j
    s
    , a
    f
    t
    e
    r t
    h
    e f
    i
    r
    s
    t "
    i
    t
    (
    )
    " s
    t
    a
    t
    e
    m
    e
    n
    t
    d
    e
    s
    c
    r
    i
    b
    e
    (
    '
    c
    t
    r
    l
    .
    a
    d
    d
    I
    t
    e
    m
    '
    , f
    u
    n
    c
    t
    i
    o
    n (
    ) {
    i
    t
    (
    '
    s
    h
    o
    u
    l
    d a
    d
    d a n
    e
    w i
    t
    e
    m t
    o t
    o
    d
    o
    I
    t
    e
    m
    s
    '
    , f
    u
    n
    c
    t
    i
    o
    n (
    ) {
    e
    x
    p
    e
    c
    t
    (
    t
    h
    i
    s
    .
    c
    t
    r
    l
    .
    t
    o
    d
    o
    I
    t
    e
    m
    s
    .
    l
    e
    n
    g
    t
    h
    )
    .
    t
    o
    B
    e
    (
    0
    )
    ;
    t
    h
    i
    s
    .
    c
    t
    r
    l
    .
    a
    d
    d
    I
    t
    e
    m
    (
    {
    n
    a
    m
    e
    : '
    N
    e
    w T
    o D
    o I
    t
    e
    m
    '
    }
    )
    ;
    e
    x
    p
    e
    c
    t
    (
    t
    h
    i
    s
    .
    c
    t
    r
    l
    .
    t
    o
    d
    o
    I
    t
    e
    m
    s
    )
    .
    t
    o
    E
    q
    u
    a
    l
    (
    [
    {
    n
    a
    m
    e
    : '
    N
    e
    w T
    o D
    o I
    t
    e
    m
    '
    }
    ]
    )
    }
    )
    ;
    }
    )
    ;

    View Slide

  32. Add the new function…
    t
    h
    i
    s
    .
    a
    d
    d
    I
    t
    e
    m = f
    u
    n
    c
    t
    i
    o
    n (
    n
    e
    w
    I
    t
    e
    m
    ) {
    t
    h
    i
    s
    .
    t
    o
    d
    o
    I
    t
    e
    m
    s
    .
    p
    u
    s
    h
    (
    n
    e
    w
    I
    t
    e
    m
    )
    ;
    }
    ;
    And we

    re green again
    .

    View Slide

  33. Do the same for Edit…
    i
    t
    (
    '
    s
    h
    o
    u
    l
    d t
    o
    g
    g
    l
    e t
    h
    e i
    t
    e
    m s
    t
    a
    t
    e
    '
    , f
    u
    n
    c
    t
    i
    o
    n (
    ) {
    v
    a
    r t
    o
    g
    g
    l
    e
    C
    o
    m
    p
    l
    e
    t
    e = t
    h
    i
    s
    .
    c
    t
    r
    l
    .
    t
    o
    g
    g
    l
    e
    C
    o
    m
    p
    l
    e
    t
    e
    ;
    t
    h
    i
    s
    .
    c
    t
    r
    l
    .
    t
    o
    d
    o
    I
    t
    e
    m
    s
    .
    f
    o
    r
    E
    a
    c
    h
    (
    f
    u
    n
    c
    t
    i
    o
    n (
    i
    t
    e
    m
    ) {
    t
    o
    g
    g
    l
    e
    C
    o
    m
    p
    l
    e
    t
    e
    (
    i
    t
    e
    m
    )
    ;
    }
    )
    ;
    e
    x
    p
    e
    c
    t
    (
    t
    h
    i
    s
    .
    c
    t
    r
    l
    .
    t
    o
    d
    o
    I
    t
    e
    m
    s
    [
    0
    ]
    .
    c
    o
    m
    p
    l
    e
    t
    e
    )
    .
    t
    o
    B
    e
    T
    r
    u
    t
    h
    y
    (
    )
    ;
    e
    x
    p
    e
    c
    t
    (
    t
    h
    i
    s
    .
    c
    t
    r
    l
    .
    t
    o
    d
    o
    I
    t
    e
    m
    s
    [
    1
    ]
    .
    c
    o
    m
    p
    l
    e
    t
    e
    )
    .
    t
    o
    B
    e
    F
    a
    l
    s
    y
    (
    )
    ;
    t
    h
    i
    s
    .
    c
    t
    r
    l
    .
    t
    o
    d
    o
    I
    t
    e
    m
    s
    .
    f
    o
    r
    E
    a
    c
    h
    (
    f
    u
    n
    c
    t
    i
    o
    n (
    i
    t
    e
    m
    ) {
    t
    o
    g
    g
    l
    e
    C
    o
    m
    p
    l
    e
    t
    e
    (
    i
    t
    e
    m
    )
    ;
    }
    )
    ;
    e
    x
    p
    e
    c
    t
    (
    t
    h
    i
    s
    .
    c
    t
    r
    l
    .
    t
    o
    d
    o
    I
    t
    e
    m
    s
    [
    0
    ]
    .
    c
    o
    m
    p
    l
    e
    t
    e
    )
    .
    t
    o
    B
    e
    F
    a
    l
    s
    y
    (
    )
    ;
    e
    x
    p
    e
    c
    t
    (
    t
    h
    i
    s
    .
    c
    t
    r
    l
    .
    t
    o
    d
    o
    I
    t
    e
    m
    s
    [
    1
    ]
    .
    c
    o
    m
    p
    l
    e
    t
    e
    )
    .
    t
    o
    B
    e
    T
    r
    u
    t
    h
    y
    (
    )
    ;
    }
    )
    ;

    View Slide

  34. Edit is more complicated, so check other
    cases as well
    i
    t
    (
    '
    s
    h
    o
    u
    l
    d c
    r
    e
    a
    t
    e a s
    t
    a
    t
    e i
    f n
    o
    n
    e e
    x
    i
    s
    t
    s
    '
    , f
    u
    n
    c
    t
    i
    o
    n (
    ) {
    v
    a
    r i
    t
    e
    m
    s = t
    h
    i
    s
    .
    c
    t
    r
    l
    .
    t
    o
    d
    o
    I
    t
    e
    m
    s
    ;
    t
    h
    i
    s
    .
    c
    t
    r
    l
    .
    t
    o
    d
    o
    I
    t
    e
    m
    s
    .
    p
    u
    s
    h
    (
    {
    n
    a
    m
    e
    : '
    N
    o c
    o
    m
    p
    l
    e
    t
    e p
    r
    o
    p
    e
    r
    t
    y
    '
    }
    )
    ;
    v
    a
    r i
    t
    e
    m = i
    t
    e
    m
    s
    [
    i
    t
    e
    m
    s
    .
    l
    e
    n
    g
    t
    h - 1
    ]
    ;
    e
    x
    p
    e
    c
    t
    (
    i
    t
    e
    m
    .
    c
    o
    m
    p
    l
    e
    t
    e
    )
    .
    t
    o
    B
    e
    U
    n
    d
    e
    f
    i
    n
    e
    d
    (
    )
    ;
    t
    h
    i
    s
    .
    c
    t
    r
    l
    .
    t
    o
    g
    g
    l
    e
    C
    o
    m
    p
    l
    e
    t
    e
    (
    i
    t
    e
    m
    )
    ;
    e
    x
    p
    e
    c
    t
    (
    i
    t
    e
    m
    .
    c
    o
    m
    p
    l
    e
    t
    e
    )
    .
    t
    o
    B
    e
    T
    r
    u
    t
    h
    y
    (
    )
    ;
    }
    )
    ;
    /
    / .
    .
    . o
    t
    h
    e
    r t
    e
    s
    t
    s .
    .
    .

    View Slide

  35. t
    h
    i
    s
    .
    t
    o
    g
    g
    l
    e
    C
    o
    m
    p
    l
    e
    t
    e = f
    u
    n
    c
    t
    i
    o
    n (
    i
    t
    e
    m
    ) {
    i
    t
    e
    m
    .
    c
    o
    m
    p
    l
    e
    t
    e = !
    i
    t
    e
    m
    .
    c
    o
    m
    p
    l
    e
    t
    e
    ;
    }
    ;

    View Slide

  36. …and Delete
    d
    e
    s
    c
    r
    i
    b
    e
    (
    '
    c
    t
    r
    l
    .
    d
    e
    l
    e
    t
    e
    I
    t
    e
    m
    '
    , f
    u
    n
    c
    t
    i
    o
    n (
    ) {
    i
    t
    (
    '
    s
    h
    o
    u
    l
    d r
    e
    m
    o
    v
    e t
    h
    e i
    t
    e
    m
    '
    , f
    u
    n
    c
    t
    i
    o
    n (
    ) {
    v
    a
    r i = 0
    ,
    a
    d
    d
    I
    t
    e
    m = t
    h
    i
    s
    .
    c
    t
    r
    l
    .
    a
    d
    d
    I
    t
    e
    m
    ,
    i
    t
    e
    m
    s = [
    {
    n
    a
    m
    e
    : '
    F
    i
    r
    s
    t I
    t
    e
    m
    '
    }
    , {
    n
    a
    m
    e
    : '
    S
    e
    c
    o
    n
    d I
    t
    e
    m
    '
    }
    ]
    ;
    w
    h
    i
    l
    e (
    i <
    = 3
    ) {
    a
    d
    d
    I
    t
    e
    m
    (
    i
    t
    e
    m
    s
    [
    i
    ]
    )
    ; i
    +
    +
    ;
    }
    t
    h
    i
    s
    .
    c
    t
    r
    l
    .
    d
    e
    l
    e
    t
    e
    I
    t
    e
    m
    (
    1
    )
    ;
    e
    x
    p
    e
    c
    t
    (
    t
    h
    i
    s
    .
    c
    t
    r
    l
    .
    t
    o
    d
    o
    I
    t
    e
    m
    s
    )
    .
    t
    o
    E
    q
    u
    a
    l
    (
    [
    i
    t
    e
    m
    s
    [
    0
    ]
    ]
    )
    ;
    }
    )
    ;
    }
    )
    ;

    View Slide

  37. t
    h
    i
    s
    .
    d
    e
    l
    e
    t
    e
    I
    t
    e
    m = f
    u
    n
    c
    t
    i
    o
    n (
    i
    n
    d
    e
    x
    ) {
    c
    t
    r
    l
    .
    t
    o
    d
    o
    I
    t
    e
    m
    s
    .
    s
    p
    l
    i
    c
    e
    (
    i
    n
    d
    e
    x
    , 1
    )
    ;
    }
    ;

    View Slide

  38. Building the Service
    Using ngResource
    , this is fairly straightforward
    .

    View Slide

  39. The test setup
    d
    e
    s
    c
    r
    i
    b
    e
    (
    '
    T
    o
    D
    o
    S
    e
    r
    v
    i
    c
    e
    '
    , f
    u
    n
    c
    t
    i
    o
    n (
    ) {
    b
    e
    f
    o
    r
    e
    E
    a
    c
    h
    (
    f
    u
    n
    c
    t
    i
    o
    n (
    ) {
    m
    o
    d
    u
    l
    e
    (
    '
    t
    o
    d
    o
    A
    p
    p
    .
    s
    e
    r
    v
    i
    c
    e
    s
    '
    )
    ;
    i
    n
    j
    e
    c
    t
    (
    f
    u
    n
    c
    t
    i
    o
    n (
    $
    h
    t
    t
    p
    B
    a
    c
    k
    e
    n
    d
    , $
    i
    n
    j
    e
    c
    t
    o
    r
    ) {
    t
    h
    i
    s
    .
    t
    o
    d
    o = $
    i
    n
    j
    e
    c
    t
    o
    r
    .
    g
    e
    t
    (
    '
    T
    o
    D
    o
    '
    )
    ;
    t
    h
    i
    s
    .
    h
    t
    t
    p
    B
    a
    c
    k
    e
    n
    d = $
    h
    t
    t
    p
    B
    a
    c
    k
    e
    n
    d
    ;
    }
    )
    ;
    }
    )
    ;
    }
    )
    ;

    View Slide

  40. A couple of tests
    /
    / I
    n t
    h
    a
    t d
    e
    s
    c
    r
    i
    b
    e b
    l
    o
    c
    k
    i
    t
    (
    '
    s
    h
    o
    u
    l
    d h
    a
    v
    e C
    R
    U
    D c
    l
    a
    s
    s m
    e
    t
    h
    o
    d
    s
    '
    , f
    u
    n
    c
    t
    i
    o
    n (
    ) {
    e
    x
    p
    e
    c
    t
    (
    t
    h
    i
    s
    .
    t
    o
    d
    o
    .
    g
    e
    t
    )
    .
    t
    o
    B
    e
    D
    e
    f
    i
    n
    e
    d
    (
    )
    ; /
    / f
    o
    r i
    n
    d
    i
    v
    i
    d
    u
    a
    l i
    t
    e
    m
    e
    x
    p
    e
    c
    t
    (
    t
    h
    i
    s
    .
    t
    o
    d
    o
    .
    q
    u
    e
    r
    y
    )
    .
    t
    o
    B
    e
    D
    e
    f
    i
    n
    e
    d
    (
    )
    ; /
    / f
    o
    r a
    l
    l i
    t
    e
    m
    s
    e
    x
    p
    e
    c
    t
    (
    t
    h
    i
    s
    .
    t
    o
    d
    o
    .
    s
    a
    v
    e
    )
    .
    t
    o
    B
    e
    D
    e
    f
    i
    n
    e
    d
    (
    )
    ; /
    / c
    r
    e
    a
    t
    e
    }
    )
    ;
    i
    t
    (
    '
    s
    h
    o
    u
    l
    d h
    a
    v
    e C
    R
    U
    D i
    n
    s
    t
    a
    n
    c
    e m
    e
    t
    h
    o
    d
    s
    '
    , f
    u
    n
    c
    t
    i
    o
    n (
    ) {
    v
    a
    r t
    o
    d
    o = n
    e
    w t
    h
    i
    s
    .
    t
    o
    d
    o
    (
    )
    ;
    e
    x
    p
    e
    c
    t
    (
    t
    o
    d
    o
    .
    $
    s
    a
    v
    e
    )
    .
    t
    o
    B
    e
    D
    e
    f
    i
    n
    e
    d
    (
    )
    ; /
    / u
    p
    d
    a
    t
    e
    e
    x
    p
    e
    c
    t
    (
    t
    o
    d
    o
    .
    $
    d
    e
    l
    e
    t
    e
    )
    .
    t
    o
    B
    e
    D
    e
    f
    i
    n
    e
    d
    (
    )
    ; /
    / d
    e
    l
    e
    t
    e
    e
    x
    p
    e
    c
    t
    (
    t
    o
    d
    o
    .
    $
    r
    e
    m
    o
    v
    e
    )
    .
    t
    o
    B
    e
    D
    e
    f
    i
    n
    e
    d
    (
    )
    ; /
    / a
    l
    i
    a
    s f
    o
    r d
    e
    l
    e
    t
    e
    }
    )
    ;

    View Slide

  41. Changes to the application
    a
    n
    g
    u
    l
    a
    r
    .
    m
    o
    d
    u
    l
    e
    (
    '
    t
    o
    d
    o
    A
    p
    p
    .
    s
    e
    r
    v
    i
    c
    e
    s
    '
    , [
    '
    n
    g
    R
    e
    s
    o
    u
    r
    c
    e
    '
    ]
    )
    .
    f
    a
    c
    t
    o
    r
    y
    (
    '
    T
    o
    D
    o
    '
    , f
    u
    n
    c
    t
    i
    o
    n (
    $
    r
    e
    s
    o
    u
    r
    c
    e
    ) {
    r
    e
    t
    u
    r
    n $
    r
    e
    s
    o
    u
    r
    c
    e
    (
    '
    /
    t
    o
    d
    o
    s
    /
    a
    p
    i
    /
    :
    i
    d
    '
    )
    ;
    }
    )
    ;

    View Slide

  42. Using $httpBackend
    Provided by the ngMock module
    (
    filename is
    angular
    -
    mocks
    )
    Makes it so you don

    t need a backend to run tests
    (
    a
    good thing
    )
    Will watch for requests and return responses

    View Slide

  43. When do I need it?
    The most obvious is when you see errors that look
    like this
    :
    i
    t
    (
    '
    s
    h
    o
    u
    l
    d q
    u
    e
    r
    y f
    r
    o
    m /
    t
    o
    d
    o
    s
    /
    a
    p
    i
    '
    , f
    u
    n
    c
    t
    i
    o
    n (
    ) {
    t
    h
    i
    s
    .
    t
    o
    d
    o
    .
    q
    u
    e
    r
    y
    (
    )
    ; /
    / c
    a
    u
    s
    e
    d t
    h
    e e
    r
    r
    o
    r
    }
    )
    ;

    View Slide

  44. $httpBackend test
    i
    t
    (
    '
    s
    h
    o
    u
    l
    d q
    u
    e
    r
    y f
    r
    o
    m /
    t
    o
    d
    o
    s
    /
    a
    p
    i
    '
    , f
    u
    n
    c
    t
    i
    o
    n (
    ) {
    t
    h
    i
    s
    .
    h
    t
    t
    p
    B
    a
    c
    k
    e
    n
    d
    .
    e
    x
    p
    e
    c
    t
    G
    E
    T
    (
    '
    /
    t
    o
    d
    o
    s
    /
    a
    p
    i
    '
    )
    .
    r
    e
    s
    p
    o
    n
    d
    (
    [
    ]
    )
    ; /
    / m
    u
    s
    t r
    e
    t
    u
    r
    n *
    s
    o
    m
    e
    t
    h
    i
    n
    g
    *
    t
    h
    i
    s
    .
    t
    o
    d
    o
    .
    q
    u
    e
    r
    y
    (
    )
    ;
    t
    h
    i
    s
    .
    h
    t
    t
    p
    B
    a
    c
    k
    e
    n
    d
    .
    f
    l
    u
    s
    h
    (
    )
    ;
    }
    )
    ;

    View Slide

  45. Integrate the service
    Time to hook everything together
    !

    View Slide

  46. Update the test con g
    /
    / i
    n t
    e
    s
    t
    /
    c
    o
    n
    t
    r
    o
    l
    l
    e
    r
    _
    s
    p
    e
    c
    .
    j
    s
    i
    n
    j
    e
    c
    t
    (
    f
    u
    n
    c
    t
    i
    o
    n
    (
    $
    c
    o
    n
    t
    r
    o
    l
    l
    e
    r
    , $
    r
    o
    o
    t
    S
    c
    o
    p
    e
    , $
    h
    t
    t
    p
    B
    a
    c
    k
    e
    n
    d
    , $
    i
    n
    j
    e
    c
    t
    o
    r
    ) {
    /
    / .
    .
    . o
    t
    h
    e
    r i
    n
    j
    e
    c
    t
    i
    o
    n
    s
    t
    h
    i
    s
    .
    t
    o
    d
    o
    B
    a
    c
    k
    e
    n
    d = $
    i
    n
    j
    e
    c
    t
    o
    r
    .
    g
    e
    t
    (
    '
    T
    o
    D
    o
    '
    )
    ;
    t
    h
    i
    s
    .
    h
    t
    t
    p
    B
    a
    c
    k
    e
    n
    d = $
    h
    t
    t
    p
    B
    a
    c
    k
    e
    n
    d
    ;
    }
    )
    ;

    View Slide

  47. Set up the test
    d
    e
    s
    c
    r
    i
    b
    e
    (
    '
    c
    t
    r
    l
    .
    a
    d
    d
    I
    t
    e
    m
    '
    , f
    u
    n
    c
    t
    i
    o
    n (
    ) {
    b
    e
    f
    o
    r
    e
    E
    a
    c
    h
    (
    f
    u
    n
    c
    t
    i
    o
    n (
    ) {
    t
    h
    i
    s
    .
    i
    t
    e
    m = {
    n
    a
    m
    e
    : '
    N
    e
    w T
    o D
    o I
    t
    e
    m
    '
    }
    ;
    s
    p
    y
    O
    n
    (
    t
    h
    i
    s
    .
    t
    o
    d
    o
    B
    a
    c
    k
    e
    n
    d
    .
    p
    r
    o
    t
    o
    t
    y
    p
    e
    , '
    $
    s
    a
    v
    e
    '
    )
    .
    a
    n
    d
    .
    c
    a
    l
    l
    T
    h
    r
    o
    u
    g
    h
    (
    )
    ;
    t
    h
    i
    s
    .
    h
    t
    t
    p
    B
    a
    c
    k
    e
    n
    d
    .
    w
    h
    e
    n
    P
    O
    S
    T
    (
    /
    t
    o
    d
    o
    s
    \
    /
    a
    p
    i
    \
    ?
    .
    *
    /
    )
    .
    r
    e
    s
    p
    o
    n
    d
    (
    t
    h
    i
    s
    .
    i
    t
    e
    m
    )
    ;
    }
    )
    ;

    View Slide

  48. Test the service call
    i
    t
    (
    '
    s
    h
    o
    u
    l
    d s
    a
    v
    e t
    o t
    h
    e T
    o
    D
    o s
    e
    r
    v
    i
    c
    e
    '
    , f
    u
    n
    c
    t
    i
    o
    n (
    ) {
    t
    h
    i
    s
    .
    c
    t
    r
    l
    .
    a
    d
    d
    I
    t
    e
    m
    (
    {
    n
    a
    m
    e
    : '
    N
    e
    w T
    o D
    o I
    t
    e
    m
    '
    }
    )
    ;
    e
    x
    p
    e
    c
    t
    (
    t
    h
    i
    s
    .
    t
    o
    d
    o
    B
    a
    c
    k
    e
    n
    d
    .
    p
    r
    o
    t
    o
    t
    y
    p
    e
    .
    $
    s
    a
    v
    e
    )
    .
    t
    o
    H
    a
    v
    e
    B
    e
    e
    n
    C
    a
    l
    l
    e
    d
    W
    i
    t
    h
    (
    t
    h
    i
    s
    .
    i
    t
    e
    m
    , j
    a
    s
    m
    i
    n
    e
    .
    a
    n
    y
    (
    F
    u
    n
    c
    t
    i
    o
    n
    )
    )
    ;
    }
    )
    ;

    View Slide

  49. Write the test
    i
    t
    (
    '
    s
    h
    o
    u
    l
    d s
    a
    v
    e t
    o t
    h
    e T
    o
    D
    o s
    e
    r
    v
    i
    c
    e
    '
    , f
    u
    n
    c
    t
    i
    o
    n (
    ) {
    e
    x
    p
    e
    c
    t
    (
    t
    h
    i
    s
    .
    c
    t
    r
    l
    .
    t
    o
    d
    o
    I
    t
    e
    m
    s
    .
    l
    e
    n
    g
    t
    h
    )
    .
    t
    o
    B
    e
    (
    0
    )
    ;
    t
    h
    i
    s
    .
    c
    t
    r
    l
    .
    a
    d
    d
    I
    t
    e
    m
    (
    t
    h
    i
    s
    .
    i
    t
    e
    m
    )
    ;
    t
    h
    i
    s
    .
    h
    t
    t
    p
    B
    a
    c
    k
    e
    n
    d
    .
    f
    l
    u
    s
    h
    (
    )
    ;
    e
    x
    p
    e
    c
    t
    (
    t
    h
    i
    s
    .
    c
    t
    r
    l
    .
    t
    o
    d
    o
    I
    t
    e
    m
    s
    .
    l
    e
    n
    g
    t
    h
    )
    .
    t
    o
    B
    e
    (
    1
    )
    ;
    e
    x
    p
    e
    c
    t
    (
    t
    h
    i
    s
    .
    c
    t
    r
    l
    .
    t
    o
    d
    o
    I
    t
    e
    m
    s
    [
    0
    ]
    .
    n
    a
    m
    e
    )
    .
    t
    o
    B
    e
    (
    t
    h
    i
    s
    .
    i
    t
    e
    m
    .
    n
    a
    m
    e
    )
    ;
    }
    )
    ;
    }
    )
    ; /
    / e
    n
    d o
    f d
    e
    s
    c
    r
    i
    b
    e
    (
    '
    c
    t
    r
    l
    .
    a
    d
    d
    I
    t
    e
    m
    '
    )
    ;

    View Slide

  50. Update the controller
    /
    / A
    t t
    h
    e t
    o
    p o
    f t
    h
    e c
    o
    n
    t
    r
    o
    l
    l
    e
    r
    a
    n
    g
    u
    l
    a
    r
    .
    m
    o
    d
    u
    l
    e
    (
    '
    t
    o
    d
    o
    A
    p
    p
    .
    c
    o
    n
    t
    r
    o
    l
    l
    e
    r
    s
    '
    , [
    '
    t
    o
    d
    o
    A
    p
    p
    .
    s
    e
    r
    v
    i
    c
    e
    s
    '
    ]
    )
    .
    c
    o
    n
    t
    r
    o
    l
    l
    e
    r
    (
    '
    T
    o
    D
    o
    A
    p
    p
    C
    o
    n
    t
    r
    o
    l
    l
    e
    r
    '
    , f
    u
    n
    c
    t
    i
    o
    n (
    $
    s
    c
    o
    p
    e
    , T
    o
    D
    o
    ) {
    The controller is dependent on the services
    , so we
    tell Angular about that
    , then load load the service

    View Slide

  51. Update the method
    t
    h
    i
    s
    .
    a
    d
    d
    I
    t
    e
    m = f
    u
    n
    c
    t
    i
    o
    n (
    n
    e
    w
    I
    t
    e
    m
    ) {
    v
    a
    r i
    t
    e
    m = n
    e
    w T
    o
    D
    o
    (
    )
    ;
    i
    t
    e
    m
    .
    $
    s
    a
    v
    e
    (
    n
    e
    w
    I
    t
    e
    m
    , f
    u
    n
    c
    t
    i
    o
    n (
    ) {
    c
    t
    r
    l
    .
    t
    o
    d
    o
    I
    t
    e
    m
    s
    .
    p
    u
    s
    h
    (
    i
    t
    e
    m
    )
    ;
    }
    )
    ;
    }
    ;

    View Slide

  52. E2E with Protractor

    View Slide

  53. Install Protractor
    $ n
    p
    m i
    n
    s
    t
    a
    l
    l -
    -
    s
    a
    v
    e
    -
    d
    e
    v p
    r
    o
    t
    r
    a
    c
    t
    o
    r
    $ n
    o
    d
    e
    _
    m
    o
    d
    u
    l
    e
    s
    /
    p
    r
    o
    t
    r
    a
    c
    t
    o
    r
    /
    b
    i
    n
    /
    w
    e
    b
    d
    r
    i
    v
    e
    r
    -
    m
    a
    n
    a
    g
    e
    r u
    p
    d
    a
    t
    e
    $ m
    k
    d
    i
    r e
    2
    e

    View Slide

  54. Con gure Protractor
    Create an e
    2e
    .conf
    .js file and add
    e
    x
    p
    o
    r
    t
    s
    .
    c
    o
    n
    f
    i
    g = {
    s
    e
    l
    e
    n
    i
    u
    m
    A
    d
    d
    r
    e
    s
    s
    : '
    h
    t
    t
    p
    :
    /
    /
    l
    o
    c
    a
    l
    h
    o
    s
    t
    :
    4
    4
    4
    4
    /
    w
    d
    /
    h
    u
    b
    '
    ,
    s
    p
    e
    c
    s
    : [
    '
    e
    2
    e
    /
    s
    p
    e
    c
    .
    j
    s
    '
    ]
    }
    ;

    View Slide

  55. Add a test
    /
    / i
    n e
    2
    e
    /
    s
    p
    e
    c
    .
    j
    s
    d
    e
    s
    c
    r
    i
    b
    e
    (
    '
    h
    o
    m
    e
    p
    a
    g
    e
    '
    , f
    u
    n
    c
    t
    i
    o
    n
    (
    ) {
    i
    t
    (
    '
    s
    h
    o
    u
    l
    d h
    a
    v
    e a t
    i
    t
    l
    e
    '
    , f
    u
    n
    c
    t
    i
    o
    n
    (
    ) {
    b
    r
    o
    w
    s
    e
    r
    .
    g
    e
    t
    (
    '
    h
    t
    t
    p
    :
    /
    /
    l
    o
    c
    a
    l
    h
    o
    s
    t
    :
    8
    0
    0
    0
    /
    i
    n
    d
    e
    x
    .
    h
    t
    m
    l
    '
    )
    ;
    e
    x
    p
    e
    c
    t
    (
    b
    r
    o
    w
    s
    e
    r
    .
    g
    e
    t
    T
    i
    t
    l
    e
    (
    )
    )
    .
    t
    o
    E
    q
    u
    a
    l
    (
    '
    T
    o
    D
    o T
    D
    D
    '
    )
    ;
    }
    )
    ;
    }
    )
    ;

    View Slide

  56. Run the servers
    In multiple terminal windows
    (
    yeah
    , it

    s awkward
    ):
    $ n
    o
    d
    e
    _
    m
    o
    d
    u
    l
    e
    s
    /
    p
    r
    o
    t
    r
    a
    c
    t
    o
    r
    /
    b
    i
    n
    /
    w
    e
    b
    d
    r
    i
    v
    e
    r
    -
    m
    a
    n
    a
    g
    e
    r s
    t
    a
    r
    t
    and
    # t
    h
    i
    s c
    a
    n b
    e r
    e
    p
    l
    a
    c
    e
    d b
    y a
    n
    y o
    t
    h
    e
    r s
    e
    r
    v
    e
    r
    ,
    # b
    u
    t o
    u
    r a
    p
    p d
    o
    e
    s
    n
    '
    t h
    a
    v
    e a w
    e
    b s
    e
    r
    v
    e
    r
    $ p
    y
    t
    h
    o
    n -
    m S
    i
    m
    p
    l
    e
    H
    T
    T
    P
    S
    e
    r
    v
    e
    r

    View Slide

  57. If you feel like this

    Don

    t worry
    , you

    re not alone
    .

    View Slide

  58. Run the test ( nally)
    $ n
    o
    d
    e
    _
    m
    o
    d
    u
    l
    e
    s
    /
    p
    r
    o
    t
    r
    a
    c
    t
    o
    r
    /
    b
    i
    n
    /
    p
    r
    o
    t
    r
    a
    c
    t
    o
    r e
    2
    e
    .
    c
    o
    n
    f
    .
    j
    s

    View Slide

  59. Protractor usage
    Uses the existing test framework
    Has some additional helper methods and global
    variables
    :
    b
    r
    o
    w
    s
    e
    r
    p
    r
    o
    t
    r
    a
    c
    t
    o
    r
    e
    l
    e
    m
    e
    n
    t
    b
    y
    Can do DOM traversal

    View Slide

  60. Resources
    by Evan Hahn
    Jasmine

    s Documentation
    :
    Angular

    s Tutorial
    :
    Protractor Tutorial
    :
    JavaScript T
    esting with Jasmine
    : JavaScript
    Behavior
    -
    Driven Development
    jasmine
    .github
    .io
    /2.0/
    introduction
    .html
    https
    ://
    docs
    .angularjs
    .org
    /
    tutorial
    https
    ://
    github
    .com
    /
    angular
    /
    protractor
    /
    blob
    /
    master
    /
    docs
    /
    tutorial
    .md

    View Slide

  61. Thank You
    Gracias Danke
    Merci
    谢谢
    ありがとう

    View Slide