@Bryntum
Unit and UI Testing Your Ext JS Web
Applications with Siesta
Slide 2
Slide 2 text
Mats Bryntse
Founder, Bryntum
Stockholm, Sweden
Slide 3
Slide 3 text
3
•Team of Sencha community members since 2007
•Powerful Gantt & Scheduling charts for Ext JS
•Testing and monitoring tools
•Training / Consulting
•2000+ clients in 70+ countries
Slide 4
Slide 4 text
Agenda
4
Siesta Intro UI tests
•Feature walkthrough
•Writing good tests
•Basic unit test
•Using PhantomJS
•Application tests
•Recorder
•Continuous Integration
•Simulating actions
•Testing a view
•Custom Test Class
Application tests
Slide 5
Slide 5 text
Siesta Introduction
Slide 6
Slide 6 text
6
Slide 7
Slide 7 text
7
• Siesta handles Unit, UI + Application testing all in one tool
• Tests any JS code base
• Siesta is web based, extensible
• Special testing layer for Ext JS
Overview
Slide 8
Slide 8 text
8
• Tests are written in JS in “plain” style or BDD
• Tests run completely isolated in iframes
• Powerful event recorder
• Code coverage
• You can extend Siesta and add own assertions or helper methods
Test features
Slide 9
Slide 9 text
9
• Report generation (HTML, JSON, XML)
• Integrates easily with TeamCity, Jenkins, and more
• Integrates with cloud testing provides such as Sauce
• Supports parallel test execution
Automation features
Slide 10
Slide 10 text
Unit Tests
Red, Green, Refactor
Slide 11
Slide 11 text
11
Terminology:
What does testing mean for a JS developer?
Slide 12
Slide 12 text
12
Unit tests, UI tests, Application tests..?
Slide 13
Slide 13 text
Ideal Test Pyramid
13
JS Unit tests
App Tests
View tests
Slide 14
Slide 14 text
Real World
14
Backend unit tests
App Tests
Slide 15
Slide 15 text
A unit test
• should focus on a single JS class (“unit”)
• should not involve DOM
• is pure logic, runs very fast
• is perfect for pre-commit hooks
15
Slide 16
Slide 16 text
16
describe(‘Some spec', function (t) {
var component;
t.beforeEach(function(t) {
component = new Ext.Component({ width : 100 });
})
t.it('Should test something', function (t) {
t.expect(component.getWidth()).toBe(100)
});
});
Basic Unit Test
Slide 17
Slide 17 text
17
describe("A simple Model test", function (t) {
t.it("Will not run", function (t) {
…
});
t.iit("Isolate this section", function (t) {
…
});
});
t.iit for fast test debugging
Slide 18
Slide 18 text
Unit tests are your friend
18
• Should be your #1 priority
• Cover your most important JS classes, code that is reused
• Run often, before commit, daily, nightly.
• Use TDD approach + BDD style for readability
Slide 19
Slide 19 text
TDD basics
19
1. Make the unit test fail
2. Implement
3. Make the test pass
4. Refactor, Repeat
Slide 20
Slide 20 text
Unit Test Demo
20
Slide 21
Slide 21 text
Writing good tests
Slide 22
Slide 22 text
Test code standards
22
• Apply same code standards for test code as for app code
• Document well
• Don’t overcomplicate: favour test readability over DRY
• Write abstracted methods for code reuse to avoid boilerplate test code
Slide 23
Slide 23 text
Break tests into subtests
23
describe("A simple Model test", function (t) {
t.it("Will not run", function (t) {
…
});
t.iit("Isolate this section", function (t) {
…
});
});
Slide 24
Slide 24 text
Minimising test maintenance
24
• Flaky tests can be hard and demoralising
• Race conditions can sneak into application / test code easily
• Debugging consumes time
• Some guidelines tips & tricks to consider
Slide 25
Slide 25 text
Avoid hard coded waits
25
t.chain(
{ click : “div.loadUserButton” },
{ waitFor : 2000 }, // loading takes time
function() {
// Should be 10 users in grid now
t.expect(userGrid.getCount()).toBe(10);
}
});
Slide 26
Slide 26 text
Use waitFor with condition
26
t.chain(
{ click : “div.loadUserButton” },
{ waitFor : function() {
return userGrid.getCount() > 0;
},
function() {
// Should be 10 users in grid now
t.expect(userGrid.getCount()).toBe(10);
}
);
Slide 27
Slide 27 text
Independent tests
27
• Tests should not rely on other tests
• It should always produce same result regardless of when executed
• Automation mode does not guarantee test order (== good)
Slide 28
Slide 28 text
UI Testing
Render, Interact, Assert
Slide 29
Slide 29 text
29
• UI unit test of a single UI component
• Or application test, open index.html and test it
Two main types of UI tests
Slide 30
Slide 30 text
30
Manually writing UI tests takes time
Slide 31
Slide 31 text
31
UI tests are more fragile & run slower than unit tests
Slide 32
Slide 32 text
32
Understanding CSS and ComponentQuery is key
Slide 33
Slide 33 text
33
Reveals tight coupling very efficiently
UserList.js
Test sandbox
Viewport.js
Slide 34
Slide 34 text
34
t.chain(
{ click : '>>[name=name]' },
{ type :'Bob[TAB]' },
{ type : ‘Bobs password' },
{ click : 'div.x-btn:contains(Login)'},
{ waitForSelectorNotFound : ‘.loginWindow'}
)
Siesta UI test format
Slide 35
Slide 35 text
35
UI Unit test demo
Slide 36
Slide 36 text
Writing stable UI tests
Slide 37
Slide 37 text
Testing dynamic DOM apps
37
• Organisation decision: Testing must be prioritised
• Code should be written to facilitate testing.
• Developers should annotate DOM for easy UI testing
Slide 38
Slide 38 text
Testing dynamic DOM apps
38
Slide 39
Slide 39 text
Beware of generated ids
39
Slide 40
Slide 40 text
Not very robust…
40
t.chain(
{ click : “div#dataview-1076-3183” },
…
});
Slide 41
Slide 41 text
Better decide on a custom attribute
41
Slide 42
Slide 42 text
Now it’s very robust…
42
t.chain(
{ click : “[data-testid=userAvatar]” },
…
});
Slide 43
Slide 43 text
Application Tests
Click, Wait, Assert
Slide 44
Slide 44 text
Application testing
44
• Aka black box testing, functional testing
• Go to application index.html
• Runs all the code of your application
• Does app work or not?
Slide 45
Slide 45 text
Challenges
45
• Database needs to be put in a known state
• Slow
• Tests can become fragile, race conditions
• Errors harder to find
Slide 46
Slide 46 text
Using the event recorder
46
Slide 47
Slide 47 text
47
•Great for application tests
•Records user actions: clicks, types, drag drop
•Can be used by a non-programmer
•Big timesaver
Using the event recorder
Slide 48
Slide 48 text
48
Let’s try the recorder
Slide 49
Slide 49 text
49
Monkey testing
Slide 50
Slide 50 text
Monkey testing
50
• Random UI testing
• Clicks, drags etc. in your UI
• Finds unhandled exceptions
• Free testing help. 0€
Automation & CI
Team City, Cloud Services, Statistics
Slide 56
Slide 56 text
Multiple test launchers
56
• webdriver (preferred)
• PhantomJS (Webkit-ish)
• SlimerJS (Firefox)
• xvfb (Linux, parallel test execution on local machine)
Slide 57
Slide 57 text
Purpose of CI
57
• Automated builds
• Nightly test suite execution
• Finding errors early => Code quality => Motivated developers
• Enables Continuous Delivery
Slide 58
Slide 58 text
58
Always ready to release!
Slide 59
Slide 59 text
59
•Bryntum uses TeamCity
•Test suites triggered by every commit in Chrome
•Nightly for all other browsers
•Reports, statistics, charts and code coverage
Slide 60
Slide 60 text
60
So…running in multiple browsers?
Slide 61
Slide 61 text
X-browser testing
61
•Need to create Virtual Machines for each version of IE
•Total: Chrome, Safari, FF, IE 7-11 => 5 VMs
•Managing such a farm can be very time consuming
Slide 62
Slide 62 text
62
• Siesta integrates seamlessly with Sauce Labs
• Run tests easily in any OS and Browser combination
• No need to setup your own VM farm
• Read more on the Bryntum blog…
Cloud to the rescue
Slide 63
Slide 63 text
63
Launching tests with Sauce
webdriver localhost/siesta/tests --saucelabs
Slide 64
Slide 64 text
64
Running tests in parallel
test1.t.js
test2.t.js
test3.t.js
test5.t.js
test4.t.js
Slide 65
Slide 65 text
65
Parallel tests with Sauce
webdriver localhost/siesta/tests --saucelabs --max-workers=20