Angular2 Component Test?

599 views
Skip to first unread message

Daniel

unread,
Dec 24, 2015, 1:35:50 PM12/24/15
to AngularJS
Hi,

I'm trying to find some information on how to best test a Component. I have a simple component that currently just looks like this.

@Component({
  selector: 'sortable',
  inputs: ['items'],
  template: `
    <div><a id="#test" (click)="sort()">sort</a></div>
    <ng-content></ng-content>
  `
})
export class Sortable {
  public items: any[]
  private reverse: boolean = false

  sort() {
    this.items.sort((a, b) => {
      if (a.name > b.name) {
        return this.reverse ? 1 : -1
      } else if (a.name < b.name) {
        return this.reverse ? -1: 1
      } else {
        return 0
      }
    })
    this.reverse = !this.reverse
  }
}

I've got Jasmine setup and working based on the guide from angular.io but haven't found much information on how to best test Components. One guide seems to be bootstrap:ing like a normal app so this is what I got so far going down that route.

import {Component, OnInit} from 'angular2/core'
import {bootstrap} from 'angular2/platform/browser'
import {Sortable} from '../sortable'

@Component({
  selector: 'test-app',
  directives: [Sortable],
  template: `
    <div>
      <sortable [items]="items">
        <div *ngFor="#item of items">{{item.name}}</div>
      </sortable>
    </div>
  `
})
class TestApp {
  public items: string[]

  constructor() {
    this.items = [{name: 'c'}, {name: 'a'}, {name: 'b'}]
  }
}

describe('Sortable', () => {
  let app: TestApp

  beforeEach(done => {
    bootstrap(TestApp)
      .then(result => result.instance)
      .then(instance => {
        app = instance
        done()
      })
  })

  it('#sort', () => {
    // How to generate click?
    expect(app.items).toEqual([{name: 'c'}, {name: 'b'}, {name: 'a'}])
  })
})

This feels strange since it actually renders on the Jasmine test page. Would really appreciate some input on how to best test a component such as this. I want to make sure it renders the list as well as the order of items when the sort method is run.

Thanks,
- Daniel


Daniel

unread,
Dec 25, 2015, 10:25:18 AM12/25/15
to AngularJS
Digging into the Angular2 source I've managed to get something like this... it feels very convoluted thought and I'm trying to find how to simplify it.

import {Component, OnInit} from 'angular2/core'
import {NgFor} from 'angular2/src/common/directives/ng_for'
import {bootstrap} from 'angular2/platform/browser'
import {Sortable} from '../sortable'

import {
  iit,
  it,
  ddescribe,
  describe,
  expect,
  injectAsync,
  TestComponentBuilder,
  beforeEachProviders
} from 'angular2/testing';

import {BrowserDomAdapter} from 'angular2/src/platform/browser/browser_adapter'
BrowserDomAdapter.makeCurrent()

@Component({
  directives: [NgFor, Sortable],
  template: `
    <div>
      <sortable [items]="items">
        <div *ngFor="#item of items">{{item.name}}</div>
      </sortable>
    </div>
  `
})
class TestApp {
  public items: any[]

  constructor() {
    this.items = [{name: 'c'}, {name: 'a'}, {name: 'b'}]
  }
}

describe('Sortable', () => {
  it('first spec', injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
    return tcb.createAsync(TestApp)
              .then((fixture) => {
                expect(true).toEqual(true)
    })
  }))

  it('second spec', injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
    return tcb.createAsync(TestApp)
              .then((fixture) => {
                expect(false).toEqual(false)
    })
  }))
})


Any ideas?

Manfred Steyer

unread,
Dec 25, 2015, 2:12:22 PM12/25/15
to AngularJS
Hi Daniel,

that looks great. Currently there are much resources about this topic. But there are two greate presentations from anguler-connect in London [1], [2] and the starter kit at [3] contains samples for some tests.

Wishes,

Daniel

unread,
Dec 26, 2015, 8:29:27 PM12/26/15
to AngularJS
Thanks Manfred,

I havent had a chance to look at the resources you provided yet, but I've made som progress. My current spec looks like this and I wanted to update this thread in case someone else is struggling.

import {Component, OnInit} from 'angular2/core'
import {NgFor} from 'angular2/src/common/directives/ng_for'
import {Sortable} from '../sortable'

import {
  it,
  describe,
  expect,
  injectAsync,
  TestComponentBuilder,
} from 'angular2/testing'

import {By} from 'angular2/platform/common_dom'

import {BrowserDomAdapter} from 'angular2/src/platform/browser/browser_adapter'
BrowserDomAdapter.makeCurrent()

@Component({
  directives: [NgFor, Sortable],
  template: `
    <div>
      <sortable [items]="items" keys="name, sz: Size">
        <div *ngFor="#item of items" class="item">{{item.name}}</div>
      </sortable>
    </div>
  `
})
class TestApp {
  public items: any[]

  constructor() {
    this.items = [{name:'c', sz:2}, {name:'a', sz:1}, {name:'b', sz:3}, {name:'d'}]
  }
}

var setupTestComponent = (fn) => injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
  return tcb.createAsync(TestApp).then((tc) => {
    tc.detectChanges()
    fn(tc)
  }
)})

describe('Sortable', () => {
  it('renders children elements', setupTestComponent((tc) => {
    var items = tc.nativeElement.querySelectorAll('.item')
    expect(items.length).toEqual(4)
    expect($(items).text()).toEqual('cabd')
  }))

  it('renders header links from keys', setupTestComponent((tc) => {
    var lis = tc.nativeElement.querySelectorAll('.sortable-header li')
    expect(lis.length).toEqual(2)
    expect($(lis).text()).toEqual('NameSize')
  }))

  it('sort on click (descending order)', setupTestComponent((tc) => {
    tc.debugElement.query(By.css('.sortable-header li')).triggerEventHandler('click', null)
    tc.detectChanges()

    var items = tc.nativeElement.querySelectorAll('.item')
    expect($(items).text()).toEqual('dcba')
  }))

  it('reverse order on each subsequent click', setupTestComponent((tc) => {
    tc.debugElement.query(By.css('.sortable-header li')).triggerEventHandler('click', null)
    tc.debugElement.query(By.css('.sortable-header li')).triggerEventHandler('click', null)
    tc.detectChanges()

    var items = tc.nativeElement.querySelectorAll('.item')
    expect($(items).text()).toEqual('abcd')
  }))
})


- Daniel

Manfred Steyer

unread,
Dec 31, 2015, 8:53:22 PM12/31/15
to AngularJS
Hi Daniel,

sorry, I wanted to say, that there are currently *NOT* many resources about testing. But perhaps the samples at [1] help you to find out, what you need. They also use the TestComponentBuilder in some cases.

Wishes,
Manfred

Reply all
Reply to author
Forward
0 new messages