A Developer's Overview of Appium

Before reading this document, please ensure that you have read and understood the more general introduction to Appium concepts and the more general contribution instructions.

Technical Vision

Appium aims to be a Mobile JSONWP front-end for the best app automation technologies. That's it. We want to take all the different useful automation engines and smooth away their differences and gotchas by making Appium drivers for them and bringing them under the umbrella of Appium itself. This is very similar to the goal of the Selenium project. For our part, we want to have every driver be an independent entity (separate repo, tests, etc...) even as it uses shared libraries that make the development of an Appium driver as simple and boilerplate-free as possible. We use modern JavaScript because JavaScript is everywhere and it's easy for many developers to understand and contribute back to.

Developer Community

Anyone is welcome to become an Appium developer; just read this guide and get some of your code merged, and you are one of us! If you stick around and help a lot, we will also make you a committer so that you can continue to help the community more easily. If you are developing code for Appium and have questions, reach out to the developer community at appium-developers@googlegroups.com. Note that this is a mailing list for development questions, not usage questions or bug reports. Usage questions belong on discuss.appium.io. The GitHub issue tracker is for bug reports and feature requests only.

Agile Development Workflow

The Appium team runs development according to a very lightweight version of SCRUM. Every two weeks we begin a new "sprint", or a period of time in which we have decided what we want to accomplish. Anyone familiar with the Appium codebase is welcome to attend our sprint planning and participate as a SCRUM team member for that sprint. No long-term commitments required! During the sprint, we update each other with daily progress in the #standup room in our Appium Slack Group (there are no real-time daily standups). At the end of the sprint, to celebrate our accomplishments and reflect on how things went, we hold a "retrospective", which might result in a list of things we can try differently or do better next time around.

Ultimately, the goal is to time an Appium release at the end of each sprint, so every two weeks. We're not quite there, but hopefully we will be soon.

Current meeting times: Sprint Planning: every other Monday from 10:00 AM - 10:45 AM (Pacific Time) Sprint Retrospective: every other other Friday from 1:00 PM - 1:30 PM (Pacific Time)

We hold meetings using Zoom video chat.

For project management, we use the ZenHub browser plugin, which adds various features like Kanban boards and Epics to the GitHub interface. To fully participate in Appium SCRUM, you'll need to have this browser plugin installed.

If you are interested in participating a sprint, ping @jlipps or @isaac in the Appium Slack Group, or DM @jlipps on Twitter, and we'll share how to join the video chat for the next sprint.

Architecture

Appium is primarily a collection of node.js packages that combine to form a running node.js server. These packages are maintained independently of one another and each have their own GitHub repo, CI, and release process. Some packages (like appium-ios-driver) are large and add significant functionality to Appium, while others play a support role and expose one specific bit of functionality that is reused by other packages.

For an overview of the package hierarchy and the role that each package plays, please check out our package overview doc.

Transpilation

Appium is written in a new form of JavaScript, called ES6 (or now ES2015). Because this version of the language is not yet supported natively by older versions of node.js, Appium code is transpiled to ES5 (the more widely-supported version of JS). This transpilation process must occur before any code is run. In addition to the new language features of ES6, we have adopted two very important keywords from the subsequent version of JS, namely async and await, which assist in writing asynchronous code cleanly. Because of the transpilation step, Appium packages include tools which watch code for changes and automatically re-transpile the code. Usually, the same tool will automatically run unit tests as well to ensure that nothing small has broken. Most Appium packages have this as the default behavior when running gulp.

Linting and Style

It's important for all of Appium's JS to look and feel the same. This includes style conventions as well as coding patterns and which libraries we use to solve various problems. You should get familiar with our new ES2015 Style Guide. When transpiling, Appium packages will automatically run ESLint or other lint tools and provide warning or error feedback if the code doesn't conform to our style. These tools are not necessarily exhaustive of the kinds of style issues we care about, so we may also mention style issues in our reviews. This isn't to be nit-picky but to have a clean, consistent, and readable codebase!

Submitting Code

Getting your code into Appium is easy: just submit a PR to one of our repos and engage with the maintainers in the review process. We have a number of requirements for code submissions (but don't worry! If the following seems like a lot, we will helpfully and patiently walk you through each step. Just send in your PR and we'll go from there):

If you do all of these things before submission, your code will almost certainly be accepted very quickly! Of course, if you're thinking of making a change to Appium that requires a lot of work, you might reach out to the developers list to make sure that the change is in line with our philosophy and in principle something that we'll accept before you get going.

Testing

Always make sure that your changes are tested! In addition to writing unit and e2e tests, make sure you run existing tests before you begin to make changes and before you push code to be reviewed. We do have CI set up for every Appium repository as a safety net for reviewers to know whether the code they are reviewing has passed muster. Running tests in any Appium package is easy! Unless the README says otherwise, here are the things you can do:

npm run lint            # run eslint on the code
npm run watch           # watch directory to re-transpile on code change, lint, and run unit tests
npm run test            # same as above but don't watch
npm run e2e-test        # transpile and run end-to-end/functional tests
_FORCE_LOGS=1 <command> # show module log output during test run

Note that we have a convention for unit test files to end in -specs.js and for e2e test files to end in -e2e-specs.js.

Updating Appium site docs

The Appium site is built using a site generator that translates the markdown in https://github.com/appium/appium to static HTML

To update the site docs, follow these steps:

  1. From Appium repo, run npm run generate-docs and make a pull request if there are any newly generated docs.
  2. When the above PR is merged, clone the appium.io repo (if you haven't done so already)
  3. Check out and pull the latest gh-pages branch
  4. Follow the setup guide in the README.md
  5. Generate the docs by running npm run build:docs
  6. Make a new branch
  7. Commit and push changes and make a pull request to have changes merged into gh-pages

Releasing

The release process for any Appium module other than the main Appium package is pretty straightforward (note that you will need to be an NPM owner for the package if you want to publish it. Ownership is managed by the Appium committers; talk to @jlipps or @imurchie if you believe you should be an owner and are not):

  1. rm -rf node_modules && rm -rf package-lock.json && npm install and run tests to make sure a clean install works.
  2. Determine whether we have a patch (bugfix), minor (feature), or major (breaking) release according to the principles of SemVer (see also this explanation of how SemVer works with NPM).
  3. Update the CHANGELOG and/or README with any appropriate changes and commit. Most subpackages don't have a CHANGELOG.
  4. Run npm version <version-type> with the appropriate version type.
  5. Push the appropriate branch to GitHub, and don't forget to include the --tags flag to include the tag just created by npm version.
  6. Run npm publish (with --tag beta if this isn't an official release).

For the main Appium packages, all the above steps must be taken, but with several changes. One reason is that for the main package we use NPM shrinkwrap to ensure dependencies don't change between installations. Another reason is that we develop on master and release on various branches. The way it works is as follows: we always develop and add new code to master. When we are ready to make a new minor or major release (i.e., 1.5.0 or 2.0.0), we create a release branch (1.5 or 2.0 respectively). We then publish off of that branch. As we feel the need to make patch releases, we first pull the patch into master, then cherry-pick individual patches to the release branch (perhaps even multiple release branches). Then we again publish from those branches with the updated patch version (1.5.1 or 2.0.1 for example).

A note about npm shrinkwrap: We use npm shrinkwrap in order to lock dependencies on release. Without it, any development on dependent packages will be reflected when Appium is installed, which may lead to issues. Since the configuration file, npm-shrinkwrap.json, only exists on release branches, it is necessary to manually manage it during the release process. It needs to be checked in to GitHub along with changes to package.json. With npm 5+ there is also a package-lock.json file produced. During the shrinkwrap process this is converted into the npm-shrinkwrap.json file.

  1. Remove the NPM shrinkwrap and package-lock JSON files if they exists.
  2. rm -rf node_modules && npm install and run tests to make sure a clean install works.
  3. Determine whether we have a patch (bugfix), minor (feature), or major (breaking) release according to the principles of SemVer.
  4. Update package.json with the appropriate new version.
  5. Update the CHANGELOG/README with appropriate changes and submit for review as a PR, along with shrinkwrap and package.json changes. Wait for it to be merged, then pull it into the release branch.
  6. Run npm run shrinkwrap-prod. This script prunes dev dependencies (leaving only production dependencies), creates a production-only npm-shrinkwrap.json and then re-installs the dev dependencies by doing npm install --no-shrinkwrap.
  7. Create a tag of the form v<version> on the release branch (usually a minor branch like 1.5 or 1.4), with: git tag -a v<version>, e.g., git tag -a v1.5.0. This is not necessary for beta versions.
  8. Push the tag to upstream: git push --tags <remote> <branch>
  9. Run npm publish (with --tag beta if this isn't an official release).
  10. Remove the NPM shrinkwrap JSON file from Git and push the changes
  11. Update the site docs (see "Updating Appium site docs" above) or put in an issue to have the site docs updated
  12. Create a new release on GitHub: go to https://github.com/appium/appium/releases/tag/v<VERSION> and hit "Edit Tag". Make the release name <VERSION> (e.g., 2.0.5), then paste in the changelog (but not the changelog header for this version). If it's a beta release, mark as pre-release.
  13. Create a new post on discuss.appium.io announcing the release. Post it in the "News" category. Paste in the changelog and any choice comments. Pin it and unpin the previous release post.
  14. Begin process of releasing appium-desktop.
  15. Notify @jlipps to so he can tweet a link to the discuss post.