{"pageProps":{"editions":[{"mdPath":"/vercel/path0/content/editions/0124.md","num":124,"rawMd":"\n\nOne of the great things about [Appium 2.0](https://appium.io) is that you can find drivers to\nenable your automation testing across a wider variety of platforms than ever before; now including\neven media streaming platforms! In this article, we'll learn how to test Roku TV applications using\na relatively new Appium driver for Roku TV. I implemented this driver on behalf of HeadSpin, and\nit's fully open source, available on GitHub: [Appium for Roku\nTV](https://github.com/headspinio/appium-roku-driver). The full documentation for the driver is\navailable there at the README, but we'll be covering all the highlights in this article.\n\n### How the Appium Roku driver works\n\nTo perform automation well on a given platform, it's always worth doing a little research on how\napp development for the platform works, beyond finding an Appium driver for it. This helps you\nunderstand how the driver itself works and what its requirements and limitations are. The more you\nknow about iOS development, for example, the better use you'll be able to make of Appium's iOS\ndriver. The same goes for Roku! The best source for Roku developer information is [Roku's Developer\nPortal](https://developer.roku.com/en-ca/docs/developer-program/getting-started/roku-dev-prog.md).\nThis is the documentation I used to build the Appium Roku driver.\n\nOne thing to note right off the bat is that Roku apps are called \"channels\" (as in TV channels) in\nthe Roku documentation, so be aware of how this language is a bit different from most platforms.\n\nYou might also notice that Roku publishes something called the [Roku\nWebDriver](https://developer.roku.com/en-ca/docs/developer-program/dev-tools/automated-channel-testing/web-driver.md),\nwhich is a WebDriver server implementation for Roku automation, written in Go. Its purpose is very\nsimilar to the purpose of the Appium Roku driver---to allow for WebDriver-style automation of Roku\napps. So why did I bother to make an Appium Roku driver at all? When I looked into the Roku\nWebDriver implementation, it unfortunately did not follow standard W3C protocol conventions, nor\nwas it already Appium-compatible. Reading through the code, it became apparent that the Roku\nWebDriver server was a thin layer on top of another Roku developer tool called the [External\nControl\nProtocol](https://developer.roku.com/en-ca/docs/developer-program/dev-tools/external-control-api.md)\n(ECP). This is an API hosted on the Roku device itself which allows limited remote control and\ndebugging of Roku developer channels. Beyond this, I noticed that the Roku WebDriver did not have\ncertain features I thought were important, like the ability to find element objects and trigger\nthem by calling the `Click Element` command. Ultimately, it seemed like a better idea to create and\nmaintain an Appium driver based on the same protocol, so that's what we did!\n\nThe ECP takes care of most of how the Appium driver works, since it lets you do things like get\na dump of the UI element hierarchy or simulate remote control keypresses. But it doesn't let you do\nthings like install apps or take screenshots. Luckily, the Roku comes with a special developer mode\nwebsite that you can access in a web browser locally connected to the Roku device. This website\nlets you upload your development apps (called \"dev channels\"), and retrieve screenshots. The Appium\ndriver simply calls out to this webserver when it needs to perform these tasks as part of its work,\nso you don't have to do it manually.\n\n### Requirements and limitations of the Appium Roku driver\n\nBefore beginning an automation project for any platform, it's important to make sure you understand\nthe requirements and limitations of the platform, so you're not stuck in a dead end. This is\ndefinitely true for Roku test automation as well. Here are some of the requirements you'll need to\nkeep in mind if you want Roku testing to be successful:\n\n1. You will need a physical Roku device for testing. There is no such thing as a Roku emulator,\n unfortunately.\n1. Your Roku needs to be on the same network as your Appium server (since the Appium server will\n make network calls to the Roku).\n1. Your Roku needs to be in [Developer\n Mode](https://developer.roku.com/en-ca/docs/developer-program/getting-started/developer-setup.md)\n so that the ECP server and Dev Mode server are up and running.\n1. You need to have access to your Roku channel as a `.zip` file in the format expected by the Roku\n channel sideloading (installation) service. In other words, it should be an archive of your\n source code, not a compiled version of the app.\n1. And of course, you should have a functional Appium 2.0 server environment, ideally updated to\n the latest and greatest!\n\nHere are some limitations of the driver to keep in mind:\n\n1. You cannot automate channels that you do not have the source code to (i.e., your dev channel).\n (Technically, you can still use the driver's remote control emulation to do anything you want on\n the device, but this will be driving the device \"blind\"---you'll have no way to check the UI\n hierarchy or grab a screenshot). I.e., the `Take Screenshot` and `Get Page Source` commands only\n work if the dev channel is active.\n1. Roku provides a way to see the UI element hierarchy, but no way to work with specific UI\n elements directly. The only way to interact the device is via the remote control. The Appium\n driver does however provide a special algorithm for emulating the `Click Element` command which\n will be highlighted below. It also has a convenience method for `Send Keys`, that simply sends\n keystrokes to the Roku as if a user were doing so with the remote. All this to say: you will be\n able to run the `Find Element` command, which is certainly useful for waiting for app state, but\n in general there is no way to interact with the element you have found. To trigger elements\n you'll need to use the driver's remote control methods or one of the few convenience methods\n mentioned above.\n1. Only one dev channel may be sideloaded at any given time. When you (or the driver) sideloads\n a dev channel, it will be given the channel ID of `dev`. So even though your app will have its\n own official channel ID used for publishing, the ID of the channel for automation purposes will\n basically always be `dev`.\n1. When you take a screenshot of a screen which contains video content, that video content will be\n shown as a black rectangle. This is because Roku does not allow DRMed video content to leave the\n device except to authorized playback machines (like TVs).\n\n### Installing the Appium Roku driver\n\nWith the Appium 2.0 extension CLI, installing the driver is as easy as running:\n\n```bash\nappium driver install --source=npm @headspinio/appium-roku-driver\n```\n\nThis will get you the latest version of the Roku driver. If you would like to upgrade at any point\nlater, you can simply run:\n\n```bash\nappium driver update roku\n```\n\n### Starting Roku app test automation sessions\n\nTesting your Roku TV apps using this driver involves using the following required capabilities in\nwhichever Appium client you're most comfortable with:\n\n|Capability|Description|\n|----------|-----------|\n|`platformName`|Should always be `Roku`|\n|`appium:automationName`|Should always be `Roku`|\n|`appium:app`|An absolute path to the zip file of the dev channel you want to install. If not included, a session will simply be started on the home screen. You can also just set it to `dev` if the dev channel is already installed.\n|`appium:rokuHost`|The host name or IP of the Roku device on the network|\n|`appium:rokuEcpPort`|The ECP port on the Roku device (usually `8060`)|\n|`appium:rokuWebPort`|The dev web interface port on the Roku device (usually `80`)|\n|`appium:rokuUser`|The username you selected when turning on dev mode|\n|`appium:rokuPass`|The password you selected when turning on dev mode|\n|`appium:rokuHeaderHost`|The IP of the Roku device on *its* local network (should usually the same as `rokuHost` unless you are tunneling or connecting via DNS)|\n\nThere is also a special capability that determines how long the driver will wait in between remote\nkey presses. This can be useful if the automated key presses are happening too quickly for your app\nto react to them. If you find yourself in this position, simply set the `appium:keyCooldown`\ncapability to the number of milliseconds you want to wait in between key presses.\n\n### Using a session to test Roku TV apps\n\nOnce you have a session going in your Appium client, you'll navigate your app and implement your\nautomation test for Roku using primarily the following commands (note that the way to write these\ncommands differs based on the client library you're using; you can refer to the client libray\ndocumentation for specific examples):\n\n|Command|Description|\n|-------|-----------|\n|`Get Page Source`|Returns an XML document representing the current UI hierarchy. You should use this document to come up with XPath queries for elements you want to interact with.|\n|`Get Screenshot`|Returns a PNG image representing the current screen.|\n|`roku: pressKey`|This is an [Execute Method](https://appium.io/docs/en/2.0/guides/execute-methods/) that allows you to trigger remote control key presses, like the home button or the play/pause buttons. This method takes a single parameter named `key`, whose value should be one of the [supported key values](https://developer.roku.com/en-ca/docs/developer-program/debugging/external-control-api.md#keypress-key-values) from the Roku documentation. Using this method, you'll be able to do anything a user would be able to do!|\n|`Find Element` / `Find Elements`|Using an XPath query as your selector, get a reference to an element found in the UI hierarchy.|\n|`Click Element`|Once you have an element, you can call `.click()` on it. When you do this, the Roku driver will go through a special algorithm to attempt to automatically focus the element you found and hit the `Enter` button to trigger its behaviour. Hopefully it will save you from having to map out the precise remote key presses required to navigate to the element.|\n|`Send Keys`|If you need to type text into an input field, first make sure the input field is active and ready to receive text input. Then call the send keys / set value command (whatever it's called in your Appium client), and the driver will use the special remote control API to send literal characters instead of remote key presses.|\n\nThere are a number of other commands available to help you in your Roku TV test automation (which\nyou can learn more about at the driver documentation), including:\n\n- Install and remove apps\n- Launch apps\n- List available apps\n- Get information about the device\n\nThat's it! This guide should be all you need to get started with automation testing for Roku. Now\ngo forth and test your streaming apps on Roku TV devices! Remember, the project is open source, so\nif you think you've found a bug, please report it at the [issue\ntracker](https://github.com/headspinio/appium-roku-driver/issues), and of course, contributions are\nalso welcome.\n","metadata":{"lang":"All Languages","platform":"All Platforms","subPlatform":"All Devices","title":"Using Appium for Automated Testing of Roku TV Apps","shortDesc":"One of the drivers available in the Appium 2.0 ecosystem is the Appium Roku driver, which enables you to test Roku TV applications.","canonicalRef":"https://www.headspin.io/blog/using-appium-for-automated-testing-of-roku-tv-apps","liveAt":"2023-04-27 14:00"},"mtime":"2023-04-28T16:49:48Z","permalink":"https://appiumpro.com/editions/124-using-appium-for-automated-testing-of-roku-tv-apps","slug":"124-using-appium-for-automated-testing-of-roku-tv-apps","path":"/editions/124-using-appium-for-automated-testing-of-roku-tv-apps","news":null,"tags":["All Languages","All Platforms","All Devices"]},{"mdPath":"/vercel/path0/content/editions/0123.md","num":123,"rawMd":"\n\nAppium 2.0 is almost here! Most of the foundational work has been done, and it has been in beta for some time now. If you haven't yet gotten the Appium 2.0 beta, you can read the Appium Pro article on [installing Appium 2.0 and Appium 2.0 drivers](https://appiumpro.com/editions/122-installing-appium-20-and-the-driver-and-plugins-cli) to get started. Apart from the differences in how you make platform drivers available to your Appium install, there will be a number of other (mostly minor) breaking changes you need to be aware of once you start migrating your Appium 1.x scripts to Appium 2.x.\n\nThis article is the first in an ongoing series that will attempt to walk you through all these changes. The topic of discussion for this article is capability prefixes. \"Capabilities\" (formerly known as \"desired capabilities\") are the parameters you use to start an Appium session. They come in key/value pairs, (for example, `platformName` which allows you to specify which platform you want to automate, whether that is iOS, Android, Mac, Windows, etc...). Depending on your Appium client, you define capabilities in a variety of ways, either using capability enum objects or strings (as in Java) or by constructing a dict (as in Python).\n\nWith Appium 2.0, the Appium server will enforce strict compability with the [W3C WebDriver specification](https://github.com/jlipps/simple-wd-spec) when it comes to Capabilities. The spec defines 9 official capabilities, many of which aren't used very frequently in Appium. The standard, official capabilities you're probably most familiar with could be the following:\n\n* `browserName`\n* `platformName`\n* `timeouts`\n\n(You can check out the others at the [full list of official capabilities](https://github.com/jlipps/simple-wd-spec#capabilities)). When it comes to these standard capabilities, there are no breaking changes. But every other capability that you use with Appium tests (like `deviceName` or `automationName` or `udid` or `app`), are _non_-standard, from the perspective of the W3C spec. Going forward, Appium will reject these capabilities. So how can we keep sending Appium the information they are designed to send? Luckily, the W3C spec defines a way for non-standard capabilities to be accepted as valid. These capabilities must include a so-called \"vendor prefix\", which looks like a string ending in a colon. If we were to take the `automationName` capability as an example, we could turn it into a valid W3C capability by adding the `appium:` prefix:\n\n```text\nappium:automationName\n```\n\nWith that background in mind, let's explore 3 different strategies for updating your tests to use these vendor prefixes appropriately, in order to avoid test failures during new session creation.\n\n### Strategy #1: Manually update your capabilities\n\nThe first strategy is perhaps the best long term strategy, but it involves the most work. Just go into your test code and update every instance of a non-official capability so that it has the `appium:` prefix!\n\n### Strategy #2: Use an updated Appium client\n\nThe Appium team is obviously aware that it's not pleasant to have to find and change every instance of a capability everywhere in a testsuite. So we've also been hard at work updating our client libraries so that, if the library detects a capability that would be invalid without an `appium: ` vendor prefix, it will add that prefix automatically.\n\nWhat this means is that if you're simply using the most recent version of the Appium client library, the vendor prefix addition will happen for you under the hood. This is probably the simplest path forward at the present time, since it involves no work on your part other than updating your client, which is probably a good idea independently.\n\n### Strategy #3: Use the `relaxed-caps` plugin\n\nIf you can't upgrade your client, or are using a Selenium client, don't give up hope! There's still a way to have Appium give you a bit of a break. While the Appium server itself will only accept valid W3C capabilities, I've written a plugin that adjusts Appium's behavior to be a little more lenient. When this plugin is active, it will accept the old-style, non-prefixed capabilities (well, secretly, what it does is just add them before you before the capabilities get to the new session creation function). The net result is that once again your tests can stay the same.\n\nThis plugin is called the [relaxed-caps](https://github.com/appium/appium-plugins/tree/master/packages/relaxed-caps) plugin, and it's one of the officially-supported Appium 2.0 plugins. You can see it, for example, if you run `appium plugin list`. And you can install it by running:\n\n```bash\nappium plugin install relaxed-caps\n```\n\nThen of course you'll need to activate it when you start your Appium server, to make sure you know what you're allowing in terms of plugins and session modification:\n\n```bash\nappium --use-plugins=relaxed-caps\n````\n\nSo this concludes our first discussion of breaking changes in Appium 2.0. I hope that one of these 3 strategies will work well for you, and at least give you the time to update your capabilities to use the appropriate vendor prefix!\n","metadata":{"lang":"All Languages","platform":"All Platforms","subPlatform":"All Devices","title":"Migrating to Appium 2.0, Part 1: Capability Prefixes","shortDesc":"Appium 2.0 will soon be the only supported version of Appium. What do you need to know about updating your test scripts so that they keep working when you upgrade? This is the first part of an open-ended series detailing the breaking changes you might encounter when migrating to Appium 2.0","liveAt":"2021-06-17 14:00","canonicalRef":"https://www.headspin.io/blog/migrating-to-appium-2-0-part-1-capability-prefixes"},"mtime":"2023-04-28T16:49:48Z","permalink":"https://appiumpro.com/editions/123-migrating-to-appium-20-part-1-capability-prefixes","slug":"123-migrating-to-appium-20-part-1-capability-prefixes","path":"/editions/123-migrating-to-appium-20-part-1-capability-prefixes","news":null,"tags":["All Languages","All Platforms","All Devices"]},{"mdPath":"/vercel/path0/content/editions/0122.md","num":122,"rawMd":"\n\n> If you've been around the Appium world for a while, you've probably heard that Appium 2.0 has been \"coming soon\" for a very long time! I'm happy to report that work on it has been progressing well, and Appium 2.0 is now ready to use as a beta!\n\n### Appium 2.0's vision\n\nBefore we get into the details of installing and running Appium 2.0, it's worth mentioning some of the core goals for this next major revision of Appium:\n\n* **Decouple the drivers!** Appium's platform drivers (the XCUITest driver, UiAutomator2 driver, Espresso driver, etc...) have very little in common with one another. They really ought to be developed as independent projects that implement the same interface and can be used equivalently with the Appium server. With Appium 2.0, the code for these drivers will no longer be bundled with the main Appium server. This decreases the size of an Appium install dramatically, and makes it so that you don't need to install drivers that you don't need to use. It also makes it possible to freely update drivers independently of Appium and of one another, so that you can get the latest changes for one driver while sticking with a known stable version of another driver, for example.\n* **Create a driver ecosystem.** Once the drivers are decoupled from Appium, it's quite an obvious question to ask: what's special about these drivers, anyway? Why couldn't anyone else create a driver for their own platform? Well with Appium 2.0, they can, and they should! By using any existing Appium drivers as a template, anyone can create their own custom drivers with a minimum of extra code. All of these custom drivers can then be installed by any Appium user (or custom drivers could be private, or sold, or whatever you can dream of).\n* **Create a plugin ecosystem.** In addition to drivers, it's become clear that there are a huge variety of use cases for Appium, which involve the use of special commands or special ways of altering the behavior of Appium for specific commands. Some good examples of this would be the [Find Element by Image API](https://appiumpro.com/editions/32-finding-elements-by-image-part-1) or the [Appium + Test AI Classifier](https://appiumpro.com/editions/101-ai-for-appium--and-selenium). Not every automation use case requires these features, but the code and dependencies that support these features are included with every Appium install. It would be better to be able to install these features as independent plugins. And it would be even better for anyone in the world to be able to easily create Appium plugins that can implement new commands, or alter the behavior of existing commands! Using the same model as our driver ecosystem, anyone can create plugins like these and easily share them with the world of Appium users.\n* **Miscellaneous standardization**. There has been a lot of deferred work on Appium that kept getting pushed off because it could introduce a breaking change into the API. We're going to take the opportunity to make those changes now, and keep bringing Appium into the future.\n\n### Installing Appium 2.0\n\nAt the moment, Appium 2.0 is not the main line of Appium development, so it cannot be installed with a simple `npm install -g appium`. Instead, Appium 2.0 beta versions will be available with a special NPM tag `next`, so you can install it on any platform using NPM as follows:\n\n```\nnpm install -g appium@next\n```\n\nThat's it!\n\n### Installing Appium drivers\n\nAt this point, after installing Appium 2.x for the first time, if you run the server, you'll get a line in the logs that looks something like this:\n\n> [Appium] No drivers have been installed. Use the \"appium driver\" command to install the one(s) you want to use.\n\n(And you'll get the same message with respect to plugins). What this is telling us is that you need to have Appium install a driver before you run any tests. That's because no drivers are included by default with Appium 2.x. Instead, you tell Appium which drivers you care to use. Those drivers can then be removed or updated as necessary, all without having to change your version of Appium! So let's take a look at the commands you could use to install, say, the XCUITest and UiAutomator2 drivers:\n\n```bash\nappium driver install xcuitest\nappium driver install uiautomator2\n```\n\nSo essentially, there is now a new set of \"subcommands\" for the main `appium` program you run from the CLI. The subcommand we're looking at here is the `driver` subcommand, which has its *own* set of subcommands! The one we just saw here is the `install` subcommand for the driver CLI. In the normal case, it takes a single parameter which is the name of the driver you want to install. How did I know which strings to use (`xcuitest` and `uiautomator2`)? Well, Appium knows about some \"official\" drivers which you can install just by name. To get a list of all these \"official\" drivers, you can run `appium driver list` (see below).\n\nBefore we talk about `driver list`, let's explore the `driver install` command a bit more. The full spec for the command looks like this:\n\n```bash\nappium driver install --source= --package= \n```\n\n#### The `--source` option\n\nThe `--source` option is not required, but can be included to tell the `driver install` command where to find the driver you want to install, if you're not installing one of Appium's \"official\" drivers. Basically it tells Appium how it should treat the `installSpec` you include, and opens up the possibility of installing drivers from practically anywhere! There are 4 options here:\n\n|Source|Meaning|\n|----|----|\n|`npm`|Install a driver as an NPM package|\n|`github`|Install a driver from a GitHub repo|\n|`git`|Install a driver from an arbitrary Git repo|\n|`local`|Install a driver from a local path on the filesystem|\n\nWe'll talk about what each of these mean for `installSpec` in a moment.\n\n#### The `--package` option\n\nIf you use the `--source` option, and if your source is something other than `npm`, then you must also include this `--package` option, and its value needs to be the package name of the driver module. The driver doesn't actually need to be *published* to NPM or anything, but since every Appium driver is a Node.js package, it will have a package name which Appium will need to know in order to find the driver when it is downloaded and installed.\n\n#### The `installSpec` parameter\n\nThe only required parameter is what we call the \"install spec\". It can be in different formats depending on your source. The following table illustrates the possibilities:\n\n|Source|Install Spec Format|Example|\n|--|--|--|\n|(no source)|The name of an official driver, as found in `appium driver list`|`xcuitest`|\n|`npm`|The name of an NPM package plus any valid NPM restrictions or tags(which could be installed|`customDriver@1.0.2`|\n|`github`|The GitHub org and repo as `/`|`appium/appium-xcuitest-driver`|\n|`git`|The fully qualified Git URL of the repo|`https://github.com/appium/appium-xcuitest-driver.git`|\n|`local`|The path to the driver on the disk|`/usr/local/drivers/custom-driver`|\n\n### Other driver CLI commands\n\nA few times we've mentioned the importance of `appium driver list`. What does this command do? It tells you which drivers you have installed, and which official drivers you *could* install that you haven't yet! For example, this is the output when I've installed only the XCUITest driver:\n\n```text\n✔ Listing available drivers\n- xcuitest@3.31.5 [installed (NPM)]\n- uiautomator2 [not installed]\n- youiengine [not installed]\n- windows [not installed]\n- mac [not installed]\n- espresso [not installed]\n- tizen [not installed]\n- flutter [not installed]\n```\n\nAny drivers that are installed will display their version, and which source was involved in installing the drivers. You can also use `driver list` to check and see if any drivers have any updates available:\n\n```bash\nappium driver list --updates\n```\n\nIf an update is available, you'll see that in the output. You can then update a specific driver as follows:\n\n```bash\nappium driver update \n```\n\n(where `driverName` is the name of the driver as printed in the output of `appium driver list`.) Note that by default Appium will not let you update a driver across a major version boundary, to keep you safe from breaking changes. Once you've done your due diligence on any breaking changes with the next major version of a driver, you can proceed with the upgrade as follows:\n\n```bash\nappium driver update --unsafe\n```\n\nAlso, you can update *all* installed drivers in one go, using the special driver name `installed`:\n\n```bash\nappium driver update installed\n```\n\nAnd that's about it for the driver CLI! Note that you can of course also uninstall particular drivers if you no longer want them around (this is also how you'd update non-NPM based drivers, using a combination of uninstall and then install again):\n\n```\nappium driver uninstall \n```\n\n### Setting the driver repository location\n\nOne question you might have had is: where does Appium install drivers when you use the driver CLI? By default, Appium creates a hidden directory called `.appium` inside your user home directory. But if you'd like to use a different directory, or if you want to keep multiple driver repositories around, you can adjust this path by using one of these three command line options (which are all aliases of the same behavior):\n\n* `-ah`\n* `--home`\n* `--appium-home`\n\nFor example, `appium -ah /path/to/custom/appium/home driver install xcuitest`.\n\n### More to come...\n\nAll we talked about in this article was installing Appium 2.0 and using the driver CLI. But there's a lot more to Appium 2.0! In future articles we'll look at some of the breaking changes that are coming, and most importantly how to leverage the plugin CLI. But for now, you can feel free to give Appium 2.0 a whirl, and see how it works for you!\n","metadata":{"lang":"All Languages","platform":"All Platforms","subPlatform":"All Devices","title":"Installing Appium 2.0 and the Driver and Plugins CLI","shortDesc":"In this article we take a first look at Appium 2.0: its goals, its installation, and the ins and outs of the very important new 'driver' command line interface.","newsletterTopNote":"By the way, sorry for the radio silence from Appium Pro! I've been hard at work on my massive Appium and Selenium Fundamentals course, which is now complete and nearing public release. You'll hear more from me in a little bit about that. In the meantime, hope you enjoy this new article!","liveAt":"2020-12-02 14:00","canonicalRef":"https://www.headspin.io/blog/installing-appium-2-0-and-the-driver-and-plugins-cli"},"mtime":"2023-04-28T16:49:48Z","permalink":"https://appiumpro.com/editions/122-installing-appium-20-and-the-driver-and-plugins-cli","slug":"122-installing-appium-20-and-the-driver-and-plugins-cli","path":"/editions/122-installing-appium-20-and-the-driver-and-plugins-cli","news":{"rawMd":"I thought many of you might like to know that Appium Pro sponsor HeadSpin now has a manual testing platform called [HeadSpin Local](https://www.headspin.io/platform/local/?utm_source=appiumpro&utm_medium=email&utm_campaign=local), which offers testing on real devices around the world.\n\nThe idea here will probably be very obvious to you; you can simply select a device (or multiple) from a diverse pool of iOS and Android devices and control those devices via a remote workbench that has all your tools, including device logs and screenshots that you can save and share with your team. Remote automation via Appium will of course be released down the line as a forthcoming product, but I've found that just being able to open up a specific device in a specific geographical location is pretty useful for a sanity check or a bug repro.\n\nAnyway, right now there's a 25% off special for the yearly version of the plan, so if you’re curious, visit our page to [get started](https://www.headspin.io/platform/local/?utm_source=appiumpro&utm_medium=email&utm_campaign=local)!\n","num":122,"mdPath":"/vercel/path0/content/news/0122.md"},"tags":["All Languages","All Platforms","All Devices"]},{"mdPath":"/vercel/path0/content/editions/0121.md","num":121,"rawMd":"\n\n> Appium Pro is usually known for Appium-related automation tutorials and advanced techniques. But sometimes it's good to step back and take a look at the bigger picture of how these techniques are used, which is most frequently in the context of \"testing\". In my forthcoming course on HeadSpin University, [Appium and Selenium Fundamentals](https://ui.headspin.io/university/courses?utm_source=appiumpro&utm_medium=referral&utm_campaign=hs_university), I talk a lot about testing, and what it is, before diving into any automation training. I think it's always useful to consider our practices from a philosophical perspective before just plowing ahead, and so this article is a snippet of the course which has to do with precisely this question: what is testing?\n\n

\n \"Ancient\n

\n\nI think we would all have a fairly good intuitive idea of what testing is. It's making sure something works, right? Indeed! But as a former linguist, I think it'd be great to dive a bit into the etymology of testing, the background and history of the word itself, to get a sense of the roots of the concept.\n\n### The Etymology of Testing\n\nThe English word \"test\" originally came from a Latin word *testum*, which referred a kind of container or pot made of earth. These were pots that were designed to hold very hot metal. People wanted to heat metal up for a number of reasons, but one was to determine whether there were any impurities in the metal.\n\nSo, by association, the pot itself became tied up with the act of checking the quality of the metal, and so now we can say that to put something to the test, i.e., to heat it up in the earthen pot called a \"testum\", is to determine the quality of whatever that thing is! You might also have heard someone talk about a \"crucible\", or maybe heard the expression \"going through the crucible\". This is another word that has a very similar history. A \"crucible\" is another kind of container for heated metal! To take our analogy a bit deeper, we can say that \"testing\" is the process of applying some kind of energy in some kind of container to determine the quality of something we care about.\n\n### Testing Software\n\nNow, what *we* care about is software. Our job as testers is to get some kind of indication of the quality of the software that sits in front of us. Maybe we developed it ourselves, or maybe someone else did. How do we even start thinking about the process of testing software? There are a huge number of methods and tools that we can use in the process. But one simple way of thinking about it is realizing that our responsibility is to design and bring about the specific conditions (like heating a pot) that will reveal the quality of the software. One common way of bringing about these conditions is to use the software in its normal modes, as a normal user. The software is meant to run in certain conditions, and we can simply run it in those conditions, as any normal user of the software would, to determine whether it works the way it's supposed to in those conditions.\n\nWe could *also* try to imagine conditions for the software that its developers might not have thought about. These are often called \"edge cases\". The trouble with software is that there can be a near infinite number of conditions a piece of software runs in, and a near infinite number of situations or states it can get itself into, based on user input or other factors. When developers write software, they usually assume a fairly simple and minimal set of conditions. It is the job of a tester to design crucibles, or test scenarios, that show how the software behaves in all kinds of situations.\n\nObviously, if there are an infinite number of situations that software can get run in, it doesn't make sense to try and test every possible case. So testing becomes a real mix of engineering and creative, out-of-the-box thinking, just to figure out *what* to test. And that is only the beginning! Testers don't have an infinite amount of time to evaluate each potential release of software. Sometimes software gets released multiple times a day! Choices have to be made about what's most important to test, and which additional tools and strategies to adopt to make sure that as much as possible can be tested.\n\nImagine if you were an ancient Roman tester, and people brought their metal to you to heat up and determine its quality. Once the metal starts piling up faster than you can gather logs and heat up your pots, you've got a problem, and you need to figure out not just new and clever methods for determining the quality of the metal, but also the mechanics of how to scale your testing practice. Maybe you buy more pots, or invest in technology that starts fires faster. Maybe you get super advanced and figure out that by mixing certain reagents in with the metal, you can get an instant read on one aspect of the quality of that metal! Anyway, I don't want to push this analogy too far. But this is very much the situation encountered by testers. Almost all testing of software nowadays is done in a context that requires great breadth, depth, speed, and scale. It's an impossible set of requirements, unless testers adopt some of the same modes of thinking that have propelled software development to huge levels of scale.\n\nAnd yes, by that I mean automation, which is a conversation for another time. The main takeaway for now is this: testing is a practice which uses creativity and technology to build and execute special crucibles for software, with the goal of determining the quality of the software to as accurate a degree as possible!\n\n## Kinds of Testing\n\nSo, we defined testing as follows: the act of defining, building, and executing processes that determine application quality. This is a good definition, but it's pretty general. We can get a lot more specific about the various types and subtypes of testing, so we know what kinds of options we have when it comes to defining and building these test processes.\n\nThe way I like to think about types of testing is as a 3-dimensional matrix. Each dimension corresponds to one facet or characteristic of a test. Here are the three dimensions that I see:\n\n1. Test *targets*. A test target is basically the thing you want to test! We might call it the \"object under test\" to be general. In software testing, it's usually called the \"App Under Test\", sometimes written AUT. But target means more than saying what app you're testing. Usually we're only responsible for testing one app anyway, so the App Under Test is kind of a given. What I mean by \"target\" is, what *component* or *layer* of the app is being tested. When we develop software, the software usually has a number of distinct components, and a number of distinct levels. We can consider the levels independently, and even test them independently if we want. One component or level of an application could be an individual code function. Users don't execute individual code functions---that happens behind the scenes, so to speak. But we could test a specific function in isolation! Another layer could be the layer of an application's API. Again, users don't typically try to access an app's backend API. That's something that the app itself would do in order to provide the appropriate information to the user. Yet another layer could be the user interface or UI of the app. This is the part that a user actually interacts with! And we could test all of these different layers. We could test individual units of code. We could test APIs. We could test integrations between various backend services. And we could test the UI. That's what I mean by \"target\"---the test target is the answer to the question, what aspect of the app itself are you trying to test?\n\n2. Test *types*. Now here I mean something very specific by the word \"type\". In this sense, I mean, what aspect of the app's *quality* are you trying to test? Apps can have good or poor quality on a number of different dimensions. One app might be fast but perform calculations incorrectly. So we would say that it has good performance but poor functionality. Another app might have good performance and functionality, but be hard for people who are hard of hearing to use. Then we would say that app has poor accessibility. Performance, functionality, and accessibility are all aspects of the quality of an app. As apps become more and more important in our lives, we keep coming up with more and more aspects of app quality that become important! If we want to test all of these categories, I would say we want to implement a number of different test *types*. So that is what I mean by \"type\".\n\n3. Test *methods*. This category is a bit more straightforward. Basically, method just refers to the procedure used to implement the test. How will the test be performed? That's the method. What are some methods? Well, what we call \"manual testing\" is one method. Manual testing is simply the act of using an app the way a user would, or exercising an app component in a one-off way. In other words, it's done by hand, by a human being. You can manually test units of code. You can manually test APIs. And of course, the most common instance of manual testing is manual testing of app UIs. But manual testing isn't the only method. We can also write software to test our app under test. In this case, our tests are considered to be using the *automated* method.\n\nSo this is the structure I use to help give us an understanding of the various types of tests. These are three dimensions, meaning that in principle the test targets are independent from the test types, and they're both independent from test methods. In practice, not every possible combination of those three dimensions ends up making sense, but a lot do. Let's look at some examples!\n\n### Unit Testing\n\nThe name \"unit testing\" refers to the idea that we are testing a specific unit of code. Unit testing can be described using the different test dimensions in this way: the \"target\" of a unit test is typically a single function in the codebase. The \"type\" is usually understood to be functionality. Usually when writing unit tests, we are making sure that the specific bit of code in question functions appropriately, in terms of its inputs and outputs. We *could* run other types of tests on single code functions, for example we could test their performance. But usually unit tests are written to test functionality. And the \"method\" for a unit test is usually automation.\n\n### UI Testing\n\nUI Testing goes under many different names. Sometimes it's called \"end-to-end\" testing. Sometimes it's just called \"functional testing,\" and some people even refer to UI tests when they talk about \"integration tests.\" I think most of these other names are a bit confusing, so I prefer to use the term \"UI Test.\" This makes clear what the target of our testing is: it's the UI of an application. As we talked about earlier, an app has many different layers, but users typically only interact with the UI. When you are doing UI testing, you are running tests from the perspective of the user! Now, \"UI\" just refers to the target of testing, and it doesn't specify the type or method involved. Typically, if we don't say anything else, UI testing is assumed to be functional in nature. That is, we are testing the UI's functionality. And of course, we can do this using different methods, whether manual or automated.\n\n### Integration Testing\n\nAnother type of testing which is commonly discussed is 'integration testing'. Sometimes, when people say \"integration testing\" they might mean \"UI testing\" so it's good to make sure everyone's working with the same definition. When *I* say integration testing, what I mean is testing the communication, or \"integration\", between two different services. Let's go back to the 3-dimensional framework we've been using to unpack this a little bit. In terms of a target or targets, integration testing is focused on two components of a larger system. In the world of modern software development, the most obvious candidate for these components would be a set of microservices that all communicate in order to power an application. But the components don't necessarily need to be free-standing services; they could also just be two chunks of a much larger monolithic codebase, which are responsible for communicating in some way. The test \"type\" I mean when I talk about \"integration testing\" is usually \"functional\". We could do performance integration testing, but it's usually assumed that we're just talking about making sure the integration works at all. Finally, the test \"mode\" can be manual or automated, just like any other form of testing we've discussed, but this kind of testing is almost always automated.\n\nA good example of integration testing would be asserting that two services communicate with one another correctly, even if the entire stack is not in the picture. Maybe you have one service that reads customer orders from a task queue, does some processing on them, and then sends certain orders to a system that is responsible for physical order fulfilment (in other words, shipping), and sends other orders to a system that is responsible for digital order fulfilment (in other words, e-mailing digital products or something like that). You could image setting up a test environment that just runs these few services, and has no frontend, and no actual real database or task queue. Fake orders can be created in a simple in-memory queue, and orders received by upstream services can simply be included in a correctness assertion, but not actually acted on. This would be an example of an integration test.\n\n### Conclusion\n\nThere are lots of other kinds of testing out there, but I hope that you remember the three dimensions we can use to define any type of testing: the test *target*, the test *type*, and the test *mode*. The target specifies what thing we're trying to ensure quality for. The type specifies what sort of quality we care about (speed, correctness, visual appeal, etc...). The mode specifies how we go about the test (do we use automated means, or manual means, or some specific subcategory of those?). Take a moment and think about the various tests you've written in your career, and try to map them on this schema.\n","metadata":{"lang":"All Languages","platform":"All Platforms","subPlatform":"All Devices","title":"What Is Testing?","shortDesc":"On Appium Pro we talk a lot about specific automation techniques, but we don't often talk about the philosophy or the art of testing. Let's do that now, with a thoughtful introduction to what testing itself is.","liveAt":"2020-09-02 00:00","canonicalRef":"https://www.headspin.io/blog/what-is-testing"},"mtime":"2023-04-28T16:49:48Z","permalink":"https://appiumpro.com/editions/121-what-is-testing","slug":"121-what-is-testing","path":"/editions/121-what-is-testing","news":null,"tags":["All Languages","All Platforms","All Devices"]},{"mdPath":"/vercel/path0/content/editions/0117.md","num":117,"rawMd":"\n\n

\n \"Appium\n

\n\nOK everyone, I have a candid confession to make. I started writing this article as a way to link up \"Appium\" and \"RPA (Robotic Process Automation)\", since RPA is such a hot thing right now. I even found an appropriately vague and generic technology graphic to accompany it. (Did you know that [this graphic](https://pixabay.com/photos/turn-on-turn-off-industry-energy-2923046/) came with the following tags: Industry, Energy, Power, and Businessman? I kid you not). But the more I tried to write some SEO gold, the more I realized how ridiculous this all is. So you're just going to get my honest thoughts here.\n\nRobotic Process Automation (or RPA) has become a huge industry. [This article](https://www.cio.com/article/3236451/what-is-rpa-robotic-process-automation-explained.html) has a wordy but standard definition for RPA:\n\n> RPA is an application of technology, governed by business logic and structured inputs, aimed at automating business processes. Using RPA tools, a company can configure software, or a “robot,” to capture and interpret applications for processing a transaction, manipulating data, triggering responses and communicating with other digital systems.\n\nOnce you parse out all the nonsense from this definition, what you arrive at is the idea of ... software controlling software! At a first pass, this is kind of a ridiculous idea. Software is already programmed to do things. Why do we need a second level of software to control other software? Why not just make that basic software do what we want to begin with? This is, in fact, what we should do if we can. Adding layers of indirection is never a good idea. Sometimes, though, we wind up in a situation where we can't actually modify the software we want to control. (Does this sound familiar to any of testers out there?) In that case, we can write additional software to *use* the first piece of software, *as if it were a user*.\n\nBefore everyone just says, \"wait a minute, that's exactly what we do with UI test automation!\" let me make one more point. The main motivation for RPA in my opinion is the proliferation of software as the primary mechanism of business. Employees are faced with the same kinds of mechanical, menial tasks they were faced with before the software revolution, but now they just happen on computer screens instead of in assembly lines. In this context, it makes sense to ask how software that you don't own, but need to use in various robotic ways, can be controlled. And the answer, as always, is \"robots!\" When it comes to manufacturing cars, that means physical robots. When it comes to entering data into spreadsheets, that means software robots.\n\nSo now, let's say it together: RPA is no different from UI test automation. It has a different *purpose*, sure, but the nuts and bolts are identical. All the tools you use for UI automation can also be used for RPA! So let's look at how Appium fits into all this. What makes Appium a good RPA tool?\n\n1. Appium supports multiple platforms. Want to automate processes on a Windows app? A macOS app? A mobile app? Together with Selenium, we've got you covered for any platform your software runs on.\n2. Appium gives you full UI control. RPA is typically black-box automation, just like UI testing, and that is where Appium focuses.\n3. Appium allows you to automate apps you don't own. This is essential for RPA, because if you owned the software you want to automate, you could just hook into its subroutines directly. That is usually not the case.\n4. Appium is a standalone server with clients written in any language, so you can get your RPA going using the language and tooling you already know.\n5. Appium, from a tooling perspective, is just a library you import, so it imposes no other restrictions on your workflow.\n\nOf course, using Appium as a scripting solution is likely not going to appeal to the audience that wants a fully point-and-click RPA development environment. However, with tools like [Appium Desktop](https://github.com/appium/appium-desktop), the barrier is slightly reduced, and there are already products built on top of Appium that allow for a fully visual experience.\n\nSo, next time you stumble across an article on RPA like the one above, and see 10-step guidelines that include phrases like \"5. Don't fall down the data rabbit hole\" or \"10. Put RPA into your whole development lifecycle\", you safely discard it as unnecessary fluff. All you really need to know about RPA is that it is UI automation, plain and simple. The rest is details. I'm not implying that there is no business or managerial complexity to implementing RPA solutions. I'm merely pointing out to all the CIOs out there that their \"RPA Center of Excellence\" is already staring them in the face in the form of their test automation team!\n\nOK, now you can go and add \"RPA\" to your resume and ask for a raise. You're welcome!\n","metadata":{"lang":"All Languages","platform":"All Platforms","subPlatform":"All Devices","title":"Using Appium for Robotic Process Automation (RPA)","shortDesc":"RPA is a massive and growing part of the software industry, focused around the automation of repetitive business processes. While it has its own name and its own use cases, RPA is really not distinct from the tools and processes used in UI test automation. In this edition we take a look at how you can use Appium for all your RPA needs.","liveAt":"2020-05-27 00:00","canonicalRef":"https://www.headspin.io/blog/using-appium-for-robotic-process-automation-rpa"},"mtime":"2023-04-28T16:49:48Z","permalink":"https://appiumpro.com/editions/117-using-appium-for-robotic-process-automation-rpa","slug":"117-using-appium-for-robotic-process-automation-rpa","path":"/editions/117-using-appium-for-robotic-process-automation-rpa","news":null,"tags":["All Languages","All Platforms","All Devices"]},{"mdPath":"/vercel/path0/content/editions/0111.md","num":111,"rawMd":"\n\nAs Covid-19 sweeps around the globe and brings a lot of unexpected change and complexity in people's lives, whether through their becoming ill or because of the social and economic consequences of this crisis, I've been asking myself: what can Appium do to help? Automating mobile apps pales in comparison to the work that healthcare professionals are doing right now, and certainly doesn't feel sufficient to address the severeness of the concrete need currently being felt in so many communities all around the world.\n\nI tried to think of a clever way to use mobile automation to trigger donations to appropriate services, [like we did once before](https://appiumpro.com/editions/49). When it really comes down to it, though, that's a gimmicky sort of response to a crisis like the one we're in. What people need most right now may not be mobile app automation. It's pretty cool that Jason Huggins can [repurpose his robot automation business to make face shields](https://twitter.com/hugs/status/1242221899884695553) for healthcare personnel, but that level of physical aid is probably beyond us on the software automation side.\n\nBut you know what? That's OK. It turns out (at least I hope it does) that we are human beings first, and Appium users second (or twentieth, or what have you). The real question is, what can we, as human beings, do for our fellow human beings in this crisis? And not just for our \"fellow human beings\" considered abstractly, but our actual physical neighbor humans that live next door and downstairs and across the street? Obviously the mandate to stay home and prevent the spread of disease through physical contact limits our options. It doesn't eliminate them, though.\n\nThis is a hugely unpredictable time in the world, and the economic fallout looks like it may be as severe as the health risks have already proven to be. Some of you reading this may have lost your jobs. For you, I hope that the work I've started to [bring high-quality test automation instruction online](https://cloudgrey.io/blog/jonathan-lipps-joins-headspin) will be of some use in helping to find good employment in an uncertain time.\n\nFor others, the sentiment may be one of more or less relief. Compared to many other industries, tech hasn't seemed poised to be altered so dramatically. Because of the Internet, we can all work from home. Because of the Internet, people can continue to consume the value that is generated through mobile app development. For those of us in this situation, we are in a uniquely fortunate position to help others. It might not be wise for us to go babysit our neighbor's kids, but we *could* send our neighbor money for groceries this week. It might not be wise for us to eat out at our local restaurant or coffee shop, but we *could* order food for the whole block and help keep them in business. It might not be wise to get a haircut or take a yoga class, but we *could* pay for those services anyway, sending a message that we value the service providers enough to help keep them afloat during a season that is uniquely difficult for their businesses.\n\nI sure hope that governments around the world are prioritizing taking care of their citizens in these times, including taking care of their physical and financial needs. But for those of us who might be quite fortunate relative to others right now, it's worth asking the question of how *we* can care for our communities in those ways too, especially when it's so easy, safe, and quick to send some cash online. I know that this is supposed to be a newsletter full of technical tips. Don't worry: we've got [over 100 of those](https://appiumpro.com/editions) for you to browse! And there will be many more to come. But today, I wanted to encourage each of us to take a step back from our computer screens, look around for some specific need in our community, and meet it. I just did this a little bit ago myself, and without going into detail, I'll just say that it was an immensely good thing.\n\nOh, and if you *do* think of a way to use Appium to help people in this crisis, or to fight the Coronavirus, let me know! I'll help you get the word out.\n\nAlright Appium humans, let's do this! Stay healthy, stay safe, and stay generous. Hopefully we'll all get back to our regularly scheduled app automation very soon, and maybe even with a little more empathy for everyone else we're \"sheltering in place\" with on this big chunk of rock floating in the starry void.\n","metadata":{"lang":"All Languages","platform":"All Platforms","subPlatform":"All Devices","title":"Appium in the Time of Coronavirus","shortDesc":"This is not a typical Appium Pro article. It's a call for kindness and compassion in the midst of the first, and hopefully the last, major global crisis during the tenure of Appium Pro.","liveAt":"2020-04-01 10:00","canonicalRef":"https://www.headspin.io/blog/appium-in-the-time-of-coronavirus"},"mtime":"2023-04-28T16:49:48Z","permalink":"https://appiumpro.com/editions/111-appium-in-the-time-of-coronavirus","slug":"111-appium-in-the-time-of-coronavirus","path":"/editions/111-appium-in-the-time-of-coronavirus","news":null,"tags":["All Languages","All Platforms","All Devices"]},{"mdPath":"/vercel/path0/content/editions/0110.md","num":110,"rawMd":"\n\n

\n \"Appium\n

\n\nDid you know that Appium is just a web server? That's right! I'm going to write a full edition at some point on the WebDriver Protocol, which is the API that Appium implements (and which, as you can tell by the name, was invented for the purpose of browser automation). But for now, let's revel in the knowledge that Appium is just like your backend web or API server at your company. In fact, you could host Appium on a server connected to the public internet, and give anybody the chance to run sessions on your devices! (Don't do this, of course, unless you're a cloud Appium vendor).\n\nYou may be used to writing Appium code in Java or some other language, that looks like this:\n\n```java\ndriver = new IOSDriver(new URL(\"http://localhost:4723/wd/hub\"), capabilities);\nWebElement el = driver.findElement(locator);\nSystem.out.println(el.getText());\ndriver.quit();\n```\n\nThis looks like Java code, but what's happening under the hood is that each of these commands is actually triggering an HTTP request to the Appium server (that's why we need to specify the location of the Appium server on the network, in the `IOSDriver` constructor). We could have written all the same code, for example, in Python:\n\n```py\ndriver = webdriver.Remote(\"http://localhost:4723/wd/hub\", capabilities)\nel = driver.find_element(locator)\nprint(el.text)\ndriver.quit()\n```\n\nIn both of these cases, while the surface code looks different, the underlying HTTP requests sent to the Appium server (and the responses coming back) are the same! This is what allows Appium (and Selenium, where we stole this architecture from) to work in any programming language. All someone needs to do is code up a nice little client library for that language, that converts that language's constructs to HTTP requests.\n\nWhat all this means is that we technically don't need a client library at all. It's convenient to use one, absolutely. But sometimes, we want to just run an ad-hoc command against the Appium server, and creating a whole new code file and trying to remember all the appropriate syntax might be too much work. In this case, we can just use [curl](https://curl.haxx.se/), which is a command line tool used for constructing HTTP requests and showing HTTP responses. Curl works on any platform, so you can download it for your environment if it's not there already (it comes by default on Macs, for example). There are lots of options for using curl, and to use it successfully on your own, you should understand all the components of HTTP requests. But for now, let's take a look at how we might encode the previous four commands, without any Appium client at all, just by using curl!\n\n```bash\n# 0. Check the Appium server is online\n> curl http://localhost:4723/wd/hub/status\n\n# response:\n{\"value\":{\"build\":{\"version\":\"1.17.0\"}},\"sessionId\":null,\"status\":0}\n```\n\nYou can see above that we can make sure we have a connection to the Appium server just by running `curl` and then the URL we want to retrieve, in this case the `/status` endpoint. We don't need any parameters to curl other than the URL, because we're making a GET request, and so no other parameters are required. The output we get back is a JSON string representing Appium's build information. Now, let's actually start a session:\n\n```bash\n# 1. Create a new session\n> curl -H 'Content-type: application/json' \\\n -X POST \\\n http://localhost:4723/wd/hub/session \\\n -d '{\"capabilities\": {\"alwaysMatch\": {\"platformName\": \"iOS\", \"platformVersion\": \"13.3\", \"browserName\": \"Safari\", \"deviceName\": \"iPhone 11\"}}}'\n\n# response:\n{\"value\":{\"capabilities\":{\"webStorageEnabled\":false,\"locationContextEnabled\":false,\"browserName\":\"Safari\",\"platform\":\"MAC\",\"javascriptEnabled\":true,\"databaseEnabled\":false,\"takesScreenshot\":true,\"networkConnectionEnabled\":false,\"platformName\":\"iOS\",\"platformVersion\":\"13.3\",\"deviceName\":\"iPhone 11\",\"udid\":\"140472E9-8733-44FD-B8A1-CDCFF51BD071\"},\"sessionId\":\"ac3dbaf9-3b4e-43a2-9416-1a207cdf52da\"}}\n\n# save session id\n> export sid=\"ac3dbaf9-3b4e-43a2-9416-1a207cdf52da\"\n```\n\nLet's break this one down line by line:\n\n1. Here we invoke the `curl` command, passing the `-H` flag in order to set an HTTP request header. The header we set is the `Content-type` header, with value `application/json`. This is so the Appium server knows we are sending a JSON string as the body of the request. Why do we need to send a body? Because we have to tell Appium what we want to automate (our \"capabilities\")!\n2. `-X POST` tells curl we want to make a POST request. We're making a POST request because the [WebDriver spec](https://github.com/jlipps/simple-wd-spec#new-session) defines the new session creation command in a way which expects a POST request.\n3. We need to include our URL, which in this case is the base URL of the Appium server, plus `/session` because that is the route defined for creating a new session.\n4. Finally, we need to include our capabilities. This is achieved by specifying a POST body with the `-d` flag. Then, we wrap up our capabilities as a JSON object inside of an `alwaysMatch` and a `capabilities` key.\n\nRunning this command, I see my simulator pop up and a session launch with Safari. (Did the session go away before you have time to do anything else? Then make sure you set the `newCommandTimeout` capability to `0`). We also get a bunch of output like in the block above. This is the result of the new session command. The thing I care most about here is the `sessionId` value of `ac3dbaf9-3b4e-43a2-9416-1a207cdf52da`, because I will need this to make future requests! Remember that HTTP requests are stateless, so for us to keep sending automation commands to the correct device, we need to include the session ID for subsequent commands, so that Appium knows where to direct each command. To save it, I can just `export` it as the `$sid` shell variable.\n\nNow, let's find an element! There's just one element in Appium's little Safari welcome page, so we can find it by its tag name:\n\n```bash\n# 2. Find an element\n> curl -H 'Content-type: application/json' \\\n -X POST http://localhost:4723/wd/hub/session/$sid/element \\\n -d '{\"using\": \"tag name\", \"value\": \"h1\"}'\n\n# response:\n{\"value\":{\"element-6066-11e4-a52e-4f735466cecf\":\"5000\",\"ELEMENT\":\"5000\"}}\n\n# save element id:\n> export eid=\"5000\"\n```\n\nIn the curl command above, we're making another POST request, but this time to `/wd/hub/session/$sid/element`. Note the use of the `$sid` variable here, so that we can target the running session. This route is the one we need to hit in order to find an element. When finding an element with Appium, two parameters are required: a locator strategy (in our case, \"tag name\") and a selector (in our case, \"h1\"). The API is designed such that the locator strategy parameter is called `using` and the selector parameter is called `value`, so that is what we have to include in the JSON body.\n\nThe response we get back is itself a JSON object, whose value consists of two keys. The reason there are two keys here is a bit complicated, but what matters is that they each convey the same information, namely the ID of the element which was just found by our search (`5000`). Just like we did with the session ID, we can store the element ID for use in future commands. Speaking of future commands, let's get the text of this element!\n\n```bash\n# 3. Get text of an element\n> curl http://localhost:4723/wd/hub/session/$sid/element/$eid/text\n\n# response:\n{\"value\":\"Let's browse!\"}\n```\n\nThis curl command is quite a bit simpler, because retrieving the text of an element is a GET command to the endpoint `/session/$sid/element/$eid/text`, and we don't need any additional parameters. Notice how here we are using both the session ID and the element ID, so that Appium knows which session and which element we're referring to (because, again, we might have multiple sessions running, or multiple elements that we've found in a particular session). The response value is the text of the element, which is exactly what we were hoping to find! Now all that's left is to clean up our session:\n\n\n```bash\n# 4. Quit the session\n> curl -X DELETE http://localhost:4723/wd/hub/session/$sid\n\n# response:\n{\"value\":null}\n```\n\nThis last command can use all the default curl arguments except we need to specify that we are making a DELETE request, since that is what the WebDriver protocol requires for ending a session. We make this request to the endpoint `/session/$sid`, which includes our session ID so Appium knows which session to shut down.\n\nThat's it! I hope you've enjoyed learning how to achieve some \"low level\" HTTP-based control over your Appium (and Selenium) servers!\n","metadata":{"lang":"All Languages","platform":"All Platforms","subPlatform":"All Devices","title":"Controlling Appium via raw HTTP requests with curl","shortDesc":"At the end of the day, Appium and Selenium are just web servers. That means we can interact with Appium just like we could with any other REST API, including using command-line tools like curl to generate raw HTTP requests directly to an Appium automation session.","liveAt":"2020-03-27 10:00","newsletterTopNote":"Sorry for the periodic delays on this weekly newsletter! A lot has been going on for me personally during the global pandemic--rest assured the Appium will keep flowing, if slightly more intermittently at the moment.","canonicalRef":"https://www.headspin.io/blog/controlling-appium-via-raw-http-requests-with-curl"},"mtime":"2023-04-28T16:49:48Z","permalink":"https://appiumpro.com/editions/110-controlling-appium-via-raw-http-requests-with-curl","slug":"110-controlling-appium-via-raw-http-requests-with-curl","path":"/editions/110-controlling-appium-via-raw-http-requests-with-curl","news":null,"tags":["All Languages","All Platforms","All Devices"]},{"mdPath":"/vercel/path0/content/editions/0105.md","num":105,"rawMd":"\n\nSo far in this series, we've looked at [mobile performance testing in general](https://appiumpro.com/editions/102), as well as [free tools for mobile performance testing](https://appiumpro.com/editions/103). Now it's time to discuss *paid* tools. Obviously, Appium is free and open source, and it's nice to focus on and promote free tools. But at the end of the day, sometimes paid tools and services can be valuable, especially in a business setting where the budget is less important than the end result. I want to make sure you have some decent and reliable information about the whole ecosystem, which includes paid tools, so will from time to time let you know my thoughts on this as well!\n\n> Disclaimers: This is not intended to be completely comprehensive, and even for the services I cover, I will not attempt to give a full overview of all their features. The point here is to drill down specifically into performance testing options. Some services might not be very complete when it comes to their performance testing offering, but that doesn't mean they don't have their strong points in other areas. For each tool, I'll also note whether I've personally used it (and am therefore speaking from experience) or whether I'm merely using their publicly-available marketing information or docs as research. Finally, I'll note for transparency that HeadSpin is an Appium Pro sponsor, and in the past I worked for Sauce Labs.\n\n## Appium Cloud Services with Performance Features\n\nMost interesting for us as Appium users will be services that allow the collection of performance data at the same time as you run your Appium tests. This is in my opinion the 'holy grail' of performance testing--when you don't have to do anything in particular to get your performance test data! In my research I found four companies that in one way or another touch on some of the performance testing topics we've discussed as part of their Appium-related products.\n\n### [HeadSpin](https://ui.headspin.io/register?referral=start-testing-appiumpro)\n\n> I've used this service\n\nHeadSpin is the most performance-focused of all the service providers I've seen. Indeed, they began life with performance testing as their sole mission, so this is not surprising. Along the way, they added support for Appium and have been heavy contributors to Appium itself in recent years. HeadSpin supports real iOS and Android devices in various geographical locations around the world, connected to a variety of networks.\n\n

\n \"HeadSpin\"\n

\n\nWhen you run any Appium test on HeadSpin, you get access to a report that looks something like the one here. Basically, HeadSpin tracks a ton of different metrics in what they call a [performance session report](https://ui.headspin.io/docs/performance-session-report). The linked doc highlights some of the metrics captured:\n\n> network traffic (in HAR and PCAP format), device metrics including CPU, memory, battery, signal strength, screen rotation, frame rate, and others, device logs, client-side method profiling, and contextual information such as Appium commands issued during the test, what app was in the foreground, and other contextual metadata.\n\nOn top of this, they try to show warnings or make suggestions based on industry-wide targets for various metrics. And this is all without you have to instrument your app or make specific commands to retrieve specific metrics. HeadSpin covers the most metrics out of any product or company I'm familiar with, including really difficult-to-measure quantities like the MOS (mean opinion score) of a video as a proxy for video quality.\n\nOne other feature useful for performance testing is what they call the 'HeadSpin bridge', which allows bridging remote devices to your local machine via their `hs` CLI tool. Concretely, this gives you the ability to run `adb` on the remote device as if it were local, so any Android-related performance testing tools that work on a local device will also work on their cloud devices, for example the [CPU Profiler](https://developer.android.com/studio/profile/cpu-profiler). The bridge works similarly for iOS, allowing step debugging or [Instruments profiling](https://developer.apple.com/library/archive/documentation/AnalysisTools/Conceptual/instruments_help-collection/Chapter/Chapter.html) on remote devices, as if they were local.\n\nIn terms of network conditioning, HeadSpin offers a number of options that can be set on a per-test basis, including network shaping, DNS spoofing, header injection (which is super useful for tracing network calls all the way through backend infrastructure), etc... This is in addition to requesting devices that exist in certain geographical regions.\n\nFinally, it's worth pointing out that HeadSpin tries to make it easy for teams to use the performance data captured on their service by spinning up a custom \"Replica DB\" for each team, where performance data is automatically written. This \"open data\" approach means it's easy to build custom dashboards, etc..., on top of the data without having to pre-process it or host it yourself.\n\n### [Sauce Labs](https://saucelabs.com)\n\n> I've used this service\n\nHistorically, Sauce Labs was focused primarily on cross-browser web testing, and so it's no surprise they have some performance-related information available about their web browser sessions. That's not what we're considering today, however, but rather Sauce's mobile offering. They have a virtual device cloud of iOS simulators and emulators, but as we mentioned before, performance testing of virtual devices is not particularly meaningful.\n\nSauce's real device cloud supports a feature called [Device Vitals](https://wiki.saucelabs.com/display/DOCS/Device+Vitals+for+Mobile+Applications) which provides a broad set of performance metrics, including CPU, memory, and performance information. It works with live/manual testing, but is also supported via their Appium interface when a special capability `recordDeviceVitals` is set. At this stage of the product it appears the only output for Appium tests is a CSV file which can be downloaded, meaning the user would be responsible for extracting and displaying the performance data itself. However, the live/manual usage shows a graph of performance data in real time:\n\n

\n \"Sauce\n

\n\nSauce also supports a virtual device bridge, which they call [Virtual USB](https://wiki.saucelabs.com/display/DOCS/Testing+with+Virtual+USB+on+Real+Devices). It is generally available for Android and in beta for iOS, and works more or less the same as HeadSpin's bridge feature.\n\nIn my experience, and as far as I can tell, Sauce does not give users the ability to specify network conditions for device connections, so testing app performance in a variety of lab conditions is not possible. However, it is possible to direct Sauce devices to use a proxy connection, including something like Charles Proxy (see below).\n\n### [AWS Device Farm](https://aws.amazon.com/device-farm/)\n\n> I've used this service\n\nAWS has its own Appium cloud, which works on a bit of a different model than HeadSpin or Sauce. With AWS, you compile your whole testsuite into a bundle and send it off to Device Farm, which then unpacks it and uses it to run tests locally. Theoretically, this gives you a lot of flexibility about how you can connect to a device during the test, and it's probably possible (though I haven't tested this) to run some of your own performance testing diagnostics on the device under test, even as your Appium script is going through its paces.\n\nLuckily, you may not need to worry about this because Device Farm does capture some performance information as your test is executing, namely CPU, memory usage, and thread count over time:\n\n

\n \"Device\n

\n\nDevice Farm does allow you to [simulate specific network conditions](https://docs.aws.amazon.com/devicefarm/latest/developerguide/how-to-simulate-network-connections-and-conditions.html) by creating a 'network profile' (that acts basically the same as the profiles we discussed in the article on [simulating network conditions for virtual devices](https://appiumpro.com/editions/104)\n\n### [Experitest](https://experitest.com)\n\n> Information retrieved from company website\n\nExperitest is a mobile testing company with Appium support, who also advertise performance data collection. They say they support different network conditions and geographical locations for their devices, as well as performance metrics like:\n\n> * Transaction duration\n> * Speed Index\n> * CPU consumption\n> * Memory Consumption\n> * Battery Consumption\n> * Network data (upload and download)\n\nI am not entirely sure what a 'transaction' is, but it appears to be a user-definable span of time or sequence of app events.\n\n

\n \"Experitest\n

\n\nI could not find more specific information in the docs about how this data is captured, and whether it is done so automatically as a part of an Appium test or whether it is a separate feature/interface. The best I can figure out, during test recording the users define start/stop points for performance 'transaction' recording, though this does not explain whether it is possible with Appium tests that you have brought yourself and did not develop in Experitest's 'Appium Studio' product.\n\nLike AWS Device Farm, Experitest apparently has the ability to manually create network 'profiles' that can be applied to certain tests or projects.\n\n### [Perfecto Mobile](https://perfectomobile.com)\n\n> Information retrieved from company website\n\nPerfecto Mobile is probably the oldest company in the entire automated mobile testing space, and they've had a lot of time to build out their support for performance testing. It looks like Perfect focuses on network condition simulation via their concept of [Personas](https://developers.perfectomobile.com/display/PD/Built-in+personas), which are essentially the same types of network profiles we have seen in other places.\n\nYou can set the Persona you want your Appium test to use via a special desired capability. Given my perusal of the docs, it appears possible to set \"points of interest\" in your test, that you can use for verification later on. It wasn't clear, but it's possible that setting one of these \"points of interest\" might capture some specific performance data at that time for later review, however I couldn't find any specific mention of the types of performance metrics that Perfecto captures, if any.\n\nIn addition, I'm not quite sure what \"Appium\" means exactly for Perfecto. From their [Appium landing page](https://www.perfecto.io/integrations/appium), we see this message:\n\n> Appium testing has limitations that may prevent it from being truly enterprise ready. Perfecto has re-implemented the Appium server so it can deliver stronger automated testing controls, mimic real user environments, and support the unique needs of today’s Global 1000 companies.\n\nWhat this implies is that, if you're using Perfecto, you're not actually running the Appium open source project code. Whether that is a good or bad thing is up to you to decide, however I can only imagine that it could generate confusion as their internal reimplementation inevitably drifts from what the Appium community is doing! How easy is it to migrate Appium tests running on Perfecto to another cloud? If they're not using standard open source Appium servers, this could be a difficult question to answer. I'm a big fan of what Perfecto is trying to do with their product, but (as is probably not surprising given my role with the Appium project) I don't think it's beneficial for any cloud provider to \"reimplement\" Appium.\n\n## Other Products\n\nCloud services are not the only types of paid products used for mobile performance testing. We also have SDKs (which are built into the app under test), and standalone software used for various purposes. None of these have any special relationship with or support with Appium, so you're responsible for figuring out how to make them work in conjunction with your Appium test.\n\n### [Charles Proxy](https://www.charlesproxy.com/)\n\n> Information retrieved from company website\n\nCharles Proxy is a networking debugging proxy that has special support for mobile devices. You can use it to inspect or adjust network traffic coming into or out of your devices. Charles comes with special VPN profiles you can install on your devices to get around issues with trusting Charles's SSL certificates, etc...\n\nCharles's main features are: SSL proxying, bandwidth throttling (network conditioning), request replay, and request validation.\n\n### [Firebase](https://firebase.google.com/)\n\n> Information retrieved from company website\n\nGoogle's Firebase is a *lot* of things, apparently intended to be a sort of one-stop-shop especially for Android developers. It's got databases and auth services, analytics and distribution tools. Firebase doesn't have any officially supported Appium product, though they do support automated functional testing of Android apps (via Espresso and UiAutomator 2) and iOS apps (via XCTest) through their Test Lab product.\n\nOf more interest for us today is their [performance monitoring](https://firebase.google.com/products/performance/) product. The way this works is by bundling in a particular SDK with your app which enables in-depth performance tracing viewable in the Firebase console. You start and stop traces using code that leverages the SDK in test versions of your app, and that's it. Of course, this means modifying your app under test, and I couldn't find any discussion of whether performance or network data is captured \"from the outside\" during test runs in the Firebase Test Lab.\n\n### [New Relic](https://newrelic.com/)\n\n> Information retrieved from company website\n\nAnother SDK-based option is [New Relic Mobile](https://newrelic.com/products/mobile-monitoring/features). Embedding their SDK in your app enables tracking of a host of network and other performance data. Where New Relic appears to have an advantage is in showing the connections your app has with other New Relic-monitored services (backend sites, for example).\n\n

\n \"New\n

\n\nOtherwise, New Relic provides most of the same types of performance data you'd expect. They also give you a \"User Interaction Summary\" which appears to be similar to HeadSpin's high level detail of potential UX issues. In addition, metrics can be viewed in aggregate across device types, so it's possible to easily spot performance trends on the level of device type as well.\n\nSince this is an SDK-based solution, you'll have to modify your app under test to gather the data. Presumably you could then use it in your Appium tests just fine!\n\n## Conclusion\n\nIn this article we examined a number of cloud services and other types of paid software used for performance testing. A small handful of these companies supports Appium as a first-class citizen, meaning you can use their cloud to run your Appium tests themselves, and potentially get a lot of useful performance data for free along with it.\n\nIn my mind, this is the best possible approach for Appium users--just write your functional tests the way a user would walk through your app, then run the tests on one of these platforms, and you'll get performance reports for free! (Or rather, for hopefully no *additional* fee). The best kind of performance test is obviously the one you didn't have to write explicitly yourself, but which still found useful information that can easily be acted on in order to improve the overall UX of your app.\n\nOh, and did I miss a good candidate for this article? It's entirely possible I did! This is a big and growing industry. Let me know about it and I'll update this list if I find a relevant product.\n","metadata":{"lang":"All Languages","platform":"All Platforms","subPlatform":"All Devices","title":"Paid Tools And Services For Mobile App Performance Testing","shortDesc":"We wrap up our long series on mobile performance and UX testing with a look at some of the non-free tools or services available to assist with the task. Some of these services provide a way to get performance reports for free as a result of an Appium test. Other tools are standalone products that can be used alongside Appium, but might require some extra setup on your part.","liveAt":"2020-02-05 10:00","canonicalRef":"https://www.headspin.io/blog/an-appium-cloud-service-with-performance-features"},"mtime":"2023-04-28T16:49:48Z","permalink":"https://appiumpro.com/editions/105-paid-tools-and-services-for-mobile-app-performance-testing","slug":"105-paid-tools-and-services-for-mobile-app-performance-testing","path":"/editions/105-paid-tools-and-services-for-mobile-app-performance-testing","news":{"rawMd":"Apologies that this newsletter is a day late! I wanted to be sure to do enough research on all the companies I could find in order to put together a useful set of descriptions. Also, I've been hard at work on the upcoming [Appium Pro Workshops](https://appiumpro.com/workshops). For those of you who are planning on attending--get ready, we're going to have some fun!\n","num":105,"mdPath":"/vercel/path0/content/news/0105.md"},"tags":["All Languages","All Platforms","All Devices"]},{"mdPath":"/vercel/path0/content/editions/0104.md","num":104,"rawMd":"\n\nIn a previous edition of Appium Pro, we sketched out some options for [measuring various network metrics](https://appiumpro.com/editions/103) for your mobile apps. In this edition, we spin the situation around, and ask: how can we *simulate* specific network speeds or conditions, in order to then test some other aspect of our app's behavior? For example, we might want to know how long a certain user flow takes when they are on a 3G network vs an LTE network.\n\nIf we want to automate a real device with specific network conditions, then we either need to put the device physically into those conditions (geographical location, mobile network provider, mobile network speed, etc...), or simulate it by connecting the device via wifi to a router which has some network shaping software on it. In either case, it's not something that's easy to attempt \"at home\".\n\nVirtual devices (like iOS simulators or Android emulators) are a different story, however! They share the same network as the virtual device host, which at least in the case of iOS is guaranteed to be a macOS machine. On macOS, which we assume we're using for this article, we have a few different ways to simulate a variety of network conditions for the entire system, which also ends up changing the network conditions for the iOS simulator or the Android emulator.\n\n### The Network Link Conditioner\n\nApple actually provides a special Preference Pane that allows you to adjust the network speed of your computer. It's called the [Network Link Conditioner](https://nshipster.com/network-link-conditioner/), and you can download it following [these instructions](https://stackoverflow.com/a/9659486/703723). When you've installed it, it looks like this:\n\n

\n \"Network\n

\n\nUsing this interface, you can manually select a certain network profile and toggle it off and on again. You can even, for example, select a profile which has 100% packet loss, meaning no network connectivity at all. This is useful to test your app's behavior in situations where the user loses connectivity, perhaps even in the middle of a user flow.\n\n### `dnctl` and `pfctl`\n\nThe Network Link Conditioner is nice, but it's not easily scriptable. However, it is just a thin GUI that calls out to some command-line applications installed on every Mac, which we can also just use directly:\n\n* `dnctl`: this is the control interface for the `dummynet` network shaping software. We use it to define network configurations based on their bandwidth, packet loss, and delay.\n* `pfctl`: this is the control interface for the packet filter device (i.e., the system-internal firewall). We can have it obey dummynet rules and turn it on, which actually enables the network shaping for the host.\n\nHere's how we might use these in combination to set a 3G network speed:\n\n```bash\ndown_bandwidth=\"780Kbit/s\"\ndown_packets_dropped=\"0.0\"\ndown_delay=\"100\"\nup_bandwidth=\"330Kbit/s\"\nup_packets_dropped=\"0.0\"\nup_delay=\"100\"\n(cat /etc/pf.conf && echo \"dummynet-anchor \\\"conditioning\\\"\" && echo \"anchor \\\"conditioning\\\"\") | sudo pfctl -f -\nsudo dnctl pipe 1 config bw \"$down_bandwidth\" plr \"$down_packets_dropped\" delay \"$down_delay\"\nsudo dnctl pipe 2 config bw \"$up_bandwidth\" plr \"$up_packets_dropped\" delay \"$up_delay\"\necho \"dummynet out quick proto tcp from any to any pipe 1\" | sudo pfctl -a conditioning -f -\necho \"dummynet in quick proto tcp from any to any pipe 2\" | sudo pfctl -a conditioning -f -\nsudo pfctl -e\n```\n\nWhat's going on here?\n\n1. We decide what our upload and download characteristics should be for a 3G connection.\n2. We create an \"anchor\" in our `pf.conf` file so our firewall changes are localized.\n3. We create two dummynet pipes, one for downloads and one for uploads, based on our 3G parameters.\n4. We tell the firewall to use our dummynet rules for uploading and downloading TCP traffic, to and from any hosts.\n5. We make sure to enable the firewall in case it's not already running.\n\nIt's a lot! And it's not all--we also need to make sure to reset our changes when we're done, otherwise our host's internet will be permanently altered:\n\n```bash\nsudo dnctl -q flush\nsudo pfctl -f /etc/pf.conf\n```\n\nIt's a bit ugly, but it is entirely automatable (recognizing however that `sudo` access is required). I've gone ahead and taken the liberty of compiling all of this into a [bash script that does network conditioning](https://github.com/cloudgrey-io/appiumpro/blob/master/scripts/network.sh). It encodes all the same options as the Network Link Conditioner preference pane (i.e., if you tell it to use \"LTE\" speeds, it will do the exact same thing that the preference pane does under the hood). Here's how you use it:\n\n```bash\n# start the network conditioning with 3G speeds (could also be LTE, etc...--see script for list)\nsudo ./network.sh start 3G\n\n# stop it when we're done\nsudo ./network.sh stop\n```\n\nA bonus is that this script is runnable from within a test script! Here's an example of how I use this script to see how long the Appium Pro takes to load on Mobile Safari, at full speed versus at 3G speed:\n\n```java\nprivate void loadPage() {\n long startTime = System.nanoTime();\n driver.get(\"https://appiumpro.com\");\n long endTime = System.nanoTime();\n long msElapsed = (endTime - startTime) / 1000000;\n System.out.println(\"Time elapsed: \" + msElapsed);\n}\n\nprivate void setNetworkMode(String mode) throws Exception {\n new ProcessExecutor().command(NET_SCRIPT, \"start\", mode).exitValueNormal().execute();\n}\n\nprivate void stopNetworkConditioning() throws Exception {\n new ProcessExecutor().command(NET_SCRIPT, \"stop\").exitValueNormal().execute();\n}\n\n@Test\npublic void testPageLoadWithNormalNetwork() {\n loadPage();\n}\n\n@Test\npublic void testPageLoadWith3GNetwork() throws Exception {\n setNetworkMode(\"3G\");\n try {\n loadPage();\n } finally {\n stopNetworkConditioning();\n }\n}\n```\n\nHere I've simply defined `NET_SCRIPT` to be the path to the network conditioning script, and also made sure to put my `stopNetworkConditioning` method in a `finally` block so that we guarantee it is reset even if we get an error during the actual test step execution. Feel free to check out the [full code example on GitHub](https://github.com/cloudgrey-io/appiumpro/blob/master/java/src/test/java/Edition104_Network_Conditioning_iOS.java).\n\nThat's it! Again, we're dealing with a pretty limited scenario here, since this trick only works with virtual devices, and it also affects the system network speeds (so if you're trying to stream video while running your test, you may notice some unpleasant side effects). But it's a quick and easy way to see how your app behaves in a variety of network conditions, without needing any specialized proxy software or other services.\n\n(For those times where you want real-world network feedback on real devices, you'll want to check out a service that offers geographically-based devices attached to networks of different speeds).\n","metadata":{"lang":"All Languages","platform":"All Platforms","subPlatform":"Virtual devices","title":"Simulating Different Network Conditions For Virtual Devices","shortDesc":"When testing your mobile app's behavior, it's important not to assume fast or even decent internet connectivity to the user's device. One way of seeing how your app behaves in situations where the network conditions are poor is to simulate those conditions locally, either for manual testing or for use in a build scenario.","liveAt":"2020-01-29 10:00","canonicalRef":"https://www.headspin.io/blog/simulating-different-network-conditions-for-virtual-devices"},"mtime":"2023-04-28T16:49:48Z","permalink":"https://appiumpro.com/editions/104-simulating-different-network-conditions-for-virtual-devices","slug":"104-simulating-different-network-conditions-for-virtual-devices","path":"/editions/104-simulating-different-network-conditions-for-virtual-devices","news":null,"tags":["All Languages","All Platforms","Virtual devices"]},{"mdPath":"/vercel/path0/content/editions/0103.md","num":103,"rawMd":"\n\n

\n \"Wireshark\"\n

\n\nIn a previous edition of Appium Pro, I discussed [mobile performance and UX testing](https://appiumpro.com/editions/102) at a conceptual level. In this edition, let's take a look at some pointers for tracking the various metrics we saw earlier. There are way too many metric to consider each in detail, so we'll just outline a solution in each case; stay tuned for future articles with fully-baked examples (and let me know which metrics you're most interested in reading about!) In this set of pointers, I'm going to focus on free and open source approaches, saving a deeper look at paid services for a follow-up article.\n\n### Time-to-interactivity (TTI)\n\nThis metric measures the time elapsed from when the user launches your app till it's actually usable. A first-pass solution to measuring TTI would be throwing some timestamps into your testcode before starting an Appium session and after the session is fully started. However, this approach falls short in several ways:\n\n* You're measuring Appium startup time in addition to app startup time\n* Just because you have an Appium session loaded doesn't mean your app is actually interactable yet.\n\nAs a second pass, we can try an approach like we did in [Edition 97](https://appiumpro.com/editions/97), where we delayed actually launching the app until after Appium startup itself was complete. This gets us a lot closer to a solid metric, but is still not bulletproof, because measurements are contingent on a find-element poll, which might not occur at exactly the moment the app is fully loaded.\n\n### DNS resolution\n\nHow on earth can you test that your mobile app API calls are hitting the appropriate server? Obviously checking this assumes that (a) you know the domains the app is trying to hit, and (b) you know the IP addresses it's *supposed* to resolve to (for its region, or whatever). The only obvious and free solution I came up with to this problem also assumes (c) you are running on emulators and simulators (i.e., using the same network as your test machine).\nWhen you're running emulators and simulators, the network used by the device under test is in fact your host machine's network, and you can use [tcpdump](https://www.tcpdump.org/) to examine all network traffic leaving your machine, including DNS resolution requests. Of course, looking at all TCP traffic will be a bit of a firehose, so you can restrict `tcpdump`'s output to requests to nameservers (typically running on port 53):\n\n```\nsudo tcpdump udp port 53\n```\n\nThe output of DNS requests will look something like:\n\n```\n20:09:54.099145 IP 10.252.121.60.62613 > resolver.qwest.net.domain: 52745+ A? play.google.com. (33)\n20:09:54.101718 IP resolver.qwest.net.domain > 10.252.121.60.62613: 52745 1/0/0 A 216.58.217.46 (49)\n```\n\nSo it would be straightforward (if not easy) to write a script that runs `tcpdump` as a subprocess, scrapes output during the space of a mobile app call, and makes assertions about domain name resolution!\n\nUnfortunately, this would not work on real devices. For real devices you'd need to set up some kind of DNS proxy and have your devices configured to use it for DNS resolution, so you can log or track data about DNS requests.\n\n### Time till 1st byte, TCP delay, TLS handshake time\n\nThese low-level network metrics are best captured by a network analysis tool like [Wireshark](https://wireshark.org), which can listen to all TCP traffic that passes through a network interface, and provide more data than a simple `tcpdump` log. The data Wireshark captures is made available in a special `.pcap` file, which has become a standard for representing network data.\n\nNote that this means you could also use Wireshark for DNS request examination!\n\nUsing a `.pcap` file (which stands for \"packet capture\" because it represents every single packet that traverses a network interface), you can get a ton of information about network requests, including the time they took. `.pcap` files can be parsed in pretty much any language, for example with the [jnetpcap](https://mvnrepository.com/artifact/jnetpcap/jnetpcap) library for Java. Parsing the file enables you to determine all kinds of facts about network requests, for example how long they took.\n\nWireshark is designed as a GUI tool, which limits is utility in CI environments, though it can be launched from the CLI in an auto-record mode, and directed to write the resulting capture file to any location.\n\nAnd finally, any method like this will again only work on virtual devices, unless you're somehow able to route real device traffic through a router which is itself running Wireshark!\n\n### Other network analysis approaches\n\nSo far I've tried to recommend very low-level and general tools, but there are also some other options. Some of these are specific to Android:\n\n* [Advanced Network Profiling](https://developer.android.com/studio/profile/android-profiler) - a library produced by Google that you build into your app, which can capture and output network data\n* [Stetho](https://facebook.github.io/stetho/) - a similar library from Facebook that provides a web devtools-like environment for inspecting your app's network requests. Also requires building into the app.\n\nCross-platform solutions would include the use of man-in-the-middle proxies:\n\n* [Postman](https://www.getpostman.com/) - a GUI-based tool that can provide network analysis information when you proxy mobile app requests through it.\n* [mitmproxy](https://mitmproxy.org/) - an open-source CLI-based tool which allows proxying of HTTP/HTTPS traffic\n\nProxy solutions require configuring the device under test with the correct proxy settings, and trusting the proxy as a certificate authority for HTTPS requests to be visible for analysis. To learn more about how to put all this together, you can check out the Appium Pro articles on [capturing iOS simulator network traffic](https://appiumpro.com/editions/62), [capturing Android emulator traffic](https://appiumpro.com/editions/63), and [capturing network traffic with Java in your test scripts](https://appiumpro.com/editions/65).\n\n### CPU utilization, memory consumption, etc...\n\nThese low-level device metrics can be retrieved in a minimal way using Appium itself. Check out these earlier Appium Pro articles for more info (note that with iOS especially, programmatically using retrieved performance info is not straightforward at all):\n\n* [Capturing performance data for Android apps](https://appiumpro.com/editions/5)\n* [Capturing performance data for iOS apps](https://appiumpro.com/editions/12)\n\n### Video quality, blank screen time, animation time\n\nThese last metrics are particularly hard to determine using free and open source tools. Video quality is a subjective measurement and to determine it in an automated fashion would require (a) the ability to capture video from the screen (which Appium can do via its [startScreenRecording](https://appiumpro.com/editions/82) command), and (b) some machine learning model which could take a video as input and provide a quality judgment as output.\n\nI could not find a good open source tool to measure video quality (though there is a paper [outlining how such a tool might be developed](https://www.researchgate.net/publication/301464319_An_Open_Source_Platform_for_Perceived_Video_Quality_Evaluation)).\n\nSimilarly, for blank screen time, the best approach would involve training some kind of machine learning model to recognize screens with no elements, though an easy approximation could be made by using Appium and logging how much time elapses with a typical element wait.\n\n### Conclusion\n\nIn general, the world of free and open source network and performance testing is a bit of a rough and tumble place. In some cases, the tools exist, but are not well-integrated with the ecosystem a tester is used to working with. In other cases, we are limited to certain platforms or devices. In yet other cases, the best tools out there today are probably not free and open source.\n\nFor that reason, stay tuned, because we're going to consider some paid tools and services in a future edition of Appium Pro, so you have the best understanding of the landscape and can make good decisions about the costs and benefits of adopting various approaches to performance testing of mobile apps.\n","metadata":{"lang":"All Languages","platform":"All Platforms","subPlatform":"All Devices","title":"Free Tools For Mobile App Performance Testing With Appium","shortDesc":"Having already looked at network and performance testing from a high level, in this article we dive into specific tools and techniques for capturing some of the most relevant performance and UX metrics for mobile apps.","liveAt":"2020-01-22 10:00","canonicalRef":"https://www.headspin.io/blog/free-tools-for-mobile-app-performance-testing-with-appium"},"mtime":"2023-04-28T16:49:48Z","permalink":"https://appiumpro.com/editions/103-free-tools-for-mobile-app-performance-testing-with-appium","slug":"103-free-tools-for-mobile-app-performance-testing-with-appium","path":"/editions/103-free-tools-for-mobile-app-performance-testing-with-appium","news":null,"tags":["All Languages","All Platforms","All Devices"]},{"mdPath":"/vercel/path0/content/editions/0102.md","num":102,"rawMd":"\n\nWhat is mobile app performance testing, exactly? What should we care about in terms of app performance and how can we test app performance as part of our automated testsuite? This is a topic I've been thinking a lot about recently, and so I convinced Brien Colwell (CTO of [HeadSpin](https://www.headspin.io/audio-visual-platform)) to sit down with me so I could pester him with some questions. I took our conversation and turned it into a sort of FAQ of mobile app performance testing. None of this is specifically tied to Appium--stay tuned for future editions where we look at how to achieve some of the goals discussed in this article, using Appium by itself or in conjunction with other tools and services.\n\n### What is performance testing all about?\n\nReally, we could think of performance testing as a big part of a broader concept: UX testing (or User Experience Testing). The idea here is that a user's experience of your app goes beyond the input/output functionality of your app. It goes beyond a lot of the things we normally associate with Appium (though of course it includes all those things too--an app that doesn't work does not provide a good experience!) It reflects the state of the app market, where the world is so crowded with nearly-identical apps, that small improvements in UX can mean the difference between life and death for one of these startups.\n\nYears ago, I considered performance testing to be exclusively in the domain of metrics like CPU or memory usage. You only did performance testing when you wanted to be sure your app had no memory leaks, that kind of thing. And this is still an important part of performance testing. But more broadly, performance testing now focuses on attributes or behaviors of your application as they interface with psychological facts about the user, like how long they are prepared to wait for a view to load before moving on to another app. One quick way of summarizing all of this is to define performance testing as ensuring that your app is responsive to the directions of the user, across all dimensions.\n\n### What performance metrics should we care most about?\n\nIt's true that classic specters of poor software performance, like memory leaks or spinning CPUs, can plague mobile app experience. And there is good reason to measure and profile these metrics. However, the primary cause of a bad user experience these days tends to be network-related. So much of the mobile app experience is dominated by the requirement of loading data over the network, that any inefficiency there can cause the user to experience painfully frustrating delays. Also, testing metrics like memory or CPU usage can often be adequately accomplished locally during development, whereas network metrics need to be tested in a variety of conditions in the field.\n\nTo this end, we might track metrics like the following:\n\n* DNS resolution (did the name resolve to an IP that was close by?)\n* Time till 1st byte received for a given response\n* Time delay between send / acknowledge in the TCP stream\n* TLS handshake time\n\nBeyond network metrics, there are a number of other UX metrics to consider:\n\n* Time-to-interactivity (TTI): how long does it take for an app to become usable after the user has launched it? (This is an extremely important UX metric)\n* Total time a blank screen is shown during a user session\n* Total time loading animations / spinners are shown during a user session\n* Video quality (MOS)\n* Time to full load (for progressively-loaded apps)\n\n### What are some common mistakes mobile app developers make that lead to poor performance?\n\nWhen developing an application, we are often doing so on top-of-the-line desktop or laptop computers and devices, with fast corporate internet. The performance we experience during development may be so good that it masks issues experienced by the average set of users. Here are a few common mistakes (again, largely network-oriented) that developers make which can radically impact performance:\n\n* Using HTTP/2 or a custom TCP communication channel instead of sticking with the simplicity of HTTP v1 and optimizing traffic. (I.e., there aren't as many gains as you might expect from a more modern or complicated network stack)\n* Having dependent/blocking network requests that are executed serially; whenever possible, network requests should be executed in parallel.\n* Having too many network requests on a single view. This can be a consequence of a microservices / micro API architecture where to get the appropriate data, lots of requests are required. For mobile it is essential to make as few requests as possible (ideally only 1 per view), and therefore to sacrifice purity / composability of API response in order to aggregate all the data necessary to build a given view.\n* Misconfigured DNS causing devices to talk to servers that are unduly far away.\n* Unoptimized images, video, or audio being sent to regions or networks that can't handle the bandwidth.\n\n### How should we think about absolute vs relative performance measurements?\n\nIn general, it can often be more useful to track performance relative to a certain baseline, whether that is an accepted standard baseline, or just the first point at which you started measuring performance of your app. However, tracking relative performance can also be a challenge when testing across a range of devices or networks, because relative measures might not be comparing apples to apples. In these cases, looking at absolute values side-by-side can be quite useful as well.\n\n### Are there any absolute standard performance targets generally recognized as helpful?\n\nIt's true that each team defines UX for their own app. Acceptable TTI measures for an e-commerce app might differ by an order of magnitude or more from acceptable measures for AAA gaming titles. Still, there are some helpful rules of thumb based on HCI (Human-Computer Interaction) research:\n\n* Any delay over 500ms becomes a \"cognitive\" event, meaning the user is aware of time having passed.\n* Any delay over 3s becomes a \"reflective\" event, meaning the user has time to reflect on the fact of time having passed. They can become distracted or choose to go do something else.\n\nThese are not hard-and-fast truths that make sense in every case. And of course nobody really has a universal answer, but again, it's helpful to treat that 500ms number as a good target for any interaction we want to feel \"snappy\".\n\n(To follow up on some of this research, read up on the [human processor model](https://en.wikipedia.org/wiki/Human_processor_model) or [powers of 10 in UX](https://www.nngroup.com/articles/powers-of-10-time-scales-in-ux/))\n\n### How widely should we expect performance to vary across different devices?\n\nIn other words, when should we be really concerned about differences in performance between different devices or networks? Actually, it's fairly common to see differences of about 30% as quite common between devices. This level of difference doesn't usually indicate a severe performance issue, and can (with all appropriate caveats) be regarded as variance.\n\nTrue performance problems can cause differences of 10-100x the baseline measurements--just think how long you've waited for some app views to load when they are downloading too much content over a slow network!\n\n### How do you decide which devices to focus on for performance testing?\n\nThe answer here is simple if not practical: test on the devices that bring in the greatest revenue! Obviously this implies that you have some kind of understanding of your userbase: where are they located? What devices do they use? What is their typical network speed? And so on. If you don't have this information, try to start tracking it so you can cross-reference with whatever sales metrics are important for your product (items purchased, time spent in app, whatever).\n\nAt that point, if you can pick the top 5 devices that meet these criteria in a given region, you're well positioned to ensure a strong UX.\n\n### Conclusion\n\n\"Performance\" turns out to be quite a broad subcategory of UX, and of course, what we care about at the end of the day is UX, in a holistic way. The more elements of the UX we can begin to measure, the more we will be able to understand the impact of changes in our application. We'll even eventually get to the point where we've identified solid app-specific metric targets, and can fail builds that don't meet these targets, guaranteeing a minimum high level of UX quality for our users. Oh, and our users? They won't know any of this is happening, but they'll *love* you for it.\n","metadata":{"lang":"All Languages","platform":"All Platforms","subPlatform":"All Devices","title":"Mobile App Performance Testing","shortDesc":"What is mobile app performance? How do we know what to track and how to interpret what we find? In this part-FAQ, part-interview, we explore a host of topics that take us to the edge of thinking about mobile app performance as a significant component of mobile app UX.","liveAt":"2020-01-15 10:00","canonicalRef":"https://www.headspin.io/blog/mobile-app-performance-testing"},"mtime":"2023-04-28T16:49:48Z","permalink":"https://appiumpro.com/editions/102-mobile-app-performance-testing","slug":"102-mobile-app-performance-testing","path":"/editions/102-mobile-app-performance-testing","news":null,"tags":["All Languages","All Platforms","All Devices"]},{"mdPath":"/vercel/path0/content/editions/0093.md","num":93,"rawMd":"\n\nAppium supports automation of all kinds of Android apps---not just native apps. You can use Appium to [automate websites using the Chrome browser on Android](https://appiumpro.com/editions/4), and also to [automate webview-based portions of hybrid apps](https://appiumpro.com/editions/17). On iOS Appium has to implement a bunch of custom logic to attach to Safari or hybrid apps, but on Android, our life is made much easier by the existence of [Chromedriver](https://chromedriver.chromium.org/). Chromedriver is an implementation of the WebDriver protocol by Google, which can control Chrome browsers on both desktop and Android platforms.\n\n### How Chromedriver works\n\nWhen you request a context switch into a webview, or when you start an Appium session using the `browserName` capability set to `Chrome`, Appium starts up Chromedriver for you automatically as a subprocess. Any standard commands your test client sends to Appium while Chromedriver is active get passed directly onto Chromedriver at that point, so that Chromedriver is effectively the component which is driving the automation of the website within the browser or webview.\n\nAll of this works transparently to you as the Appium user because both Appium and Chromedriver expose the W3C WebDriver protocol! This fact even allows Appium to do clever things like decide *not* to pass certain commands to Chromedriver and instead execute its own implementation of them. This is why you can still run certain `mobile:` commands while in a webview or browser context, for example. From the Appium developers' perspective, Chromedriver is also nice because it makes our job a lot simpler; rather than figure out how to implement fundamental automation of Chrome ourselves, we can rely on the tool that Google has provided (and Google is the producer of Chrome, so they are in the best position to make the most robust and stable tool!).\n\nThere is one downside of relying on Chromedriver, however, which is that new versions of Chromedriver are not compatible with older versions of Chrome. Starting with version 73, Chromedriver updated its versioning scheme to match the version of Chrome. Nowadays, what you want to ensure is that if you have version `XX` of Chrome on your device, you are using version `XX` of Chromedriver with Appium. But Appium releases contain only *one* version of Chromedriver--typically the latest version of Chromedriver which is out in the wild at the time of an Appium release. (So Appium 1.15.1, for example, comes bundled with Chromedriver `76.0.3809.126`). This is because we don't want Appium users to have to download their own version of Chromedriver and manage it separately--that'd be too many moving parts!\n\nBut what if you've upgraded to Appium 1.15.1, but the version of Chrome on your device is only at 75? Well, then you'll abruptly encounter an error that looks like this:\n\n```txt\nAn unknown server-side error occurred while processing the command.\nOriginal error: unknown error: Chrome version must be >= 76\n```\n\nUh oh! How do you resolve this error? There are a few different strategies.\n\n### Strategy 1: Update Chrome\n\nThe first strategy is pretty obvious. Don't you want Chrome to be at the latest version, too? If so, just update Chrome (you can usually find x86-based APKs for emulators with a bit of judicious Googling), and you'll be good to go. But if you want to make sure you're at an older version of Chrome, or if you can't update, or are automating a webview targeting a different version of Chrome, then read on...\n\n### Strategy 2: Tell Appium to use a different Chrome\n\nAppium downloads and installs the version of Chrome which it was published with, if you don't tell it otherwise. But you can tell it otherwise! There is a command-line flag you can pass to the Appium install process that allows you to install any version of Chrome you like:\n\n```bash\nnpm install appium --chromedriver_version=\"75.0.3770.140\"\n```\n\nWhen you run this command, you'll see Appium downloading the version you specified instead of the default. Of course, this version must exist at the Chromedriver downloads site in the expected location!\n\n### Strategy 3: Use your own Chromedriver(s)\n\nIf you are responsible for automating different devices with different versions of Chrome, you might want the Appium server not to use just one version of Chromedriver, but to use a number of versions, based on the automation scenario. If you're in this situation, you can maintain your own local repository of Chromedriver executables, and pass the path to one of them in when you start the Appium server:\n\n```bash\nappium --chromedriver-executable /path/to/my/chromedriver\n```\n\n### Strategy 4: Let Appium download new Chromedrivers on the fly\n\nBy far the easiest of all the strategies is to just let Appium decide what version of Chromedriver works with your browser or webview, and download it when necessary for you. To make this work, you need to use a couple desired capabilities:\n\n* `chromedriverExecutableDir`: the path to a writable directory on the Appium server's host, where new Chromedriver binaries can be downloaded and executed from\n* `chromedriverChromeMappingFile`: the path to a JSON file on the Appium server's host, where a mapping will be stored of Chromedriver versions to Chrome support.\n\nNow, because Appium is downloading executables to the machine from the Internet, there's a potential security risk here (even though Appium does verify the Google-provided checksum of the downloaded files). What this means is to use this feature, you need to enable it as an \"insecure\" feature when you start the Appium server:\n\n```bash\nappium --allow-insecure chromedriver_autodownload\n```\n\n(If you have other insecure features to allow, like `execute_driver_script`, you can simply separate them with the `,` symbol).\n\nWhen you put all of this together, Appium will automatically download a Chromedriver to work with your webview or browser, and keep it in the directory specified, so that future requests for automating the same version of Chrome don't trigger a new download. So if you wind up in a case where you can't or don't want to upgrade Chrome, or are dealing with a potentially large number of devices with varying versions of Chrome on them, this strategy might be the key to some momentary sanity.\n","metadata":{"lang":"All Languages","platform":"Android","subPlatform":"All Devices","title":"Managing Chromedriver for Android Chrome and Webview Testing","shortDesc":"Appium uses Chromedriver to automate Android web and hybrid apps. Chromedriver is great, but it comes with its own wrinkles in terms of Chrome version support. In this edition, we take a look at four strategies for approaching these challenges.","liveAt":"2019-10-30 10:00","canonicalRef":"https://www.headspin.io/blog/managing-chromedriver-for-android-chrome-and-webview-testing"},"mtime":"2023-04-28T16:49:48Z","permalink":"https://appiumpro.com/editions/93-managing-chromedriver-for-android-chrome-and-webview-testing","slug":"93-managing-chromedriver-for-android-chrome-and-webview-testing","path":"/editions/93-managing-chromedriver-for-android-chrome-and-webview-testing","news":null,"tags":["All Languages","Android","All Devices"]},{"mdPath":"/vercel/path0/content/editions/0091.md","num":91,"rawMd":"\n\n

\n \"Appium\n

\n\nWe've discussed before how to [use Appium to automate Windows desktop apps](https://appiumpro.com/editions/81), but of course it's also possible to use Windows as the host environment for traditional mobile testing with Appium. It is not, unfortunately, possible to automate iOS simulators on Windows, because iOS simulators are only designed to run on macOS as part of Xcode. It is also not technically possible to work with real iOS devices plugged into a Windows machine, though some folks have figured this out. It's just not a supported use case.\n\nWhat *is* supported is to run your Android tests with Appium on Windows! So let's take a look at all the steps required to support this kind of automation. (Note that I am assuming a recent install of the modern Windows 10 OS).\n\n### Requirements\n\nAppium's requirements for Android testing on Windows are what you'd expect: basically the requirements for Android dev, plus Appium's own requirement for its runtime environment.\n\n1. A version of NodeJS supported by Appium (currently 10+, but typically the latest stable version), *or* [Appium Desktop](https://github.com/appium/appium-desktop)\n1. The Java Development Kit (JDK)\n1. Android Studio and related tools\n\n### System Setup\n\n1. [Install NodeJS](https://nodejs.org/en/download/). (If you are going to run Appium Desktop, you can skip this step since Appium Desktop bundles its own version of Node. But I think it's a good practice to be able to run Appium from the command line, since you might want to run a beta version of Appium at some point. And don't worry--Appium Desktop's Inspector can talk to versions of Appium running on the CLI).\n1. [Install the JDK](https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html). (I usually get Java 8 for compatibility with older test suites, but get whatever version works for you). Sorry, you'll have to do Oracle's signup/login dance. When you run the downloaded installer, pay attention to where Java is installed (for example, did it get put in the directory `C:\\Program Files\\Java\\jdk1.8.0`?).\n1. Set the `JAVA_HOME` environment variable in your system settings. If you've never set an environment variable before, [this](https://www.architectryan.com/2018/08/31/how-to-change-environment-variables-on-windows-10/) is a good guide. Basically, we need to create a new variable with the name `JAVA_HOME`, and the value equal to the path where the JDK was installed (e.g., `C:\\Program Files\\Java\\jdk1.8.0`). Once you've saved out of all the dialogs, open up a command prompt and type `echo %JAVA_HOME%`. You should see your JDK path printed back out to you! Appium needs this in order to know where to find relevant Java binaries.\n\n### Appium Setup\n\n1. Start an Admin command prompt (type \"cmd\" into the Start menu and then hit CTRL+SHIFT+ENTER to launch the command prompt in Admin mode).\n1. Use the NPM binary installed with Node to download the most recent version of Appium:\n ```bash\n npm install -g appium\n ```\n1. Run Appium (ensuring I'm still in the Admin console!) to make sure it works.\n ```bash\n appium\n ```\n\n(NB: You'll always want to run Appium from an Admin console.)\n\nFor now, we can just kill the Appium server until we're ready to actually run a test.\n\n### Android Setup\n\n1. Download and install [Android Studio](https://developer.android.com/studio/). You can safely follow all the defaults during the installation.\n1. Once Android Studio is launched, click the \"Configure\" menu option in the launch window, where you'll see two important items: \"AVD Manager\" and \"SDK Manager\". First, click SDK Manager.
\"Android\n1. Once the SDK Manager is open, ensure that at least one Android SDK is installed. On this view, take note of the \"Android SDK Location\", since we'll need this location in a bit.\n1. Close the SDK Manager and open the AVD Manager. The AVD Manager is where we will create and launch Android Virtual Devices, otherwise known as emulators. When it launches, assuming you have no other devices already, you can click \"Create Device\" to begin the emulator creation wizard. The first screen you're presented with looks something like this:
\"Choose
Here you can choose any device configuration preset. It doesn't really matter what you choose at this point, so pick something fun!\n1. Next, work through the various other prompts. You can safely pick default values unless you happen to know you have other needs. When prompted for the system version of the emulator, you'll need to pick a system image that you have downloaded. If one is not already downloaded, click the \"Download\" link beside it to make it available for the emulator.
\"Choose
You can name the emulator whatever you want.\n1. Once it's done being created, click the green play button looking icon to launch it! You'll see what looks like an Android device being booted. Let it boot fully and play with it a bit to make sure it works as expected.\n1. The last thing we need to do is make sure the location of the Android SDK is made available to Appium. We do this by creating another environment variable (like we did for `JAVA_HOME` above). This one should be called `ANDROID_HOME`, and it should be set to the location of the Android SDK you saw in the SDK Manager window.\n1. A technically optional but very useful final step is to add part of the Android SDK path to your system PATH, so that certain commands (like `adb`) are available from a command prompt. To do this, go to the same place you did to edit the environment variables, but look for an existing variable called PATH. You can edit it, and tack this special string onto the end: `;%ANDROID_HOME%\\platform-tools`. What is this doing? First of all, the semicolon separates this path segment from other ones that came before. `%ANDROID_HOME%` references the environment variable we previously set, and includes it as part of a path to a particular directory, where the program `adb.exe` resides.\n1. Save out of all dialogs and open up another command prompt. Type `adb devices` and hit enter. If all configuration is correct, you will see some output from ADB telling you that you have one connected device, which is the emulator you booted up a moment ago.\n1. One last useful tip is to add yet another directory to the path, this time `%ANDROID_HOME%\\emulator`, which gives you access to the `emulator` binary from the command line, in case you don't want to open Android Studio just to run your emulator. (If you do add this, make sure not to forget the `;` as a separator between paths).\n\n### Conclusion\n\nLet's review what we've done: we've installed basic system dependencies, the Appium server itself, and everything related to working with Android specifically. That means we're finished!\n\nAll that remains is to start the Appium server (just run `appium` from an admin command prompt), load up an Appium test in your editor of choice, tweak anything that needs to be tweaked for your system, and then kick off the test. If all goes well, you should see the Appium server spitting out logs and launching your app on the Android emulator!\n","metadata":{"lang":"All Languages","platform":"Windows","subPlatform":"Android Devices","title":"Getting Started With Appium For Android On Windows","shortDesc":"This is a complete, step-by-step guide to installing and configuring Appium and its dependencies on Windows 10, for the purpose of Android mobile app automation.","liveAt":"2019-10-16 10:00","canonicalRef":"https://www.headspin.io/blog/getting-started-with-appium-for-android-on-windows"},"mtime":"2023-04-28T16:49:48Z","permalink":"https://appiumpro.com/editions/91-getting-started-with-appium-for-android-on-windows","slug":"91-getting-started-with-appium-for-android-on-windows","path":"/editions/91-getting-started-with-appium-for-android-on-windows","news":{"rawMd":"In a few weeks I'll be giving a webinar on some Appium test development tools I've found useful. [Sign up](https://info.headspin.io/webinar/appium-tools-for-rapid-development-functional-and-performance-test) for reminders and please join me on November 5th.\n\nAlso, did you know that Appium Pro is rolling out a [job board](https://appiumpro.com/editions/jobs), to help all you Appium pros out there find your next gig? Check it out---and if you're a hiring manager or in recruiting, and want to post a job, hit reply and let me know!\n","num":91,"mdPath":"/vercel/path0/content/news/0091.md"},"tags":["All Languages","Windows","Android Devices"]},{"mdPath":"/vercel/path0/content/editions/0089.md","num":89,"rawMd":"\n\nAppium is not just one \"thing\". It can automate multiple platforms, from iOS to Android and beyond. The way that Appium organizes itself around this multi-platform model is by means of various \"drivers\". This is more or less the same architecture as was first adopted by Selenium/WebDriver, which also utilizes a number of independent \"drivers\" in order to support the automation of multiple browsers.\n\nThere is one Appium driver per underlying automation technology. This almost means one Appium driver per platform (one for iOS, one for Android, etc...), but not quite. This is because some platforms (like Android) have multiple automation technologies which Appium targets to support automation of that platform. Android actually has 3 Appium drivers: one based on UiAutomator, one based on UiAutomator 2, and one based on Espresso.\n\n### How Drivers Work\n\nThe driver is arguably the most important concept in all of Appium. It's ultimately the driver's responsibility to turn the Appium API (known as the WebDriver Protocol) into automation for a particular platform. Drivers are essentially translators that turn Appium client commands into ... something else---whatever gets the job done on the platform!\n\nFor architectural simplicity among other reasons, each individual driver is itself a standalone WebDriver-compatible server (though it doesn't have all the options the main Appium server does).Within the driver, commands that are received are handled in idiosyncratic ways. They might be passed on to a separate process running as a Java program on an Android device, for example.\n\nDrivers themselves can have quite a complex internal architecture, sometimes relying on a whole stack of technologies. Here's a diagram showing the full stack of technologies involved in the XCUITest driver (the current iOS driver):\n\n

\n \"The\n

\n\nThere's quite a lot going on! The XCUITest driver is made available as part of Appium, and is brought to life whenever someone starts an iOS session. Internally, it spins up another bit of technology known as WebDriverAgent, which is responsible for turning WebDriver protocol commands into XCUITest library calls.\n\nMany drivers have an architecture like this, though each driver can set up its architecture however it likes, so long as, at the end of the day, it is published as an NPM package that exposes a class which extends Appium's `BaseDriver` class. This is what makes it possible for a driver to plug easily into Appium!\n\n### The Drivers\n\nWell, what drivers _are_ there? It's honestly a bit hard to say exactly, because there exist \"unofficial\" drivers in addition to the ones that ship with Appium. But if we take a look at the current list in the Appium codebase itself, we can see a fair few:\n\n```js\nconst AUTOMATION_NAMES = {\n APPIUM: 'Appium',\n UIAUTOMATOR2: 'UiAutomator2',\n UIAUTOMATOR1: 'UiAutomator1',\n XCUITEST: 'XCUITest',\n YOUIENGINE: 'YouiEngine',\n ESPRESSO: 'Espresso',\n TIZEN: 'Tizen',\n FAKE: 'Fake',\n INSTRUMENTS: 'Instruments',\n WINDOWS: 'Windows',\n MAC: 'Mac',\n};\n```\n\nThese \"automation names\" are the labels given to the various drivers which Appium knows about. This bit of code defines which strings are allowed to be used as values for the `automationName` capability. Of course, each driver typically only supports one platform. Here's a brief description of each of the drivers, by their `automationName`:\n\n* `Appium`: this automation name really means \"just give me the default driver for the platform I've chosen.\" It's not actually a separate driver on its own.\n* `UiAutomator2` ([repo](https://github.com/appium/appium-uiautomator2-driver)): this is the current default Android driver, based on Google's UiAutomator technology.\n* `UiAutomator1` ([repo](https://github.com/appium/appium-android-driver)): this is the older Android driver, based on an older version of UiAutomator.\n* `XCUITest` ([repo](https://github.com/appium/appium-xcuitest-driver)): this is the current iOS driver, based on Apple's XCUITest technology.\n* `YouiEngine` ([repo](https://github.com/YOU-i-Labs/appium-youiengine-driver)): this is a driver produced by You.i Labs, to support automation of apps on many different platforms built using their SDK.\n* `Espresso` ([repo](https://github.com/appium/appium-espresso-driver)): this is the newest Android driver, based on Google's Espresso technology.\n* `Tizen` ([repo](https://github.com/Samsung/appium-tizen-driver)): this is a driver produced by Samsung to assist in automation of Xamarin apps built for the Tizen OS.\n* `Fake`: the \"fake\" driver is used internally by Appium for the purpose of testing, and you shouldn't need to ever use it!\n* `Instruments` ([repo](https://github.com/appium/appium-ios-driver)): this is an older iOS driver based on an Apple technology which was removed after iOS 9. Basically, don't use this!\n* `Windows` ([repo](https://github.com/appium/appium-windows-driver)): Microsoft put together an Appium-compatible server called [WinAppDriver](https://github.com/microsoft/WinAppDriver), and this is the driver that connects it up with the main Appium server. You can use this driver to automate Windows apps!\n* `Mac` ([repo](https://github.com/appium/appium-mac-driver)): this is a driver which enables automation of Mac desktop apps.\n\nAs mentioned above, each of these drivers has its own internal architecture, as you can see in this detailed diagram:\n\n

\n \"All\n

\n\n### Drivers FAQ\n\n*How do I know which driver to use?* Well, if you want to automate iOS, Windows, Mac, or Tizen, your choice is simple: use the only driver which currently enables automation of that platform! If you want to use Android, you have the choice of the UiAutomator2 driver or the Espresso driver. It's worth learning a bit about each of these technologies to see which one might better support your use case. The feature set for these drivers is similar but not identical.\n\n*Do all the drivers support the same commands in the same way?* Yes and no. At a certain fundamental level, we are limited by the automation capabilities provided by the platform vendors. A \"tap\" on an Android device is the same as the \"tap\" on an iOS device. But other commands might not work in exactly the same way. As far as possible the Appium team tries to ensure parity of behavior across platforms and drivers.\n\n*Can I switch from one driver to another and expect my tests to pass?* Yes and no. It all depends on which drivers we're talking about. Part of the benefit of using Appium is that you _can_ change from one automation technology (like UiAutomator2) to another (like Espresso) without throwing away your entire test suite. But you should perform the migration slowly and methodically, making sure that everything is happening as you expect. The Appium team sometimes publishes migration guides for moving from one driver to another; check those out if possible!\n\n*Can I make my own driver?* Yes! Lots of people have done this, most recently both [Jason Huggins](https://github.com/hugs/appium-arduino-driver) and [myself](https://github.com/jlipps/appium-raspi-driver) (at AppiumConf 2019). But there are others too, like Christian Bromann's [hbbtv-driver](https://github.com/christian-bromann/appium-hbbtv-driver).\n\n*Will anything change with drivers in Appium 2.0?* I'm so glad you asked! One unwieldy bit of Appium's driver system is that we have to include drivers as strict dependencies of the Appium server. But we want the drivers to exist in more of a loosely-related ecosystem, where you can pick and choose which drivers you want to use with Appium. This means that you won't need to install the old UiAutomator2 driver and its dependencies if all you are using Appium for is running iOS tests! (Did you know there is a [proposal for Appium 2.0's design](https://gist.github.com/jlipps/651b62316603400cabc95ff0f9faf70f) out there on the Internet?)\n","metadata":{"lang":"All Languages","platform":"All Platforms","subPlatform":"All Devices","title":"Understanding Appium Drivers (And How To Choose Which One To Use)","shortDesc":"Appium supports a whole host of platforms by means of a large array of 'drivers', each of which is responsible for translating Appium's own protocol to automation behaviors on a particular platform, using a particular automation technology. Learn all about this system, and how to choose the right driver for your testing.","liveAt":"2019-10-02 10:00","canonicalRef":"https://www.headspin.io/blog/understanding-appium-drivers-and-how-to-choose-which-one-to-use"},"mtime":"2023-04-28T16:49:48Z","permalink":"https://appiumpro.com/editions/89-understanding-appium-drivers-and-how-to-choose-which-one-to-use","slug":"89-understanding-appium-drivers-and-how-to-choose-which-one-to-use","path":"/editions/89-understanding-appium-drivers-and-how-to-choose-which-one-to-use","news":null,"tags":["All Languages","All Platforms","All Devices"]},{"mdPath":"/vercel/path0/content/editions/0087.md","num":87,"rawMd":"\n\nAndroid 10, by and large, works the same way with Appium as any previous version. There is one important change to be aware of from an automation perspective, however. If the app you're testing has a target SDK version of less than 23 (Android 6.0), then when you launch it on Android 10, you might see a fancy new permissions interstitial before your app launches. Something like this:\n\n

\n \"Permissions\n

\n\nPresumably this is because of Android 10's new, more fine-grained app permissions model. Because these older apps haven't been coded with an eye to the new permissions model, Android needs to pop up this annoying interstitial in order to make sure everything's cool, permissions-wise. This is a slight annoyance for users, with a great gain in terms of privacy. However, it can be devastating for automation if your code isn't expecting it. You have three options for what to do about this.\n\n### Option 1: Automate the Permissions View\n\nThe first option is the big hammer: you could just use Appium to automate this dialog by tapping the \"Continue\" button. But this means you have to throw a conditional in your test code for Android 10, and potentially waste a bunch of timing waiting for a \"Continue\" button that doesn't exist on versions of Android less than 10. So I don't recommend it.\n\n### Option 2: Update your app's targetSdkVersion\n\nEvery Android app can specify 3 different Android SDK versions. Somewhat confusingly, they are:\n\n* `minSdkVersion`: This is the minimum version of Android your app will launch on.\n* `compileSdkVersion`: This is the version of Android that your app will be built with, which determines which APIs your code has access to as you are compiling it. It also determines which compilation errors and warnings will be logged.\n* `targetSdkVersion`: This is kind of a weird one. By targeting a certain SDK, you are telling Android which SDK you have tested, so Android is free to apply system-wide behavior changes to your app. For example, imagine that your app has a `targetSdkVersion` of 21---in that case, the Android OS might decide that your app doesn't support Dark Mode, even though Dark Mode is available more generally on the device which is running your app. Essentially, it clues Android in to which system behaviors your app is designed to support.\n\nIf you have access to your app's source code, or can convince your developers to do this, you could always update your app's `targetSdkVersion` to 29 (the SDK version of Android 10), and this will do away with the interstitial. Though of course you'll need to participate in the new permissions system, and that might require some code updates throughout the app.\n\n### Option 3: Use `autoGrantPermissions`\n\nThe final, and in my opinion most straightforward, option is to use the `autoGrantPermissions` capability. If you include this capability and set it to `true`, Appium will attempt to automatically grant your app all permissions from the system perspective, so that when it comes time to launch your app, Android already thinks that all permissions have been requested and accepted.\n\nUsing this capability is nice because you might need it already (as a way to do away with dialogs popping up throughout the execution of your test), but also because you don't need to update the app in order to use it. Of course, you should still bug your developers to update the target SDK version for your app so that it stays current!\n\nAppium 1.15 is the most current release that supports Android 10, so make sure you download it whenever you need to automate apps on this Android platform. As of the time of writing, Appium 1.15 is currently in the Release Candidate stage, and should be generally available soon!\n","metadata":{"lang":"All Languages","platform":"Android","subPlatform":"All Devices","title":"Working With Android 10","shortDesc":"Android 10 comes with a few changes to the permissions model that might cause issues for app automation, especially of older apps. In this article we take a look at how to work around these changes and keep the automation rolling.","liveAt":"2019-09-18 10:00","canonicalRef":"https://www.headspin.io/blog/working-with-android-10"},"mtime":"2023-04-28T16:49:48Z","permalink":"https://appiumpro.com/editions/87-working-with-android-10","slug":"87-working-with-android-10","path":"/editions/87-working-with-android-10","news":null,"tags":["All Languages","Android","All Devices"]},{"mdPath":"/vercel/path0/content/editions/0086.md","num":86,"rawMd":"\n\nThis edition of Appium Pro is in many ways the sequel to the earlier article on [how to batch Appium commands together using Execute Driver Script](https://appiumpro.com/editions/85). In that article, we saw one way of getting around network latency, by combining many Appium commands into one network request to the Appium server.\n\nWhen using a cloud service, however, there might be other network-related issues to worry about. Many cloud services adopt the standard Webdriver/Appium client/server model for running Appium tests. But because they host hundreds or thousands of devices, they'll be running a very high number of Appium servers. To reduce complexity for their users, they often provide a single entry point for starting sessions. The users' requests all come to this single entry point, and they are proxied on to the appropriate Appium server based on the user's authentication details and the session ID. In these scenarios, the single entry point acts as a kind of Appium load balancer, as in the diagram below:\n\n

\n \"Cloud\n

\n\nThis model is great for making it easy for users to connect to the service. But it's not necessarily so great from a test performance perspective, because it puts an additional HTTP request/response in between your test client and the Appium server which is ultimately handling your client's commands. How big of a deal this is depends on the physical arrangement of the cloud service. Some clouds keep their load balancers and devices all together within one physical datacenter. In that case, the extra HTTP call is not expensive, because it's local to a datacenter. Other cloud providers emphasize geographical and network distribution, with real devices on real networks scattered all over the world. That latter scenario implies Appium servers _also_ scattered around the world (since Appium servers must be running on hosts physically connected to devices). So, if you want both the convenience of a single Appium endpoint for your test script plus the benefit of a highly distributed device cloud, you'll be paying for it with a bunch of extra latency.\n\nWell, the Appium team really doesn't like unnecessary latency, so we thought of a way to fix this little problem, in the form of what we call _direct connect_ capabilities. Whenever an Appium server finishes starting up a session, it sends a response back to your Appium client, with a JSON object containing the capabilities the server provides (usually it's just a copy of whatever capabilities you sent in with your session request). If a cloud service implements direct connect, it will add four new capabilities to that list:\n\n* `directConnectProtocol`\n* `directConnectHost`\n* `directConnectPort`\n* `directConnectPath`\n\nThese capabilities will encode the location and access information for a _non-intermediary_ Appium server--the one actually handling your test. Now, your client had connected to the Appium load balancer, so it doesn't know anything about the host and port of the non-intermediary Appium server. But these capabilities give your client that information, and if your client also supports direct connect, it will parse these capabilities automatically, and ensure that each subsequent command gets sent not to the load balancer but directly to the Appium server which is handling your session. At this point in time, the official Appium Ruby and Python libraries support direct connect, as well as WebdriverIO--support for other clients coming soon.\n\nIt's essentially what's depicted in the diagram below, where for every command after the session initialization, HTTP requests are made directly to the final Appium server, not to the load balancer:\n\n

\n \"Cloud\n

\n\nThe most beautiful thing about this whole feature is that you don't even need to know about direct connect for it to work! It's a passive client feature that will work as long as the Appium cloud service you use has implemented it on their end as well. And, because it's a new feature all around, you _may_ have to turn on a flag in your client to signal that you want to use this feature if available. (For example, in WebdriverIO, you'll need to add the `enableDirectConnect` option to your WebdriverIO config file or object.) But beyond this, it's all automatic!\n\nThe only other thing you might need to worry about is your corporate firewall--if your security team has allowed connections explicitly to the load balancer through the firewall, but not to other hosts, then you may run into issues with commands being blocked by your firewall. In that case, either have your security team update the firewall rules, or turn off direct connect so your commands don't fail.\n\n## Direct Connect In Action\n\nTo figure out the actual, practical benefit of direct connect, I again engaged in some experimentation using [HeadSpin](https://ui.headspin.io/register?referral=start-testing-appiumpro)'s device cloud (HeadSpin helped with implementing direct connect, and their cloud currently supports it).\n\nHere's what I found when, from my office in Vancouver, I ran a bunch of tests, with a bunch of commands, with and without direct connect, on devices sitting in California and Japan (in all cases, the load balancer was also located in California):\n\n|Devices|Using Direct Connect?|Avg Test Time|Avg Command Time|Avg Speedup|\n|------|---------------------|-------------|----------------|-----------|\n|Cali|No|72.53s|0.81s||\n|Cali|Yes|71.62|0.80s|1.2%|\n|Japan|No|102.03s|1.13s||\n|Japan|Yes|70.83s|0.79s|30.6%|\n\n### Analysis\n\nWhat we see here is that, for tests I ran on devices in California, direct connect added only marginal benefit. It _did_ add a marginal benefit with no downside, so it's still a nice little bump, but because Vancouver and California are pretty close, and because the load balancer was geographically quite close to the remote devices, we're not gaining very much.\n\nLooking at the effects when the devices (and therefore Appium server) are located much further away, we see that direct connect provides a very significant speedup of about 30%. This is because, without direct connect, each command must travel from Vancouver to California and then on to Japan. With direct connect, we not only cut out the middleman in California, but we also avoid constructing another whole HTTP request along the way.\n\n### Test Methodology\n\n(The way I ran these tests was essentially the same as the way I ran tests for [the article on Execute Driver Script](https://appiumpro.com/editions/85))\n\n* These tests were run on real Android devices hosted by HeadSpin around the world on real networks, in Mountain View, CA and Tokyo, Japan.\n* For each test condition (location and use of direct connect), 15 distinct tests were run.\n* Each test consisted of a login and logout flow repeated 5 times.\n* The total number of Appium commands, not counting session start and quit, was 90 per test, meaning 1,350 overall for each test condition.\n* The numbers in the table discard session start and quit time, counting only in-session test time (this means of course that if your tests consist primarily of session start time and contain very few commands, then you will get a proportionally small benefit from optimizing using this new feature).\n\n## Conclusion\n\nYou may not find yourself in a position where you need to use direct connect, but if you're a regular user of an Appium cloud provider, make sure to check in with them to ask whether they support the feature and whether your test situation might benefit from the use of it. Because the feature needs to be implemented in the load balancer itself, it's not something that you can take advantage of by using open source Appium directly (although, it would be great if someone built support for direct connect as a Selenium Grid plugin!) Still, as use of devices located around the world becomes more common, I'm happy that we have at least a partial solution for eliminating any unnecessary latency.\n","metadata":{"lang":"All Languages","platform":"All Platforms","subPlatform":"All Devices","title":"Connecting Directly to Appium Hosts in Distributed Environments","shortDesc":"When using Appium with cloud services, we can sometimes be victims of too many network hops and proxies. However, if the cloud service supports the `directConnect` response capabilities, it can make our lives a lot easier.","liveAt":"2019-09-11 10:00","canonicalRef":"https://www.headspin.io/blog/connecting-directly-to-appium-hosts-in-distributed-environments"},"mtime":"2023-04-28T16:49:48Z","permalink":"https://appiumpro.com/editions/86-connecting-directly-to-appium-hosts-in-distributed-environments","slug":"86-connecting-directly-to-appium-hosts-in-distributed-environments","path":"/editions/86-connecting-directly-to-appium-hosts-in-distributed-environments","news":{"rawMd":"I'll actually be speaking about the topic of this newsletter as well as a few other topics TODAY on this [webinar](https://info.headspin.io/webinar/speeding-up-your-remote-appium-sessions). It's happening in just a few hours so please join me by [signing up here](https://info.headspin.io/webinar/speeding-up-your-remote-appium-sessions)!\n\nAs mentioned last week, Cloud Grey is exploring taking its world-class Appium training on the road to a city near you! Are you interested in attending one of our excellent 2-day workshops? Help us figure out where to start by [filling out this survey](https://cloudgrey.typeform.com/to/sItabH), which will close soon. Thanks in advance!\n","num":86,"mdPath":"/vercel/path0/content/news/0086.md"},"tags":["All Languages","All Platforms","All Devices"]},{"mdPath":"/vercel/path0/content/editions/0076.md","num":76,"rawMd":"\n\n> This article is based on a [webinar](https://register.gotowebinar.com/recording/4229598430933236231) that was hosted by [HeadSpin](https://ui.headspin.io/register?referral=start-testing-appiumpro) in June 2019. Be sure to check out the recording as well!\n\n

\n \"React\n

\n\n## Intro to React Native\n\n[React Native](https://facebook.github.io/react-native/) is a response to the age-old problem of how to get an agreeable cross-platform mobile app developer experience while not sacrificing _user_ experience or perceived performance. Developers love building apps with a single set of tools and methodologies, and this of course means _web_ development tools and methodologies, since the web is the canonical universal platform. Unfortunately, building native apps on different mobile platforms (Android and iOS) often involves using a host of _different_ tools and methodologies, based on whatever Google or Apple dictate to their developer communities.\n\nChoosing to build a hybrid app was always a way out of the double-platform problem, but hybrid apps came with lots of perceived UX issues. This is where React Native shines: rather than writing web-like code which actually runs in a webview, you use React Native to write web-like code which is interpreted on the fly inside of a _native_ mobile app, which creates _native_ UI components and response, and which responds to _native_ UI events. The end-user experience is (at least in principle) exactly the same as any native mobile app built with the first-party platform SDKs, but the developer experience is that of a web developer, writing in React-flavoured JavaScript, and using JSX along with a CSS equivalent for structure and styling.\n\nHow does React Native accomplish this best of both worlds feat? Between the app code and the user experience it interposes several unique modules, as depicted in the following diagram:\n\n

\n \"React\n

\n\nBasically, when a React Native app is launched, regular old native app code is run. You don't write this code---it's maintained as part of the React Native project. In addition to these native (per-platform) modules, React Native apps come bundled with a JavaScript engine called [JavaScript Core](https://github.com/WebKit/webkit/tree/master/Source/JavaScriptCore). The code you write is executed by this JS engine, and any time this results in a UI update, a message is passed to the native modules via a special message bus called the React Native Bridge. Once the native modules again have control, they are free to update the UI, create native UI components, or listen for user input, just as any native app would.\n\nThis multi-part architecture certainly adds internal complexity to the app, but its complexity which is hidden away by the architecture. A React Native app developer can usually ignore it, and just live in the world of React.js, all the while building apps which produce native user experiences. Well, mostly. At the end of the day, these apps still need to be compiled as iOS `.ipa` files or Android `.apk` files. They still need to have the appropriate app manifests and resources in the appropriate places. So there is some amount of platform-specific wrangling that still needs to be done, even with React Native. How much exactly depends on your specific app, and how differently-designed you _want_ your apps to be. But in general, a more accurate picture of the architecture, including your responsibilities, is as pictured here:\n\n

\n \"React\n

\n\nBased on my experience maintaining a React Native app ([The App](https://github.com/cloudgrey-io/the-app), which is used for almost all of Appium Pro's examples), these are the pros and cons of using React Native for mobile app development:\n\n|Pros|Cons|\n|----|----|\n|Mostly single codebase|A lot of \"mosts\"—need some iOS/Android experience|\n|Mostly no need to learn iOS or Android app dev|Reliant on RN team for SDK compatibility updates|\n|Good debugging toolkit for rapid development|Difficult to write truly platform-specific UX|\n|Mostly native app speed / UX|Reliant on project owned by FB (though now under MIT license)|\n|Extensible—write your own native modules| |\n\n## Testing React Native Apps\n\nAs with any kind of app, there are different levels of testing to consider, from unit testing up to end-to-end or UI testing. The most popular option for unit testing React Native apps is [Jest](https://jestjs.io/docs/en/tutorial-react-native.html), produced by Facebook (same as React Native). This kind of testing doesn't involve UI components at all. Jest can be combined with another library (like [react-native-testing-library](https://github.com/callstack/react-native-testing-library)), to get a little more fancy and test at the component level (though again, this is not testing involving native UI components, only virtual components).\n\nWhen it comes to UI testing, Appium is a great option for testing React Native apps. React Native apps just _are_ native apps, therefore they're testable out of the box with Appium. React Native components even respond to a [`testID`](https://facebook.github.io/react-native/docs/view#testid) attribute that allows developers to attach test-friendly labels to components. However, there are a few things to consider when developing React Native apps to make sure that they are _fully_ testable with Appium. In the Appium Desktop screenshot below, for example, you will notice a pretty substantial problem with this React Native app:\n\n

\n \"No\n

\n\nThe problem is that, even though I can clearly see many elements with lots of unique text labels and so on, all I can find in the XML hierarchy is a single `android.widget.FrameLayout`! The reason for this is that Appium's element finding algorithms operate on the UI Accessibility layer, and the designer of this React Native app has designated certain elements as important for accessibility, thus rendering many _other_ elements _un_-important for accessibility. Oops!\n\nThe solution here is to make sure not just to use the `testID` attribute on important components, but also to set the [`accessibilityLabel`](https://facebook.github.io/react-native/docs/view#accessibilitylabel) attribute, to ensure that the element is always findable via Appium's 'accessibility id' locator strategy. (Actually, this is only a problem on Android, because on Android, React Native puts the `testID` into something called a 'view tag', which is not accessible to Appium at all.\n\nI like to make a convenience function called `testProps` to make this process easy:\n\n```js\nexport function testProps (id) {\n return {testID: id, accessibilityLabel: id};\n}\n```\n\nNow I can just use this function everywhere instead of `testID`:\n\n```jsx\n\n```\n\nAnother tactic for dealing with this issue, if we don't want to add labels and IDs to lots of components, is to make sure that parent components have their `accessible` attribute set to `false`; this allows the accessibility visibility of children to bubble up through a parent, rather than treating the parent component as a monolithic component from the perspective of the accessibility system.\n\nThat's really it! I haven't run into any other significant issues testing React Native apps with Appium. But check out the [webinar](https://register.gotowebinar.com/recording/4229598430933236231) for a more in-depth discussion, and a comparison of Appium with the Detox UI testing framework, which has some special integrations with React Native specifically.\n","metadata":{"lang":"All Languages","platform":"All Platforms","subPlatform":"All Devices","title":"Testing React Native Apps with Appium","shortDesc":"React Native is a popular app development framework that enables native user experiences while maintaining a mostly single platform developer experience. Testing React Native apps with Appium is relatively straightforward, but there are a few tips that might make the difference between a successful and and an unsuccessful Appium testing expedition.","liveAt":"2019-07-03 10:00","canonicalRef":"https://www.headspin.io/blog/testing-react-native-apps-with-appium"},"mtime":"2023-04-28T16:49:48Z","permalink":"https://appiumpro.com/editions/76-testing-react-native-apps-with-appium","slug":"76-testing-react-native-apps-with-appium","path":"/editions/76-testing-react-native-apps-with-appium","news":null,"tags":["All Languages","All Platforms","All Devices"]},{"mdPath":"/vercel/path0/content/editions/0035.md","num":35,"rawMd":"\n\nI've written a couple editions of Appium Pro on the topic of [finding elements reliably](https://appiumpro.com/editions/20), including why you should [consider not using XPath](https://appiumpro.com/editions/8) at all as part of your element-finding strategy. There are two main reasons for not using XPath:\n\n1. XPath queries can be strictly hierarchical in nature, with the result that any change in the structure of your app (even accidental, or OS-caused) means a failure to find an element (or worse, finding the wrong element).\n2. With Appium specifically, using the XPath locator strategy can be expensive and slow, because of the extra work required to convert an app's UI hierarchy to XML, and then to match up found XML nodes with actual UI elements.\n\nThese are really good reasons to avoid XPath if at all possible. Sometimes, however, there is no alternative! (This goes for both Appium and Selenium, by the way: everything I'm about to say is equally valid for both automation tools.) Sometimes, you've been able to determine that XPath is, in your particular case, not actually expensive or slow (how did you determine this? You tried it!), and so you might prefer XPath to some of the platform-specific locator strategies (iOS Predicate String, or Android UISelector) in order to help your test code be more cross-platform.\n\nEither way, what's important is that you write _good_ XPath queries. In essence, these are queries which are _anchored by elements uniquely identified by unchanging criteria_. Let's first take a look at some examples of queries which fail to meet this description:\n\n* `//*` (this is the worst possible query. It selects every single element!)\n* `//android.widget.Layout/android.widget.Layout[3]/android.widget.Layout/android.widget.TextView[2]` (this query relies too much on hierarchical structure. If an extra layout is added to the hierarchy, or anything is shuffled around, it is likely to break. In addition, the query is not cross-platform).\n\nHow can we make better queries? The first is to remember that XPath offers the use of _predicates_, which allow the restriction of matched nodes based on special criteria. For example, we can find any element which has a certain attribute (say a `text` attribute):\n\n* `//*[@text=\"foo\"]`\n\n(How did we know that the `text` attribute was a thing? We looked at the XML source of the app of course! Maybe by using [Appium Desktop](https://github.com/appium/appium-desktop).) We can also use XPath _functions_ for predicates involving functions other than equality:\n\n* `//*[contains(@text, \"f\")]` (find any element which contains the letter \"f\").\n\nIn practice, the same attributes are not in use within XML sources produced for iOS and Android, so using predicates is often not a cross-platform approach. It can become cross-platform, however, when you remember that XPath also allows _boolean operations_!\n\n* `//*[@text=\"foo\" or @label=\"foo\"]` (find any element whose `text` (Android) or `label` (iOS) attribute is \"foo\").\n\nNotice that I haven't really been referring to the specific type of node in these searches, and instead I have been using the wildcard matcher (`*`). Doesn't this severely hurt performance since the XPath engine has to search so many more nodes? Not really. XPath searches are pretty fast, unless you have a truly gigantic hierarchy, and that doesn't happen too often. (Of course you can always optimize for a given platform by including the type of element you are expecting). For Appium, the truly expensive part of using XPath is in generating the XML, and matching found XPath nodes to native UI elements---not in the XPath search itself.\n\nFor our last consideration, consider an example where there is really no uniquely identifying information on a particular element. We might have a list view with many different elements inside, of an indeterminate ordering, many of which have duplicate text. We're interested in just one of these elements based on external criteria (maybe the text of an ancestor element). Fear not! We can stay in the mostly safe zone of XPath by ensuring that we use an anchor element which _does_ have some unique attribute:\n\n* `//*[@content-desc=\"foo\" or @name=\"foo\"]//*[@content-desc=\"bar\" or @name=\"bar\"]` (a cross-platform accessibility label search for elements called `bar` that descend from elements called `foo`).\n\nIn the above case, we considered the `foo` element our \"anchor\" element, and essentially scoped our query inside of it, making it much more robust. It can work the other way as well, using a child element (or a sibling element) as an anchor:\n\n* `//ancestor::*[*[@text=\"foo\"]][@text=\"bar\"]` (find the ancestor of a node with text \"foo\"; the ancestor must also have text \"bar\").\n\nThese XPath queries may be complex or ugly, but they are not particularly bad from the perspective of maintainability, assuming your app structure guarantees a minimum ancestor/descendant relationship between elements. It simply becomes a process of triangulating an unchanging query for your element based on attributes of other elements! All this to say, if you're not an XPath expert already it's worth finding some good tutorials and making sure you understand the possibilities of XPath for writing better queries, before rejecting the strategy out of hand.\n\nThe way XPath is actually used in practice in many functional testsuites should absolutely be avoided. But this avoidance should not be cargo-culted any more than the use of XPath. In many cases the question of speed and performance with respect to XPath must be determined experimentally, in the context of your particular app. Don't assume without checking that it will be too slow to be useful! Hopefully these reflections and examples help to bring a bit of nuance to the \"XPath is bad\" conversation that I often find myself in, as I'm sure you do as well.\n","metadata":{"lang":"All Languages","platform":"All Platforms","subPlatform":"All Devices","title":"Writing XPath Queries That Work","shortDesc":"We hear a lot (from Appium Pro and other places) about how it's not a good idea to use XPath. That's generally correct. There are times, however, when it is totally fine to use XPath, or when XPath is the only option. In this edition we take a look at how to write good XPath queries to minimize the XPath blast radius.","liveAt":"2018-09-19 10:00","canonicalRef":"https://www.headspin.io/blog/writing-xpath-queries-that-work"},"mtime":"2023-04-28T16:49:48Z","permalink":"https://appiumpro.com/editions/35-writing-xpath-queries-that-work","slug":"35-writing-xpath-queries-that-work","path":"/editions/35-writing-xpath-queries-that-work","news":{"rawMd":"I am honored that two recent editions of Appium Pro (32 and 33, on finding elements by image) have been translated to Japanese. While I do not read Japanese myself, it appears that Naruhiko Ogasawara has done an amazing job in porting these over, and publishing them on the Selenium Japan site:\n\n* [Appium Pro #32 in Japanese](http://www.selenium.jp/translation/huaxiangniyoruyaosujiansuopart1)\n* [Appium Pro #33 in Japanese](http://www.selenium.jp/translation/appiumhuaxiangniyoruyaosujiansuopart2)\n\nThanks, Naruhiko!\n","num":35,"mdPath":"/vercel/path0/content/news/0035.md"},"tags":["All Languages","All Platforms","All Devices"]},{"mdPath":"/vercel/path0/content/editions/0027.md","num":27,"rawMd":"\n\n> This article is the ninth in a multi-part series on test speed and reliability, inspired by a webinar I gave on the same subject (you can [watch the webinar here](https://www.youtube.com/watch?v=Sx-jscrsSRM&list=PLFoVxiw64PraVz_N33Z4uv-GzMmLm7EBI)). You might also want to check out the previous episodes on [Test Flakiness](https://appiumpro.com/editions/19), [Finding Elements Reliably](https://appiumpro.com/editions/20), [Waiting for App States](https://appiumpro.com/editions/21), [Dealing With Unfindable Elements](https://appiumpro.com/editions/22), [Setting Up App State](https://appiumpro.com/editions/23), [Advanced Capabilities](https://appiumpro.com/editions/24), [Disabling Animations](https://appiumpro.com/editions/25), and [Mocking External Services](https://appiumpro.com/editions/26).\n\nWe come finally to the last episode in this not-so-little series on test speed and stability. This edition is not about specific speed and reliability techniques; instead, it's about what to do when none of the previously-discussed suggestions have been helpful. There are no doubt lots of other useful tips hiding in the wings, and they'll make their appearance here in due time. But even if there's not an obvious solution to a particular problem, it's very useful to be able to pinpoint the problem so that you can look for a reasonable workaround or notify the appropriate authorities (Appium, Apple, Google, etc...).\n\nIn order to pinpoint any kind of problem with an Appium test (whether it's a straight-up error, or undesired slowness or instability), it's necessary to understand something about the complexity of the technology stack that comes into play during test execution. Take a look at this diagram of (most of) the pieces of Appium's XCUITest stack:\n\n

\n \"Appium\n

\n\nYou've got your test code, the Appium client code, the Appium server code, WebDriverAgent, XCUITest itself, and who knows how much proprietary Apple code shoved in between XCUITest and the various bits of iOS. A problem on any one of these layers will eventually manifest itself on the level of test behavior. It's not impossible to figure out what's going on, and there are typically lots of helpful clues lying about, but my point is that a little work is required to get to a useful answer about your problem. So, here is what I recommend doing to diagnose issues, in roughly this order:\n\n#### Test Code Exceptions\n\nThe first investigation should always be into your own test code. Oftentimes an exception arises that has nothing to do with Appium whatsoever, and is a simple programming error in your test code itself. Always read your test code exceptions in detail! Since your test code imports the Appium client in your language, this is also where you will get the first indication of any other errors. Whenever possible, Appium puts useful information in the error messages it returns to the client, and these messages should end up in your IDE or console.\n\nIn the case of exceptions generated by the Appium client, the exception will often belong to a certain class (`NoSuchElementException`, for example), which will give you a clue as to what has gone wrong. In the case of a generic exception, look for the message itself to see if the Appium server has conveyed anything about what could be wrong. Often, system configuration errors will be noticed by the Appium server and expressed in this manner, and a quick look at the message may even give you specific instructions as to how to fix the issue.\n\n#### Appium Logs\n\nThe Appium server writes a _ton_ of messages to the console (or to a file if that's how you've set it up). In the case of normal test execution, this information is mostly superfluous. It tells you all about what Appium is doing, and gives you a very detailed picture of the flow of HTTP requests/responses, commands Appium is running under the hood, and much more. Check out the [Appium Pro article on how to read the Appium logs](https://appiumpro.com/editions/10) (by Appium maintainer Isaac Murchie) for a more detailed introduction to the logs. Here are some of the things I usually look at as a first quick pass of the logs:\n\n1. The session start loglines, to double-check that all the capabilities were sent in as I expected.\n2. The very end of the log, to see the last things Appium did (especially in the case of an Appium crash).\n3. Any stacktraces Appium has written to the logs (since these will often have information directly related to an error).\n4. Any log lines rated \"warn\" or \"error\".\n\nIf nothing pops out after following those steps, I read through the logs in more detail to try and match up my test steps with loglines, and then look for the area in the log matching the problematic area in my test.\n\n#### Log Timestamps\n\nIn the case of slowness issues, it's essential to see how long different commands take. It's possible to determine this on the client side by adding time measurements before and after individual commands. Often, however, this doesn't reveal anything useful. We already know that a certain command is slow---that's why we're having trouble! But using the Appium logs, we can dig deeper and try to isolate the slowness to a particular Appium subroutine, which can be much more useful.\n\nBy default, the Appium log does not show timestamps, in order to keep the log lines short and uncluttered. But if you start the Appium server with `--log-timestamp`, each line will be prepended with a timestamp. You can use these to good effect by isolating the section of the log that matches the problematic area in your test, and start looking for large jumps in time in the log. You might find a single line or a small set of lines which are taking a long time. If it is surprising to find such a lag with those particular lines, you can always reach out to the Appium issue tracker and share your findings with the maintainers to see if there's a potential bug causing the slowness.\n\n#### Device Logs\n\nWhen it comes to problems whose root cause lies with your app, the mobile OS, or vendor-owned frameworks (like XCUITest or UiAutomator2), Appium is typically unable to provide any insight. This doesn't mean we're out of options, however. On both iOS and Android, apps can write to system-level logs, and often the system logs will also capture any exceptions thrown in your app (which might have led to a crash, say).\n\nSo, if the Appium logs don't provide any help in your investigation, the next place to go is to these logs. On Android, you can run `adb logcat` to access this log stream, and on iOS you can simply tail the system log (for iOS simulators) or use a tool like `idevicesyslog` for real devices. In fact, you can also set the `showIOSLog` capability to `true`, and Appium will scrape data from these logs and interleave it with the regular Appium logs, which often helps to put device problems into the context of the Appium session.\n\n#### Use a Different Appium Client\n\nIf you don't notice anything untoward in the Appium server logs, and suspect that the issue might lie with the Appium client you are using, you could always try to rewrite your test script (or the problematic portion of it) using a different client (either in the same language or a different language). If after doing this the problem goes away, you have pretty strong evidence that the problem was with the Appium client.\n\nHappily, the Appium team is often able to fix bugs with the Appium client very quickly (as long as the client is officially maintained by the project). Sometimes, though, a bug might exist in the underlying Selenium WebDriver client library which the Appium client is built on, and then the bug will need to be reported to the Selenium project. The Appium team can assist in that process, too.\n\n#### Use the Underlying Automation Engine Directly\n\nAppium is built on top of other automation technologies, like XCUITest as we saw in the diagram above. In many cases, issues that appear to be related to Appium are actually issues with the underlying automation technology. Before deciding that the Appium code is at fault for errors or slowness and creating a bug in the Appium issue tracker, it can be useful to write up a small testcase using the underlying engine, expressing the same test steps as with your Appium script. If you notice the same kind of problem (slowness, errors, etc...), then it's unlikely Appium will be able to do anything to directly fix the issue, and it should instead be reported to Apple or Google (and great---now you have a perfect minimal repro case for them!)\n\nIt's still useful to ask around the Appium forums in such a case, because there are often workarounds to these kinds of problems. If the workaround is useful enough, we can also build it into Appium as a first-class citizen, making life easier for all Appium users (at least until Apple or Google fixes the original problem).\n\n#### Ask for Help\n\nIf none of the strategies above have resulted in clarity on the problem or a satisfactory resolution, it's time to reach out for help. A good first step is always searching the Appium issue tracker, StackOverflow, or the Internet more generally for any sign of your problem. Maybe someone else has already discussed a workaround for it.\n\nIf that's not the case, it's a good idea to create an issue at the [Appium issue tracker](https://github.com/appium/appium/issues). At this point, if you've followed all the steps above, prepare to be showered with love and praise by the Appium maintainers, who will appreciate the extremely detailed report you will be able to include in your issue.\n\nHopefully the Appium maintainers will be able to provide a resolution, especially if it's determined that your issue reflects an Appium bug. If not, then I suppose you could always put on your crazy hacker hat and start decompiling some XCUITest source code! Yeah---that's no fun. Anyway, hopefully you'll find resolution somewhere else along the way, using the methods we've discussed here.\n\nI hope you've enjoyed this series on test speed and reliability. If in the course of your Appium test writing you come across any other good suggestions, please send them along to me, and I'll be happy to feature them in a future article. Even though the series is over, I'll certainly continue to cover tips to do with speed and reliability moving forward.\n","metadata":{"lang":"All Languages","platform":"All Platforms","subPlatform":"All Devices","title":"Making Your Appium Tests Fast and Reliable, Part 9: When Things Go Wrong","shortDesc":"Rounding out this series on speed and reliability, we consider failure resolution strategies. How do you debug issues? How do you locate a problem in the Appium stack? Where do you report bugs? And so on.","liveAt":"2018-07-25 10:00","canonicalRef":"https://www.headspin.io/blog/making-your-appium-tests-fast-and-reliable-part-9-when-things-go-wrong"},"mtime":"2023-04-28T16:49:48Z","permalink":"https://appiumpro.com/editions/27-making-your-appium-tests-fast-and-reliable-part-9-when-things-go-wrong","slug":"27-making-your-appium-tests-fast-and-reliable-part-9-when-things-go-wrong","path":"/editions/27-making-your-appium-tests-fast-and-reliable-part-9-when-things-go-wrong","news":null,"tags":["All Languages","All Platforms","All Devices"]},{"mdPath":"/vercel/path0/content/editions/0010.md","num":10,"rawMd":"\n\nWhen the Appium server runs there is often a bewildering stream of logs, giving\ninformation about the automation in process, but the details are often obscure.\n\n### Server Startup\nThe first lines of the log announce the version of Appium, and the address it is running on:\n```\n$ appium\n[Appium] Welcome to Appium v1.8.0-beta3 (REV 40e40975ebd3593d08c3f83de2546258f7ddf11d)\n[Appium] Appium REST http interface listener started on 0.0.0.0:4723\n```\nFurther, if you have started the server with any [special flags](http://appium.io/docs/en/writing-running-appium/server-args/),\nincluding [default desired capabilities](http://appium.io/docs/en/writing-running-appium/default-capabilities-arg/)\nthey will also be noted here, to help with understand the environment that is being run:\n```\n$ appium --address 172.19.131.113 --port 8000 --default-capabilities '{\"showIOSLog\": true}'\n[Appium] Welcome to Appium v1.8.0-beta3 (REV 40e40975ebd3593d08c3f83de2546258f7ddf11d)\n[Appium] Non-default server args:\n[Appium] address: 172.19.131.113\n[Appium] port: 8000\n[Appium] defaultCapabilities: {\n[Appium] showIOSLog: true\n[Appium] }\n[Appium] Default capabilities, which will be added to each request unless overridden by desired capabilities:\n[Appium] showIOSLog: true\n[Appium] Appium REST http interface listener started on 172.19.131.113:8000\n```\nThis information is invaluable for providing context to the test automation that will be run. In particular, different\nversions of Appium will have different capacities and issues, so knowing what version is running is necessary\nto begin to make any determination of what is going on in any run.\n\n### Session Creation\nWhile session creation involves a complicated array of operations to get the\nenvironment set up and the application under test running, the beginning of the\nlogs for a command to create the session provides basic information about the\nsession. In particular, the [desired capabilities](http://appium.io/docs/en/writing-running-appium/caps/),\nalong with any [default capabilities](http://appium.io/docs/en/writing-running-appium/default-capabilities-arg/)\nare listed. It is often useful to check that what was intended to be requested was\nactually received by the Appium server, since it is the capabilities listed here\nthat will be acted upon for the automation session.\n```\n[Appium] Creating new XCUITestDriver (v2.68.0) session\n[Appium] Capabilities:\n[Appium] app: /Users/isaac/apps/UICatalog-iphonesimulator.app\n[Appium] platformName: iOS\n[Appium] platformVersion: 11.3\n[Appium] deviceName: iPhone 6\n[Appium] automationName: XCUITest\n[Appium] noReset: true\n[Appium] maxTypingFrequency: 30\n[Appium] clearSystemFiles: true\n[Appium] showXcodeLog: false\n[debug] [BaseDriver]\n[debug] [BaseDriver] Creating session with MJSONWP desired capabilities: {\"app\":\"/Users/isaac/code/a...\n```\n\n### Appium Commands\nAppium is a [REST](https://en.wikipedia.org/wiki/Representational_state_transfer)\nserver, accepting incoming HTTP requests, performing the action requested, and returning a result\nof some sort. In the Appium server logs, each such incoming request is delineated by a line indicating the request, and\na line indicating the response. In between these are the details of the execution of the requested command:\n```\n[HTTP] --> GET /wd/hub/status {}\n[debug] [MJSONWP] Calling AppiumDriver.getStatus() with args: []\n[debug] [MJSONWP] Responding to client with driver.getStatus() result: {\"build\":{\"version\":\"1.8.0-beta3\",\"revision\":\"30e7b45bdc5668124af33c41492aa5195fcdf64d\"}}\n[HTTP] <-- GET /wd/hub/status 200 121 ms - 126\n```\n\n### Investigating Errors\nOn the client side errors are usually helpful, there is usually more information\nto be found in the logs. Usually the errors will be at the end of the automation\nsession, but sometimes the session can continue and the error logs will be earlier.\nSo the first step is to identify the command where the error happened. As we have\nalready seen, each command is marked by `[HTTP] -->` and `[HTTP] <--`. Within these\nmarkers is the details of the execution of the command, including any error output.\n\nLet's take a look at a concrete example:\n\n```\n[HTTP] --> POST /wd/hub/session\n\n[debug] [AndroidDriver] Shutting down Android driver\n[debug] [AndroidDriver] Called deleteSession but bootstrap wasn't active\n[debug] [Logcat] Stopping logcat capture\n[debug] [ADB] Getting connected devices...\n[debug] [ADB] 1 device(s) connected\n[debug] [ADB] Running '/home/user/Android/Sdk/platform-tools//adb' with args: [\"-P\",5037,\"-s\",\"ec8c4df\",\"shell\",\"am\",\"force-stop\",\"io.appium.unlock\"]\n[debug] [AndroidDriver] Not cleaning generated files. Add `clearSystemFiles` capability if wanted.\n[MJSONWP] Encountered internal error running command: Error: Cannot stop and clear com.company.app. Original error: Error executing adbExec. Original error: 'Command '/home/user/Android/Sdk/platform-tools//adb -P 5037 -s ec8c4df shell pm clear com.company.app' exited with code 1'; Stderr: 'Error: java.lang.SecurityException: PID 22126 does not have permission android.permission.CLEAR_APP_USER_DATA to clear data of package com.company.app'; Code: '1'\n at Object.wrappedLogger.errorAndThrow (../../lib/logging.js:63:13)\n at ADB.callee$0$0$ (../../../lib/tools/adb-commands.js:334:9)\n at tryCatch (/home/linuxbrew/.linuxbrew/lib/node_modules/appium/node_modules/babel-runtime/regenerator/runtime.js:67:40)\n at GeneratorFunctionPrototype.invoke [as _invoke] (/home/linuxbrew/.linuxbrew/lib/node_modules/appium/node_modules/babel-runtime/regenerator/runtime.js:315:22)\n at GeneratorFunctionPrototype.prototype.(anonymous function) [as throw] (/home/linuxbrew/.linuxbrew/lib/node_modules/appium/node_modules/babel-runtime/regenerator/runtime.js:100:21)\n at GeneratorFunctionPrototype.invoke (/home/linuxbrew/.linuxbrew/lib/node_modules/appium/node_modules/babel-runtime/regenerator/runtime.js:136:37)\n at \n at process._tickCallback (internal/process/next_tick.js:188:7)\n[HTTP] <-- POST /wd/hub/session 500 40811 ms - 557\n```\n\nIn this abridged set of logs, the user has attempted to start a session using the Android driver, and has been met with an error. In this case it looks like the error happened during Appium's attempt to stop and clear the AUT in preparation for the session. Here the error gives us two important pieces of information:\n\n1. What Appium was trying to do, specifically\n2. What went wrong (in the form of error text and any related codes)\n\nIn this case, Appium was trying to run an `adb` command (`adb shell am force-stop`), with parameters that have been included in the error text. And what happened? It was met with an Android system error about permissions. At this point, we have everything we need to troubleshoot locally. We can run the `adb` command that Appium tried to run, for example, and determine whether we can reproduce the issue outside of Appium. If so, we can then seek recourse through a helpful Android-specific forum, or from other Appium users who might have run into the same problem. If the command can be run successfully from the command line, then it may be we have uncovered a bug in Appium, and it should be reported as a [GitHub issue](https://github.com/appium/appium/issues).\n\n(If you're curious, in this case the user was able to reproduce the problem outside of Appium, so it appeared to be related to the specific device manufacturer's security model).\n\nObviously, this is one of many, many examples that could have been given, but it illustrates the core point that, when faced with an error, the logs can help provide more information that facilitate a local repro attempt, or help the Appium team understand what could be going wrong. No issue should ever be submitted to the Appium issue tracker without a complete set of logs!\n\n### Server Flags for Changing the Logging Output\nWhile the default logging output is often enough, and if you are opening an\n[issue on Github](https://github.com/appium/appium/issues) to get help with a\nproblem, the more information the better, there are [server flags](http://appium.io/docs/en/writing-running-appium/server-args/)\nprovided to change the logging behavior of the Appium server.\n\n* `--log-level` - change the level at which Appium logs information. Appium defaults\n to logging _everything_, which can be a lot. The options for the flag are\n `'info'`, `'info:debug'`, `'info:info'`, `'info:warn'`, `'info:error'`,\n `'warn'`, `'warn:debug'`, `'warn:info'`, `'warn:warn'`, `'warn:error'`,\n `'error'`, `'error:debug'`, `'error:info'`, `'error:warn'`, `'error:error'`,\n `'debug'`, `'debug:debug'`, `'debug:info'`, `'debug:warn'`, `'debug:error'`\n* `--log-no-colors` - If your console does not display colors (this will be manifested\n as logs with odd character sequences like `TODO: find the color`) you can turn\n off colors with this flag\n* `--log-timestamp` - Add a timestamp to the beginning of each log line, which is\n useful in cases where timeouts are occurring. The log lines will look like\n ```\n 2018-03-15 13:17:58:663 - [Appium] Welcome to Appium v1.8.0-beta3 (REV 30e7b45bdc5668124af33c41492aa5195fcdf64d)\n 2018-03-15 13:17:58:664 - [Appium] Non-default server args:\n 2018-03-15 13:17:58:665 - [Appium] logTimestamp: true\n 2018-03-15 13:17:58:732 - [Appium] Appium REST http interface listener started on 0.0.0.0:4723\n ```\n","metadata":{"lang":"All Languages","platform":"All Platforms","subPlatform":"All Devices","title":"Anatomy of Logging in Appium","shortDesc":"Running into problems with Appium can be a frustrating experience. Sometimes you just get a cryptic, unhelpful message as part of an error thrown in your client code. Where do you go next? The Appium logs! This is a guest post from Isaac Murchie on how to take advantage of reading the Appium logs to help understand what's going on and potentially resolve issues.","introMsg":"This is a guest post from Isaac Murchie, Head of Open Source at Sauce labs and longtime Appium maintainer. He'll be presenting at AppiumConf in a few weeks on the topic of how to profitably read your Appium logs to help resolve issues. This is a sneak preview of what he'll be discussing at the conference. Enjoy! --Jonathan","liveAt":"2018-03-21 10:00","canonicalRef":"https://www.headspin.io/blog/anatomy-of-logging-in-appium"},"mtime":"2023-04-28T16:49:48Z","permalink":"https://appiumpro.com/editions/10-anatomy-of-logging-in-appium","slug":"10-anatomy-of-logging-in-appium","path":"/editions/10-anatomy-of-logging-in-appium","news":null,"tags":["All Languages","All Platforms","All Devices"]}],"tag":"All Languages"},"__N_SSG":true}