Wednesday, December 31, 2014

Testing AngularJS app with Protractor in multiple browsers (OS X)

Different browsers have different quirks, so let's try to run e2e tests in multiple major browsers.
We can't run IE in OS X, Opera is customized Chrome, so we need: Chrome, Safari,  Firefox.

Protractor has option to run specs in multiple browsers, called multiCapabilities.
By default all browsers run tests simultaneously, but in my experience it leads to errors ("failed expectations"), because sometimes tests trying to fulfill same records and it leads to conflicts.
To run tests in browsers consecutive, we can use "maxSessions: 1" in Protractor config.
So result is:

multiCapabilities: [
'browserName': 'chrome'
, {
'browserName': 'safari'
, {
'browserName': 'firefox'
maxSessions: 1,

If you use browserSync to run app locally, add "ghostMode: false" in browserSync config to avoid conflicts in launched versions of app when testing.

But software is often more complicated than we expect.
First: we can't run actual version of Firefox on OS X, even with new Selenium drivers.
Bug has status "Fixed" but nobody cares about regression.

So now we have Chrome and Safari in list.
Safari don't want to run too, hehe :) But it's fixable at least, thanks to this detailed answer.
Get actual version of Selenium driver jar here:
rename extension to .zip, 
unzip file 
and then in folder 'org/openqa/selenium' find file 'SafariDriver.safariextz' (it's not random letters :)) and double-click it.

After that, we can run tests in Safari, hurray!
And it's not the end of this story :)
Selenium can't navigate in browsing history of Safari (known issue), so if you use 


replace it to:

// before changing URL
var prevUrl = browser.getCurrentUrl();
// here some changing URL action, maybe click()
// ...
// and then

It's pretty obvious fix.
And now we can run Protractor tests in Chrome and Safari consecutive. It took few hours of my time to find all these fixes and workarounds, so I hope this article will help somebody to save time :)

Wednesday, November 12, 2014

AngularJS 1.3 and ES6 - how to use it already today

ES6, AtScript

Next version of Angular will use AtScript - superset of ES6 (upcoming version of JavaScript). So, if you write in ES5 (current version of JavaScript), you already write in AtScript, just without all of these optional additions - annotations, types and introspections. Yes, they will stay optional, but it's nice to have them.

We can't use AtScript in existing projects yet (and Angular 2 will be ready even later than AtScript), but we already can use ES6 with AngularJS 1.3, best Angular yet (current stable branch), with all cool things ES6 going to give us. Take it now! :)

How to

I'll show you how to do it on example of the project, bootstrapped by Yeoman's generator-angular. Maybe not top-notch folders structure, but easy to start with.
Source code of project:

Step 1 - install modules

When we have base of project, let's add components:
Grunt will transpile ES6 to ES5 (I know I know, Gulp is our new trend, but.. next time)

npm install grunt-traceur --save-dev

PhantomJS doesn't support ES5 even, so we will run unit tests in Chrome:

npm install karma-chrome-launcher --save-dev

We need traceur runtime in app:

bower install traceur --save

That's all.

Step 2 - Structure

In structure of this project most convenient place I found for ES6 files is /app/es6 - I just copied content of 'scripts' folder here. Now I can use watch, livereload, build project and run tests. Awesome.

Step 3 - Gruntfile

Example of Gruntfile.js
And what has been changed in file, generated by generator-angular:
We add new task, 'traceur' and add it to build, test, serve tasks. 

Step 4 - Unit tests config

replace PhantomJS by Chrome (it will run without taking focus, in background) and add traceur.min.js link.

Step 5 - index.html

Just add link to traceur.min.js

Enjoy ES6!

Now you can use ES6 in your AngularJS project. For example, I use ES6 classes for Services, because I like it and it works :)
Traceur will compile AtScript in the same way it compile ES6 for us in this project, so it's nice to meet Traceur already now and start use advantages of new technologies.

Additional Links

Monday, November 10, 2014

SOA for client-side apps as the way of interoperation

It's idea to discuss and, maybe, implementation.

When building web-apps, we write code for the server side and for the client side. On the server side we can use any language we want - just give API (REST as standard nowadays) and be happy - any app, written in any language (with access to network), can communicate with your programm.

On the client side.. You know, only JavaScript.
TypeScript and even Dart, at the moment I write this, should be transpiled into JS to run in all major browsers. On the web page we can use different JS libraries, jQuery plugins and each one will do it's task and they will not do something in cooperation - in the best case functionality of one library (often jQuery) will be used as a tool in other JS libraries. It doesn't mean they can't coexist - they can and do, but often by the price of tight coupling and only in the scope of one language, so even if you transpile Dart to JS, you can't use all the power of Dart just because of compatibility. And it's the reason why there is not so many new languages for the client side.


I think we could use SOA inside web page, when web app is the set of services, communicating by APIs. So we need transport, like HTTP, and as this transport we can use DOM (what most JS libs use now) or Local Storage (SessionStorage). DOM (and especially Shadow DOM) looks more attractive, because here we can use object.observe and some other interesting things, but DOM requires browser's attention and I'm not sure if this approach is safe in terms of occasional re-renderings, leaked nodes and collisions/pollution with user-defined elements.
In Session Storage we can have more freedom and it's just less dangerous. If we can do dirty-checking with speed of 300 000 checks/ms in JS, then maybe we can something similar with SessionStorage (or DOM at least), and then we can build event dispatchers on top of that and use it as transport for APIs interoperation. It will not be possible to send pointers of functions (as we used to in JS), but it's how a lot of amazing apps work on the servers and on desktops.

If it's implemented already somewhere - please let me know.

Sunday, November 9, 2014

Importance of idempotence - what if POST request will be cached

Couple of weeks ago tester of mobile app I'm building sent us bug report, and described bug was awful - data loss because of wrong synchronization process. Synchronization is always tricky thing to do, but I was sure all works fine because all code, especially of synchronization, is heavily covered by tests (unit and e2e). And all of them were "green".

I've tried to reproduce, as described in report - not reproducible... It's even worse than reproducible.
But what was more interesting - teammates in the USA were able to reproduce it with 100% chance. Really, we demonstrated each other how app behaves and they could reproduce it, I saw it, when I couldn't, even in most difficult cases (for synchronization algorithm)..

As I discovered by symptoms, server has been sending same responses for separate POST requests, when server should generate unique identificator. We checked code of the API - all fine. And for me API doesn't send same responses, so... Yes, responses (or requests) were cached! And cached not by server (nobody will configure server to cache POST requests, I suppose), but somewhere inside the US network between users and server - that's why it wasn't reproducible from my side - I'm testing it from Russia (where I live).

Same "unique" id for different records it's a very dangerous thing and leads to very bad bugs and data losses, so we decided to add random hash to all requests and it solved our issue.

It wasn't difficult to fix, but it was very difficult to find, because I couldn't imagine that POST request can be cached (responses have been sent without touching server, just responses for previous requests with the same signature).

What to think about it? Should we (all programmers) add cache-preventing garbage to each POST/DELETE request? Of course, network providers shouldn't cache POST requests, but we can't force them and can't wait while they'll fix it.

I'm still not sure, so please share your opinions.

Friday, October 10, 2014

How to run WebStorm (IntelliJ IDE) on OS X Yosemite (without legacy JDK)

1. Download Java 7 SDK

2. Open package (it will not install because of bug in checking function)

3. Run in terminal:
pkgutil --expand "/Volumes/JDK 7 Update 67/JDK 7 Update 67.pkg" "/tmp/JDK 7 Update 67.unpkg"

cd /tmp/JDK\ 7\ Update\ 67.unpkg/

4. Open file named "Distribution"

5. Find function pm_install_check() { (it's line 70 at this moment)

6. Change it to always return true:

function pm_install_check() {
  return true;

7. Run in terminal:
pkgutil --flatten "/tmp/JDK 7 Update 67.unpkg" "/tmp/JDK 7 Update 67.pkg"

open "/tmp/JDK 7 Update 67.pkg"

8. Now let's patch WebStorm settings - it's officially recommended way, so copypaste:

To force running under JDK 1.7 edit /Applications/<Product>.app/Contents/Info.plist file, change JVMVersion from 1.6* to 1.7* :

Sunday, September 14, 2014

Typing is not a bottleneck

Some phrases are deep even when short

Wednesday, August 27, 2014

How to not minify already minified on each "grunt build" in yeoman

Long title, yeah.

Let's speed-up Grunt a little

In some of my projects I use yeoman (generator-angular), and on each "grunt build" Grunt runs minification of all JS files from the 'vendor' list (and from 'scripts' also, but it's not a problem).
It takes a long time, especially if you use a lot of external modules.
But most of them already have minified versions, so why to waste a time to minify them again?

I've made Grunt to skip minification of 'vendor' block and it decreased time of 'grunt build' execution in 5 times.

But it wasn't easy (that's why I decided to write this article).

You can't just ask usemin to skip 'vendor', but you can ignore configuration, made by usemin for uglify. To do this, add 'onlyScripts' target to your uglify task:

    uglify:        {
      onlyScripts: {
        files:   [{
          dest: '<%= yeoman.dist %>/scripts/scripts.js',
          src:  ['.tmp/concat/scripts/scripts.js']

Also, now uglify will not copy your vendor.js from temporary folder, so add "vendorJS" section to "copy" task:

      vendorJS: {
        expand: true,
        cwd:    '.tmp/concat/scripts/',
        dest:   '<%= yeoman.dist %>/scripts/',
        src:    'vendor.js'

Then, in "build" task, set target of uglify to 'onlyScripts' and copy vendor.js:

  grunt.registerTask('build', [
    // ...
   // ...

About commented out lines:
 "wiredep" - this task will replace all .min.js-links (in "vendors" block) to .js-links. We don't want to allow it (otherwise our vendor.js will be huge non-minified file).
 "concurrent:dist" - when this task is commented out, Grunt works much faster on MBP with 2 cores. I don't know why. Try it, maybe it will help you too.