All files / wdio-browserstack-service/src service.js

100% Statements 47/47
96.3% Branches 26/27
100% Functions 17/17
100% Lines 46/46

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 141 142 143 144          1x       27x 27x 27x                 3x 2x     3x 2x   3x 3x       6x 6x       6x 1x   6x       2x 1x         2x   2x 1x 1x         4x                           3x         1x       2x 2x 2x 2x 2x 2x       3x 3x           3x     3x           5x               14x 14x             14x 2x     12x 2x       10x 80x 80x     10x 10x          
import logger from '@wdio/logger'
import request from 'request'
 
import { BROWSER_DESCRIPTION } from './constants'
 
const log = logger('@wdio/browserstack-service')
 
export default class BrowserstackService {
    constructor (config) {
        this.config = config
        this.failures = 0
        this.sessionBaseUrl = 'https://api.browserstack.com/automate/sessions'
    }
 
    /**
     * if no user and key is specified even though a sauce service was
     * provided set user and key with values so that the session request
     * will fail
     */
    beforeSession (config) {
        if (!config.user) {
            config.user = 'NotSetUser'
        }
 
        if (!config.key) {
            config.key = 'NotSetKey'
        }
        this.config.user = config.user
        this.config.key = config.key
    }
 
    before() {
        this.sessionId = global.browser.sessionId
        this.auth = {
            user: this.config.user,
            pass: this.config.key
        }
        if (global.browser.capabilities.app) {
            this.sessionBaseUrl = 'https://api-cloud.browserstack.com/app-automate/sessions'
        }
        return this._printSessionURL()
    }
 
    afterSuite(suite) {
        if (Object.prototype.hasOwnProperty.call(suite, 'error')) {
            this.failures++
        }
    }
 
    afterTest(test) {
        this.fullTitle = test.parent + ' - ' + test.title
 
        if (!test.passed) {
            this.failures++
            this.failReason = (test.error && test.error.message ? test.error.message : 'Unknown Error')
        }
    }
 
    afterStep(uri, feature) {
        if (
            /**
             * Cucumber v1
             */
            feature.failureException ||
            /**
             * Cucumber v2
             */
            (typeof feature.getFailureException === 'function' && feature.getFailureException()) ||
            /**
             * Cucumber v3, v4
             */
            (feature.status === 'failed')
        ) {
            ++this.failures
        }
    }
 
    after() {
        return this._update(this.sessionId, this._getBody())
    }
 
    async onReload(oldSessionId, newSessionId) {
        this.sessionId = newSessionId
        await this._update(oldSessionId, this._getBody())
        this.failures = 0
        delete this.fullTitle
        delete this.failReason
        this._printSessionURL()
    }
 
    _update(sessionId, requestBody) {
        return new Promise((resolve, reject) => {
            request.put(`${this.sessionBaseUrl}/${sessionId}.json`, {
                json: true,
                auth: this.auth,
                body: requestBody
            }, (error, response, body) => {
                /* istanbul ignore if */
                if (error) {
                    return reject(error)
                }
                return resolve(body)
            })
        })
    }
 
    _getBody() {
        return {
            status: this.failures === 0 ? 'completed' : 'error',
            name: this.fullTitle,
            reason: this.failReason
        }
    }
 
    _printSessionURL() {
        const capabilities = global.browser.capabilities
        return new Promise((resolve, reject) => request.get(
            `${this.sessionBaseUrl}/${this.sessionId}.json`,
            {
                json: true,
                auth: this.auth
            },
            (error, response, body) => {
                if (error) {
                    return reject(error)
                }
 
                if (response.statusCode !== 200) {
                    return reject(new Error(`Bad response code: Expected (200), Received (${response.statusCode})!`))
                }
 
                // These keys describe the browser the test was run on
                const browserString = BROWSER_DESCRIPTION
                    .map(k => capabilities[k])
                    .filter(v => !!v)
                    .join(' ')
 
                log.info(`${browserString} session: ${body.automation_session.browser_url}`)
                return resolve(body)
            }
        ))
    }
}