UNPKG

webdriver-manager

Version:

A selenium server and browser driver manager for your end to end tests.

244 lines 9.59 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const child_process_1 = require("child_process"); const fs = require("fs"); const glob = require("glob"); const ini = require("ini"); const path = require("path"); const q = require("q"); const config_1 = require("../config"); const utils_1 = require("../utils"); const noop = () => { }; // Make a function which configures a child process to automatically respond // to a certain question function respondFactory(question, answer, verbose) { return (child) => { child.stdin.setDefaultEncoding('utf-8'); child.stdout.on('data', (data) => { if (data != null) { if (verbose) { process.stdout.write(data); } if (data.toString().indexOf(question) != -1) { child.stdin.write(answer + '\n'); } } }); }; } // Run a command on the android SDK function runAndroidSDKCommand(sdkPath, cmd, args, stdio, config_fun) { let child = utils_1.spawn(path.resolve(sdkPath, 'tools', 'android'), [cmd].concat(args), stdio); if (config_fun) { config_fun(child); } ; let deferred = q.defer(); child.on('exit', (code) => { if (deferred != null) { if (code) { deferred.reject(code); } else { deferred.resolve(); } deferred = null; } }); child.on('error', (err) => { if (deferred != null) { deferred.reject(err); deferred = null; } }); return deferred.promise; } // Download updates via the android SDK function downloadAndroidUpdates(sdkPath, targets, search_all, auto_accept, verbose) { return runAndroidSDKCommand(sdkPath, 'update', ['sdk', '-u'].concat(search_all ? ['-a'] : []).concat(['-t', targets.join(',')]), auto_accept ? 'pipe' : 'inherit', auto_accept ? respondFactory('Do you accept the license', 'y', verbose) : noop); } // Setup hardware acceleration for x86-64 emulation function setupHardwareAcceleration(sdkPath) { // TODO(sjelin): linux setup let toolDir = path.resolve(sdkPath, 'extras', 'intel', 'Hardware_Accelerated_Execution_Manager'); if (config_1.Config.osType() == 'Darwin') { console.log('Enabling hardware acceleration (requires root access)'); // We don't need the wrapped spawnSync because we know we're on OSX child_process_1.spawnSync('sudo', ['silent_install.sh'], { stdio: 'inherit', cwd: toolDir }); } else if (config_1.Config.osType() == 'Windows_NT') { console.log('Enabling hardware acceleration (requires admin access)'); // We don't need the wrapped spawnSync because we know we're on windows child_process_1.spawnSync('silent_install.bat', [], { stdio: 'inherit', cwd: toolDir }); } } // Get a list of all the SDK download targets for a given set of APIs, // architectures, and platforms function getAndroidSDKTargets(apiLevels, architectures, platforms, oldAVDs) { function getSysImgTarget(architecture, platform, level) { if (platform.toUpperCase() == 'DEFAULT') { platform = 'android'; } return 'sys-img-' + architecture + '-' + platform + '-' + level; } let targets = apiLevels .map((level) => { return 'android-' + level; }) .concat(architectures.reduce((targets, architecture) => { return targets.concat.apply(targets, platforms.map((platform) => { return apiLevels.map(getSysImgTarget.bind(null, architecture, platform)); })); }, [])); oldAVDs.forEach((name) => { let avd = new AVDDescriptor(name); if (targets.indexOf(avd.api) == -1) { targets.push(avd.api); } let sysImgTarget = getSysImgTarget(avd.architecture, avd.platform, avd.api.slice('android-'.length)); if (targets.indexOf(sysImgTarget) == -1) { targets.push(sysImgTarget); } }); return targets; } // All the information about an android virtual device class AVDDescriptor { constructor(api, platform, architecture) { if (platform != undefined) { this.api = api; this.platform = platform; this.architecture = architecture; this.name = [api, platform, architecture].join('-'); } else { this.name = api; let nameParts = this.name.split('-'); this.api = nameParts[0] + '-' + nameParts[1]; if (/v[0-9]+[a-z]+/.test(nameParts[nameParts.length - 1]) && (nameParts[nameParts.length - 2].slice(0, 3) == 'arm')) { this.architecture = nameParts[nameParts.length - 2] + '-' + nameParts[nameParts.length - 1]; } else { this.architecture = nameParts[nameParts.length - 1]; } this.platform = this.name.slice(this.api.length + 1, -this.architecture.length - 1); } this.abi = (this.platform.toUpperCase() == 'DEFAULT' ? '' : this.platform + '/') + this.architecture; } avdName(version) { return this.name + '-v' + version + '-wd-manager'; } } // Gets the descriptors for all AVDs which are possible to make given the // SDKs which were downloaded function getAVDDescriptors(sdkPath) { let deferred = q.defer(); // `glob` package always prefers patterns to use `/` glob('system-images/*/*/*', { cwd: sdkPath }, (err, files) => { if (err) { deferred.reject(err); } else { deferred.resolve(files.map((file) => { // `file` could use `/` or `\`, so we use `path.normalize` let info = path.normalize(file).split(path.sep).slice(-3); return new AVDDescriptor(info[0], info[1], info[2]); })); } }); return deferred.promise; } function sequentialForEach(array, func) { let ret = q(null); array.forEach((x) => { ret = ret.then(() => { return func(x); }); }); return ret; } // Configures the hardware.ini file for a system image of a new AVD function configureAVDHardware(sdkPath, desc) { let file = path.resolve(sdkPath, 'system-images', desc.api, desc.platform, desc.architecture, 'hardware.ini'); return q.nfcall(fs.stat, file) .then((stats) => { return q.nfcall(fs.readFile, file); }, (err) => { return q(''); }) .then((contents) => { let config = ini.parse(contents.toString()); config['hw.keyboard'] = 'yes'; config['hw.battery'] = 'yes'; config['hw.ramSize'] = 1024; return q.nfcall(fs.writeFile, file, ini.stringify(config)); }); } // Make an android virtual device function makeAVD(sdkPath, desc, version, verbose) { return runAndroidSDKCommand(sdkPath, 'delete', ['avd', '--name', desc.avdName(version)]) .then(noop, noop) .then(() => { return runAndroidSDKCommand(sdkPath, 'create', ['avd', '--name', desc.avdName(version), '--target', desc.api, '--abi', desc.abi], 'pipe', respondFactory('Do you wish to create a custom hardware profile', 'no', verbose)); }); } // Initialize the android SDK function android(sdkPath, apiLevels, architectures, platforms, acceptLicenses, version, oldAVDs, logger, verbose) { let avdDescriptors; let tools = ['platform-tool', 'tool']; if ((config_1.Config.osType() == 'Darwin') || (config_1.Config.osType() == 'Windows_NT')) { tools.push('extra-intel-Hardware_Accelerated_Execution_Manager'); } logger.info('android-sdk: Downloading additional SDK updates'); downloadAndroidUpdates(sdkPath, tools, false, acceptLicenses, verbose) .then(() => { return setupHardwareAcceleration(sdkPath); }) .then(() => { logger.info('android-sdk: Downloading more additional SDK updates ' + '(this may take a while)'); return downloadAndroidUpdates(sdkPath, ['build-tools-24.0.0'].concat(getAndroidSDKTargets(apiLevels, architectures, platforms, oldAVDs)), true, acceptLicenses, verbose); }) .then(() => { return getAVDDescriptors(sdkPath); }) .then((descriptors) => { avdDescriptors = descriptors; logger.info('android-sdk: Configuring virtual device hardware'); return sequentialForEach(avdDescriptors, (descriptor) => { return configureAVDHardware(sdkPath, descriptor); }); }) .then(() => { return sequentialForEach(avdDescriptors, (descriptor) => { logger.info('android-sdk: Setting up virtual device "' + descriptor.name + '"'); return makeAVD(sdkPath, descriptor, version, verbose); }); }) .then(() => { return q.nfcall(fs.writeFile, path.resolve(sdkPath, 'available_avds.json'), JSON.stringify(avdDescriptors.map((descriptor) => { return descriptor.name; }))); }) .then(() => { logger.info('android-sdk: Initialization complete'); }) .done(); } exports.android = android; ; function iOS(logger) { if (config_1.Config.osType() != 'Darwin') { throw new Error('Must be on a Mac to simulate iOS devices.'); } try { fs.statSync('/Applications/Xcode.app'); } catch (e) { logger.warn('You must install the xcode commandline tools!'); } } exports.iOS = iOS; //# sourceMappingURL=initialize.js.map