All files / wdio-devtools-service/src/handler network.js

100% Statements 48/48
96.67% Branches 29/30
100% Functions 9/9
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 145 146        10x 10x 10x   10x 10x 10x 10x       81x         18x 2x   18x       9x             9x 6x     3x 3x       9x       9x 1x     8x 8x 8x 8x 8x       9x   9x                             3x   1x         1x     9x           9x 1x                 9x 2x           7x     9x 1x 1x 1x   8x               6x 1x               1x       1x 1x 1x          
import { IGNORED_URLS } from '../constants'
 
export default class NetworkHandler {
    constructor (cdp) {
        this.requestLog = { requests: [] }
        this.requestTypes = {}
        this.cachedFirstRequest = null
 
        cdp.on('Network.dataReceived', ::this.onDataReceived)
        cdp.on('Network.responseReceived', ::this.onNetworkResponseReceived)
        cdp.on('Network.requestWillBeSent', ::this.onNetworkRequestWillBeSent)
        cdp.on('Page.frameNavigated', ::this.onPageFrameNavigated)
    }
 
    findRequest (params) {
        let request = this.requestLog.requests.find((req) => req.id === params.requestId)
 
        /**
         * If no match is found, check if the corresponding request is the cached first request
         */
        if (!request && this.cachedFirstRequest && this.cachedFirstRequest.id === params.requestId) {
            request = this.cachedFirstRequest
        }
        return request
    }
 
    onDataReceived (params) {
        let request = this.findRequest(params)
 
        /**
         * ensure that
         *  - a requestWillBeSent event was triggered before
         *  - the request type is accurate and known (sometimes this is not the case when `Network.requestWillBeSent` is triggered)
         */
        if (!request || !this.requestTypes[request.type]) {
            return
        }
 
        this.requestTypes[request.type].size += parseInt(params.dataLength, 10)
        this.requestTypes[request.type].encoded += parseInt(params.encodedDataLength, 10)
    }
 
    onNetworkResponseReceived (params) {
        let request = this.findRequest(params)
        /**
         * ensure that a requestWillBeSent event was triggered before
         */
        if (!request) {
            return
        }
 
        request.statusCode = params.response.status
        request.requestHeaders = params.response.requestHeaders
        request.responseHeaders = params.response.headers
        request.timing = params.response.timing
        request.type = params.type
    }
 
    onNetworkRequestWillBeSent (params) {
        let isFirstRequestOfFrame = false
 
        if (
            /**
             * A new page was opened when request type is a document.
             * The first request is sent before the Page.frameNavigated event is triggered,
             * so this request must be cached to be able to add it to the requestLog later.
             */
            params.type === 'Document' &&
            /**
             * ensure that only page loads triggered by non scripts (devtools only) are considered
             * new page loads
             */
            params.initiator.type === 'other' &&
            /**
             * ignore pages not initated by the user
             */
            IGNORED_URLS.filter((url) => params.request.url.startsWith(url)).length === 0
        ) {
            isFirstRequestOfFrame = true
 
            /**
             * reset the request type sizes
             */
            this.requestTypes = {}
        }
 
        const log = {
            id: params.requestId,
            url: params.request.url,
            method: params.request.method
        }
 
        if (params.redirectResponse) {
            log.redirect = {
                url: params.redirectResponse.url,
                statusCode: params.redirectResponse.status,
                requestHeaders: params.redirectResponse.requestHeaders,
                responseHeaders: params.redirectResponse.headers,
                timing: params.redirectResponse.timing
            }
        }
 
        if (!this.requestTypes[params.type]) {
            this.requestTypes[params.type] = {
                size: 0,
                encoded: 0,
                count: 1
            }
        } else {
            this.requestTypes[params.type].count++
        }
 
        if (isFirstRequestOfFrame) {
            log.loaderId = params.loaderId
            this.cachedFirstRequest = log
            return
        }
        return this.requestLog.requests.push(log)
    }
 
    onPageFrameNavigated (params) {
        /**
         * Only create a requestLog for pages that don't have a parent frame.
         * I.e. iframes are ignored
         */
        if (!params.frame.parentId && IGNORED_URLS.filter((url) => params.frame.url.startsWith(url)).length === 0) {
            this.requestLog = {
                id: params.frame.loaderId,
                url: params.frame.url,
                requests: []
            }
            /**
             * Add the first request that was cached before the actual requestLog could be created
             */
            Eif (this.cachedFirstRequest && this.cachedFirstRequest.loaderId === params.frame.loaderId) {
                /**
                 * Delete the loaderId of the first request so that all request data has the same structure
                 */
                delete this.cachedFirstRequest.loaderId
                this.requestLog.requests.push(this.cachedFirstRequest)
                this.cachedFirstRequest = null
            }
        }
    }
}