🏡 index : quine-global/webdriverio.git

import { writeHeapSnapshot } from 'node:v8'
import { browser, expect } from '@wdio/globals'
import logger from '@wdio/logger'

const log = logger('test')
const executeCalls = 10
const scriptSize = 2_000_000 // ~2 MiB

function getHeapUsageMiB() {
    return process.memoryUsage().heapUsed / 1024 / 1024
}

function heapSnapshot() {
    if (process.env.WRITE_HEAP_SNAPSHOTS === 'true') {
        return writeHeapSnapshot(undefined, { exposeInternals: true, exposeNumericValues: true })
    }
    return ''
}

describe('`execute` memory leak check', () => {
    it('repeated large `execute` scripts should not lead to memory leak', async () => {
        // @ts-expect-error mock feature
        const nockReset = await browser.executeMemLeakScenario(executeCalls)
        // @ts-expect-error gc is exposed
        globalThis.gc()
        const initialHeapUsage = getHeapUsageMiB()
        log.debug(`Initial heap usage ${initialHeapUsage.toFixed(2)} MiB (${heapSnapshot()})`)
        let heapUsage = 0
        for (let i = 0; i < executeCalls; i++) {
            // use `scriptSize + i` to make each script unique
            await browser.execute(`{ let foo = "${'a'.repeat(scriptSize + i)}"; }`)
            heapUsage = getHeapUsageMiB()
            log.debug(`[${i.toString().padStart(2, '0')}] Heap usage ${heapUsage.toFixed(2)} MiB`)
        }
        nockReset()
        globalThis.gc?.()
        const finalHeapUsage = getHeapUsageMiB()
        log.debug(`Final heap usage ${finalHeapUsage.toFixed(2)} MiB (${heapSnapshot()})`)
        // 5% for variability / v8 internals + script size once due to nock interceptor leaking the last request+response (despite nockReset)
        await expect(finalHeapUsage).toBeLessThanOrEqual(1.05 * initialHeapUsage + scriptSize / 1024 / 1024)
    })
})