[Re-Blog] Dev Chat: Vlad Filippov of Mozilla

July 28th, 2014 by Amber Kaplan

Last week Sauce Labs’ Chris Wren took a moment to chat with Vlad Filippov of Mozilla on his blog. Topics covered all things open source and front-end web development, so we thought we’d share. Click the image below to read the full interview, or just click here.

Dev Chat: Vlad Filippov of Mozilla

 

Announcing Support For Android 4.4 (KitKat)

July 25th, 2014 by Amber Kaplan

Hungry for moar Android? We thought so. kitkat

Announcing Sauce Labs support for Android 4.4 (KitKat)! Now you can test mobile web apps with Selenium Webdriver and native and hybrid apps with Appium using our Android emulators. Nom!

Before you start testing, there are a couple of caveats you should know about:

A. When an Android 4.4. emulator is in landscape mode, its apps are unable to recognize the orientation [1]. Further, while the Android 4.4 emulator looks like it’s in landscape mode, apps will not rotate to reflect this. At this time, there is no known workaround.

B. Certain Appium test runs on Android 4.4 emulators will error out when the Selenium `clear` command is sent [2]. This will only affect test runs that end up using the Selendroid testing framework under the hood [3]. The accepted workaround until a fix can be landed is, instead of using the `clear` command, use the `sendKeys` command, and send multiple DELETE (backspace) keys to clear out any text fields.

Can’t wait to get testing? Visit https://saucelabs.com/platforms to get started now.

Sauce + KitKat FTW.

[1] https://code.google.com/p/android/issues/detail?id=61671
[2] https://github.com/appium/appium/issues/3186
[3] https://github.com/selendroid/selendroid/issues/492

sauce_supports_android_4_4_kitkat

Announcing Cloud9 Preview: Instantly Preview Your Cloud9 Project In Any Browser (Powered by Sauce Labs)

July 24th, 2014 by Jonathan Lipps

Sauce + C9 IntegrationToday our friends at Cloud9 have released a brand new version of their powerful Cloud9 Development Environment, the web-based IDE that gives you unlimited flexibility to develop and test your applications directly from your browser.

As part of this release, we’re excited to announce an integration that we’ve been working on together for a while—the ability to instantly check out the site or app you’re developing in any desktop or mobile browser that Sauce Labs supports, directly in the Cloud9 interface.

Cloud9 has always given you the ability to easily preview the site you’re working on using your current browser. For example, in the screenshot below, you can see the preview window conveniently located where you can work on your code and see the changes reflected immediately:

cloud9 screenshot 1

Our integration simply adds another option to the drop-down menu to the right of the URL bar in the preview pane. If you click “Browser”, you’ll see additional options (it even remembers the last four browsers you used for quick access):

c9browsers

You can select any of our desktop or mobile browsers right from this interface. And if you’re already logged in to Sauce Labs, you’ll see the browser loading immediately. Now you can see whether your “responsive” website actually works as expected on, say, an iPhone Simulator, without ever leaving your IDE:

c9+saucelabs

We think this integration opens up a ton of possibilities for your development workflow, and are proud to be a part of the web-based IDE revolution with Cloud9. Check it out and let us know what you think!

Adding Custom Methods to Data Models with Angular $resource

July 24th, 2014 by Amber Kaplan

Sauce Labs software developer Alan Christopher Thomas and his team have been hard at work updating our stack. He shared with us some insight into their revised dev process, so we thought we’d show off what he’s done. Read his follow-up post below.

Thanks for your great feedback to this post. Previously we examined three different approaches to modeling data in AngularJS. We’ve since incorporated some of your feedback, so we wanted to share that information here. You can also see updates we made in our original post.

One of our commenters made mention of a cleaner approach to adding custom methods to $resource models when our API response response allows it, using angular.extend().

In this implementation, we’re imagining an API response that looks like this:

[
  {
    "breakpointed": null,
    "browser": "android",
    "browser_short_version": "4.3",
    ...
  },
  {
    ...
  }
  ...
]

Each of the response objects in the list is a “Job” that contains a whole lot of metadata about an individual job that’s been run in the Sauce cloud.

We want to be able to iterate over the jobs to build a list for our users, showing the outcome of each: “Pass,” “Fail,” etc.

Our template looks something like this:

{{ job.getResult() }} {{ job.name }}

Note the job.getResult() call. In order to get this convenience, however, we need to be able to attach a getResult() method to each Job returned in the response.

So, here’s what the model looks like, using Angular $resource:

angular.module('job.models', [])
    .factory('Job', ['$resource', function($resource) {
        var Job = $resource('/api/jobs/:jobId', {
            full: 'true',
            jobId: '@id'
        });

        angular.extend(Job.prototype, {
            getResult: function() {
                if (this.status == 'complete') {
                    if (this.passed === null) return "Finished";
                    else if (this.passed === true) return "Pass";
                    else if (this.passed === false) return "Fail";
                }
                else return "Running";
            }
        });

        return Job;
    }]);

Note that since each resulting object returned by $resource is a Job object itself, we can simply extend Job.prototype to include the behavior we want for every individual job instance.

Then, our controller looks like this (revised from the original post to make use of the not-so-obvious promise):

angular.module('job.controllers', [])
    .controller('jobsController', ['$scope', '$http', 'Job', function($scope, $http, Job) {
        $scope.loadJobs = function() {
            $scope.isLoading = true;
            var jobs = Job.query().$promise.then(function(jobs) {
                $scope.jobs = jobs;
            });
        };

        $scope.loadJobs();
    }]);

The simplicity of this example makes $resource a much more attractive option for our team’s data-modeling needs, especially considering that for simple applications, custom behavior isn’t incredibly unwieldy to implement.

Alan Christopher Thomas, Software Developer, Sauce Labs

Appium Bootcamp – Chapter 2: The Console

July 23rd, 2014 by Amber Kaplan

appium_logoThis is the second post in a series called Appium Bootcamp by noted Selenium expert Dave Haeffner

Read:  Chapter 1 Chapter 2 | Chapter 3 | Chapter 4 | Chapter 5 | Chapter 6 | Chapter 7 | Chapter 8

Dave recently immersed himself in the open source Appium project and collaborated with leading Appium contributor Matthew Edwards to bring us this material. Appium Bootcamp is for those who are brand new to mobile test automation with Appium. No familiarity with Selenium is required, although it may be useful. This is the second of eight posts; a new post will be released each week.

Configuring Appium

In order to get Appium up and running there are a few additional things we’ll need to take care of.

If you haven’t already done so, install Ruby and setup the necessary Appium client libraries (a.k.a. “gems”). You can read a write-up on how to do that here.

Installing Necessary Libraries

Assuming you’ve already installed Ruby and need some extra help installing the gems, here’s what you to do.

  1. Install the gems from the command-line with gem install appium_console
  2. Once it completes, run gem list | grep appium

You should see the following listed (your version numbers may vary):

appium_console (1.0.1)
appium_lib (4.0.0)

Now you have all of the necessary gems installed on your system to follow along.

An Appium Gems Primer

appium_lib is the gem for the Appium Ruby client bindings. It is what we’ll use to write and run our tests against Appium. It was installed as a dependency to appium_console.

appium_console is where we’ll focus most of our attention in the remainder of this and the next post. It is an interactive prompt that enables us to send commands to Appium in real-time and receive a response. This is also known as a record-eval-print loop (REPL).

Now that we have our libraries setup, we’ll want to grab a copy of our app to test against.

Sample Apps

Don’t have a test app? Don’t sweat it. There are pre-compiled test apps available to kick the tires with. You can grab the iOS app here and the Android app here. If you’re using the iOS app, you’ll want to make sure to unzip the file before using it with Appium.

If you want the latest and greatest version of the app, you can compile it from source. You can find instructions on how to do that for iOS here and Android here.

Just make sure to put your test app in a known location, because you’ll need to reference the path to it next.

App Configuration

When it comes to configuring your app to run on Appium there are a lot of similarities to Selenium — namelythe use of Capabilities (e.g., “caps” for short).

You can specify the necessary configurations of your app through caps by storing them in a file called appium.txt.

Here’s what appium.txt looks like for the iOS test app to run in an iPhone simulator:

[caps]
platformName = "ios"
app = "/path/to/UICatalog.app.zip"
deviceName = "iPhone Simulator"

And here’s what appium.txt looks like for Android:

[caps]
platformName = "android"
app = "/path/to/api.apk"
deviceName = "Android"
avd = "training"

For Android, note the use of both avd. The "training" value is for the Android Virtual Device that we configured in the previous post. This is necessary for Appium to auto-launch the emulator and connect to it. This type of configuration is not necessary for iOS.

For a full list of available caps, read this.

Go ahead and create an appium.txt with the caps for your app.

Launching The Console

Now that we have a test app on our system and configured it to run in Appium, let’s fire up the Appium Console.

First we’ll need to start the Appium server. So let’s head over to the Appium GUI and launch it. It doesn’t matter which radio button is selected (e.g., Android or Apple). Just click the Launch button in the top right-hand corner of the window. After clicking it, you should see some debug information in the center console. Assuming there are no errors or exceptions, it should be up ready to receive a session.

After that, go back to your terminal window and run arc (from the same directory asappium.txt). This is the execution command for the Appium Ruby Console. It will take the caps from appium.txt and launch the app by connecting it to the Appium server. When it’s done you will have an emulator window of your app that you can interact with as well as an interactive command-prompt for Appium.

Outro

Now that we have our test app up and running, it’s time to interrogate our app and learn how to interact with it.

Read:  Chapter 1 Chapter 2 | Chapter 3 | Chapter 4 | Chapter 5 | Chapter 6 | Chapter 7 | Chapter 8

About Dave Haeffner: Dave is a recent Appium convert and the author of Elemental Selenium (a free, once weekly Selenium tip newsletter that is read by thousands of testing professionals) as well as The Selenium Guidebook (a step-by-step guide on how to use Selenium Successfully). He is also the creator and maintainer of ChemistryKit (an open-source Selenium framework). He has helped numerous companies successfully implement automated acceptance testing; including The Motley Fool, ManTech International, Sittercity, and Animoto. He is a founder and co-organizer of the Selenium Hangout and has spoken at numerous conferences and meetups about acceptance testing.

Follow Dave on Twitter - @tourdedave

Campus Explorer Reduces Testing Time From 72 Hours to 72 Minutes Using Sauce Labs

July 18th, 2014 by Amber Kaplan

We sat down with Senior QA Manager Sage Rimal to hear how they use Sauce Labs at Campus Explorer.  Sage shared how they’ve automated their tests on Sauce, and have since reduced their testing time from 72 hours to 72 minutes.

Watch the video below to get the latest!

Want to share your story? We want to hear from you! Submit a request here.

Appium Bootcamp – Chapter 1: Get Started With Appium

July 16th, 2014 by Amber Kaplan

appium_logoThis is the first post in a series called Appium Bootcamp by noted Selenium expert Dave Haeffner.

Read:  Chapter 1 Chapter 2 | Chapter 3 | Chapter 4 | Chapter 5 | Chapter 6 | Chapter 7 | Chapter 8

Dave recently immersed himself in the open source Appium project and collaborated with leading Appium contributor Matthew Edwards to bring us this material. Appium Bootcamp is for those who are brand new to mobile test automation with Appium. No familiarity with Selenium is required, although it may be useful. This is the first of eight posts; a new post will be released each week. 

Before You Get Started

Appium is built to test mobile apps of all kinds (native, hybrid, and mobile web), has client libraries written in every popular programming language, it’s open source, works on every prominent operating system, and best of all — it works for iOS and Android.

But before you jump in with both feet, know that there is a bit of setup in order to get things up and running on your local machine.

A brief Appium primer

Appium is architected similarly to Selenium — there is a server which receives commands and executes them on a desired node. But instead of a desktop browser, the desired node is running a mobile app on a mobile device (which can be either a simulator, an emulator, or a physical device).

So in order for Appium to work, we will need to install the dependent libraries for each device we care about.

Initial Setup

Testing an iOS app? Here’s what you’ll need:

+ Install Java (version 7 of the JDK or higher)
+ Install Xcode
+ Install Xcode Command-line Build Tools

For more info on supported Xcode versions, read this.

Testing an Android app? Here’s what you’ll need:

+ Install Java (version 7 of the JDK or higher)
+ Install the Android SDK (version 17 or higher)
+ Install the necessary packages for your Android platform version in the Android SDK Manager
+ Configure an Android Virtual Device (AVD) that mimics the device you want to test against

For more info on setting up the Android SDK and configuring an AVD, read this.

Next, you’ll need to install Appium. Luckily, there’s a handy binary for it Appium.app for OSX and Appium.exe for Windows. This binary also happens to be a GUI wrapper for Appium.

Alternatively, if you want the absolute latest version of Appium and aren’t afraid to get your hands dirty, then you can install Appium from source and run it from the command line.

But if you’re new to mobile testing, then the one-click installer is a better place to start.

An Appium GUI primer

The Appium GUI is a one-click installer for the Appium server that enables easy configuration of your app and Appium.

Aside from the easy install, it adds a key piece of functionality — an inspector. The inspector enables a host of functionality, most notably:

+ Shows you all of the elements in your app
+ Enables you to record and playback user actions

inspector_android

While the inspector works well for iOS, there are some problem areas with it in Android on Appium at the moment. To that end, the Appium team encourages the use of uiautomatorviewer (which is an inspector tool provided by Google that provides similar functionality to the Appium inspector tool). For more info on how to set that up, read this.

uiautomatorviewer

More on inspectors and how to use them in a later post.

It’s worth noting that while we can configure our app within the Appium GUI, it’s not necessary since we will be able to do it more flexibly in code. More on that in the next post.

Making Sure Appium Is Setup

After you have your Appium one-click installer up and running, you can verify your setup by using it’s Doctor functionality. It is the button on the left of the `Launch` button. It is the one that looks like a doctor’s stethoscope.

Click on that, and it should output information in the center console window of the Appium GUI.

appium_doctor

If you don’t see anything outputted, refer to this open issue.

What About A Programming Language?

Before you do a victory lap, you’ll also want to have chosen a programming language to write your tests in, installed said programming language, and installed it’s client bindings for Appium.

Currently, Appium has client bindings for JavaJavaScriptObjective C.NETPHPPython, and Ruby.

The examples in this series will be written in Ruby. You can use version 1.9.3 or later, but it’s advisable to use the latest stable version. For instructions on installing Ruby and the necessary client libraries (a.k.a. “gems”), read this.

Outro

Now that you have Appium setup with all of it’s requisite dependencies, along with a programming language and Appium client bindings, we’re ready to load up a test app and step through it.

Read:  Chapter 1 Chapter 2 | Chapter 3 | Chapter 4 | Chapter 5 | Chapter 6 | Chapter 7 | Chapter 8

About Dave Haeffner: Dave is a recent Appium convert and the author of Elemental Selenium (a free, once weekly Selenium tip newsletter that is read by thousands of testing professionals) as well as The Selenium Guidebook (a step-by-step guide on how to use Selenium Successfully). He is also the creator and maintainer of ChemistryKit (an open-source Selenium framework). He has helped numerous companies successfully implement automated acceptance testing; including The Motley Fool, ManTech International, Sittercity, and Animoto. He is a founder and co-organizer of the Selenium Hangout and has spoken at numerous conferences and meetups about acceptance testing.

Follow Dave on Twitter – @tourdedave

 

 

AngularJS Data Models: $http VS $resource VS Restangular

July 15th, 2014 by Amber Kaplan

Sauce Labs software developer Alan Christopher Thomas and his team have been hard at work updating our stack. He shared with us some insight into their dev process, so we thought we’d show off what he’s done. Read his post below.

Over the past few months, the Sauce Labs web team has fixed its crosshairs on several bits of our stack that needed to be refreshed. One of those bits is the list of jobs all customers see when they first log into their account. It looks like this:

stack

Our current app is built in Backbone.js. We vetted lots of options for frontend MVC frameworks and data binding that could replace and simplify the existing Backbone code: Ember, Angular, React, Rivets, Stapes, etc.

After lots of research, building some stuff, and personal preference, our team decided we were most comfortable with Angular.

We had one more thing we wanted to verify, though, before settling.

How complicated will it be to model our data?

This was the first question on most of our minds, and it was the one question about Angular that Google fell into a void of silence. Backbone has models and collections. Ember.js has Ember Data and ember-model. Stapes has extensible observable objects that can function as collections. But what about Angular? Most examples we found were extremely thin on the data layer, just returning simple JavaScript objects and assigning them directly to a $scope model.

So, we built a small proof of concept using three different AngularJS data modeling techniques. This is a dumbed down version of our Jobs page, which only displays a list of jobs and their results. Our only basic requirement was that we kept business logic out of our controllers so they wouldn’t become bloated.

We gave ourselves some flexibility with the API responses and allowed them to be wrapped with an object or not wrapped to emphasize the strengths of each approach. However, all calls require limit and full parameters to be passed in the GET query string.

Here’s what we wanted the resulting DOM template to look like:

{{ job.getResult() }} {{ job.name }}

Note that each resulting job should be able to have a getResult() method that displays a human-readable outcome in a badge. The rendered page looks like this:

jobs


The Code: $http vs $resource vs Restangular

So, here’s the resulting code for all three approaches, each implementing a getResult() method on every job.

$http

In this approach, we created a service that made the API calls and wrapped each result as a Job() object with a getResult() method defined on the prototype.

API Response Format:

{
  "meta": {}, 
  "objects": [
    {
      "breakpointed": null, 
      "browser": "android", 
      "browser_short_version": "4.3",
      ...
    },
    {
      ...
    },
    ...
  ]
}

models.js:

angular.module('job.models', [])
    .service('JobManager', ['$q', '$http', 'Job', function($q, $http, Job) {
        return {
            getAll: function(limit) {
                var deferred = $q.defer();

                $http.get('/api/jobs?limit=' + limit + '&full=true').success(function(data) {
                    var jobs = [];
                    for (var i = 0; i < data.objects.length; i ++) {
                        jobs.push(new Job(data.objects[i]));
                    }
                    deferred.resolve(jobs);
                });

                return deferred.promise;
            }
        };
    }])
    .factory('Job', function() {
        function Job(data) {
            for (attr in data) {
                if (data.hasOwnProperty(attr))
                    this[attr] = data[attr];
            }
        }

        Job.prototype.getResult = function() {
            if (this.status == 'complete') {
                if (this.passed === null) return "Finished";
                else if (this.passed === true) return "Pass";
                else if (this.passed === false) return "Fail";
            }
            else return "Running";
        };

        return Job;
    });

controllers.js:

angular.module('job.controllers', [])
    .controller('jobsController', ['$scope', 'JobManager', function($scope, JobManager) {
        var limit = 20;
        $scope.loadJobs = function() {
            JobManager.getAll(limit).then(function(jobs) {
                $scope.jobs = jobs;
                limit += 10;
            });
        };

        $scope.loadJobs();
    }]);

This approach made for a pretty simple controller, but since we needed a custom method on the model, our services and factories quickly became verbose. Also, if we were to abstract away this behavior to apply to other data types (sub-accounts, tunnels, etc.), we might end up writing a whole lot of boilerplate.

$resource

UPDATE: Per Micke’s suggestion in the comments section below, we’ve posted a follow-up with a cleaner implementation of the $resource version of the Job model. It parses an API response similar to the one shown in the Restangular scenario and allows for much cleaner method declaration usingangular.extend.

Angular provides its own $resource factory, which has to be included in your project as a separate dependency. It takes away some of the pain we felt in writing our JobManager service boilerplate code and allows us to apply our custom method directly to the $resource prototype, then transform responses to be wrapped in itself.

API Response Format:

{
  "items": [
    {
      "breakpointed": null, 
      "browser": "android", 
      "browser_short_version": "4.3", 
      ...
    }, 
    {
      ...
    }
    ...
  ]
}

models.js:

angular.module('job.models', [])
    .factory('Job', ['$resource', function($resource) {
        var Job = $resource('/api/jobs/:jobId', { full: 'true', jobId: '@id' }, {
            query: {
                method: 'GET',
                isArray: false,
                transformResponse: function(data, header) {
                    var wrapped = angular.fromJson(data);
                    angular.forEach(wrapped.items, function(item, idx) {
                        wrapped.items[idx] = new Job(item);
                    });
                    return wrapped;
                }
            }
        });

        Job.prototype.getResult = function() {
            if (this.status == 'complete') {
                if (this.passed === null) return "Finished";
                else if (this.passed === true) return "Pass";
                else if (this.passed === false) return "Fail";
            }
            else return "Running";
        };

        return Job;
    }]);

controllers.js:

angular.module('job.controllers', [])
    .controller('jobsController', ['$scope', 'Job', function($scope, Job) {
        var limit = 20;
        $scope.loadJobs = function() {
            var jobs = Job.query({ limit: limit }, function(jobs) {
                $scope.jobs = jobs.items;
                limit += 10;
            });
        };

        $scope.loadJobs();
    }]);

This approach also makes for a pretty elegant controller, except we really didn’t like that the query() methodtook a callback instead of giving us a promise didn’t return a promise directly, but gave us an object with the promise in a $promise attribute (thanks Louis!). It felt pretty un-Angular a little ugly. Also, the process of transforming result objects and wrapping them felt like a strange dance to achieve some simple behavior (UPDATE: see this post). We’d probably end up writing more boilerplate to abstract that part away.

Restangular

Last, but not least, we gave Restangular a shot. Restangular is a third-party library that attempts to abstract away pain points of dealing with API responses, reduce boilerplate, and do it in the most Angular-y way possible.

API Response Format:

[
  {
    "breakpointed": null, 
    "browser": "android", 
    "browser_short_version": "4.3", 
    ...
  }, 
  {
    ...
  }
  ...
]

models.js:

angular.module('job.models', [])
  .service('Job', ['Restangular', function(Restangular) {
    var Job = Restangular.service('jobs');

    Restangular.extendModel('jobs', function(model) {
      model.getResult = function() {
        if (this.status == 'complete') {
          if (this.passed === null) return "Finished";
          else if (this.passed === true) return "Pass";
          else if (this.passed === false) return "Fail";
        }
        else return "Running";
      };

      return model;
    });

    return Job;
  }]);

controllers.js:

angular.module('job.controllers', [])
  .controller('jobsController', ['$scope', 'Job', function($scope, Job) {
    var limit = 20;
    $scope.loadJobs = function() {
      Job.getList({ full: true, limit: limit }).then(function(jobs) {
        $scope.jobs = jobs;
        limit += 10;
      });
    };
$scope.loadJobs();
}]);

In this one, we got to cheat and use Restangular.service(), which provides all the RESTful goodies for us. It even abstracted away writing out full URLs for our API calls. Restangular.extendModel() gives us an elegant way to attach methods to each of our model results, making getResult() straightforward and readable. Lastly, the call in our controller returns a promise! This let us write the controller logic a bit more cleanly and allows us to be more flexible with the response in the future.

tldr; Concluding Thoughts

Each of the three approaches have their appropriate use cases, but I think in ours we’re leaning toward Restangular.

$http - $http is built into Angular, so there’s no need for the extra overhead of loading in an external dependency. $http is good for quick retrieval of server-side data that doesn’t really need any specific structure or complex behaviors. It’s probably best injected directly into your controllers for simplicity’s sake.

$resource - $resouce is good for situations that are slightly more complex than $http. It’s good when you have pretty structured data, but you plan to do most of your crunching, relationships, and other operations on the server side before delivering the API response. $resource doesn’t let you do much once you get the data into your JavaScript app, so you should deliver it to the app in its final state and make more REST calls when you need to manipulate or look at it from a different angle. Any custom behavior on the client side will need a lot of boilerplate.

Restangular - Restangular is a perfect option for complex operations on the client side. It lets you easily attach custom behaviors and interact with your data in much the same way as other model paradigms you’ve used in the past. It’s promise-based, clean, and feature-rich. However, it might be overkill if your needs are basic, and it carries along with it any extra implications that come with bringing in additional third-party dependencies.

Restangular seems to be a decently active project with the prospect of a 2.0 that’s compatible with Angular 2.0, currently a private repository. However, a lot of the project’s progress seem to be dependent on the work of a single developer for the time being.

We’re looking forward to seeing how Restangular progresses and whether or not it seems like a good fit for us at Sauce!

- Alan Christopher Thomas, Software Developer, Sauce Labs

Register Today: Fearless Browser Test Automation [WEBINAR]

July 14th, 2014 by Amber Kaplan

john_david_daltonWe’re thrilled to be working with our friends at O’Reilly to present our next webinar, Fearless Browser Test Automation with John-David Dalton, on August 5 at 10:00 AM Pacific Time.

Browser test automation can be intimidating, leaving developers to spend their time manually testing browsers (many times in VMs) or opting to simply not test a range of browsers. Join John-David Dalton as he discusses browser test automation, removes the roadblocks/gotchas, and shows lots of awesome things you can do (code coverage, perf testing, tagging, & more).

Visit this link to sign up today!

About John-David Dalton, Program Manager, Microsoft

John-David Dalton is a Program Manager at Microsoft, working on the Chakra JavaScript engine, helping make your web applications, animations, and games run faster and smoother in Internet Explorer. He’s also the creator of Lo-Dash, co-maintainer of jsPerf and Benchmark.js, and contributes to other open source projects to help developers be more productive & write better JavaScript.

How HotelTonight.com Leverages Appium for Mobile Test Automation

July 1st, 2014 by Amber Kaplan

We love this blog post written by Quentin Thomas at HotelTonight! In it, he explains how they use Appium to automate their mobile tests. He also walks readers through specifics, such as the RSpec config helper. Read a snippet below.

Thanks to the engineers at Sauce Labs, it is now possible to tackle the mobile automation world with precision and consistency.

Appium, one of the newest automation frameworks introduced to the open source community, has become a valuable test tool for us at HotelTonight. The reason we chose this tool boils down to Appium’s philosophy.

“Appium is built on the idea that testing native apps shouldn’t require including an SDK or recompiling your app. And that you should be able to use your preferred test practices, frameworks, and tools”.

-Quentin Thomas, HotelTonight, June 17, 2014

To read the full post with code, click here. You can follow Quentin on Twitter at @TheQuengineer.

Have an idea for a blog post, webinar, or more? We want to hear from you! Submit topic ideas (or questions!) here.