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
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 () => {
const nockReset = await browser.executeMemLeakScenario(executeCalls)
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++) {
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()})`)
await expect(finalHeapUsage).toBeLessThanOrEqual(1.05 * initialHeapUsage + scriptSize / 1024 / 1024)
})
})