├── .gitignore ├── README.md ├── index.js ├── package.json ├── pre-built ├── ContactManager-selendroid.apk ├── ContactManager.apk └── selendroid-test-app.apk └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ##sample-apps## 2 | 3 | `npm install sample-apps` 4 | 5 | 6 | This module allows you to ask for apps by name and version, and it will return a full path to the .app, .apk or .zip file. 7 | 8 | Some of the apps are just binaries we have, stored in the pre-built directory. 9 | Others exist as their own npm modules, loaded as dependencies and made available here. 10 | 11 | It shouldn't matter to the user whether they are pre-built or not. 12 | 13 | The modularized apps are in the package.json file as "optional dependencies" which means if for some reason they can't be loaded, this module will still install the rest of the apps. 14 | But if an app doesn't load, it won't be included in `list()` 15 | 16 | ##Usage## 17 | 18 | ``` 19 | sample_apps = require('sample-apps'); 20 | 21 | apps = sample_apps.list(); 22 | 23 | console.log(apps); 24 | //[ 'ApiDemos-debug', 25 | // 'UICatalog7.1', 26 | // 'ContactManager-selendroid', 27 | // 'ContactManager', 28 | // 'TestApp', 29 | // 'TestApp6.0', 30 | // 'TestApp6.1', 31 | // 'TestApp7.1', 32 | // 'UICatalog6.0', 33 | // 'UICatalog6.1', 34 | // 'WebViewApp6.0', 35 | // 'WebViewApp6.1', 36 | // 'WebViewApp7.1' ] 37 | 38 | pathToApiDemos = sample_apps('ApiDemos-debug'); 39 | // /Users/jonahss/sample-apps/node_modules/android-apidemos/bin/ApiDemos-debug.apk 40 | ``` 41 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var _ = require('underscore'); 3 | var path = require('path'); 4 | 5 | var suffixes = ['zip', 'app', 'apk']; 6 | 7 | // returns last filename in a path string 8 | var lastFile = function(fullPath) { 9 | return _.last(fullPath.split(path.sep)); 10 | } 11 | 12 | var getOptionalDeps = function() { 13 | return Object.keys(require('./package.json').optionalDependencies); 14 | } 15 | 16 | var appPathsForModule = function(module) { 17 | try { 18 | var moduleEntrypoint = require.resolve(module); 19 | } catch (e) { 20 | if (e.code == "MODULE_NOT_FOUND") { 21 | return []; 22 | } else { 23 | throw e; 24 | } 25 | } 26 | 27 | var ext = _.last(moduleEntrypoint.split('.')); 28 | if (ext == 'json' || ext == 'js') { 29 | var moduleBasePath = moduleEntrypoint.split(path.sep).slice(0, -1).join(path.sep); 30 | var paths = require(module); 31 | if(paths.absolute) { 32 | // support for the more recent ios-test-app format 33 | paths = [paths.absolute.iphoneos, paths.absolute.iphonesimulator]; 34 | return paths; 35 | } 36 | return paths.map(function(appPath) { 37 | return moduleBasePath + path.sep + path.normalize(appPath); 38 | }); 39 | } 40 | else { 41 | return [moduleEntrypoint]; 42 | } 43 | 44 | } 45 | 46 | // returns an array of all app files pointed to within the package.json's optionalDependencies 47 | // for most apps this is equivalent to the 'main' entrypoint for the module 48 | // some modules 'main' entrypoint is a .json file which yields a registry of multiple app binaries contained in the module, these are all returned. 49 | var getPathsFromOptionalDeps = function() { 50 | 51 | var unflattened = getOptionalDeps().map(appPathsForModule); 52 | return _.flatten(unflattened); 53 | } 54 | 55 | // get an app by name. 56 | // If you specify only the beginning of a name, return first alphabetical match 57 | var _getApp = function(app) { 58 | 59 | // first search npm modules 60 | var optionalDeps = getPathsFromOptionalDeps(); 61 | optionalDeps = _.sortBy(optionalDeps, 'length'); 62 | var appPath = _.find(optionalDeps, function(name) { 63 | return lastFile(name).indexOf(app) >= 0; 64 | }); 65 | 66 | if (appPath) { 67 | return appPath; 68 | } 69 | 70 | // then search static apps 71 | var preBuilt = fs.readdirSync(path.resolve(__dirname, 'pre-built')); 72 | preBuilt = _.sortBy(preBuilt, 'length'); 73 | var appPath = _.find(preBuilt, function(name) { 74 | return name.indexOf(app) >= 0; 75 | }); 76 | 77 | if (appPath) { 78 | return require.resolve('./pre-built/' + appPath); 79 | } 80 | 81 | return undefined; 82 | } 83 | 84 | // get an app by name. 85 | // If you specify only the beginning of a name, return first alphabetical match 86 | // Optional `realDevice` param is a boolean. 87 | // If true: add '-iphoneos' to the name of the app, 88 | // otherwise adds '-iphonesimulator'. If false and no app 89 | // is found, try to return an app just by name with no special suffix. 90 | var getApp = function(app, realDevice) { 91 | var appPath; 92 | 93 | if (realDevice) { 94 | appPath = _getApp(app+'-iphoneos'); 95 | } else { 96 | appPath = _getApp(app+'-iphonesimulator'); 97 | } 98 | 99 | if (!appPath) { 100 | appPath = _getApp(app); 101 | } 102 | 103 | return appPath; 104 | } 105 | 106 | module.exports = getApp; 107 | 108 | var dropSuffix = function(name) { 109 | var parts = name.split('.'); 110 | 111 | while (_.contains(suffixes, parts[parts.length-1])) { 112 | parts.pop(); 113 | } 114 | 115 | return parts.join('.'); 116 | } 117 | 118 | module.exports.list = function() { 119 | var optionalDeps = getPathsFromOptionalDeps(); 120 | optionalDeps = optionalDeps.map(lastFile); 121 | 122 | var preBuilt = fs.readdirSync(path.resolve(__dirname, 'pre-built')); 123 | 124 | return optionalDeps.concat(preBuilt).map(dropSuffix); 125 | } 126 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample-apps", 3 | "version": "2.0.4", 4 | "description": "bundles and manages paths to sample mobile apps, for testing", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/appium/sample-apps.git" 12 | }, 13 | "keywords": [ 14 | "appium", 15 | "test", 16 | "app" 17 | ], 18 | "author": "jonahss", 19 | "license": "Apache-2.0", 20 | "bugs": { 21 | "url": "https://github.com/appium/sample-apps/issues" 22 | }, 23 | "homepage": "https://github.com/appium/sample-apps", 24 | "optionalDependencies": { 25 | "android-apidemos": "^1.1.1", 26 | "gps-demo-app": "^1.0.0", 27 | "ios-test-app": "^2.1.3", 28 | "ios-uicatalog": "^1.0.0", 29 | "ios-webview-app": "^1.0.0", 30 | "toggle-test-app": "^1.0.0", 31 | "io.appium.gappium.sampleapp": "^1.1.1" 32 | }, 33 | "dependencies": { 34 | "underscore": "^1.7.0" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /pre-built/ContactManager-selendroid.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appium/sample-apps/0e92532585431d3b362c1ff12c65b54936fbe26f/pre-built/ContactManager-selendroid.apk -------------------------------------------------------------------------------- /pre-built/ContactManager.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appium/sample-apps/0e92532585431d3b362c1ff12c65b54936fbe26f/pre-built/ContactManager.apk -------------------------------------------------------------------------------- /pre-built/selendroid-test-app.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appium/sample-apps/0e92532585431d3b362c1ff12c65b54936fbe26f/pre-built/selendroid-test-app.apk -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | doit = require('./index.js'); 2 | 3 | console.log(doit.list()); 4 | 5 | console.log(doit('ApiDemos-debug')); 6 | console.log(doit('ContactManager')); 7 | console.log(doit('HelloGappium')); 8 | console.log(doit('HelloGappium-debug')); 9 | --------------------------------------------------------------------------------