Test like a pro
Mike North - Silicon Valley Ember.js Meetup - April 30, 2015
@MichaelLNorth2
Mike North
@MichaelLNorth
The Plan
3
Testing Basics
 Test types
 Test technology
Testing with Ember
 Test helpers
 Simulating an API
 Lessons learned @
Yahoo
Test Automation
 Continuous Integration
 Cross-Device testing
Testing Basics
@MichaelLNorth
Unit tests
5
Fast & Focused
Isolated
Excellent at testing
“algorithmic complexity”
Functional tests
(a.k.a. “acceptance tests)
Test behavior in context
Simulate user behavior
Often based on specs or
acceptance criteria
Integration tests
Ensure that contracts at
integration points stay in
place
NOT functional tests
“End to end test”
Check for multi-
component system
integrity
Usually very slow
@MichaelLNorth
Test types - how to test a….
6
Algorithm Unit Test
Acceptance Criteria Acceptance/Functional Test
Workflow Acceptance/Functional Test
Contract between two
components
Integration test
Total System Integrity “End to end” test
Testing with Ember
8
Testing with Ember - QUnit Modules
import Ember from 'ember';
import startApp from '../../tests/helpers/start-
app';
import { test } from 'ember-qunit';
var App;
module('Acceptance - Loader', {
beforeEach() { App = startApp(); },
afterEach() { Ember.run(App, 'destroy'); }
});
test("Load the page I'm testing", assert => {
visit('/loader');
assert.equal(Ember.$('.loader').length, 0,
'No loader showing');
click('.stop-loader-button');
andThen(() => {
assert.equal(Ember.$('.loader').length, 0,
'No loader showing');
});
});
per-test setup
and teardown
hooks
9
Testing with Ember - ember-test-helpers modules
moduleFor(name [, description [, callbacks]])
moduleForModel( … )
moduleForComponent( … )
• Setup an empty container to unit test in isolation
• Set context of view, so bindings work
moduleForComponent('my-tabs', {
needs: ['component:my-tab']
});
@MichaelLNorth
Testing with Ember - Integration Test Helpers
10
 visit(url)
 fillIn(selector, text)
 click(selector)
 keyEvent(sel, type, key)
 triggerEvent(sel, type, opts)
 find(selector, content)
 currentPath()
 currentRouteName()
 currentURL()
Async Sync
@MichaelLNorth
An example
11
Router.map(() => {
this.resource('lists', () => {
this.route('index', {path: '/'});
});
this.resource('list', {path: 'list/:id'}, () => {
this.route('show', {path: '/'});
});
});
router.js
@MichaelLNorth
Steps
Testing with Ember - Integration Test Helpers - Async
12
test('Drilling into a shopping list from the index page', assert => {
visit('/lists');
andThen(() => {
assert.equal(
currentURL(), ‘/lists',
'Should be at the index page’
);
assert.equal(
find('.list-of-lists .list-item').length, 2,
'Two shopping lists are in the index’
);
});
click('.list-of-lists .list-item:nth-child(1)');
andThen(() => {
assert.equal(currentURL(), ‘/list/1’,
'Showing the first shopping list’
);
});
console.log('Hello world!');
});
@MichaelLNorth
Testing with Ember - Simulating an API
13
trek/fakehr trek/pretender
• Resolve a pending request • Set up a fake “server”
/api/lines
/api/items?ids[]=1&ids[]=2&ids[]=3
"items": [
{"id": 1, "name": "Apple", "list": 1},
{"id": 2, "name": "Pear", "list": 1},
{"id": 3, "name": "Grape", "list": 1}
]
"lists": [
{"id": 1, "name": "Fruit", "items": [1, 2, 3]},
{"id": 2, "name": "Vegetables", "items": [4, 5, 6]}
]
@MichaelLNorth
Testing with Ember - Simulating an API
14
trek/fakehr trek/pretender
@MichaelLNorth
Testing with Ember - Simulating an API
15
/api/lines
/api/lines/1/items
trek/fakehr
Continuous Integration
@MichaelLNorth
Continuous Integration
17
Clone
Checkout
before_install
install
before_script
script
after_success after_failure
after_script
npm install; bower
install
ember test ci
setup phantomjs
2.0
mark PR
“ok”
mark PR
“failed”
@MichaelLNorth
Continuous Integration
w/ ember-try
18
kategengler/ember-try
env:
matrix:
- EMBER_TRY_SCENARIO=default
- EMBER_TRY_SCENARIO=ember-release
- EMBER_TRY_SCENARIO=ember-beta
- EMBER_TRY_SCENARIO=ember-canary
.travis.yml
matrix:
fast_finish: true
allow_failures:
- env: EMBER_TRY_SCENARIO=ember-canary
Build has passed, but this is still running!
@MichaelLNorth
Cross-Device Testing
w/ ember-cli-sauce
19
johanneswuerbach/ember-cli-sauce
@MichaelLNorth
Cross-Device Testing
w/ ember-cli-sauce
20
PROTIP: You may need to fiddle with
testem port and/or hostname to get OS X
working
{
"framework": "qunit",
"host": "lvh.me",
"port": "7000",
"test_page": "tests/index.html?hidepassed",
...
}
@MichaelLNorth21
$0
for open
source

Test like a pro with Ember.js

  • 1.
    Test like apro Mike North - Silicon Valley Ember.js Meetup - April 30, 2015
  • 2.
  • 3.
    @MichaelLNorth The Plan 3 Testing Basics Test types  Test technology Testing with Ember  Test helpers  Simulating an API  Lessons learned @ Yahoo Test Automation  Continuous Integration  Cross-Device testing
  • 4.
  • 5.
    @MichaelLNorth Unit tests 5 Fast &Focused Isolated Excellent at testing “algorithmic complexity” Functional tests (a.k.a. “acceptance tests) Test behavior in context Simulate user behavior Often based on specs or acceptance criteria Integration tests Ensure that contracts at integration points stay in place NOT functional tests “End to end test” Check for multi- component system integrity Usually very slow
  • 6.
    @MichaelLNorth Test types -how to test a…. 6 Algorithm Unit Test Acceptance Criteria Acceptance/Functional Test Workflow Acceptance/Functional Test Contract between two components Integration test Total System Integrity “End to end” test
  • 7.
  • 8.
    8 Testing with Ember- QUnit Modules import Ember from 'ember'; import startApp from '../../tests/helpers/start- app'; import { test } from 'ember-qunit'; var App; module('Acceptance - Loader', { beforeEach() { App = startApp(); }, afterEach() { Ember.run(App, 'destroy'); } }); test("Load the page I'm testing", assert => { visit('/loader'); assert.equal(Ember.$('.loader').length, 0, 'No loader showing'); click('.stop-loader-button'); andThen(() => { assert.equal(Ember.$('.loader').length, 0, 'No loader showing'); }); }); per-test setup and teardown hooks
  • 9.
    9 Testing with Ember- ember-test-helpers modules moduleFor(name [, description [, callbacks]]) moduleForModel( … ) moduleForComponent( … ) • Setup an empty container to unit test in isolation • Set context of view, so bindings work moduleForComponent('my-tabs', { needs: ['component:my-tab'] });
  • 10.
    @MichaelLNorth Testing with Ember- Integration Test Helpers 10  visit(url)  fillIn(selector, text)  click(selector)  keyEvent(sel, type, key)  triggerEvent(sel, type, opts)  find(selector, content)  currentPath()  currentRouteName()  currentURL() Async Sync
  • 11.
    @MichaelLNorth An example 11 Router.map(() =>{ this.resource('lists', () => { this.route('index', {path: '/'}); }); this.resource('list', {path: 'list/:id'}, () => { this.route('show', {path: '/'}); }); }); router.js
  • 12.
    @MichaelLNorth Steps Testing with Ember- Integration Test Helpers - Async 12 test('Drilling into a shopping list from the index page', assert => { visit('/lists'); andThen(() => { assert.equal( currentURL(), ‘/lists', 'Should be at the index page’ ); assert.equal( find('.list-of-lists .list-item').length, 2, 'Two shopping lists are in the index’ ); }); click('.list-of-lists .list-item:nth-child(1)'); andThen(() => { assert.equal(currentURL(), ‘/list/1’, 'Showing the first shopping list’ ); }); console.log('Hello world!'); });
  • 13.
    @MichaelLNorth Testing with Ember- Simulating an API 13 trek/fakehr trek/pretender • Resolve a pending request • Set up a fake “server” /api/lines /api/items?ids[]=1&ids[]=2&ids[]=3 "items": [ {"id": 1, "name": "Apple", "list": 1}, {"id": 2, "name": "Pear", "list": 1}, {"id": 3, "name": "Grape", "list": 1} ] "lists": [ {"id": 1, "name": "Fruit", "items": [1, 2, 3]}, {"id": 2, "name": "Vegetables", "items": [4, 5, 6]} ]
  • 14.
    @MichaelLNorth Testing with Ember- Simulating an API 14 trek/fakehr trek/pretender
  • 15.
    @MichaelLNorth Testing with Ember- Simulating an API 15 /api/lines /api/lines/1/items trek/fakehr
  • 16.
  • 17.
  • 18.
    @MichaelLNorth Continuous Integration w/ ember-try 18 kategengler/ember-try env: matrix: -EMBER_TRY_SCENARIO=default - EMBER_TRY_SCENARIO=ember-release - EMBER_TRY_SCENARIO=ember-beta - EMBER_TRY_SCENARIO=ember-canary .travis.yml matrix: fast_finish: true allow_failures: - env: EMBER_TRY_SCENARIO=ember-canary Build has passed, but this is still running!
  • 19.
  • 20.
    @MichaelLNorth Cross-Device Testing w/ ember-cli-sauce 20 PROTIP:You may need to fiddle with testem port and/or hostname to get OS X working { "framework": "qunit", "host": "lvh.me", "port": "7000", "test_page": "tests/index.html?hidepassed", ... }
  • 21.