Slide 1

Slide 1 text

Testing JavaScript with Siesta Mats Bryntse, developer at Bryntum @bryntum

Slide 2

Slide 2 text

Who am I? • Started as .NET dev 2003 • Full time Ext JS developer since 2007 • Founded Bryntum 2009 • Components & tools for the Sencha ecosystem • www.bryntum.com

Slide 3

Slide 3 text

Agenda ! •Why test your JS? •What is Siesta? •Writing your first unit Siesta test •Functional testing •Event Recorder

Slide 4

Slide 4 text

Do you test your JS?

Slide 5

Slide 5 text

Why test your JS?

Slide 6

Slide 6 text

What we do @Bryntum: Gantt chart: ~41k lines of code

Slide 7

Slide 7 text

Too many variants •Different OS’s •Different browsers •Different browser versions (IE7-11) •Strict vs quirks mode •Daylight savings issues •Testing all combinations doesn’t scale

Slide 8

Slide 8 text

Refactoring untested code

Slide 9

Slide 9 text

Fighting bugs once

Slide 10

Slide 10 text

Solutions? •Unit tests? •Integration tests? •Exploratory tests? •Monkey tests?

Slide 11

Slide 11 text

The more the merrier

Slide 12

Slide 12 text

What is Siesta?

Slide 13

Slide 13 text

•Built with standard JS/CSS •Test any JS/web/Node codebase •Event simulation (click, type etc) •Event recorder •Sandboxed tests, 1 iframe per test •We use it to test all our products Siesta facts:

Slide 14

Slide 14 text

Unit + Functional tests

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

A look at the Siesta UI

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

Writing a Siesta test

Slide 20

Slide 20 text

Test Model Layer First •Easy to unit test, high ROI. •Your.data.Model •Your.data.Store •Your.util.Class •Focus on one class per test file •Test your code, not framework code

Slide 21

Slide 21 text

Ext.define(“My.model.User”, { extend : ‘Ext.data.Model’, ! fields : [‘FirstName’, ‘LastName’, ‘Salary’], ! getAnnualSalary : function () { return this.get(‘Salary’) * 12; }, ! isValid : function() { return this.get(‘FirstName’) && this.get(‘LastName’); } }); My.model.User

Slide 22

Slide 22 text

describe(“Testing my User model”, function(t) { t.it(‘Should get correct annual salary’, function(t) { var user = new My.model.User({ Salary : 5000 }); t.expect(user.getAnnualSalary()).toBe(60000); }); ! t.it(‘Should treat incomplete name as invalid’, function(t) { var user = new My.model.User({ FirstName : ‘Bob’ }); t.expect(user.isValid()).toBeFalsy(); }); }) User.t.js

Slide 23

Slide 23 text

StartTest(function(t) { ! t.it(‘Should be able to get name’, function(t) { ! var user = new My.model.User({ FirstName : ‘Bob’ }); t.expect(user.get(‘FirstName’)).toBe(‘Bob’); }); }) Don’t test Ext JS

Slide 24

Slide 24 text

var Harness = Siesta.Harness.Browser.ExtJS; ! Harness.configure({ preload : [ "http://cdn.sencha.io/ext-4.2.0-gpl/resources/css/ext-all.css", "http://cdn.sencha.io/ext-4.2.0-gpl/ext-all-debug.js", "my-app-all-debug.js" ] }); ! Harness.start({ group : 'Model Layer', items : [ 'User.t.js' ] }); Harness.js

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

Using PhantomJS (or Selenium)

Slide 27

Slide 27 text

Testing views •Normally, your app consists of many view classes •Test your components in isolation: •My.app.UserList •My.app.OrderForm •Test your public config properties + API •Sanity tests give you peace of mind

Slide 28

Slide 28 text

http://github.com/matsbryntse

Slide 29

Slide 29 text

10 Sanity tests 1. Your namespace is created, no global variable leaks. 2. Your component can be loaded on demand 3. No global Ext JS overrides 4. Basic JsHint rules 5. It does not use global CSS rules ('.x-panel' etc) 6. It can be sub-classed 7. It does not leak any additional components or DOM 8. It doesn't override any private Ext JS methods 9. It can be created, destroyed 10. It passes a basic monkey test

Slide 30

Slide 30 text

Functional testing

Slide 31

Slide 31 text

Functional testing •More complex than unit testing, involves DOM •Interacting with the UI as a user (or cat) would •Siesta allows you to simulate user interactions: • type • click • drag

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

Targeting the UI •A Sencha application consists of Components •1 Component === Many HTML elements •HTML is not a good abstraction layer when testing Sencha apps •Markup is generated by the framework.

Slide 34

Slide 34 text

Ext.grid.Panel Ext.Viewport Ext.chart.Chart

Slide 35

Slide 35 text

CSS Query: div>div>div>div>div>:contains(Company)

Slide 36

Slide 36 text

Component Query: gridcolumn[text=Company]

Slide 37

Slide 37 text

Composite Query: gridcolumn[text=Company] => span

Slide 38

Slide 38 text

Query Power - CSS Query “.x-column-header” - Component Query “gridcolumn” - Composite Query “gridcolumn => .x-header-text”

Slide 39

Slide 39 text

Component Inspector

Slide 40

Slide 40 text

Event recorder

Slide 41

Slide 41 text

Event recorder •Authoring UI tests manually takes time •The Event Recorder records user interactions •Understands the Sencha component model •Generates best practice JS test code

Slide 42

Slide 42 text

No content

Slide 43

Slide 43 text

Code Coverage

Slide 44

Slide 44 text

Code Coverage

Slide 45

Slide 45 text

Final thoughts… •Testing saves time and time === $$ •Automation and CI is key •High code coverage !== working code

Slide 46

Slide 46 text

Thanks for listening!

Slide 47

Slide 47 text

Questions? [email protected] @bryntum Download Siesta bryntum.com/products/siesta Slides: speakerdeck.com/mats