Good Karma: UX Patterns and Unit Testing in Angular with Karma Laura Ferguson and Boris Kan @ Create, inc, 2015 http://goo.gl/hurhTR
AngularJS: MVW http://stackoverflow.com/questions/13329485/mvw-what-does-it-stand-for http://goo.gl/hurhTR
Why AngularJS? ● Open Source Web Application Framework ● Maintained by Google & individual developers ● Addresses challenges encountered in developing single- page apps ● Embraces Model-View-Controller → Now called MVW ● Provides rich internet components ● Mobile(ish) friendly & responsive http://en.wikipedia.org/wiki/AngularJS http://goo.gl/hurhTR
By Ben Nadel www.bennadel.com
Bind an element to items in a list, one at a time: <ul> <li ng-repeat="boat in boats"> <span>{{boat.name}}</span> </li> </ul> *While doable, try not to use ids and classes UI Patterns in Angular: Bind an element to a variable in the controller: <span ng-bind="mobileApp"></span> or <span>{{mobileApp}}</span> Bind an element by ng-click <button ng-click="next()"></button>
What is scope? And what is $scope? In Computer Science (cs) a scope may contains a set of variables that may have a specific value when a function is called. In angular, $scope is the model that contains the values displayed by the view and controlled by the controller. ex: $scope.model.address = “123 45th St NW DC 20012”; https://docs.angularjs.org/guide/scope
What is a controller? Think of a controller as the wizard (as in the wizard of oz) deciding what should happen after the view (the gui/the html) reports a user interaction back to the controller. Let’s take a closer look...
For Example: .controller('MainController', ['$scope', '$document', '$window', '$rootScope', 'deviceReady', 'getCurrentPosition', 'getWeather', function ($scope, $document, $window, $rootScope, deviceReady, getCurrentPosition, getWeather) { $scope.model = { "address": "555 Pennsylvania Ave NW, Washington, DC 20001", "latitude": 0, "longitude": 0, "walkAddress": "", "googleAddress": "", "currentPosition": "", "location":"", "weather":"", "markers":"" }; $scope.changeText = function () { var textElement = document.getElementById("householdIncome"); textElement.innerHTML = 'I am a changed div!'; console.log(textElement.innerHTML); };
Now let’s make something happen $scope.walkAddressLookup = function () { if ($scope.model.address) { var address = $scope.model.address; address = address.replace(',', ''); //for walkscore return address.split(' ').join('-'); } };
$scope.loadAddresses = function () { getCurrentPosition(function (position) { $scope.model.currentPosition = position; $scope.model.latitude = position.coords.latitude; $scope.model.longitude = position.coords.longitude; getWeather( position.coords.latitude, position.coords.longitude, function(location, weather){ $scope.model.location = location; $scope.model.weather = weather; }); }); if ($scope.model.address) { //for walkscore $scope.model.walkAddress = $scope.walkAddressLookup(); } };
Testing Isn’t that a backend thing?
Types of testing Unit Testing -- Developer writes small automated tests for each unit of functionality Quality Assurance testing (Each developer) Integration Testing & E2E -- All components work together as expected (Lead Developer / UX) Quality Assurance Testing -- Systematic objective testing of a working release following a thorough test plan. Load Testing -- Automated testing of system with simulated users and/or simulated traffic. Acceptance (Success) Testing -- A knowledgeable user can use the system to complete the intended tasks Alpha Testing -- Typical users are given the opportunity to use the system, observed while doing so, and issues are noted and fixed by an objective observer (QA) Beta Testing -- A small number of users are given complete access to the system and asked for feedback periodically.
What is Test Driven Development? ● Very short cycles, write tiny tests, and test everything. ● Run a continuous integration server and maintain the integrity of your tests at all time. ● Keeps your code base fully functional. http://en.wikipedia.org/wiki/Test-driven_development
Why front-end e2e testing? Practical reasons ● Get notified when backend changes break the gui ● Get notified when “simple” front- end changes break usability ● Get notified when your app doesn’t work right on some browsers (and hopefully sometime soon on devices) Or just for better “Cred” ● Validation is a good practice. ● Earn some ’spect from backend developers (’sup) ● Think big and think ahead.
For Example: it('should have be able to find the title', function() { var docs = element(by.css('.navbar-brand-center')); expect(docs.getText()).toContain('Good Karma Commutability'); });
Acceptance Tests Best Commute: Show commutability at any location ● Get current location ● Get commuting data for that location ● Show distance to metro, bus, retail(?) ● Show commuting time
What’s Next 1) Write a basic test that fails because no the code doesn’t exist yet. 2) Then make the test pass by writing the code. 3) Rinse / Repeat (with new tests)
// spec.js describe('Protractor Demo App', function() { it('should have a title', function() { browser.get('http://localhost:8000'); expect(browser.getTitle()).toEqual('Property Lookup'); }); } Write an E2E Test Acceptance Test: The app should display a title
Pass or Fail? Acceptance Test: user can edit text field in your spec.js it('should be able to edit the text field', function() { var textArea = element(by.model('areaText')); textArea.sendKeys("Hi", protractor.Key.ENTER); expect(textArea.getAttribute('value')).toContain('Hi!'); }); In your html application <textarea ng-model="'areaText'" readonly><textarea>
It failed! (let’s drown our sorrow with a beer!!!)
the Corrected Code would be: In your html application <textarea ng-model="'areaText'"><textarea>
Pass or Fail? Acceptance Test: user can edit text field in your spec.js it('should be able to edit the text field', function() { var textArea = element(by.model('areaText')); textArea.sendKeys("Hi", protractor.Key.ENTER); expect(textArea.getAttribute('value')).toContain('Hi!'); }); In your html application <textarea ng-model="'areaText'"><textarea>
It passed! (let’s celebrate this with a beer!!!) sip sip sip. Now, on to the next one!
Bind an element to items in a list, one at a time: element( by.repeater(boat in boats' ).row(0).column('name') ); <ul> <li ng-repeat="boat in boats"> <span>{{boat.name}}</span> </li> </ul> *While doable, try not to use ids and classes Capturing UI Patterns in Angular in Tests: Bind an element to a variable in the controller: element( by.binding('mobileApp') ); <span ng-bind="mobileApp"></span> or <span>{{mobileApp}}</span> Bind an element by ng-click element.all( by.css('ng-click="issue()"]') ).click(); <button ng-click="next()"></button>
Hands On: Try the Example
#1: Build it with Angular http://goo.gl/hurhTR //install the requirements -- get node curl -L https://npmjs.com/install.sh | sh sudo npm install -g bower yo gulp generator-mobileangularui sudo npm install -g phonegap sudo npm install -g ios-deploy sudo npm install -g ios-sim bower install --save font-awesome#4.2 //create folders and directories mkdir mobilephonegap cd mobilephonegap http://mobileangularui.com/blog/your-first-phonegap-app-with-mobile-angular-ui/
Try out the working code git clone https://github.com/CreateIO/propertyLookup.git git checkout -b example git pull origin example cordova plugin add org.apache.cordova.geolocation sudo npm install sudo npm install -g bower bower install //build this and view at localhost:8000 gulp
Get the simulator running on ios or android gulp build phonegap run ios //you’ll need the android sdk... phonegap run android
#3: Test it! basic file structure app ├── src ├── www ├── testing │ ├── spec.js │ ├── conf.js - spec.js (where the testing happens.) - conf.js (configuration file. we will generate this together on the next page) Setup npm install -g protractor (-g for global install) webdriver-manager update (just to make sure we have the latest version)
In your terminal, enter: gulp In a new terminal(command + T), enter: webdriver-manager start In another new terminal, enter: protractor testing/conf.js // this is the relative path to your conf.js file
// conf.js exports.config = { seleniumAddress: 'http://localhost:4444/wd/hub', capabilities: { 'browserName': 'chrome' }, specs: ['spec.js'], jasmineNodeOpts: { showColors: true } } Standard Configuration
More! More! Export your results! npm install jasmine-reporters Different test suites! suites: { homepage: 'testings/home/*Spec.js', login: 'testings/login/*Spec.js' } Multiple browsers! {'browserName' : 'chrome'}, {'browserName' : 'firefox’}
Your Turn
Acceptance Test Best Commute: Show commutability at any location ● Get current location (done) ● Get commuting data for that location (done) ● Show distance to metro, bus, retail(?) ● Show commuting time
Try It! 1. Test if the map is displayed 2. Substitute in model.googleaddress for lat/long -- does your test still pass? 3. Write a test for displaying a streetview, and then make the test pass by writing the needed code.
Try It! 4. Extra: Move the google maps & streetview code into factories just like forcast.com, make sure your tests still pass. 5. Extra: Write a test and code to make sure the map doesn’t stretch. 6. Go Full Stack: Hook up a reverse geocoder to go from current location to an address tying the whole app together.
Hands On: Build your own
//get the build done yo mobileangularui gulp build (this will compress your src folder files and build everything in to the www/ folder) phonegap run ios (this will open the ios simulator to display your app) * borrow image from: http://mobileangularui.com/blog/your-first-phonegap-app-with-mobile-angular- ui/ #1: Generate an app
src ├── html │ └── index.html ├── images ├── js │ ├── app.js │ ├── controllers │ │ └── main_controller.js │ ├── directives │ └── services ├── less │ ├── app.less │ ├── mixins.less │ ├── responsive.less │ └── variables.less └── templates ├── home.html └── sidebar.html t
#2: Get it running! //gulp to test it at localhost:8000 gulp // to deploy the application gulp build //get the simulator running on ios phonegap run ios (it can be android as well) // often needed when installing new libraries or downloading code: sudo npm install sudo npm install -g bower bower install
#3: Test it! basic file structure app ├── src ├── www ├── testing │ ├── spec.js │ ├── conf.js - spec.js (where the testing happens.) - conf.js (configuration file. we will generate this together on the next page) Setup npm install -g protractor (-g for global install) webdriver-manager update (just to make sure we have the latest version)
Google api https://github.com/google/google-api-nodejs-client Angular Google Maps http://angular-ui.github.io/angular-google-maps/#!/ http://angular-ui.github.io/angular-google-maps/#!/demo Mobile Angular UI http://mobileangularui.com/blog/your-first-phonegap-app-with-mobile-angular-ui/ Protractor testing Related http://ramonvictor.github.io/protractor/slides http://angular.github.io/protractor/#/tutorial Ionic framework, similiar to the ones we use http://learn.ionicframework.com/formulas/Protractor/
Who are we? Create is a real estate information system packed with property data, 3D maps, and tools that empower instant investment decision making. We gather and display data from public and private sectors to let the user determine the potential of any given properties in any neighborhoods in the district in map layers, 3d buildings, charts, table and other formats. Plus, we have lots of really useful and pretty maps. Check us out at create.io
Thanks for participating! Say hi to us in the conference and on social media! Email: laura@create.io boris@create.io Twitter: @allenderlaura @borisboryakan
Good Karma: UX Patterns and Unit Testing in Angular with Karma Laura Ferguson and Boris Kan @ Create, inc, 2015 http://goo.gl/hurhTR

Good karma: UX Patterns and Unit Testing in Angular with Karma

  • 1.
    Good Karma: UX Patternsand Unit Testing in Angular with Karma Laura Ferguson and Boris Kan @ Create, inc, 2015 http://goo.gl/hurhTR
  • 2.
  • 3.
    Why AngularJS? ● OpenSource Web Application Framework ● Maintained by Google & individual developers ● Addresses challenges encountered in developing single- page apps ● Embraces Model-View-Controller → Now called MVW ● Provides rich internet components ● Mobile(ish) friendly & responsive http://en.wikipedia.org/wiki/AngularJS http://goo.gl/hurhTR
  • 4.
    By Ben Nadelwww.bennadel.com
  • 5.
    Bind an elementto items in a list, one at a time: <ul> <li ng-repeat="boat in boats"> <span>{{boat.name}}</span> </li> </ul> *While doable, try not to use ids and classes UI Patterns in Angular: Bind an element to a variable in the controller: <span ng-bind="mobileApp"></span> or <span>{{mobileApp}}</span> Bind an element by ng-click <button ng-click="next()"></button>
  • 6.
    What is scope? Andwhat is $scope? In Computer Science (cs) a scope may contains a set of variables that may have a specific value when a function is called. In angular, $scope is the model that contains the values displayed by the view and controlled by the controller. ex: $scope.model.address = “123 45th St NW DC 20012”; https://docs.angularjs.org/guide/scope
  • 7.
    What is acontroller? Think of a controller as the wizard (as in the wizard of oz) deciding what should happen after the view (the gui/the html) reports a user interaction back to the controller. Let’s take a closer look...
  • 8.
    For Example: .controller('MainController', ['$scope', '$document','$window', '$rootScope', 'deviceReady', 'getCurrentPosition', 'getWeather', function ($scope, $document, $window, $rootScope, deviceReady, getCurrentPosition, getWeather) { $scope.model = { "address": "555 Pennsylvania Ave NW, Washington, DC 20001", "latitude": 0, "longitude": 0, "walkAddress": "", "googleAddress": "", "currentPosition": "", "location":"", "weather":"", "markers":"" }; $scope.changeText = function () { var textElement = document.getElementById("householdIncome"); textElement.innerHTML = 'I am a changed div!'; console.log(textElement.innerHTML); };
  • 9.
    Now let’s makesomething happen $scope.walkAddressLookup = function () { if ($scope.model.address) { var address = $scope.model.address; address = address.replace(',', ''); //for walkscore return address.split(' ').join('-'); } };
  • 10.
    $scope.loadAddresses = function() { getCurrentPosition(function (position) { $scope.model.currentPosition = position; $scope.model.latitude = position.coords.latitude; $scope.model.longitude = position.coords.longitude; getWeather( position.coords.latitude, position.coords.longitude, function(location, weather){ $scope.model.location = location; $scope.model.weather = weather; }); }); if ($scope.model.address) { //for walkscore $scope.model.walkAddress = $scope.walkAddressLookup(); } };
  • 11.
    Testing Isn’t that abackend thing?
  • 12.
    Types of testing UnitTesting -- Developer writes small automated tests for each unit of functionality Quality Assurance testing (Each developer) Integration Testing & E2E -- All components work together as expected (Lead Developer / UX) Quality Assurance Testing -- Systematic objective testing of a working release following a thorough test plan. Load Testing -- Automated testing of system with simulated users and/or simulated traffic. Acceptance (Success) Testing -- A knowledgeable user can use the system to complete the intended tasks Alpha Testing -- Typical users are given the opportunity to use the system, observed while doing so, and issues are noted and fixed by an objective observer (QA) Beta Testing -- A small number of users are given complete access to the system and asked for feedback periodically.
  • 13.
    What is TestDriven Development? ● Very short cycles, write tiny tests, and test everything. ● Run a continuous integration server and maintain the integrity of your tests at all time. ● Keeps your code base fully functional. http://en.wikipedia.org/wiki/Test-driven_development
  • 14.
    Why front-end e2etesting? Practical reasons ● Get notified when backend changes break the gui ● Get notified when “simple” front- end changes break usability ● Get notified when your app doesn’t work right on some browsers (and hopefully sometime soon on devices) Or just for better “Cred” ● Validation is a good practice. ● Earn some ’spect from backend developers (’sup) ● Think big and think ahead.
  • 15.
    For Example: it('should havebe able to find the title', function() { var docs = element(by.css('.navbar-brand-center')); expect(docs.getText()).toContain('Good Karma Commutability'); });
  • 16.
    Acceptance Tests Best Commute:Show commutability at any location ● Get current location ● Get commuting data for that location ● Show distance to metro, bus, retail(?) ● Show commuting time
  • 17.
    What’s Next 1) Writea basic test that fails because no the code doesn’t exist yet. 2) Then make the test pass by writing the code. 3) Rinse / Repeat (with new tests)
  • 18.
    // spec.js describe('Protractor DemoApp', function() { it('should have a title', function() { browser.get('http://localhost:8000'); expect(browser.getTitle()).toEqual('Property Lookup'); }); } Write an E2E Test Acceptance Test: The app should display a title
  • 19.
    Pass or Fail? AcceptanceTest: user can edit text field in your spec.js it('should be able to edit the text field', function() { var textArea = element(by.model('areaText')); textArea.sendKeys("Hi", protractor.Key.ENTER); expect(textArea.getAttribute('value')).toContain('Hi!'); }); In your html application <textarea ng-model="'areaText'" readonly><textarea>
  • 20.
    It failed! (let’sdrown our sorrow with a beer!!!)
  • 21.
    the Corrected Codewould be: In your html application <textarea ng-model="'areaText'"><textarea>
  • 22.
    Pass or Fail? AcceptanceTest: user can edit text field in your spec.js it('should be able to edit the text field', function() { var textArea = element(by.model('areaText')); textArea.sendKeys("Hi", protractor.Key.ENTER); expect(textArea.getAttribute('value')).toContain('Hi!'); }); In your html application <textarea ng-model="'areaText'"><textarea>
  • 23.
    It passed! (let’scelebrate this with a beer!!!) sip sip sip. Now, on to the next one!
  • 24.
    Bind an elementto items in a list, one at a time: element( by.repeater(boat in boats' ).row(0).column('name') ); <ul> <li ng-repeat="boat in boats"> <span>{{boat.name}}</span> </li> </ul> *While doable, try not to use ids and classes Capturing UI Patterns in Angular in Tests: Bind an element to a variable in the controller: element( by.binding('mobileApp') ); <span ng-bind="mobileApp"></span> or <span>{{mobileApp}}</span> Bind an element by ng-click element.all( by.css('ng-click="issue()"]') ).click(); <button ng-click="next()"></button>
  • 25.
  • 26.
    #1: Build itwith Angular http://goo.gl/hurhTR //install the requirements -- get node curl -L https://npmjs.com/install.sh | sh sudo npm install -g bower yo gulp generator-mobileangularui sudo npm install -g phonegap sudo npm install -g ios-deploy sudo npm install -g ios-sim bower install --save font-awesome#4.2 //create folders and directories mkdir mobilephonegap cd mobilephonegap http://mobileangularui.com/blog/your-first-phonegap-app-with-mobile-angular-ui/
  • 27.
    Try out theworking code git clone https://github.com/CreateIO/propertyLookup.git git checkout -b example git pull origin example cordova plugin add org.apache.cordova.geolocation sudo npm install sudo npm install -g bower bower install //build this and view at localhost:8000 gulp
  • 28.
    Get the simulatorrunning on ios or android gulp build phonegap run ios //you’ll need the android sdk... phonegap run android
  • 29.
    #3: Test it! basicfile structure app ├── src ├── www ├── testing │ ├── spec.js │ ├── conf.js - spec.js (where the testing happens.) - conf.js (configuration file. we will generate this together on the next page) Setup npm install -g protractor (-g for global install) webdriver-manager update (just to make sure we have the latest version)
  • 30.
    In your terminal,enter: gulp In a new terminal(command + T), enter: webdriver-manager start In another new terminal, enter: protractor testing/conf.js // this is the relative path to your conf.js file
  • 31.
    // conf.js exports.config ={ seleniumAddress: 'http://localhost:4444/wd/hub', capabilities: { 'browserName': 'chrome' }, specs: ['spec.js'], jasmineNodeOpts: { showColors: true } } Standard Configuration
  • 32.
    More! More! Export yourresults! npm install jasmine-reporters Different test suites! suites: { homepage: 'testings/home/*Spec.js', login: 'testings/login/*Spec.js' } Multiple browsers! {'browserName' : 'chrome'}, {'browserName' : 'firefox’}
  • 33.
  • 34.
    Acceptance Test Best Commute: Showcommutability at any location ● Get current location (done) ● Get commuting data for that location (done) ● Show distance to metro, bus, retail(?) ● Show commuting time
  • 35.
    Try It! 1. Testif the map is displayed 2. Substitute in model.googleaddress for lat/long -- does your test still pass? 3. Write a test for displaying a streetview, and then make the test pass by writing the needed code.
  • 36.
    Try It! 4. Extra:Move the google maps & streetview code into factories just like forcast.com, make sure your tests still pass. 5. Extra: Write a test and code to make sure the map doesn’t stretch. 6. Go Full Stack: Hook up a reverse geocoder to go from current location to an address tying the whole app together.
  • 37.
  • 38.
    //get the builddone yo mobileangularui gulp build (this will compress your src folder files and build everything in to the www/ folder) phonegap run ios (this will open the ios simulator to display your app) * borrow image from: http://mobileangularui.com/blog/your-first-phonegap-app-with-mobile-angular- ui/ #1: Generate an app
  • 39.
    src ├── html │ └──index.html ├── images ├── js │ ├── app.js │ ├── controllers │ │ └── main_controller.js │ ├── directives │ └── services ├── less │ ├── app.less │ ├── mixins.less │ ├── responsive.less │ └── variables.less └── templates ├── home.html └── sidebar.html t
  • 40.
    #2: Get itrunning! //gulp to test it at localhost:8000 gulp // to deploy the application gulp build //get the simulator running on ios phonegap run ios (it can be android as well) // often needed when installing new libraries or downloading code: sudo npm install sudo npm install -g bower bower install
  • 41.
    #3: Test it! basicfile structure app ├── src ├── www ├── testing │ ├── spec.js │ ├── conf.js - spec.js (where the testing happens.) - conf.js (configuration file. we will generate this together on the next page) Setup npm install -g protractor (-g for global install) webdriver-manager update (just to make sure we have the latest version)
  • 42.
    Google api https://github.com/google/google-api-nodejs-client Angular GoogleMaps http://angular-ui.github.io/angular-google-maps/#!/ http://angular-ui.github.io/angular-google-maps/#!/demo Mobile Angular UI http://mobileangularui.com/blog/your-first-phonegap-app-with-mobile-angular-ui/ Protractor testing Related http://ramonvictor.github.io/protractor/slides http://angular.github.io/protractor/#/tutorial Ionic framework, similiar to the ones we use http://learn.ionicframework.com/formulas/Protractor/
  • 43.
    Who are we? Createis a real estate information system packed with property data, 3D maps, and tools that empower instant investment decision making. We gather and display data from public and private sectors to let the user determine the potential of any given properties in any neighborhoods in the district in map layers, 3d buildings, charts, table and other formats. Plus, we have lots of really useful and pretty maps. Check us out at create.io
  • 44.
    Thanks for participating! Sayhi to us in the conference and on social media! Email: laura@create.io boris@create.io Twitter: @allenderlaura @borisboryakan
  • 45.
    Good Karma: UX Patternsand Unit Testing in Angular with Karma Laura Ferguson and Boris Kan @ Create, inc, 2015 http://goo.gl/hurhTR