Download - Drupal8 Front-end Automated Testing
Front-end Automated Testing#drupal-fat
Ruben Teijeiro
@rteijeiro
I don't know what I like
more: Drupal or Beer
Based on a true history...
Web Development
In collaboration with
Developers
I'm ready for website
development!
DevOpsAlmost finished setting up your server. Just one
minute...
WTF!!
DesignersJust redesigned the website. Now it's shinny, edgy
and it pops!!
So, what?
UsersIn-place Content Authoring
Holy shit!!
ClientsJust something like Facebook!
We need it yesterday...
And kitten pics. Everyone loves kittens!
Better in Comic Sans
Should work also in IE7
OMG!!
Browsers
Result
Front-endI said: “{float: left;}” !!
Solution
Fixed
RefactoringFixed
Fixed
Fixed
Fixed
Fixed Fixed
Oh man!
DEMO
BONUS!
And now I will show you how it
looks like in Internet Explorer...
Now what?
FAT
Front-end Automated Testing
Because people like code that works
Continuous Integration
Push Button Receive Bacon
Unit Test
Take one tablet every “git push”
· Automated· Repeteable· Easy to understand· Incremental· Easy to run· Fast
Unit Test
BA-K-47
Testing Tools
Drupal 8 Modules
Drupal Modules
· TestSwarmhttps://drupal.org/project/testswarm
· FAThttps://drupal.org/project/fat
Testing Frameworks
· QUnit
· CasperJS
· PhantomJS
· Jasmine
Testing Frameworks
TestSwarm moduleFAT module
QUnit Tests
Bacon Module
/** * Implements hook_testswarm_tests(). */function bacon_testswarm_tests() { 'bacon_test' => array( 'module' => 'bacon', 'description' => 'Testing bacon.', 'js' => array( $path . '/tests/bacon.tests.js' => array(), ), 'dependencies' => array( array('testswarm', 'jquery.simulate'), ), 'path' => 'admin/bacon/test', 'permissions' => array('test bacon') ),}
bacon.module
/*global Drupal: true, jQuery: true, QUnit:true*/(function ($, Drupal, window, document, undefined) { "use strict";
Drupal.tests.bacon = { getInfo: function() { return { name: 'Bacon test', description: 'Testing bacon.', group: 'Bacon' }; }, tests: function() { [Insert your QUnit tests here] }, };})(jQuery, Drupal, this, this.document);
tests/bacon.tests.js
Setup
Drupal.tests.bacon = { getInfo: function() { return { name: 'Bacon test', description: 'Testing bacon.', group: 'Bacon' }; }, setup: function() { [Insert your setup code here] }, teardown: function() { [Insert your teardown code here] }, tests: function() { [Insert your QUnit tests here] },};
tests/bacon.tests.js
QUnit
Assert
Assert
Passes if the first argument is truthy.
var bbq_ready = true;QUnit.ok(bbq_ready, 'Barbecue ready!.');
var bbq_ready = false;QUnit.ok(bbq_ready, 'Barbecue ready!.');
ok(state, message)
equal(actual, expected, message)Assert
Simple comparison operator (==) to compare the actual and expected arguments.
var bbq = 'Bacon';
QUnit.equal(bbq, 'Bacon', 'Bacon barbecue!');
QUnit.equal(bbq, 'Chicken', 'Chicken barbecue!');
notEqual(actual, expected, message)Assert
Simple inverted comparison operator (!=) to compare the actual and expected arguments.
var bbq = 'Bacon';QUnit.notEqual(bbq, 'Salad', 'No salad!');
var bbq = 'Salad';QUnit.notEqual(bbq, 'Salad', 'No salad!');
deepEqual(actual, expected, message)Assert
Just like equal() when comparing objects, such that { key: value } is equal to { key: value }.
var bbq = {meat: 'Bacon'};QUnit.deepEqual(bbq, {meat: 'Bacon'}, 'Bacon barbecue!');
var bbq = {meat: 'Chicken'};QUnit.deepEqual(bbq, {meat: 'Bacon'}, 'Bacon barbecue!');
notDeepEqual(actual, expected, message)Assert
Just like notEqual() when comparing objects, such that { key: value } is not equal to { key: value }.
var bbq = {food: 'Bacon'};QUnit.notDeepEqual(bbq, {food: 'Salad'}, 'No salad!');
var bbq = {food: 'Salad'};QUnit.notDeepEqual(bbq, {food: 'Salad'}, 'No salad!');
strictEqual(actual, expected, message)Assert
Most rigid comparison of type and value with the strict equality operator (===).
var bacon = '1';
QUnit.strictEqual(bacon, '1', 'Bacon!');
QUnit.strictEqual(bacon, 1, 'Bacon!');
notStrictEqual(actual, expected, message)Assert
Most rigid comparison of type and value with the strict inverted equality operator (!==).
var bacon = '1';
QUnit.notStrictEqual(bacon, 1, 'No Bacon!');
QUnit.notStrictEqual(bacon, '1', 'No Bacon!');
Expect
expect(amount)Expect
Specify how many assertions are expected to run within a test. If the number of assertions run does not match the expected count, the test will fail.var bbq = 'Bacon';
// GoodQUnit.expect(1);QUnit.equal(bbq, 'Bacon', 'Bacon barbecue!');
// WrongQUnit.expect(1);QUnit.equal(bbq, 'Bacon', 'Bacon barbecue!');QUnit.notEqual(bbq, 'Chicken', 'Chicken barbecue!');
Synchronous Testing
Synchronous Testing
// Number of assertions.QUnit.expect(3);
var bbq_ready = true, bbq = 'Bacon';
// Assertions.QUnit.ok(bbq_ready, 'Barbacue is ready!');QUnit.equal(bbq, 'Bacon', 'Bacon barbecue!');QUnit.notEqual(bbq, 'Salad', 'No salad!');
Asynchronous Testing
Asynchronous Testing
QUnit.expect(2);
var bbq_ready = false, bbq = 'Bacon', time = 36000; // Miliseconds.
QUnit.stop();setTimeout(function() { bbq_ready = true; QUnit.ok(bbq_ready, 'Barbacue is ready!'); QUnit.start();}, time);
QUnit.equal(bbq, 'Bacon', 'Bacon barbecue!');
Testing User Actions
Testing User Actions
/** * Implements hook_testswarm_tests(). */function bacon_testswarm_tests() { 'bacon_test' => array( 'module' => 'bacon', 'description' => 'Testing bacon.', 'js' => array( $path . '/tests/bacon.tests.js' => array(), ), 'dependencies' => array( array('testswarm', 'jquery.simulate'), ), 'path' => 'admin/bacon/test', 'permissions' => array('test bacon') ),}
Testing User Actions
QUnit.expect(1);
var bbq_ready = false, bbq = 'Bacon';
bbq_ready.trigger('change');QUnit.ok(bbq_ready, 'Barbecue ready!');
https://github.com/jquery/jquery-simulate
DEMO