Practical AngularJS PDF
Practical AngularJS PDF
Dinis Cruz
This book is for sale at http://leanpub.com/Practical_AngularJS
This is a Leanpub book. Leanpub empowers authors and publishers with the Lean Publishing process. Lean
Publishing is the act of publishing an in-progress ebook using lightweight tools and many iterations to get
reader feedback, pivot until you have the right book and build traction once you do.
This work is licensed under a Creative Commons Attribution 3.0 Unported License
Tweet This Book!
Please help Dinis Cruz by spreading the word about this book on Twitter!
The suggested hashtag for this book is #PracticalAngularJS.
Find out what other people are saying about the book by clicking on this link to search for this hashtag on
Twitter:
https://twitter.com/search?q=#PracticalAngularJS
Contents
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . i
Change log: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ii
1 Using AngularJS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1 A really SIMPLE and clean AngularJS+Firebase example . . . . . . . . . . . . . . . . . . . . 2
1.2 Using AngularJS in Eclipse, Part 1) The Basics . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.3 Using AngularJS in Eclipse, Part 2) Add Some Control . . . . . . . . . . . . . . . . . . . . . . 21
1.4 Using AngularJS in Eclipse, Part 3) Wire up a Backend . . . . . . . . . . . . . . . . . . . . . 36
1.5 Using AngularJS in Eclipse, Part 4) Create Components . . . . . . . . . . . . . . . . . . . . . 50
1.6 AngularJS code editor using UI-Bootstrap and CodeMirror (done without using jQuery) . . . 58
2 KarmaJS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
2.1 A small AngularJS Jasmine test executed by KarmaJS . . . . . . . . . . . . . . . . . . . . . . 63
2.2 Creating an Eclipse UI to run AngularJS e2e tests using Karma . . . . . . . . . . . . . . . . . 72
2.3 Running KarmaJSs AngularJS example test/e2e/angular-scenario (on Chrome) . . . . . . . . 82
3 Firebase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
3.1 First PoC of sending TeamMentors server-side request URLS to Firebase (and seeing it in
realtime in an AngularJS page) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
3.2 Trying out Firebase (Beta) hosting solution and good example of Firebase Security rules . . . 94
5 IDEs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
5.1 Eclipse Groovy REPL script to sync a Browser with file changes (with recursive folder search
via Javas WatchService) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
5.2 Eclipse Groovy script to remove the busy image from the WebBrowser Editor . . . . . . . . 116
5.3 Using Chrome inside a native VisualStudio pane (using Window Handle Hijacking) . . . . . 122
5.4 Using WebStorm with Chrome and ChromeDriver (to view KarmaJS execution results) . . . 126
5.5 When the best way to automate Chrome is to use Chrome (with examples on Google search,
direct AngularJS scope manipulation and ChromeDriver javascript access) . . . . . . . . . . 129
5.6 Adding KarmaJS support to WebStorm to automagically run tests on file changes (and test UI
with SublimeText, Chrome and Cmd.exe) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
CONTENTS
6 Troubleshooting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
6.1 KarmaJS AngularJS Scenario Test Runner execution variations in IE 7,8,9 and 10 when using
AngularJS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
6.2 If AngularJS doesnt work on your O2 Platform IE scripts (the fix is to change browser
compatibility mode) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
6.3 Debugging a weird case of missing module in AngularJS and KarmaJS . . . . . . . . . . . . . 151
The first version of this book had the chapter order created by the original import from blogger (i.e. by
publish order).
In the current version, the posts are split into the following areas: Using AngularJS, KarmaJS, Firebase,
Misc Tricks, IDEs, Troubleshooting, Appendices, which is a filter based on technology. Note that this
can change based on reader feedback, so if you think the order should be different, please send your feedback
and ideas.
Dinis Cruz is a Developer and Application Security Engineer focused on how to develop secure applications.
A key drive is on Automating Application Security Knowledge and Workflows which is the main concept
behind the OWASP O2 Platform and Security Innovations TeamMentor (Dinis is the main developer and
architect of both Applications). Current day job is with Security Innovation where Dinis tries to promote
openness, quality and sharing as part a core tenet of TeamMentors application development environment.
After many years (and multiple roles) Dinis is still very active at OWASP, currently leading the O2 Platform
project and helping out other projects and initiatives.
After failing to scale his own security knowledge, learned Git, created security vulnerabilities in code
published to production servers, delivered training to developers, and building multiple CI (Continuous
Integration) environments; Dinis had the epiphany that the key to application security is Secure Continuous
Delivery: Developers Immediate Connection to What Theyre Creating. This Immediate Connection/Feed-
back concept is deep rooted in the development of the O2 Platform/TeamMentor, and is something that will
keep Dinis busy for many years.
Change log:
As seen on the First PoC of sending TeamMentors server-side request URLS to Firebase (and seeing it in
realtime in an AngularJS page) I created a Simple AngularJS website which Im very happy with (and I mean
Simple with a capital S).
The main reason I really like the solution shown below, is because it represents a number of really nice, clean
and Simple solutions for common (complex) problems that exist while developing in Javascript.
The created application is an:
The image below shows what the AngularJS+Firebase application looks like, with the urls shown in the
background browser being the ones requested when the TeamMentor website is loaded or navigated (note
that the latency between request made _and _request listed is really small (about 50 milliseconds)):
What I also like about the AngularJS structure that I ended up with, is that it represents a great way to learn
AngularJS architecture and capabilities (and yes I know and agree that for bigger AngularJS apps it is better
to organise by feature and group the multiple files under a dedicated folder (for example the login controller,
service, factory, view and tests should all go under the same logical folder))
This post contains a tour of the multiple files created (gist here) which where developed/refactored while in
Eclipse using the Eclipse Groovy REPL script to sync a Browser with file changes (with recursive folder search
via Javas WatchService)
Folder/File Structure:
Inside an Eclipse Web Static project, I created a file structure with:
_index.html _as the main AngularJS file (i.e. this is the single-page application file)
Using AngularJS 3
all javascript files were placed in the _js _folder (with the file names providing a clue on what they are
doing/providing)
1 directive created in the directives folder
3 views placed on the views folder
1) Index.html
This is the file loaded directly by the browser, which is made of:
Since Im using the AngularJS Eclipse plugin, hovering the mouse op top of an AngularJS directive provides
a nice description of they do.
Here is the _ng-app _directive
Using AngularJS 4
2) app.js
This is where the project module is created (with two dependencies ngRoute and firebase).
Since I moved the controllers, factories, directives and routes into their own separate js file, there wasnt much
to do here, apart from creating global values for the firebase URL and auth token (which will be dependency
injected into the controllers and factories)
3) controllers.js
This file contains 3 controllers: DebugCtrl, MessagesCtrl and _RequestsUrlCtrl _(each will be used on a
specific view)
Note that each controller has services injected into them (the AngularJS $scope _**and the custom **_-
fbDebugMsg, fbRequestUrl, fbaDebugUrl)
The DebugCtrl _is currently just adding the injected _fbDebugMsg and **fbRequestUrl **services into the
$scope so that we can see them in the view (this is a nice trick to get an inside view of AngularJS objects)
The MessagesCtrl is using the Firebase AngularFire API, which is makes it really easy to create the firebase-
real-time update view (my only problem with this was that there didnt seem to be an easy way to re-order
the new elements (which in the current AngularFire implementation are added at the end of the provided
array)
The _RequestsUrlsCtrl _uses the default Firebase Javascript API (i.e not the AngularFire one) which gives us
more control on how to handle the data received by Firebase. The _$scope.urls _array is used to store the
data received from the Firebase _child_added _event (one note here to say that the Firebase _child_added
_will also provide the entire data-set on first load, which is okish, but I would prefer that the _child_added
_only fired for new events)
Using AngularJS 5
**4) directives.js **
This is a simple directive used by index.html, that will display a top menu, created by the content of the
topMenu.html file (directives are AngularJS way to creating/defining new HTML tags/attributes)
5) factories.js
These factories create the Firebase mappings, namely they define the area (or namespace/object) that the
data will be read from.
The first two (fbDebugMsg and fbRequestUrl) use the Firebase Javascript API. I needed to do them this way
so that I could add the Firebase auth token (that said, Im sure there is a better way to do this in Angular, since
ideally I would have an Angular service that took the two variables that need to be set: the target Firebase
area and auth code)
The _fbaDebugMsg _is just a simple service/factory to return an AngularFire API object based on the
(dependency injected) fbDebugMsg service
6) routes.js
The routes configuration is basically defining the 3 available views (each with a different controller mapped
to it)
Using AngularJS 6
8) messages.html (view)
In this view the $scope.messages (used in the ng-repeat) is populated by the **MessagesCtrl **controller
which is using the AngularFire API. This means that data will be updated in real time (on both add and change
events)
9) debug.html (view)
This view just shows a json representation of the fbDebugMsg and _fbRequestUrl _
All code:
For reference here is the entire source code (gist here) of the source code files shown above:
Btw, did you noticed anything different in the formatting of the code samples above?
Is it easier to read?
If you are interested in the topic of code formatting also see On Java code formatting and Formatting code
for readability
This is the first of four posts on how to run (inside Eclipse) the examples provided in AngularJSs home page:
With the final setup being the conversion into an AngularJS Project
Using AngularJS 10
**NOTE: **The reason this first file is called The_Basics.html is because Im going to be using the examples
from AngularJS home page http://angularjs.org/
Note how the AngularJS Eclipse plugin successfully detects the Angular attributes and showed relevant
information about it.
Here is ng-app:
Here is ng-model:
which basically means that Eclipse is not recognising the AngularJS Html attributes:
Using AngularJS 13
To fix this, I went to the AngularJS_Test _**projects Properties, opened the _HTML Syntax _page
(from the **_Validation section) and set to false the Undefined attribute name **setting (in the
**Attributes options , not the Elements)
With that config change, there are no problems in this page, and hovering on top of one the AngularJS
directives will show the correct tooltip:
with the AngularJS test working as expected (in this case any text typed in the Name TextBox will
automatically be shown in the page:
We can also preview some of the changes in real time, by choosing the Web Page Editor:
which will look like this (note the non-processed HTML at the top and the HTML code at the bottom):
Using AngularJS 15
Opening up the Preview tab (from the default Design tab) will allow us to test the page currently being edited
(note how Angular JS is working):
This means that (when in the Design tab) we can edit the AngularJS HTML page and see the changes
immediately:
NOTE: This version of the Web Page Editor **doesnt render the CSS while in that **Design mode, which
means that if we add bootstrap to this project:
Using AngularJS 16
This was easily solved via the command line (by executing $ git init on the _AngularJS_Tests _folder)
where we can use the Add an existing local Git repository link:
Using AngularJS 19
In order to create a git commit, I also opened the Git Staging view:
This is what these two git views look like (note that there are not commits/references and the list of new files
in the **Unstaged Changes **list)
Using AngularJS 20
To commit the files drag-n-drop them from the Unstaged Changes to the Staged Changes, and write a
commit message:
After clicking the Commit button the _Git Repositories _view will give a visual representation of the location
current HEAD (which is the commit just done)
This is the second of four posts on how to run (inside Eclipse) the examples provided in AngularJSs home
page:
called Add Some Control to the _WebContent _folder of the AngularJS_Tests project
Using AngularJS 22
And inside it, I created the index.html, todo.js and todo.css files (each using the Eclipse default template for
the respective file type)
Using AngularJS 23
Here is what they look like with the content from the AngularJs.org _Add Some Control _sample:
The objective of this sample is to add new _Todos _to the list shown, using the TextBox provided and the add
button
So in the example shown above, after entering This is a new ToDo _on the TextBox and clicking _add a new
item will be added to the list (see below)
We can also remove Todos by using the checkboxes (see above) and clicking on the archive link (see below
for the result)
Using AngularJS 26
which Im going to modify by adding a new paragraph containing the value of the todoText variable
(note that the _todoText _variable is used on the _input _HTML element, auto-wired to Angular by using the
ng-model attribute).
After refreshing the browser, we can see this in action by typing some text on the TextBox and seeing it show
in real time after the **New Todo text: **text (one of the features of AngularJS is to keep all these variables
in sync):
Using AngularJS 27
which can be seen in action by refreshing the browser (note that it is already checked by default, since I
set the done variable to true)
Using AngularJS 28
After refreshing the web browser, we can see that if we add a new todo:
the TextBox (and paragraph below) will have the value _Default value _(vs the original behaviour of being
empty)
Using AngularJS 29
which means that (after refresh) and clicking on the archive link
and lets use that variable to provide visual feedback to the user when the TodoCtrl has executed:
Now, we should see the message _AngularJS controller is all set _just after the page finishes reloading:
Using AngularJS 32
To make it more relevant, lets add a _$scope.message _to the _$scope.addTodo _method:
Finally lets refactor the $scope.addTodo method to so that it doesnt add a new Todo when no value is
provided:
After reloading the page, we can confirm that trying to click on the add button without entering first any
text on the TextBox will show this message:
Using AngularJS 34
and if we add a new one (in this case not an empty todo) we will see this message:
was not being shown inside eclipse (as you can see on multiple screenshots above), but worked ok in
Chrome:
Using AngularJS 35
and stand-alone Safari (note that there is a line-through applied when an item it checked as done)
This is the third of four posts on how to run (inside Eclipse) the examples provided in AngularJSs home page:
to hold the 4 files required for this example: index.html, detail.html, list.html and project.js
project.js :
Using AngularJS 38
list.html :
detail.html :
with a search bar at the top that can be used to filter the loaded data:
Only problem is that it doesnt look at all like it does on the http://angularjs.org page (see below)
Using AngularJS 40
Note how not only the css styles are different, the add and edit links (i.e. icons) are missing:
which looks like this (notice the extra Bootstrap css included that is not present on the code sample provided
in the http://angularjs.org page )
Using AngularJS 42
For reference here is what the Edit Me form looks like in the http://angularjs.org page (with the values passed
as hidden parameters to jsfiddle)
And here is the jsfiddle API description for the method used (http://doc.jsfiddle.net/api/post.html)
Using Chrome Browser Inspector, on the _Styles _tab, I was able to see that they were using two css libraries:
Bootstrap and Font Awesome:
And on refresh, the page looked better (but the edit and add icons/links where still missing)
So I went back to the angularjs.org source code to see what they were using:
First I tried adding the latest Font Awesome from their CDN:
Using AngularJS 44
But since that didnt work, I decided to add both font-awesome.css **and docs.css **references:
But there was still something wrong, since the new page looked like this:
Since it was all good on the angular.org site, my next try was to use the bootstrap.min.css file from it (vs
the CDN)
Using AngularJS 45
and the edit page now looking just like the real thing (note the Search TextBox (above) and the fields
(below))
That said, the layout where still a little bit different (namely the background of the local file which was white).
So I had a look at the style of the example in angular.org and noticed that there was a _div _element with the
bootstrap classes well **and ng-scope**:
Using AngularJS 46
Back in the local file, I edited the index.html to also have a similar div:
And finally the local form looked just like the original:
Here is the page on Safari (left) and Firefox (right), which are loaded ok:
Basically chrome does not allow Cross origin requests from html files loaded from the local disk (which does
make sense from a security point of view).
As a final little comment, in case you noticed that on the Firefox screenshot the Angular content was correctly
displayed but the icons didnt show up, that much be a similar problem with loading Bootstrap or Font
Awesome from the local disk
Using AngularJS 48
Here is the same example running on Firefox browser, so it works when loaded from http:
Firebase
This example uses the Firebase which is a very powerful API to store and sync data in realtime.
After writing this post, I spend some time researching how it works and can be used.
Here are some posts Ive written about Firebase:
Using Firebase to sync data with a webpage (via Javascript, REST and Firebase Admin panel)
XSS considerations when developing with Firebase
Trying out Firebase (Beta) hosting solution and good example of Firebase Security rules
First PoC of sending TeamMentors server-side request URLS to Firebase (and seeing it in realtime in
an AngularJS page)
Using AngularJS 49
This is the last of four posts on how to run (inside Eclipse) the examples provided in AngularJSs home page:
index.html
components.js
Using AngularJS 52
app.js
and bootstrap.css
This example shows how we can create components (i.e directives ) that are able to handle multiple languages
or currencies.
The Localization tab (shown above) is currently set for english (USA) and the Pluralization tab (shown below)
is currently set to English.
This demo also has support for SK, but there didnt seem to be an easy way to change the browsers locale
(so that we can see the SK values in action)
But on the angular.org page they were able to show both US and SK side by side:
load up the angular-locale_sk.js _file followed by immediately creating a module called _ngLocal.sk
load up the angular-locale_en-us.js _file followed by immediately creating a module called _ngLo-
cal.us
create a module called app-us that depends/consumes ngLocal.us
create a module called app-sk that depends/consumes ngLocal.sk
with the text showing in Slovak (well I hope it does, since I dont speak Slovakian :) )
If we wanted to have the site back in english (US), we can change the ng-app to be app-us
Using AngularJS 55
After choosing the Share Project **menu option, **I was asked to chose the Git repository type (which is
a bit weird since this was already a Git repository)
and chose to use the repository in the parent folder of the selected project:
Using AngularJS 57
Once that completed, I was able to see the Compare With -> HEAD Revision option:
Im adding a number of AngularJS views to TeamMentor, and here is a simple HTML based source code editor
inspired on the How to Integrate Codemirror With Angular UI post and ui-codemirror repository.
In the end, these are the APIs I used:
http://angularjs.org/
http://angular-ui.github.io/bootstrap/
http://twitter.github.io/bootstrap
http://codemirror.net/ (just the core bit)
The source code editor is showing the contents of the current page (dynamically fetched using Angular
$http.get) and the bottom yellow div is showing (in real-time) the contents of the source code editor:
What is nice about this example is that I didnt use jQuery at all!
The great posts http://stackoverflow.com/a/15012542 and AngularJS for jQuery Developers explain why
learning to code in Angular without JQuery is so important.
Basically, its better not have jQuery available, since them, the only way to solve a problem, is the AngularJS
way :)
How it works:
Here is a brief explanation of the code behind this PoC (included in full at the end of this page):
Using AngularJS 59
use a controller to get the code to show (using $http.get) and assign it to the the_ $scope.code_ variable
configure angularJS in the HTML by setting the textarea element to be a codemirror (linked to the
**$scope.code **model)
finally show the current value of $scope.code in side an bootstrap alert element
Using AngularJS 60
1 <!DOCTYPE html>
2
3 <html>
4 <head>
5 <title>CodeMirror with AngularJS</title>
6 <link href="/Content/bootstrap.min.css" rel="stylesheet">
7 <script src="/Scripts/angular.min.js" type="text/javascript"></script>
8 <script src="/Scripts/angular-ui.js" type="text/javascript"></script>
9 <script src="/Scripts/ui-bootstrap-tpls-0.3.0.min.js" type="text/javascript"></scr\
10 ipt>
11
12 <link href="/Content/codemirror-3.01/codemirror.css" rel="stylesheet"/>
13 <link href="/Content/codemirror-3.01/theme/rubyblue.css" rel="stylesheet"/>
14 <script src="/Scripts/codemirror-3.01/codemirror.js" type="text/javascript"></scri\
15 pt>
16 <script src="/Scripts/codemirror-3.01/mode/javascript.js" type="text/javascript"><\
17 /script>
18
19
20 <script type="text/javascript">
21 var myApp = angular.module('myApp', ['ui', 'ui.bootstrap']);
22
23 myApp.value('ui.config',
24 {
25 codemirror:
26 {
27 mode: 'javascript',
28 lineNumbers: true,
29 matchBrackets: true,
30 theme: 'rubyblue'
31 }
32 });
Using AngularJS 61
33
34 function codeCtrl($scope,$http)
35 {
36 $scope.docLocation = document.location.href;
37 $http.get($scope.docLocation)
38 .success(function (data)
39 {
40 $scope.code = data;
41 });
42 //$scope.code = "var a = 'somecode'; \n//which also shows above</h1>";
43 }
44 </script>
45 </head>
46 <body ng-app="myApp">
47 <div class="well well-large">
48 <div class="container">
49 <h2>CodeMirror working with AngularJS and Bootstrap</h2></div>
50 </div>
51 <div ng-controller="codeCtrl">
52 <div class="container">
53
54 <h4>Code Editor:</h4>
55 <p>With the the contents of this page (i.e.: {{docLocation}} )</p>
56
57 <textarea ui-codemirror ng-model="code"></textarea>
58
59 <br/><hr/><br/>
60
61 <h4>Bootstrap alert style</h4>
62 <p>
63 Showing in real time the contents of the code shown above (make a chan\
64 ge to try it)
65 </p>
66 <alert type="success">{{code}}</alert>
67 </div>
68 </div>
69 </body>
70 </html>
When I try to understand how a particular technology works I always like to create a simple test case with a
small number of moving parts.
This post shows such example for an AngularJS page, a Jasmine test, a NodeJS web server and a KarmaJS
execution cycle.
The files used/customised were based on the KarmaJS test/e2e/angular-scenario example:
1 <!DOCTYPE html>
2 <html xmlns:ng="http://angularjs.org" id="ng-app" ng-app>
3 <head>
4 <meta charset="utf-8">
5 <title>Sample Angular App</title>
6 <script src="angular.min.js"></script>
7 </head>
8 <body>
9 <div>
10 <label>Name:</label>
11 <input type="text" ng-model="yourName" placeholder="Enter a name here">
12 <hr>
13 <h1>Hello {{yourName}}!</h1>
14 </div>
15 </body>
16 </html>
1 module.exports = function(karma)
2 {
3 karma.configure(
4 {
5 // generic
6 frameworks : ['ng-scenario'],
7 urlRoot : '/__karma/',
8 autoWatch : true,
9 plugins : ['karma-ng-scenario'],
10
11 //project specific
12 proxies : { '/': 'http://localhost:8000/'},
13 files : ['singleTest.js'],
14
15 //run specific
16 singleRun : true,
17 });
18 };
5) server.js is a working Web NodeJS server (also reduced for easier reading):
KarmaJS 65
91 'png': 'image/png',
92 'manifest': 'text/cache-manifest'
93 };
94
95 StaticServlet.prototype.handleRequest = function(req, res)
96 {
97 var self = this;
98 var path = ('./' + req.url.pathname).replace('//','/').replace(/%(..)/g, function(\
99 match, hex)
100 {
101 return String.fromCharCode(parseInt(hex, 16));
102 });
103 var parts = path.split('/');
104
105 fs.stat(path, function(err, stat)
106 {
107 if (err)
108 return self.sendMissing_(req, res, path);
109 return self.sendFile_(req, res, path);
110 });
111 };
112
113 StaticServlet.prototype.sendFile_ = function(req, res, path)
114 {
115 var self = this;
116 var file = fs.createReadStream(path);
117 res.writeHead(200,
118 {
119 // CSP headers, uncomment to enable CSP
120 //"X-WebKit-CSP": "default-src 'self';",
121 //"X-Content-Security-Policy": "default-src 'self'",
122 'Content-Type': StaticServlet.
123 MimeMap[path.split('.').pop()] || 'text/plain'
124 });
125 if (req.method === 'HEAD')
126 {
127 res.end();
128 } else
129 {
130 file.on('data', res.write.bind(res));
131 file.on('close', function()
132 {
133 res.end();
134 });
135 file.on('error', function(error)
KarmaJS 68
136 {
137 self.sendError_(req, res, error);
138 });
139 }
140 };
141
142 StaticServlet.prototype.sendError_ = function(req, res, error)
143 {
144 res.writeHead(500, {
145 'Content-Type': 'text/html'
146 });
147 res.write('<!doctype html>\n');
148 res.write('<title>Internal Server Error</title>\n');
149 res.write('<h1>Internal Server Error</h1>');
150 res.write('<pre>' + escapeHtml(sys.inspect(error)) + '</pre>');
151 sys.puts('500 Internal Server Error');
152 sys.puts(sys.inspect(error));
153 };
154
155 StaticServlet.prototype.sendMissing_ = function(req, res, path)
156 {
157 path = path.substring(1);
158 res.writeHead(404, {
159 'Content-Type': 'text/html'
160 });
161 res.write('<!doctype html>\n');
162 res.write('<title>404 Not Found</title>\n');
163 res.write('<h1>Not Found</h1>');
164 res.write('<p>The requested URL ' + escapeHtml(path) +
165 ' was not found on this server.</p>');
166 res.end();
167 sys.puts('404 Not Found: ' + path);
168 };
169
170 // Must be last,
171 main(process.argv);
Since we have singleRun **set to true (in **karma.conf.js), the karma process ends after each execution,
which means that the captured browsers will go into a wait state (i.e. waiting for another karma server to
come back to life)
So here it is, a petty small example of a really powerful combination of technologies (and UnitTests workflows)
**NOTE: while creating this post, I wrote an O2 Platform C# script to help **
this script created a nice integrated test UI
Which allowed me to (in the same window) make changes and see its impact
C# script of UI shown above
The source code of the test is shown in the Eclipse Java editor
Just below is the console out of the Karma runner (which is detecting files changes)
On the top-right is the hooked browser (i.e. the one that will run the tests)
On the middle-right is the simple AngularJS Hello World page
On the bottom-right is the debug view of the hooked browser (which is what you get if you click on
the Debug Button included on the top-right page)
Here are the tools and Eclipse Plugins used to create this UI:
The code used on this sample is based on my past attempts of using Karma (see A small AngularJS Jasmine
test executed by KarmaJS , Running KarmaJSs AngularJS example test/e2e/angular-scenario (on Chrome)
and KarmaJS related posts)
Although the AngularJS and NodeJs Eclipse plugins provide nice helpers and views, they didnt provide (yet)
the kind of UI that I was looking for. Namely they didnt support the use of KarmaJS to run AngularJS tests.
But since I now have the ability to quickly manipulate and create new Eclipse views without restarting Eclipse
(using the Groovy REPL script environment ) it was not very hard to create the UI that I wanted (see Eclipse
Plugin that allows the execution of REPL Groovy Scripts (in the current Eclipse Instance) and Fluent API for
Eclipse+SWT).
Basically the brief was to:
KarmaJS 73
Create new (Eclipse) view with a browser showing _http://localhost:9879/__karma/ _(the KarmaJs
browser runner/hook)
Create new view with a browser showing http://localhost:9879/index.html (the AngularJS page)
Create new view with a browser showing _http://localhost:9879/__karma/debug.html _(debug view of
Karma runner), with an toolbar button to refresh it.
Here is the gist with the code that creates this 3 Eclipse views:
Hopefully this Groovy script is easier to read (the idea of the Fluent API that I added to the Groovy REPL
was allow the easy reading and understanding of scripts like this).
1) Setting up the environment
Now lets look at how this environment was setup:
We start with a simple AngularJS project test page that will just show the model-binding capabilities of
AngularJS (yes I know that all those JS files should be in separate folders :) )
Then I opened up Groovy REPL script environment_ _and wrote the script (shown above) that creates the
multiple views:
which (as seen in the first screenshot of this post) looks like this:
Part of this UI (but not created using the Groovy script) is an Eclipse Console _with the _Karma Runner
process console **out **:
The AngularJS tests were executed when the Karma Runner view was opened, because the Karma process
(configured via Karma.config.js) is set to wait for new browsers hooks/runners and (on connection or code
changes) execute the configured tests.
2) Making changes to existing tests
To see Karma in action, lets make a test fail :)
The current AngularJS page is basically just echoing/binding the contents of the Name TextBox into the H1
tag:
KarmaJS 75
Here is the test that is currently being executed, which is an e2e test that runs on the browser (just like
Selenium or Watin).
To make this test fail, lets change just the **yourName **value:
Immediately after saving the test with the changes shown above, Karma refreshes the hooked browsers in
order to trigger the execution of the tests.
And as the image below will show, there is now one failed test:
KarmaJS 76
In cases like this, the _Karma Runner - debug _is very useful since it will show more details on what
happened, and where the test failed:
Just to confirm that the page is actually being loaded and the tests are happening in a real browser instance,
if we add an Javascript alert to the current test:
we will get an alert box in the Karma Runner - debug (note that on the screenshot below we are seeing
the image of the final state of execution of the previous test (in this case the A small Angular Test)
Eclipse is in the background (containing the views previously created and showing the console out of
the Karma test runner process)
There are 3 stand lone browser windows (Chrome, Safari and Firefox)
Firefox (top most window) shows the tests being executed (in green the test executed, in yellow the test
being executed)
After execution, a quick look at the Karma runner shows that the modified test failed (as expected) on all
browsers:
Just to make sure all is working as expected, lets create a test that will fail only in one browser.
For example Firefox is the only one that has defined the navigator.userAgent.contains Javascript function
(so we can use this to detect Firefox, and create a test that will only fail if executed inside it):
After saving the changes, the tests will be executed on all 4 browsers, with the one test that failed being the
one executed in Firefox:
KarmaJS 78
Refreshing the Firefox debug runner, shows the failed test and assert:
4) Setup
In addition to creating the views programatically, I also setup an Eclipse_ Run configurations** for **_-
NodeJS and an _External Tools Configuration _for KarmaJS.
The NodeJS configuration was done here:
which contains a simple NodeJS web server (we could also had used NodeJS Express, but that would had
added a lot of other stuff to this project)
Note: I started the Karma process like this because there was an issue with KarmaJS finding the **NodeJS
**executable from Eclipse (and at the time I didnt had time to debug why that was happening)
External References:
To learn and get an idea of how Karma (the Spectacular Test Runner for JavaScript) works, and how it can
be used to create browser automations tests, here are the steps I took to get the test/e2e/angular-scenario
example to work.
It all started with a clone of: git@github.com:karma-runner/karma.git
With this KarmaJS test example (see below), being the one that we are going to use:
I then opened an nodejs command prompt and navigated to the folder shown above:
on port 8000:
The test case we are using (on KarmaJSs test/e2e/angular-scenario) is a simple AngularJS example, which
just consumes the angular-min.js file model attribute:
and uses angular to populate the {{yourName}} value dynamically (wired to the input field via the ng-
model=yourName)
Next we are going to run this Jasmine (Behavior-Driven Development framework for testing JavaScript code)
test using KarmaJS
KarmaJS 84
but it didnt
There is a module dependency missing, which in this case can be resolved by running this command from
the root of the karma repository:
UPDATE: the issue above was caused by the fact that I had an the official released version of karma
installed globally which is the one that was running when I tried it on the test/e2e/angular-scenario
folder
And now (based on an option from the karma.conf.js) a Chrome window opened up:
In this case the problem is that the proxy mapping that karma does is not correct
If we look at the karma.config.js file
we can see that karma will try to open /index.html from http://localhost:8000/test/e2e/angular-
scenario/index.html
KarmaJS 86
That is not going to work since the page we want it is on http://localhost:8000/index.html (which happened
because we started _node server.js _on the** /test/e2e/angular-scenario **folder)
_
and after stopping and starting the karma server:
the karma runner will detect the changes and rerun the tests (note that there are 2 tests executed now)
This 2nd test shows an interesting behaviors since it will make the test wait for 15 seconds (with the browser
window opened):
KarmaJS 88
Note how the time execution time for the 2nd test was 15 secs
the execution test UI will look like this (note that the execution was triggered when I saved the test file :)
**NOTE 1: **to solve the ENOENT error shown the first screenshot of localhost:8000, we just needed to a
KarmaJS 89
Note 2: **when trying to run Karma for the first time, I had a prob with grunt where it was failing with
an **Error: spawn ENOENT:
this was resolved by installed the 32bit version of nodeJS and running npm install on the karma folder
(after cloning it)
After getting my head around how Firebase works (see Using Firebase to sync data with a webpage (via
Javascript, REST and Firebase Admin panel) and Trying our Firebase (Beta) hosting solution and good example
of Firebase Security rules), I really wanted to see how it could work on a key feature that Ive been wanting
to add to TeamMentor for ages: Realtime ****viewing of ****traffic and logs
And it worked :)
This is really exciting!!! (can you tell :) ), specially since I can see so many great uses of this type of technique
and technology in TeamMentor (for example it will allow for much better understanding on how the content
is used, and for better collaboration between its readers (and authors))
Im going to write a number of blog posts that explain how this works in detail, but the core of it is the C#
code shown below (gist here) which is running on a test TeamMentor instance, and basically hooks into the
ASP.net HTTP pipeline in order to send the current URL to Firebase (using Firebases REST API):
Here is the AngularJS+Firebase Html app that I created in Eclipse which shows the data received from the
TeamMentor website (i.e. all requests made by a client visiting its home page):
Quick look at the C# code executed on the TeamMentor server **(gist here):**
Here is how the HTTP pipeline is hooked (using the TMEvents helper object from TM)
the logDebugMsg and logRequestURL lambda functions are used to set the Firebase object to store the
received messages:
the sendData lambda function is used to configure the Firebase target app and authorisation token:
the **sendData_Raw **lambda function is the one that sends the REST/POST request to the mapped Firebase
app:
3.2 Trying out Firebase (Beta) hosting solution and good example
of Firebase Security rules
Since Firebase now offers a Beta hosting service (and I was looking for a quick way to publish one of the
firebase PoCs Im working at the moment), I decided to take it for a spin.
I have to say that Im really impressed with the end result, and as you will see below, there entire process
(from install to published website) was really smooth.
Note 1: in the example below I already had created an Firebase app to hold the data (see Using Firebase to
sync data with a webpage (via Javascript, REST and Firebase Admin panel) for details on how to create one)
Note 2: at the time I wrote this post, the website created is/was (depending on when you are reading this)
hosted at https://tm-admin-test.firebaseapp.com/
Starting with the instructions from Firebase hosting page:
**
**
**
**
2) Run the firebase BootStrap
Firebase 95
after logging in (above), we are asked to chose the firebase app to use (below)
Here are the files created locally (all under the tm-admin-test folder)
changed))
**
**
Anonymous users can read all data, but not write by default
The syncedValue object can be read and written by all
there is a validation on this field that ensures that it is not empty and not bigger that 100 chars
The messages object (i.e. firebase section/subdomain):
can be read by all
each message must include a property called_ text _with a max length of 1000 chars
(I think) the .validate = false means that no other properties can be added
the users object:
each $user child object:
* can be read if the current user matches its name (i.e. it is logged in as that user)
* each user can write into two fields: name and email (both with a max length of 2000)
Firebase 98
6) Create an account
To test the provided authorisation solution, lets start by trying to login with an account that doesnt exist:
then click on the Register button (which just adds a confirm pass field)
Here is what the post register/login page looks like (note that the top-menu-bar login link was also changed
to account)
Firebase 99
Clicking on home takes us to the first page, which also shows a different message (now that we are logged in)
Interestingly the Chat page doesnt seem to take into account that we are logged in now (would be nice to
show the current user in the message posted)
b) here is the messages object (which is a firebase kind-of-array, based on a name/value pair. The name is
the node text (for example_ -JGoCMZRRGo1WQHmYxmc) and the value is the child _text node value (for
example _test _)):
Firebase 100
c) There was a new users node/object in the root of the apps data:
which contains the user provided (and editable by that user) data (email and name)
Wrapping up
**
**Kudos to the Firebase team for providing such easy-to-use hosting solution (next step for me is to try to use
it in the TeamMentor PoC Im currently working on)
**
Firebase 101
**For reference the AngularJS+Firebase website that was created by the Firebase cli tool, is the one available at
https://github.com/firebase/angularFire-seed (which contains a nice **README.md **file with more details)
Programatically changing an AngularJS scope variable and adding Firebug Lite to an AngularJs app
Hubspot current.js code includes JQuery on it
Submitting TM users to HubSpot via TBOT interface (using Angular JS)
In this post Im going to show two really nice tricks that help when developing AngularJS applications:
Lets say that we are inside Eclipse and have this simple AngularJS app (gist here)
To add Firebug Lite to this page, all we need to do is to add a script reference to https://getfirebug.com/firebug-
lite-debug.js
Misc Tricks 104
and after refresh we will have a nice Firebug Lite console (and other nice goodies) at the bottom of our
page :)
Next lets see how to access and change the AngularJS $scope of the ContactController.
The objective is to access programatically the New Contact value (set below to Hello Firebug :) )
In Firebug Lite, we can access the scope object by executing: var scope = angular.element(document.body).scope()
Misc Tricks 105
If we change the New Contact value here (in Firebug Lite) using scope.newcontact = Hello AngularJS
we will notice that the value will not automagically (ala AngularJS way) change in the binded (via ng-
model) input field
The reason that didnt happen is because the change was done outside the AngularJS $digest cycle.
The solution is to call the scope.$apply() function (and the input field will be updated):
Misc Tricks 106
Although Im using Angular.js on the HubSpot TBot page (see Submitting TM users to HubSpot via TBOT
interface (using Angular JS) ) Im still more comfortable/knowledgeable in jQuery, so I decided to use it to
populate the HubSpot fields.
So my first action was to load jQuery at the top of the TBot page:
I noticed that they had embedded jQuery _**in the **_current.js code, namely at the window.hsJQuery
variable
this means that we can use jQuery to access the pages DOM
And the previous code (that used the $) is working again (now using the JQuery version from current.js)
Following the need to submit TM new users to HubSpot, I just created an TBot razor page (TM admin script)
that uses Angular JS to get data about a particular user and populates a form that can then be submitted to
HubSpot.
Here is what the Form looks like for the admin user (value provided on the url):
Pressing the Submit button will send the data to HubSpot which is captured like this:
This works using the new HubSpot form API and Structure (which is quite nice).
The form is created using this HubSpot provided script:
Misc Tricks 111
5.1 Eclipse Groovy REPL script to sync a Browser with file changes
(with recursive folder search via Javas WatchService)
Since I am using Eclipse to develop using AngularJS (see Creating an Eclipse UI to run AngularJS e2e tests
using Karma), I needed a way to refresh the browser window every-time I made changes to any AngularJS
related file (note that due to the nature of the AngularJS projects, I need the change to trigger on any change
made inside the root folder and all its subfolders).
Since there didnt seem to be an easy way to do this (auto browser refresh on file changes) in Eclipse, I used
the Eclipse Grovy REPL Scripting Environment to develop a script/macro that:
For reference here is the groovy code for this script (gist here):
Originally I had tried to use Eclipse file change events (like on this SO thread), but that didnt work as well
as the WatchService.
A next step is to create a mini UI to allow the configuration of the target files (maybe as a view added to the
next version of the Groovy REPL Eclipse plugin)
Seeing it in action
**
**Here is how to test this script:
1) create a Web project with an Html file on it:
IDEs 114
2) run the Groovy code in the REPL window (note that the image below is using a different root file and the
version of script is an older one (which didnt contain the recursive folder monitoring)):
on execution you will see a new view (called Synced WebBrowser) show up in your current Eclipse instance.
3) make some changes on the Html file
4) and note that the Synced WebBrowser view will be refreshed automatically (it takes about 500ms to 1s
for the change to be picked up (see this SO answer for why I had to use the SensitivityWatchEventModi-
fier.HIGH setting on the WatchService))
5) if you open the TeamMentor Console, you will also see a number of log messages that help to see what is
going on:
8) note that the the log message shows the events being triggered and the resetting of the WatcherService:
5.2 Eclipse Groovy script to remove the busy image from the
WebBrowser Editor
Now that Im doing AngularJS and Firebase development inside Eclipse, there was a little thing that was
starting to drive me crazy: The animation icon on the top right of the Eclipse WebBrowser!
**
Apart from the mosaic 2000s look (which is kinda ok), there is a big problem with pages that keep
running for a while: **the animation doesnt stop!
_
_This means that if you are developing inside Eclipse, there is this thing (i.e. the top right icon) that keeps
moving and demand my brains attention:
Since there didnt seem to be an preference or option to disable this behaviour, it was time to open up the
Eclipse Grovy REPL Scripting Environment and fix it with a script :)
The solution
After a quick prototyping, I come up with this script to remove all icons from all opened WebBrowser editors
(gist here):
2) then I looked at the list the ids of all current opened editors, and found one that sounded promising:
org.eclipse.ui.browser.editor
3) to confirm that that was the one I wanted, I looked at the **titles **of the current editors, and confirmed
that the browser window I want to capture was there (the title was Angular with Firebase Lite);
4) now that I knew the title, it was easy to get an EditorReference to it:
5) everytime I have an object reference that I want to take a look, I call the _show({object}) _viewer, since
that will give me a nice TreeViewer of all methods, fields and properties ( see Viewing Eclipse and SWT
objects (Workbench, Display and Shell) using Groovys ObjectBrowser and using TeamMentors Plugin
ObjectBrowser for more details how this works)
IDEs 118
6) in this case we dont want the _EditorReference _object. What we really want is the actually editor, which
can be retrieved by invoking the getEditor(true) _**method (note how the object we are currently seeing
in the **_Object Browser is the org.eclipse.ui.internal.WebBrowserEditor)
8) Inside the webBrowser object I found the busy field (which is an org.eclipse.ui.internal.browser.BusyIndicator
object)
9) and finally inside the** busy object I found the **visible property (ie the getVisible and **setVisible
**methods)
10) back in the REPL, it was time to do the same thing programatically.
First I got a reference to the webBrowser field:
IDEs 120
11) Once I had the reference to the busy field, it was easy to make it invisible (by just setting the visible
property to false)
12) final step was to write a generic script that would work on all opened browser editor windows (a robust
script would use the same trick I used in the integration with the Fortify plugin, where a callback is received
on every new view opened (i.e. we could wait for new instances of the **org.eclipse.ui.browser.editor **to be
opened, and apply the fix then))
Note: another way to to stop the constant animation was to just set the stop value to false, but this would
only work for the current opened page (i.e. the animation would be back on page reload)
To help me debug and visualize an AngularJS page I was developing, I used the O2s Window Handle Hijack
technique to insert an Chrome window inside VisualStudio 2010.
Here it is in action:
On the right you can see a full chrome window, inserted inside a VisualStudio dockable pane.
On the left you can see the AngularJs file (rendered from a RazorSharp template) that I can edit and quickly
view its output on the right-hand-side Chrome window (with no web recompilation needed)
To create this, I searched in O2 Platform for the Util - Win32 Window Handle Hijack (simple).h2 script
to create a native VisualStudio pane with the Windows Handle Hijack Gui
With this GUI, we can grab any Windows Window, by dragging the target icon (top left) into the window
we want to use/hijack:
IDEs 124
Tip: before Hikacking a window, it is a good idea to take a screenshot and see if we have the right one:
Once were sure, just hit the _Hijack _link, and we will have have a fully functional Chrome window that
we can place anywhere inside VisualStudios GUI.
For example, we can place it in the documents area as one of the source code files
(tip: double click on the Hijacked Window/Control text to hide the hijack controls)
IDEs 125
As a final example, here is what it looks like if we just Hijack the browsers website window (without the
navigation and top bars)
Following from the example described inWhen the best way to automate Chrome is to use Chrome , here is
a more practical scenario where Im creating a GUI that has both WebStorm and Chrome running side-by-side
Here is what it looks like:
What makes this example practical is the KarmaJS auto execution on file change, just like it was described in
Adding KarmaJS support to WebStorm to automagically run tests on file changes
Here is the code that creates this GUI (with some functionality since the last example, but it still needs to a
bit of work to make it more robust):
When executed for the first time, this GUI looks like this:
Refreshing the browser will capture it and manually execute the tests:
IDEs 128
Opening up the normal page will start the auto test execution loop:
and if we add a new test and save the file, the unit test execution will occour
Note: there is some kind of weird event race-condition happening and the keyboard keys events are not being
fired inside the captured WebStorm. So in the case shown above, I open the file to edit in a WebStorm popup
window, where the keyboard events fire-up ok (and I was able to make the changes to the unit test file)
On the topic of Web Automation, I always wanted to have a REPL environment for Chrome like I have for IE
(using Watin).
In the past I have explored multiple solutions, for example the use of CefSharp (see here and here). But that
was never the real thing, and there was always a couple issues (caused by the fact that the real chrome
wasnt being used).
For a while, in the back on my mind the solution was simple and obvious: Use the real Chrome process in
a way that it can be programmatically accessed from an O2s C# repl environment!
Well, the good news is that is exactly what I have done :)
I just created the Gui you can see below, which uses the Window-Hikacking technique to inject an (Seleniums
ChromeDriver started) Chrome process window in a Panel, and pass its reference (as a variable) to an O2
REPL environment.
The script is called_ Util - Chrome Browser with REPL.h2_ and it has:
The cmd.exe window from the ChromeDriver.exe process in the bottom right
The Chrome window (started by the ChromeDriver) in the top right
A C# REPL (with the CromeDriver object passed in as a parameter) in the left
Which will:
next I create a number of variables with the url and commands to execute:
here:
And this is all programmed in a nice REPL environment, which makes it really easy to try thing out.
For example, here are a couple interesting two way data exchange between the C# script and the
Chrome javascript:
1) get an int value
4) get an array
9) show an alert
which will populate the search text value and click on the search icon
IDEs 134
What is cool about all these examples is that we are running the code on the local installation of Chrome, ie
it is the actually chrome process that we are using, which is great for testing, debugging and developing :)
Scripts used in this post
A) C# code that created the GUI (start chromeDriver and chrome processes and hijack they main
window)
31
32 //O2Ref:WebDriver.dll
33
34 **B) first code example (open Google and do a search)**
35
36
37 chromeDriver.open("http://www.google.com");
38 chromeDriver.FindElement(By.Name("q"))
39 .SendKeys("O2 Platform");
40 chromeDriver.FindElement(By.Name("btnG"))
41 .Click();
42 return "done";
43
44 //using OpenQA.Selenium;
45 //O2Ref:WebDriver.dll
46 //O2File:API_ChromeDriver.cs
47
48 **C) 2nd code example, open AngularJS page and programmatically change a $scope variable**\
49
50
51
52 var url = "http://localhost:12120/AngularJS/Tests/AngularJS/Simple.html";
53
54 //var jQuery = "http://code.jquery.com/jquery-1.10.1.min.js".GET();
55 var jQuery = "jquery-1.9.1.min.js".local().fileContents();
56 var angular_Cmd1 = "scope = angular.element($('input').eq(0)).scope()";
57 var angular_Cmd2 = "scope.yourName='12345'";
58 var angular_Cmd3 = "scope.$apply()";
59
60 var console_Cmd1 = "console.log('all done, hello should say 12345')";
61
62 chromeDriver.Navigate().GoToUrl(url);
63
64 chromeDriver.ExecuteScript(jQuery);
65
66 chromeDriver.ExecuteScript(angular_Cmd1);
67 chromeDriver.ExecuteScript(angular_Cmd2);
68 chromeDriver.ExecuteScript(angular_Cmd3);
69
70 chromeDriver.ExecuteScript(console_Cmd1);
71
72 return "done";
73
74 // doesn't work to open chrome's inspector
75 // chromeDriver.Keyboard.SendKeys(OpenQA.Selenium.Keys.F12);
IDEs 136
76
77 //using OpenQA.Selenium;
78 //O2Ref:WebDriver.dll
79 **D) last example where search filed was retrieved using two different techniques:**
80
81
82 //open Url
83 /*chromeDriver.ExecuteScript(
84 "document.location= 'http://localhost:12120'"); */
85
86 //Getting the SearchTextBox object via ExecuteScript
87 var searchElement = (RemoteWebElement)chromeDriver.ExecuteScript(
88 "return document.getElementById('SearchTextBox')");
89 searchElement.Clear();
90 searchElement.SendKeys("Sql ");
91
92 //Getting the SearchTextBox object via Selenium selector
93 chromeDriver.FindElement(By.Id("SearchTextBox"))
94 .SendKeys("Injection");
95
96 //Click on search Button
97 chromeDriver.FindElement(By.Id("ctl00_ContentPlaceHolder1_SearchControl1_SearchButton"))
98 .Click();
99
100 return "done";
101
102 //using OpenQA.Selenium.Remote
103 //using OpenQA.Selenium;
104 //O2Ref:WebDriver.dll
On the AngularJs **and KarmaJS** theme (see A small AngularJS Jasmine test executed by KarmaJS and
the related posts linked at the bottom), here is my first attempt at using Karma to test AngularJS code inside
TeamMentor.
Im using WebStorm instead of VisualStudio, since for Javascript coding WebStorm is MUCH better/faster/-
cleverer, specially since it has good support for AngularJs and Jasmine (with KarmaJS support easily added,
as we are about to see).
Also shown below is a cool tool I created that hijacks windows from SublimeText, Chrome and Cmd.exe
windows into the same UI (an O2 Platform .NET Script)
Here is the directory structure:
1 module.exports = function(karma)
2 {
3 karma.configure(
4 {
5 frameworks: ['ng-scenario'],
6
7 files:
8 [
9 '../Tests/**/*.Spec.js'
10 ],
11
12 urlRoot: '/__karma/',
13
14 autoWatch: true,
15
16 proxies: {
17 '/' : 'http://localhost:12120/',
IDEs 138
18 '/Tests': 'http://localhost:12120/AngularJs/Tests/'
19
20 },
21
22 //browsers: ['Chrome'],
23
24 reporters: ['dots'], //reporters: ['progress'],
25 plugins: [
26 'karma-ng-scenario',
27 'karma-chrome-launcher'
28 //,'karma-firefox-launcher'
29 ] ,
30 //logLevel: karma.LOG_DEBUG
31 logLevel: karma.LOG_INFO
32 });
33 };
1 <!DOCTYPE html>
2 <html xmlns:ng="http://angularjs.org" id="ng-app" ng-app>
3 <head>
4 <meta charset="utf-8">
5 <meta http-equiv="X-UA-Compatible" __content="IE=EmulateIE9" />
6 <title>Simple AngularJS page</title>
7 <script src="/Javascript/angularJS/1.0.5/angular.min.js"></script>
8 </head>
9 <body>
10 <div>
11 <label>Name:</label>
12 <input type="text" ng-model="yourName" placeholder="Enter a name here">
13 <hr>
14 <h1>Hello {{yourName}}!</h1>
15 </div>
16 </body>
17 </html>
Here are two connected KarmaJS Runners (one in IE and one in Chrome)
And finally, here is the (super useful) AngularJS: Scenario Test Runner view, in a collapsed state:
IDEs 141
With this set-up KarmaJS is configured to run continuously and to monitor any file changes, which is really
powerful, since it allows for continuous development and testing.
For example (to see the automagically execution in action), here is what the WebStorm UI looks like:
** with an Javascript error:** (KarmaJS execution triggered on Save) :
IDEs 142
This is a really nice environment to quickly develop AngularJS apps, specially since the tests are super quick
to execute and we can control what tests are executed (for example by creating multiple karma.conf.js files)
O2 Platform Test GUI (created by hijacking 3 processe windows)
I also created a test GUI using the O2 Platforms window-handle Hijack capabilities, which looked like this:
The host process is the O2 Platform Util - Win32 Window Handle Hijack (4x host panels ).h2 script/tool
(which is a .Net app)
The left-hand side the Sublime Text editor (which is a C++, Pyhton app)
The top-right is Chrome (which is C++ app)
The bottom-right is cmd.exe (C++ app) running the command karma start karma.conf.js
**in the **E:TeamMentorTM_Dev ReposTM_Dev_DinisWeb ApplicationsTM_WebsiteAn-
gularJSKarma folder
KarmaJS AngularJS Scenario Test Runner execution variations in IE 7,8,9 and 10 when using AngularJS
If AngularJS doesnt work on your O2 Platform IE scripts (the fix is to change browser compatibility
mode)
Debugging a weird case of missing module in AngularJS and KarmaJS
Just to confirm that the target page works in the multiple IE configurations, here it is running in:
IE 10 , IE9, IE 8:
and even in IE 7:
Now lets click on the _DEBUG _button to open the KarmaJSs_ AngularJS Scenario Test Runner_ view and
see what happens in multiple IE compatibility modes.
IE 10 Works:
**
**
****IE 10 Compatibility View
Troubleshooting 147
**
**
****IE 9 Fails:
**
**
****IE 8 Works (WTF!!)
**
**
****IE 7 Fails
**
**
Troubleshooting 148
So unfortunately it looks like this technique cant be used to run e2e (end-to-end) tests on AngularJS apps
using KarmaJS
If when trying to open an AngularJS page inside an O2 Platform script, you see:
this means that the IE browser embedded in that .NET process is set to run under IE 7
To confirm it, try opening the http://www.whatismybrowser.com and you should see something like:
As mentioned in the set .NET WebBrowser Control to use latest version of IE post to. change it on your system,
run this script
and now after restarting the O2 Platform process, IE should be on Internet Explorer 9 compatibility mode
**
Troubleshooting 150
**
and AngularJS should work:
**Note 1: **if you control the site you are testing, you can also add this also works to make it work (with the
advantage that it is not exe specific)
When I was trying the Running KarmaJSs AngularJS example test/e2e/angular-scenario (on Chrome) I hit
on the the following weird behaviour.
TLDR; the solution was to run npm install g _****_karma@canary
Setup
**
**Chrome window opened in:
**
****Scenario A) Running from folder with karma clone (and npm install)**
**
****_karma start ..\angular-scenario\karma.conf.js _**works OK
_
So what I think is happening is that because I run_ npm install** on the karma folder (the one I got
from a GitHub clone), there are more modules in there than in the global karma (which I got when
I installed karma using **_npm install g karma)
At the moment there are 49 modules in the GitHub karma:
Troubleshooting 153
_
Troubleshooting 155
March 2013
Using Chrome inside a native VisualStudio pane (using Window Handle Hijacking)
April 2013
June 2013
AngularJS code editor using UI-Bootstrap and CodeMirror (done without using jQuery)
Running KarmaJSs AngularJS example test/e2e/angular-scenario (on Chrome)
Debugging a weird case of missing module in AngularJS and KarmaJS
If AngularJS doesnt work on your O2 Platform IE scripts (the fix is to change browser compatibility
mode)
KarmaJS AngularJS Scenario Test Runner execution variations in IE 7,8,9 and 10 when using AngularJS
A small AngularJS Jasmine test executed by KarmaJS
Adding KarmaJS support to WebStorm to automagically run tests on file changes (and test UI with
SublimeText, Chrome and Cmd.exe)
When the best way to automate Chrome is to use Chrome (with examples on Google search, direct
AngularJS scope manipulation and ChromeDriver javascript access)
Using WebStorm with Chrome and ChromeDriver (to view KarmaJS execution results)
February 2014
March 2014
Eclipse Groovy script to remove the busy image from the WebBrowser Editor
Programatically changing an AngularJS scope variable and adding Firebug Lite to an AngularJs app