• Mocha • Chai.js • Buster.js • jsCover • Plato • Wrap-up Agenda • A word about testing • Test taxonomy • Methodology • vocabulary • Phantom.js • Zombie.js LIVE LIVE LIVE LIVE LIVE LIVE
numbers Given I have entered 10 in the calculator And I have entered 7 in the calculator When I press substract Then the result should be 3 on the screen BDD Style (Gherkin)
no head ? » A browser with no graphical Interface ! Executable from the command line Mega-Ultra-Fast Can be automated We can’t always know what’s going on
(JavascriptCore) - full javascript API - true rendering (no emulation) - pure headless (no X11 required) ! • Created by Ariya Hidayat (@ariyahidayat) in 2010 ! • Cross platform (Linux, MacOSX and Window) ! • Blazing fast • Used in test workflow of many famous projects (Bootstrap, Grunt...) PhantomJS
null; page.evaluate(function() { title = document.title ; }); console.log(title) // prints null. ! ! ! // GOOD var title = page.evaluate(function() { return document.title; }); console.log(title) // prints the title. ! • Dual evaluation context (browser and server) ! • Communication between contexts can be tricky (only primitive types) ! • Easy to use it wrong at first Evaluation context
since version 1.5 (was preventing phantom to be pure headless) • CSS 3D • Video and Audio • WebGL • Geolocation (but can easily be mocked) • Fonts (rarely a problem when used for testing) ! Yep, everything else is working !
tool : true rendering, reliable, very fast. ! But... – Raw API which can be hard to handle – The dual execution context can be confusing at first – Tricky asynchronous nature (callback cascading) – Actually only a browser, not a test framework ! This is why...
• Adds an higher level API : • Fluent API • More graceful handling of asynchronism nature • Make is easier to interact with the page • Allow the creation of functional test suites • A lot of sugar methods
teardown as CLI arguments and global to every test... :/ ! - export results in xUnit format (for CI integration) $ casperjs test --includes=foo.js,bar.js \ ## these scripts will be included at startup --pre=pre-test.js \ ## this will be executed before each test --post=post-test.js \ ## this will be executed after each test --direct \ ## log messages redirected to the console --log-level=debug \ ## log level --fail-fast \ ## stop suite after first fail. --xunit=xunit.xml ## path for the xunit output file test1.js test2.js /path/to/another/test/dir ## path to test and test folders to launch
- French developer ! ! - Adds an higher level API to the power of PhantomJS ! - Very fast ! - Export results to xUnit format ! - Easy to extend - Test API not really mature (limited setup / teardown usage... Even on 1.1 branch) ! - Python or Ruby launcher, can be problematic for Window (but is this really an issue ?)
« true » browser, it uses carefully selected emulation libraries to simulate all the stuff a browser does : ! ! • JSDom by Elijah Insuas (Dom Emulation) • HTML5 by Aria Stewarts (HTML5 Parsing) • Sizzle.js by John Resig (Css Selectors) • ...
Fluent API • Test code is a *joy* to read • Emulates a Browser • Does not work on Windows • Errors are somewhat cryptic • Integrating this in a java build is not easy. • Main developer says "it’s a side project"
to use test framework ! • Initially developed by John Resig (jQuery) • Became public in 2008 ! • Browser based test launcher ! • Format xUnit ! • Extensible (plugins)
rel="stylesheet" href="/qunit.css"> </head> <body> <div id="qunit"></div> <div id="qunit-fixture"></div> <script src="/qunit.js"></script> <script src="/tests.js"></script> </body> qunit.html module("Hello.World"); ! test("universe should agree", function() { ok(42==42, "probably true"); }); ! module("JS.Troll"); ! test("equality should be trolling material", function() { equal('\n\r\t' , 0, "a whitespace string is equal to zero"); }); ! test("transitivity should be trolling material", function() { equal(0, "", "zero is equal to empty string"); equal(0, "0", "zero is equal to the string '0'"); notEqual("", "0", "the empty string is not equal to the '0' string"); }); tests.js Very simple :
: • ok() • equal() • deepEqual() • strictEqual() • throws() • notEqual / not[...] ! Yep, that's all ! // ok() ok(3 > 2); // pass ok(1==2); // fail ! // equals() equal("same value", "same value"); // pass equal("some value", "another value"); // fail ! // deepEqual() var a = { someValue : 2 }; var b = { someValue : 2 }; equal(a, b); // fail because a and b have not the same reference. deepEqual(a, b); // pass because a and b have the same attributes. ! // strictEqual() equal(1, true); // pass because (1==true) is true strictEqual(1, true); // fail because (1===true) is false" ! // throws() throws(function() { throw "thrown"; }, "thrown"); // pass because expected exception is raised.
asyncTest("stuff and remote work loading", function() { ! var stuff = new Stuff(); ok(!stuff.readyToWork); ! $.get("/some/work/url", function(work) { ! stuff.loadWork(work); ! ok(stuff.readyToWork); ! start(); // telling the test to start. }); ! });
(canvas, html...) • Runners (junit) • Integration (drupal, rails) • Framework integration (sinon, jsTestDriver) • Themes Example of assertion definition QUnit.extend( QUnit.assert, { /** * given number should be strictly greater than given minimum */ greaterThan : function(number, minimum, message) { QUnit.push(number > minimum, number, ">" + minimum, message); } }); ! // […] using the assertion in a test test("testing my assertion", function(assert) { var five = 5; var three = 3; assert.greaterThan(five, three, "5 should be greater than 3"); });
! • Created by Christian Johansen ( @cjno ) – Creator of juicer, core developer of Buster.js – Author of « Test-Driven Javascript Development » ! • Initial release in june 2010 – Actual version : 1.7.3 ( 20/06/2013 ) ! • No dependencies, works on any environment (browser, node...)
greeter = { greet : function(name) { console.log("hello " + name); } }; var mock = sinon.mock(greeter); // expects greet to be called once with 'john' mock.expects("greet").withArgs("john").once(); ! // mock.verify() // would raise greeter.greet("john"); mock.verify(); // will pass }); Mocks and expectations - Mock an object converts every methods to expectations. ! - An expectation : - extend stub (and spy) API - adds calls validation methods ! Mock.restore() allow to cleanup and restore original object behaviour
sandbox.useFakeTimers(); sandbox.useFakeServer(); // all code from there uses fake timers and server. ! // […] var spy = sandbox.spy(someObject, “method”); ! sandbox.restore(); // original behaviour is now restored // sandbox spies are also removed Allows isolation and cleanup of faking features ! Test classes inherits from Sandbox.
test("sinon adapter should work", function () { ! var stub = this.stub(); stub.returns("stubbed"); ! var result = stub(); ! equal(result, "stubbed", "result value should be stubbed"); ok(stub.calledOnce, "spy should have been called once"); }); Adapters Allows partial or complete Sinon.js API integration in other test frameworks ! - Jasmine - Chai - QUnit - NodeUnit - ... Sinon-qunit usage example
way to call original method in stubbed one) ! Beware of Date faking when using date libraries ! Ajax faking is not that great on IE6/7 (strange isn't it?) In a few words... Extremely powerful ! Play (very) well with others ! Fluent and readable API ! Spies and stubs quickly become essentials in tests.
Works only with Angular.js application • No CallBack Handling (Yeeepeee !!!!) • Every element is a future : expect(element('title').text()).toBe 'Devoxx'
Scenario • Quite Fast • Watch files and run tests continuously • End 2 End testing on angular only • Documentation is "ok" at best • Browser must be installed separately • Verbose configuration file • Protractor coming in ? !
in Node.js Or In a browser • Able to run synchronous & asynchronous tests • Out of the box integration with Jenkins, TeamCity, Junit • chai.js compatible ! • 1.13.0 • MIT Licence
! describe 'mocha example', -> ! it 'should uppercase the 1st letter', -> assert.equal('Foo', uppercaser('foo')) ! it 'should render uppercase even if its already done', -> assert.equal('Foo', uppercaser('Foo'))
fast • Fluent API • Testing code is readable ! • No browser emulation (scenario) • Java Build Integration is heavy • Chai’s Should assertion can be seen as intrusive
refreshing features • Still in beta (latest : 0.7.4) • Multiple launch modes : – Node module – Browser capture ( like jsTestDriver or Karma) – Embed static server – In browser ( experimental ) – Headless with PhantomJS ( not yet implemented ) • Allows to create and manage multiple test contexts • Ships with sinon.js
before(function() { this.stuff = new Stuff(); }); it("should exists", function () { expect(this.stuff).toBeDefined(); }); it("should be fluffy", function() { expect(this.stuff.isFluffy()).toBe(tru e); }); }); buster.testCase("project.Stuff", { setUp: function () { this.stuff = new Stuff(); }, "my stuff should exists" : function () { assert.defined(this.stuff); }, "my stuff should be fluffy" : function() { assert(this.stuff.isFluffy()); } }); Two syntaxes to write tests : xUnit format BDD format
! refute.isNull(); refute instead of assert.not[...] buster.testCase("My thing", { requiresSupportFor: { "touch events": typeof(document.body.ontouchstart) != "undefined", "XHR": typeof(XMLHttpRequest) != "undefined" }, ! "touch events should trigger an ajax call": function () { // .. } }); Disable tests with // in name Tests prerequisites buster.testCase("projet.deferred", { ! "this test will be executed": function () { assert(true); }, ! "// this test will not launch": function () { assert(false); } });
young ( beta 0.7 ) ! Lot of 'not yet implemented' features – Window support – Headless testing – Custom “test bed” Already very feature rich for a beta ! Some great new / fresh ideas ! Seems very promising
! - Java rewrite of JsCoverage (was c++) ! - Two instrumentation modes : - build time - runtime using proxy ! - Export to Cobertura format (for integration in Jenkins / CI)
to do ! - Active developer ! - Results can be integrated to CI - Integration in test phase can be (well, is) tricky in both modes ! - plain old jar, not in maven repositories for now...
- Easy to use ! - Beautiful Dashboard - Reports only available in html or json. No other format to export. ! - So very difficult to integrate in a CI (not possible)