All files / wdio-config/src utils.js

100% Statements 36/36
100% Branches 64/64
100% Functions 3/3
100% Lines 36/36

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 14184x 84x 84x   84x               37x 37x 4x     33x             87x           87x 1x                     86x 1x                   85x             57x   57x             28x                   1x                   27x                           7x   7x       7x 1x     6x 1x     6x 5x 1x     4x 2x 2x   1x       3x 1x     2x       3x    
const DEFAULT_HOSTNAME = '127.0.0.1'
const DEFAULT_PORT = 4444
const DEFAULT_PROTOCOL = 'http'
 
const REGION_MAPPING = {
    'us': '', // default endpoint
    'eu': 'eu-central-1.',
    'eu-central-1': 'eu-central-1.',
    'us-east-1': 'us-east-1.'
}
 
export function getSauceEndpoint (region, isRDC) {
    const shortRegion = REGION_MAPPING[region] ? region : 'us'
    if (isRDC){
        return `${shortRegion}1.appium.testobject.com`
    }
 
    return `ondemand.${REGION_MAPPING[shortRegion]}saucelabs.com`
}
 
/**
 * helper to detect the Selenium backend according to given capabilities
 */
export function detectBackend (options = {}, isRDC = false) {
    let { port, hostname, user, key, protocol, region, headless } = options
 
    /**
     * browserstack
     * e.g. zHcv9sZ39ip8ZPsxBVJ2
     */
    if (typeof user === 'string' && typeof key === 'string' && key.length === 20) {
        return {
            protocol: 'https',
            hostname: 'hub-cloud.browserstack.com',
            port: 443
        }
    }
 
    /**
     * testingbot
     * e.g. ec337d7b677720a4dde7bd72be0bfc67
     */
    if (typeof user === 'string' && typeof key === 'string' && key.length === 32) {
        return {
            hostname: 'hub.testingbot.com',
            port: 80
        }
    }
 
    /**
     * Sauce Labs
     * e.g. 50aa152c-1932-B2f0-9707-18z46q2n1mb0
     */
    if ((typeof user === 'string' && typeof key === 'string' && key.length === 36) ||
        // When SC is used a user needs to be provided and `isRDC` needs to be true
        (typeof user === 'string' && isRDC) ||
        // Or only RDC
        isRDC
    ) {
        // Sauce headless is currently only in us-east-1
        const sauceRegion = headless ? 'us-east-1' : region
 
        return {
            protocol: protocol || 'https',
            hostname: hostname || getSauceEndpoint(sauceRegion, isRDC),
            port: port || 443
        }
    }
 
    if (
        /**
         * user and key are set in config
         */
        (typeof user === 'string' || typeof key === 'string') &&
        /**
         * but no custom WebDriver endpoint was configured
         */
        !hostname
    ) {
        throw new Error(
            'A "user" or "key" was provided but could not be connected to a ' +
            'known cloud service (SauceLabs, Browerstack or Testingbot). ' +
            'Please check if given user and key properties are correct!'
        )
    }
 
    /**
     * no cloud provider detected, fallback to local browser driver
     */
    return {
        hostname: hostname || DEFAULT_HOSTNAME,
        port: port || DEFAULT_PORT,
        protocol: protocol || DEFAULT_PROTOCOL
    }
}
 
/**
 * validates configurations based on default values
 * @param  {Object} defaults  object describing all allowed properties
 * @param  {Object} options   option to check agains
 * @return {Object}           validated config enriched with default values
 */
export function validateConfig (defaults, options) {
    const params = {}
 
    for (const [name, expectedOption] of Object.entries(defaults)) {
        /**
         * check if options is given
         */
        if (typeof options[name] === 'undefined' && !expectedOption.default && expectedOption.required) {
            throw new Error(`Required option "${name}" is missing`)
        }
 
        if (typeof options[name] === 'undefined' && expectedOption.default) {
            params[name] = expectedOption.default
        }
 
        if (typeof options[name] !== 'undefined') {
            if (typeof expectedOption.type === 'string' && typeof options[name] !== expectedOption.type) {
                throw new Error(`Expected option "${name}" to be type of ${expectedOption.type} but was ${typeof options[name]}`)
            }
 
            if (typeof expectedOption.type === 'function') {
                try {
                    expectedOption.type(options[name])
                } catch (e) {
                    throw new Error(`Type check for option "${name}" failed: ${e.message}`)
                }
            }
 
            if (expectedOption.match && !options[name].match(expectedOption.match)) {
                throw new Error(`Option "${name}" doesn't match expected values: ${expectedOption.match}`)
            }
 
            params[name] = options[name]
        }
    }
 
    return params
}